aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-05-05 20:01:26 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-05-05 20:01:26 -0700
commit9d7ecf7909f17835024c7754c38eed25e1dbb592 (patch)
treec8854114efa97b4b9b30b69848b803df783e3ac1
parent31cb49a026610382d06f319cbe76ce0efeded345 (diff)
downloadbun-9d7ecf7909f17835024c7754c38eed25e1dbb592.tar.gz
bun-9d7ecf7909f17835024c7754c38eed25e1dbb592.tar.zst
bun-9d7ecf7909f17835024c7754c38eed25e1dbb592.zip
[misctools] Add cold jsc start test
-rw-r--r--.gitignore3
-rw-r--r--Makefile16
-rw-r--r--misctools/cold-jsc-start.cpp191
3 files changed, 210 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index d7e8d953e..b2377f761 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,3 +116,6 @@ src/bun.js/debug-bindings-obj
failing-tests.txt
test.txt
myscript.sh
+
+cold-jsc-start
+cold-jsc-start.d
diff --git a/Makefile b/Makefile
index 874a35116..7bdba3f6e 100644
--- a/Makefile
+++ b/Makefile
@@ -1827,6 +1827,22 @@ copy-to-bun-release-dir-bin:
PACKAGE_MAP = --pkg-begin async_io $(BUN_DIR)/src/io/io_darwin.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin javascript_core $(BUN_DIR)/src/jsc.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end
+.PHONY: cold-jsc-start
+cold-jsc-start:
+ $(CXX_WITH_CCACHE) $(CLANG_FLAGS) \
+ $(MACOS_MIN_FLAG) \
+ $(OPTIMIZATION_LEVEL) \
+ -MMD \
+ -fno-exceptions \
+ -fno-rtti \
+ -ferror-limit=1000 \
+ $(LIBICONV_PATH) \
+ $(DEFAULT_LINKER_FLAGS) \
+ $(PLATFORM_LINKER_FLAGS) \
+ $(ICU_FLAGS) \
+ $(JSC_FILES) \
+ misctools/cold-jsc-start.cpp -o cold-jsc-start
+
.PHONY: vendor-without-npm
vendor-without-npm: node-fallbacks runtime_js fallback_decoder bun_error mimalloc picohttp zlib boringssl libarchive lolhtml sqlite usockets uws tinycc c-ares
diff --git a/misctools/cold-jsc-start.cpp b/misctools/cold-jsc-start.cpp
new file mode 100644
index 000000000..2703d7016
--- /dev/null
+++ b/misctools/cold-jsc-start.cpp
@@ -0,0 +1,191 @@
+// print how long each step took
+#define VERBOSE
+
+//
+// This loads up a JavaScriptCore global object which only has a "write"
+// global function and then calls eval
+//
+//
+// Usage:
+// ./cold-jsc-start <file>
+// ./cold-jsc-start -e "write('hey')"
+//
+#include "root.h"
+
+#include <wtf/FileSystem.h>
+
+#include <JavaScriptCore/JSGlobalObject.h>
+
+#include <JavaScriptCore/JSArrayBufferView.h>
+#include <JavaScriptCore/JSArrayBufferViewInlines.h>
+
+#include <JavaScriptCore/Completion.h>
+#include <JavaScriptCore/InitializeThreading.h>
+#include <unistd.h>
+#include <wtf/Stopwatch.h>
+
+using namespace JSC;
+
+JSC_DEFINE_HOST_FUNCTION(jsFunctionWrite, (JSC::JSGlobalObject * globalObject,
+ JSC::CallFrame *callframe)) {
+
+ if (callframe->argumentCount() < 1)
+ return JSValue::encode(jsUndefined());
+
+ JSValue arg1 = callframe->argument(0);
+ JSValue toWriteArg = callframe->argument(1);
+ auto &vm = globalObject->vm();
+ auto scope = DECLARE_CATCH_SCOPE(vm);
+
+ int32_t fd = STDOUT_FILENO;
+ if (callframe->argumentCount() > 1) {
+ fd = arg1.toInt32(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ } else {
+ toWriteArg = arg1;
+ }
+
+ if (auto *buffer = jsDynamicCast<JSC::JSArrayBufferView *>(toWriteArg)) {
+ auto *data = buffer->vector();
+ auto length = buffer->byteLength();
+ auto written = write(fd, data, length);
+ return JSValue::encode(jsNumber(written));
+ }
+
+ auto string = toWriteArg.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ auto utf8 = string.utf8();
+ auto length = utf8.length();
+ auto written = write(fd, utf8.data(), length);
+ return JSValue::encode(jsNumber(written));
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <file>\n", argv[0]);
+ return 1;
+ }
+#ifdef VERBOSE
+ auto stopwatch = Stopwatch::create();
+ stopwatch->start();
+#endif
+
+ {
+ WTF::initializeMainThread();
+ JSC::initialize();
+ {
+ JSC::Options::AllowUnfinalizedAccessScope scope;
+
+ JSC::Options::useConcurrentJIT() = true;
+ // JSC::Options::useSigillCrashAnalyzer() = true;
+ JSC::Options::useWebAssembly() = true;
+ JSC::Options::useSourceProviderCache() = true;
+ // JSC::Options::useUnlinkedCodeBlockJettisoning() = false;
+ JSC::Options::exposeInternalModuleLoader() = true;
+ JSC::Options::useSharedArrayBuffer() = true;
+ JSC::Options::useJIT() = true;
+ JSC::Options::useBBQJIT() = true;
+ JSC::Options::useJITCage() = false;
+ JSC::Options::useShadowRealm() = true;
+ JSC::Options::useResizableArrayBuffer() = true;
+ JSC::Options::showPrivateScriptsInStackTraces() = true;
+ JSC::Options::useSetMethods() = true;
+ JSC::Options::assertOptionsAreCoherent();
+ }
+ }
+
+#ifdef VERBOSE
+
+ fprintf(stderr, "JSC::Initialize took %f ms\n",
+ stopwatch->elapsedTime().milliseconds());
+ stopwatch->reset();
+ stopwatch->start();
+#endif
+
+ auto &vm = JSC::VM::create(JSC::HeapType::Large).leakRef();
+ vm.heap.acquireAccess();
+
+#ifdef VERBOSE
+ fprintf(stderr, "JSC::VM::create took %f ms\n",
+ stopwatch->elapsedTime().milliseconds());
+ stopwatch->reset();
+ stopwatch->start();
+#endif
+
+ JSC::JSLockHolder locker(vm);
+ auto *globalObject = JSC::JSGlobalObject::create(
+ vm, JSC::JSGlobalObject::createStructure(vm, JSC::jsNull()));
+
+#ifdef VERBOSE
+ fprintf(stderr, "JSC::JSGlobalObject::create took %f ms\n",
+ stopwatch->elapsedTime().milliseconds());
+ stopwatch->reset();
+ stopwatch->start();
+#endif
+
+ JSC::gcProtect(globalObject);
+ globalObject->putDirectNativeFunction(
+ vm, globalObject,
+ PropertyName(JSC::Identifier::fromString(vm, "write"_s)), 0,
+ jsFunctionWrite, ImplementationVisibility::Public, JSC::NoIntrinsic,
+ JSC::PropertyAttribute::ReadOnly | 0);
+
+ vm.ref();
+ if (argc > 2) {
+ auto source = JSC::makeSource(WTF::String::fromUTF8(argv[argc - 1]),
+ SourceOrigin(WTF::URL("file://eval.js"_s)),
+ "eval.js"_s);
+
+ NakedPtr<Exception> evaluationException;
+ JSValue returnValue =
+ JSC::profiledEvaluate(globalObject, ProfilingReason::API, source,
+ globalObject, evaluationException);
+
+#ifdef VERBOSE
+ fprintf(stderr, "\neval took %f ms\n",
+ stopwatch->elapsedTime().milliseconds());
+ stopwatch->reset();
+
+#endif
+
+ if (evaluationException) {
+ fprintf(
+ stderr, "Exception: %s\n",
+ evaluationException->value().toWTFString(globalObject).utf8().data());
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ WTF::String fileURLString = WTF::String::fromUTF8(argv[argc - 1]);
+
+ if (auto contents = WTF::FileSystemImpl::readEntireFile(fileURLString)) {
+ auto source =
+ JSC::makeSource(WTF::String::fromUTF8(contents.value()),
+ SourceOrigin(WTF::URL(fileURLString)), fileURLString);
+
+ NakedPtr<Exception> evaluationException;
+ JSValue returnValue =
+ JSC::profiledEvaluate(globalObject, ProfilingReason::API, source,
+ globalObject, evaluationException);
+
+#ifdef VERBOSE
+ fprintf(stderr, "eval took %f ms\n",
+ stopwatch->elapsedTime().milliseconds());
+ stopwatch->reset();
+#endif
+
+ if (evaluationException) {
+ fprintf(
+ stderr, "Exception: %s\n",
+ evaluationException->value().toWTFString(globalObject).utf8().data());
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ fprintf(stderr, "Could not read file %s\n", argv[argc - 1]);
+ return 1;
+ }
+}