blob: 1c6af5f916fb78f7b112b6a789a2de1d2736a486 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime.h"
#include <lib/syslog/cpp/macros.h>
#include <string.h>
#include "src/developer/shell/josh/lib/fdio.h"
#include "src/developer/shell/josh/lib/fidl.h"
#include "src/developer/shell/josh/lib/zx.h"
#include "third_party/quickjs/quickjs-libc.h"
#include "third_party/quickjs/quickjs.h"
// This is present and needs to be called in the most recent version of quickjs.
// It's only here so that we can run against both the old and new version until
// we integrate the new version.
__attribute__((weak)) void js_std_init_handlers(JSRuntime* rt) {}
namespace shell {
Runtime::Runtime() {
rt_ = JS_NewRuntime();
js_std_init_handlers(rt_);
is_valid_ = (rt_ == nullptr);
// The correct loader for ES6 modules. Not sure why this has to be done by hand.
JS_SetModuleLoaderFunc(rt_, nullptr, js_module_loader, nullptr);
}
Runtime::~Runtime() {
if (is_valid_) {
js_std_free_handlers(rt_);
JS_FreeRuntime(rt_);
}
}
Context::Context(const Runtime* rt) : ctx_(JS_NewContext(rt->Get())) {
is_valid_ = (ctx_ == nullptr);
#if __has_feature(address_sanitizer)
// ASan tends to exceed the max stack size of 256K.
JS_SetMaxStackSize(rt->Get(), 1024 * 1024);
#endif // __has_feature(address_sanitizer)
}
Context::~Context() {
if (is_valid_) {
JS_FreeContext(ctx_);
}
}
bool Context::Export(const std::string& lib, const std::string& js_path) {
std::string path;
int flags = JS_EVAL_TYPE_MODULE;
if (!js_path.empty()) {
path = js_path;
if (path[path.length() - 1] != '/') {
path.append("/");
}
path.append(lib);
path.append(".js");
} else {
path = lib;
flags |= JS_EVAL_FLAG_COMPILE_ONLY;
}
std::string init_str = "import * as " + lib + " from '" + path +
"';\n"
"globalThis." +
lib + " = " + lib + ";\n";
JSValue init_compile = JS_Eval(ctx_, init_str.c_str(), init_str.length(), "<input>", flags);
if (JS_IsException(init_compile)) {
return false;
}
if (js_path.empty()) {
js_module_set_import_meta(ctx_, init_compile, 1, 1);
JSValue init_run = JS_EvalFunction(ctx_, init_compile);
if (JS_IsException(init_run)) {
js_std_dump_error(ctx_);
return false;
}
}
return true;
}
bool Context::InitStd() {
// System modules
js_init_module_std(ctx_, "std");
if (!Export("std")) {
return false;
}
js_init_module_os(ctx_, "os");
if (!Export("os")) {
return false;
}
return true;
}
extern "C" const uint8_t qjsc_fidl[];
extern "C" const uint32_t qjsc_fidl_size;
extern "C" const uint8_t qjsc_fdio[];
extern "C" const uint32_t qjsc_fdio_size;
extern "C" const uint8_t qjsc_zx[];
extern "C" const uint32_t qjsc_zx_size;
bool Context::InitBuiltins(const std::string& fidl_path, const std::string& boot_js_path) {
if (fdio::FdioModuleInit(ctx_, "fdio") == nullptr) {
return false;
}
if (!Export("fdio")) {
return false;
}
if (fidl::FidlModuleInit(ctx_, "fidl_internal", fidl_path) == nullptr) {
return false;
}
js_std_eval_binary(ctx_, qjsc_fidl, qjsc_fidl_size, 0);
if (zx::ZxModuleInit(ctx_, "zx_internal") == nullptr) {
return false;
}
js_std_eval_binary(ctx_, qjsc_zx, qjsc_zx_size, 0);
if (!boot_js_path.empty()) {
if (!Export("pp", boot_js_path)) {
return false;
}
if (!Export("ns", boot_js_path)) {
return false;
}
if (!Export("task", boot_js_path)) {
return false;
}
}
return true;
}
} // namespace shell