diff options
Diffstat (limited to 'misctools')
-rw-r--r-- | misctools/cold-jsc-start.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
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; + } +} |