JSSpiderMonkeyVM.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. // LICENSE: Atomic Game Engine Editor and Tools EULA
  4. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  5. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  6. //
  7. #ifdef USE_SPIDERMONKEY
  8. #include "AtomicEditor.h"
  9. #include "/Users/josh/Desktop/SpiderMonkey/include/mozjs-37a1/jsapi.h"
  10. #include "js/RootingAPI.h"
  11. #include "JSSpiderMonkeyVM.h"
  12. using namespace JS;
  13. #include "Context.h"
  14. #include "FileSystem.h"
  15. #include "ResourceCache.h"
  16. #include "JSFile.h"
  17. static RootedObject* __global = NULL;
  18. // The class of the global object.
  19. static JSClass globalClass = {
  20. "global",
  21. JSCLASS_GLOBAL_FLAGS,
  22. JS_PropertyStub,
  23. JS_DeletePropertyStub,
  24. JS_PropertyStub,
  25. JS_StrictPropertyStub,
  26. JS_EnumerateStub,
  27. JS_ResolveStub,
  28. JS_ConvertStub,
  29. nullptr, nullptr, nullptr, nullptr,
  30. JS_GlobalObjectTraceHook
  31. };
  32. // The error reporter callback.
  33. void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
  34. fprintf(stderr, "%s:%u:%s\n",
  35. report->filename ? report->filename : "[no filename]",
  36. (unsigned int) report->lineno,
  37. message);
  38. }
  39. namespace AtomicEditor
  40. {
  41. WeakPtr<JSSpiderMonkeyVM> JSSpiderMonkeyVM::instance_;
  42. static bool
  43. print(JSContext *cx, unsigned argc, jsval *vp)
  44. {
  45. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  46. for (unsigned i = 0; i < args.length(); i++) {
  47. JSString *str = JS::ToString(cx, args[i]);
  48. if (!str)
  49. return false;
  50. char *bytes = JS_EncodeString(cx, str);
  51. if (!bytes)
  52. return false;
  53. printf("%s%s", i ? " " : "", bytes);
  54. JS_free(cx, bytes);
  55. }
  56. putchar('\n');
  57. fflush(stdout);
  58. args.rval().setUndefined();
  59. return true;
  60. }
  61. JSSpiderMonkeyVM::JSSpiderMonkeyVM(Context* context) :
  62. Object(context), runtime_(0), jscontext_(0),
  63. autorequest_(0), autocompartment_(0)
  64. {
  65. context_->RegisterSubsystem(this);
  66. instance_ = this;
  67. // Initialize the JS engine.
  68. if (!JS_Init())
  69. {
  70. assert(0);
  71. }
  72. // Create a JS runtime.
  73. runtime_ = JS_NewRuntime(32L * 1024L * 1024L);
  74. if (runtime_)
  75. {
  76. jscontext_ = JS_NewContext(runtime_, 8192);
  77. if (jscontext_)
  78. {
  79. JS_SetErrorReporter(runtime_, reportError);
  80. }
  81. else
  82. {
  83. assert(0);
  84. }
  85. }
  86. else
  87. {
  88. assert(0);
  89. }
  90. // Enter a request before running anything in the context.
  91. autorequest_ = new JSAutoRequest(jscontext_);
  92. // Create the global object and a new compartment.
  93. __global = new RootedObject(jscontext_);
  94. *__global = JS_NewGlobalObject(jscontext_, &globalClass, nullptr,
  95. JS::DontFireOnNewGlobalHook);
  96. // Enter the new global object's compartment.
  97. autocompartment_ = new JSAutoCompartment(jscontext_, *__global);
  98. // Populate the global object with the standard globals, like Object and
  99. // Array.
  100. if (!JS_InitStandardClasses(jscontext_, *__global))
  101. {
  102. assert(0);
  103. }
  104. if (!JS_InitReflect(jscontext_, *__global))
  105. {
  106. assert(0);
  107. }
  108. JS_DefineFunction(jscontext_, *__global, "print", (JSNative) print, 0, 0);
  109. ExecuteFile("AtomicEditor/javascript/modules/acorn_spidermonkey.js");
  110. }
  111. JSSpiderMonkeyVM::~JSSpiderMonkeyVM()
  112. {
  113. instance_ = NULL;
  114. if (autocompartment_)
  115. delete autocompartment_;
  116. if (__global)
  117. {
  118. delete __global;
  119. __global = NULL;
  120. }
  121. if (autorequest_)
  122. delete autorequest_;
  123. // Shut everything down.
  124. if (context_)
  125. JS_DestroyContext(jscontext_);
  126. if (runtime_)
  127. JS_DestroyRuntime(runtime_);
  128. JS_ShutDown();
  129. }
  130. bool JSSpiderMonkeyVM::ExecuteFile(const String& path)
  131. {
  132. SharedPtr<JSFile> jsfile;
  133. jsfile = GetSubsystem<ResourceCache>()->GetResource<JSFile>(path);
  134. JS::RootedValue returnValue(jscontext_);
  135. OwningCompileOptions options(jscontext_);
  136. options.setFileAndLine(jscontext_, path.CString(), 0);
  137. options.setCompileAndGo(true);
  138. bool ok = JS::Evaluate(jscontext_, *__global, options,
  139. jsfile->GetSource(), strlen(jsfile->GetSource()), &returnValue);
  140. return ok;
  141. }
  142. bool JSSpiderMonkeyVM::ParseJavascriptToJSON(const char* source, String& json)
  143. {
  144. json.Clear();
  145. bool ok = true;
  146. JS::Rooted<JS::Value> v(jscontext_);
  147. JS::RootedValue returnValue(jscontext_);
  148. JS::RootedValue jsource(jscontext_, JS::StringValue(JS_NewStringCopyZ(jscontext_, source)));
  149. JS_CallFunctionName(jscontext_, *__global, "__atomic_parse_to_json", HandleValueArray(jsource), &returnValue);
  150. JS::RootedString hm(jscontext_);
  151. hm = JS::ToString(jscontext_, returnValue);
  152. const char* strjson = JS_EncodeStringToUTF8(jscontext_, hm);
  153. json = strjson;
  154. //printf("%s\n", strjson);
  155. JS_free(jscontext_, (void *) strjson);
  156. return ok;
  157. }
  158. bool JSSpiderMonkeyVM::ParseJavascriptToJSONWithSpiderMonkeyReflectAPI(const char* source, String& json)
  159. {
  160. json.Clear();
  161. bool ok = true;
  162. JS::Rooted<JS::Value> v(jscontext_);
  163. JS::RootedValue returnValue(jscontext_);
  164. JS::RootedValue jsource(jscontext_, JS::StringValue(JS_NewStringCopyZ(jscontext_, source)));
  165. // get the Reflect object
  166. if (!JS_GetProperty(jscontext_, *__global, "Reflect", &v))
  167. return false;
  168. JS::RootedObject reflectObject(jscontext_);
  169. JS_ValueToObject(jscontext_, v, &reflectObject);
  170. JS_CallFunctionName(jscontext_, reflectObject, "parse", HandleValueArray(jsource), &returnValue);
  171. JS::RootedObject jsonObject(jscontext_);
  172. if (!JS_GetProperty(jscontext_, *__global, "JSON", &v))
  173. return false;
  174. JS_ValueToObject(jscontext_, v, &jsonObject);
  175. // pretty printed, can remove for speed
  176. JS::AutoValueArray<3> args(jscontext_);
  177. args[0].set(returnValue);
  178. args[1].set(JS::NullValue());
  179. args[2].setNumber(3.0);
  180. JS::RootedValue jjson(jscontext_);
  181. JS_CallFunctionName(jscontext_, jsonObject, "stringify", HandleValueArray(args), &jjson);
  182. JS::RootedString hm(jscontext_);
  183. hm = JS::ToString(jscontext_, jjson);
  184. const char* strjson = JS_EncodeStringToUTF8(jscontext_, hm);
  185. json = strjson;
  186. //printf("%s\n", strjson);
  187. JS_free(jscontext_, (void *) strjson);
  188. return ok;
  189. }
  190. bool JSSpiderMonkeyVM::ReadZeroTerminatedSourceFile(const String& path, String& source)
  191. {
  192. File file(instance_->GetContext());
  193. file.Open(path);
  194. unsigned size = file.GetSize();
  195. SharedArrayPtr<char> data;
  196. data = new char[size + 1];
  197. data[size] = '\0';
  198. file.Read(data, size);
  199. source = data;
  200. return true;
  201. }
  202. }
  203. int run(JSContext *cx) {
  204. // Enter a request before running anything in the context.
  205. JSAutoRequest ar(cx);
  206. // Create the global object and a new compartment.
  207. RootedObject global(cx);
  208. global = JS_NewGlobalObject(cx, &globalClass, nullptr,
  209. JS::DontFireOnNewGlobalHook);
  210. if (!global)
  211. return 1;
  212. // Enter the new global object's compartment.
  213. JSAutoCompartment ac(cx, global);
  214. // Populate the global object with the standard globals, like Object and
  215. // Array.
  216. if (!JS_InitStandardClasses(cx, global))
  217. return 1;
  218. // Your application code here. This may include JSAPI calls to create your
  219. // own custom JS objects and run scripts.
  220. return 0;
  221. }
  222. #endif