From 6734aa44ec049224c241ef29d21770671bf17806 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 2 Apr 2022 15:12:50 +0200 Subject: [PATCH] Update to Angelscript 2.35.1 --- add_on/autowrapper/aswrappedcall.h | 11 +- .../autowrapper/generator/generateheader.cpp | 11 +- add_on/datetime/datetime.cpp | 43 +++-- add_on/scriptarray/scriptarray.cpp | 49 +++-- add_on/scriptarray/scriptarray.h | 1 + add_on/scriptbuilder/scriptbuilder.cpp | 53 +++-- add_on/scriptdictionary/scriptdictionary.cpp | 2 - add_on/scriptfile/scriptfilesystem.cpp | 2 + add_on/scripthandle/scripthandle.cpp | 5 +- add_on/scripthelper/scripthelper.cpp | 14 +- add_on/scriptmath/scriptmath.cpp | 32 +-- .../scriptstdstring/scriptstdstring_utils.cpp | 7 +- add_on/weakref/weakref.cpp | 8 +- angelscript/source/as_atomic.cpp | 9 +- angelscript/source/as_builder.cpp | 55 +++++- angelscript/source/as_builder.h | 4 +- angelscript/source/as_callfunc.cpp | 5 +- angelscript/source/as_callfunc.h | 30 ++- angelscript/source/as_callfunc_arm64.cpp | 4 +- angelscript/source/as_callfunc_arm64_gcc.S | 10 +- angelscript/source/as_compiler.cpp | 182 ++++++++++++------ angelscript/source/as_config.h | 112 +++++++---- angelscript/source/as_context.cpp | 39 +++- angelscript/source/as_module.cpp | 49 +++-- angelscript/source/as_parser.cpp | 29 ++- angelscript/source/as_restore.cpp | 119 +++++++----- angelscript/source/as_restore.h | 5 +- angelscript/source/as_scriptengine.cpp | 43 +++-- angelscript/source/as_scriptfunction.cpp | 21 +- angelscript/source/as_scriptfunction.h | 3 +- angelscript/source/as_scriptobject.cpp | 2 + angelscript/source/as_symboltable.h | 2 +- angelscript/source/as_texts.h | 5 +- 33 files changed, 650 insertions(+), 316 deletions(-) diff --git a/add_on/autowrapper/aswrappedcall.h b/add_on/autowrapper/aswrappedcall.h index 880265e..b07a6fb 100644 --- a/add_on/autowrapper/aswrappedcall.h +++ b/add_on/autowrapper/aswrappedcall.h @@ -551,12 +551,9 @@ struct Id { template Id id(T /*fn_ptr*/) { return Id(); } -// On some versions of GNUC it is necessary to use the template keyword as disambiguator, -// on others the template keyword gives an error, hence the need for the following define. -// MSVC on the other hand seems to accept both with or without the template keyword. -#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) - // GNUC 4.4.3 doesn't need the template keyword, and - // hopefully upcoming versions won't need it either +// On GNUC it is necessary to use the template keyword as disambiguator. +// MSVC seems to accept both with or without the template keyword. +#if defined(__GNUC__) #define TMPL template #else #define TMPL @@ -568,7 +565,7 @@ Id id(T /*fn_ptr*/) { return Id(); } #define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >()) #define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >)) -#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >)) +#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >)) #define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >)) #define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >)) diff --git a/add_on/autowrapper/generator/generateheader.cpp b/add_on/autowrapper/generator/generateheader.cpp index 277799a..d15a7bf 100644 --- a/add_on/autowrapper/generator/generateheader.cpp +++ b/add_on/autowrapper/generator/generateheader.cpp @@ -113,12 +113,9 @@ int main() "template \n" "Id id(T fn_ptr) { return Id(); }\n" "\n" - "// On some versions of GNUC it is necessary to use the template keyword as disambiguator,\n" - "// on others the template keyword gives an error, hence the need for the following define.\n" - "// MSVC on the other hand seems to accept both with or without the template keyword.\n" - "#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))\n" - " // GNUC 4.4.3 doesn't need the template keyword, and\n" - " // hopefully upcoming versions won't need it either\n" + "// On GNUC it is necessary to use the template keyword as disambiguator.\n" + "// MSVC seems to accept both with or without the template keyword.\n" + "#if defined(__GNUC__)\n" " #define TMPL template\n" "#else\n" " #define TMPL\n" @@ -130,7 +127,7 @@ int main() "#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n" "\n" "#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >))\n" - "#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >))\n" + "#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< AS_METHOD_AMBIGUITY_CAST(ReturnType (ClassType::*)Parameters)(&ClassType::name) >))\n" "#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >))\n" "#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >))\n" "\n" diff --git a/add_on/datetime/datetime.cpp b/add_on/datetime/datetime.cpp index 3ea75d8..cd56cf6 100644 --- a/add_on/datetime/datetime.cpp +++ b/add_on/datetime/datetime.cpp @@ -20,6 +20,7 @@ static tm time_point_to_tm(const std::chrono::time_point newTp; + if (!tm_to_time_point(local, newTp)) + return false; + + // Check if the date was actually valid + tm local2 = time_point_to_tm(newTp); + + if (local.tm_year != local2.tm_year || + local.tm_mon != local2.tm_mon || + local.tm_mday != local2.tm_mday) + return false; + + tp = newTp; + return true; } bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second) @@ -121,7 +127,20 @@ bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second) local.tm_min = minute; local.tm_sec = second; - return tm_to_time_point(local, tp); + std::chrono::time_point newTp; + if (!tm_to_time_point(local, newTp)) + return false; + + // Check if the time was actually valid + tm local2 = time_point_to_tm(newTp); + + if (local.tm_hour != local2.tm_hour || + local.tm_min != local2.tm_min || + local.tm_sec != local2.tm_sec) + return false; + + tp = newTp; + return true; } CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second) diff --git a/add_on/scriptarray/scriptarray.cpp b/add_on/scriptarray/scriptarray.cpp index 58512f3..169b566 100644 --- a/add_on/scriptarray/scriptarray.cpp +++ b/add_on/scriptarray/scriptarray.cpp @@ -1331,6 +1331,19 @@ void CScriptArray::Copy(void *dst, void *src) } +// internal +// Swap two elements +// Even in arrays of objects the objects are allocated on +// the heap and the array stores the pointers to the objects. +void CScriptArray::Swap(void* a, void* b) +{ + asBYTE tmp[16]; + Copy(tmp, a); + Copy(a, b); + Copy(b, tmp); +} + + // internal // Return pointer to array item (object handle or primitive value) void *CScriptArray::GetArrayItemPointer(int index) @@ -1574,32 +1587,31 @@ void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) if (cmpContext == 0) cmpContext = objType->GetEngine()->RequestContext(); - // Insertion sort - asBYTE tmp[16]; - for (asUINT i = start + 1; i < end; i++) + // TODO: Security issue: If the array is accessed from the callback while the sort is going on the result may be unpredictable + // For example, the callback resizes the array in the middle of the sort + // Possible solution: set a lock flag on the array, and prohibit modifications while the lock flag is set + + // Bubble sort + // TODO: optimize: Use an efficient sort algorithm + for (asUINT i = start; i+1 < end; i++) { - Copy(tmp, GetArrayItemPointer(i)); - - asUINT j = i - 1; - - while (j != 0xFFFFFFFF && j >= start ) + asUINT best = i; + for (asUINT j = i + 1; j < end; j++) { cmpContext->Prepare(func); - cmpContext->SetArgAddress(0, GetDataPointer(tmp)); - cmpContext->SetArgAddress(1, At(j)); + cmpContext->SetArgAddress(0, At(j)); + cmpContext->SetArgAddress(1, At(best)); int r = cmpContext->Execute(); if (r != asEXECUTION_FINISHED) break; if (*(bool*)(cmpContext->GetAddressOfReturnValue())) - { - Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); - j--; - } - else - break; + best = j; } - Copy(GetArrayItemPointer(j + 1), tmp); + // With Swap we guarantee that the array always sees all references + // if the GC calls the EnumReferences in the middle of the sorting + if( best != i ) + Swap(GetArrayItemPointer(i), GetArrayItemPointer(best)); } if (cmpContext) @@ -2170,8 +2182,9 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine) r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); + #if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); diff --git a/add_on/scriptarray/scriptarray.h b/add_on/scriptarray/scriptarray.h index 4903a97..f48aa39 100644 --- a/add_on/scriptarray/scriptarray.h +++ b/add_on/scriptarray/scriptarray.h @@ -124,6 +124,7 @@ protected: void *GetArrayItemPointer(int index); void *GetDataPointer(void *buffer); void Copy(void *dst, void *src); + void Swap(void *a, void *b); void Precache(); bool CheckMaxSize(asUINT numElements); void Resize(int delta, asUINT at); diff --git a/add_on/scriptbuilder/scriptbuilder.cpp b/add_on/scriptbuilder/scriptbuilder.cpp index 97b2833..597046e 100644 --- a/add_on/scriptbuilder/scriptbuilder.cpp +++ b/add_on/scriptbuilder/scriptbuilder.cpp @@ -302,7 +302,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length declaration.reserve(100); #endif - // Then check for meta data and #include directives + // Then check for meta data and pre-processor directives pos = 0; while( pos < modifiedScript.size() ) { @@ -313,10 +313,19 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length pos += len; continue; } + string token; + token.assign(&modifiedScript[pos], len); #if AS_PROCESS_METADATA == 1 - // Check if class - if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) + // Skip possible decorators before class and interface declarations + if (token == "shared" || token == "abstract" || token == "mixin" || token == "external") + { + pos += len; + continue; + } + + // Check if class or interface so the metadata for members can be gathered + if( currentClass == "" && (token == "class" || token == "interface") ) { // Get the identifier after "class" do @@ -362,15 +371,15 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length } // Check if end of class - if( currentClass != "" && modifiedScript[pos] == '}' ) + if( currentClass != "" && token == "}" ) { currentClass = ""; pos += len; continue; } - // Check if namespace - if( modifiedScript.substr(pos,len) == "namespace" ) + // Check if namespace so the metadata for members can be gathered + if( token == "namespace" ) { // Get the identifier after "namespace" do @@ -403,7 +412,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length } // Check if end of namespace - if( currentNamespace != "" && modifiedScript[pos] == '}' ) + if( currentNamespace != "" && token == "}" ) { size_t found = currentNamespace.rfind( "::" ); if( found != string::npos ) @@ -419,7 +428,7 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length } // Is this the start of metadata? - if( modifiedScript[pos] == '[' ) + if( token == "[" ) { // Get the metadata string pos = ExtractMetadata(pos, metadata); @@ -438,37 +447,36 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length else #endif // Is this a preprocessor directive? - if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + if( token == "#" && (pos + 1 < modifiedScript.size()) ) { int start = pos++; t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_IDENTIFIER ) + if (t == asTC_IDENTIFIER) { - string token; token.assign(&modifiedScript[pos], len); - if( token == "include" ) + if (token == "include") { pos += len; t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_WHITESPACE ) + if (t == asTC_WHITESPACE) { pos += len; t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); } - if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) + if (t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'')) { // Get the include file string includefile; - includefile.assign(&modifiedScript[pos+1], len-2); + includefile.assign(&modifiedScript[pos + 1], len - 2); pos += len; // Store it for later processing includes.push_back(includefile); // Overwrite the include directive with space characters to avoid compiler error - OverwriteCode(start, pos-start); + OverwriteCode(start, pos - start); } } else if (token == "pragma") @@ -491,6 +499,19 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length OverwriteCode(start, pos - start); } } + else + { + // Check for lines starting with #!, e.g. shebang interpreter directive. These will be treated as comments and removed by the preprocessor + if (modifiedScript[pos] == '!') + { + // Read until the end of the line + pos += len; + for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); + + // Overwrite the directive with space characters to avoid compiler error + OverwriteCode(start, pos - start); + } + } } // Don't search for metadata/includes within statement blocks or between tokens in statements else diff --git a/add_on/scriptdictionary/scriptdictionary.cpp b/add_on/scriptdictionary/scriptdictionary.cpp index 8de2e41..2ae5305 100644 --- a/add_on/scriptdictionary/scriptdictionary.cpp +++ b/add_on/scriptdictionary/scriptdictionary.cpp @@ -1140,7 +1140,6 @@ void RegisterScriptDictionary_Native(asIScriptEngine *engine) // Same as deleteAll r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); #endif - (void)r; // Cache some things the dictionary will need at runtime SDictionaryCache::Setup(engine); @@ -1209,7 +1208,6 @@ void RegisterScriptDictionary_Generic(asIScriptEngine *engine) r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - (void)r; // Cache some things the dictionary will need at runtime SDictionaryCache::Setup(engine); } diff --git a/add_on/scriptfile/scriptfilesystem.cpp b/add_on/scriptfile/scriptfilesystem.cpp index 99c6277..d2fa8a4 100644 --- a/add_on/scriptfile/scriptfilesystem.cpp +++ b/add_on/scriptfile/scriptfilesystem.cpp @@ -1,5 +1,6 @@ #include "scriptfilesystem.h" #include "../autowrapper/aswrappedcall.h" +#include // strstr() #if defined(_WIN32) #include // _getcwd @@ -383,6 +384,7 @@ asINT64 CScriptFileSystem::GetSize(const string &path) const // - path not found // - access denied // TODO: Should be able to define the permissions for the directory +// TODO: Should support recursively creating directories int CScriptFileSystem::MakeDir(const string &path) { string search; diff --git a/add_on/scripthandle/scripthandle.cpp b/add_on/scripthandle/scripthandle.cpp index da95e36..1114b2b 100644 --- a/add_on/scripthandle/scripthandle.cpp +++ b/add_on/scripthandle/scripthandle.cpp @@ -222,9 +222,8 @@ void CScriptHandle::EnumReferences(asIScriptEngine *inEngine) inEngine->GCEnumCallback(m_type); } -void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine) +void CScriptHandle::ReleaseReferences(asIScriptEngine * /*inEngine*/) { - (void)inEngine; // Simply clear the content to release the references Set(0, 0); } @@ -250,7 +249,6 @@ void RegisterScriptHandle_Native(asIScriptEngine *engine) r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 ); - (void)r; } void CScriptHandle_Construct_Generic(asIScriptGeneric *gen) @@ -348,7 +346,6 @@ void RegisterScriptHandle_Generic(asIScriptEngine *engine) r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - (void)r; } void RegisterScriptHandle(asIScriptEngine *engine) diff --git a/add_on/scripthelper/scripthelper.cpp b/add_on/scripthelper/scripthelper.cpp index 5e90ece..d3c4e1c 100644 --- a/add_on/scripthelper/scripthelper.cpp +++ b/add_on/scripthelper/scripthelper.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "../autowrapper/aswrappedcall.h" using namespace std; @@ -980,9 +981,16 @@ void RegisterExceptionRoutines(asIScriptEngine *engine) // The string type must be available assert(engine->GetTypeInfoByDecl("string")); - r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); - (void)r; + if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0) + { + r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); + } + else + { + r = engine->RegisterGlobalFunction("void throw(const string &in)", WRAP_FN(ScriptThrow), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string getExceptionInfo()", WRAP_FN(ScriptGetExceptionInfo), asCALL_GENERIC); assert(r >= 0); + } } END_AS_NAMESPACE diff --git a/add_on/scriptmath/scriptmath.cpp b/add_on/scriptmath/scriptmath.cpp index 5814d73..c5b86c3 100644 --- a/add_on/scriptmath/scriptmath.cpp +++ b/add_on/scriptmath/scriptmath.cpp @@ -72,45 +72,27 @@ double fraction(double v) } #endif -template -struct alias_cast_t -{ - union - { - F raw; - T data; - }; -}; - // As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of // functions for converting float values to IEEE 754 formatted values etc. This also allow us to // provide a platform agnostic representation to the script so the scripts don't have to worry // about whether the CPU uses IEEE 754 floats or some other representation float fpFromIEEE(asUINT raw) { - // TODO: Identify CPU family to provide proper conversion - // if the CPU doesn't natively use IEEE style floats - alias_cast_t t; - t.raw = raw; - return t.data; + // TODO: Identify CPU family to provide proper conversion + // if the CPU doesn't natively use IEEE style floats + return *reinterpret_cast(&raw); } asUINT fpToIEEE(float fp) { - alias_cast_t t; - t.raw = fp; - return t.data; + return *reinterpret_cast(&fp); } double fpFromIEEE(asQWORD raw) { - alias_cast_t t; - t.raw = raw; - return t.data; + return *reinterpret_cast(&raw); } asQWORD fpToIEEE(double fp) { - alias_cast_t t; - t.raw = fp; - return t.data; + return *reinterpret_cast(&fp); } // closeTo() is used to determine if the binary representation of two numbers are @@ -214,7 +196,6 @@ void RegisterScriptMath_Native(asIScriptEngine *engine) r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); #endif - (void)r; } #if AS_USE_FLOAT @@ -351,7 +332,6 @@ void RegisterScriptMath_Generic(asIScriptEngine *engine) r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); #endif - (void)r; } void RegisterScriptMath(asIScriptEngine *engine) diff --git a/add_on/scriptstdstring/scriptstdstring_utils.cpp b/add_on/scriptstdstring/scriptstdstring_utils.cpp index 54662aa..0f900a8 100644 --- a/add_on/scriptstdstring/scriptstdstring_utils.cpp +++ b/add_on/scriptstdstring/scriptstdstring_utils.cpp @@ -34,8 +34,9 @@ static CScriptArray *StringSplit(const string &delim, const string &str) CScriptArray *array = CScriptArray::Create(arrayType); // Find the existence of the delimiter in the input string - int pos = 0, prev = 0, count = 0; - while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) + size_t pos = 0, prev = 0; + asUINT count = 0; + while( (pos = str.find(delim, prev)) != string::npos ) { // Add the part to the array array->Resize(array->GetSize()+1); @@ -43,7 +44,7 @@ static CScriptArray *StringSplit(const string &delim, const string &str) // Find the next part count++; - prev = pos + (int)delim.length(); + prev = pos + delim.length(); } // Add the remaining part diff --git a/add_on/weakref/weakref.cpp b/add_on/weakref/weakref.cpp index 385ff71..7d82a15 100644 --- a/add_on/weakref/weakref.cpp +++ b/add_on/weakref/weakref.cpp @@ -226,7 +226,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); @@ -242,7 +242,7 @@ void RegisterScriptWeakRef_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); @@ -332,7 +332,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); @@ -348,7 +348,7 @@ void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+) explicit", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); diff --git a/angelscript/source/as_atomic.cpp b/angelscript/source/as_atomic.cpp index 718f04e..e110b3f 100644 --- a/angelscript/source/as_atomic.cpp +++ b/angelscript/source/as_atomic.cpp @@ -37,7 +37,6 @@ #include "as_atomic.h" BEGIN_AS_NAMESPACE -const asUINT MAX_VALUE = 100000000; asCAtomic::asCAtomic() { @@ -48,7 +47,7 @@ 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 < MAX_VALUE); + asASSERT(value < 1000000); return value; } @@ -57,7 +56,7 @@ 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 < MAX_VALUE); + asASSERT(value < 1000000); value = val; } @@ -66,7 +65,7 @@ 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 < MAX_VALUE); + asASSERT(value < 1000000); return asAtomicInc((int&)value); } @@ -75,7 +74,7 @@ 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 < MAX_VALUE); + asASSERT(value < 1000000); return asAtomicDec((int&)value); } diff --git a/angelscript/source/as_builder.cpp b/angelscript/source/as_builder.cpp index 73c66e6..5d0f29d 100644 --- a/angelscript/source/as_builder.cpp +++ b/angelscript/source/as_builder.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -1602,8 +1602,29 @@ int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScri } #ifndef AS_NO_COMPILER - // Check against class types + // Check against interface types asUINT n; + for (n = 0; n < interfaceDeclarations.GetLength(); n++) + { + if (interfaceDeclarations[n]->name == name && + interfaceDeclarations[n]->typeInfo->nameSpace == ns) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_INTF, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Check against class types for( n = 0; n < classDeclarations.GetLength(); n++ ) { if( classDeclarations[n]->name == name && @@ -2080,10 +2101,12 @@ int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asS asCScriptNode *n = cl->firstChild; - // Skip potential 'final' and 'shared' tokens + // Skip potential decorator tokens while( n->tokenType == ttIdentifier && (file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) || - file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) ) + file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN) || + file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) || + file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) ) { // Report error, because mixin class cannot be final or shared asCString msg; @@ -2921,7 +2944,8 @@ void asCBuilder::CompileInterfaces() // If any of the derived interfaces are found after this interface, then move this to the end of the list for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ ) { - if( intfType->Implements(interfaceDeclarations[m]->typeInfo) ) + if( intfType != interfaceDeclarations[m]->typeInfo && + intfType->Implements(interfaceDeclarations[m]->typeInfo) ) { interfaceDeclarations.RemoveIndex(n); interfaceDeclarations.PushLast(intfDecl); @@ -4762,7 +4786,7 @@ int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCod return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits); } -asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns) +asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns, bool isShared) { // Get the parameter names from the node asCArray parameterNames; @@ -4785,7 +4809,9 @@ asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode // Get the return and parameter types from the funcDef asCString funcName = name; - int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits()); + asSFunctionTraits traits; + traits.SetTrait(asTRAIT_SHARED, isShared); + int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, traits); if( r < 0 ) return 0; @@ -5470,7 +5496,7 @@ void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *ob // TODO: child funcdef: A scope can include a template type, e.g. array int n = scope.FindLast("::"); asCString className = n >= 0 ? scope.SubString(n+2) : scope; - asCString nsName = n >= 0 ? scope.SubString(0, n) : ""; + asCString nsName = n >= 0 ? scope.SubString(0, n) : asCString(""); // If a namespace was specifically defined, then this must be used asSNameSpace *ns = 0; @@ -5954,6 +5980,19 @@ asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCod { if( n->tokenType == ttOpenBracket ) { + if (isImplicitHandle) + { + // Make the type a handle + if (dt.MakeHandle(true, acceptHandleForScope) < 0) + { + if (reportError) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + } + isImplicitHandle = false; + } + // Make sure the sub type can be instantiated if( !dt.CanBeInstantiated() ) { diff --git a/angelscript/source/as_builder.h b/angelscript/source/as_builder.h index 3b2f5c7..9caba65 100644 --- a/angelscript/source/as_builder.h +++ b/angelscript/source/as_builder.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2019 Andreas Jonsson + 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 @@ -217,7 +217,7 @@ protected: 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); + 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); diff --git a/angelscript/source/as_callfunc.cpp b/angelscript/source/as_callfunc.cpp index 58dfaaa..4941967 100644 --- a/angelscript/source/as_callfunc.cpp +++ b/angelscript/source/as_callfunc.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -55,8 +55,7 @@ BEGIN_AS_NAMESPACE int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal) { - memset(internal, 0, sizeof(asSSystemFunctionInterface)); - + internal->Clear(); internal->func = ptr.ptr.f.func; internal->auxiliary = 0; diff --git a/angelscript/source/as_callfunc.h b/angelscript/source/as_callfunc.h index c9bdfc6..8bb6ffe 100644 --- a/angelscript/source/as_callfunc.h +++ b/angelscript/source/as_callfunc.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -119,13 +119,35 @@ struct asSSystemFunctionInterface }; asCArray cleanArgs; - asSSystemFunctionInterface() : 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) {} + 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; @@ -136,12 +158,14 @@ struct asSSystemFunctionInterface hostReturnSize = in.hostReturnSize; paramSize = in.paramSize; takesObjByVal = in.takesObjByVal; - paramAutoHandles = in.paramAutoHandles; returnAutoHandle = in.returnAutoHandle; compositeOffset = in.compositeOffset; isCompositeIndirect = in.isCompositeIndirect; auxiliary = in.auxiliary; + cleanArgs = in.cleanArgs; + paramAutoHandles = in.paramAutoHandles; + return *this; } }; diff --git a/angelscript/source/as_callfunc_arm64.cpp b/angelscript/source/as_callfunc_arm64.cpp index 3e0944d..280b3ed 100644 --- a/angelscript/source/as_callfunc_arm64.cpp +++ b/angelscript/source/as_callfunc_arm64.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2020-2020 Andreas Jonsson + 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 @@ -110,7 +110,7 @@ static inline bool IsRegisterHFA(const asCDataType &type) if( typeInfo == nullptr || (typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 || - type.IsObjectHandle() && type.IsReference() ) + type.IsObjectHandle() || type.IsReference() ) return false; const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0; diff --git a/angelscript/source/as_callfunc_arm64_gcc.S b/angelscript/source/as_callfunc_arm64_gcc.S index b5d5a5d..5ece468 100644 --- a/angelscript/source/as_callfunc_arm64_gcc.S +++ b/angelscript/source/as_callfunc_arm64_gcc.S @@ -1,6 +1,6 @@ // // AngelCode Scripting Library -// Copyright (c) 2020-2020 Andreas Jonsson +// 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 @@ -35,6 +35,10 @@ // Compile with GCC/GAS +#if !defined(AS_MAX_PORTABILITY) + +#if defined(__aarch64__) + .arch armv8-a .text @@ -217,3 +221,7 @@ CallARM64RetInMemory: .cfi_def_cfa_offset 0 ret .cfi_endproc + +#endif /* __aarch64__ */ + +#endif /* !AS_MAX_PORTABILITY */ diff --git a/angelscript/source/as_compiler.cpp b/angelscript/source/as_compiler.cpp index 12700c6..1fa38dd 100644 --- a/angelscript/source/as_compiler.cpp +++ b/angelscript/source/as_compiler.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -1513,7 +1513,8 @@ int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, as else if( ctx->type.dataType.IsNullHandle() ) { // Make sure the argument type can support handles (or is itself a handle) - if( !dt.SupportHandles() && !dt.IsObjectHandle() ) + // Don't allow null handle to be converted to an object type of ASHANDLE here, that would require more logic to call the constructor (which should be handled in ImplicitConversion) + if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) ) { asCString str; str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); @@ -2696,7 +2697,6 @@ bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx // For types that support handles auto should prefer handle // as it is more efficient than making a copy - // TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want? if( newType.SupportHandles() ) newType.MakeHandle(true); @@ -3163,7 +3163,7 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, co } else { - // Call the default constructur, then call the assignment operator + // Call the default constructor, then call the assignment operator asCExprContext ctx(engine); // Call the default constructor here @@ -3812,7 +3812,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr asCExprContext ctx(engine); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); - if( !lctx.type.dataType.IsPrimitive() ) + if( !ctx.type.dataType.IsPrimitive() ) ctx.bc.Instr(asBC_PopPtr); // Release temporary variables used by expression @@ -3904,7 +3904,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr asCExprContext ctx(engine); DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); - if( !lctx.type.dataType.IsPrimitive() ) + if( !ctx.type.dataType.IsPrimitive() ) ctx.bc.Instr(asBC_PopPtr); // Release temporary variables used by expression @@ -4855,7 +4855,7 @@ void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext * { ctx->bc.Instr(asBC_PopPtr); ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); - ctx->type.dataType.MakeReference(true); + ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset)); } return; @@ -5273,7 +5273,7 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo bool isOnHeap = true; if( t.IsPrimitive() || - (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) ) + (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap && !asReference) ) { // Primitives and value types (unless overridden) are allocated on the stack isOnHeap = false; @@ -6106,7 +6106,7 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const // Start by implicitly converting constant values if( ctx->type.isConstant ) { - ImplicitConversionConstant(ctx, to, node, convType); + ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType); ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); return cost; } @@ -6482,7 +6482,7 @@ asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataT name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++); // Register the lambda with the builder for later compilation - asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace); + asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace, outFunc->IsShared()); asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) ); ctx->bc.InstrPTR(asBC_FuncPtr, func); @@ -7174,12 +7174,23 @@ asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDat asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode); // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly - // construct the object through any of the available constructors + // construct the object through any of the available constructors (except those marked as explicit) if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) { asCArray funcs; funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; + // Don't allow use of explicit constructors/factories in implicit conversions + if (convType == asIC_IMPLICIT_CONV) + { + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]); + if (desc->IsExplicit()) + funcs.RemoveIndex(n--); + } + } + asCArray args; args.PushLast(ctx); @@ -8049,17 +8060,28 @@ void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCData // Verify if it is possible if( to.GetSizeInMemoryBytes() == 1 ) { - if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() ) + if( (from->type.dataType.GetSizeInMemoryBytes() == 2 && asBYTE(from->type.GetConstantW()) != from->type.GetConstantW()) || + (from->type.dataType.GetSizeInMemoryBytes() == 4 && asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW()) || + (from->type.dataType.GetSizeInMemoryBytes() == 8 && asBYTE(from->type.GetConstantQW()) != from->type.GetConstantQW()) ) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); + if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantW())); + else if (from->type.dataType.GetSizeInMemoryBytes() == 4) + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); + else if (from->type.dataType.GetSizeInMemoryBytes() == 8) + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantQW())); } else if( to.GetSizeInMemoryBytes() == 2 ) { - if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) + if( (from->type.dataType.GetSizeInMemoryBytes() == 4 && asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) || + (from->type.dataType.GetSizeInMemoryBytes() == 8 && asWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) ) if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); - from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); + if (from->type.dataType.GetSizeInMemoryBytes() == 4) + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); + else if (from->type.dataType.GetSizeInMemoryBytes() == 8) + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantQW())); } else if (to.GetSizeInMemoryBytes() == 4) { @@ -8650,7 +8672,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) { Error(TXT_EXPR_MUST_BE_BOOL, cexpr); e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); - } + } ctype = e.type; if( ProcessPropertyGetAccessor(&e, cexpr) < 0) @@ -8673,44 +8695,22 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) int rr = CompileAssignment(cexpr->next->next, &re); DetermineSingleFunc(&re, cexpr->next->next); - if( lr >= 0 && rr >= 0 ) + if (lr >= 0 && rr >= 0) { // Don't allow any operators on expressions that take address of class method - if( le.IsClassMethod() || re.IsClassMethod() ) + if (le.IsClassMethod() || re.IsClassMethod()) { Error(TXT_INVALID_OP_ON_METHOD, expr); return -1; } - if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 ) + if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0) return -1; - if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 ) + if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0) return -1; bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle; - // Allow a 0 or null in the first case to be implicitly converted to the second type - if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() ) - { - asCDataType to = re.type.dataType; - to.MakeReference(false); - to.MakeReadOnly(true); - ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - else if( le.type.IsNullConstant() ) - { - asCDataType to = re.type.dataType; - to.MakeHandle(true); - ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); - } - - // Allow either case to be converted to const @ if the other is const @ - if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) - { - le.type.dataType.MakeHandleToConst(true); - re.type.dataType.MakeHandleToConst(true); - } - // Allow an anonymous initialization list to be converted to the type in the other condition if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory) { @@ -8727,7 +8727,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV); } - if (le.IsAnonymousInitList() ) + if (le.IsAnonymousInitList()) { Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next); return -1; @@ -8738,6 +8738,81 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) return -1; } + // Try to perform an implicit cast to make the two operands of the same type + // Choose the conversion that is the least costly + if (le.type.dataType != re.type.dataType) + { + asCExprContext tmp(engine); + tmp.type = le.type; + tmp.type.dataType.MakeReference(false); + asUINT costAtoB = ImplicitConversion(&tmp, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, false); + if (!tmp.type.dataType.IsEqualExceptRef(re.type.dataType)) + costAtoB = 0xFFFFFFFF; + tmp.type = re.type; + tmp.type.dataType.MakeReference(false); + asUINT costBtoA = ImplicitConversion(&tmp, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, false); + if (!tmp.type.dataType.IsEqualExceptRef(le.type.dataType)) + costBtoA = 0xFFFFFFFF; + + if (costAtoB < costBtoA && costAtoB != 0xFFFFFFFF) + { + Dereference(&le, true); + ImplicitConversion(&le, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, true); + } + else if (costAtoB > costBtoA && costBtoA != 0xFFFFFFFF) + { + Dereference(&re, true); + ImplicitConversion(&re, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, true); + } + + // If the cost for conversion is the same in both directions we have an ambigious situation, + // which we do not resolve. In that case the script need to perform an explicit conversion + } + + // Allow a 0 to be implicitly converted to the other type + if (le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType()) + { + asCDataType to = re.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(true); + ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + else if( re.type.isConstant && re.type.GetConstantData() == 0 && re.type.dataType.IsIntegerType()) + { + asCDataType to = le.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(true); + ImplicitConversionConstant(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV); + } + + // Allow expression to be converted to handle if the other is handle + if (!le.type.dataType.IsObjectHandle() && re.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo() ) + { + asCDataType dt = le.type.dataType; + dt.MakeHandle(true); + ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV); + } + if (!re.type.dataType.IsObjectHandle() && le.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo()) + { + asCDataType dt = re.type.dataType; + dt.MakeHandle(true); + ImplicitConversion(&re, dt, cexpr->next->next, asIC_IMPLICIT_CONV); + } + + // Allow either case to be converted to const @ if the other is const @ + if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) + { + le.type.dataType.MakeHandleToConst(true); + re.type.dataType.MakeHandleToConst(true); + } + + // Make sure both expressions have the same type + if (!le.type.dataType.IsEqualExceptRefAndConst(re.type.dataType)) + { + Error(TXT_BOTH_MUST_BE_SAME, expr); + return -1; + } + //--------------------------------- // Output the byte code int afterLabel = nextLabel++; @@ -8766,10 +8841,6 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) MergeExprBytecode(ctx, &re); ctx->bc.Label((short)afterLabel); - // Make sure both expressions have the same type - if( le.type.dataType != re.type.dataType ) - Error(TXT_BOTH_MUST_BE_SAME, expr); - // Set the type of the result ctx->type = le.type; } @@ -8810,7 +8881,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) // with a stack offset (i.e. it will not be allowed to use asBC_VAR) if( le.type.isLValue && re.type.isLValue && - le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 && + le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() == 0 && !le.type.isTemporary && !re.type.isTemporary && le.type.dataType == re.type.dataType ) { @@ -8928,6 +8999,9 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) // Release the old temporary variable ReleaseTemporaryVariable(le.type, &ctx->bc); + // Process any deferred arguments in the expressions as these must not survive until after the condition returns + ProcessDeferredParams(ctx); + ctx->bc.InstrINT(asBC_JMP, afterLabel); // Start of the right expression @@ -8950,11 +9024,10 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) // Release the old temporary variable ReleaseTemporaryVariable(re.type, &ctx->bc); - ctx->bc.Label((short)afterLabel); + // Process any deferred arguments in the expressions as these must not survive until after the condition returns + ProcessDeferredParams(ctx); - // Make sure both expressions have the same type - if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) ) - Error(TXT_BOTH_MUST_BE_SAME, expr); + ctx->bc.Label((short)afterLabel); // Set the temporary variable as output ctx->type = rtemp; @@ -9366,7 +9439,7 @@ asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const a // TODO: child funcdef: A scope can include a template type, e.g. array int n = currScope.FindLast("::"); asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope; - asCString nsName = n >= 0 ? currScope.SubString(0, n) : ""; + asCString nsName = n >= 0 ? currScope.SubString(0, n) : asCString(""); // If the scope represents a type that the current class inherits // from then that should be used instead of going through the namespaces @@ -10988,7 +11061,8 @@ int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx) if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) { // Make sure the result is a reference, just as if to a local variable - dt.MakeReference(true); + if( !dt.IsFuncdef() ) + dt.MakeReference(true); // Make sure any property accessor is already evaluated if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 ) diff --git a/angelscript/source/as_config.h b/angelscript/source/as_config.h index 8af33a2..43f28a0 100644 --- a/angelscript/source/as_config.h +++ b/angelscript/source/as_config.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -252,26 +252,27 @@ // compiler is the same for both, when this is so these flags are used to produce the // right code. -// AS_WIN - Microsoft Windows -// AS_LINUX - Linux -// AS_MAC - Apple Macintosh -// AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc) -// AS_XBOX - Microsoft XBox -// AS_XBOX360 - Microsoft XBox 360 -// AS_PSP - Sony Playstation Portable -// AS_PSVITA - Sony Playstation Vita -// AS_PS2 - Sony Playstation 2 -// AS_PS3 - Sony Playstation 3 -// AS_DC - Sega Dreamcast -// AS_GC - Nintendo GameCube -// AS_WII - Nintendo Wii -// AS_WIIU - Nintendo Wii U -// AS_IPHONE - Apple IPhone -// AS_ANDROID - Android -// AS_HAIKU - Haiku -// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc) -// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS) -// AS_SUN - Sun UNIX +// AS_WIN - Microsoft Windows +// AS_LINUX - Linux +// AS_MAC - Apple Macintosh +// AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc) +// AS_XBOX - Microsoft XBox +// AS_XBOX360 - Microsoft XBox 360 +// AS_PSP - Sony Playstation Portable +// AS_PSVITA - Sony Playstation Vita +// AS_PS2 - Sony Playstation 2 +// AS_PS3 - Sony Playstation 3 +// AS_DC - Sega Dreamcast +// AS_GC - Nintendo GameCube +// AS_WII - Nintendo Wii +// AS_WIIU - Nintendo Wii U +// AS_NINTENDOSWITCH - Nintendo Switch +// AS_IPHONE - Apple IPhone +// AS_ANDROID - Android +// AS_HAIKU - Haiku +// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc) +// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS) +// AS_SUN - Sun UNIX @@ -656,6 +657,37 @@ // Native calling conventions are not yet supported #define AS_MAX_PORTABILITY + // Nintendo Switch + // Note, __SWITCH__ is not an official define in the Nintendo dev kit. + // You need to manually add this to the project when compiling for Switch. + #elif defined(__SWITCH__) + #define AS_NINTENDOSWITCH + + #if (!defined(__LP64__)) + #error write me + #else + #define AS_ARM64 + #undef STDCALL + #define STDCALL + + #undef GNU_STYLE_VIRTUAL_METHOD + #undef AS_NO_THISCALL_FUNCTOR_METHOD + + #define HAS_128_BIT_PRIMITIVES + + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #endif + // Marmalade is a cross platform SDK. It uses g++ to compile for iOS and Android #elif defined(__S3E__) #ifndef AS_MARMALADE @@ -757,7 +789,7 @@ #undef STDCALL #define STDCALL - #elif (defined(__arm64__)) + #elif (defined(__aarch64__)) // The IPhone 5S+ uses an ARM64 processor // AngelScript currently doesn't support native calling @@ -779,7 +811,7 @@ #undef COMPLEX_RETURN_MASK #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__arm64__) + #elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__aarch64__) // http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1 #define AS_X64_GCC #undef AS_NO_THISCALL_FUNCTOR_METHOD @@ -1091,30 +1123,40 @@ #undef COMPLEX_RETURN_MASK #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) - #if (defined(_ARM_) || defined(__arm__)) + #if (defined(_ARM_) || defined(__arm__) || defined(__aarch64__) || defined(__AARCH64EL__)) // Android ARM - // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S - #define AS_NO_EXCEPTIONS - #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE - #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 - // The stdcall calling convention is not used on the arm cpu #undef STDCALL #define STDCALL #undef GNU_STYLE_VIRTUAL_METHOD - - #define AS_ARM #undef AS_NO_THISCALL_FUNCTOR_METHOD - #define AS_SOFTFP - #define AS_CALLEE_DESTROY_OBJ_BY_VAL + + #if (!defined(__LP64__)) + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #define AS_ARM + #define AS_SOFTFP + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #elif (defined(__LP64__) || defined(__aarch64__)) + #define AS_ARM64 + + #define HAS_128_BIT_PRIMITIVES + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #endif #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) // Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image. diff --git a/angelscript/source/as_context.cpp b/angelscript/source/as_context.cpp index d578c3f..f78677a 100644 --- a/angelscript/source/as_context.cpp +++ b/angelscript/source/as_context.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -2882,7 +2882,8 @@ void asCContext::ExecuteNext() m_regs.stackPointer = l_sp; m_regs.stackFramePointer = l_fp; - if( !(objType->flags & asOBJ_NOCOUNT) ) + // Update ref counter for object types that require it + if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) ) { // Release previous object held by destination pointer if( *d != 0 && beh->release ) @@ -3912,21 +3913,21 @@ void asCContext::ExecuteNext() } else { - if( func->funcType == asFUNC_SCRIPT ) + if (func->funcType == asFUNC_SCRIPT) { m_regs.programPointer++; CallScriptFunction(func); } - else if( func->funcType == asFUNC_DELEGATE ) + else if (func->funcType == asFUNC_DELEGATE) { // Push the object pointer on the stack. There is always a reserved space for this so // we don't don't need to worry about overflowing the allocated memory buffer - asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); + asASSERT(m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex]); m_regs.stackPointer -= AS_PTR_SIZE; *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); // Call the delegated method - if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) + if (func->funcForDelegate->funcType == asFUNC_SYSTEM) { m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this); @@ -3942,16 +3943,33 @@ void asCContext::ExecuteNext() CallInterfaceMethod(func->funcForDelegate); } } - else + else if (func->funcType == asFUNC_SYSTEM) { - asASSERT( func->funcType == asFUNC_SYSTEM ); - m_regs.stackPointer += CallSystemFunction(func->id, this); // Update program position after the call so the line number // is correct in case the system function queries it m_regs.programPointer++; } + else if (func->funcType == asFUNC_IMPORTED) + { + m_regs.programPointer++; + int funcId = m_engine->importedFunctions[func->id & ~FUNC_IMPORTED]->boundFunctionId; + if (funcId > 0) + CallScriptFunction(m_engine->scriptFunctions[funcId]); + else + { + // Tell the exception handler to clean up the arguments to this method + m_needToCleanupArgs = true; + + SetInternalException(TXT_UNBOUND_FUNCTION); + } + } + else + { + // Should not get here + asASSERT(false); + } } // Extract the values from the context again @@ -4141,7 +4159,8 @@ void asCContext::ExecuteNext() m_regs.stackPointer = l_sp; m_regs.stackFramePointer = l_fp; - if( !(objType->flags & asOBJ_NOCOUNT) ) + // Update ref counter for object types that require it + if( !(objType->flags & (asOBJ_NOCOUNT | asOBJ_VALUE)) ) { // Release previous object held by destination pointer if( *d != 0 && beh->release ) diff --git a/angelscript/source/as_module.cpp b/angelscript/source/as_module.cpp index 5ec5542..365b4b8 100644 --- a/angelscript/source/as_module.cpp +++ b/angelscript/source/as_module.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -1470,7 +1470,8 @@ const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const if( func == 0 ) return 0; asCString *tempString = &asCThreadManager::GetLocalData()->string; - *tempString = func->GetDeclarationStr(); + // TODO: Allow the application to decide if the parameter name should be included or not (requires change in the interface) + *tempString = func->GetDeclarationStr(true, true, false); return tempString->AddressOf(); } @@ -1536,28 +1537,28 @@ int asCModule::UnbindAllImportedFunctions() void asCModule::AddClassType(asCObjectType* type) { m_classTypes.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); } // internal void asCModule::AddEnumType(asCEnumType* type) { m_enumTypes.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); } // internal void asCModule::AddTypeDef(asCTypedefType* type) { m_typeDefs.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); } // internal void asCModule::AddFuncDef(asCFuncdefType* type) { m_funcDefs.PushLast(type); - m_typeLookup.Insert({type->nameSpace, type->name}, type); + m_typeLookup.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); } // internal @@ -1569,8 +1570,8 @@ void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType) m_funcDefs[i] = newType; // Replace it in the lookup map too - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {type->nameSpace, type->name})) + asSMapNode* result = 0; + if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(type->nameSpace, type->name))) { asASSERT( result->value == type ); result->value = newType; @@ -1581,8 +1582,8 @@ void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType) // internal asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const { - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {ns, type})) + asSMapNode* result = 0; + if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type))) { return result->value; } @@ -1592,8 +1593,8 @@ asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const // internal asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const { - asSMapNode* result = nullptr; - if(m_typeLookup.MoveTo(&result, {ns, type})) + asSMapNode* result = 0; + if(m_typeLookup.MoveTo(&result, asSNameSpaceNamePair(ns, type))) { return CastToObjectType(result->value); } @@ -1759,11 +1760,11 @@ int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int l } // interface -int asCModule::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) +int asCModule::CompileFunction(const char* sectionName, const char* code, int lineOffset, asDWORD compileFlags, asIScriptFunction** outFunc) { // Make sure the outFunc is null if the function fails, so the // application doesn't attempt to release a non-existent function - if( outFunc ) + if (outFunc) *outFunc = 0; #ifdef AS_NO_COMPILER @@ -1774,19 +1775,19 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li return asNOT_SUPPORTED; #else // Validate arguments - if( code == 0 || - (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE) ) + if (code == 0 || + (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE)) return asINVALID_ARG; // Only one thread may build at one time // TODO: It should be possible to have multiple threads perform compilations int r = m_engine->RequestBuild(); - if( r < 0 ) + if (r < 0) return r; // Prepare the engine m_engine->PrepareEngine(); - if( m_engine->configFailed ) + if (m_engine->configFailed) { m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); m_engine->BuildCompleted(); @@ -1796,9 +1797,19 @@ int asCModule::CompileFunction(const char *sectionName, const char *code, int li // Compile the single function asCBuilder funcBuilder(m_engine, this); asCString str = code; - asCScriptFunction *func = 0; + asCScriptFunction* func = 0; r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); + if (r >= 0) + { + // Invoke the JIT compiler if it has been set + asIJITCompiler* jit = m_engine->GetJITCompiler(); + if (jit) + { + func->JITCompile(); + } + } + m_engine->BuildCompleted(); if( r >= 0 && outFunc && func ) diff --git a/angelscript/source/as_parser.cpp b/angelscript/source/as_parser.cpp index 2de81aa..db5839e 100644 --- a/angelscript/source/as_parser.cpp +++ b/angelscript/source/as_parser.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2019 Andreas Jonsson + 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 @@ -2488,7 +2488,7 @@ asCScriptNode *asCParser::ParseScript(bool inBlock) UNREACHABLE_RETURN; } -// BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER '{' SCRIPT '}' +// BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER {'::' IDENTIFIER} '{' SCRIPT '}' asCScriptNode *asCParser::ParseNamespace() { asCScriptNode *node = CreateNode(snNamespace); @@ -2505,11 +2505,32 @@ asCScriptNode *asCParser::ParseNamespace() Error(InsteadFound(t1), &t1); } - // TODO: namespace: Allow declaration of multiple nested namespace with namespace A::B::C { } node->AddChildLast(ParseIdentifier()); if( isSyntaxError ) return node; + asCScriptNode *lowestNode = node; GetToken(&t1); + while (t1.type == ttScope) + { + lowestNode->UpdateSourcePos(t1.pos, t1.length); + + asCScriptNode *scopeNode = CreateNode(snScript); + if (scopeNode == 0) + return 0; + lowestNode->AddChildLast(scopeNode); + + lowestNode = CreateNode(snNamespace); + if (lowestNode == 0) + return 0; + + scopeNode->AddChildLast(lowestNode); + lowestNode->AddChildLast(ParseIdentifier()); + if (isSyntaxError) + return node; + + GetToken(&t1); + } + if( t1.type == ttStartStatementBlock ) node->UpdateSourcePos(t1.pos, t1.length); else @@ -2521,7 +2542,7 @@ asCScriptNode *asCParser::ParseNamespace() sToken start = t1; - node->AddChildLast(ParseScript(true)); + lowestNode->AddChildLast(ParseScript(true)); if( !isSyntaxError ) { diff --git a/angelscript/source/as_restore.cpp b/angelscript/source/as_restore.cpp index a6b9abc..6f27314 100644 --- a/angelscript/source/as_restore.cpp +++ b/angelscript/source/as_restore.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -155,7 +155,7 @@ int asCReader::ReadInner() noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; // Read enums - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); module->m_enumTypes.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { @@ -228,7 +228,7 @@ int asCReader::ReadInner() // classTypes[] // First restore the structure names, then the properties - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); module->m_classTypes.Allocate(count, false); for( i = 0; i < count && !error; ++i ) { @@ -299,7 +299,7 @@ int asCReader::ReadInner() if( error ) return asERROR; // Read func defs - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); module->m_funcDefs.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { @@ -401,7 +401,7 @@ int asCReader::ReadInner() if( error ) return asERROR; // Read typedefs - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); module->m_typeDefs.Allocate(count, false); for( i = 0; i < count && !error; i++ ) { @@ -422,7 +422,7 @@ int asCReader::ReadInner() if( error ) return asERROR; // scriptGlobals[] - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); if( count && engine->ep.disallowGlobalVars ) { engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED); @@ -435,7 +435,7 @@ int asCReader::ReadInner() } // scriptFunctions[] - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); for( i = 0; i < count && !error; ++i ) { size_t len = module->m_scriptFunctions.GetLength(); @@ -496,7 +496,7 @@ int asCReader::ReadInner() } // globalFunctions[] - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); for( i = 0; i < count && !error; ++i ) { bool isNew; @@ -516,7 +516,7 @@ int asCReader::ReadInner() if( error ) return asERROR; // bindInformations[] - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); module->m_bindInformations.Allocate(count, false); for( i = 0; i < count && !error; ++i ) { @@ -554,7 +554,7 @@ int asCReader::ReadInner() if( error ) return asERROR; // usedTypes[] - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); usedTypes.Allocate(count, false); for( i = 0; i < count && !error; ++i ) { @@ -660,7 +660,7 @@ void asCReader::ReadUsedStringConstants() asCString str; asUINT count; - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); if (count > 0 && engine->stringFactory == 0) { @@ -681,7 +681,7 @@ void asCReader::ReadUsedFunctions() TimeIt("asCReader::ReadUsedFunctions"); asUINT count; - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); usedFunctions.SetLength(count); if( usedFunctions.GetLength() != count ) { @@ -1026,13 +1026,7 @@ void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **p ReadDataType(&func->returnType); - count = ReadEncodedUInt(); - if( count > 256 ) - { - // Too many arguments, must be something wrong in the file - Error(TXT_INVALID_BYTECODE_d); - return; - } + count = SanityCheck(ReadEncodedUInt(), 256); func->parameterTypes.Allocate(count, false); for( i = 0; i < count; ++i ) { @@ -1253,12 +1247,12 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a ReadByteCode(func); - func->scriptData->variableSpace = ReadEncodedUInt(); + func->scriptData->variableSpace = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->objVariablesOnHeap = 0; if (bits & 8) { - count = ReadEncodedUInt(); + count = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->objVariablePos.Allocate(count, false); func->scriptData->objVariableTypes.Allocate(count, false); for (i = 0; i < count; ++i) @@ -1275,14 +1269,14 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a } } if (count > 0) - func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); + func->scriptData->objVariablesOnHeap = SanityCheck(ReadEncodedUInt(), 10000); - int length = ReadEncodedUInt(); + int length = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->objVariableInfo.SetLength(length); for (i = 0; i < length; ++i) { - func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); - func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].programPos = SanityCheck(ReadEncodedUInt(), 1000000); + func->scriptData->objVariableInfo[i].variableOffset = SanityCheck(ReadEncodedInt(), 10000); asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); func->scriptData->objVariableInfo[i].option = option; if (option != asOBJ_INIT && @@ -1301,19 +1295,19 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a if (bits & 16) { // Read info on try/catch blocks - int length = ReadEncodedUInt(); + int length = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->tryCatchInfo.SetLength(length); for (i = 0; i < length; ++i) { // The program position must be adjusted to be in number of instructions - func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt(); - func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt(); + func->scriptData->tryCatchInfo[i].tryPos = SanityCheck(ReadEncodedUInt(), 1000000); + func->scriptData->tryCatchInfo[i].catchPos = SanityCheck(ReadEncodedUInt(), 1000000); } } if (!noDebugInfo) { - int length = ReadEncodedUInt(); + int length = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->lineNumbers.SetLength(length); if (int(func->scriptData->lineNumbers.GetLength()) != length) { @@ -1326,7 +1320,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a func->scriptData->lineNumbers[i] = ReadEncodedUInt(); // Read the array of script sections - length = ReadEncodedUInt(); + length = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->sectionIdxs.SetLength(length); if (int(func->scriptData->sectionIdxs.GetLength()) != length) { @@ -1351,7 +1345,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a // Read the variable information if (!noDebugInfo) { - int length = ReadEncodedUInt(); + int length = SanityCheck(ReadEncodedUInt(), 1000000); func->scriptData->variables.Allocate(length, false); for (i = 0; i < length; i++) { @@ -1366,7 +1360,7 @@ asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool a func->scriptData->variables.PushLast(var); var->declaredAtProgramPos = ReadEncodedUInt(); - var->stackOffset = ReadEncodedUInt(); + var->stackOffset = SanityCheck(ReadEncodedInt(),10000); ReadString(&var->name); ReadDataType(&var->type); @@ -1551,7 +1545,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern // Read the initial attributes ReadString(&type->name); ReadData(&type->flags, 4); - type->size = ReadEncodedUInt(); + type->size = SanityCheck(ReadEncodedUInt(), 1000000); asCString ns; ReadString(&ns); type->nameSpace = engine->AddNameSpace(ns.AddressOf()); @@ -1613,7 +1607,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern if( type->flags & asOBJ_ENUM ) { asCEnumType *t = CastToEnumType(type); - int count = ReadEncodedUInt(); + int count = SanityCheck(ReadEncodedUInt(), 1000000); bool sharedExists = existingShared.MoveTo(0, type); if( !sharedExists ) { @@ -1695,7 +1689,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern } // interfaces[] / interfaceVFTOffsets[] - int size = ReadEncodedUInt(); + int size = SanityCheck(ReadEncodedUInt(), 1000000); if( sharedExists ) { for( int n = 0; n < size; n++ ) @@ -1725,7 +1719,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern if (!ot->IsInterface()) { - asUINT offset = ReadEncodedUInt(); + asUINT offset = SanityCheck(ReadEncodedUInt(), 1000000); ot->interfaceVFTOffsets.PushLast(offset); } } @@ -1776,7 +1770,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern ot->beh.destruct = 0; } - size = ReadEncodedUInt(); + size = SanityCheck(ReadEncodedUInt(), 1000000); for( int n = 0; n < size; n++ ) { func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); @@ -1880,7 +1874,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern } // methods[] - size = ReadEncodedUInt(); + size = SanityCheck(ReadEncodedUInt(), 1000000); int n; for( n = 0; n < size; n++ ) { @@ -1946,7 +1940,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern } // virtualFunctionTable[] - size = ReadEncodedUInt(); + size = SanityCheck(ReadEncodedUInt(), 1000000); for( n = 0; n < size; n++ ) { bool isNew; @@ -2011,7 +2005,7 @@ void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExtern asASSERT(ot); // properties[] - asUINT size = ReadEncodedUInt(); + asUINT size = SanityCheck(ReadEncodedUInt(), 1000000); for( asUINT n = 0; n < size; n++ ) ReadObjectProperty(ot); } @@ -2039,10 +2033,15 @@ asUINT asCReader::ReadEncodedUInt() return asUINT(qw & 0xFFFFFFFFu); } +int asCReader::ReadEncodedInt() +{ + return int(ReadEncodedUInt()); +} + asQWORD asCReader::ReadEncodedUInt64() { asQWORD i = 0; - asBYTE b; + asBYTE b = 0xFF; // set to 0xFF to better catch if the stream doesn't update the value ReadData(&b, 1); bool isNegative = ( b & 0x80 ) ? true : false; b &= 0x7F; @@ -2113,9 +2112,35 @@ asQWORD asCReader::ReadEncodedUInt64() return i; } +asUINT asCReader::SanityCheck(asUINT val, asUINT max) +{ + if (val > max) + { + Error(TXT_INVALID_BYTECODE_d); + + // Return 0 as default value + return 0; + } + + return val; +} + +int asCReader::SanityCheck(int val, asUINT max) +{ + if (val > int(max) || val < -int(max)) + { + Error(TXT_INVALID_BYTECODE_d); + + // Return 0 as default value + return 0; + } + + return val; +} + void asCReader::ReadString(asCString* str) { - asUINT len = ReadEncodedUInt(); + asUINT len = SanityCheck(ReadEncodedUInt(), 1000000); if( len & 1 ) { asUINT idx = len/2; @@ -2261,7 +2286,7 @@ asCTypeInfo* asCReader::ReadTypeInfo() return 0; } - asUINT numSubTypes = ReadEncodedUInt(); + asUINT numSubTypes = SanityCheck(ReadEncodedUInt(), 100); asCArray subTypes; for( asUINT n = 0; n < numSubTypes; n++ ) { @@ -2422,7 +2447,7 @@ void asCReader::ReadByteCode(asCScriptFunction *func) // Read number of instructions asUINT total, numInstructions; - total = numInstructions = ReadEncodedUInt(); + total = numInstructions = SanityCheck(ReadEncodedUInt(), 1000000); // Reserve some space for the instructions func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false); @@ -2664,7 +2689,7 @@ void asCReader::ReadUsedTypeIds() { TimeIt("asCReader::ReadUsedTypeIds"); - asUINT count = ReadEncodedUInt(); + asUINT count = SanityCheck(ReadEncodedUInt(), 1000000); usedTypeIds.Allocate(count, false); for( asUINT n = 0; n < count; n++ ) { @@ -2678,7 +2703,7 @@ void asCReader::ReadUsedGlobalProps() { TimeIt("asCReader::ReadUsedGlobalProps"); - int c = ReadEncodedUInt(); + int c = SanityCheck(ReadEncodedUInt(), 1000000); usedGlobalProperties.Allocate(c, false); @@ -2719,7 +2744,7 @@ void asCReader::ReadUsedObjectProps() { TimeIt("asCReader::ReadUsedObjectProps"); - asUINT c = ReadEncodedUInt(); + asUINT c = SanityCheck(ReadEncodedUInt(), 1000000); usedObjectProperties.SetLength(c); for( asUINT n = 0; n < c; n++ ) diff --git a/angelscript/source/as_restore.h b/angelscript/source/as_restore.h index 462c2ae..65b71f6 100644 --- a/angelscript/source/as_restore.h +++ b/angelscript/source/as_restore.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2017 Andreas Jonsson + 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 @@ -76,7 +76,10 @@ protected: 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(); diff --git a/angelscript/source/as_scriptengine.cpp b/angelscript/source/as_scriptengine.cpp index d8aa274..4b6b961 100644 --- a/angelscript/source/as_scriptengine.cpp +++ b/angelscript/source/as_scriptengine.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -951,12 +951,16 @@ asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func if( in_func->module != in_mod) return in_func->module; - if (in_func->objectType && in_func->objectType->module && - in_func->objectType->module != in_func->module) + // Check if this is a class method or class factory for a type that has already been moved to a different module + if ((in_func->objectType && in_func->objectType->module && in_func->objectType->module != in_func->module) || + (in_func->IsFactory() && in_func->returnType.GetTypeInfo()->module && in_func->returnType.GetTypeInfo()->module != in_func->module)) { // The object type for the method has already been transferred to // another module, so transfer the method to the same module - in_func->module = in_func->objectType->module; + if (in_func->objectType) + in_func->module = in_func->objectType->module; + else + in_func->module = in_func->returnType.GetTypeInfo()->module; // Make sure the function is listed in the module // The compiler may not have done this earlier, since the object @@ -1370,7 +1374,9 @@ int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *dec for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ ) { asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]]; - if( f->IsSignatureEqual(&func) ) + + // We don't really care if the name of the function is correct + if( f->IsSignatureExceptNameEqual(&func) ) { id = ot->beh.factories[n]; break; @@ -2156,7 +2162,9 @@ int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, as } // Verify the parameters - if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) + // The templates take a hidden parameter with the object type + if( (!(objectType->flags & asOBJ_TEMPLATE) && (func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference())) || + ((objectType->flags & asOBJ_TEMPLATE) && (func.parameterTypes.GetLength() != 2 || !func.parameterTypes[0].IsReference() || !func.parameterTypes[1].IsReference())) ) { if( listPattern ) listPattern->Destroy(this); @@ -4960,7 +4968,8 @@ int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo // Look for ref cast behaviours asCScriptFunction *universalCastFunc = 0; - asCObjectType *from = reinterpret_cast(fromType); + asCObjectType *from = CastToObjectType(reinterpret_cast< asCTypeInfo*>(fromType)); + if( from == 0 ) return asINVALID_ARG; for( asUINT n = 0; n < from->methods.GetLength(); n++ ) { asCScriptFunction *func = scriptFunctions[from->methods[n]]; @@ -5044,7 +5053,8 @@ void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type) { if( type == 0 ) return 0; - asCObjectType *objType = const_cast(reinterpret_cast(type)); + asCObjectType *objType = CastToObjectType(const_cast(reinterpret_cast(type))); + if (objType == 0) return 0; void *ptr = 0; // Check that there is a default factory for ref types @@ -5243,7 +5253,9 @@ void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *type) if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) ) return 0; - asCObjectType *objType = const_cast(reinterpret_cast(type)); + asCObjectType *objType = CastToObjectType(const_cast(reinterpret_cast(type))); + if (objType == 0) + return 0; // Construct the object, but do not call the actual constructor that initializes the members // The initialization will be done by the application afterwards, e.g. through serialization. @@ -5260,9 +5272,11 @@ void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo * { if( origObj == 0 || type == 0 ) return 0; + const asCObjectType* ot = CastToObjectType(const_cast(reinterpret_cast(type))); + if (ot == 0) return 0; + void *newObj = 0; - const asCObjectType *ot = reinterpret_cast(type); if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory) { // Call the script class' default factory with a context @@ -5286,7 +5300,7 @@ void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo * } #endif } - else if( ot->beh.copyconstruct ) + else if(ot->beh.copyconstruct ) { // Manually allocate the memory, then call the copy constructor newObj = CallAlloc(ot); @@ -5351,7 +5365,8 @@ int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITyp // TODO: Warn about invalid call in message stream (make it optional) if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG; - const asCObjectType *objType = reinterpret_cast(type); + const asCObjectType *objType = CastToObjectType(const_cast(reinterpret_cast(type))); + if (objType == 0) return asINVALID_ARG; // If value assign for ref types has been disabled, then don't do anything if the type is a ref type if (ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED)) @@ -5389,7 +5404,7 @@ void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type) // Make sure it is not a null pointer if( obj == 0 || type == 0 ) return; - const asCTypeInfo *ti = static_cast(type); + const asCTypeInfo *ti = reinterpret_cast(type); if (ti->flags & asOBJ_FUNCDEF) { CallObjectMethod(obj, functionBehaviours.beh.addref); @@ -5411,7 +5426,7 @@ void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type) // Make sure it is not a null pointer if( obj == 0 || type == 0 ) return; - const asCTypeInfo *ti = static_cast(type); + const asCTypeInfo *ti = reinterpret_cast(type); if (ti->flags & asOBJ_FUNCDEF) { CallObjectMethod(obj, functionBehaviours.beh.release); diff --git a/angelscript/source/as_scriptfunction.cpp b/angelscript/source/as_scriptfunction.cpp index 2601454..13af3db 100644 --- a/angelscript/source/as_scriptfunction.cpp +++ b/angelscript/source/as_scriptfunction.cpp @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2020 Andreas Jonsson + 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 @@ -306,7 +306,9 @@ int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char asCBuilder builder(engine, 0); asCScriptCode code; code.SetCode("", decl, 0, false); - dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, CastToObjectType(returnType.GetTypeInfo())); + + // For list factory we get the object type from the return type, for list constructor we get it from the object type directly + dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, objectType ? objectType : CastToObjectType(returnType.GetTypeInfo())); node->next = asNEW(asSListPatternDataTypeNode)(dt); node = node->next; @@ -1722,5 +1724,20 @@ bool asCScriptFunction::IsProperty() const return traits.GetTrait(asTRAIT_PROPERTY); } +// internal +bool asCScriptFunction::IsFactory() const +{ + if (objectType) return false; + + asCObjectType* type = CastToObjectType(returnType.GetTypeInfo()); + if (type == 0) return false; + + if (type->name != name) return false; + + if (type->nameSpace != nameSpace) return false; + + return true; +} + END_AS_NAMESPACE diff --git a/angelscript/source/as_scriptfunction.h b/angelscript/source/as_scriptfunction.h index 416f1d0..294c0b9 100644 --- a/angelscript/source/as_scriptfunction.h +++ b/angelscript/source/as_scriptfunction.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2019 Andreas Jonsson + 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 @@ -215,6 +215,7 @@ public: 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(); diff --git a/angelscript/source/as_scriptobject.cpp b/angelscript/source/as_scriptobject.cpp index 17cabd6..260792e 100644 --- a/angelscript/source/as_scriptobject.cpp +++ b/angelscript/source/as_scriptobject.cpp @@ -336,6 +336,7 @@ asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) { refCount.set(1); objType = ot; + objType->AddRef(); isDestructCalled = false; extra = 0; hasRefCountReachedZero = false; @@ -480,6 +481,7 @@ asCScriptObject::~asCScriptObject() } } + objType->Release(); objType = 0; // Something is really wrong if the refCount is not 0 by now diff --git a/angelscript/source/as_symboltable.h b/angelscript/source/as_symboltable.h index a54041d..261b4f3 100644 --- a/angelscript/source/as_symboltable.h +++ b/angelscript/source/as_symboltable.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2012-2015 Andreas Jonsson + 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 diff --git a/angelscript/source/as_texts.h b/angelscript/source/as_texts.h index 8a7acc7..88fb6dd 100644 --- a/angelscript/source/as_texts.h +++ b/angelscript/source/as_texts.h @@ -1,6 +1,6 @@ /* AngelCode Scripting Library - Copyright (c) 2003-2019 Andreas Jonsson + 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 @@ -48,7 +48,7 @@ #define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times" #define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here" -#define TXT_BOTH_MUST_BE_SAME "Both expressions must have the same type" +#define TXT_BOTH_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" @@ -189,6 +189,7 @@ #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."