Browse Source

Updated to AngelScript 2.23.1 WIP.
Fixed crash at exit when a script contains an array of Node handles.
Fixed missing sound type enum in the editor. Added Ambient sound type.
Fixed incorrect occlusion when a drawable is set for no occlusion, but the parent octant is occluded.
Removed unnecessary node lookup in network replication.
Added GetScene() to Component for convenience.

Lasse Öörni 13 years ago
parent
commit
1a9dced05b
49 changed files with 1688 additions and 1338 deletions
  1. 0 3
      Bin/Data/Scripts/Editor/EditorNodeWindow.as
  2. 1 1
      Docs/Urho3D.dox
  3. 2 1
      Engine/Audio/AudioDefs.h
  4. 2 2
      Engine/Audio/SoundSource.cpp
  5. 2 1
      Engine/Engine/AudioAPI.cpp
  6. 1 1
      Engine/Graphics/AnimatedModel.cpp
  7. 1 1
      Engine/Graphics/BillboardSet.cpp
  8. 5 1
      Engine/Graphics/Drawable.cpp
  9. 1 1
      Engine/Graphics/Light.cpp
  10. 7 10
      Engine/Graphics/Octree.cpp
  11. 0 6
      Engine/Graphics/Octree.h
  12. 2 2
      Engine/Graphics/ParticleEmitter.cpp
  13. 1 1
      Engine/Graphics/StaticModel.cpp
  14. 96 75
      Engine/Network/Connection.cpp
  15. 1 1
      Engine/Network/Connection.h
  16. 1 1
      Engine/Physics/CollisionShape.cpp
  17. 2 2
      Engine/Physics/Joint.cpp
  18. 1 1
      Engine/Physics/PhysicsWorld.cpp
  19. 3 3
      Engine/Physics/RigidBody.cpp
  20. 5 0
      Engine/Scene/Component.cpp
  21. 4 3
      Engine/Scene/Component.h
  22. 1 1
      Engine/Scene/SmoothedTransform.cpp
  23. 14 22
      Engine/Script/ScriptInstance.cpp
  24. 1 1
      Readme.txt
  25. 28 25
      ThirdParty/AngelScript/include/angelscript.h
  26. 64 0
      ThirdParty/AngelScript/source/as_array.h
  27. 8 8
      ThirdParty/AngelScript/source/as_builder.cpp
  28. 126 121
      ThirdParty/AngelScript/source/as_bytecode.cpp
  29. 0 3
      ThirdParty/AngelScript/source/as_bytecode.h
  30. 235 235
      ThirdParty/AngelScript/source/as_callfunc_arm_gcc.S
  31. 242 242
      ThirdParty/AngelScript/source/as_callfunc_arm_msvc.asm
  32. 223 152
      ThirdParty/AngelScript/source/as_callfunc_x86.cpp
  33. 222 133
      ThirdParty/AngelScript/source/as_compiler.cpp
  34. 1 1
      ThirdParty/AngelScript/source/as_compiler.h
  35. 1 7
      ThirdParty/AngelScript/source/as_config.h
  36. 175 85
      ThirdParty/AngelScript/source/as_context.cpp
  37. 1 0
      ThirdParty/AngelScript/source/as_context.h
  38. 3 1
      ThirdParty/AngelScript/source/as_criticalsection.h
  39. 2 2
      ThirdParty/AngelScript/source/as_generic.cpp
  40. 2 4
      ThirdParty/AngelScript/source/as_module.cpp
  41. 1 2
      ThirdParty/AngelScript/source/as_objecttype.cpp
  42. 85 97
      ThirdParty/AngelScript/source/as_restore.cpp
  43. 6 13
      ThirdParty/AngelScript/source/as_scriptengine.cpp
  44. 15 9
      ThirdParty/AngelScript/source/as_scriptfunction.cpp
  45. 9 5
      ThirdParty/AngelScript/source/as_scriptfunction.h
  46. 2 0
      ThirdParty/AngelScript/source/as_texts.h
  47. 72 40
      ThirdParty/AngelScript/source/as_thread.cpp
  48. 10 12
      ThirdParty/AngelScript/source/as_thread.h
  49. 1 0
      Urho3D/Urho3D.cpp

+ 0 - 3
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -463,9 +463,6 @@ UIElement@ CreateAttributeEditor(ListView@ list, Array<Serializable@>@ serializa
 
 
             for (uint i = 0; i < enumNames.length; ++i)
             for (uint i = 0; i < enumNames.length; ++i)
             {
             {
-                // Hack: check for certain internal enums and break
-                if (enumNames[i] == "Master")
-                    break;
                 Text@ choice = Text();
                 Text@ choice = Text();
                 choice.SetStyle(uiStyle, "EditorEnumAttributeText");
                 choice.SetStyle(uiStyle, "EditorEnumAttributeText");
                 choice.text = enumNames[i];
                 choice.text = enumNames[i];

+ 1 - 1
Docs/Urho3D.dox

@@ -61,7 +61,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org/) and Horde3D (http://
 
 
 Urho3D uses the following third-party libraries:
 Urho3D uses the following third-party libraries:
 
 
-- AngelScript 2.23.0 (http://www.angelcode.com/angelscript/)
+- AngelScript 2.23.1 WIP (http://www.angelcode.com/angelscript/)
 - Bullet 2.80 (http://www.bulletphysics.org/)
 - Bullet 2.80 (http://www.bulletphysics.org/)
 - FreeType 2.3.12 (http://www.freetype.org/)
 - FreeType 2.3.12 (http://www.freetype.org/)
 - GLee 5.4 (http://elf-stone.com/)
 - GLee 5.4 (http://elf-stone.com/)

+ 2 - 1
Engine/Audio/AudioDefs.h

@@ -27,8 +27,9 @@
 enum SoundType
 enum SoundType
 {
 {
     SOUND_EFFECT = 0,
     SOUND_EFFECT = 0,
-    SOUND_MUSIC,
+    SOUND_AMBIENT,
     SOUND_VOICE,
     SOUND_VOICE,
+    SOUND_MUSIC,
     SOUND_MASTER,
     SOUND_MASTER,
     MAX_SOUND_TYPES
     MAX_SOUND_TYPES
 };
 };

+ 2 - 2
Engine/Audio/SoundSource.cpp

@@ -90,10 +90,10 @@
 
 
 static const String typeNames[] =
 static const String typeNames[] =
 {
 {
-    "Master",
     "Effect",
     "Effect",
-    "Music",
+    "Ambient",
     "Voice",
     "Voice",
+    "Music",
     ""
     ""
 };
 };
 
 

+ 2 - 1
Engine/Engine/AudioAPI.cpp

@@ -44,8 +44,9 @@ void RegisterSoundSources(asIScriptEngine* engine)
 {
 {
     engine->RegisterEnum("SoundType");
     engine->RegisterEnum("SoundType");
     engine->RegisterEnumValue("SoundType", "SOUND_EFFECT", SOUND_EFFECT);
     engine->RegisterEnumValue("SoundType", "SOUND_EFFECT", SOUND_EFFECT);
-    engine->RegisterEnumValue("SoundType", "SOUND_MUSIC", SOUND_MUSIC);
+    engine->RegisterEnumValue("SoundType", "SOUND_AMBIENT", SOUND_AMBIENT);
     engine->RegisterEnumValue("SoundType", "SOUND_VOICE", SOUND_VOICE);
     engine->RegisterEnumValue("SoundType", "SOUND_VOICE", SOUND_VOICE);
+    engine->RegisterEnumValue("SoundType", "SOUND_MUSIC", SOUND_MUSIC);
     engine->RegisterEnumValue("SoundType", "SOUND_MASTER", SOUND_MASTER);
     engine->RegisterEnumValue("SoundType", "SOUND_MASTER", SOUND_MASTER);
     
     
     RegisterSoundSource<SoundSource>(engine, "SoundSource");
     RegisterSoundSource<SoundSource>(engine, "SoundSource");

+ 1 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -83,7 +83,7 @@ void AnimatedModel::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
-    ATTRIBUTE(AnimatedModel, VAR_BOOL, "Can Be Occluded", occludee_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);

+ 1 - 1
Engine/Graphics/BillboardSet.cpp

@@ -77,7 +77,7 @@ void BillboardSet::RegisterObject(Context* context)
     
     
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_BOOL, "Can Be Occluded", occludee_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Scale", IsScaled, SetScaled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Relative Scale", IsScaled, SetScaled, bool, true, AM_DEFAULT);

+ 5 - 1
Engine/Graphics/Drawable.cpp

@@ -172,6 +172,10 @@ void Drawable::SetOccluder(bool enable)
 void Drawable::SetOccludee(bool enable)
 void Drawable::SetOccludee(bool enable)
 {
 {
     occludee_ = enable;
     occludee_ = enable;
+    // If occludee mode is disabled, reinsert to octree root to make sure octant occlusion does not erroneously hide
+    // this drawable
+    if (octant_ && !reinsertionQueued_)
+        octant_->GetRoot()->QueueReinsertion(this);
 }
 }
 
 
 void Drawable::MarkForUpdate()
 void Drawable::MarkForUpdate()
@@ -304,7 +308,7 @@ void Drawable::OnMarkedDirty(Node* node)
 
 
 void Drawable::AddToOctree()
 void Drawable::AddToOctree()
 {
 {
-    Scene* scene = node_->GetScene();
+    Scene* scene = GetScene();
     if (scene)
     if (scene)
     {
     {
         Octree* octree = scene->GetComponent<Octree>();
         Octree* octree = scene->GetComponent<Octree>();

+ 1 - 1
Engine/Graphics/Light.cpp

@@ -117,7 +117,7 @@ void Light::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Attenuation Texture", GetRampTextureAttr, SetRampTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Attenuation Texture", GetRampTextureAttr, SetRampTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Light Shape Texture", GetShapeTextureAttr, SetShapeTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_RESOURCEREF, "Light Shape Texture", GetShapeTextureAttr, SetShapeTextureAttr, ResourceRef, ResourceRef(Texture2D::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
-    ATTRIBUTE(Light, VAR_BOOL, "Can Be Occluded", occludee_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Light, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Per Vertex", perVertex_, false, AM_DEFAULT);
     ATTRIBUTE(Light, VAR_BOOL, "Per Vertex", perVertex_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Light, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);

+ 7 - 10
Engine/Graphics/Octree.cpp

@@ -148,8 +148,10 @@ void Octant::DeleteChild(Octant* octant)
 
 
 void Octant::InsertDrawable(Drawable* drawable, const Vector3& boxCenter, const Vector3& boxSize)
 void Octant::InsertDrawable(Drawable* drawable, const Vector3& boxCenter, const Vector3& boxSize)
 {
 {
-    // If size OK or outside, stop recursion & insert here
-    if (CheckDrawableSize(boxSize) || cullingBox_.IsInside(drawable->GetWorldBoundingBox()) != INSIDE)
+    // If size OK or outside, stop recursion & insert here. Also, if drawable is not occluded, must stay in the root octant
+    // so that hierarchic octant occlusion does not erroneously hide the drawable
+    if ((!drawable->IsOccludee() && this == root_) || CheckDrawableSize(boxSize) ||
+        cullingBox_.IsInside(drawable->GetWorldBoundingBox()) != INSIDE)
     {
     {
         Octant* oldOctant = drawable->octant_;
         Octant* oldOctant = drawable->octant_;
         if (oldOctant != this)
         if (oldOctant != this)
@@ -319,7 +321,6 @@ OBJECTTYPESTATIC(Octree);
 Octree::Octree(Context* context) :
 Octree::Octree(Context* context) :
     Component(context),
     Component(context),
     Octant(BoundingBox(-DEFAULT_OCTREE_SIZE, DEFAULT_OCTREE_SIZE), 0, 0, this),
     Octant(BoundingBox(-DEFAULT_OCTREE_SIZE, DEFAULT_OCTREE_SIZE), 0, 0, this),
-    scene_(0),
     numLevels_(DEFAULT_OCTREE_LEVELS)
     numLevels_(DEFAULT_OCTREE_LEVELS)
 {
 {
     // Resize threaded ray query intermediate result vector according to number of worker threads
     // Resize threaded ray query intermediate result vector according to number of worker threads
@@ -503,7 +504,8 @@ void Octree::QueueUpdate(Drawable* drawable)
 
 
 void Octree::QueueReinsertion(Drawable* drawable)
 void Octree::QueueReinsertion(Drawable* drawable)
 {
 {
-    if (scene_ && scene_->IsThreadedUpdate())
+    Scene* scene = GetScene();
+    if (scene && scene->IsThreadedUpdate())
     {
     {
         MutexLock lock(octreeMutex_);
         MutexLock lock(octreeMutex_);
         drawableReinsertions_.Push(WeakPtr<Drawable>(drawable));
         drawableReinsertions_.Push(WeakPtr<Drawable>(drawable));
@@ -523,11 +525,6 @@ void Octree::DrawDebugGeometry(bool depthTest)
         Octant::DrawDebugGeometry(debug, depthTest);
         Octant::DrawDebugGeometry(debug, depthTest);
 }
 }
 
 
-void Octree::OnNodeSet(Node* node)
-{
-    scene_ = node ? node->GetScene() : 0;
-}
-
 void Octree::UpdateDrawables(const FrameInfo& frame)
 void Octree::UpdateDrawables(const FrameInfo& frame)
 {
 {
     // Let drawables update themselves before reinsertion
     // Let drawables update themselves before reinsertion
@@ -536,7 +533,7 @@ void Octree::UpdateDrawables(const FrameInfo& frame)
     
     
     PROFILE(UpdateDrawables);
     PROFILE(UpdateDrawables);
     
     
-    Scene* scene = node_->GetScene();
+    Scene* scene = GetScene();
     WorkQueue* queue = GetSubsystem<WorkQueue>();
     WorkQueue* queue = GetSubsystem<WorkQueue>();
     scene->BeginThreadedUpdate();
     scene->BeginThreadedUpdate();
     
     

+ 0 - 6
Engine/Graphics/Octree.h

@@ -192,18 +192,12 @@ public:
     /// Add debug geometry to the debug renderer.
     /// Add debug geometry to the debug renderer.
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
     
     
-protected:
-    /// Handle node being assigned.
-    virtual void OnNodeSet(Node* node);
-    
 private:
 private:
     /// Update drawable objects marked for update. Updates are executed in worker threads.
     /// Update drawable objects marked for update. Updates are executed in worker threads.
     void UpdateDrawables(const FrameInfo& frame);
     void UpdateDrawables(const FrameInfo& frame);
     /// Reinsert moved drawable objects into the octree.
     /// Reinsert moved drawable objects into the octree.
     void ReinsertDrawables(const FrameInfo& frame);
     void ReinsertDrawables(const FrameInfo& frame);
     
     
-    /// Scene.
-    Scene* scene_;
     /// Drawable objects that require update.
     /// Drawable objects that require update.
     Vector<WeakPtr<Drawable> > drawableUpdates_;
     Vector<WeakPtr<Drawable> > drawableUpdates_;
     /// Drawable objects that require reinsertion.
     /// Drawable objects that require reinsertion.

+ 2 - 2
Engine/Graphics/ParticleEmitter.cpp

@@ -83,7 +83,7 @@ void ParticleEmitter::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_RESOURCEREF, "Parameter Source", GetParameterSourceAttr, SetParameterSourceAttr, ResourceRef, ResourceRef(XMLFile::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_RESOURCEREF, "Parameter Source", GetParameterSourceAttr, SetParameterSourceAttr, ResourceRef, ResourceRef(XMLFile::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Active", active_, true, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Active", active_, true, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
-    ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Can Be Occluded", occludee_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
@@ -409,7 +409,7 @@ void ParticleEmitter::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = node->GetScene();
+        Scene* scene = GetScene();
         if (scene)
         if (scene)
             SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter, HandleScenePostUpdate));
             SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter, HandleScenePostUpdate));
     }
     }

+ 1 - 1
Engine/Graphics/StaticModel.cpp

@@ -62,7 +62,7 @@ void StaticModel::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_RESOURCEREFLIST, "Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Is Visible", visible_, true, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
-    ATTRIBUTE(StaticModel, VAR_BOOL, "Can Be Occluded", occludee_, true, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(StaticModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ATTRIBUTE(StaticModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(StaticModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);

+ 96 - 75
Engine/Network/Connection.cpp

@@ -223,36 +223,18 @@ void Connection::SendServerUpdate()
     
     
     // Always check the root node (scene) first so that the scene-wide components get sent first,
     // Always check the root node (scene) first so that the scene-wide components get sent first,
     // and all other replicated nodes get added to the dirty set for sending the initial state
     // and all other replicated nodes get added to the dirty set for sending the initial state
-    nodesToProcess_.Insert(scene_->GetID());
-    ProcessNode(scene_);
+    unsigned sceneID = scene_->GetID();
+    nodesToProcess_.Insert(sceneID);
+    ProcessNode(sceneID);
     
     
     // Then go through all dirtied nodes
     // Then go through all dirtied nodes
     nodesToProcess_.Insert(sceneState_.dirtyNodes_);
     nodesToProcess_.Insert(sceneState_.dirtyNodes_);
-    nodesToProcess_.Erase(scene_->GetID()); // Do not process the root node twice
+    nodesToProcess_.Erase(sceneID); // Do not process the root node twice
     
     
     while (nodesToProcess_.Size())
     while (nodesToProcess_.Size())
     {
     {
-        unsigned id = nodesToProcess_.Front();
-        Node* node = scene_->GetNode(id);
-        if (node)
-            ProcessNode(node);
-        else
-        {
-            nodesToProcess_.Erase(id);
-            
-            // If node is dirty, but is no longer found, it has been removed
-            if (sceneState_.nodeStates_.Contains(id))
-            {
-                msg_.Clear();
-                msg_.WriteNetID(id);
-                
-                // Note: we will send MSG_REMOVENODE redundantly for each node in the hierarchy, even if removing the root node
-                // would be enough. However, this may be better due to the client not possibly having updated parenting
-                // information at the time of receiving this message
-                SendMessage(MSG_REMOVENODE, true, true, msg_);
-                sceneState_.nodeStates_.Erase(id);
-            }
-        }
+        unsigned nodeID = nodesToProcess_.Front();
+        ProcessNode(nodeID);
     }
     }
 }
 }
 
 
@@ -1009,31 +991,57 @@ void Connection::HandleAsyncLoadFinished(StringHash eventType, VariantMap& event
     SendMessage(MSG_SCENELOADED, true, true, msg_);
     SendMessage(MSG_SCENELOADED, true, true, msg_);
 }
 }
 
 
-void Connection::ProcessNode(Node* node)
+void Connection::ProcessNode(unsigned nodeID)
 {
 {
-    if (!node || !nodesToProcess_.Contains(node->GetID()))
+    // Check that we have not already processed this due to dependency recursion
+    if (!nodesToProcess_.Erase(nodeID))
         return;
         return;
     
     
-    nodesToProcess_.Erase(node->GetID());
-    
-    // Process depended upon nodes first, if they are dirty
-    const PODVector<Node*>& dependencyNodes = node->GetDependencyNodes();
-    for (PODVector<Node*>::ConstIterator i = dependencyNodes.Begin(); i != dependencyNodes.End(); ++i)
+    // Find replication state for the node
+    HashMap<unsigned, NodeReplicationState>::Iterator i = sceneState_.nodeStates_.Find(nodeID);
+    if (i != sceneState_.nodeStates_.End())
     {
     {
-        if (sceneState_.dirtyNodes_.Contains((*i)->GetID()))
-            ProcessNode(*i);
+        // Replication state found: the node is either be existing or removed
+        Node* node = i->second_.node_;
+        if (!node)
+        {
+            msg_.Clear();
+            msg_.WriteNetID(nodeID);
+            
+            // Note: we will send MSG_REMOVENODE redundantly for each node in the hierarchy, even if removing the root node
+            // would be enough. However, this may be better due to the client not possibly having updated parenting
+            // information at the time of receiving this message
+            SendMessage(MSG_REMOVENODE, true, true, msg_);
+            sceneState_.nodeStates_.Erase(nodeID);
+        }
+        else
+            ProcessExistingNode(node, i->second_);
     }
     }
-    
-    // Check if the client's replication state already has this node
-    HashMap<unsigned, NodeReplicationState>::Iterator i = sceneState_.nodeStates_.Find(node->GetID());
-    if (i != sceneState_.nodeStates_.End())
-        ProcessExistingNode(node, i->second_);
     else
     else
-        ProcessNewNode(node);
+    {
+        // Replication state not found: this is a new node
+        Node* node = scene_->GetNode(nodeID);
+        if (node)
+            ProcessNewNode(node);
+        else
+        {
+            // Did not find the new node (may have been created, then removed immediately): erase from dirty set.
+            sceneState_.dirtyNodes_.Erase(nodeID);
+        }
+    }
 }
 }
 
 
 void Connection::ProcessNewNode(Node* node)
 void Connection::ProcessNewNode(Node* node)
 {
 {
+    // Process depended upon nodes first, if they are dirty
+    const PODVector<Node*>& dependencyNodes = node->GetDependencyNodes();
+    for (PODVector<Node*>::ConstIterator i = dependencyNodes.Begin(); i != dependencyNodes.End(); ++i)
+    {
+        unsigned nodeID = (*i)->GetID();
+        if (sceneState_.dirtyNodes_.Contains(nodeID))
+            ProcessNode(nodeID);
+    }
+    
     msg_.Clear();
     msg_.Clear();
     msg_.WriteNetID(node->GetID());
     msg_.WriteNetID(node->GetID());
     
     
@@ -1084,7 +1092,17 @@ void Connection::ProcessNewNode(Node* node)
 
 
 void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState)
 void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState)
 {
 {
+    // Process depended upon nodes first, if they are dirty
+    const PODVector<Node*>& dependencyNodes = node->GetDependencyNodes();
+    for (PODVector<Node*>::ConstIterator i = dependencyNodes.Begin(); i != dependencyNodes.End(); ++i)
+    {
+        unsigned nodeID = (*i)->GetID();
+        if (sceneState_.dirtyNodes_.Contains(nodeID))
+            ProcessNode(nodeID);
+    }
+    
     // Check from the interest management component, if exists, whether should update
     // Check from the interest management component, if exists, whether should update
+    /// \todo Searching for the component is a potential CPU hotspot. It should be cached
     NetworkPriority* priority = node->GetComponent<NetworkPriority>();
     NetworkPriority* priority = node->GetComponent<NetworkPriority>();
     if (priority && (!priority->GetAlwaysUpdateOwner() || node->GetOwner() != this))
     if (priority && (!priority->GetAlwaysUpdateOwner() || node->GetOwner() != this))
     {
     {
@@ -1153,39 +1171,25 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
         }
         }
     }
     }
     
     
-    // Check for new or changed components
-    const Vector<SharedPtr<Component> >& components = node->GetComponents();
-    for (unsigned i = 0; i < components.Size(); ++i)
+    // Check for removed or changed components
+    for (HashMap<unsigned, ComponentReplicationState>::Iterator i = nodeState.componentStates_.Begin();
+        i != nodeState.componentStates_.End(); )
     {
     {
-        Component* component = components[i];
-        // Check if component is not to be replicated
-        if (component->GetID() >= FIRST_LOCAL_ID)
-            continue;
-        
-        HashMap<unsigned, ComponentReplicationState>::Iterator j = nodeState.componentStates_.Find(component->GetID());
-        if (j == nodeState.componentStates_.End())
+        HashMap<unsigned, ComponentReplicationState>::Iterator current = i++;
+        ComponentReplicationState& componentState = current->second_;
+        Component* component = componentState.component_;
+        if (!component)
         {
         {
-            // New component
-            ComponentReplicationState& componentState = nodeState.componentStates_[component->GetID()];
-            componentState.connection_ = this;
-            componentState.nodeState_ = &nodeState;
-            componentState.component_ = component;
-            component->AddReplicationState(&componentState);
-            
+            // Removed component
             msg_.Clear();
             msg_.Clear();
-            msg_.WriteNetID(node->GetID());
-            msg_.WriteShortStringHash(component->GetType());
-            msg_.WriteNetID(component->GetID());
-            component->WriteInitialDeltaUpdate(msg_);
+            msg_.WriteNetID(current->first_);
             
             
-            SendMessage(MSG_CREATECOMPONENT, true, true, msg_);
+            SendMessage(MSG_REMOVECOMPONENT, true, true, msg_);
+            nodeState.componentStates_.Erase(current);
         }
         }
         else
         else
         {
         {
-            // Existing component
-            ComponentReplicationState& componentState = j->second_;
-            
-            // Check if attributes have changed
+            // Existing component. Check if attributes have changed
             if (componentState.dirtyAttributes_.Count())
             if (componentState.dirtyAttributes_.Count())
             {
             {
                 const Vector<AttributeInfo>* attributes = component->GetNetworkAttributes();
                 const Vector<AttributeInfo>* attributes = component->GetNetworkAttributes();
@@ -1211,7 +1215,7 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
                     SendMessage(MSG_COMPONENTLATESTDATA, true, false, msg_, component->GetID());
                     SendMessage(MSG_COMPONENTLATESTDATA, true, false, msg_, component->GetID());
                 }
                 }
                 
                 
-                // Send deltaupdate if remaining dirty bits, or vars have changed
+                // Send deltaupdate if remaining dirty bits
                 if (componentState.dirtyAttributes_.Count())
                 if (componentState.dirtyAttributes_.Count())
                 {
                 {
                     msg_.Clear();
                     msg_.Clear();
@@ -1226,18 +1230,35 @@ void Connection::ProcessExistingNode(Node* node, NodeReplicationState& nodeState
         }
         }
     }
     }
     
     
-    // Check for removed components
-    for (HashMap<unsigned, ComponentReplicationState>::Iterator i = nodeState.componentStates_.Begin();
-        i != nodeState.componentStates_.End();)
+    // Check for new components
+    if (nodeState.componentStates_.Size() != node->GetNumNetworkComponents())
     {
     {
-        HashMap<unsigned, ComponentReplicationState>::Iterator current = i++;
-        if (!current->second_.component_)
+        const Vector<SharedPtr<Component> >& components = node->GetComponents();
+        for (unsigned i = 0; i < components.Size(); ++i)
         {
         {
-            msg_.Clear();
-            msg_.WriteNetID(current->first_);
+            Component* component = components[i];
+            // Check if component is not to be replicated
+            if (component->GetID() >= FIRST_LOCAL_ID)
+                continue;
             
             
-            SendMessage(MSG_REMOVECOMPONENT, true, true, msg_);
-            nodeState.componentStates_.Erase(current);
+            HashMap<unsigned, ComponentReplicationState>::Iterator j = nodeState.componentStates_.Find(component->GetID());
+            if (j == nodeState.componentStates_.End())
+            {
+                // New component
+                ComponentReplicationState& componentState = nodeState.componentStates_[component->GetID()];
+                componentState.connection_ = this;
+                componentState.nodeState_ = &nodeState;
+                componentState.component_ = component;
+                component->AddReplicationState(&componentState);
+                
+                msg_.Clear();
+                msg_.WriteNetID(node->GetID());
+                msg_.WriteShortStringHash(component->GetType());
+                msg_.WriteNetID(component->GetID());
+                component->WriteInitialDeltaUpdate(msg_);
+                
+                SendMessage(MSG_CREATECOMPONENT, true, true, msg_);
+            }
         }
         }
     }
     }
     
     

+ 1 - 1
Engine/Network/Connection.h

@@ -194,7 +194,7 @@ private:
     /// Handle scene loaded event.
     /// Handle scene loaded event.
     void HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData);
     void HandleAsyncLoadFinished(StringHash eventType, VariantMap& eventData);
     /// Process a node for sending a network update. Recurses to process depended on node(s) first.
     /// Process a node for sending a network update. Recurses to process depended on node(s) first.
-    void ProcessNode(Node* node);
+    void ProcessNode(unsigned nodeID);
     /// Process a node that the client has not yet received.
     /// Process a node that the client has not yet received.
     void ProcessNewNode(Node* node);
     void ProcessNewNode(Node* node);
     /// Process a node that the client has already received.
     /// Process a node that the client has already received.

+ 1 - 1
Engine/Physics/CollisionShape.cpp

@@ -494,7 +494,7 @@ void CollisionShape::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = node->GetScene();
+        Scene* scene = GetScene();
         if (scene)
         if (scene)
         {
         {
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();

+ 2 - 2
Engine/Physics/Joint.cpp

@@ -85,7 +85,7 @@ void Joint::ApplyAttributes()
     {
     {
         otherBody_.Reset();
         otherBody_.Reset();
         
         
-        Scene* scene = node_ ? node_->GetScene() : 0;
+        Scene* scene = GetScene();
         if (scene && otherBodyNodeID_)
         if (scene && otherBodyNodeID_)
         {
         {
             Node* otherNode = scene->GetNode(otherBodyNodeID_);
             Node* otherNode = scene->GetNode(otherBodyNodeID_);
@@ -153,7 +153,7 @@ void Joint::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = node->GetScene();
+        Scene* scene = GetScene();
         if (scene)
         if (scene)
         {
         {
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();

+ 1 - 1
Engine/Physics/PhysicsWorld.cpp

@@ -323,7 +323,7 @@ void PhysicsWorld::OnNodeSet(Node* node)
     // Subscribe to the scene subsystem update, which will trigger the physics simulation step
     // Subscribe to the scene subsystem update, which will trigger the physics simulation step
     if (node)
     if (node)
     {
     {
-        scene_ = node->GetScene();
+        scene_ = GetScene();
         SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
         SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
     }
     }
 }
 }

+ 3 - 3
Engine/Physics/RigidBody.cpp

@@ -149,7 +149,7 @@ void RigidBody::setWorldTransform(const btTransform &worldTrans)
     // If the rigid body is parented to another rigid body, can not set the transform immediately.
     // If the rigid body is parented to another rigid body, can not set the transform immediately.
     // In that case store it to PhysicsWorld for delayed assignment
     // In that case store it to PhysicsWorld for delayed assignment
     Node* parent = node_->GetParent();
     Node* parent = node_->GetParent();
-    if (parent && parent != node_->GetScene())
+    if (parent && parent != GetScene())
         parentRigidBody = parent->GetComponent<RigidBody>();
         parentRigidBody = parent->GetComponent<RigidBody>();
     
     
     if (!parentRigidBody)
     if (!parentRigidBody)
@@ -643,7 +643,7 @@ void RigidBody::OnMarkedDirty(Node* node)
     if (!inSetTransform_ && !hasSmoothedTransform_)
     if (!inSetTransform_ && !hasSmoothedTransform_)
     {
     {
         // Physics operations are not safe from worker threads
         // Physics operations are not safe from worker threads
-        Scene* scene = node->GetScene();
+        Scene* scene = GetScene();
         if (scene && scene->IsThreadedUpdate())
         if (scene && scene->IsThreadedUpdate())
         {
         {
             scene->DelayedMarkedDirty(this);
             scene->DelayedMarkedDirty(this);
@@ -671,7 +671,7 @@ void RigidBody::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = node->GetScene();
+        Scene* scene = GetScene();
         if (scene)
         if (scene)
         {
         {
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();
             physicsWorld_ = scene->GetComponent<PhysicsWorld>();

+ 5 - 0
Engine/Scene/Component.cpp

@@ -73,6 +73,11 @@ void Component::Remove()
         node_->RemoveComponent(this);
         node_->RemoveComponent(this);
 }
 }
 
 
+Scene* Component::GetScene() const
+{
+    return node_ ? node_->GetScene() : 0;
+}
+
 const Matrix3x4& Component::GetWorldTransform() const
 const Matrix3x4& Component::GetWorldTransform() const
 {
 {
     return node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     return node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;

+ 4 - 3
Engine/Scene/Component.h

@@ -27,6 +27,7 @@
 #include "Serializable.h"
 #include "Serializable.h"
 
 
 class Node;
 class Node;
+class Scene;
 
 
 struct ComponentReplicationState;
 struct ComponentReplicationState;
 
 
@@ -56,9 +57,10 @@ public:
     
     
     /// Return ID.
     /// Return ID.
     unsigned GetID() const { return id_; }
     unsigned GetID() const { return id_; }
-    /// Get scene node.
+    /// Return scene node.
     Node* GetNode() const { return node_; }
     Node* GetNode() const { return node_; }
-    
+    /// Return the scene the node belongs to.
+    Scene* GetScene() const;
     /// Return parent node's transform matrix in world space.
     /// Return parent node's transform matrix in world space.
     const Matrix3x4& GetWorldTransform() const;
     const Matrix3x4& GetWorldTransform() const;
     /// Return parent node's position in world space.
     /// Return parent node's position in world space.
@@ -67,7 +69,6 @@ public:
     Quaternion GetWorldRotation() const { return GetWorldTransform().Rotation(); }
     Quaternion GetWorldRotation() const { return GetWorldTransform().Rotation(); }
     /// Return parent node's scale in world space.
     /// Return parent node's scale in world space.
     Vector3 GetWorldScale() const { return GetWorldTransform().Scale(); }
     Vector3 GetWorldScale() const { return GetWorldTransform().Scale(); }
-    
     /// Return components in the same scene node by type.
     /// Return components in the same scene node by type.
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
     void GetComponents(PODVector<Component*>& dest, ShortStringHash type) const;
     /// Return component in the same scene node by type. If there are several, returns the first.
     /// Return component in the same scene node by type. If there are several, returns the first.

+ 1 - 1
Engine/Scene/SmoothedTransform.cpp

@@ -149,7 +149,7 @@ void SmoothedTransform::OnNodeSet(Node* node)
         targetRotation_ = node->GetRotation();
         targetRotation_ = node->GetRotation();
         
         
         // Subscribe to smoothing update
         // Subscribe to smoothing update
-        Scene* scene = node_->GetScene();
+        Scene* scene = GetScene();
         if (scene)
         if (scene)
             SubscribeToEvent(scene, E_UPDATESMOOTHING, HANDLER(SmoothedTransform, HandleUpdateSmoothing));
             SubscribeToEvent(scene, E_UPDATESMOOTHING, HANDLER(SmoothedTransform, HandleUpdateSmoothing));
     }
     }

+ 14 - 22
Engine/Script/ScriptInstance.cpp

@@ -175,11 +175,7 @@ void ScriptInstance::DelayedExecute(float delay, const String& declaration, cons
     
     
     // Make sure we are registered to the scene update event, because delayed calls are executed there
     // Make sure we are registered to the scene update event, because delayed calls are executed there
     if (!methods_[METHOD_UPDATE] && !HasSubscribedToEvent(E_SCENEUPDATE))
     if (!methods_[METHOD_UPDATE] && !HasSubscribedToEvent(E_SCENEUPDATE))
-    {
-        Node* node = GetNode();
-        if (node)
-            SubscribeToEvent(node->GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
-    }
+        SubscribeToEvent(GetScene(), E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
 }
 }
 
 
 void ScriptInstance::ClearDelayedExecute()
 void ScriptInstance::ClearDelayedExecute()
@@ -357,25 +353,21 @@ void ScriptInstance::GetSupportedMethods()
         methods_[i] = scriptFile_->GetMethod(scriptObject_, methodDeclarations[i]);
         methods_[i] = scriptFile_->GetMethod(scriptObject_, methodDeclarations[i]);
     
     
     // Subscribe to the update events as supported
     // Subscribe to the update events as supported
-    Node* node = GetNode();
-    if (node)
+    Scene* scene = GetScene();
+    if (scene)
     {
     {
-        Scene* scene = node->GetScene();
-        if (scene)
+        if (methods_[METHOD_UPDATE])
+            SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
+        if (methods_[METHOD_POSTUPDATE])
+            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
+        
+        PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
+        if (world)
         {
         {
-            if (methods_[METHOD_UPDATE])
-                SubscribeToEvent(scene, E_SCENEUPDATE, HANDLER(ScriptInstance, HandleSceneUpdate));
-            if (methods_[METHOD_POSTUPDATE])
-                SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ScriptInstance, HandleScenePostUpdate));
-            
-            PhysicsWorld* world = scene->GetComponent<PhysicsWorld>();
-            if (world)
-            {
-                if (methods_[METHOD_FIXEDUPDATE])
-                    SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
-                if (methods_[METHOD_FIXEDPOSTUPDATE])
-                    SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
-            }
+            if (methods_[METHOD_FIXEDUPDATE])
+                SubscribeToEvent(world, E_PHYSICSPRESTEP, HANDLER(ScriptInstance, HandlePhysicsPreStep));
+            if (methods_[METHOD_FIXEDPOSTUPDATE])
+                SubscribeToEvent(world, E_PHYSICSPOSTSTEP, HANDLER(ScriptInstance, HandlePhysicsPostStep));
         }
         }
     }
     }
 }
 }

+ 1 - 1
Readme.txt

@@ -36,7 +36,7 @@ Urho3D is greatly inspired by OGRE (http://www.ogre3d.org) and Horde3D
   http://timothylottes.blogspot.com/2011/04/nvidia-fxaa-ii-for-console.html
   http://timothylottes.blogspot.com/2011/04/nvidia-fxaa-ii-for-console.html
 
 
 Urho3D uses the following third-party libraries:
 Urho3D uses the following third-party libraries:
-- AngelScript 2.23.0 (http://www.angelcode.com/angelscript/)
+- AngelScript 2.23.1 WIP (http://www.angelcode.com/angelscript/)
 - Bullet 2.80 (http://www.bulletphysics.org/)
 - Bullet 2.80 (http://www.bulletphysics.org/)
 - FreeType 2.3.12 (http://www.freetype.org/)
 - FreeType 2.3.12 (http://www.freetype.org/)
 - GLee 5.4 (http://elf-stone.com/)
 - GLee 5.4 (http://elf-stone.com/)

+ 28 - 25
ThirdParty/AngelScript/include/angelscript.h

@@ -59,8 +59,8 @@ BEGIN_AS_NAMESPACE
 
 
 // AngelScript version
 // AngelScript version
 
 
-#define ANGELSCRIPT_VERSION        22300
-#define ANGELSCRIPT_VERSION_STRING "2.23.0"
+#define ANGELSCRIPT_VERSION        22301
+#define ANGELSCRIPT_VERSION_STRING "2.23.1 WIP"
 
 
 // Data types
 // Data types
 
 
@@ -1147,8 +1147,8 @@ public:
 // Byte code instructions
 // Byte code instructions
 enum asEBCInstr
 enum asEBCInstr
 {
 {
-	asBC_POP			= 0,
-	asBC_PUSH			= 1,
+	asBC_PopPtr			= 0,
+	asBC_PshGPtr		= 1,
 	asBC_PshC4			= 2,
 	asBC_PshC4			= 2,
 	asBC_PshV4			= 3,
 	asBC_PshV4			= 3,
 	asBC_PSF			= 4,
 	asBC_PSF			= 4,
@@ -1323,22 +1323,25 @@ enum asEBCInstr
 	asBC_ChkNullS		= 173,
 	asBC_ChkNullS		= 173,
 	asBC_ClrHi			= 174,
 	asBC_ClrHi			= 174,
 	asBC_JitEntry		= 175,
 	asBC_JitEntry		= 175,
-	asBC_CallPtr        = 176,
-	asBC_FuncPtr        = 177,
-	asBC_LoadThisR      = 178,
-	asBC_PshV8          = 179,
+	asBC_CallPtr		= 176,
+	asBC_FuncPtr		= 177,
+	asBC_LoadThisR		= 178,
+	asBC_PshV8			= 179,
 	asBC_DIVu			= 180,
 	asBC_DIVu			= 180,
 	asBC_MODu			= 181,
 	asBC_MODu			= 181,
 	asBC_DIVu64			= 182,
 	asBC_DIVu64			= 182,
 	asBC_MODu64			= 183,
 	asBC_MODu64			= 183,
-	asBC_LoadRObjR      = 184,
-	asBC_LoadVObjR      = 185,
+	asBC_LoadRObjR		= 184,
+	asBC_LoadVObjR		= 185,
+	asBC_RefCpyV		= 186,
+	asBC_JLowZ			= 187,
+	asBC_JLowNZ			= 188,
 
 
-	asBC_MAXBYTECODE	= 186,
+	asBC_MAXBYTECODE	= 189,
 
 
 	// Temporary tokens. Can't be output to the final program
 	// Temporary tokens. Can't be output to the final program
-	asBC_VarDecl        = 251,
-	asBC_Block          = 252,
+	asBC_VarDecl		= 251,
+	asBC_Block			= 252,
 	asBC_ObjInfo		= 253,
 	asBC_ObjInfo		= 253,
 	asBC_LINE			= 254,
 	asBC_LINE			= 254,
 	asBC_LABEL			= 255
 	asBC_LABEL			= 255
@@ -1426,8 +1429,8 @@ struct asSBCInfo
 
 
 const asSBCInfo asBCInfo[256] =
 const asSBCInfo asBCInfo[256] =
 {
 {
-	asBCINFO(POP,		W_ARG,			0xFFFF),
-	asBCINFO(PUSH,		W_ARG,			0xFFFF),
+	asBCINFO(PopPtr,	NO_ARG,			-AS_PTR_SIZE),
+	asBCINFO(PshGPtr,	PTR_ARG,		AS_PTR_SIZE),
 	asBCINFO(PshC4,		DW_ARG,			1),
 	asBCINFO(PshC4,		DW_ARG,			1),
 	asBCINFO(PshV4,		rW_ARG,			1),
 	asBCINFO(PshV4,		rW_ARG,			1),
 	asBCINFO(PSF,		rW_ARG,			AS_PTR_SIZE),
 	asBCINFO(PSF,		rW_ARG,			AS_PTR_SIZE),
@@ -1499,8 +1502,8 @@ const asSBCInfo asBCInfo[256] =
 	asBCINFO(CHKREF,	NO_ARG,			0),
 	asBCINFO(CHKREF,	NO_ARG,			0),
 	asBCINFO(GETOBJREF,	W_ARG,			0),
 	asBCINFO(GETOBJREF,	W_ARG,			0),
 	asBCINFO(GETREF,	W_ARG,			0),
 	asBCINFO(GETREF,	W_ARG,			0),
-	asBCINFO(PshNull,   NO_ARG,			AS_PTR_SIZE),
-	asBCINFO(ClrVPtr,   rW_ARG,			0),
+	asBCINFO(PshNull,	NO_ARG,			AS_PTR_SIZE),
+	asBCINFO(ClrVPtr,	rW_ARG,			0),
 	asBCINFO(OBJTYPE,	PTR_ARG,		AS_PTR_SIZE),
 	asBCINFO(OBJTYPE,	PTR_ARG,		AS_PTR_SIZE),
 	asBCINFO(TYPEID,	DW_ARG,			1),
 	asBCINFO(TYPEID,	DW_ARG,			1),
 	asBCINFO(SetV4,		wW_DW_ARG,		0),
 	asBCINFO(SetV4,		wW_DW_ARG,		0),
@@ -1602,20 +1605,20 @@ const asSBCInfo asBCInfo[256] =
 	asBCINFO(ChkNullS,	W_ARG,			0),
 	asBCINFO(ChkNullS,	W_ARG,			0),
 	asBCINFO(ClrHi,		NO_ARG,			0),
 	asBCINFO(ClrHi,		NO_ARG,			0),
 	asBCINFO(JitEntry,	PTR_ARG,		0),
 	asBCINFO(JitEntry,	PTR_ARG,		0),
-	asBCINFO(CallPtr,   rW_ARG,         0xFFFF),
-	asBCINFO(FuncPtr,   PTR_ARG,        AS_PTR_SIZE),
-	asBCINFO(LoadThisR, W_DW_ARG,       0),
+	asBCINFO(CallPtr,	rW_ARG,			0xFFFF),
+	asBCINFO(FuncPtr,	PTR_ARG,		AS_PTR_SIZE),
+	asBCINFO(LoadThisR,	W_DW_ARG,		0),
 	asBCINFO(PshV8,		rW_ARG,			2),
 	asBCINFO(PshV8,		rW_ARG,			2),
 	asBCINFO(DIVu,		wW_rW_rW_ARG,	0),
 	asBCINFO(DIVu,		wW_rW_rW_ARG,	0),
 	asBCINFO(MODu,		wW_rW_rW_ARG,	0),
 	asBCINFO(MODu,		wW_rW_rW_ARG,	0),
 	asBCINFO(DIVu64,	wW_rW_rW_ARG,	0),
 	asBCINFO(DIVu64,	wW_rW_rW_ARG,	0),
 	asBCINFO(MODu64,	wW_rW_rW_ARG,	0),
 	asBCINFO(MODu64,	wW_rW_rW_ARG,	0),
-	asBCINFO(LoadRObjR, rW_W_DW_ARG,    0),
-	asBCINFO(LoadVObjR, rW_W_DW_ARG,    0),
+	asBCINFO(LoadRObjR,	rW_W_DW_ARG,	0),
+	asBCINFO(LoadVObjR,	rW_W_DW_ARG,	0),
+	asBCINFO(RefCpyV,	wW_PTR_ARG,		0),
+	asBCINFO(JLowZ,		DW_ARG,			0),
+	asBCINFO(JLowNZ,	DW_ARG,			0),
 
 
-	asBCINFO_DUMMY(186),
-	asBCINFO_DUMMY(187),
-	asBCINFO_DUMMY(188),
 	asBCINFO_DUMMY(189),
 	asBCINFO_DUMMY(189),
 	asBCINFO_DUMMY(190),
 	asBCINFO_DUMMY(190),
 	asBCINFO_DUMMY(191),
 	asBCINFO_DUMMY(191),

+ 64 - 0
ThirdParty/AngelScript/source/as_array.h

@@ -51,12 +51,14 @@ public:
 	~asCArray();
 	~asCArray();
 
 
 	void   Allocate(size_t numElements, bool keepData);
 	void   Allocate(size_t numElements, bool keepData);
+	void   AllocateNoConstruct(size_t numElements, bool keepData);
 	size_t GetCapacity() const;
 	size_t GetCapacity() const;
 
 
 	void PushLast(const T &element);
 	void PushLast(const T &element);
 	T    PopLast();
 	T    PopLast();
 
 
 	void   SetLength(size_t numElements);
 	void   SetLength(size_t numElements);
+	void   SetLengthNoConstruct(size_t numElements);
 	size_t GetLength() const;
 	size_t GetLength() const;
 
 
 	void Copy(const T*, size_t count);
 	void Copy(const T*, size_t count);
@@ -248,6 +250,59 @@ void asCArray<T>::Allocate(size_t numElements, bool keepData)
 	maxLength = numElements;
 	maxLength = numElements;
 }
 }
 
 
+template <class T>
+void asCArray<T>::AllocateNoConstruct(size_t numElements, bool keepData)
+{
+	// We have 4 situations
+	// 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller
+	// 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes
+	// 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller
+	// 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes
+
+	T *tmp = 0;
+	if( numElements )
+	{
+		if( sizeof(T)*numElements <= 8 )
+			// Use the internal buffer
+			tmp = (T*)buf;
+		else
+			// Allocate the array and construct each of the elements
+			tmp = asNEWARRAY(T,numElements);
+	}
+
+	if( array )
+	{
+		if( array == tmp )
+		{
+			if( keepData )
+			{
+				if( length > numElements )
+					length = numElements;
+			}
+			else
+				length = 0;
+		}
+		else
+		{
+			if( keepData )
+			{
+				if( length > numElements )
+					length = numElements;
+
+				memcpy(tmp, array, sizeof(T)*length);
+			}
+			else
+				length = 0;
+
+			if( array != (T*)buf )
+				asDELETEARRAY(array);
+		}
+	}
+
+	array = tmp;
+	maxLength = numElements;
+}
+
 template <class T>
 template <class T>
 size_t asCArray<T>::GetCapacity() const
 size_t asCArray<T>::GetCapacity() const
 {
 {
@@ -263,6 +318,15 @@ void asCArray<T>::SetLength(size_t numElements)
 	length = numElements;
 	length = numElements;
 }
 }
 
 
+template <class T>
+void asCArray<T>::SetLengthNoConstruct(size_t numElements)
+{
+	if( numElements > maxLength )
+		AllocateNoConstruct(numElements, true);
+
+	length = numElements;
+}
+
 template <class T>
 template <class T>
 void asCArray<T>::Copy(const T *data, size_t count)
 void asCArray<T>::Copy(const T *data, size_t count)
 {
 {

+ 8 - 8
ThirdParty/AngelScript/source/as_builder.cpp

@@ -1409,7 +1409,7 @@ int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, const as
 	decl->objType = st;
 	decl->objType = st;
 
 
 	// Add script classes to the GC
 	// Add script classes to the GC
-	// TODO: optimize: Only add the class to the GC when the module won't use the type anymore
+	// TODO: runtime optimize: Only add the class to the GC when the module won't use the type anymore
 	engine->gc.AddScriptObjectToGC(st, &engine->objectTypeBehaviours);
 	engine->gc.AddScriptObjectToGC(st, &engine->objectTypeBehaviours);
 
 
 	// Use the default script class behaviours
 	// Use the default script class behaviours
@@ -2298,19 +2298,19 @@ void asCBuilder::CompileClasses()
 			{
 			{
 				if( dt.IsObjectHandle() )
 				if( dt.IsObjectHandle() )
 				{
 				{
-					// TODO: optimize: If it is known that the handle can't be involved in a circular reference
-					//                 then this object doesn't need to be marked as garbage collected. 
-					//                 - The application could set a flag when registering the object.
-					//                 - The script classes can be marked as final, then the compiler will 
-					//                   be able to determine whether the class is garbage collected or not.
+					// TODO: runtime optimize: If it is known that the handle can't be involved in a circular reference
+					//                         then this object doesn't need to be marked as garbage collected. 
+					//                         - The application could set a flag when registering the object.
+					//                         - The script classes can be marked as final, then the compiler will 
+					//                           be able to determine whether the class is garbage collected or not.
 
 
 					ot->flags |= asOBJ_GC;
 					ot->flags |= asOBJ_GC;
 					break;
 					break;
 				}
 				}
 				else if( dt.GetObjectType()->flags & asOBJ_GC )
 				else if( dt.GetObjectType()->flags & asOBJ_GC )
 				{
 				{
-					// TODO: optimize: Just because the member type is a potential circle doesn't mean that this one is
-					//                 Only if the object is of a type that can reference this type, either directly or indirectly
+					// TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is
+					//                         Only if the object is of a type that can reference this type, either directly or indirectly
 
 
 					ot->flags |= asOBJ_GC;
 					ot->flags |= asOBJ_GC;
 					break;
 					break;

+ 126 - 121
ThirdParty/AngelScript/source/as_bytecode.cpp

@@ -390,7 +390,7 @@ bool asCByteCode::PostponeInitOfTemp(cByteInstruction *curr, cByteInstruction **
 
 
 bool asCByteCode::RemoveUnusedValue(cByteInstruction *curr, cByteInstruction **next)
 bool asCByteCode::RemoveUnusedValue(cByteInstruction *curr, cByteInstruction **next)
 {
 {
-	// TODO: optimize: Should work for 64bit types as well
+	// TODO: runtime optimize: Should work for 64bit types as well
 
 
 	// The value isn't used for anything
 	// The value isn't used for anything
 	if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
 	if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ||
@@ -414,7 +414,7 @@ bool asCByteCode::RemoveUnusedValue(cByteInstruction *curr, cByteInstruction **n
 		return true;
 		return true;
 	}
 	}
 
 
-	// TODO: optimize: There should be one for doubles as well
+	// TODO: runtime optimize: There should be one for doubles as well
 	// The value is immediately used and then never again
 	// The value is immediately used and then never again
 	if( curr->op == asBC_SetV4 &&
 	if( curr->op == asBC_SetV4 &&
 		curr->next && 
 		curr->next && 
@@ -590,28 +590,17 @@ bool asCByteCode::IsTemporary(short offset)
 
 
 int asCByteCode::Optimize()
 int asCByteCode::Optimize()
 {
 {
-	// TODO: optimize: The optimizer should be able to inline function calls.
-	//                 If the called function has only a few instructions, the function call should be inlined.
-	//                 This is especially useful with the factory stubs used for template types and script classes.
+	// TODO: runtime optimize: The optimizer should be able to inline function calls.
+	//                         If the called function has only a few instructions, the function call should be inlined.
+	//                         This is especially useful with the factory stubs used for template types and script classes.
 
 
-	// TODO: optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call
+	// TODO: runtime optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call
 	
 	
-	// TODO: optimize: A bytecode BC_RefCpyV that copies a handle from a local variable to another local variable
-	//                 can easily substitute the frequently appearing pattern BC_PshV4, BC_PSF, BC_REFCPY, BC_POP
+	// TODO: runtime optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve 
+	//                         loops a lot. How often do these loops really occur?
 
 
-	// TODO: optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve 
-	//                 loops a lot. How often do these loops really occur?
-
-	// TODO: optimize: Script class methods are currently implemented to increase the ref count of the object upon
-	//                 entry, and then release it upon exit. When the method isn't doing anything at all, this is
-	//                 not necessary, as the function could simply do a RET immediately. This optimization is only
-	//                 possible if the code has been built without the line cues, as if the SUSPEND is within the 
-	//                 function, then we can't do this optimization. Of course, this optimization may not be all
-	//                 that useful, since in a real world app, it is probably not very common that empty class 
-	//                 methods are called.
-
-	// TODO: optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no 
-	//                 function calls that can suspend the execution.
+	// TODO: runtime optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no 
+	//                         function calls that can suspend the execution.
 
 
 	cByteInstruction *instr = first;
 	cByteInstruction *instr = first;
 	while( instr )
 	while( instr )
@@ -638,17 +627,63 @@ int asCByteCode::Optimize()
 			instr = GoBack(instr);
 			instr = GoBack(instr);
 		}
 		}
 		// T??, ClrHi -> T??
 		// T??, ClrHi -> T??
-		else if( IsCombination(curr, asBC_TZ, asBC_ClrHi) ||
+		else if( IsCombination(curr, asBC_TZ , asBC_ClrHi) ||
 				 IsCombination(curr, asBC_TNZ, asBC_ClrHi) ||
 				 IsCombination(curr, asBC_TNZ, asBC_ClrHi) ||
-				 IsCombination(curr, asBC_TS, asBC_ClrHi) ||
+				 IsCombination(curr, asBC_TS , asBC_ClrHi) ||
 				 IsCombination(curr, asBC_TNS, asBC_ClrHi) ||
 				 IsCombination(curr, asBC_TNS, asBC_ClrHi) ||
-				 IsCombination(curr, asBC_TP, asBC_ClrHi) ||
+				 IsCombination(curr, asBC_TP , asBC_ClrHi) ||
 				 IsCombination(curr, asBC_TNP, asBC_ClrHi) )
 				 IsCombination(curr, asBC_TNP, asBC_ClrHi) )
 		{
 		{
 			// Remove the ClrHi instruction, since the test instructions always clear the top bytes anyway
 			// Remove the ClrHi instruction, since the test instructions always clear the top bytes anyway
 			DeleteInstruction(instr);
 			DeleteInstruction(instr);
 			instr = GoBack(curr);
 			instr = GoBack(curr);
 		}
 		}
+		// ClrHi, JZ -> JLowZ
+		else if( IsCombination(curr, asBC_ClrHi, asBC_JZ) )
+		{
+			DeleteInstruction(curr);
+			instr->op = asBC_JLowZ;
+			instr = GoBack(instr);
+		}
+		// ClrHi, JNZ -> JLowNZ
+		else if( IsCombination(curr, asBC_ClrHi, asBC_JNZ) )
+		{
+			DeleteInstruction(curr);
+			instr->op = asBC_JLowNZ;
+			instr = GoBack(instr);
+		}
+		// PGA, RDSPtr -> PshGPtr
+		else if( IsCombination(curr, asBC_PGA, asBC_RDSPtr) )
+		{
+			curr->op = asBC_PshGPtr;
+			DeleteInstruction(instr);
+			instr = GoBack(curr);
+		}
+		// ChkRefS, RDSPtr -> RDSPtr, CHKREF
+		else if( IsCombination(curr, asBC_ChkRefS, asBC_RDSPtr) )
+		{
+			// This exchange removes one pointer dereference, and also 
+			// makes it easier to completely remove the CHKREF instruction
+			curr->op = asBC_RDSPtr;
+			instr->op = asBC_CHKREF;
+			instr = GoBack(curr);
+		}
+		// CHKREF, ADDSi -> ADDSi
+		// CHKREF, RDSPtr -> RDSPtr
+		else if( IsCombination(curr, asBC_CHKREF, asBC_ADDSi) ||
+			     IsCombination(curr, asBC_CHKREF, asBC_RDSPtr) )
+		{
+			// As ADDSi & RDSPtr already checks the pointer, the CHKREF instruction is unnecessary
+			DeleteInstruction(curr);
+			instr = GoBack(instr);
+		}
+		// ADDSi, CHKREF -> ADDSi
+		else if( IsCombination(curr, asBC_ADDSi, asBC_CHKREF) )
+		{
+			// As ADDSi is guaranteed to work on valid pointers, then CHKREF is not necessary
+			DeleteInstruction(instr);
+			instr = GoBack(curr);
+		}
 		// PshVPtr 0, ADDSi, PopRPtr -> LoadThisR
 		// PshVPtr 0, ADDSi, PopRPtr -> LoadThisR
 		else if( IsCombination(curr, asBC_PshVPtr, asBC_ADDSi) &&
 		else if( IsCombination(curr, asBC_PshVPtr, asBC_ADDSi) &&
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
@@ -657,7 +692,7 @@ int asCByteCode::Optimize()
 			DeleteInstruction(curr);
 			DeleteInstruction(curr);
 			instr = GoBack(ChangeFirstDeleteNext(instr, asBC_LoadThisR));
 			instr = GoBack(ChangeFirstDeleteNext(instr, asBC_LoadThisR));
 		}
 		}
-		// TODO: Optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0
+		// TODO: runtime optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0
 		// PshVPtr x, ADDSi, PopRPtr -> LoadRObjR
 		// PshVPtr x, ADDSi, PopRPtr -> LoadRObjR
 		else if( IsCombination(curr, asBC_PshVPtr, asBC_ADDSi) &&
 		else if( IsCombination(curr, asBC_PshVPtr, asBC_ADDSi) &&
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) &&
@@ -672,6 +707,24 @@ int asCByteCode::Optimize()
 			DeleteInstruction(instr);
 			DeleteInstruction(instr);
 			instr = GoBack(curr);
 			instr = GoBack(curr);
 		}
 		}
+		// PSF x, REFCPY -> RefCpyV x
+		else if( IsCombination(curr, asBC_PSF, asBC_REFCPY) )
+		{
+			instr->op = asBC_RefCpyV;
+			instr->wArg[0] = curr->wArg[0];
+			instr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc;
+			DeleteInstruction(curr);
+			instr = GoBack(instr);
+		}
+		// PshNull, RefCpyV, PopPtr -> FREE
+		else if( IsCombination(curr, asBC_PshNull, asBC_RefCpyV) &&
+			     IsCombination(instr, asBC_RefCpyV, asBC_PopPtr) )
+		{
+			DeleteInstruction(curr);
+			instr->op = asBC_FREE;
+			DeleteInstruction(instr->next);
+			instr = GoBack(instr);
+		}
 		// PSF x, ADDSi, PopRPtr -> LoadVObjR
 		// PSF x, ADDSi, PopRPtr -> LoadVObjR
 		else if( IsCombination(curr, asBC_PSF, asBC_ADDSi) &&
 		else if( IsCombination(curr, asBC_PSF, asBC_ADDSi) &&
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) )
 		         IsCombination(instr, asBC_ADDSi, asBC_PopRPtr) )
@@ -724,13 +777,13 @@ int asCByteCode::Optimize()
 			DeleteInstruction(instr);
 			DeleteInstruction(instr);
 			instr = GoBack(curr);
 			instr = GoBack(curr);
 		}
 		}
-		// POP a, RET b -> RET b
-		else if( IsCombination(curr, asBC_POP, asBC_RET) )
+		// PopPtr, RET b -> RET b
+		else if( IsCombination(curr, asBC_PopPtr, asBC_RET) )
 		{
 		{
-			// We don't combine the POP+RET because RET first restores
+			// We don't combine the PopPtr+RET because RET first restores
 			// the previous stack pointer and then pops the arguments
 			// the previous stack pointer and then pops the arguments
 
 
-			// Delete POP
+			// Delete PopPtr
 			instr = GoBack(DeleteInstruction(curr));
 			instr = GoBack(DeleteInstruction(curr));
 		}
 		}
 		// Delete JitEntry if the JIT instructions are not supposed to be included
 		// Delete JitEntry if the JIT instructions are not supposed to be included
@@ -762,16 +815,6 @@ int asCByteCode::Optimize()
 			// Delete the first instruction
 			// Delete the first instruction
 			instr = GoBack(DeleteInstruction(curr));
 			instr = GoBack(DeleteInstruction(curr));
 		}
 		}
-		// PUSH a, PUSH b -> PUSH a+b
-		else if( IsCombination(curr, asBC_PUSH, asBC_PUSH) )
-		{
-			// Combine the two PUSH
-			instr->wArg[0] = curr->wArg[0] + instr->wArg[0];
-			// Delete current
-			DeleteInstruction(curr);
-			// Continue with the instruction before the one removed
-			instr = GoBack(instr);
-		}
 		// VAR a, GETREF 0 -> PSF a
 		// VAR a, GETREF 0 -> PSF a
 		else if( IsCombination(curr, asBC_VAR, asBC_GETREF) && instr->wArg[0] == 0 )
 		else if( IsCombination(curr, asBC_VAR, asBC_GETREF) && instr->wArg[0] == 0 )
 		{
 		{
@@ -805,30 +848,24 @@ int asCByteCode::Optimize()
 			InsertBefore(curr, instr);
 			InsertBefore(curr, instr);
 			instr = GoBack(instr);
 			instr = GoBack(instr);
 		}
 		}
-		// PshVPtr y, POP x -> POP x-AS_PTR_SIZE
-		// PSF y    , POP x -> POP x-AS_PTR_SIZE
-		// VAR y    , POP x -> POP x-AS_PTR_SIZE
-		// PshNull  , POP x -> POP x-AS_PTR_SIZE
-		// PshRPtr  , POP x -> POP x-AS_PTR_SIZE
-		else if( (IsCombination(curr, asBC_PshRPtr, asBC_POP) ||
-			      IsCombination(curr, asBC_PSF    , asBC_POP) ||
-				  IsCombination(curr, asBC_VAR    , asBC_POP) || 
-				  IsCombination(curr, asBC_PshVPtr, asBC_POP) ||
-			      IsCombination(curr, asBC_PshNull, asBC_POP)) && 
-				 instr->wArg[0] >= AS_PTR_SIZE )
+		// PshVPtr y, PopPtr -> nothing
+		// PSF y    , PopPtr -> nothing
+		// VAR y    , PopPtr -> nothing
+		// PshNull  , PopPtr -> nothing
+		// PshRPtr  , PopPtr -> nothing
+		else if( IsCombination(curr, asBC_PshRPtr, asBC_PopPtr) ||
+			     IsCombination(curr, asBC_PSF    , asBC_PopPtr) ||
+				 IsCombination(curr, asBC_VAR    , asBC_PopPtr) || 
+				 IsCombination(curr, asBC_PshVPtr, asBC_PopPtr) ||
+			     IsCombination(curr, asBC_PshNull, asBC_PopPtr) )
 		{
 		{
-			// The pop instruction will always only pop a single pointer
-			asASSERT( instr->wArg[0] == AS_PTR_SIZE );
-
 			// A pointer is pushed on the stack then immediately removed
 			// A pointer is pushed on the stack then immediately removed
+			// Remove both instructions as they cancel each other
+			cByteInstruction *instr2 = instr->next;
 			DeleteInstruction(curr);
 			DeleteInstruction(curr);
-			instr->wArg[0] -= AS_PTR_SIZE;
-			instr = GoBack(instr);
+			DeleteInstruction(instr);
+			instr = GoBack(instr2);
 		}
 		}
-		// POP 0 -> remove
-		// PUSH 0 -> remove
-		else if( (curr->op == asBC_POP || curr->op == asBC_PUSH ) && curr->wArg[0] == 0 )  
-			instr = GoBack(DeleteInstruction(curr));
 // Begin PATTERN
 // Begin PATTERN
 		// T**; J** +x -> J** +x
 		// T**; J** +x -> J** +x
 		else if( IsCombination(curr, asBC_TZ , asBC_JZ ) || 
 		else if( IsCombination(curr, asBC_TZ , asBC_JZ ) || 
@@ -869,23 +906,21 @@ int asCByteCode::Optimize()
 			DeleteInstruction(instr->next);
 			DeleteInstruction(instr->next);
 			instr = GoBack(curr);
 			instr = GoBack(curr);
 		}
 		}
-		// PSF, ChkRefS, POP -> ChkNullV
-		else if( (IsCombination(curr, asBC_PSF, asBC_ChkRefS) &&
-		          IsCombination(instr, asBC_ChkRefS, asBC_POP) &&
-		          instr->next->wArg[0] >= AS_PTR_SIZE) )
+		// PSF, ChkRefS, PopPtr -> ChkNullV
+		else if( IsCombination(curr, asBC_PSF, asBC_ChkRefS) &&
+		         IsCombination(instr, asBC_ChkRefS, asBC_PopPtr) )
 		{
 		{
 			curr->op = asBC_ChkNullV;
 			curr->op = asBC_ChkNullV;
 			curr->stackInc = 0;
 			curr->stackInc = 0;
-			// Decrease the number of DWORDs popped
-			instr->next->wArg[0] -= AS_PTR_SIZE;
+			// Delete the PopPtr instruction
+			DeleteInstruction(instr->next);
 			// Delete the ChkRefS instruction
 			// Delete the ChkRefS instruction
 			DeleteInstruction(instr);
 			DeleteInstruction(instr);
 			instr = GoBack(curr);
 			instr = GoBack(curr);
 		}
 		}
-		// PshVPtr, CHKREF, POP -> ChkNullV
-		else if( (IsCombination(curr, asBC_PshVPtr, asBC_CHKREF) &&
-		          IsCombination(instr, asBC_CHKREF, asBC_POP) &&
-		          instr->next->wArg[0] == AS_PTR_SIZE) )
+		// PshVPtr, CHKREF, PopPtr -> ChkNullV
+		else if( IsCombination(curr, asBC_PshVPtr, asBC_CHKREF) &&
+		         IsCombination(instr, asBC_CHKREF, asBC_PopPtr) )
 		{
 		{
 			curr->op = asBC_ChkNullV;
 			curr->op = asBC_ChkNullV;
 			curr->stackInc = 0;
 			curr->stackInc = 0;
@@ -934,6 +969,8 @@ bool asCByteCode::IsInstrJmpOrLabel(cByteInstruction *curr)
 		curr->op == asBC_JMP     ||
 		curr->op == asBC_JMP     ||
 		curr->op == asBC_JZ      ||
 		curr->op == asBC_JZ      ||
 		curr->op == asBC_JNZ     ||
 		curr->op == asBC_JNZ     ||
+		curr->op == asBC_JLowZ   ||
+		curr->op == asBC_JLowNZ  ||
 		curr->op == asBC_LABEL   )
 		curr->op == asBC_LABEL   )
 		return true;
 		return true;
 
 
@@ -992,9 +1029,10 @@ bool asCByteCode::IsTempVarRead(cByteInstruction *curr, int offset)
 
 
 				break;
 				break;
 			}
 			}
-			else if( curr->op == asBC_JZ || curr->op == asBC_JNZ ||
-				     curr->op == asBC_JS || curr->op == asBC_JNS ||
-					 curr->op == asBC_JP || curr->op == asBC_JNP )
+			else if( curr->op == asBC_JZ    || curr->op == asBC_JNZ    ||
+				     curr->op == asBC_JS    || curr->op == asBC_JNS    ||
+					 curr->op == asBC_JP    || curr->op == asBC_JNP    ||
+					 curr->op == asBC_JLowZ || curr->op == asBC_JLowNZ )
 			{
 			{
 				cByteInstruction *dest = 0;
 				cByteInstruction *dest = 0;
 				int label = *((int*)ARG_DW(curr->arg));
 				int label = *((int*)ARG_DW(curr->arg));
@@ -1073,6 +1111,8 @@ bool asCByteCode::IsTempRegUsed(cByteInstruction *curr)
 			curr->op == asBC_TNP      ||
 			curr->op == asBC_TNP      ||
 			curr->op == asBC_JZ       ||
 			curr->op == asBC_JZ       ||
 			curr->op == asBC_JNZ      ||
 			curr->op == asBC_JNZ      ||
+			curr->op == asBC_JLowZ    ||
+			curr->op == asBC_JLowNZ   ||
 			curr->op == asBC_JS       ||
 			curr->op == asBC_JS       ||
 			curr->op == asBC_JNS      ||
 			curr->op == asBC_JNS      ||
 			curr->op == asBC_JP       ||
 			curr->op == asBC_JP       ||
@@ -1104,6 +1144,8 @@ bool asCByteCode::IsTempRegUsed(cByteInstruction *curr)
 			curr->op == asBC_JMP       ||
 			curr->op == asBC_JMP       ||
 			curr->op == asBC_JZ        ||
 			curr->op == asBC_JZ        ||
 			curr->op == asBC_JNZ       ||
 			curr->op == asBC_JNZ       ||
+			curr->op == asBC_JLowZ     ||
+			curr->op == asBC_JLowNZ    ||
 			curr->op == asBC_CMPi      ||
 			curr->op == asBC_CMPi      ||
 			curr->op == asBC_CMPu      ||
 			curr->op == asBC_CMPu      ||
 			curr->op == asBC_CMPf      ||
 			curr->op == asBC_CMPf      ||
@@ -1483,17 +1525,14 @@ int asCByteCode::FindLabel(int label, cByteInstruction *from, cByteInstruction *
 
 
 int asCByteCode::ResolveJumpAddresses()
 int asCByteCode::ResolveJumpAddresses()
 {
 {
-	int pos = 0;
 	cByteInstruction *instr = first;
 	cByteInstruction *instr = first;
 	while( instr )
 	while( instr )
 	{
 	{
-		// The program pointer is updated as the instruction is read
-		pos += instr->GetSize();
-
-		if( instr->op == asBC_JMP || 
-			instr->op == asBC_JZ || instr->op == asBC_JNZ ||
-			instr->op == asBC_JS || instr->op == asBC_JNS || 
-			instr->op == asBC_JP || instr->op == asBC_JNP )
+		if( instr->op == asBC_JMP   || 
+			instr->op == asBC_JZ    || instr->op == asBC_JNZ    ||
+			instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
+			instr->op == asBC_JS    || instr->op == asBC_JNS    || 
+			instr->op == asBC_JP    || instr->op == asBC_JNP    )
 		{
 		{
 			int label = *((int*) ARG_DW(instr->arg));
 			int label = *((int*) ARG_DW(instr->arg));
 			int labelPosOffset;			
 			int labelPosOffset;			
@@ -1641,9 +1680,10 @@ void asCByteCode::PostProcess()
 				AddPath(paths, dest, stackSize);
 				AddPath(paths, dest, stackSize);
 				break;
 				break;
 			}
 			}
-			else if( instr->op == asBC_JZ || instr->op == asBC_JNZ ||
-					 instr->op == asBC_JS || instr->op == asBC_JNS ||
-					 instr->op == asBC_JP || instr->op == asBC_JNP )
+			else if( instr->op == asBC_JZ    || instr->op == asBC_JNZ ||
+					 instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ ||
+					 instr->op == asBC_JS    || instr->op == asBC_JNS ||
+					 instr->op == asBC_JP    || instr->op == asBC_JNP )
 			{
 			{
 				// Find the label that is being jumped to
 				// Find the label that is being jumped to
 				int label = *((int*) ARG_DW(instr->arg));
 				int label = *((int*) ARG_DW(instr->arg));
@@ -1792,7 +1832,7 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
 		fprintf(file, "%5d ", pos);
 		fprintf(file, "%5d ", pos);
 		pos += instr->GetSize();
 		pos += instr->GetSize();
 
 
-		fprintf(file, "%3d %c ", instr->stackSize, instr->marked ? '*' : ' ');
+		fprintf(file, "%3d %c ", instr->stackSize + func->variableSpace, instr->marked ? '*' : ' ');
 
 
 		switch( asBCInfo[instr->op].type )
 		switch( asBCInfo[instr->op].type )
 		{
 		{
@@ -1870,9 +1910,11 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
 
 
 			case asBC_JMP:
 			case asBC_JMP:
 			case asBC_JZ:
 			case asBC_JZ:
+			case asBC_JLowZ:
 			case asBC_JS:
 			case asBC_JS:
 			case asBC_JP:
 			case asBC_JP:
 			case asBC_JNZ:
 			case asBC_JNZ:
+			case asBC_JLowNZ:
 			case asBC_JNS:
 			case asBC_JNS:
 			case asBC_JNP:
 			case asBC_JNP:
 				fprintf(file, "   %-8s %+d              (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg)));
 				fprintf(file, "   %-8s %+d              (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg)));
@@ -1990,43 +2032,6 @@ void asCByteCode::DebugOutput(const char *name, asCScriptEngine *engine, asCScri
 
 
 //=============================================================================
 //=============================================================================
 
 
-// Decrease stack with "numDwords"
-int asCByteCode::Pop(int numDwords)
-{
-	// Only single pointers are popped
-	// TODO: optimize: Change the instruction to be PopPtr and remove the argument
-	asASSERT(numDwords == AS_PTR_SIZE);
-
-	asASSERT(asBCInfo[asBC_POP].type == asBCTYPE_W_ARG);
-
-	if( AddInstruction() < 0 )
-		return 0;
-
-	last->op = asBC_POP;
-	last->wArg[0] = (short)numDwords;
-	last->size = asBCTypeSize[asBCInfo[asBC_POP].type];
-	last->stackInc = -numDwords;
-
-	return last->stackInc;
-}
-
-// Increase stack with "numDwords"
-int asCByteCode::Push(int numDwords)
-{
-	asASSERT(asBCInfo[asBC_PUSH].type == asBCTYPE_W_ARG);
-
-	if( AddInstruction() < 0 )
-		return 0;
-
-	last->op = asBC_PUSH;
-	last->wArg[0] = (short)numDwords;
-	last->size = asBCTypeSize[asBCInfo[asBC_PUSH].type];
-	last->stackInc = numDwords;
-
-	return last->stackInc;
-}
-
-
 int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param)
 int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param)
 {
 {
 	asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);
 	asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG);

+ 0 - 3
ThirdParty/AngelScript/source/as_bytecode.h

@@ -128,9 +128,6 @@ public:
 	int InstrW_FLOAT(asEBCInstr bc, asWORD a, float b);
 	int InstrW_FLOAT(asEBCInstr bc, asWORD a, float b);
 	int InstrW_W(asEBCInstr bc, int w, int b);
 	int InstrW_W(asEBCInstr bc, int w, int b);
 
 
-	int Pop (int numDwords);
-	int Push(int numDwords);
-
 	asCArray<int> lineNumbers;
 	asCArray<int> lineNumbers;
 	int largestStackUsed;
 	int largestStackUsed;
 
 

+ 235 - 235
ThirdParty/AngelScript/source/as_callfunc_arm_gcc.S

@@ -1,235 +1,235 @@
-/*
-  AngelCode Scripting Library
-  Copyright (c) 2003-2009 Andreas Jonsson
-
-  This software is provided 'as-is', without any express or implied
-  warranty. In no event will the authors be held liable for any
-  damages arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any
-  purpose, including commercial applications, and to alter it and
-  redistribute it freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you
-     must not claim that you wrote the original software. If you use
-     this software in a product, an acknowledgment in the product
-     documentation would be appreciated but is not required.
-
-  2. Altered source versions must be plainly marked as such, and
-     must not be misrepresented as being the original software.
-
-  3. This notice may not be removed or altered from any source
-     distribution.
-
-  The original version of this library can be located at:
-  http://www.angelcode.com/angelscript/
-
-  Andreas Jonsson
-  [email protected]
-*/
-
-
-// Assembly routines for the ARM call convention
-// Written by Fredrik Ehnbom in June 2009
-
-// Adapted to GNUC by darktemplar216 in September 2009
-
-#if defined(__arm__) || defined(__ARM__)
-
-.global armFunc
-.global armFuncR0
-.global armFuncR0R1
-.global armFuncObjLast
-.global armFuncR0ObjLast
-    
-armFunc:
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  // arg table
-    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  // function address
-    mov     r8, #0
-
-    beq     nomoreargs
-
-    // Load the first 4 arguments into r0-r3
-    cmp     r7, #4
-    ldrge   r0, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #3*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #4*4
-    ldrge   r3, [r6],#4
-    ble     nomoreargs
-
-    // Load the rest of the arguments onto the stack
-    sub     r7, r7, #4*4    // skip the 4 registers already loaded into r0-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-stackargsloop:
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     stackargsloop
-nomoreargs:
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-
-armFuncObjLast:
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  // arg table
-    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  // function address
-    mov     r8, #0
-
-    mov     r0, r3          // objlast. might get overwritten
-    str     r3, [sp, #-4]!  // objlast again.
-
-    beq     nomoreargsarmFuncObjLast
-
-    // Load the first 4 arguments into r0-r3
-    cmp     r7, #4
-    ldrge   r0, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r1, [r6],#4
-    ldrlt   r1, [sp]    
-    cmp     r7, #3*4
-    ldrge   r2, [r6],#4
-    ldrlt   r2, [sp]
-    cmp     r7, #4*4
-    ldrge   r3, [r6],#4
-    ldrlt   r3, [sp]
-    ble     nomoreargsarmFuncObjLast
-
-    // Load the rest of the arguments onto the stack
-    sub     r7, r7, #4*4    // skip the 4 registers already loaded into r0-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-stackargslooparmFuncObjLast:
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     stackargslooparmFuncObjLast
-nomoreargsarmFuncObjLast:
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    add     sp, sp, #4
-    ldmia   sp!, {r4-r8, pc}
-
-armFuncR0ObjLast:
-    stmdb   sp!, {r4-r8, lr}
-    ldr     r7, [sp,#6*4]
-    str     r7, [sp,#-4]!
-
-    mov     r6, r0  // arg table
-    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  // function address
-    mov     r8, #0
-
-    mov     r0, r3      // r0 explicitly set
-    ldr     r1, [sp]    // objlast.  might get overwritten
-
-    beq     nomoreargsarmFuncR0ObjLast
-
-    // Load the first 3 arguments into r1-r3
-    cmp     r7, #1*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r2, [r6],#4
-    ldrlt   r2, [sp]
-    cmp     r7, #3*4
-    ldrge   r3, [r6],#4
-    ldrlt   r3, [sp]
-    ble     nomoreargsarmFuncR0ObjLast
-
-    // Load the rest of the arguments onto the stack
-    sub     r7, r7, #3*4    // skip the 3 registers already loaded into r1-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-stackargslooparmFuncR0ObjLast:
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     stackargslooparmFuncR0ObjLast
-nomoreargsarmFuncR0ObjLast:
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    add     sp, sp, #4
-    ldmia   sp!, {r4-r8, pc}
-
-
-armFuncR0:
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  // arg table
-    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  // function address
-    mov     r8, #0
-
-    mov     r0, r3  // r0 explicitly set
-
-    beq     nomoreargsarmFuncR0
-
-    // Load the first 3 arguments into r1-r3
-    cmp     r7, #1*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #3*4
-    ldrge   r3, [r6],#4
-    ble     nomoreargsarmFuncR0
-
-    // Load the rest of the arguments onto the stack
-    sub     r7, r7, #3*4    // skip the 3 registers already loaded into r1-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-stackargslooparmFuncR0:
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     stackargslooparmFuncR0
-nomoreargsarmFuncR0:
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-
-
-armFuncR0R1:
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  // arg table
-    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  // function address
-    mov     r8, #0
-
-    mov     r0, r3          // r0 explicitly set
-    ldr     r1, [sp, #6*4]  // r1 explicitly set too
-
-    beq     nomoreargsarmFuncR0R1
-
-    // Load the first 2 arguments into r2-r3
-    cmp     r7, #1*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r3, [r6],#4
-    ble     nomoreargsarmFuncR0R1
-
-    // Load the rest of the arguments onto the stack
-    sub     r7, r7, #2*4    // skip the 2 registers already loaded into r2-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-stackargslooparmFuncR0R1:
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     stackargslooparmFuncR0R1
-nomoreargsarmFuncR0R1:
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-
-#endif
+/*
+  AngelCode Scripting Library
+  Copyright (c) 2003-2009 Andreas Jonsson
+
+  This software is provided 'as-is', without any express or implied
+  warranty. In no event will the authors be held liable for any
+  damages arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any
+  purpose, including commercial applications, and to alter it and
+  redistribute it freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you
+     must not claim that you wrote the original software. If you use
+     this software in a product, an acknowledgment in the product
+     documentation would be appreciated but is not required.
+
+  2. Altered source versions must be plainly marked as such, and
+     must not be misrepresented as being the original software.
+
+  3. This notice may not be removed or altered from any source
+     distribution.
+
+  The original version of this library can be located at:
+  http://www.angelcode.com/angelscript/
+
+  Andreas Jonsson
+  [email protected]
+*/
+
+
+// Assembly routines for the ARM call convention
+// Written by Fredrik Ehnbom in June 2009
+
+// Adapted to GNUC by darktemplar216 in September 2009
+
+#if defined(__arm__) || defined(__ARM__)
+
+.global armFunc
+.global armFuncR0
+.global armFuncR0R1
+.global armFuncObjLast
+.global armFuncR0ObjLast
+    
+armFunc:
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  // arg table
+    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  // function address
+    mov     r8, #0
+
+    beq     nomoreargs
+
+    // Load the first 4 arguments into r0-r3
+    cmp     r7, #4
+    ldrge   r0, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #3*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #4*4
+    ldrge   r3, [r6],#4
+    ble     nomoreargs
+
+    // Load the rest of the arguments onto the stack
+    sub     r7, r7, #4*4    // skip the 4 registers already loaded into r0-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+stackargsloop:
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     stackargsloop
+nomoreargs:
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+
+armFuncObjLast:
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  // arg table
+    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  // function address
+    mov     r8, #0
+
+    mov     r0, r3          // objlast. might get overwritten
+    str     r3, [sp, #-4]!  // objlast again.
+
+    beq     nomoreargsarmFuncObjLast
+
+    // Load the first 4 arguments into r0-r3
+    cmp     r7, #4
+    ldrge   r0, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r1, [r6],#4
+    ldrlt   r1, [sp]    
+    cmp     r7, #3*4
+    ldrge   r2, [r6],#4
+    ldrlt   r2, [sp]
+    cmp     r7, #4*4
+    ldrge   r3, [r6],#4
+    ldrlt   r3, [sp]
+    ble     nomoreargsarmFuncObjLast
+
+    // Load the rest of the arguments onto the stack
+    sub     r7, r7, #4*4    // skip the 4 registers already loaded into r0-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+stackargslooparmFuncObjLast:
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     stackargslooparmFuncObjLast
+nomoreargsarmFuncObjLast:
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    add     sp, sp, #4
+    ldmia   sp!, {r4-r8, pc}
+
+armFuncR0ObjLast:
+    stmdb   sp!, {r4-r8, lr}
+    ldr     r7, [sp,#6*4]
+    str     r7, [sp,#-4]!
+
+    mov     r6, r0  // arg table
+    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  // function address
+    mov     r8, #0
+
+    mov     r0, r3      // r0 explicitly set
+    ldr     r1, [sp]    // objlast.  might get overwritten
+
+    beq     nomoreargsarmFuncR0ObjLast
+
+    // Load the first 3 arguments into r1-r3
+    cmp     r7, #1*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r2, [r6],#4
+    ldrlt   r2, [sp]
+    cmp     r7, #3*4
+    ldrge   r3, [r6],#4
+    ldrlt   r3, [sp]
+    ble     nomoreargsarmFuncR0ObjLast
+
+    // Load the rest of the arguments onto the stack
+    sub     r7, r7, #3*4    // skip the 3 registers already loaded into r1-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+stackargslooparmFuncR0ObjLast:
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     stackargslooparmFuncR0ObjLast
+nomoreargsarmFuncR0ObjLast:
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    add     sp, sp, #4
+    ldmia   sp!, {r4-r8, pc}
+
+
+armFuncR0:
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  // arg table
+    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  // function address
+    mov     r8, #0
+
+    mov     r0, r3  // r0 explicitly set
+
+    beq     nomoreargsarmFuncR0
+
+    // Load the first 3 arguments into r1-r3
+    cmp     r7, #1*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #3*4
+    ldrge   r3, [r6],#4
+    ble     nomoreargsarmFuncR0
+
+    // Load the rest of the arguments onto the stack
+    sub     r7, r7, #3*4    // skip the 3 registers already loaded into r1-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+stackargslooparmFuncR0:
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     stackargslooparmFuncR0
+nomoreargsarmFuncR0:
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+
+
+armFuncR0R1:
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  // arg table
+    movs    r7, r1  // arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  // function address
+    mov     r8, #0
+
+    mov     r0, r3          // r0 explicitly set
+    ldr     r1, [sp, #6*4]  // r1 explicitly set too
+
+    beq     nomoreargsarmFuncR0R1
+
+    // Load the first 2 arguments into r2-r3
+    cmp     r7, #1*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r3, [r6],#4
+    ble     nomoreargsarmFuncR0R1
+
+    // Load the rest of the arguments onto the stack
+    sub     r7, r7, #2*4    // skip the 2 registers already loaded into r2-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+stackargslooparmFuncR0R1:
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     stackargslooparmFuncR0R1
+nomoreargsarmFuncR0R1:
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+
+#endif

+ 242 - 242
ThirdParty/AngelScript/source/as_callfunc_arm_msvc.asm

@@ -1,242 +1,242 @@
-;
-;  AngelCode Scripting Library
-;  Copyright (c) 2003-2009 Andreas Jonsson
-;
-;  This software is provided 'as-is', without any express or implied
-;  warranty. In no event will the authors be held liable for any
-;  damages arising from the use of this software.
-;
-;  Permission is granted to anyone to use this software for any
-;  purpose, including commercial applications, and to alter it and
-;  redistribute it freely, subject to the following restrictions:
-;
-;  1. The origin of this software must not be misrepresented; you
-;     must not claim that you wrote the original software. If you use
-;     this software in a product, an acknowledgment in the product
-;     documentation would be appreciated but is not required.
-;
-;  2. Altered source versions must be plainly marked as such, and
-;     must not be misrepresented as being the original software.
-;
-;  3. This notice may not be removed or altered from any source
-;     distribution.
-;
-;  The original version of this library can be located at:
-;  http://www.angelcode.com/angelscript/
-;
-;  Andreas Jonsson
-;  [email protected]
-;
-
-
-; Assembly routines for the ARM call convention
-; Written by Fredrik Ehnbom in June 2009
-
-; MSVC currently doesn't support inline assembly for the ARM platform
-; so this separate file is needed.
-
-
-    AREA	|.rdata|, DATA, READONLY
-    EXPORT |armFunc|
-    EXPORT armFuncR0
-    EXPORT armFuncR0R1
-    EXPORT armFuncObjLast
-    EXPORT armFuncR0ObjLast
-    
-
-    AREA	|.text|, CODE, ARM
-
-|armFunc| PROC
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  ; arg table
-    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  ; function address
-    mov     r8, #0
-
-    beq     |nomoreargs|
-
-    ; Load the first 4 arguments into r0-r3
-    cmp     r7, #4
-    ldrge   r0, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #3*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #4*4
-    ldrge   r3, [r6],#4
-    ble     |nomoreargs|
-
-    ; Load the rest of the arguments onto the stack
-    sub     r7, r7, #4*4    ; skip the 4 registers already loaded into r0-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-|stackargsloop|
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     |stackargsloop|
-|nomoreargs|
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-    ENDP
-
-armFuncObjLast PROC
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  ; arg table
-    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  ; function address
-    mov     r8, #0
-
-    mov     r0, r3          ; objlast. might get overwritten
-    str     r3, [sp, #-4]!  ; objlast again.
-
-    beq     |nomoreargs@armFuncObjLast|
-
-    ; Load the first 4 arguments into r0-r3
-    cmp     r7, #4
-    ldrge   r0, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r1, [r6],#4
-    ldrlt   r1, [sp]    
-    cmp     r7, #3*4
-    ldrge   r2, [r6],#4
-    ldrlt   r2, [sp]
-    cmp     r7, #4*4
-    ldrge   r3, [r6],#4
-    ldrlt   r3, [sp]
-    ble     |nomoreargs@armFuncObjLast|
-
-    ; Load the rest of the arguments onto the stack
-    sub     r7, r7, #4*4    ; skip the 4 registers already loaded into r0-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-|stackargsloop@armFuncObjLast|
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     |stackargsloop@armFuncObjLast|
-|nomoreargs@armFuncObjLast|
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    add     sp, sp, #4
-    ldmia   sp!, {r4-r8, pc}
-    ENDP
-
-armFuncR0ObjLast PROC
-    stmdb   sp!, {r4-r8, lr}
-    ldr     r7, [sp,#6*4]
-    str     r7, [sp,#-4]!
-
-    mov     r6, r0  ; arg table
-    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  ; function address
-    mov     r8, #0
-
-    mov     r0, r3      ; r0 explicitly set
-    ldr     r1, [sp]    ; objlast.  might get overwritten
-
-    beq     |nomoreargs@armFuncR0ObjLast|
-
-    ; Load the first 3 arguments into r1-r3
-    cmp     r7, #1*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r2, [r6],#4
-    ldrlt   r2, [sp]
-    cmp     r7, #3*4
-    ldrge   r3, [r6],#4
-    ldrlt   r3, [sp]
-    ble     |nomoreargs@armFuncR0ObjLast|
-
-    ; Load the rest of the arguments onto the stack
-    sub     r7, r7, #3*4    ; skip the 3 registers already loaded into r1-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-|stackargsloop@armFuncR0ObjLast|
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     |stackargsloop@armFuncR0ObjLast|
-|nomoreargs@armFuncR0ObjLast|
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    add     sp, sp, #4
-    ldmia   sp!, {r4-r8, pc}
-    ENDP
-
-armFuncR0 PROC
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  ; arg table
-    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  ; function address
-    mov     r8, #0
-
-    mov     r0, r3  ; r0 explicitly set
-
-    beq     |nomoreargs@armFuncR0|
-
-    ; Load the first 3 arguments into r1-r3
-    cmp     r7, #1*4
-    ldrge   r1, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #3*4
-    ldrge   r3, [r6],#4
-    ble     |nomoreargs@armFuncR0|
-
-    ; Load the rest of the arguments onto the stack
-    sub     r7, r7, #3*4    ; skip the 3 registers already loaded into r1-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-|stackargsloop@armFuncR0|
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     |stackargsloop@armFuncR0|
-|nomoreargs@armFuncR0|
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-    ENDP
-
-armFuncR0R1 PROC
-    stmdb   sp!, {r4-r8, lr}
-    mov     r6, r0  ; arg table
-    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
-    mov     r4, r2  ; function address
-    mov     r8, #0
-
-    mov     r0, r3          ; r0 explicitly set
-    ldr     r1, [sp, #6*4]  ; r1 explicitly set too
-
-    beq     |nomoreargs@armFuncR0R1|
-
-    ; Load the first 2 arguments into r2-r3
-    cmp     r7, #1*4
-    ldrge   r2, [r6],#4
-    cmp     r7, #2*4
-    ldrge   r3, [r6],#4
-    ble     |nomoreargs@armFuncR0R1|
-
-    ; Load the rest of the arguments onto the stack
-    sub     r7, r7, #2*4    ; skip the 2 registers already loaded into r2-r3
-    sub     sp, sp, r7
-    mov     r8, r7
-|stackargsloop@armFuncR0R1|
-    ldr     r5, [r6], #4
-    str     r5, [sp], #4
-    subs    r7, r7, #4
-    bne     |stackargsloop@armFuncR0R1|
-|nomoreargs@armFuncR0R1|
-    sub     sp, sp, r8
-    blx     r4
-    add     sp, sp, r8
-    ldmia   sp!, {r4-r8, pc}
-    ENDP
-
-    END
+;
+;  AngelCode Scripting Library
+;  Copyright (c) 2003-2009 Andreas Jonsson
+;
+;  This software is provided 'as-is', without any express or implied
+;  warranty. In no event will the authors be held liable for any
+;  damages arising from the use of this software.
+;
+;  Permission is granted to anyone to use this software for any
+;  purpose, including commercial applications, and to alter it and
+;  redistribute it freely, subject to the following restrictions:
+;
+;  1. The origin of this software must not be misrepresented; you
+;     must not claim that you wrote the original software. If you use
+;     this software in a product, an acknowledgment in the product
+;     documentation would be appreciated but is not required.
+;
+;  2. Altered source versions must be plainly marked as such, and
+;     must not be misrepresented as being the original software.
+;
+;  3. This notice may not be removed or altered from any source
+;     distribution.
+;
+;  The original version of this library can be located at:
+;  http://www.angelcode.com/angelscript/
+;
+;  Andreas Jonsson
+;  [email protected]
+;
+
+
+; Assembly routines for the ARM call convention
+; Written by Fredrik Ehnbom in June 2009
+
+; MSVC currently doesn't support inline assembly for the ARM platform
+; so this separate file is needed.
+
+
+    AREA	|.rdata|, DATA, READONLY
+    EXPORT |armFunc|
+    EXPORT armFuncR0
+    EXPORT armFuncR0R1
+    EXPORT armFuncObjLast
+    EXPORT armFuncR0ObjLast
+    
+
+    AREA	|.text|, CODE, ARM
+
+|armFunc| PROC
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  ; arg table
+    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  ; function address
+    mov     r8, #0
+
+    beq     |nomoreargs|
+
+    ; Load the first 4 arguments into r0-r3
+    cmp     r7, #4
+    ldrge   r0, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #3*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #4*4
+    ldrge   r3, [r6],#4
+    ble     |nomoreargs|
+
+    ; Load the rest of the arguments onto the stack
+    sub     r7, r7, #4*4    ; skip the 4 registers already loaded into r0-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+|stackargsloop|
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     |stackargsloop|
+|nomoreargs|
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+    ENDP
+
+armFuncObjLast PROC
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  ; arg table
+    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  ; function address
+    mov     r8, #0
+
+    mov     r0, r3          ; objlast. might get overwritten
+    str     r3, [sp, #-4]!  ; objlast again.
+
+    beq     |nomoreargs@armFuncObjLast|
+
+    ; Load the first 4 arguments into r0-r3
+    cmp     r7, #4
+    ldrge   r0, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r1, [r6],#4
+    ldrlt   r1, [sp]    
+    cmp     r7, #3*4
+    ldrge   r2, [r6],#4
+    ldrlt   r2, [sp]
+    cmp     r7, #4*4
+    ldrge   r3, [r6],#4
+    ldrlt   r3, [sp]
+    ble     |nomoreargs@armFuncObjLast|
+
+    ; Load the rest of the arguments onto the stack
+    sub     r7, r7, #4*4    ; skip the 4 registers already loaded into r0-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+|stackargsloop@armFuncObjLast|
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     |stackargsloop@armFuncObjLast|
+|nomoreargs@armFuncObjLast|
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    add     sp, sp, #4
+    ldmia   sp!, {r4-r8, pc}
+    ENDP
+
+armFuncR0ObjLast PROC
+    stmdb   sp!, {r4-r8, lr}
+    ldr     r7, [sp,#6*4]
+    str     r7, [sp,#-4]!
+
+    mov     r6, r0  ; arg table
+    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  ; function address
+    mov     r8, #0
+
+    mov     r0, r3      ; r0 explicitly set
+    ldr     r1, [sp]    ; objlast.  might get overwritten
+
+    beq     |nomoreargs@armFuncR0ObjLast|
+
+    ; Load the first 3 arguments into r1-r3
+    cmp     r7, #1*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r2, [r6],#4
+    ldrlt   r2, [sp]
+    cmp     r7, #3*4
+    ldrge   r3, [r6],#4
+    ldrlt   r3, [sp]
+    ble     |nomoreargs@armFuncR0ObjLast|
+
+    ; Load the rest of the arguments onto the stack
+    sub     r7, r7, #3*4    ; skip the 3 registers already loaded into r1-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+|stackargsloop@armFuncR0ObjLast|
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     |stackargsloop@armFuncR0ObjLast|
+|nomoreargs@armFuncR0ObjLast|
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    add     sp, sp, #4
+    ldmia   sp!, {r4-r8, pc}
+    ENDP
+
+armFuncR0 PROC
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  ; arg table
+    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  ; function address
+    mov     r8, #0
+
+    mov     r0, r3  ; r0 explicitly set
+
+    beq     |nomoreargs@armFuncR0|
+
+    ; Load the first 3 arguments into r1-r3
+    cmp     r7, #1*4
+    ldrge   r1, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #3*4
+    ldrge   r3, [r6],#4
+    ble     |nomoreargs@armFuncR0|
+
+    ; Load the rest of the arguments onto the stack
+    sub     r7, r7, #3*4    ; skip the 3 registers already loaded into r1-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+|stackargsloop@armFuncR0|
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     |stackargsloop@armFuncR0|
+|nomoreargs@armFuncR0|
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+    ENDP
+
+armFuncR0R1 PROC
+    stmdb   sp!, {r4-r8, lr}
+    mov     r6, r0  ; arg table
+    movs    r7, r1  ; arg size (also set the condition code flags so that we detect if there are no arguments)
+    mov     r4, r2  ; function address
+    mov     r8, #0
+
+    mov     r0, r3          ; r0 explicitly set
+    ldr     r1, [sp, #6*4]  ; r1 explicitly set too
+
+    beq     |nomoreargs@armFuncR0R1|
+
+    ; Load the first 2 arguments into r2-r3
+    cmp     r7, #1*4
+    ldrge   r2, [r6],#4
+    cmp     r7, #2*4
+    ldrge   r3, [r6],#4
+    ble     |nomoreargs@armFuncR0R1|
+
+    ; Load the rest of the arguments onto the stack
+    sub     r7, r7, #2*4    ; skip the 2 registers already loaded into r2-r3
+    sub     sp, sp, r7
+    mov     r8, r7
+|stackargsloop@armFuncR0R1|
+    ldr     r5, [r6], #4
+    str     r5, [sp], #4
+    subs    r7, r7, #4
+    bne     |stackargsloop@armFuncR0R1|
+|nomoreargs@armFuncR0R1|
+    sub     sp, sp, r8
+    blx     r4
+    add     sp, sp, r8
+    ldmia   sp!, {r4-r8, pc}
+    ENDP
+
+    END

+ 223 - 152
ThirdParty/AngelScript/source/as_callfunc_x86.cpp

@@ -28,7 +28,6 @@
    [email protected]
    [email protected]
 */
 */
 
 
-// Modified by Lasse Öörni for Urho3D
 
 
 //
 //
 // as_callfunc_x86.cpp
 // as_callfunc_x86.cpp
@@ -73,35 +72,16 @@ BEGIN_AS_NAMESPACE
 #define _S(x) _TOSTRING(x)
 #define _S(x) _TOSTRING(x)
 #define _TOSTRING(x) #x
 #define _TOSTRING(x) #x
 
 
-typedef asQWORD (*t_CallCDeclQW)(const asDWORD *, int, asFUNCTION_t);
-typedef asQWORD (*t_CallCDeclQWObj)(void *obj, const asDWORD *, int, asFUNCTION_t);
-typedef asDWORD (*t_CallCDeclRetByRef)(const asDWORD *, int, asFUNCTION_t, void *);
-typedef asDWORD (*t_CallCDeclObjRetByRef)(void *obj, const asDWORD *, int, asFUNCTION_t, void *);
-typedef asQWORD (*t_CallSTDCallQW)(const asDWORD *, int, asFUNCTION_t);
-typedef asQWORD (*t_CallThisCallQW)(const void *, const asDWORD *, int, asFUNCTION_t);
-typedef asDWORD (*t_CallThisCallRetByRef)(const void *, const asDWORD *, int, asFUNCTION_t, void *);
-
 // Prototypes
 // Prototypes
-void CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
-void CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
-void CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
-void CallCDeclFunctionRetByRef_impl(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
-void CallCDeclFunctionRetByRefObjLast_impl(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
-void CallCDeclFunctionRetByRefObjFirst_impl(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
-void CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
-void CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
-void CallThisCallFunctionRetByRef_impl(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr);
-
-// Initialize function pointers
-const t_CallCDeclQW CallCDeclFunctionQWord = (t_CallCDeclQW)CallCDeclFunction;
-const t_CallCDeclQWObj CallCDeclFunctionQWordObjLast = (t_CallCDeclQWObj)CallCDeclFunctionObjLast;
-const t_CallCDeclQWObj CallCDeclFunctionQWordObjFirst = (t_CallCDeclQWObj)CallCDeclFunctionObjFirst;
-const t_CallCDeclRetByRef CallCDeclFunctionRetByRef = (t_CallCDeclRetByRef)CallCDeclFunctionRetByRef_impl;
-const t_CallCDeclObjRetByRef CallCDeclFunctionRetByRefObjLast = (t_CallCDeclObjRetByRef)CallCDeclFunctionRetByRefObjLast_impl;
-const t_CallCDeclObjRetByRef CallCDeclFunctionRetByRefObjFirst = (t_CallCDeclObjRetByRef)CallCDeclFunctionRetByRefObjFirst_impl;
-const t_CallSTDCallQW CallSTDCallFunctionQWord = (t_CallSTDCallQW)CallSTDCallFunction;
-const t_CallThisCallQW CallThisCallFunctionQWord = (t_CallThisCallQW)CallThisCallFunction;
-const t_CallThisCallRetByRef CallThisCallFunctionRetByRef = (t_CallThisCallRetByRef)CallThisCallFunctionRetByRef_impl;
+asQWORD CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
+asQWORD CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
+asQWORD CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
+asQWORD CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
+asQWORD CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
+asQWORD CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr);
+asQWORD CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func);
+asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func);
+asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr);
 
 
 asDWORD GetReturnedFloat();
 asDWORD GetReturnedFloat();
 asQWORD GetReturnedDouble();
 asQWORD GetReturnedDouble();
@@ -111,16 +91,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 	asCScriptEngine            *engine    = context->engine;
 	asCScriptEngine            *engine    = context->engine;
 	asSSystemFunctionInterface *sysFunc   = descr->sysFuncIntf;
 	asSSystemFunctionInterface *sysFunc   = descr->sysFuncIntf;
 
 
-	// This needs to be volatile, as GCC 4.2 is optimizing 
-	// away the assignment of the return code on Mac OS X. 
-	// ref: http://www.gamedev.net/topic/621357-porting-dustforce-to-os-x/
-
-	// Urho3D: do not apply this fix on Linux, as it causes problems in release builds
-#ifndef __linux__
-	volatile asQWORD retQW = 0;
-#else
 	asQWORD retQW = 0;
 	asQWORD retQW = 0;
-#endif
 
 
 	// Prepare the parameters
 	// Prepare the parameters
 	int paramSize = sysFunc->paramSize;
 	int paramSize = sysFunc->paramSize;
@@ -175,7 +146,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 	switch( callConv )
 	switch( callConv )
 	{
 	{
 	case ICC_CDECL:
 	case ICC_CDECL:
-		retQW = CallCDeclFunctionQWord(args, paramSize<<2, func);
+		retQW = CallCDeclFunction(args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_CDECL_RETURNINMEM:
 	case ICC_CDECL_RETURNINMEM:
@@ -183,7 +154,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 		break;
 		break;
 
 
 	case ICC_STDCALL:
 	case ICC_STDCALL:
-		retQW = CallSTDCallFunctionQWord(args, paramSize<<2, func);
+		retQW = CallSTDCallFunction(args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_STDCALL_RETURNINMEM:
 	case ICC_STDCALL_RETURNINMEM:
@@ -192,11 +163,11 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 		args--;
 		args--;
 		*(asPWORD*)args = (size_t)retPointer;
 		*(asPWORD*)args = (size_t)retPointer;
 
 
-		retQW = CallSTDCallFunctionQWord(args, paramSize<<2, func);
+		retQW = CallSTDCallFunction(args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_THISCALL:
 	case ICC_THISCALL:
-		retQW = CallThisCallFunctionQWord(obj, args, paramSize<<2, func);
+		retQW = CallThisCallFunction(obj, args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_THISCALL_RETURNINMEM:
 	case ICC_THISCALL_RETURNINMEM:
@@ -207,7 +178,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 		{
 		{
 			// Get virtual function table from the object pointer
 			// Get virtual function table from the object pointer
 			asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
 			asFUNCTION_t *vftable = *(asFUNCTION_t**)obj;
-			retQW = CallThisCallFunctionQWord(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]);
+			retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]);
 		}
 		}
 		break;
 		break;
 
 
@@ -220,7 +191,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 		break;
 		break;
 
 
 	case ICC_CDECL_OBJLAST:
 	case ICC_CDECL_OBJLAST:
-		retQW = CallCDeclFunctionQWordObjLast(obj, args, paramSize<<2, func);
+		retQW = CallCDeclFunctionObjLast(obj, args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_CDECL_OBJLAST_RETURNINMEM:
 	case ICC_CDECL_OBJLAST_RETURNINMEM:
@@ -230,7 +201,7 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 
 
 	case ICC_CDECL_OBJFIRST:
 	case ICC_CDECL_OBJFIRST:
 		// Call the system object method as a cdecl with the obj ref as the first parameter
 		// Call the system object method as a cdecl with the obj ref as the first parameter
-		retQW = CallCDeclFunctionQWordObjFirst(obj, args, paramSize<<2, func);
+		retQW = CallCDeclFunctionObjFirst(obj, args, paramSize<<2, func);
 		break;
 		break;
 
 
 	case ICC_CDECL_OBJFIRST_RETURNINMEM:
 	case ICC_CDECL_OBJFIRST_RETURNINMEM:
@@ -264,8 +235,10 @@ asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr,
 #endif
 #endif
 
 
 
 
-void NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
+asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -298,26 +271,32 @@ endcopy:
 		// Pop arguments from stack
 		// Pop arguments from stack
 		add  esp, paramSize
 		add  esp, paramSize
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
+	// It is not possible to rely on ESP or BSP to refer to variables or arguments on the stack
+	// depending on compiler settings BSP may not even be used, and the ESP is not always on the 
+	// same offset from the local variables. Because the code adjusts the ESP register it is not
+	// possible to inform the arguments through symbolic names below.
+
+	// It's not also not possible to rely on the memory layout of the function arguments, because
+	// on some compiler versions and settings the arguments may be copied to local variables with a 
+	// different ordering before they are accessed by the rest of the code. 
 
 
-	// GNUC 4.6.1 seems to have a bug when compiling with -O2. This wasn't a problem in earlier versions.
-	// Even though the clobber list is specifically listing the esp register, it still doesn't understand
-	// that it cannot rely on esp for getting the function arguments. So in order to work around this
-	// I'm passing the address of the first arg in edx to the inline assembly, and then copy it to ebx
-	// where it is guaranteed to be maintained over the function call.
+	// I'm copying the arguments into this array where I know the exact memory layout. The address
+	// of this array will then be passed to the inline asm in the EDX register.
+	volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
 
 
 	asm __volatile__(
 	asm __volatile__(
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -333,6 +312,7 @@ endcopy:
 		"subl  %%ecx, %%esp     \n"
 		"subl  %%ecx, %%esp     \n"
 		"pushl %%eax            \n" // Store the original stack pointer
 		"pushl %%eax            \n" // Store the original stack pointer
 
 
+		// Copy all arguments to the stack and call the function
 		"movl  4(%%ebx), %%ecx  \n" // paramSize
 		"movl  4(%%ebx), %%ecx  \n" // paramSize
 		"movl  0(%%ebx), %%eax  \n" // args
 		"movl  0(%%ebx), %%eax  \n" // args
 		"addl  %%ecx, %%eax     \n" // push arguments on the stack
 		"addl  %%ecx, %%eax     \n" // push arguments on the stack
@@ -346,20 +326,30 @@ endcopy:
 		"endcopy:               \n"
 		"endcopy:               \n"
 		"call  *8(%%ebx)        \n"
 		"call  *8(%%ebx)        \n"
 		"addl  4(%%ebx), %%esp  \n" // pop arguments
 		"addl  4(%%ebx), %%esp  \n" // pop arguments
-		
+
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&args)               // input - pass pointer of args in edx
-		: "%eax", "%ecx", "%esp"   // clobber
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
+asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -396,21 +386,21 @@ endcopy:
 		add  esp, paramSize
 		add  esp, paramSize
 		add  esp, 4
 		add  esp, 4
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -445,16 +435,26 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
+asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -491,21 +491,21 @@ endcopy:
 		add  esp, paramSize
 		add  esp, paramSize
 		add  esp, 4
 		add  esp, 4
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -540,16 +540,26 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallCDeclFunctionRetByRefObjFirst_impl(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
+asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -594,22 +604,22 @@ endcopy:
 #else
 #else
 		add  esp, 4
 		add  esp, 4
 #endif
 #endif
+
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
-	UNUSED_VAR(retPtr);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -648,15 +658,25 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallCDeclFunctionRetByRef_impl(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
+asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -696,6 +716,12 @@ endcopy:
 		// Pop the return pointer
 		// Pop the return pointer
 		add  esp, 4
 		add  esp, 4
 #endif
 #endif
+
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
 
 
@@ -704,13 +730,10 @@ endcopy:
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
-	UNUSED_VAR(retPtr);
+	volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -746,16 +769,26 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&args)               // input - pass pointer of args in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallCDeclFunctionRetByRefObjLast_impl(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
+asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -798,22 +831,22 @@ endcopy:
 		// Pop the return pointer
 		// Pop the return pointer
 		add  esp, 4
 		add  esp, 4
 #endif
 #endif
+
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
-	UNUSED_VAR(retPtr);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -852,16 +885,26 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
+asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -893,20 +936,21 @@ endcopy:
 
 
 		// The callee already removed parameters from the stack
 		// The callee already removed parameters from the stack
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
+	volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -938,17 +982,27 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&args)               // input - pass pointer of args in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
 
 
-void NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
+asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -995,21 +1049,21 @@ endcopy:
 #endif
 #endif
 #endif
 #endif
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// Return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
+		_S(CLEAR_FPU_STACK)    "\n"
 		"pushl %%ebx            \n"
 		"pushl %%ebx            \n"
 		"movl  %%edx, %%ebx     \n"	
 		"movl  %%edx, %%ebx     \n"	
 
 
@@ -1045,16 +1099,26 @@ endcopy:
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp            \n"
 		"popl  %%esp            \n"
 		"popl  %%ebx            \n" 
 		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
-void NOINLINE CallThisCallFunctionRetByRef_impl(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
+asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr)
 {
 {
+	volatile asQWORD retQW;
+
 #if defined ASM_INTEL
 #if defined ASM_INTEL
 
 
 	// Copy the data to the real stack. If we fail to do
 	// Copy the data to the real stack. If we fail to do
@@ -1109,24 +1173,23 @@ endcopy:
 #endif
 #endif
 #endif
 #endif
 
 
+		// Copy return value from EAX:EDX
+		lea  ecx, retQW
+		mov  [ecx], eax
+		mov  4[ecx], edx
+
 		// Restore registers
 		// Restore registers
 		pop  ecx
 		pop  ecx
-
-		// Return value in EAX or EAX:EDX
 	}
 	}
 
 
 #elif defined ASM_AT_N_T
 #elif defined ASM_AT_N_T
 
 
-	UNUSED_VAR(obj);
-	UNUSED_VAR(args);
-	UNUSED_VAR(paramSize);
-	UNUSED_VAR(func);
-	UNUSED_VAR(retPtr);
+	volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)};
 
 
 	asm __volatile__ (
 	asm __volatile__ (
-		_S(CLEAR_FPU_STACK)  "\n"
-		"pushl %%ebx            \n"
-		"movl  %%edx, %%ebx     \n"	
+		_S(CLEAR_FPU_STACK)   "\n"
+		"pushl %%ebx           \n"
+		"movl  %%edx, %%ebx    \n"	
 
 
 		// Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
 		// Need to align the stack pointer so that it is aligned to 16 bytes when making the function call.
 		// It is assumed that when entering this function, the stack pointer is already aligned, so we need
 		// It is assumed that when entering this function, the stack pointer is already aligned, so we need
@@ -1163,13 +1226,21 @@ endcopy:
 		                           // the return pointer was popped by the callee
 		                           // the return pointer was popped by the callee
 		// Pop the alignment bytes
 		// Pop the alignment bytes
 		"popl  %%esp           \n"
 		"popl  %%esp           \n"
-		"popl  %%ebx            \n" 
-		:                          // output
-		: "d"(&obj)                // input - pass pointer of obj in edx
-		: "%eax", "%ecx", "%esp"   // clobber 
+		"popl  %%ebx           \n" 
+
+		// Copy EAX:EDX to retQW. As the stack pointer has been 
+		// restored it is now safe to access the local variable
+		"leal  %1, %%ecx        \n"
+		"movl  %%eax, 0(%%ecx)  \n"
+		"movl  %%edx, 4(%%ecx)  \n"
+		:                           // output
+		: "d"(a), "m"(retQW)        // input - pass pointer of args in edx, pass pointer of retQW in memory argument
+		: "%eax", "%ecx"            // clobber
 		);
 		);
 
 
 #endif
 #endif
+
+	return retQW;
 }
 }
 
 
 asDWORD GetReturnedFloat()
 asDWORD GetReturnedFloat()

+ 222 - 133
ThirdParty/AngelScript/source/as_compiler.cpp

@@ -51,6 +51,18 @@
 
 
 BEGIN_AS_NAMESPACE
 BEGIN_AS_NAMESPACE
 
 
+//
+// The calling convention rules for script functions:
+// - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
+// - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
+// - The object pointer is always passed as the first argument, position 0
+// - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
+//
+
+
+
+
+
 // TODO: I must correct the interpretation of a references to objects in the compiler.
 // TODO: I must correct the interpretation of a references to objects in the compiler.
 //       A reference should mean that a pointer to the object is on the stack.
 //       A reference should mean that a pointer to the object is on the stack.
 //       No expression should end up as non-references to objects, as the actual object is
 //       No expression should end up as non-references to objects, as the actual object is
@@ -168,11 +180,11 @@ int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCS
 	// Allocate the class and instanciate it with the constructor
 	// Allocate the class and instanciate it with the constructor
 	int varOffset = AllocateVariable(dt, true);
 	int varOffset = AllocateVariable(dt, true);
 
 
-	byteCode.Push(AS_PTR_SIZE);
+	outFunc->variableSpace = AS_PTR_SIZE;
 	byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
 	byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
 
 
 	// Copy all arguments to the top of the stack
 	// Copy all arguments to the top of the stack
-	// TODO: optimize: Might be interesting to have a specific instruction for copying all arguments
+	// TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
 	int offset = (int)outFunc->GetSpaceNeededForArguments();
 	int offset = (int)outFunc->GetSpaceNeededForArguments();
 	for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
 	for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
 	{
 	{
@@ -238,14 +250,30 @@ void asCCompiler::FinalizeFunction()
 	byteCode.ExtractObjectVariableInfo(outFunc);
 	byteCode.ExtractObjectVariableInfo(outFunc);
 
 
 	// Compile the list of object variables for the exception handler
 	// Compile the list of object variables for the exception handler
+	// Start with the variables allocated on the heap, and then the ones allocated on the stack
 	for( n = 0; n < variableAllocations.GetLength(); n++ )
 	for( n = 0; n < variableAllocations.GetLength(); n++ )
 	{
 	{
 		if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
 		if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
 		{
 		{
-			outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
-			outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
-			outFunc->objVariablePos.PushLast(GetVariableOffset(n));
-			outFunc->objVariableIsOnHeap.PushLast(variableIsOnHeap[n]);
+			if( variableIsOnHeap[n] )
+			{
+				outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
+				outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
+				outFunc->objVariablePos.PushLast(GetVariableOffset(n));
+			}
+		}
+	}
+	outFunc->objVariablesOnHeap = outFunc->objVariablePos.GetLength();
+	for( n = 0; n < variableAllocations.GetLength(); n++ )
+	{
+		if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
+		{
+			if( !variableIsOnHeap[n] )
+			{
+				outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
+				outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
+				outFunc->objVariablePos.PushLast(GetVariableOffset(n));
+			}
 		}
 		}
 	}
 	}
 
 
@@ -253,7 +281,7 @@ void asCCompiler::FinalizeFunction()
 	outFunc->byteCode.SetLength(byteCode.GetSize());
 	outFunc->byteCode.SetLength(byteCode.GetSize());
 	byteCode.Output(outFunc->byteCode.AddressOf());
 	byteCode.Output(outFunc->byteCode.AddressOf());
 	outFunc->AddReferences();
 	outFunc->AddReferences();
-	outFunc->stackNeeded = byteCode.largestStackUsed;
+	outFunc->stackNeeded = byteCode.largestStackUsed + outFunc->variableSpace;
 	outFunc->lineNumbers = byteCode.lineNumbers;
 	outFunc->lineNumbers = byteCode.lineNumbers;
 }
 }
 
 
@@ -286,10 +314,19 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, sEx
 
 
 	if( !signature )
 	if( !signature )
 	{
 	{
-		// Skip the private keyword if it is there
 		node = func->firstChild;
 		node = func->firstChild;
-		if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
+		if( outFunc->objectType )
+		{
+			// Skip the private keyword if it is there
+			if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
+				node = node->next;
+		}
+		else if( outFunc->IsShared() )
+		{
+			// Skip the shared keyword
+			asASSERT( node->nodeType == snIdentifier );
 			node = node->next;
 			node = node->next;
+		}
 
 
 		//----------------------------------------------
 		//----------------------------------------------
 		// Examine return type
 		// Examine return type
@@ -487,23 +524,37 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, sEx
 
 
 	// Count total variable size
 	// Count total variable size
 	int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
 	int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
-	byteCode.Push(varSize);
+	outFunc->variableSpace = varSize;
 
 
 	if( outFunc->objectType )
 	if( outFunc->objectType )
 	{
 	{
 		// Call the base class' default constructor unless called manually in the code
 		// Call the base class' default constructor unless called manually in the code
 		if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
 		if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
 		{
 		{
-			byteCode.InstrSHORT(asBC_PSF, 0);
-			byteCode.Instr(asBC_RDSPtr);
-			byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
+			if( outFunc->objectType->derivedFrom->beh.construct )
+			{
+				byteCode.InstrSHORT(asBC_PSF, 0);
+				byteCode.Instr(asBC_RDSPtr);
+				byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
+			}
+			else
+			{
+				Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
+			}
 		}
 		}
 
 
 		// Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
 		// Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
-		// TODO: optimize: This is probably not necessary for constructors as no outside reference to the object is created yet
-		byteCode.InstrSHORT(asBC_PSF, 0);
-		byteCode.Instr(asBC_RDSPtr);
-		byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
+		if( !m_isConstructor && !outFunc->returnType.IsReference() )
+		{
+			// TODO: runtime optimize: If the function is trivial, i.e. doesn't access any outside functions, 
+			//                         then this is not necessary. If I implement this, then the function needs 
+			//                         to set a flag so the exception handler doesn't try to release the handle.
+			// It is not necessary to do this for constructors, as they have no outside references that can be released anyway
+			// It is not necessary to do this for methods that return references, as the caller is guaranteed to hold a reference to the object
+			byteCode.InstrSHORT(asBC_PSF, 0);
+			byteCode.Instr(asBC_RDSPtr);
+			byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
+		}
 	}
 	}
 
 
 	// Add the code for the statement block
 	// Add the code for the statement block
@@ -542,7 +593,7 @@ int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, sEx
 	}
 	}
 
 
 	// Release the object pointer again
 	// Release the object pointer again
-	if( outFunc->objectType )
+	if( outFunc->objectType && !m_isConstructor && !outFunc->returnType.IsReference() )
 	{
 	{
 		byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
 		byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
 	}
 	}
@@ -613,7 +664,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
 				PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
 				PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
 
 
 				// Pop the reference left by the function call
 				// Pop the reference left by the function call
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -624,7 +675,7 @@ int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjec
 				ctx.bc.Instr(asBC_RDSPtr);
 				ctx.bc.Instr(asBC_RDSPtr);
 				ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
 				ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
 				ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
 				ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 				ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 				ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 			}
 			}
 
 
@@ -709,7 +760,7 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
 				PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
 				PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
 
 
 				// Pop the reference left by the function call
 				// Pop the reference left by the function call
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -720,7 +771,7 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
 				ctx.bc.Instr(asBC_RDSPtr);
 				ctx.bc.Instr(asBC_RDSPtr);
 				ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
 				ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
 				ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
 				ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 				ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 				ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 			}
 			}
 
 
@@ -961,7 +1012,7 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
 							ctx.bc.Instr(asBC_RDSPtr);
 							ctx.bc.Instr(asBC_RDSPtr);
 							ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
 							ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
 							ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
 							ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
-							ctx.bc.Pop(AS_PTR_SIZE);
+							ctx.bc.Instr(asBC_PopPtr);
 							ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 							ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 						}
 						}
 						else
 						else
@@ -1036,9 +1087,9 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
 		}
 		}
 		else
 		else
 		{
 		{
-			// TODO: optimize: Here we should look for the best matching constructor, instead of
-			//                 just the copy constructor. Only if no appropriate constructor is
-			//                 available should the assignment operator be used.
+			// TODO: runtime optimize: Here we should look for the best matching constructor, instead of
+			//                         just the copy constructor. Only if no appropriate constructor is
+			//                         available should the assignment operator be used.
 
 
 			if( !gvar->datatype.IsObjectHandle() )
 			if( !gvar->datatype.IsObjectHandle() )
 			{
 			{
@@ -1071,7 +1122,7 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
 				if( assigned )
 				if( assigned )
 				{
 				{
 					// Pop the resulting value
 					// Pop the resulting value
-					ctx.bc.Pop(AS_PTR_SIZE);
+					ctx.bc.Instr(asBC_PopPtr);
 
 
 					// Release the argument
 					// Release the argument
 					ProcessDeferredParams(&ctx);
 					ProcessDeferredParams(&ctx);
@@ -1102,7 +1153,7 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
 				// Release temporary variables used by expression
 				// Release temporary variables used by expression
 				ReleaseTemporaryVariable(expr.type, &ctx.bc);
 				ReleaseTemporaryVariable(expr.type, &ctx.bc);
 
 
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1124,7 +1175,7 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
 	LineInstr(&byteCode, pos);
 	LineInstr(&byteCode, pos);
 
 
 	// Reserve space for all local variables
 	// Reserve space for all local variables
-	byteCode.Push(varSize);
+	outFunc->variableSpace = varSize;
 
 
 	byteCode.AddCode(&ctx.bc);
 	byteCode.AddCode(&ctx.bc);
 
 
@@ -1269,7 +1320,7 @@ void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, a
 
 
 					PerformAssignment(&type, &ctx->type, &ctx->bc, node);
 					PerformAssignment(&type, &ctx->type, &ctx->bc, node);
 
 
-					ctx->bc.Pop(AS_PTR_SIZE);
+					ctx->bc.Instr(asBC_PopPtr);
 
 
 					ReleaseTemporaryVariable(ctx->type, &ctx->bc);
 					ReleaseTemporaryVariable(ctx->type, &ctx->bc);
 
 
@@ -1363,7 +1414,7 @@ void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, a
 					ctx->bc.Instr(asBC_RDSPtr);
 					ctx->bc.Instr(asBC_RDSPtr);
 				ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
 				ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
 				ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
 				ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
-				ctx->bc.Pop(AS_PTR_SIZE);
+				ctx->bc.Instr(asBC_PopPtr);
 				ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
 				ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
 
 
 				dt.MakeHandle(false);
 				dt.MakeHandle(false);
@@ -1468,7 +1519,7 @@ void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, a
 
 
 			if( ctx->type.isVariable || ctx->type.isTemporary )
 			if( ctx->type.isVariable || ctx->type.isTemporary )
 			{
 			{
-				ctx->bc.Pop(AS_PTR_SIZE);
+				ctx->bc.Instr(asBC_PopPtr);
 				ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
 				ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
 
 
 				ProcessDeferredParams(ctx);
 				ProcessDeferredParams(ctx);
@@ -1547,8 +1598,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprC
 					if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
 					if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
 					{
 					{
 						if( !IsVariableOnHeap(args[n]->type.stackOffset) )
 						if( !IsVariableOnHeap(args[n]->type.stackOffset) )
-							// TODO: optimize: Actually the reference can be pushed on the stack directly
-							//                 as the value allocated on the stack is guaranteed to be safe
+							// TODO: runtime optimize: Actually the reference can be pushed on the stack directly
+							//                         as the value allocated on the stack is guaranteed to be safe
 							bc->InstrWORD(asBC_GETREF, (asWORD)offset);
 							bc->InstrWORD(asBC_GETREF, (asWORD)offset);
 						else 
 						else 
 							bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
 							bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
@@ -1565,8 +1616,8 @@ void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprC
 					// Send the object as a reference to the object,
 					// Send the object as a reference to the object,
 					// and not to the variable holding the object
 					// and not to the variable holding the object
 					if( !IsVariableOnHeap(args[n]->type.stackOffset) )
 					if( !IsVariableOnHeap(args[n]->type.stackOffset) )
-						// TODO: optimize: Actually the reference can be pushed on the stack directly
-						//                 as the value allocated on the stack is guaranteed to be safe
+						// TODO: runtime optimize: Actually the reference can be pushed on the stack directly
+						//                         as the value allocated on the stack is guaranteed to be safe
 						bc->InstrWORD(asBC_GETREF, (asWORD)offset);
 						bc->InstrWORD(asBC_GETREF, (asWORD)offset);
 					else
 					else
 						bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
 						bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
@@ -1953,7 +2004,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
 								MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
 								MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
 
 
 								// Pop the reference left by the function call
 								// Pop the reference left by the function call
-								ctx.bc.Pop(AS_PTR_SIZE);
+								ctx.bc.Instr(asBC_PopPtr);
 							}
 							}
 							else
 							else
 							{
 							{
@@ -2045,7 +2096,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
 				}
 				}
 				else
 				else
 				{
 				{
-					// TODO: optimize: We can use a copy constructor here
+					// TODO: runtime optimize: We can use a copy constructor here
 
 
 					sVariable *v = variables->GetVariable(name.AddressOf());
 					sVariable *v = variables->GetVariable(name.AddressOf());
 
 
@@ -2077,7 +2128,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
 						if( assigned )
 						if( assigned )
 						{
 						{
 							// Pop the resulting value
 							// Pop the resulting value
-							ctx.bc.Pop(AS_PTR_SIZE);
+							ctx.bc.Instr(asBC_PopPtr);
 
 
 							// Release the argument
 							// Release the argument
 							ProcessDeferredParams(&ctx);
 							ProcessDeferredParams(&ctx);
@@ -2112,7 +2163,7 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
 						// Release temporary variables used by expression
 						// Release temporary variables used by expression
 						ReleaseTemporaryVariable(expr.type, &ctx.bc);
 						ReleaseTemporaryVariable(expr.type, &ctx.bc);
 
 
-						ctx.bc.Pop(AS_PTR_SIZE);
+						ctx.bc.Instr(asBC_PopPtr);
 
 
 						ProcessDeferredParams(&ctx);
 						ProcessDeferredParams(&ctx);
 					}
 					}
@@ -2176,7 +2227,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
 	{
 	{
 		// Call factory and store the handle in the given variable
 		// Call factory and store the handle in the given variable
 		PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
 		PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
-		ctx.bc.Pop(AS_PTR_SIZE);
+		ctx.bc.Instr(asBC_PopPtr);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -2186,7 +2237,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
 		ctx.bc.Instr(asBC_RDSPtr);
 		ctx.bc.Instr(asBC_RDSPtr);
 		ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
 		ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
 		ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
 		ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
-		ctx.bc.Pop(AS_PTR_SIZE);
+		ctx.bc.Instr(asBC_PopPtr);
 		ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 		ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
 	}
 	}
 
 
@@ -2284,7 +2335,7 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
 			DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
 			DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
 
 
 			if( !lctx.type.dataType.IsPrimitive() )
 			if( !lctx.type.dataType.IsPrimitive() )
-				ctx.bc.Pop(AS_PTR_SIZE);
+				ctx.bc.Instr(asBC_PopPtr);
 
 
 			// Release temporary variables used by expression
 			// Release temporary variables used by expression
 			ReleaseTemporaryVariable(ctx.type, &ctx.bc);
 			ReleaseTemporaryVariable(ctx.type, &ctx.bc);
@@ -2496,8 +2547,8 @@ void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCo
 	expr.bc.InstrDWORD(asBC_JP, defaultLabel);
 	expr.bc.InstrDWORD(asBC_JP, defaultLabel);
 	ReleaseTemporaryVariable(tmpOffset, &expr.bc);
 	ReleaseTemporaryVariable(tmpOffset, &expr.bc);
 
 
-	// TODO: optimize: We could possibly optimize this even more by doing a
-	//                 binary search instead of a linear search through the ranges
+	// TODO: runtime optimize: We could possibly optimize this even more by doing a
+	//                         binary search instead of a linear search through the ranges
 
 
 	// For each range
 	// For each range
 	int range;
 	int range;
@@ -2778,27 +2829,14 @@ void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCB
 
 
 void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
 void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
 {
 {
-	// TODO: optimize: We should be able to remove the static JMP to the beginning of the loop by rearranging the
-	//                 byte code a bit.
-	//
-	//                 init
-	//                 jump to before
-	//                 begin:
-	//                 statements
-	//                 continue:
-	//                 next
-	//                 before:
-	//                 condition
-	//                 if loop jump to begin
-	//                 break:
-
 	// Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
 	// Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
 	AddVariableScope(true, true);
 	AddVariableScope(true, true);
 
 
 	// We will use three labels for the for loop
 	// We will use three labels for the for loop
-	int beforeLabel = nextLabel++;
+	int conditionLabel = nextLabel++;
 	int afterLabel = nextLabel++;
 	int afterLabel = nextLabel++;
 	int continueLabel = nextLabel++;
 	int continueLabel = nextLabel++;
+	int insideLabel = nextLabel++;
 
 
 	continueLabels.PushLast(continueLabel);
 	continueLabels.PushLast(continueLabel);
 	breakLabels.PushLast(afterLabel);
 	breakLabels.PushLast(afterLabel);
@@ -2833,7 +2871,7 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
 				ConvertToVariable(&expr);
 				ConvertToVariable(&expr);
 				expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
 				expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
 				expr.bc.Instr(asBC_ClrHi);
 				expr.bc.Instr(asBC_ClrHi);
-				expr.bc.InstrDWORD(asBC_JZ, afterLabel);
+				expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
 				ReleaseTemporaryVariable(expr.type, &expr.bc);
 				ReleaseTemporaryVariable(expr.type, &expr.bc);
 			}
 			}
 		}
 		}
@@ -2855,20 +2893,28 @@ void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
 	//-------------------------------
 	//-------------------------------
 	// Join the code pieces
 	// Join the code pieces
 	bc->AddCode(&initBC);
 	bc->AddCode(&initBC);
-	bc->Label((short)beforeLabel);
+	bc->InstrDWORD(asBC_JMP, conditionLabel);
+
+	bc->Label((short)insideLabel);
 
 
 	// Add a suspend bytecode inside the loop to guarantee
 	// Add a suspend bytecode inside the loop to guarantee
 	// that the application can suspend the execution
 	// that the application can suspend the execution
 	bc->Instr(asBC_SUSPEND);
 	bc->Instr(asBC_SUSPEND);
 	bc->InstrPTR(asBC_JitEntry, 0);
 	bc->InstrPTR(asBC_JitEntry, 0);
 
 
-
-	bc->AddCode(&expr.bc);
 	LineInstr(bc, fnode->lastChild->tokenPos);
 	LineInstr(bc, fnode->lastChild->tokenPos);
 	bc->AddCode(&forBC);
 	bc->AddCode(&forBC);
+
 	bc->Label((short)continueLabel);
 	bc->Label((short)continueLabel);
 	bc->AddCode(&nextBC);
 	bc->AddCode(&nextBC);
-	bc->InstrINT(asBC_JMP, beforeLabel);
+
+	bc->Label((short)conditionLabel);
+	if( expr.bc.GetLastInstr() == -1 )
+		// There is no condition, so we just always jump
+		bc->InstrDWORD(asBC_JMP, insideLabel);
+	else
+		bc->AddCode(&expr.bc);
+
 	bc->Label((short)afterLabel);
 	bc->Label((short)afterLabel);
 
 
 	continueLabels.PopLast();
 	continueLabels.PopLast();
@@ -3078,9 +3124,15 @@ void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *
 		asSExprContext expr(engine);
 		asSExprContext expr(engine);
 		CompileAssignment(enode->firstChild, &expr);
 		CompileAssignment(enode->firstChild, &expr);
 
 
+		// If we get here and there is still an unprocessed property
+		// accessor, then process it as a get access. Don't call if there is 
+		// already a compile error, or we might report an error that is not valid
+		if( !hasCompileErrors )
+			ProcessPropertyGetAccessor(&expr, enode);
+
 		// Pop the value from the stack
 		// Pop the value from the stack
 		if( !expr.type.dataType.IsPrimitive() )
 		if( !expr.type.dataType.IsPrimitive() )
-			expr.bc.Pop(AS_PTR_SIZE);
+			expr.bc.Instr(asBC_PopPtr);
 
 
 		// Release temporary variables used by expression
 		// Release temporary variables used by expression
 		ReleaseTemporaryVariable(expr.type, &expr.bc);
 		ReleaseTemporaryVariable(expr.type, &expr.bc);
@@ -3103,7 +3155,7 @@ void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ct
 		// the expression needs to be reevaluated to a reference
 		// the expression needs to be reevaluated to a reference
 		if( !ctx->type.dataType.IsReference() )
 		if( !ctx->type.dataType.IsReference() )
 		{
 		{
-			ctx->bc.Pop(AS_PTR_SIZE);
+			ctx->bc.Instr(asBC_PopPtr);
 			ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
 			ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
 			ctx->type.dataType.MakeReference(true);
 			ctx->type.dataType.MakeReference(true);
 		}
 		}
@@ -3157,7 +3209,7 @@ void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ct
 			}
 			}
 
 
 			// Pop the original reference
 			// Pop the original reference
-			ctx->bc.Pop(AS_PTR_SIZE);
+			ctx->bc.Instr(asBC_PopPtr);
 		}
 		}
 	}
 	}
 
 
@@ -3344,9 +3396,9 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
 				// that has been reserved by the calling function. 
 				// that has been reserved by the calling function. 
 				if( outFunc->DoesReturnOnStack() )
 				if( outFunc->DoesReturnOnStack() )
 				{
 				{
-					// TODO: optimize: If the return type has a constructor that takes the type of the expression,
-					//                 it should be called directly instead of first converting the expression and 
-					//                 then copy the value.
+					// TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
+					//                         it should be called directly instead of first converting the expression and 
+					//                         then copy the value.
 					if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) 
 					if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) 
 					{
 					{
 						ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
 						ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
@@ -3377,7 +3429,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
 						lexpr.type.Set(v->type);
 						lexpr.type.Set(v->type);
 						lexpr.type.isLValue = true;
 						lexpr.type.isLValue = true;
 						PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
 						PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
-						expr.bc.Pop(AS_PTR_SIZE);
+						expr.bc.Instr(asBC_PopPtr);
 
 
 						// Release any temporary variable
 						// Release any temporary variable
 						ReleaseTemporaryVariable(expr.type, &expr.bc);
 						ReleaseTemporaryVariable(expr.type, &expr.bc);
@@ -3396,7 +3448,7 @@ void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
 					PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
 					PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
 
 
 					// Pop the reference to the temporary variable
 					// Pop the reference to the temporary variable
-					expr.bc.Pop(AS_PTR_SIZE);
+					expr.bc.Instr(asBC_PopPtr);
 
 
 					// Clean up the local variables and process deferred parameters
 					// Clean up the local variables and process deferred parameters
 					DestroyVariables(&expr.bc);
 					DestroyVariables(&expr.bc);
@@ -3709,10 +3761,7 @@ void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
 		{
 		{
 			ctx->type.dataType.MakeReference(false);
 			ctx->type.dataType.MakeReference(false);
 			if( generateCode )
 			if( generateCode )
-			{
-				ctx->bc.Instr(asBC_CHKREF);
 				ctx->bc.Instr(asBC_RDSPtr);
 				ctx->bc.Instr(asBC_RDSPtr);
-			}
 		}
 		}
 		else
 		else
 		{
 		{
@@ -3920,7 +3969,7 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
 			}
 			}
 
 
 			// Copy larger data types from a reference
 			// Copy larger data types from a reference
-			// TODO: optimize: COPY should pop both arguments and store the reference in the register. 
+			// TODO: runtime optimize: COPY should pop both arguments and store the reference in the register. 
 			bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
 			bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
 		}
 		}
 	}
 	}
@@ -3933,7 +3982,6 @@ int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asC
 			return -1;
 			return -1;
 		}
 		}
 
 
-		// TODO: optimize: Convert to register based
 		bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
 		bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
 
 
 		// Mark variable as initialized
 		// Mark variable as initialized
@@ -4030,30 +4078,30 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
 		{
 		{
 			if( generateCode )
 			if( generateCode )
 			{
 			{
-				// TODO: optimize: Instead of producing bytecode for checking if the handle is
-				//                 null, we can create a special CALLSYS instruction that checks
-				//                 if the object pointer is null and if so sets the object register
-				//                 to null directly without executing the function.
+				// TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
+				//                         null, we can create a special CALLSYS instruction that checks
+				//                         if the object pointer is null and if so sets the object register
+				//                         to null directly without executing the function.
 				//
 				//
-				//                 Alternatively I could force the ref cast behaviours be global
-				//                 functions with 1 parameter, even though they should still be
-				//                 registered with RegisterObjectBehaviour()
+				//                         Alternatively I could force the ref cast behaviours be global
+				//                         functions with 1 parameter, even though they should still be
+				//                         registered with RegisterObjectBehaviour()
 
 
 				// Add code to avoid calling the cast behaviour if the handle is already null,
 				// Add code to avoid calling the cast behaviour if the handle is already null,
 				// because that will raise a null pointer exception due to the cast behaviour
 				// because that will raise a null pointer exception due to the cast behaviour
 				// being a class method, and the this pointer cannot be null.
 				// being a class method, and the this pointer cannot be null.
 
 
 				if( ctx->type.isVariable )
 				if( ctx->type.isVariable )
-					ctx->bc.Pop(AS_PTR_SIZE);
+					ctx->bc.Instr(asBC_PopPtr);
 				else
 				else
 				{
 				{
 					Dereference(ctx, true);
 					Dereference(ctx, true);
 					ConvertToVariable(ctx);
 					ConvertToVariable(ctx);
 				}
 				}
 
 
-				// TODO: optimize: should have immediate comparison for null pointer
+				// TODO: runtime optimize: should have immediate comparison for null pointer
 				int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
 				int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
-				// TODO: optimize: ClrVPtr is not necessary, because the VM will initialize the variable to null anyway
+				// TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though)
 				ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
 				ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
 				ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
 				ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
 				DeallocateVariable(offset);
 				DeallocateVariable(offset);
@@ -4070,7 +4118,7 @@ bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, boo
 				asCArray<asSExprContext *> args;
 				asCArray<asSExprContext *> args;
 				MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
 				MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
 
 
-				ctx->bc.Pop(AS_PTR_SIZE);
+				ctx->bc.Instr(asBC_PopPtr);
 
 
 				int endLabel = nextLabel++;
 				int endLabel = nextLabel++;
 
 
@@ -5949,8 +5997,14 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
 				return -1;
 				return -1;
 			}
 			}
 		}
 		}
-		else if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
-			rctx->bc.Instr(asBC_RDSPtr);
+		else 
+		{
+			// Process any property accessor first, before placing the final reference on the stack
+			ProcessPropertyGetAccessor(rctx, rexpr);
+
+			if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
+				rctx->bc.Instr(asBC_RDSPtr);
+		}
 
 
 		MergeExprBytecode(ctx, rctx);
 		MergeExprBytecode(ctx, rctx);
 		MergeExprBytecode(ctx, lctx);
 		MergeExprBytecode(ctx, lctx);
@@ -5958,9 +6012,9 @@ int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExpr
 		if( !simpleExpr )
 		if( !simpleExpr )
 		{
 		{
 			if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
 			if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
-				// TODO: optimize: Actually the reference can be pushed on the stack directly
-				//                 as the value allocated on the stack is guaranteed to be safe.
-				//                 The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
+				// TODO: runtime optimize: Actually the reference can be pushed on the stack directly
+				//                         as the value allocated on the stack is guaranteed to be safe.
+				//                         The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
 				ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
 				ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
 			else
 			else
 				ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
 				ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
@@ -6132,7 +6186,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
 				}
 				}
 				PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
 				PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
 				if( !rtemp.dataType.IsPrimitive() )
 				if( !rtemp.dataType.IsPrimitive() )
-					ctx->bc.Pop(AS_PTR_SIZE); // Pop the original value (always a pointer)
+					ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
 
 
 				// Release the old temporary variable
 				// Release the old temporary variable
 				ReleaseTemporaryVariable(le.type, &ctx->bc);
 				ReleaseTemporaryVariable(le.type, &ctx->bc);
@@ -6153,7 +6207,7 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
 				}
 				}
 				PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
 				PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
 				if( !rtemp.dataType.IsPrimitive() )
 				if( !rtemp.dataType.IsPrimitive() )
-					ctx->bc.Pop(AS_PTR_SIZE); // Pop the original value (always a pointer)
+					ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
 
 
 				// Release the old temporary variable
 				// Release the old temporary variable
 				ReleaseTemporaryVariable(re.type, &ctx->bc);
 				ReleaseTemporaryVariable(re.type, &ctx->bc);
@@ -6450,7 +6504,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 				// Reference to primitive must be stored in the temp register
 				// Reference to primitive must be stored in the temp register
 				if( prop->type.IsPrimitive() )
 				if( prop->type.IsPrimitive() )
 				{
 				{
-					// TODO: optimize: The ADD offset command should store the reference in the register directly
+					// TODO: runtime optimize: The ADD offset command should store the reference in the register directly
 					ctx->bc.Instr(asBC_PopRPtr);
 					ctx->bc.Instr(asBC_PopRPtr);
 				}
 				}
 
 
@@ -6573,7 +6627,7 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
 							if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
 							if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
 								!ctx->type.dataType.IsObjectHandle() )
 								!ctx->type.dataType.IsObjectHandle() )
 							{
 							{
-								// TODO: optimize: This is not necessary for application registered properties
+								// TODO: runtime optimize: This is not necessary for application registered properties
 								ctx->bc.Instr(asBC_ChkRefS);
 								ctx->bc.Instr(asBC_ChkRefS);
 							}
 							}
 						}
 						}
@@ -7427,7 +7481,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
 				asSExprContext o(engine);
 				asSExprContext o(engine);
 				DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
 				DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
 
 
-				if( !o.type.dataType.IsPrimitive() ) o.bc.Pop(AS_PTR_SIZE);
+				if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
 
 
 				MergeExprBytecode(ctx, &o);
 				MergeExprBytecode(ctx, &o);
 			}
 			}
@@ -7436,7 +7490,7 @@ void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
 				// We must still evaluate the expression
 				// We must still evaluate the expression
 				MergeExprBytecode(ctx, expr);
 				MergeExprBytecode(ctx, expr);
 				if( !expr->type.isConstant || expr->type.IsNullConstant() )
 				if( !expr->type.isConstant || expr->type.IsNullConstant() )
-					ctx->bc.Pop(AS_PTR_SIZE);
+					ctx->bc.Instr(asBC_PopPtr);
 
 
 				// Give a warning, except if the argument is null or 0 which indicate the argument is really to be ignored
 				// Give a warning, except if the argument is null or 0 which indicate the argument is really to be ignored
 				if( !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
 				if( !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
@@ -7714,9 +7768,6 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
 			ctx->type.SetVariable(dt, 0, false);
 			ctx->type.SetVariable(dt, 0, false);
 			ctx->type.dataType.MakeReference(true);
 			ctx->type.dataType.MakeReference(true);
 
 
-			// TODO: optimize: This adds a CHKREF. Is that really necessary? It isn't as the 
-			//                 VM will check for null pointer anyway before calling the method.
-			//                 The bytecode optimizer should know this and remove the unnecessary CHKREF
 			Dereference(ctx, true);
 			Dereference(ctx, true);
 		}			
 		}			
 	}
 	}
@@ -7853,7 +7904,7 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
 					ConvertToVariable(&funcPtr);
 					ConvertToVariable(&funcPtr);
 					ctx->bc.AddCode(&funcPtr.bc);
 					ctx->bc.AddCode(&funcPtr.bc);
 					if( !funcPtr.type.isTemporary )
 					if( !funcPtr.type.isTemporary )
-						ctx->bc.Pop(AS_PTR_SIZE);
+						ctx->bc.Instr(asBC_PopPtr);
 				}
 				}
 
 
 				MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
 				MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
@@ -8353,27 +8404,55 @@ int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx
 		}
 		}
 	}
 	}
 
 
+	bool isConst = false;
+	if( ctx->type.dataType.IsObjectHandle() )
+		isConst = ctx->type.dataType.IsHandleToConst();
+	else
+		isConst = ctx->type.dataType.IsReadOnly();
+
 	// Check for multiple matches
 	// Check for multiple matches
 	if( multipleGetFuncs.GetLength() > 0 )
 	if( multipleGetFuncs.GetLength() > 0 )
 	{
 	{
-		asCString str;
-		str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
-		Error(str.AddressOf(), node);
+		// Filter the list by constness
+		FilterConst(multipleGetFuncs, !isConst);
 
 
-		PrintMatchingFuncs(multipleGetFuncs, node);
+		if( multipleGetFuncs.GetLength() > 1 )
+		{
+			asCString str;
+			str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
+			Error(str.AddressOf(), node);
 
 
-		return -1;
+			PrintMatchingFuncs(multipleGetFuncs, node);
+
+			return -1;
+		}
+		else
+		{
+			// The id may have changed
+			getId = multipleGetFuncs[0];
+		}
 	}
 	}
 
 
 	if( multipleSetFuncs.GetLength() > 0 )
 	if( multipleSetFuncs.GetLength() > 0 )
 	{
 	{
-		asCString str;
-		str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
-		Error(str.AddressOf(), node);
+		// Filter the list by constness
+		FilterConst(multipleSetFuncs, !isConst);
 
 
-		PrintMatchingFuncs(multipleSetFuncs, node);
+		if( multipleSetFuncs.GetLength() > 1 )
+		{
+			asCString str;
+			str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
+			Error(str.AddressOf(), node);
 
 
-		return -1;
+			PrintMatchingFuncs(multipleSetFuncs, node);
+
+			return -1;
+		}
+		else
+		{
+			// The id may have changed
+			setId = multipleSetFuncs[0];
+		}
 	}
 	}
 
 
 	// Check for type compatibility between get and set accessor
 	// Check for type compatibility between get and set accessor
@@ -8970,6 +9049,11 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
 				if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
 				if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
 				if( ctx->property_ref )	ctx->type.dataType.MakeReference(true);
 				if( ctx->property_ref )	ctx->type.dataType.MakeReference(true);
 			}
 			}
+			else
+			{
+				ctx->type.SetDummy();
+			}
+
 			ctx->property_get = ctx->property_set = 0;
 			ctx->property_get = ctx->property_set = 0;
 			if( ctx->property_arg )
 			if( ctx->property_arg )
 			{
 			{
@@ -9646,7 +9730,7 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx)
 		if( ctx->type.IsNullConstant() )
 		if( ctx->type.IsNullConstant() )
 		{
 		{
 			if( ctx->bc.GetLastInstr() == asBC_PshNull )
 			if( ctx->bc.GetLastInstr() == asBC_PshNull )
-				ctx->bc.Pop(AS_PTR_SIZE); // Pop the null constant pushed onto the stack
+				ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
 			ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
 			ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
 		}
 		}
 		else
 		else
@@ -9654,8 +9738,7 @@ void asCCompiler::ConvertToVariable(asSExprContext *ctx)
 			// Copy the object handle to a variable
 			// Copy the object handle to a variable
 			ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
 			ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
 			ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
 			ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
-			// TODO: optimize: REFCPY should pop both arguments, and store the return in the register, just like a normal function
-			ctx->bc.Pop(AS_PTR_SIZE);
+			ctx->bc.Instr(asBC_PopPtr);
 		}
 		}
 
 
 		ReleaseTemporaryVariable(ctx->type, &ctx->bc);
 		ReleaseTemporaryVariable(ctx->type, &ctx->bc);
@@ -10869,9 +10952,9 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
 
 
 	// Need to pop the value if it is a null constant
 	// Need to pop the value if it is a null constant
 	if( lctx->type.IsNullConstant() )
 	if( lctx->type.IsNullConstant() )
-		lctx->bc.Pop(AS_PTR_SIZE);
+		lctx->bc.Instr(asBC_PopPtr);
 	if( rctx->type.IsNullConstant() )
 	if( rctx->type.IsNullConstant() )
-		rctx->bc.Pop(AS_PTR_SIZE);
+		rctx->bc.Instr(asBC_PopPtr);
 
 
 	// Convert both sides to explicit handles
 	// Convert both sides to explicit handles
 	to.MakeHandle(true);
 	to.MakeHandle(true);
@@ -10898,6 +10981,12 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
 		Error(str.AddressOf(), node);
 		Error(str.AddressOf(), node);
 	}
 	}
 
 
+	// Make sure it really is handles that are being compared
+	if( !lctx->type.dataType.IsObjectHandle() )
+	{
+		Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
+	}
+
 	ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
 	ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
 
 
 	int op = node->tokenType;
 	int op = node->tokenType;
@@ -10905,11 +10994,11 @@ void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *
 	{
 	{
 		// If the object handle already is in a variable we must manually pop it from the stack
 		// If the object handle already is in a variable we must manually pop it from the stack
 		if( lctx->type.isVariable )
 		if( lctx->type.isVariable )
-			lctx->bc.Pop(AS_PTR_SIZE);
+			lctx->bc.Instr(asBC_PopPtr);
 		if( rctx->type.isVariable )
 		if( rctx->type.isVariable )
-			rctx->bc.Pop(AS_PTR_SIZE);
+			rctx->bc.Instr(asBC_PopPtr);
 
 
-		// TODO: optimize: Treat the object handles as two integers, i.e. don't do REFCPY
+		// TODO: runtime optimize: don't do REFCPY
 		ConvertToVariableNotIn(lctx, rctx);
 		ConvertToVariableNotIn(lctx, rctx);
 		ConvertToVariable(rctx);
 		ConvertToVariable(rctx);
 
 
@@ -10972,7 +11061,7 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
 	{
 	{
 		// The class method we're calling is returning a reference, which may be to a member of the object.
 		// The class method we're calling is returning a reference, which may be to a member of the object.
 		// In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
 		// In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
-		// TODO: optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
+		// TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
 		int tempRef = AllocateVariable(ctx->type.dataType, true);
 		int tempRef = AllocateVariable(ctx->type.dataType, true);
 		ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
 		ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
 		ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
 		ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
@@ -11023,13 +11112,13 @@ void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isCo
 			argSize += AS_PTR_SIZE;
 			argSize += AS_PTR_SIZE;
 		}
 		}
 
 
-		// TODO: optimize: If it is known that a class method cannot be overridden the call
-		//                 should be made with asBC_CALL as it is faster. Examples where this
-		//                 is known is for example finalled methods where the class doesn't derive 
-		//                 from any other, or even non-finalled methods but where it is known
-		//                 at compile time the true type of the object. The first should be
-		//                 quite easy to determine, but the latter will be quite complex and possibly
-		//                 not worth it.
+		// TODO: runtime optimize: If it is known that a class method cannot be overridden the call
+		//                         should be made with asBC_CALL as it is faster. Examples where this
+		//                         is known is for example finalled methods where the class doesn't derive 
+		//                         from any other, or even non-finalled methods but where it is known
+		//                         at compile time the true type of the object. The first should be
+		//                         quite easy to determine, but the latter will be quite complex and possibly
+		//                         not worth it.
 		if( descr->funcType == asFUNC_IMPORTED )
 		if( descr->funcType == asFUNC_IMPORTED )
 			ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
 			ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
 		// TODO: Maybe we need two different byte codes
 		// TODO: Maybe we need two different byte codes
@@ -11203,7 +11292,7 @@ void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContex
 	// Do not copy the origExpr member
 	// Do not copy the origExpr member
 }
 }
 
 
-void asCCompiler::FilterConst(asCArray<int> &funcs)
+void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
 {
 {
 	if( funcs.GetLength() == 0 ) return;
 	if( funcs.GetLength() == 0 ) return;
 
 
@@ -11217,7 +11306,7 @@ void asCCompiler::FilterConst(asCArray<int> &funcs)
 	for( n = 0; n < funcs.GetLength(); n++ )
 	for( n = 0; n < funcs.GetLength(); n++ )
 	{
 	{
 		desc = builder->GetFunctionDescription(funcs[n]);
 		desc = builder->GetFunctionDescription(funcs[n]);
-		if( !desc->isReadOnly )
+		if( desc->isReadOnly != removeConst )
 		{
 		{
 			foundNonConst = true;
 			foundNonConst = true;
 			break;
 			break;
@@ -11230,7 +11319,7 @@ void asCCompiler::FilterConst(asCArray<int> &funcs)
 		for( n = 0; n < funcs.GetLength(); n++ )
 		for( n = 0; n < funcs.GetLength(); n++ )
 		{
 		{
 			desc = builder->GetFunctionDescription(funcs[n]);
 			desc = builder->GetFunctionDescription(funcs[n]);
-			if( desc->isReadOnly )
+			if( desc->isReadOnly == removeConst )
 			{
 			{
 				if( n == funcs.GetLength() - 1 )
 				if( n == funcs.GetLength() - 1 )
 					funcs.PopLast();
 					funcs.PopLast();

+ 1 - 1
ThirdParty/AngelScript/source/as_compiler.h

@@ -206,7 +206,7 @@ protected:
 	int  DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode);
 	int  DoAssignment(asSExprContext *out, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode);
 	void MergeExprBytecode(asSExprContext *before, asSExprContext *after);
 	void MergeExprBytecode(asSExprContext *before, asSExprContext *after);
 	void MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after);
 	void MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after);
-	void FilterConst(asCArray<int> &funcs);
+	void FilterConst(asCArray<int> &funcs, bool removeConst = true);
 	void ConvertToVariable(asSExprContext *ctx);
 	void ConvertToVariable(asSExprContext *ctx);
 	void ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude);
 	void ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude);
 	void ConvertToTempVariable(asSExprContext *ctx);
 	void ConvertToTempVariable(asSExprContext *ctx);

+ 1 - 7
ThirdParty/AngelScript/source/as_config.h

@@ -61,12 +61,7 @@
 
 
 // AS_DEBUG
 // AS_DEBUG
 // This flag can be defined to make the library write some extra output when
 // This flag can be defined to make the library write some extra output when
-// compiling and executing scripts.
-
-// AS_DEBUG_STATS
-// This flag, combined with AS_DEBUG, make the library write out statistics
-// from the VM, for example how many times each bytecode instruction is executed,
-// etc. It is used to help identify potential code for optimizations.
+// compiling and executing scripts. 
 
 
 // AS_DEPRECATED
 // AS_DEPRECATED
 // If this flag is defined then some backwards compatibility is maintained.
 // If this flag is defined then some backwards compatibility is maintained.
@@ -582,7 +577,6 @@
 			#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
 			#define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR)
 		#elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__)
 		#elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__)
 			// 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
 			// 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_NO_THREADS
 			#define AS_X64_GCC
 			#define AS_X64_GCC
 			#define HAS_128_BIT_PRIMITIVES
 			#define HAS_128_BIT_PRIMITIVES
 			#define SPLIT_OBJS_BY_MEMBER_TYPES
 			#define SPLIT_OBJS_BY_MEMBER_TYPES

+ 175 - 85
ThirdParty/AngelScript/source/as_context.cpp

@@ -62,7 +62,7 @@ const int RESERVE_STACK = 2*AS_PTR_SIZE;
 const int CALLSTACK_FRAME_SIZE = 5;
 const int CALLSTACK_FRAME_SIZE = 5;
 
 
 
 
-#if defined(AS_DEBUG) && defined(AS_DEBUG_STATS)
+#if defined(AS_DEBUG)
 
 
 class asCDebugStats
 class asCDebugStats
 {
 {
@@ -137,8 +137,7 @@ public:
 
 
 AS_API asIScriptContext *asGetActiveContext()
 AS_API asIScriptContext *asGetActiveContext()
 {
 {
-	asASSERT(threadManager);
-	asCThreadLocalData *tld = threadManager->GetLocalData();
+	asCThreadLocalData *tld = asCThreadManager::GetLocalData();
 	if( tld->activeContexts.GetLength() == 0 )
 	if( tld->activeContexts.GetLength() == 0 )
 		return 0;
 		return 0;
 	return tld->activeContexts[tld->activeContexts.GetLength()-1];
 	return tld->activeContexts[tld->activeContexts.GetLength()-1];
@@ -146,15 +145,13 @@ AS_API asIScriptContext *asGetActiveContext()
 
 
 void asPushActiveContext(asIScriptContext *ctx)
 void asPushActiveContext(asIScriptContext *ctx)
 {
 {
-	asASSERT(threadManager);
-	asCThreadLocalData *tld = threadManager->GetLocalData();
+	asCThreadLocalData *tld = asCThreadManager::GetLocalData();
 	tld->activeContexts.PushLast(ctx);
 	tld->activeContexts.PushLast(ctx);
 }
 }
 
 
 void asPopActiveContext(asIScriptContext *ctx)
 void asPopActiveContext(asIScriptContext *ctx)
 {
 {
-	asASSERT(threadManager);
-	asCThreadLocalData *tld = threadManager->GetLocalData();
+	asCThreadLocalData *tld = asCThreadManager::GetLocalData();
 
 
 	asASSERT(tld->activeContexts.GetLength() > 0);
 	asASSERT(tld->activeContexts.GetLength() > 0);
 	asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == ctx);
 	asASSERT(tld->activeContexts[tld->activeContexts.GetLength()-1] == ctx);
@@ -288,10 +285,20 @@ asIScriptFunction *asCContext::GetSystemFunction()
 int asCContext::Prepare(asIScriptFunction *func)
 int asCContext::Prepare(asIScriptFunction *func)
 {
 {
 	if( func == 0 ) 
 	if( func == 0 ) 
+	{
+		asCString str;
+		str.Format(TXT_FAILED_IN_FUNC_s_WITH_s, "Prepare", "null");
+		engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
 		return asNO_FUNCTION;
 		return asNO_FUNCTION;
+	}
 
 
 	if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
 	if( status == asEXECUTION_ACTIVE || status == asEXECUTION_SUSPENDED )
+	{
+		asCString str;
+		str.Format(TXT_FAILED_IN_FUNC_s, "Prepare");
+		engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
 		return asCONTEXT_ACTIVE;
 		return asCONTEXT_ACTIVE;
+	}
 
 
 	// Clean the stack if not done before
 	// Clean the stack if not done before
 	if( status != asEXECUTION_FINISHED && status != asEXECUTION_UNINITIALIZED )
 	if( status != asEXECUTION_FINISHED && status != asEXECUTION_UNINITIALIZED )
@@ -318,7 +325,7 @@ int asCContext::Prepare(asIScriptFunction *func)
 		initialFunction->AddRef();
 		initialFunction->AddRef();
 		currentFunction = initialFunction;
 		currentFunction = initialFunction;
 
 
-		// TODO: optimize: GetSpaceNeededForArguments() should be precomputed
+		// TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed
 		argumentsSize = currentFunction->GetSpaceNeededForArguments() + (currentFunction->objectType ? AS_PTR_SIZE : 0);
 		argumentsSize = currentFunction->GetSpaceNeededForArguments() + (currentFunction->objectType ? AS_PTR_SIZE : 0);
 
 
 		// Reserve space for the arguments and return value
 		// Reserve space for the arguments and return value
@@ -365,6 +372,7 @@ int asCContext::Prepare(asIScriptFunction *func)
 		stackIndex              = 0;
 		stackIndex              = 0;
 	}
 	}
 	status = asEXECUTION_PREPARED;
 	status = asEXECUTION_PREPARED;
+	regs.programPointer = 0;
 
 
 	// Reserve space for the arguments and return value
 	// Reserve space for the arguments and return value
 	regs.stackFramePointer = stackBlocks[0] + stackBlockSize - argumentsSize - returnValueSize;
 	regs.stackFramePointer = stackBlocks[0] + stackBlockSize - argumentsSize - returnValueSize;
@@ -383,22 +391,6 @@ int asCContext::Prepare(asIScriptFunction *func)
 		*(void**)ptr = (void*)(stackBlocks[0] + stackBlockSize - returnValueSize);
 		*(void**)ptr = (void*)(stackBlocks[0] + stackBlockSize - returnValueSize);
 	}
 	}
 
 
-	if( currentFunction->funcType == asFUNC_SCRIPT )
-	{
-		regs.programPointer = currentFunction->byteCode.AddressOf();
-
-		// Set all object variables to 0
-		for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
-		{
-			if( !currentFunction->objVariableIsOnHeap[n] ) continue;
-
-			int pos = currentFunction->objVariablePos[n];
-			*(asPWORD*)&regs.stackFramePointer[-pos] = 0;
-		}
-	}
-	else
-		regs.programPointer = 0;
-
 	return asSUCCESS;
 	return asSUCCESS;
 }
 }
 
 
@@ -999,7 +991,12 @@ int asCContext::Execute()
 	asASSERT( engine != 0 );
 	asASSERT( engine != 0 );
 
 
 	if( status != asEXECUTION_SUSPENDED && status != asEXECUTION_PREPARED )
 	if( status != asEXECUTION_SUSPENDED && status != asEXECUTION_PREPARED )
+	{
+		asCString str;
+		str.Format(TXT_FAILED_IN_FUNC_s, "Execute");
+		engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf());
 		return asERROR;
 		return asERROR;
+	}
 
 
 	status = asEXECUTION_ACTIVE;
 	status = asEXECUTION_ACTIVE;
 
 
@@ -1050,24 +1047,20 @@ int asCContext::Execute()
 				if( realFunc )
 				if( realFunc )
 				{
 				{
 					if( realFunc->signatureId != currentFunction->signatureId )
 					if( realFunc->signatureId != currentFunction->signatureId )
-					{
 						SetInternalException(TXT_NULL_POINTER_ACCESS);
 						SetInternalException(TXT_NULL_POINTER_ACCESS);
-					}
 					else
 					else
-					{
 						currentFunction = realFunc;
 						currentFunction = realFunc;
-						regs.programPointer = currentFunction->byteCode.AddressOf();
-
-						// Set the local objects to 0
-						for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
-						{
-							int pos = currentFunction->objVariablePos[n];
-							*(asPWORD*)&regs.stackFramePointer[-pos] = 0;
-						}
-					}
 				}
 				}
 			}
 			}
 		}
 		}
+
+		if( currentFunction->funcType == asFUNC_SCRIPT )
+		{
+			regs.programPointer = currentFunction->byteCode.AddressOf();
+
+			// Set up the internal registers for executing the script function
+			PrepareScriptFunction();
+		}
 		else if( currentFunction->funcType == asFUNC_SYSTEM )
 		else if( currentFunction->funcType == asFUNC_SYSTEM )
 		{
 		{
 			// The current function is an application registered function
 			// The current function is an application registered function
@@ -1121,7 +1114,12 @@ int asCContext::Execute()
 
 
 void asCContext::PushCallState()
 void asCContext::PushCallState()
 {
 {
-	callStack.SetLength(callStack.GetLength() + CALLSTACK_FRAME_SIZE);
+	if( callStack.GetLength() == callStack.GetCapacity() )
+	{
+		// Allocate space for 10 call states at a time to save time
+		callStack.AllocateNoConstruct(callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true);
+	}
+	callStack.SetLengthNoConstruct(callStack.GetLength() + CALLSTACK_FRAME_SIZE);
 
 
     // Separating the loads and stores limits data cache trash, and with a smart compiler
     // Separating the loads and stores limits data cache trash, and with a smart compiler
     // could turn into SIMD style loading/storing if available.
     // could turn into SIMD style loading/storing if available.
@@ -1216,16 +1214,12 @@ int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **secti
 
 
 void asCContext::CallScriptFunction(asCScriptFunction *func)
 void asCContext::CallScriptFunction(asCScriptFunction *func)
 {
 {
-	// TODO: Should perhaps call CallLineCallback() if set. This will allow the 
-	//       application that compiles without line cues to interrupt scripts
-	//       with endless recursive calls. Without this there is no guarantee
-	//       that the SUSPEND instruction is guaranteed to be executed.
-
 	// Push the framepointer, function id and programCounter on the stack
 	// Push the framepointer, function id and programCounter on the stack
 	PushCallState();
 	PushCallState();
 
 
+	// Update the current function and program position before increasing the stack 
+	// so the exception handler will know what to do if there is a stack overflow
 	currentFunction = func;
 	currentFunction = func;
-
 	regs.programPointer = currentFunction->byteCode.AddressOf();
 	regs.programPointer = currentFunction->byteCode.AddressOf();
 
 
 	// Verify if there is enough room in the stack block. Allocate new block if not
 	// Verify if there is enough room in the stack block. Allocate new block if not
@@ -1270,18 +1264,35 @@ void asCContext::CallScriptFunction(asCScriptFunction *func)
 		memcpy(regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
 		memcpy(regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords);
 	}
 	}
 
 
-	// Update framepointer and programCounter
+	PrepareScriptFunction();
+}
+
+void asCContext::PrepareScriptFunction()
+{
+	// Update framepointer
 	regs.stackFramePointer = regs.stackPointer;
 	regs.stackFramePointer = regs.stackPointer;
 
 
-	// TODO: optimize: This can be avoided handling this as is done for value types in the exception handler
-	// Set all object variables to 0
-	for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
+	// Set all object variables to 0 to guarantee that they are null before they are used
+	// Only variables on the heap should be cleared. The rest will be cleared by calling the constructor
+	asUINT n = currentFunction->objVariablesOnHeap;
+	while( n-- > 0 )
 	{
 	{
-		if( !currentFunction->objVariableIsOnHeap[n] ) continue;
-
 		int pos = currentFunction->objVariablePos[n];
 		int pos = currentFunction->objVariablePos[n];
 		*(asPWORD*)&regs.stackFramePointer[-pos] = 0;
 		*(asPWORD*)&regs.stackFramePointer[-pos] = 0;
 	}
 	}
+
+	// Initialize the stack pointer with the space needed for local variables
+	regs.stackPointer -= currentFunction->variableSpace;
+
+	// Call the line callback for each script function, to guarantee that infinitely recursive scripts can
+	// be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES
+	if( regs.doProcessSuspend )
+	{
+		if( lineCallback )
+			CallLineCallback();
+		if( doSuspend )
+			status = asEXECUTION_SUSPENDED;
+	}
 }
 }
 
 
 void asCContext::CallInterfaceMethod(asCScriptFunction *func)
 void asCContext::CallInterfaceMethod(asCScriptFunction *func)
@@ -1296,14 +1307,14 @@ void asCContext::CallInterfaceMethod(asCScriptFunction *func)
 
 
 	asCObjectType *objType = obj->objType;
 	asCObjectType *objType = obj->objType;
 
 
-	// TODO: optimize: The object type should have a list of only those methods that 
-	//                 implement interface methods. This list should be ordered by
-	//                 the signatureId so that a binary search can be made, instead
-	//                 of a linear search.
+	// TODO: runtime optimize: The object type should have a list of only those methods that 
+	//                         implement interface methods. This list should be ordered by
+	//                         the signatureId so that a binary search can be made, instead
+	//                         of a linear search.
 	//
 	//
-	//                 When this is done, we must also make sure the signatureId of a 
-	//                 function never changes, e.g. when if the signature functions are
-	//                 released.
+	//                         When this is done, we must also make sure the signatureId of a 
+	//                         function never changes, e.g. when if the signature functions are
+	//                         released.
 
 
 	// Search the object type for a function that matches the interface function
 	// Search the object type for a function that matches the interface function
 	asCScriptFunction *realFunc = 0;
 	asCScriptFunction *realFunc = 0;
@@ -1347,9 +1358,9 @@ void asCContext::ExecuteNext()
 	{
 	{
 
 
 #ifdef AS_DEBUG
 #ifdef AS_DEBUG
-#ifdef AS_DEBUG_STATS
+	// Gather statistics on executed bytecode 
 	stats.Instr(*(asBYTE*)l_bc);
 	stats.Instr(*(asBYTE*)l_bc);
-#endif
+
 	// Used to verify that the size of the instructions are correct
 	// Used to verify that the size of the instructions are correct
 	asDWORD *old = l_bc;
 	asDWORD *old = l_bc;
 #endif
 #endif
@@ -1365,18 +1376,17 @@ void asCContext::ExecuteNext()
 //--------------
 //--------------
 // memory access functions
 // memory access functions
 
 
-	// Decrease the stack pointer with n dwords (stack grows downward)
-	case asBC_POP:
-		// TODO: optimize: This instruction always pop a single pointer, so there is not really any need for it to take an argument
-		asASSERT( asBC_WORDARG0(l_bc) == AS_PTR_SIZE );
-		l_sp += asBC_WORDARG0(l_bc);
+	case asBC_PopPtr:
+		// Pop a pointer from the stack
+		l_sp += AS_PTR_SIZE;
 		l_bc++;
 		l_bc++;
 		break;
 		break;
 
 
-	// Increase the stack pointer with n dwords
-	case asBC_PUSH:
-		l_sp -= asBC_WORDARG0(l_bc);
-		l_bc++;
+	case asBC_PshGPtr:
+		// Replaces PGA + RDSPtr
+		l_sp -= AS_PTR_SIZE;
+		*(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc);
+		l_bc += 1 + AS_PTR_SIZE;
 		break;
 		break;
 
 
 	// Push a dword value on the stack
 	// Push a dword value on the stack
@@ -1898,8 +1908,21 @@ void asCContext::ExecuteNext()
 		break;
 		break;
 
 
 	case asBC_RDSPtr:
 	case asBC_RDSPtr:
-		// Pop an address from the stack, read a pointer from that address and push it on the stack
-		*(asPWORD*)l_sp = *(asPWORD*)*(asPWORD*)l_sp;
+		{
+			// The pointer must not be null
+			asPWORD a = *(asPWORD*)l_sp;
+			if( a == 0 )
+			{
+				regs.programPointer = l_bc;
+				regs.stackPointer = l_sp;
+				regs.stackFramePointer = l_fp;
+
+				SetInternalException(TXT_NULL_POINTER_ACCESS);
+				return;
+			}
+			// Pop an address from the stack, read a pointer from that address and push it on the stack
+			*(asPWORD*)l_sp = *(asPWORD*)a;
+		}
 		l_bc++;
 		l_bc++;
 		break;
 		break;
 
 
@@ -2360,6 +2383,9 @@ void asCContext::ExecuteNext()
 		break;
 		break;
 
 
 	case asBC_ClrVPtr:
 	case asBC_ClrVPtr:
+		// TODO: optimize: Is this instruction really necessary? 
+		//                 CallScriptFunction() can clear the null handles upon entry, just as is done for 
+		//                 all other object variables
 		// Clear pointer variable
 		// Clear pointer variable
 		*(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
 		*(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0;
 		l_bc++;
 		l_bc++;
@@ -2390,7 +2416,21 @@ void asCContext::ExecuteNext()
 		break;
 		break;
 
 
 	case asBC_ADDSi:
 	case asBC_ADDSi:
-		*(asPWORD*)l_sp = asPWORD(*(asPWORD*)l_sp) + asBC_SWORDARG0(l_bc);
+		{
+			// The pointer must not be null
+			asPWORD a = *(asPWORD*)l_sp;
+			if( a == 0 )
+			{
+				regs.programPointer = l_bc;
+				regs.stackPointer = l_sp;
+				regs.stackFramePointer = l_fp;
+
+				SetInternalException(TXT_NULL_POINTER_ACCESS);
+				return;
+			}
+			// Add an offset to the pointer
+			*(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc);
+		}
 		l_bc += 2;
 		l_bc += 2;
 		break;
 		break;
 
 
@@ -2506,8 +2546,8 @@ void asCContext::ExecuteNext()
 
 
 	case asBC_CmpPtr:
 	case asBC_CmpPtr:
 		{
 		{
-			// TODO: optimize: This instruction should really just be an equals, and return true or false.
-			//                 The instruction is only used for is and !is tests anyway.
+			// TODO: runtime optimize: This instruction should really just be an equals, and return true or false.
+			//                         The instruction is only used for is and !is tests anyway.
 			asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
 			asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc));
 			asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc));
 			asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc));
 			if( p1 == p2 )     *(int*)&regs.valueRegister =  0;
 			if( p1 == p2 )     *(int*)&regs.valueRegister =  0;
@@ -2806,7 +2846,7 @@ void asCContext::ExecuteNext()
 		{
 		{
 			// Verify if the pointer on the stack refers to a non-null value
 			// Verify if the pointer on the stack refers to a non-null value
 			// This is used to validate a reference to a handle
 			// This is used to validate a reference to a handle
-			asDWORD *a = (asDWORD*)*(asPWORD*)l_sp;
+			asPWORD *a = (asPWORD*)*(asPWORD*)l_sp;
 			if( *a == 0 )
 			if( *a == 0 )
 			{
 			{
 				regs.programPointer = l_bc;
 				regs.programPointer = l_bc;
@@ -3397,11 +3437,56 @@ void asCContext::ExecuteNext()
 		}
 		}
 		break;
 		break;
 
 
+	case asBC_RefCpyV:
+		// Same as PSF v, REFCPY
+		{
+			asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc);
+			asSTypeBehaviour *beh = &objType->beh;
+
+			// Determine destination from argument
+			void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc));
+			
+			// Read wanted pointer from the stack
+			void *s = (void*)*(asPWORD*)l_sp;
+
+			// Need to move the values back to the context as the called functions
+			// may use the debug interface to inspect the registers
+			regs.programPointer = l_bc;
+			regs.stackPointer = l_sp;
+			regs.stackFramePointer = l_fp;
+
+			if( !(objType->flags & asOBJ_NOCOUNT) )
+			{
+				// Release previous object held by destination pointer
+				if( *d != 0 )
+					engine->CallObjectMethod(*d, beh->release);
+				// Increase ref counter of wanted object
+				if( s != 0 )
+					engine->CallObjectMethod(s, beh->addref);
+			}
+
+			// Set the new object in the destination
+			*d = s;
+		}
+		l_bc += 1+AS_PTR_SIZE;
+		break;
+
+	case asBC_JLowZ:
+		if( *(asBYTE*)&regs.valueRegister == 0 )
+			l_bc += asBC_INTARG(l_bc) + 2;
+		else
+			l_bc += 2;
+		break;
+
+	case asBC_JLowNZ:
+		if( *(asBYTE*)&regs.valueRegister != 0 )
+			l_bc += asBC_INTARG(l_bc) + 2;
+		else
+			l_bc += 2;
+		break;
+
 	// Don't let the optimizer optimize for size,
 	// Don't let the optimizer optimize for size,
 	// since it requires extra conditions and jumps
 	// since it requires extra conditions and jumps
-	case 186: l_bc = (asDWORD*)186; break;
-	case 187: l_bc = (asDWORD*)187; break;
-	case 188: l_bc = (asDWORD*)188; break;
 	case 189: l_bc = (asDWORD*)189; break;
 	case 189: l_bc = (asDWORD*)189; break;
 	case 190: l_bc = (asDWORD*)190; break;
 	case 190: l_bc = (asDWORD*)190; break;
 	case 191: l_bc = (asDWORD*)191; break;
 	case 191: l_bc = (asDWORD*)191; break;
@@ -3475,18 +3560,19 @@ void asCContext::ExecuteNext()
 		asASSERT(false);
 		asASSERT(false);
 		SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
 		SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE);
 #endif
 #endif
-/*
+#if defined(_MSC_VER) && !defined(AS_DEBUG)
 	default:
 	default:
 		// This Microsoft specific code allows the
 		// This Microsoft specific code allows the
 		// compiler to optimize the switch case as
 		// compiler to optimize the switch case as
 		// it will know that the code will never
 		// it will know that the code will never
 		// reach this point
 		// reach this point
 		__assume(0);
 		__assume(0);
-*/	}
+#endif
+	}
 
 
 #ifdef AS_DEBUG
 #ifdef AS_DEBUG
 		asDWORD instr = *(asBYTE*)old;
 		asDWORD instr = *(asBYTE*)old;
-		if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) &&
+		if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ &&
 			instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr && 
 			instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr && 
 			instr != asBC_JitEntry )
 			instr != asBC_JitEntry )
 		{
 		{
@@ -3749,7 +3835,7 @@ void asCContext::CleanStackFrame()
 		for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
 		for( asUINT n = 0; n < currentFunction->objVariablePos.GetLength(); n++ )
 		{
 		{
 			int pos = currentFunction->objVariablePos[n];
 			int pos = currentFunction->objVariablePos[n];
-			if( currentFunction->objVariableIsOnHeap[n] )
+			if( n < currentFunction->objVariablesOnHeap )
 			{
 			{
 				// Check if the pointer is initialized
 				// Check if the pointer is initialized
 				if( *(asPWORD*)&regs.stackFramePointer[-pos] )
 				if( *(asPWORD*)&regs.stackFramePointer[-pos] )
@@ -3793,11 +3879,15 @@ void asCContext::CleanStackFrame()
 		// the function has actually been entered
 		// the function has actually been entered
 		if( currentFunction->objectType && regs.programPointer != currentFunction->byteCode.AddressOf() )
 		if( currentFunction->objectType && regs.programPointer != currentFunction->byteCode.AddressOf() )
 		{
 		{
-			asSTypeBehaviour *beh = &currentFunction->objectType->beh;
-			if( beh->release && *(asPWORD*)&regs.stackFramePointer[0] != 0 )
+			// Methods returning a reference or constructors don't add a reference
+			if( !currentFunction->returnType.IsReference() && currentFunction->name != currentFunction->objectType->name )
 			{
 			{
-				engine->CallObjectMethod((void*)*(asPWORD*)&regs.stackFramePointer[0], beh->release);
-				*(asPWORD*)&regs.stackFramePointer[0] = 0;
+				asSTypeBehaviour *beh = &currentFunction->objectType->beh;
+				if( beh->release && *(asPWORD*)&regs.stackFramePointer[0] != 0 )
+				{
+					engine->CallObjectMethod((void*)*(asPWORD*)&regs.stackFramePointer[0], beh->release);
+					*(asPWORD*)&regs.stackFramePointer[0] = 0;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -4131,7 +4221,7 @@ void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel)
 			{
 			{
 				if( func->objVariablePos[n] == pos )
 				if( func->objVariablePos[n] == pos )
 				{
 				{
-					onHeap = func->objVariableIsOnHeap[n];
+					onHeap = n < func->objVariablesOnHeap;
 
 
 					if( !onHeap )
 					if( !onHeap )
 					{
 					{

+ 1 - 0
ThirdParty/AngelScript/source/as_context.h

@@ -144,6 +144,7 @@ public:
 	void PopCallState();
 	void PopCallState();
 	void CallScriptFunction(asCScriptFunction *func);
 	void CallScriptFunction(asCScriptFunction *func);
 	void CallInterfaceMethod(asCScriptFunction *func);
 	void CallInterfaceMethod(asCScriptFunction *func);
+	void PrepareScriptFunction();
 
 
 	void SetInternalException(const char *descr);
 	void SetInternalException(const char *descr);
 
 

+ 3 - 1
ThirdParty/AngelScript/source/as_criticalsection.h

@@ -48,7 +48,9 @@ BEGIN_AS_NAMESPACE
 #define DECLARECRITICALSECTION(x) 
 #define DECLARECRITICALSECTION(x) 
 #define ENTERCRITICALSECTION(x) 
 #define ENTERCRITICALSECTION(x) 
 #define LEAVECRITICALSECTION(x) 
 #define LEAVECRITICALSECTION(x) 
-#define TRYENTERCRITICALSECTION(x) true
+
+inline bool tryEnter() { return true; }
+#define TRYENTERCRITICALSECTION(x) tryEnter()
 
 
 #else
 #else
 
 

+ 2 - 2
ThirdParty/AngelScript/source/as_generic.cpp

@@ -42,8 +42,8 @@
 
 
 BEGIN_AS_NAMESPACE
 BEGIN_AS_NAMESPACE
 
 
-// TODO: optimize: The access to the arguments should be optimized so that code 
-//                 doesn't have to count the position of the argument with every call
+// TODO: runtime optimize: The access to the arguments should be optimized so that code 
+//                         doesn't have to count the position of the argument with every call
 
 
 // internal
 // internal
 asCGeneric::asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer)
 asCGeneric::asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer)

+ 2 - 4
ThirdParty/AngelScript/source/as_module.cpp

@@ -671,8 +671,7 @@ const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespa
 
 
 	asCGlobalProperty *prop = scriptGlobals[index];
 	asCGlobalProperty *prop = scriptGlobals[index];
 
 
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	*tempString = prop->type.Format();
 	*tempString = prop->type.Format();
 	*tempString += " ";
 	*tempString += " ";
 	if( includeNamespace )
 	if( includeNamespace )
@@ -979,8 +978,7 @@ const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const
 	asCScriptFunction *func = GetImportedFunction(index);
 	asCScriptFunction *func = GetImportedFunction(index);
 	if( func == 0 ) return 0;
 	if( func == 0 ) return 0;
 
 
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	*tempString = func->GetDeclarationStr();
 	*tempString = func->GetDeclarationStr();
 
 
 	return tempString->AddressOf();
 	return tempString->AddressOf();

+ 1 - 2
ThirdParty/AngelScript/source/as_objecttype.cpp

@@ -521,8 +521,7 @@ const char *asCObjectType::GetPropertyDeclaration(asUINT index) const
 	if( index >= properties.GetLength() )
 	if( index >= properties.GetLength() )
 		return 0;
 		return 0;
 
 
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	if( properties[index]->isPrivate )
 	if( properties[index]->isPrivate )
 		*tempString = "private ";
 		*tempString = "private ";
 	else
 	else

+ 85 - 97
ThirdParty/AngelScript/source/as_restore.cpp

@@ -536,6 +536,8 @@ asCScriptFunction *asCReader::ReadFunction(bool addToModule, bool addToEngine, b
 		
 		
 		ReadByteCode(func);
 		ReadByteCode(func);
 
 
+		func->variableSpace = ReadEncodedUInt();
+
 		count = ReadEncodedUInt();
 		count = ReadEncodedUInt();
 		func->objVariablePos.Allocate(count, 0);
 		func->objVariablePos.Allocate(count, 0);
 		func->objVariableTypes.Allocate(count, 0);
 		func->objVariableTypes.Allocate(count, 0);
@@ -547,9 +549,11 @@ asCScriptFunction *asCReader::ReadFunction(bool addToModule, bool addToEngine, b
 			func->funcVariableTypes.PushLast((asCScriptFunction*)(asPWORD)idx);
 			func->funcVariableTypes.PushLast((asCScriptFunction*)(asPWORD)idx);
 			num = ReadEncodedUInt();
 			num = ReadEncodedUInt();
 			func->objVariablePos.PushLast(num);
 			func->objVariablePos.PushLast(num);
-			bool b; ReadData(&b, 1);
-			func->objVariableIsOnHeap.PushLast(b);
 		}
 		}
+		if( count > 0 )
+			func->objVariablesOnHeap = ReadEncodedUInt();
+		else
+			func->objVariablesOnHeap = 0;
 
 
 		int length = ReadEncodedUInt();
 		int length = ReadEncodedUInt();
 		func->objVariableInfo.SetLength(length);
 		func->objVariableInfo.SetLength(length);
@@ -871,10 +875,15 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase)
 							// TODO: Write message
 							// TODO: Write message
 							error = true;
 							error = true;
 						}
 						}
-						// Destroy the function without releasing any references
-						func->id = 0;
-						func->byteCode.SetLength(0);
-						func->Release();
+						// If the function received wasn't an already existing 
+						// function we must now destroy it
+						if( !savedFunctions.Exists(func) )
+						{
+							// Destroy the function without releasing any references
+							func->id = 0;
+							func->byteCode.SetLength(0);
+							func->Release();
+						}
 					}
 					}
 					else
 					else
 					{
 					{
@@ -920,10 +929,15 @@ void asCReader::ReadObjectTypeDeclaration(asCObjectType *ot, int phase)
 							// TODO: Write message
 							// TODO: Write message
 							error = true;
 							error = true;
 						}
 						}
-						// Destroy the function without releasing any references
-						func->id = 0;
-						func->byteCode.SetLength(0);
-						func->Release();
+						// If the function received wasn't an already existing 
+						// function we must now destroy it
+						if( !savedFunctions.Exists(func) )
+						{
+							// Destroy the function without releasing any references
+							func->id = 0;
+							func->byteCode.SetLength(0);
+							func->Release();
+						}
 					}
 					}
 					else
 					else
 					{
 					{
@@ -1693,7 +1707,9 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 	{
 	{
 		int c = *(asBYTE*)&bc[n];
 		int c = *(asBYTE*)&bc[n];
 		if( c == asBC_FREE ||
 		if( c == asBC_FREE ||
-			c == asBC_REFCPY || c == asBC_OBJTYPE )
+			c == asBC_REFCPY || 
+			c == asBC_RefCpyV ||
+			c == asBC_OBJTYPE )
 		{
 		{
 			// Translate the index to the true object type
 			// Translate the index to the true object type
 			asPWORD *ot = (asPWORD*)&bc[n+1];
 			asPWORD *ot = (asPWORD*)&bc[n+1];
@@ -1751,10 +1767,6 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 			if( func->objectType ) dw += AS_PTR_SIZE;
 			if( func->objectType ) dw += AS_PTR_SIZE;
 			asBC_WORDARG0(&bc[n]) = dw;
 			asBC_WORDARG0(&bc[n]) = dw;
 		}
 		}
-		else if( c == asBC_POP )
-		{
-			asBC_WORDARG0(&bc[n]) = AS_PTR_SIZE;
-		}
 		else if( c == asBC_CALL ||
 		else if( c == asBC_CALL ||
 				 c == asBC_CALLINTF ||
 				 c == asBC_CALLINTF ||
 				 c == asBC_CALLSYS )
 				 c == asBC_CALLSYS )
@@ -1836,13 +1848,14 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 				return;
 				return;
 			}
 			}
 		}
 		}
-		else if( c == asBC_PGA ||
-			     c == asBC_LDG ||
-				 c == asBC_PshG4 ||
-				 c == asBC_LdGRdR4 ||
+		else if( c == asBC_PGA      ||
+			     c == asBC_PshGPtr  ||
+			     c == asBC_LDG      ||
+				 c == asBC_PshG4    ||
+				 c == asBC_LdGRdR4  ||
 				 c == asBC_CpyGtoV4 ||
 				 c == asBC_CpyGtoV4 ||
 				 c == asBC_CpyVtoG4 ||
 				 c == asBC_CpyVtoG4 ||
-				 c == asBC_SetG4 )
+				 c == asBC_SetG4    )
 		{
 		{
 			// Translate the global var index to pointer
 			// Translate the global var index to pointer
 			asPWORD *index = (asPWORD*)&bc[n+1];
 			asPWORD *index = (asPWORD*)&bc[n+1];
@@ -1855,13 +1868,15 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 				return;
 				return;
 			}
 			}
 		}
 		}
-		else if( c == asBC_JMP ||
-			     c == asBC_JZ ||
-				 c == asBC_JNZ ||
-				 c == asBC_JS ||
-				 c == asBC_JNS ||
-				 c == asBC_JP ||
-				 c == asBC_JNP ) // The JMPP instruction doesn't need modification
+		else if( c == asBC_JMP    ||
+			     c == asBC_JZ     ||
+				 c == asBC_JNZ    ||
+			     c == asBC_JLowZ  ||
+				 c == asBC_JLowNZ ||
+				 c == asBC_JS     ||
+				 c == asBC_JNS    ||
+				 c == asBC_JP     ||
+				 c == asBC_JNP    ) // The JMPP instruction doesn't need modification
 		{
 		{
 			// Get the offset 
 			// Get the offset 
 			int offset = int(bc[n+1]);
 			int offset = int(bc[n+1]);
@@ -1929,19 +1944,12 @@ void asCReader::TranslateFunction(asCScriptFunction *func)
 			break;
 			break;
 		}
 		}
 
 
-		if( c == asBC_PUSH )
-		{
-			// TODO: Maybe the push instruction should be removed, and be kept in 
-			//       the asCScriptFunction as a property instead. CallScriptFunction 
-			//       can immediately reserve the space
-
-			// PUSH is only used to reserve stack space for variables
-			asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n]));
-		}
-
 		n += asBCTypeSize[asBCInfo[c].type];
 		n += asBCTypeSize[asBCInfo[c].type];
 	}
 	}
 
 
+	// Adjust the space needed for local variables
+	func->variableSpace = AdjustStackPosition(func->variableSpace);
+
 	// Adjust the variable information. This will be used during the adjustment below
 	// Adjust the variable information. This will be used during the adjustment below
 	for( n = 0; n < func->variables.GetLength(); n++ )
 	for( n = 0; n < func->variables.GetLength(); n++ )
 	{
 	{
@@ -2006,10 +2014,10 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
 	memset(&stackSize[0], -1, stackSize.GetLength()*4);
 	memset(&stackSize[0], -1, stackSize.GetLength()*4);
 
 
 	// Add the first instruction to the list of unchecked code 
 	// Add the first instruction to the list of unchecked code 
-	// paths and set the stack size at that instruction to 0
+	// paths and set the stack size at that instruction to variableSpace
 	asCArray<asUINT> paths;
 	asCArray<asUINT> paths;
 	paths.PushLast(0);
 	paths.PushLast(0);
-	stackSize[0] = 0;
+	stackSize[0] = func->variableSpace;
 
 
 	// Go through each of the code paths
 	// Go through each of the code paths
 	for( asUINT p = 0; p < paths.GetLength(); ++p )
 	for( asUINT p = 0; p < paths.GetLength(); ++p )
@@ -2026,27 +2034,21 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
 		if( stackInc == 0xFFFF )
 		if( stackInc == 0xFFFF )
 		{
 		{
 			// Determine the true delta from the instruction arguments
 			// Determine the true delta from the instruction arguments
-			if( bc == asBC_POP )
-			{
-				stackInc = -(int)asBC_WORDARG0(&func->byteCode[pos]);
-			}
-			else if( bc == asBC_PUSH )
-			{
-				stackInc = asBC_WORDARG0(&func->byteCode[pos]);
-			}
-			else if( bc == asBC_CALL ||
-			         bc == asBC_CALLSYS ||
-					 bc == asBC_CALLBND ||
-					 bc == asBC_ALLOC ||
-					 bc == asBC_CALLINTF )
+			if( bc == asBC_CALL ||
+			    bc == asBC_CALLSYS ||
+				bc == asBC_CALLBND ||
+				bc == asBC_ALLOC ||
+				bc == asBC_CALLINTF ||
+				bc == asBC_CallPtr )
 			{
 			{
 				asCScriptFunction *called = GetCalledFunction(func, pos);
 				asCScriptFunction *called = GetCalledFunction(func, pos);
 				if( called )
 				if( called )
 				{
 				{
 					stackInc = -called->GetSpaceNeededForArguments();
 					stackInc = -called->GetSpaceNeededForArguments();
-
 					if( called->objectType )
 					if( called->objectType )
 						stackInc -= AS_PTR_SIZE;
 						stackInc -= AS_PTR_SIZE;
+					if( called->DoesReturnOnStack() )
+						stackInc -= AS_PTR_SIZE;
 				}
 				}
 				else
 				else
 				{
 				{
@@ -2055,11 +2057,6 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
 					stackInc = -AS_PTR_SIZE;
 					stackInc = -AS_PTR_SIZE;
 				}
 				}
 			}
 			}
-			else if ( bc == asBC_CallPtr )
-			{
-				// TODO: bytecode: Determine the function signature from the variable
-				break;
-			}
 		}
 		}
 		
 		
 		currStackSize += stackInc;
 		currStackSize += stackInc;
@@ -2084,9 +2081,10 @@ void asCReader::CalculateStackNeeded(asCScriptFunction *func)
 				asASSERT(stackSize[pos] == currStackSize);
 				asASSERT(stackSize[pos] == currStackSize);
 			continue;
 			continue;
 		}
 		}
-		else if( bc == asBC_JZ || bc == asBC_JNZ ||
-				 bc == asBC_JS || bc == asBC_JNS ||
-				 bc == asBC_JP || bc == asBC_JNP )
+		else if( bc == asBC_JZ    || bc == asBC_JNZ    ||
+				 bc == asBC_JLowZ || bc == asBC_JLowNZ ||
+				 bc == asBC_JS    || bc == asBC_JNS    ||
+				 bc == asBC_JP    || bc == asBC_JNP )
 		{
 		{
 			// Find the label that is being jumped to
 			// Find the label that is being jumped to
 			int offset = asBC_INTARG(&func->byteCode[pos]);
 			int offset = asBC_INTARG(&func->byteCode[pos]);
@@ -2207,7 +2205,7 @@ void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func)
 			// Determine the size the variable currently occupies on the stack
 			// Determine the size the variable currently occupies on the stack
 			int size = AS_PTR_SIZE;
 			int size = AS_PTR_SIZE;
 			if( (func->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
 			if( (func->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
-				!func->objVariableIsOnHeap[n] )
+				n >= func->objVariablesOnHeap )
 			{
 			{
 				size = func->objVariableTypes[n]->GetSize();
 				size = func->objVariableTypes[n]->GetSize();
 				if( size < 4 ) 
 				if( size < 4 ) 
@@ -2663,6 +2661,9 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
 
 
 		WriteByteCode(func);
 		WriteByteCode(func);
 
 
+		asDWORD varSpace = AdjustStackPosition(func->variableSpace);
+		WriteEncodedInt64(varSpace);
+
 		count = (asUINT)func->objVariablePos.GetLength();
 		count = (asUINT)func->objVariablePos.GetLength();
 		WriteEncodedInt64(count);
 		WriteEncodedInt64(count);
 		for( i = 0; i < count; ++i )
 		for( i = 0; i < count; ++i )
@@ -2671,8 +2672,9 @@ void asCWriter::WriteFunction(asCScriptFunction* func)
 			// TODO: Only write this if the object type is the builtin function type
 			// TODO: Only write this if the object type is the builtin function type
 			WriteEncodedInt64(FindFunctionIndex(func->funcVariableTypes[i]));
 			WriteEncodedInt64(FindFunctionIndex(func->funcVariableTypes[i]));
 			WriteEncodedInt64(AdjustStackPosition(func->objVariablePos[i]));
 			WriteEncodedInt64(AdjustStackPosition(func->objVariablePos[i]));
-			WriteData(&func->objVariableIsOnHeap[i], 1);
 		}
 		}
+		if( count > 0 )
+			WriteEncodedInt64(func->objVariablesOnHeap);
 
 
 		WriteEncodedInt64((asUINT)func->objVariableInfo.GetLength());
 		WriteEncodedInt64((asUINT)func->objVariableInfo.GetLength());
 		for( i = 0; i < func->objVariableInfo.GetLength(); ++i )
 		for( i = 0; i < func->objVariableInfo.GetLength(); ++i )
@@ -3110,7 +3112,7 @@ void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func)
 			// Determine the size the variable currently occupies on the stack
 			// Determine the size the variable currently occupies on the stack
 			int size = AS_PTR_SIZE;
 			int size = AS_PTR_SIZE;
 			if( (func->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
 			if( (func->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) &&
-				!func->objVariableIsOnHeap[n] )
+				n >= func->objVariablesOnHeap )
 			{
 			{
 				size = func->objVariableTypes[n]->GetSize();
 				size = func->objVariableTypes[n]->GetSize();
 				if( size < 4 ) 
 				if( size < 4 ) 
@@ -3303,9 +3305,10 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
 			if( ot->flags & asOBJ_SCRIPT_OBJECT )
 			if( ot->flags & asOBJ_SCRIPT_OBJECT )
 				*(int*)&tmp[1+AS_PTR_SIZE] = FindFunctionIndex(engine->scriptFunctions[*(int*)&tmp[1+AS_PTR_SIZE]]);
 				*(int*)&tmp[1+AS_PTR_SIZE] = FindFunctionIndex(engine->scriptFunctions[*(int*)&tmp[1+AS_PTR_SIZE]]);
 		}
 		}
-		else if( c == asBC_FREE   || // wW_PTR_ARG
-			     c == asBC_REFCPY || // PTR_ARG
-				 c == asBC_OBJTYPE ) // PTR_ARG
+		else if( c == asBC_FREE    || // wW_PTR_ARG
+			     c == asBC_REFCPY  || // PTR_ARG
+				 c == asBC_RefCpyV || // wW_PTR_ARG
+				 c == asBC_OBJTYPE )  // PTR_ARG
 		{
 		{
 			// Translate object type pointers into indices
 			// Translate object type pointers into indices
 			*(int*)(tmp+1) = FindObjectTypeIdx(*(asCObjectType**)(tmp+1));
 			*(int*)(tmp+1) = FindObjectTypeIdx(*(asCObjectType**)(tmp+1));
@@ -3352,14 +3355,6 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
 			// Save with arg 0, as this will be recalculated on the target platform
 			// Save with arg 0, as this will be recalculated on the target platform
 			asBC_WORDARG0(tmp) = 0;
 			asBC_WORDARG0(tmp) = 0;
 		}
 		}
-		else if( c == asBC_POP ) // W_ARG
-		{
-			// The pop instruction always pop a single pointer
-			asASSERT(asBC_WORDARG0(tmp) == AS_PTR_SIZE);
-			
-			// Save with arg 0, as this will be recalculated on the target platform
-			asBC_WORDARG0(tmp) = 0;
-		}
 		else if( c == asBC_CALL ||     // DW_ARG
 		else if( c == asBC_CALL ||     // DW_ARG
 				 c == asBC_CALLINTF || // DW_ARG
 				 c == asBC_CALLINTF || // DW_ARG
 				 c == asBC_CALLSYS )   // DW_ARG
 				 c == asBC_CALLSYS )   // DW_ARG
@@ -3391,24 +3386,27 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
 
 
 			tmp[1] = funcId;
 			tmp[1] = funcId;
 		}
 		}
-		else if( c == asBC_PGA ||      // PTR_ARG
-			     c == asBC_LDG ||      // PTR_ARG
-				 c == asBC_PshG4 ||    // PTR_ARG
-				 c == asBC_LdGRdR4 ||  // wW_PTR_ARG
+		else if( c == asBC_PGA      || // PTR_ARG
+			     c == asBC_PshGPtr  || // PTR_ARG 
+			     c == asBC_LDG      || // PTR_ARG
+				 c == asBC_PshG4    || // PTR_ARG
+				 c == asBC_LdGRdR4  || // wW_PTR_ARG
 				 c == asBC_CpyGtoV4 || // wW_PTR_ARG
 				 c == asBC_CpyGtoV4 || // wW_PTR_ARG
 				 c == asBC_CpyVtoG4 || // rW_PTR_ARG
 				 c == asBC_CpyVtoG4 || // rW_PTR_ARG
-				 c == asBC_SetG4 )     // PTR_DW_ARG
+				 c == asBC_SetG4    )  // PTR_DW_ARG
 		{
 		{
 			// Translate global variable pointers into indices
 			// Translate global variable pointers into indices
 			*(int*)(tmp+1) = FindGlobalPropPtrIndex(*(void**)(tmp+1));
 			*(int*)(tmp+1) = FindGlobalPropPtrIndex(*(void**)(tmp+1));
 		}
 		}
-		else if( c == asBC_JMP ||	// DW_ARG
-			     c == asBC_JZ ||
-				 c == asBC_JNZ ||
-				 c == asBC_JS ||
-				 c == asBC_JNS ||
-				 c == asBC_JP ||
-				 c == asBC_JNP ) // The JMPP instruction doesn't need modification
+		else if( c == asBC_JMP    ||	// DW_ARG
+			     c == asBC_JZ     ||
+				 c == asBC_JNZ    ||
+				 c == asBC_JLowZ  ||
+				 c == asBC_JLowNZ ||
+				 c == asBC_JS     ||
+				 c == asBC_JNS    ||
+				 c == asBC_JP     ||
+				 c == asBC_JNP    ) // The JMPP instruction doesn't need modification
 		{
 		{
 			// Get the DWORD offset from arg
 			// Get the DWORD offset from arg
 			int offset = *(int*)(tmp+1);
 			int offset = *(int*)(tmp+1);
@@ -3467,16 +3465,6 @@ void asCWriter::WriteByteCode(asCScriptFunction *func)
 			break;
 			break;
 		}
 		}
 
 
-		if( c == asBC_PUSH )
-		{
-			// TODO: Maybe the push instruction should be removed, and be kept in 
-			//       the asCScriptFunction as a property instead. CallScriptFunction 
-			//       can immediately reserve the space
-
-			// PUSH is only used to reserve stack space for variables
-			asBC_WORDARG0(tmp) = (asWORD)AdjustStackPosition(asBC_WORDARG0(tmp));
-		}
-				 
 		// TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. 
 		// TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. 
 		//                 Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values
 		//                 Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values
 		
 		

+ 6 - 13
ThirdParty/AngelScript/source/as_scriptengine.cpp

@@ -384,13 +384,7 @@ asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const
 
 
 asCScriptEngine::asCScriptEngine() 
 asCScriptEngine::asCScriptEngine() 
 {
 {
-	// Instanciate the thread manager
-	ENTERCRITICALSECTION(engineCritical);
-	if( threadManager == 0 )
-		threadManager = asNEW(asCThreadManager);
-	else
-		threadManager->AddRef();
-	LEAVECRITICALSECTION(engineCritical);
+	asCThreadManager::AddRef();
 
 
 	// Engine properties
 	// Engine properties
 	{
 	{
@@ -672,8 +666,7 @@ asCScriptEngine::~asCScriptEngine()
 	if( userData && cleanEngineFunc )
 	if( userData && cleanEngineFunc )
 		cleanEngineFunc(this);
 		cleanEngineFunc(this);
 
 
-	// Release the thread manager
-	threadManager->Release();
+	asCThreadManager::Release();
 }
 }
 
 
 // interface
 // interface
@@ -2968,6 +2961,7 @@ asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *t
 		}
 		}
 		func->inOutFlags[p-1] = factory->inOutFlags[p];
 		func->inOutFlags[p-1] = factory->inOutFlags[p];
 	}
 	}
+	func->objVariablesOnHeap = 0;
 
 
 	SetScriptFunction(func);
 	SetScriptFunction(func);
 
 
@@ -3493,7 +3487,7 @@ void asCScriptEngine::GCEnumCallback(void *reference)
 
 
 
 
 // TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it
 // TODO: multithread: The mapTypeIdToDataType must be protected with critical sections in all functions that access it
-/// Urho3D: modified for type id caching
+// Urho3D: modified for type id caching
 int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const
 int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const
 {
 {
 	if( dtIn.IsNullHandle() ) return 0;
 	if( dtIn.IsNullHandle() ) return 0;
@@ -3617,8 +3611,7 @@ const char *asCScriptEngine::GetTypeDeclaration(int typeId, bool includeNamespac
 {
 {
 	asCDataType dt = GetDataTypeFromTypeId(typeId);
 	asCDataType dt = GetDataTypeFromTypeId(typeId);
 
 
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	*tempString = dt.Format(includeNamespace);
 	*tempString = dt.Format(includeNamespace);
 
 
 	return tempString->AddressOf();
 	return tempString->AddressOf();
@@ -3685,7 +3678,7 @@ void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectT
 	// This function is only meant to be used for value types
 	// This function is only meant to be used for value types
 	asASSERT( type->flags & asOBJ_VALUE );
 	asASSERT( type->flags & asOBJ_VALUE );
 
 
-	// TODO: optimize: Should use the copy constructor when available
+	// TODO: runtime optimize: Should use the copy constructor when available
 	int funcIndex = type->beh.construct;
 	int funcIndex = type->beh.construct;
 	if( funcIndex )
 	if( funcIndex )
 		CallObjectMethod(mem, funcIndex);
 		CallObjectMethod(mem, funcIndex);

+ 15 - 9
ThirdParty/AngelScript/source/as_scriptfunction.cpp

@@ -148,11 +148,12 @@ asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, as
 	id                     = 0;
 	id                     = 0;
 	accessMask             = 0xFFFFFFFF;
 	accessMask             = 0xFFFFFFFF;
 	isShared               = false;
 	isShared               = false;
+	variableSpace          = 0;
 
 
-	// TODO: optimize: The engine could notify the GC just before it wants to
-	//                 discard the function. That way the GC won't waste time
-	//                 trying to determine if the functions are garbage before
-	//                 they can actually be considered garbage.
+	// TODO: runtime optimize: The engine could notify the GC just before it wants to
+	//                         discard the function. That way the GC won't waste time
+	//                         trying to determine if the functions are garbage before
+	//                         they can actually be considered garbage.
 	// Notify the GC of script functions
 	// Notify the GC of script functions
 	if( funcType == asFUNC_SCRIPT )
 	if( funcType == asFUNC_SCRIPT )
 		engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
 		engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours);
@@ -194,7 +195,7 @@ void asCScriptFunction::DestroyInternal()
 	// Release all references the function holds to other objects
 	// Release all references the function holds to other objects
 	ReleaseReferences();
 	ReleaseReferences();
 	parameterTypes.SetLength(0);
 	parameterTypes.SetLength(0);
-	returnType == asCDataType::CreatePrimitive(ttVoid, false);
+	returnType = asCDataType::CreatePrimitive(ttVoid, false);
 	byteCode.SetLength(0);
 	byteCode.SetLength(0);
 
 
 	for( asUINT n = 0; n < variables.GetLength(); n++ )
 	for( asUINT n = 0; n < variables.GetLength(); n++ )
@@ -488,8 +489,7 @@ const char *asCScriptFunction::GetVarDecl(asUINT index) const
 	if( index >= variables.GetLength() )
 	if( index >= variables.GetLength() )
 		return 0;
 		return 0;
 
 
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	*tempString = variables[index]->type.Format();
 	*tempString = variables[index]->type.Format();
 	*tempString += " " + variables[index]->name;
 	*tempString += " " + variables[index]->name;
 
 
@@ -597,6 +597,7 @@ void asCScriptFunction::AddReferences()
 		case asBC_OBJTYPE:
 		case asBC_OBJTYPE:
 		case asBC_FREE:
 		case asBC_FREE:
 		case asBC_REFCPY:
 		case asBC_REFCPY:
+		case asBC_RefCpyV:
 			{
 			{
                 asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
                 asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				objType->AddRef();
 				objType->AddRef();
@@ -617,6 +618,7 @@ void asCScriptFunction::AddReferences()
 
 
 		// Global variables
 		// Global variables
 		case asBC_PGA:
 		case asBC_PGA:
+		case asBC_PshGPtr:
 		case asBC_LDG:
 		case asBC_LDG:
 		case asBC_PshG4:
 		case asBC_PshG4:
 		case asBC_LdGRdR4:
 		case asBC_LdGRdR4:
@@ -704,6 +706,7 @@ void asCScriptFunction::ReleaseReferences()
 		case asBC_OBJTYPE:
 		case asBC_OBJTYPE:
 		case asBC_FREE:
 		case asBC_FREE:
 		case asBC_REFCPY:
 		case asBC_REFCPY:
+		case asBC_RefCpyV:
 			{
 			{
 				asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				if( objType ) 
 				if( objType ) 
@@ -736,6 +739,7 @@ void asCScriptFunction::ReleaseReferences()
 
 
 		// Global variables
 		// Global variables
 		case asBC_PGA:
 		case asBC_PGA:
+		case asBC_PshGPtr:
 		case asBC_LDG:
 		case asBC_LDG:
 		case asBC_PshG4:
 		case asBC_PshG4:
 		case asBC_LdGRdR4:
 		case asBC_LdGRdR4:
@@ -843,8 +847,7 @@ asIScriptEngine *asCScriptFunction::GetEngine() const
 // interface
 // interface
 const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace) const
 const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace) const
 {
 {
-	asASSERT(threadManager);
-	asCString *tempString = &threadManager->GetLocalData()->string;
+	asCString *tempString = &asCThreadManager::GetLocalData()->string;
 	*tempString = GetDeclarationStr(includeObjectName, includeNamespace);
 	*tempString = GetDeclarationStr(includeObjectName, includeNamespace);
 	return tempString->AddressOf();
 	return tempString->AddressOf();
 }
 }
@@ -979,6 +982,7 @@ void asCScriptFunction::EnumReferences(asIScriptEngine *)
 		case asBC_OBJTYPE:
 		case asBC_OBJTYPE:
 		case asBC_FREE:
 		case asBC_FREE:
 		case asBC_REFCPY:
 		case asBC_REFCPY:
+		case asBC_RefCpyV:
 			{
 			{
                 asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
                 asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				engine->GCEnumCallback(objType);
 				engine->GCEnumCallback(objType);
@@ -1016,6 +1020,7 @@ void asCScriptFunction::EnumReferences(asIScriptEngine *)
 
 
 		// Global variables
 		// Global variables
 		case asBC_PGA:
 		case asBC_PGA:
+		case asBC_PshGPtr:
 		case asBC_LDG:
 		case asBC_LDG:
 		case asBC_PshG4:
 		case asBC_PshG4:
 		case asBC_LdGRdR4:
 		case asBC_LdGRdR4:
@@ -1068,6 +1073,7 @@ void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *)
 		case asBC_OBJTYPE:
 		case asBC_OBJTYPE:
 		case asBC_FREE:
 		case asBC_FREE:
 		case asBC_REFCPY:
 		case asBC_REFCPY:
+		case asBC_RefCpyV:
 			{
 			{
 				asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&byteCode[n]);
 				if( objType )
 				if( objType )

+ 9 - 5
ThirdParty/AngelScript/source/as_scriptfunction.h

@@ -86,10 +86,10 @@ struct asSSystemFunctionInterface;
 //       also functions/methods that are being called. This could be used to build a 
 //       also functions/methods that are being called. This could be used to build a 
 //       code database with call graphs, etc.
 //       code database with call graphs, etc.
 
 
-// TODO: optimize: The GC should only be notified of the script function when the last module
-//                 removes it from the scope. Must make sure it is only added to the GC once
-//                 in case the function is added to another module after the GC already knows 
-//                 about the function.
+// TODO: runtime optimize: The GC should only be notified of the script function when the last module
+//                         removes it from the scope. Must make sure it is only added to the GC once
+//                         in case the function is added to another module after the GC already knows 
+//                         about the function.
 
 
 void RegisterScriptFunction(asCScriptEngine *engine);
 void RegisterScriptFunction(asCScriptEngine *engine);
 
 
@@ -211,13 +211,17 @@ public:
 
 
 	// Used by asFUNC_SCRIPT
 	// Used by asFUNC_SCRIPT
 	asCArray<asDWORD>               byteCode;
 	asCArray<asDWORD>               byteCode;
+	// The stack space needed for the local variables
+	asDWORD                         variableSpace;
 
 
 	// These hold information objects and function pointers, including temporary
 	// These hold information objects and function pointers, including temporary
 	// variables used by exception handler and when saving bytecode
 	// variables used by exception handler and when saving bytecode
 	asCArray<asCObjectType*>        objVariableTypes;
 	asCArray<asCObjectType*>        objVariableTypes;
 	asCArray<asCScriptFunction*>    funcVariableTypes;
 	asCArray<asCScriptFunction*>    funcVariableTypes;
 	asCArray<int>	                objVariablePos;
 	asCArray<int>	                objVariablePos;
-	asCArray<bool>                  objVariableIsOnHeap;
+	// The first variables in above array are allocated on the heap, the rest on the stack.
+	// This variable shows how many are on the heap.
+	asUINT                          objVariablesOnHeap;
 
 
 	// Holds information on scope for object variables on the stack
 	// Holds information on scope for object variables on the stack
 	asCArray<asSObjectVariableInfo> objVariableInfo;
 	asCArray<asSObjectVariableInfo> objVariableInfo;

+ 2 - 0
ThirdParty/AngelScript/source/as_texts.h

@@ -46,6 +46,7 @@
 
 
 #define TXT_BOTH_MUST_BE_SAME                     "Both expressions must have the same type"
 #define TXT_BOTH_MUST_BE_SAME                     "Both expressions must have the same type"
 #define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor"
 #define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor"
+#define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR          "Base class doesn't have default constructor. Make explicit call to base constructor"
 
 
 #define TXT_CANDIDATES_ARE                       "Candidates are:"
 #define TXT_CANDIDATES_ARE                       "Candidates are:"
 #define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS     "Can't call a constructor in loops"
 #define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS     "Can't call a constructor in loops"
@@ -168,6 +169,7 @@
 #define TXT_ONLY_ONE_ARGUMENT_IN_CAST      "A cast operator has one argument"
 #define TXT_ONLY_ONE_ARGUMENT_IN_CAST      "A cast operator has one argument"
 #define TXT_ONLY_ONE_FUNCTION_ALLOWED      "The code must contain one and only one function"
 #define TXT_ONLY_ONE_FUNCTION_ALLOWED      "The code must contain one and only one function"
 #define TXT_ONLY_ONE_VARIABLE_ALLOWED      "The code must contain one and only one global variable"
 #define TXT_ONLY_ONE_VARIABLE_ALLOWED      "The code must contain one and only one global variable"
+#define TXT_OPERANDS_MUST_BE_HANDLES       "Both operands must be handles when comparing identity"
 
 
 #define TXT_PARAMETER_ALREADY_DECLARED            "Parameter already declared"
 #define TXT_PARAMETER_ALREADY_DECLARED            "Parameter already declared"
 #define TXT_PARAMETER_CANT_BE_s                   "Parameter type can't be '%s', because the type cannot be instanciated."
 #define TXT_PARAMETER_CANT_BE_s                   "Parameter type can't be '%s', because the type cannot be instanciated."

+ 72 - 40
ThirdParty/AngelScript/source/as_thread.cpp

@@ -1,6 +1,6 @@
 /*
 /*
    AngelCode Scripting Library
    AngelCode Scripting Library
-   Copyright (c) 2003-2011 Andreas Jonsson
+   Copyright (c) 2003-2012 Andreas Jonsson
 
 
    This software is provided 'as-is', without any express or implied 
    This software is provided 'as-is', without any express or implied 
    warranty. In no event will the authors be held liable for any 
    warranty. In no event will the authors be held liable for any 
@@ -42,57 +42,74 @@
 
 
 BEGIN_AS_NAMESPACE
 BEGIN_AS_NAMESPACE
 
 
-// Singleton
-asCThreadManager *threadManager = 0;
-
 //======================================================================
 //======================================================================
 
 
 extern "C"
 extern "C"
 {
 {
 
 
+// Global API function
 AS_API int asThreadCleanup()
 AS_API int asThreadCleanup()
 {
 {
-	// As this function can be called globally, 
-	// we can't assume the threadManager exists
-	if( threadManager )
-		return threadManager->CleanupLocalData();
-
-	return 0;
+	return asCThreadManager::CleanupLocalData();
 }
 }
 
 
 }
 }
 
 
+//=======================================================================
+
+// Singleton
+static asCThreadManager *threadManager = 0;
+
+#ifndef AS_NO_THREADS
+static DECLARECRITICALSECTION(criticalSection)
+#endif
+
 //======================================================================
 //======================================================================
 
 
 asCThreadManager::asCThreadManager()
 asCThreadManager::asCThreadManager()
 {
 {
+	// We're already in the critical section when this function is called
+
 #ifdef AS_NO_THREADS
 #ifdef AS_NO_THREADS
 	tld = 0;
 	tld = 0;
 #endif
 #endif
-	refCount.set(1);
+	refCount = 1;
 }
 }
 
 
 void asCThreadManager::AddRef()
 void asCThreadManager::AddRef()
 {
 {
-	refCount.atomicInc();
+	// It's necessary to protect this section to 
+	// avoid two threads attempting to create thread
+	// managers at the same time.
+	ENTERCRITICALSECTION(criticalSection);
+
+	if( threadManager == 0 )
+		threadManager = asNEW(asCThreadManager);
+	else
+		threadManager->refCount++;
+
+	LEAVECRITICALSECTION(criticalSection);
 }
 }
 
 
 void asCThreadManager::Release()
 void asCThreadManager::Release()
 {
 {
-	if( refCount.atomicDec() == 0 )
+	// It's necessary to protect this section so no
+	// other thread attempts to call AddRef or Release
+	// while clean up is in progress.
+	ENTERCRITICALSECTION(criticalSection);
+	if( --threadManager->refCount == 0 )
 	{
 	{
 		// The last engine has been destroyed, so we 
 		// The last engine has been destroyed, so we 
 		// need to delete the thread manager as well
 		// need to delete the thread manager as well
-		asDELETE(this,asCThreadManager);
+		asDELETE(threadManager,asCThreadManager);
 		threadManager = 0;
 		threadManager = 0;
 	}
 	}
+	LEAVECRITICALSECTION(criticalSection);
 }
 }
 
 
 asCThreadManager::~asCThreadManager()
 asCThreadManager::~asCThreadManager()
 {
 {
 #ifndef AS_NO_THREADS
 #ifndef AS_NO_THREADS
-	ENTERCRITICALSECTION(criticalSection);
-
 	// Delete all thread local datas
 	// Delete all thread local datas
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
 	if( tldMap.MoveFirst(&cursor) )
 	if( tldMap.MoveFirst(&cursor) )
@@ -105,8 +122,6 @@ asCThreadManager::~asCThreadManager()
 			}
 			}
 		} while( tldMap.MoveNext(&cursor, cursor) );
 		} while( tldMap.MoveNext(&cursor, cursor) );
 	}
 	}
-
-	LEAVECRITICALSECTION(criticalSection);
 #else
 #else
 	if( tld ) 
 	if( tld ) 
 	{
 	{
@@ -128,16 +143,22 @@ int asCThreadManager::CleanupLocalData()
 
 
 	ENTERCRITICALSECTION(criticalSection);
 	ENTERCRITICALSECTION(criticalSection);
 
 
+	if( threadManager == 0 )
+	{
+		LEAVECRITICALSECTION(criticalSection);
+		return 0;
+	}
+
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
-	if( tldMap.MoveTo(&cursor, id) )
+	if( threadManager->tldMap.MoveTo(&cursor, id) )
 	{
 	{
-		asCThreadLocalData *tld = tldMap.GetValue(cursor);
+		asCThreadLocalData *tld = threadManager->tldMap.GetValue(cursor);
 		
 		
 		// Can we really remove it at this time?
 		// Can we really remove it at this time?
 		if( tld->activeContexts.GetLength() == 0 )
 		if( tld->activeContexts.GetLength() == 0 )
 		{
 		{
 			asDELETE(tld,asCThreadLocalData);
 			asDELETE(tld,asCThreadLocalData);
-			tldMap.Erase(cursor);
+			threadManager->tldMap.Erase(cursor);
 			r = 0;
 			r = 0;
 		}
 		}
 		else
 		else
@@ -148,12 +169,12 @@ int asCThreadManager::CleanupLocalData()
 
 
 	return r;
 	return r;
 #else
 #else
-	if( tld )
+	if( threadManager && threadManager->tld )
 	{
 	{
-		if( tld->activeContexts.GetLength() == 0 )
+		if( threadManager->tld->activeContexts.GetLength() == 0 )
 		{
 		{
-			asDELETE(tld,asCThreadLocalData);
-			tld = 0;
+			asDELETE(threadManager->tld,asCThreadLocalData);
+			threadManager->tld = 0;
 		}
 		}
 		else
 		else
 			return asCONTEXT_ACTIVE;
 			return asCONTEXT_ACTIVE;
@@ -165,26 +186,22 @@ int asCThreadManager::CleanupLocalData()
 #ifndef AS_NO_THREADS
 #ifndef AS_NO_THREADS
 asCThreadLocalData *asCThreadManager::GetLocalData(asPWORD threadId)
 asCThreadLocalData *asCThreadManager::GetLocalData(asPWORD threadId)
 {
 {
-	asCThreadLocalData *tld = 0;
+	// We're already in the critical section when this function is called
 
 
-	ENTERCRITICALSECTION(criticalSection);
+	asCThreadLocalData *tld = 0;
 
 
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
 	asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
-	if( tldMap.MoveTo(&cursor, threadId) )
-		tld = tldMap.GetValue(cursor);
-
-	LEAVECRITICALSECTION(criticalSection);
+	if( threadManager->tldMap.MoveTo(&cursor, threadId) )
+		tld = threadManager->tldMap.GetValue(cursor);
 
 
 	return tld;
 	return tld;
 }
 }
 
 
 void asCThreadManager::SetLocalData(asPWORD threadId, asCThreadLocalData *tld)
 void asCThreadManager::SetLocalData(asPWORD threadId, asCThreadLocalData *tld)
 {
 {
-	ENTERCRITICALSECTION(criticalSection);
+	// We're already in the critical section when this function is called
 
 
 	tldMap.Insert(threadId, tld);
 	tldMap.Insert(threadId, tld);
-
-	LEAVECRITICALSECTION(criticalSection);
 }
 }
 #endif
 #endif
 
 
@@ -196,21 +213,36 @@ asCThreadLocalData *asCThreadManager::GetLocalData()
 #elif defined AS_WINDOWS_THREADS
 #elif defined AS_WINDOWS_THREADS
 	asPWORD id = (asPWORD)GetCurrentThreadId();
 	asPWORD id = (asPWORD)GetCurrentThreadId();
 #endif
 #endif
-		
-	asCThreadLocalData *tld = GetLocalData(id);
+
+	ENTERCRITICALSECTION(criticalSection);
+
+	asASSERT(threadManager);
+
+	if( threadManager == 0 )
+	{
+		LEAVECRITICALSECTION(criticalSection);
+		return 0;
+	}
+
+	asCThreadLocalData *tld = threadManager->GetLocalData(id);
 	if( tld == 0 )
 	if( tld == 0 )
 	{
 	{
 		// Create a new tld
 		// Create a new tld
 		tld = asNEW(asCThreadLocalData)();
 		tld = asNEW(asCThreadLocalData)();
-		SetLocalData(id, tld);
+		threadManager->SetLocalData(id, tld);
 	}
 	}
 
 
+	LEAVECRITICALSECTION(criticalSection);
+
 	return tld;
 	return tld;
 #else
 #else
-	if( tld == 0 )
-		tld = asNEW(asCThreadLocalData)();
+	if( threadManager == 0 )
+		return 0;
 
 
-	return tld;
+	if( threadManager->tld == 0 )
+		threadManager->tld = asNEW(asCThreadLocalData)();
+
+	return threadManager->tld;
 #endif
 #endif
 }
 }
 
 

+ 10 - 12
ThirdParty/AngelScript/source/as_thread.h

@@ -1,6 +1,6 @@
 /*
 /*
    AngelCode Scripting Library
    AngelCode Scripting Library
-   Copyright (c) 2003-2008 Andreas Jonsson
+   Copyright (c) 2003-2012 Andreas Jonsson
 
 
    This software is provided 'as-is', without any express or implied 
    This software is provided 'as-is', without any express or implied 
    warranty. In no event will the authors be held liable for any 
    warranty. In no event will the authors be held liable for any 
@@ -43,7 +43,6 @@
 #include "as_string.h"
 #include "as_string.h"
 #include "as_array.h"
 #include "as_array.h"
 #include "as_map.h"
 #include "as_map.h"
-#include "as_atomic.h"
 #include "as_criticalsection.h"
 #include "as_criticalsection.h"
 
 
 BEGIN_AS_NAMESPACE
 BEGIN_AS_NAMESPACE
@@ -53,31 +52,30 @@ class asCThreadLocalData;
 class asCThreadManager
 class asCThreadManager
 {
 {
 public:
 public:
-	asCThreadManager();
-
-	asCThreadLocalData *GetLocalData();
-	int CleanupLocalData();
+	static asCThreadLocalData *GetLocalData();
+	static int CleanupLocalData();
 
 
-	void AddRef();
-	void Release();
+	static void AddRef();
+	static void Release();
 
 
 protected:
 protected:
+	asCThreadManager();
 	~asCThreadManager();
 	~asCThreadManager();
-	asCAtomic refCount;
+
+	// No need to use the atomic int here, as it will only be
+	// updated within the thread manager's critical section
+	int refCount;
 
 
 #ifndef AS_NO_THREADS
 #ifndef AS_NO_THREADS
 	asCThreadLocalData *GetLocalData(asPWORD threadId);
 	asCThreadLocalData *GetLocalData(asPWORD threadId);
 	void SetLocalData(asPWORD threadId, asCThreadLocalData *tld);
 	void SetLocalData(asPWORD threadId, asCThreadLocalData *tld);
 
 
 	asCMap<asPWORD,asCThreadLocalData*> tldMap;
 	asCMap<asPWORD,asCThreadLocalData*> tldMap;
-	DECLARECRITICALSECTION(criticalSection)
 #else
 #else
 	asCThreadLocalData *tld;
 	asCThreadLocalData *tld;
 #endif
 #endif
 };
 };
 
 
-extern asCThreadManager *threadManager;
-
 //======================================================================
 //======================================================================
 
 
 class asIScriptContext;
 class asIScriptContext;

+ 1 - 0
Urho3D/Urho3D.cpp

@@ -125,6 +125,7 @@ void Run()
             engine->Exit(); // Close the rendering window
             engine->Exit(); // Close the rendering window
             ErrorDialog("Urho3D", context->GetSubsystem<Log>()->GetLastMessage());
             ErrorDialog("Urho3D", context->GetSubsystem<Log>()->GetLastMessage());
         }
         }
+        scriptFile.Reset();
     }
     }
     catch (std::bad_alloc&)
     catch (std::bad_alloc&)
     {
     {