v8embed.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "v8.h"
  15. #include "eclrtl.hpp"
  16. #include "jexcept.hpp"
  17. #include "jthread.hpp"
  18. #include "hqlplugins.hpp"
  19. #ifdef _WIN32
  20. #define EXPORT __declspec(dllexport)
  21. #else
  22. #define EXPORT
  23. #endif
  24. static const char * compatibleVersions[] = {
  25. "V8 JavaScript Embed Helper 1.0.0",
  26. NULL };
  27. static const char *version = "V8 JavaScript Embed Helper 1.0.0";
  28. static const char * EclDefinition =
  29. "EXPORT Language := SERVICE\n"
  30. " boolean getEmbedContext():cpp,pure,namespace='javascriptLanguageHelper',entrypoint='getEmbedContext',prototype='IEmbedContext* getEmbedContext()';\n"
  31. " boolean syntaxCheck(const varstring src):cpp,pure,namespace='javascriptLanguageHelper',entrypoint='syntaxCheck';\n"
  32. "END;"
  33. "export getEmbedContext := Language.getEmbedContext;"
  34. "export syntaxCheck := Language.syntaxCheck;"
  35. "EXPORT boolean supportsImport := false;"
  36. "EXPORT boolean supportsScript := true;";
  37. extern "C" EXPORT bool getECLPluginDefinition(ECLPluginDefinitionBlock *pb)
  38. {
  39. if (pb->size == sizeof(ECLPluginDefinitionBlockEx))
  40. {
  41. ECLPluginDefinitionBlockEx * pbx = (ECLPluginDefinitionBlockEx *) pb;
  42. pbx->compatibleVersions = compatibleVersions;
  43. }
  44. else if (pb->size != sizeof(ECLPluginDefinitionBlock))
  45. return false;
  46. pb->magicVersion = PLUGIN_VERSION;
  47. pb->version = version;
  48. pb->moduleName = "javascript";
  49. pb->ECL = EclDefinition;
  50. pb->flags = PLUGIN_DLL_MODULE | PLUGIN_MULTIPLE_VERSIONS;
  51. pb->description = "V8 JavaScript Embed Helper";
  52. return true;
  53. }
  54. namespace javascriptLanguageHelper {
  55. class V8JavascriptEmbedFunctionContext : public CInterfaceOf<IEmbedFunctionContext>
  56. {
  57. public:
  58. V8JavascriptEmbedFunctionContext()
  59. {
  60. isolate = v8::Isolate::New();
  61. isolate->Enter();
  62. context = v8::Context::New();
  63. context->Enter();
  64. }
  65. ~V8JavascriptEmbedFunctionContext()
  66. {
  67. script.Dispose();
  68. result.Dispose();
  69. context->Exit();
  70. context.Dispose();
  71. isolate->Exit();
  72. isolate->Dispose();
  73. }
  74. virtual void bindBooleanParam(const char *name, bool val)
  75. {
  76. v8::HandleScope handle_scope;
  77. context->Global()->Set(v8::String::New(name), v8::Boolean::New(val));
  78. }
  79. virtual void bindRealParam(const char *name, double val)
  80. {
  81. v8::HandleScope handle_scope;
  82. context->Global()->Set(v8::String::New(name), v8::Number::New(val));
  83. }
  84. virtual void bindSignedParam(const char *name, __int64 val)
  85. {
  86. // MORE - might need to check does not overflow 32 bits? Or store as a real?
  87. v8::HandleScope handle_scope;
  88. context->Global()->Set(v8::String::New(name), v8::Integer::New(val));
  89. }
  90. virtual void bindUnsignedParam(const char *name, unsigned __int64 val)
  91. {
  92. // MORE - might need to check does not overflow 32 bits
  93. v8::HandleScope handle_scope;
  94. context->Global()->Set(v8::String::New(name), v8::Integer::NewFromUnsigned(val));
  95. }
  96. virtual void bindStringParam(const char *name, size32_t len, const char *val)
  97. {
  98. v8::HandleScope handle_scope;
  99. context->Global()->Set(v8::String::New(name), v8::String::New(val, len));
  100. }
  101. virtual void bindVStringParam(const char *name, const char *val)
  102. {
  103. v8::HandleScope handle_scope;
  104. context->Global()->Set(v8::String::New(name), v8::String::New(val));
  105. }
  106. virtual bool getBooleanResult()
  107. {
  108. assertex (!result.IsEmpty());
  109. v8::HandleScope handle_scope;
  110. return result->BooleanValue();
  111. }
  112. virtual double getRealResult()
  113. {
  114. assertex (!result.IsEmpty());
  115. v8::HandleScope handle_scope;
  116. return v8::Number::Cast(*result)->Value();
  117. }
  118. virtual __int64 getSignedResult()
  119. {
  120. assertex (!result.IsEmpty());
  121. v8::HandleScope handle_scope;
  122. return v8::Integer::Cast(*result)->Value();
  123. }
  124. virtual unsigned __int64 getUnsignedResult()
  125. {
  126. assertex (!result.IsEmpty());
  127. v8::HandleScope handle_scope;
  128. return v8::Integer::Cast(*result)->Value();
  129. }
  130. virtual void getStringResult(size32_t &__len, char * &__result)
  131. {
  132. assertex (!result.IsEmpty());
  133. v8::HandleScope handle_scope; // May not strictly be needed?
  134. v8::String::AsciiValue ascii(result);
  135. const char *chars= *ascii;
  136. __len = strlen(chars);
  137. __result = (char *)rtlMalloc(__len);
  138. memcpy(__result, chars, __len);
  139. }
  140. virtual void compileEmbeddedScript(const char *text)
  141. {
  142. v8::HandleScope handle_scope;
  143. v8::Handle<v8::String> source = v8::String::New(text);
  144. v8::Handle<v8::Script> lscript = v8::Script::Compile(source);
  145. script = v8::Persistent<v8::Script>::New(lscript);
  146. }
  147. virtual void importFunction(const char *text)
  148. {
  149. UNIMPLEMENTED; // Not sure if meaningful for js
  150. }
  151. virtual void callFunction()
  152. {
  153. assertex (!script.IsEmpty());
  154. v8::HandleScope handle_scope;
  155. result = v8::Persistent<v8::Value>::New(script->Run());
  156. }
  157. protected:
  158. v8::Isolate *isolate;
  159. v8::Persistent<v8::Context> context;
  160. v8::Persistent<v8::Script> script;
  161. v8::Persistent<v8::Value> result;
  162. };
  163. static __thread V8JavascriptEmbedFunctionContext * theFunctionContext; // We reuse per thread, for speed
  164. static __thread ThreadTermFunc threadHookChain;
  165. static void releaseContext()
  166. {
  167. ::Release(theFunctionContext);
  168. if (threadHookChain)
  169. (*threadHookChain)();
  170. }
  171. class V8JavascriptEmbedContext : public CInterfaceOf<IEmbedContext>
  172. {
  173. public:
  174. V8JavascriptEmbedContext()
  175. {
  176. Link(); // Deliberately 'leak' in order to avoid freeing this global object
  177. }
  178. virtual IEmbedFunctionContext *createFunctionContext(bool isImport, const char *options)
  179. {
  180. assertex(!isImport);
  181. if (!theFunctionContext)
  182. {
  183. theFunctionContext = new V8JavascriptEmbedFunctionContext;
  184. threadHookChain = addThreadTermFunc(releaseContext);
  185. }
  186. return LINK(theFunctionContext);
  187. }
  188. } theEmbedContext;
  189. extern IEmbedContext* getEmbedContext()
  190. {
  191. return LINK(&theEmbedContext);
  192. }
  193. extern bool syntaxCheck(const char *script)
  194. {
  195. return true; // MORE
  196. }
  197. } // namespace