JSVM.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #pragma once
  5. #include <Atomic/Core/Context.h>
  6. #include <Atomic/Core/Object.h>
  7. #include <Atomic/Container/List.h>
  8. #include <Atomic/IO/Log.h>
  9. #include "JSAPI.h"
  10. //#define JSVM_DEBUG
  11. namespace Atomic
  12. {
  13. class JSFile;
  14. class JSUI;
  15. class ATOMIC_API JSVM : public Object
  16. {
  17. OBJECT(JSVM);
  18. public:
  19. /// Construct.
  20. JSVM(Context* context);
  21. /// Destruct.
  22. virtual ~JSVM();
  23. void InitJSContext();
  24. bool ExecuteFile(File* file);
  25. // Resources/Scripts/*.js
  26. bool ExecuteScript(const String& scriptPath);
  27. // Resources/Script/main.js
  28. // Catches not requiring AtomicGame, etc
  29. bool ExecuteMain();
  30. bool ExecuteFunction(const String& functionName);
  31. inline static JSVM* GetJSVM(duk_context* context)
  32. {
  33. return instance_;
  34. }
  35. inline duk_context* GetJSContext() { return ctx_; }
  36. void DumpJavascriptObjects() {}
  37. #ifdef JSVM_DEBUG
  38. inline void ValidateJSHeapPtr(void* heapptr)
  39. {
  40. assert(removedHeapPtr_.Find(heapptr) == removedHeapPtr_.End());
  41. assert(heapToObject_.Find(heapptr) != heapToObject_.End());
  42. }
  43. #endif
  44. inline void AddObject(void* heapptr, RefCounted* object)
  45. {
  46. assert(!object->JSGetHeapPtr());
  47. object->JSSetHeapPtr(heapptr);
  48. #ifdef JSVM_DEBUG
  49. assert(heapToObject_.Find(heapptr) == heapToObject_.End());
  50. #endif
  51. heapToObject_[heapptr] = object;
  52. #ifdef JSVM_DEBUG
  53. HashMap<void*, void*>::Iterator itr = removedHeapPtr_.Find(heapptr);
  54. if (itr != removedHeapPtr_.End())
  55. removedHeapPtr_.Erase(itr);
  56. #endif
  57. }
  58. inline void RemoveObject(RefCounted* object)
  59. {
  60. void* heapptr = object->JSGetHeapPtr();
  61. assert(heapptr);
  62. object->JSSetHeapPtr(NULL);
  63. HashMap<void*, RefCounted*>::Iterator hitr = heapToObject_.Find(heapptr);
  64. assert(hitr != heapToObject_.End());
  65. heapToObject_.Erase(hitr);
  66. #ifdef JSVM_DEBUG
  67. assert(removedHeapPtr_.Find(heapptr) == removedHeapPtr_.End());
  68. removedHeapPtr_[heapptr] = heapptr;
  69. #endif
  70. }
  71. inline RefCounted* GetObjectPtr(void* heapptr)
  72. {
  73. #ifdef JSVM_DEBUG
  74. assert(!removedHeapPtr_.Contains(heapptr));
  75. #endif
  76. assert(heapToObject_.Contains(heapptr));
  77. #ifdef JSVM_DEBUG
  78. RefCounted* ref = heapToObject_[heapptr];
  79. assert(ref->JSGetHeapPtr() == heapptr);
  80. #endif
  81. return heapToObject_[heapptr];
  82. }
  83. void SetModuleSearchPath(const String& searchPath)
  84. {
  85. moduleSearchPath_ = searchPath;
  86. }
  87. void SetLastModuleSearchFile(const String& fileName) { lastModuleSearchFilename_ = fileName; }
  88. const String& GetLastModuleSearchFile() { return lastModuleSearchFilename_; }
  89. const String& GetErrorString() { return errorString_; }
  90. void SendJSErrorEvent(const String& filename = String::EMPTY);
  91. private:
  92. bool GenerateComponent(const String& cname, const String& jsfilename, const String& csource);
  93. void InitComponents();
  94. void InitPackageComponents();
  95. void SubscribeToEvents();
  96. void HandleUpdate(StringHash eventType, VariantMap& eventData);
  97. static int js_module_search(duk_context* ctx);
  98. duk_context* ctx_;
  99. HashMap<void*, RefCounted*> heapToObject_;
  100. #ifdef JSVM_DEBUG
  101. // Debugging
  102. HashMap<void*, void*> removedHeapPtr_;
  103. #endif
  104. float gcTime_;
  105. String moduleSearchPath_;
  106. String lastModuleSearchFilename_;
  107. String errorString_;
  108. SharedPtr<JSUI> ui_;
  109. static JSVM* instance_;
  110. };
  111. template<typename T>
  112. T* js_to_class_instance(duk_context* ctx, int index, unsigned classID)
  113. {
  114. if (!duk_is_object(ctx, index))
  115. return NULL;
  116. return (T*) JSVM::GetJSVM(ctx)->GetObjectPtr(duk_get_heapptr(ctx, index));
  117. }
  118. // pushes null if instance is null
  119. // pushes from object store if already wrapped
  120. // pushes a new'd instance with wrapped native
  121. // must be an Object (so downcast works)
  122. inline bool js_push_class_object_instance(duk_context* ctx, const RefCounted *instance, const char* classname = "")
  123. {
  124. if (!instance)
  125. {
  126. duk_push_null(ctx);
  127. return true;
  128. }
  129. int top = duk_get_top(ctx);
  130. if (instance->JSGetHeapPtr())
  131. {
  132. duk_push_heapptr(ctx, instance->JSGetHeapPtr());
  133. assert(duk_is_object(ctx, -1));
  134. return true;
  135. }
  136. duk_get_global_string(ctx, "Atomic");
  137. // will not handle renamed classes
  138. if (instance->IsObject())
  139. duk_get_prop_string(ctx, -1, ((Object*)instance)->GetTypeName().CString());
  140. else
  141. {
  142. duk_get_prop_string(ctx, -1, classname);
  143. }
  144. duk_push_pointer(ctx, (void*) instance);
  145. duk_new(ctx, 1);
  146. duk_remove(ctx, -2); // remove Atomic object
  147. assert(duk_is_object(ctx, -1));
  148. assert ((top + 1) == duk_get_top(ctx));
  149. return true;
  150. }
  151. }