11cb0ef41Sopenharmony_ci#include "node_sea.h"
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci#include "env-inl.h"
41cb0ef41Sopenharmony_ci#include "node_external_reference.h"
51cb0ef41Sopenharmony_ci#include "node_internals.h"
61cb0ef41Sopenharmony_ci#include "node_union_bytes.h"
71cb0ef41Sopenharmony_ci#include "simdutf.h"
81cb0ef41Sopenharmony_ci#include "v8.h"
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
111cb0ef41Sopenharmony_ci// the Node.js project that is present only once in the entire binary. It is
121cb0ef41Sopenharmony_ci// used by the postject_has_resource() function to efficiently detect if a
131cb0ef41Sopenharmony_ci// resource has been injected. See
141cb0ef41Sopenharmony_ci// https://github.com/nodejs/postject/blob/35343439cac8c488f2596d7c4c1dddfec1fddcae/postject-api.h#L42-L45.
151cb0ef41Sopenharmony_ci#define POSTJECT_SENTINEL_FUSE "NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2"
161cb0ef41Sopenharmony_ci#include "postject-api.h"
171cb0ef41Sopenharmony_ci#undef POSTJECT_SENTINEL_FUSE
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci#include <memory>
201cb0ef41Sopenharmony_ci#include <string_view>
211cb0ef41Sopenharmony_ci#include <tuple>
221cb0ef41Sopenharmony_ci#include <vector>
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci#if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ciusing v8::Context;
271cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo;
281cb0ef41Sopenharmony_ciusing v8::Local;
291cb0ef41Sopenharmony_ciusing v8::Object;
301cb0ef41Sopenharmony_ciusing v8::Value;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cinamespace {
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciconst std::string_view FindSingleExecutableCode() {
351cb0ef41Sopenharmony_ci  static const std::string_view sea_code = []() -> std::string_view {
361cb0ef41Sopenharmony_ci    size_t size;
371cb0ef41Sopenharmony_ci#ifdef __APPLE__
381cb0ef41Sopenharmony_ci    postject_options options;
391cb0ef41Sopenharmony_ci    postject_options_init(&options);
401cb0ef41Sopenharmony_ci    options.macho_segment_name = "NODE_JS";
411cb0ef41Sopenharmony_ci    const char* code = static_cast<const char*>(
421cb0ef41Sopenharmony_ci        postject_find_resource("NODE_JS_CODE", &size, &options));
431cb0ef41Sopenharmony_ci#else
441cb0ef41Sopenharmony_ci    const char* code = static_cast<const char*>(
451cb0ef41Sopenharmony_ci        postject_find_resource("NODE_JS_CODE", &size, nullptr));
461cb0ef41Sopenharmony_ci#endif
471cb0ef41Sopenharmony_ci    return {code, size};
481cb0ef41Sopenharmony_ci  }();
491cb0ef41Sopenharmony_ci  return sea_code;
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_civoid GetSingleExecutableCode(const FunctionCallbackInfo<Value>& args) {
531cb0ef41Sopenharmony_ci  node::Environment* env = node::Environment::GetCurrent(args);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  static const std::string_view sea_code = FindSingleExecutableCode();
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  if (sea_code.empty()) {
581cb0ef41Sopenharmony_ci    return;
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  // TODO(joyeecheung): Use one-byte strings for ASCII-only source to save
621cb0ef41Sopenharmony_ci  // memory/binary size - using UTF16 by default results in twice of the size
631cb0ef41Sopenharmony_ci  // than necessary.
641cb0ef41Sopenharmony_ci  static const node::UnionBytes sea_code_union_bytes =
651cb0ef41Sopenharmony_ci      []() -> node::UnionBytes {
661cb0ef41Sopenharmony_ci    size_t expected_u16_length =
671cb0ef41Sopenharmony_ci        simdutf::utf16_length_from_utf8(sea_code.data(), sea_code.size());
681cb0ef41Sopenharmony_ci    auto out = std::make_shared<std::vector<uint16_t>>(expected_u16_length);
691cb0ef41Sopenharmony_ci    size_t u16_length = simdutf::convert_utf8_to_utf16(
701cb0ef41Sopenharmony_ci        sea_code.data(),
711cb0ef41Sopenharmony_ci        sea_code.size(),
721cb0ef41Sopenharmony_ci        reinterpret_cast<char16_t*>(out->data()));
731cb0ef41Sopenharmony_ci    out->resize(u16_length);
741cb0ef41Sopenharmony_ci    return node::UnionBytes{out};
751cb0ef41Sopenharmony_ci  }();
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  args.GetReturnValue().Set(
781cb0ef41Sopenharmony_ci      sea_code_union_bytes.ToStringChecked(env->isolate()));
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci}  // namespace
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_cinamespace node {
841cb0ef41Sopenharmony_cinamespace sea {
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cibool IsSingleExecutable() {
871cb0ef41Sopenharmony_ci  return postject_has_resource();
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_cistd::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
911cb0ef41Sopenharmony_ci  // Repeats argv[0] at position 1 on argv as a replacement for the missing
921cb0ef41Sopenharmony_ci  // entry point file path.
931cb0ef41Sopenharmony_ci  if (IsSingleExecutable()) {
941cb0ef41Sopenharmony_ci    static std::vector<char*> new_argv;
951cb0ef41Sopenharmony_ci    new_argv.reserve(argc + 2);
961cb0ef41Sopenharmony_ci    new_argv.emplace_back(argv[0]);
971cb0ef41Sopenharmony_ci    new_argv.insert(new_argv.end(), argv, argv + argc);
981cb0ef41Sopenharmony_ci    new_argv.emplace_back(nullptr);
991cb0ef41Sopenharmony_ci    argc = new_argv.size() - 1;
1001cb0ef41Sopenharmony_ci    argv = new_argv.data();
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  return {argc, argv};
1041cb0ef41Sopenharmony_ci}
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_civoid Initialize(Local<Object> target,
1071cb0ef41Sopenharmony_ci                Local<Value> unused,
1081cb0ef41Sopenharmony_ci                Local<Context> context,
1091cb0ef41Sopenharmony_ci                void* priv) {
1101cb0ef41Sopenharmony_ci  SetMethod(
1111cb0ef41Sopenharmony_ci      context, target, "getSingleExecutableCode", GetSingleExecutableCode);
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_civoid RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1151cb0ef41Sopenharmony_ci  registry->Register(GetSingleExecutableCode);
1161cb0ef41Sopenharmony_ci}
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci}  // namespace sea
1191cb0ef41Sopenharmony_ci}  // namespace node
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(sea, node::sea::Initialize)
1221cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(sea, node::sea::RegisterExternalReferences)
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci#endif  // !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)
125