14#include <unordered_set>
15#include <choc/containers/choc_Value.h>
16#include <choc/text/choc_JSON.h>
25using LogCallback = std::function<void(std::string_view level, std::string_view message)>;
28using NativeFunction = std::function<choc::value::Value(
const choc::value::Value* args,
size_t num_args)>;
119 virtual choc::value::Value
evaluate(
const std::string& code) = 0;
135 throw std::runtime_error(
"bounded JSON evaluation is unsupported");
146 claim_native_symbol(name);
151 virtual choc::value::Value
invoke(std::string_view name) = 0;
154 virtual choc::value::Value
invoke(std::string_view name,
155 const choc::value::Value* args,
156 size_t num_args) = 0;
164 claim_native_symbol(name);
172 claim_native_symbol(name);
238 const auto quote_string = [] (std::string_view
text) {
239 return choc::json::toString(choc::value::createString(std::string(
text)));
242 const auto js_literal = [&] (
const choc::value::Value&
value) -> std::string {
245 return choc::json::toString(
value);
248 static uint64_t global_host_symbol = 0;
250 std::string target =
"globalThis[" + quote_string(name) +
"]";
252 script.reserve(256 + descriptor.properties.size() * 64 + descriptor.methods.size() * 96);
253 script += target +
" = {};\n";
255 if (!descriptor.class_name.empty())
256 script += target +
"[\"_objectName\"] = " + quote_string(descriptor.class_name) +
";\n";
258 for (
const auto& property : descriptor.properties)
259 script += target +
"[" + quote_string(property.name) +
"] = " + js_literal(property.value) +
";\n";
261 for (
auto& method : descriptor.methods) {
262 auto hidden_name =
"__pulp_host_object_" + std::to_string(global_host_symbol++);
264 script += target +
"[" + quote_string(method.name) +
"] = globalThis[" + quote_string(hidden_name) +
"];\n";
265 script +=
"delete globalThis[" + quote_string(hidden_name) +
"];\n";
272 const auto quote_string = [] (std::string_view
text) {
273 return choc::json::toString(choc::value::createString(std::string(
text)));
276 static uint64_t global_promise_symbol = 0;
277 auto hidden_name =
"__pulp_promise_function_" + std::to_string(global_promise_symbol++);
280 std::string quoted_hidden = quote_string(hidden_name);
281 std::string quoted_name = quote_string(name);
283 "globalThis[" + quoted_name +
"] = ((fn) => (...args) => Promise.resolve().then(() => fn(...args)))(globalThis[" + quoted_hidden +
"]);\n"
284 "delete globalThis[" + quoted_hidden +
"];\n"
285 "globalThis[" + quoted_name +
"];";
290 std::unordered_set<std::string> registered_native_symbols_;
292 void claim_native_symbol(
const std::string& name) {
293 if (!registered_native_symbols_.insert(name).second)
294 throw std::runtime_error(
"JsEngine native symbol already registered: " + name);
355 const std::atomic<bool>*
cancel =
nullptr);
JsEngine & operator=(JsEngine &&)=delete
virtual std::string provider_path() const
Definition js_engine.hpp:107
void register_promise_function(const std::string &name, NativePromiseFunction fn)
Definition js_engine.hpp:171
JsEngine(const JsEngine &)=delete
virtual void register_function_impl(const std::string &name, NativeFunction fn)=0
virtual void register_host_object_impl(const std::string &name, HostObjectDescriptor descriptor)
Definition js_engine.hpp:237
virtual bool set_memory_limit(std::size_t)
Definition js_engine.hpp:183
virtual void request_interrupt()
Definition js_engine.hpp:206
virtual bool supports_bounded_json_evaluation() const
Definition js_engine.hpp:133
virtual choc::value::Value invoke(std::string_view name)=0
virtual bool supports_interrupt() const
Definition js_engine.hpp:196
virtual void pump_message_loop()
Definition js_engine.hpp:189
virtual std::string expected_runtime_version() const
Definition js_engine.hpp:112
virtual std::string runtime_version() const
Definition js_engine.hpp:99
virtual bool supports_host_objects() const
Definition js_engine.hpp:219
virtual bool clear_pending_interrupt()
Definition js_engine.hpp:213
virtual JsEngineType type() const =0
virtual std::string evaluate_bounded_json(const std::string &, std::size_t)
Definition js_engine.hpp:134
virtual bool is_valid() const =0
virtual void set_log_callback(LogCallback callback)=0
virtual std::string provider_kind() const
Definition js_engine.hpp:104
void register_function(const std::string &name, NativeFunction fn)
Definition js_engine.hpp:145
JsEngine & operator=(const JsEngine &)=delete
virtual ~JsEngine()=default
JsEngine(JsEngine &&)=delete
virtual void register_promise_function_impl(const std::string &name, NativePromiseFunction fn)
Definition js_engine.hpp:271
virtual void gc_hint()
Definition js_engine.hpp:177
virtual choc::value::Value invoke(std::string_view name, const choc::value::Value *args, size_t num_args)=0
virtual void run_module(const std::string &code, ModuleResolver resolver, ModuleCompletionHandler completion={})=0
virtual choc::value::Value evaluate_script(const std::string &code)
Definition js_engine.hpp:126
virtual bool supports_promises() const
Definition js_engine.hpp:224
virtual bool supports_typed_arrays() const
Definition js_engine.hpp:223
virtual choc::value::Value evaluate(const std::string &code)=0
void register_host_object(const std::string &name, HostObjectDescriptor descriptor)
Definition js_engine.hpp:163
Definition accessibility_provider.hpp:65
void clear_embedded_script_bytecode_for_tests()
Tests only: forget every registered embedded bytecode blob.
void set_precompile_claim_hook_for_tests(std::function< void(const std::string &)> hook)
Tests only: called by precompile_scripts() on its own thread after it has claimed source and before i...
std::function< void(const std::string &)> precompile_claim_hook_for_tests()
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
@ path
Definition anchor_strategy.hpp:42
constexpr std::size_t kDefaultJsMemoryLimitBytes
Definition js_engine.hpp:79
@ text
Plain text (default color).
Definition code_editor_tokenizer.hpp:37
@ type
Built-in / common type name (e.g. int, Number).
Definition code_editor_tokenizer.hpp:39
JsEngineType
Definition js_engine.hpp:59
@ jsc
Definition js_engine.hpp:61
@ quickjs
Definition js_engine.hpp:60
@ v8
Definition js_engine.hpp:62
std::function< choc::value::Value(const choc::value::Value *args, size_t num_args)> NativeFunction
Definition js_engine.hpp:28
std::unique_ptr< JsEngine > create_default_js_engine()
JsEngineCreationStats js_engine_creation_stats()
std::size_t precompile_scripts(const std::vector< std::string > &sources, const std::atomic< bool > *cancel=nullptr)
Compile whole scripts into the bytecode cache without running them, on the calling thread,...
std::string script_bytecode_engine_fingerprint()
The engine's bytecode fingerprint: the QuickJS version plus a digest of the bytecode this engine emit...
void reset_js_engine_creation_stats_for_tests()
ScriptBytecodeCacheStats script_bytecode_cache_stats()
void clear_script_bytecode_cache()
Drop every stored script (tests; a host that wants the memory back).
std::function< void(const std::string &error, const choc::value::Value &result)> ModuleCompletionHandler
Definition js_engine.hpp:22
std::vector< std::uint8_t > build_embedded_script_bytecode(const std::string &source)
Build-time script bytecode (QuickJS backend).
bool is_engine_available(JsEngineType type)
std::unique_ptr< JsEngine > create_js_engine(JsEngineType type)
@ value
the widget's primary value (Knob, Fader, RangeSlider, Toggle, ProgressBar)
Definition binding_diagnostics.hpp:19
bool register_embedded_script_bytecode(const std::uint8_t *blob, std::size_t size)
Returns false (and registers nothing) for a malformed blob, or one whose engine fingerprint differs f...
bool script_bytecode_cached(const std::string &source)
True when byte-identical source has stored bytecode (tests, diagnostics).
constexpr std::string_view engine_type_name(JsEngineType type)
Definition js_engine.hpp:66
@ cancel
Definition window_classes.hpp:126
NativeFunction NativePromiseFunction
Definition js_engine.hpp:29
std::function< std::optional< std::string >(std::string_view path)> ModuleResolver
Definition js_engine.hpp:21
std::function< void(std::string_view level, std::string_view message)> LogCallback
Definition js_engine.hpp:25
@ error
Definition design_ir.hpp:697
Definition js_engine.hpp:45
std::vector< HostObjectProperty > properties
Definition js_engine.hpp:47
std::string class_name
Definition js_engine.hpp:46
std::vector< HostObjectMethod > methods
Definition js_engine.hpp:48
Definition js_engine.hpp:40
std::string name
Definition js_engine.hpp:41
NativeFunction fn
Definition js_engine.hpp:42
Definition js_engine.hpp:35
choc::value::Value value
Definition js_engine.hpp:37
std::string name
Definition js_engine.hpp:36
Definition js_engine.hpp:51
uint64_t v8
Definition js_engine.hpp:55
uint64_t quickjs
Definition js_engine.hpp:53
uint64_t jsc
Definition js_engine.hpp:54
uint64_t total
Definition js_engine.hpp:52
Process-wide reuse of compiled script bytecode (QuickJS backend).
Definition js_engine.hpp:330
std::uint64_t bypassed
too small to cache, or cache disabled
Definition js_engine.hpp:333
std::uint64_t precompiled
of compiles, done by precompile_scripts()
Definition js_engine.hpp:334
std::uint64_t waits
evaluations that waited for an in-flight compile
Definition js_engine.hpp:335
std::uint64_t hits
evaluations served from stored bytecode
Definition js_engine.hpp:332
std::size_t entries
Definition js_engine.hpp:337
std::uint64_t embedded
misses served from build-time bytecode, not compiled
Definition js_engine.hpp:336
std::uint64_t compiles
scripts compiled and stored
Definition js_engine.hpp:331
std::size_t bytes
bytecode + key bytes held
Definition js_engine.hpp:338