JSSpiderMonkeyVM.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #ifdef USE_SPIDERMONKEY
  23. #include "AtomicEditor.h"
  24. #include "/Users/josh/Desktop/SpiderMonkey/include/mozjs-37a1/jsapi.h"
  25. #include "js/RootingAPI.h"
  26. #include "JSSpiderMonkeyVM.h"
  27. using namespace JS;
  28. #include "Context.h"
  29. #include "FileSystem.h"
  30. #include "ResourceCache.h"
  31. #include "JSFile.h"
  32. static RootedObject* __global = NULL;
  33. // The class of the global object.
  34. static JSClass globalClass = {
  35. "global",
  36. JSCLASS_GLOBAL_FLAGS,
  37. JS_PropertyStub,
  38. JS_DeletePropertyStub,
  39. JS_PropertyStub,
  40. JS_StrictPropertyStub,
  41. JS_EnumerateStub,
  42. JS_ResolveStub,
  43. JS_ConvertStub,
  44. nullptr, nullptr, nullptr, nullptr,
  45. JS_GlobalObjectTraceHook
  46. };
  47. // The error reporter callback.
  48. void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
  49. fprintf(stderr, "%s:%u:%s\n",
  50. report->filename ? report->filename : "[no filename]",
  51. (unsigned int) report->lineno,
  52. message);
  53. }
  54. namespace AtomicEditor
  55. {
  56. WeakPtr<JSSpiderMonkeyVM> JSSpiderMonkeyVM::instance_;
  57. static bool
  58. print(JSContext *cx, unsigned argc, jsval *vp)
  59. {
  60. JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  61. for (unsigned i = 0; i < args.length(); i++) {
  62. JSString *str = JS::ToString(cx, args[i]);
  63. if (!str)
  64. return false;
  65. char *bytes = JS_EncodeString(cx, str);
  66. if (!bytes)
  67. return false;
  68. printf("%s%s", i ? " " : "", bytes);
  69. JS_free(cx, bytes);
  70. }
  71. putchar('\n');
  72. fflush(stdout);
  73. args.rval().setUndefined();
  74. return true;
  75. }
  76. JSSpiderMonkeyVM::JSSpiderMonkeyVM(Context* context) :
  77. Object(context), runtime_(0), jscontext_(0),
  78. autorequest_(0), autocompartment_(0)
  79. {
  80. context_->RegisterSubsystem(this);
  81. instance_ = this;
  82. // Initialize the JS engine.
  83. if (!JS_Init())
  84. {
  85. assert(0);
  86. }
  87. // Create a JS runtime.
  88. runtime_ = JS_NewRuntime(32L * 1024L * 1024L);
  89. if (runtime_)
  90. {
  91. jscontext_ = JS_NewContext(runtime_, 8192);
  92. if (jscontext_)
  93. {
  94. JS_SetErrorReporter(runtime_, reportError);
  95. }
  96. else
  97. {
  98. assert(0);
  99. }
  100. }
  101. else
  102. {
  103. assert(0);
  104. }
  105. // Enter a request before running anything in the context.
  106. autorequest_ = new JSAutoRequest(jscontext_);
  107. // Create the global object and a new compartment.
  108. __global = new RootedObject(jscontext_);
  109. *__global = JS_NewGlobalObject(jscontext_, &globalClass, nullptr,
  110. JS::DontFireOnNewGlobalHook);
  111. // Enter the new global object's compartment.
  112. autocompartment_ = new JSAutoCompartment(jscontext_, *__global);
  113. // Populate the global object with the standard globals, like Object and
  114. // Array.
  115. if (!JS_InitStandardClasses(jscontext_, *__global))
  116. {
  117. assert(0);
  118. }
  119. if (!JS_InitReflect(jscontext_, *__global))
  120. {
  121. assert(0);
  122. }
  123. JS_DefineFunction(jscontext_, *__global, "print", (JSNative) print, 0, 0);
  124. ExecuteFile("AtomicEditor/javascript/modules/acorn_spidermonkey.js");
  125. }
  126. JSSpiderMonkeyVM::~JSSpiderMonkeyVM()
  127. {
  128. instance_ = NULL;
  129. if (autocompartment_)
  130. delete autocompartment_;
  131. if (__global)
  132. {
  133. delete __global;
  134. __global = NULL;
  135. }
  136. if (autorequest_)
  137. delete autorequest_;
  138. // Shut everything down.
  139. if (context_)
  140. JS_DestroyContext(jscontext_);
  141. if (runtime_)
  142. JS_DestroyRuntime(runtime_);
  143. JS_ShutDown();
  144. }
  145. bool JSSpiderMonkeyVM::ExecuteFile(const String& path)
  146. {
  147. SharedPtr<JSFile> jsfile;
  148. jsfile = GetSubsystem<ResourceCache>()->GetResource<JSFile>(path);
  149. JS::RootedValue returnValue(jscontext_);
  150. OwningCompileOptions options(jscontext_);
  151. options.setFileAndLine(jscontext_, path.CString(), 0);
  152. options.setCompileAndGo(true);
  153. bool ok = JS::Evaluate(jscontext_, *__global, options,
  154. jsfile->GetSource(), strlen(jsfile->GetSource()), &returnValue);
  155. return ok;
  156. }
  157. bool JSSpiderMonkeyVM::ParseJavascriptToJSON(const char* source, String& json)
  158. {
  159. json.Clear();
  160. bool ok = true;
  161. JS::Rooted<JS::Value> v(jscontext_);
  162. JS::RootedValue returnValue(jscontext_);
  163. JS::RootedValue jsource(jscontext_, JS::StringValue(JS_NewStringCopyZ(jscontext_, source)));
  164. JS_CallFunctionName(jscontext_, *__global, "__atomic_parse_to_json", HandleValueArray(jsource), &returnValue);
  165. JS::RootedString hm(jscontext_);
  166. hm = JS::ToString(jscontext_, returnValue);
  167. const char* strjson = JS_EncodeStringToUTF8(jscontext_, hm);
  168. json = strjson;
  169. //printf("%s\n", strjson);
  170. JS_free(jscontext_, (void *) strjson);
  171. return ok;
  172. }
  173. bool JSSpiderMonkeyVM::ParseJavascriptToJSONWithSpiderMonkeyReflectAPI(const char* source, String& json)
  174. {
  175. json.Clear();
  176. bool ok = true;
  177. JS::Rooted<JS::Value> v(jscontext_);
  178. JS::RootedValue returnValue(jscontext_);
  179. JS::RootedValue jsource(jscontext_, JS::StringValue(JS_NewStringCopyZ(jscontext_, source)));
  180. // get the Reflect object
  181. if (!JS_GetProperty(jscontext_, *__global, "Reflect", &v))
  182. return false;
  183. JS::RootedObject reflectObject(jscontext_);
  184. JS_ValueToObject(jscontext_, v, &reflectObject);
  185. JS_CallFunctionName(jscontext_, reflectObject, "parse", HandleValueArray(jsource), &returnValue);
  186. JS::RootedObject jsonObject(jscontext_);
  187. if (!JS_GetProperty(jscontext_, *__global, "JSON", &v))
  188. return false;
  189. JS_ValueToObject(jscontext_, v, &jsonObject);
  190. // pretty printed, can remove for speed
  191. JS::AutoValueArray<3> args(jscontext_);
  192. args[0].set(returnValue);
  193. args[1].set(JS::NullValue());
  194. args[2].setNumber(3.0);
  195. JS::RootedValue jjson(jscontext_);
  196. JS_CallFunctionName(jscontext_, jsonObject, "stringify", HandleValueArray(args), &jjson);
  197. JS::RootedString hm(jscontext_);
  198. hm = JS::ToString(jscontext_, jjson);
  199. const char* strjson = JS_EncodeStringToUTF8(jscontext_, hm);
  200. json = strjson;
  201. //printf("%s\n", strjson);
  202. JS_free(jscontext_, (void *) strjson);
  203. return ok;
  204. }
  205. bool JSSpiderMonkeyVM::ReadZeroTerminatedSourceFile(const String& path, String& source)
  206. {
  207. File file(instance_->GetContext());
  208. file.Open(path);
  209. unsigned size = file.GetSize();
  210. SharedArrayPtr<char> data;
  211. data = new char[size + 1];
  212. data[size] = '\0';
  213. file.Read(data, size);
  214. source = data;
  215. return true;
  216. }
  217. }
  218. int run(JSContext *cx) {
  219. // Enter a request before running anything in the context.
  220. JSAutoRequest ar(cx);
  221. // Create the global object and a new compartment.
  222. RootedObject global(cx);
  223. global = JS_NewGlobalObject(cx, &globalClass, nullptr,
  224. JS::DontFireOnNewGlobalHook);
  225. if (!global)
  226. return 1;
  227. // Enter the new global object's compartment.
  228. JSAutoCompartment ac(cx, global);
  229. // Populate the global object with the standard globals, like Object and
  230. // Array.
  231. if (!JS_InitStandardClasses(cx, global))
  232. return 1;
  233. // Your application code here. This may include JSAPI calls to create your
  234. // own custom JS objects and run scripts.
  235. return 0;
  236. }
  237. #endif