JSVM.h 4.4 KB

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