diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/jsapi-tests/testStencil.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jsapi-tests/testStencil.cpp')
-rw-r--r-- | js/src/jsapi-tests/testStencil.cpp | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testStencil.cpp b/js/src/jsapi-tests/testStencil.cpp new file mode 100644 index 0000000000..ab89222ebd --- /dev/null +++ b/js/src/jsapi-tests/testStencil.cpp @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <string.h> + +#include "jsapi.h" + +#include "frontend/CompilationStencil.h" +#include "js/CompilationAndEvaluation.h" +#include "js/experimental/CompileScript.h" +#include "js/experimental/JSStencil.h" +#include "js/Modules.h" +#include "js/PropertyAndElement.h" // JS_GetProperty, JS_HasOwnProperty, JS_SetProperty +#include "js/Transcoding.h" +#include "jsapi-tests/tests.h" +#include "vm/HelperThreads.h" // js::RunPendingSourceCompressions +#include "vm/Monitor.h" // js::Monitor, js::AutoLockMonitor + +BEGIN_TEST(testStencil_Basic) { + const char* chars = + "function f() { return 42; }" + "f();"; + auto result = basic_test<char, mozilla::Utf8Unit>(chars); + CHECK(result); + + const char16_t* chars16 = + u"function f() { return 42; }" + u"f();"; + auto result16 = basic_test<char16_t, char16_t>(chars16); + CHECK(result16); + + return true; +} + +template <typename CharT, typename SourceT> +bool basic_test(const CharT* chars) { + size_t length = std::char_traits<CharT>::length(chars); + + JS::SourceText<SourceT> srcBuf; + CHECK(srcBuf.init(cx, chars, length, JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + RefPtr<JS::Stencil> stencil = + JS::CompileGlobalScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + JS::InstantiateOptions instantiateOptions(options); + JS::RootedScript script( + cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + CHECK(script); + + JS::RootedValue rval(cx); + CHECK(JS_ExecuteScript(cx, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + + return true; +} +END_TEST(testStencil_Basic) + +BEGIN_TEST(testStencil_Module) { + const char* chars = + "export function f() { return 42; }" + "globalThis.x = f();"; + auto result = basic_test<char, mozilla::Utf8Unit>(chars); + CHECK(result); + + const char16_t* chars16 = + u"export function f() { return 42; }" + u"globalThis.x = f();"; + auto result16 = basic_test<char16_t, char16_t>(chars16); + CHECK(result16); + + return true; +} + +template <typename CharT, typename SourceT> +bool basic_test(const CharT* chars) { + size_t length = std::char_traits<CharT>::length(chars); + + JS::SourceText<SourceT> srcBuf; + CHECK(srcBuf.init(cx, chars, length, JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + RefPtr<JS::Stencil> stencil = + JS::CompileModuleScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + JS::InstantiateOptions instantiateOptions(options); + JS::RootedObject moduleObject( + cx, JS::InstantiateModuleStencil(cx, instantiateOptions, stencil)); + CHECK(moduleObject); + + // Link and evaluate the module graph. The link step used to be call + // "instantiate" but is unrelated to the concept in Stencil with same name. + JS::RootedValue rval(cx); + CHECK(JS::ModuleLink(cx, moduleObject)); + CHECK(JS::ModuleEvaluate(cx, moduleObject, &rval)); + CHECK(!rval.isUndefined()); + + js::RunJobs(cx); + CHECK(JS_GetProperty(cx, global, "x", &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + + return true; +} +END_TEST(testStencil_Module) + +BEGIN_TEST(testStencil_NonSyntactic) { + const char* chars = + "function f() { return x; }" + "f();"; + + JS::SourceText<mozilla::Utf8Unit> srcBuf; + CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + options.setNonSyntacticScope(true); + + RefPtr<JS::Stencil> stencil = + JS::CompileGlobalScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + JS::InstantiateOptions instantiateOptions(options); + JS::RootedScript script( + cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + CHECK(script); + + JS::RootedObject obj(cx, JS_NewPlainObject(cx)); + JS::RootedValue val(cx, JS::Int32Value(42)); + CHECK(obj); + CHECK(JS_SetProperty(cx, obj, "x", val)); + + JS::RootedObjectVector chain(cx); + CHECK(chain.append(obj)); + + JS::RootedValue rval(cx); + CHECK(JS_ExecuteScript(cx, chain, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + + return true; +} +END_TEST(testStencil_NonSyntactic) + +BEGIN_TEST(testStencil_MultiGlobal) { + const char* chars = + "/**************************************/" + "/**************************************/" + "/**************************************/" + "/**************************************/" + "/**************************************/" + "/**************************************/" + "function f() { return 42; }" + "f();"; + + JS::SourceText<mozilla::Utf8Unit> srcBuf; + CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + RefPtr<JS::Stencil> stencil = + JS::CompileGlobalScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + CHECK(RunInNewGlobal(cx, stencil)); + CHECK(RunInNewGlobal(cx, stencil)); + CHECK(RunInNewGlobal(cx, stencil)); + + // Start any pending SourceCompressionTasks now to confirm nothing fell apart + // when using a JS::Stencil multiple times. + CHECK(strlen(chars) > js::ScriptSource::MinimumCompressibleLength); + js::RunPendingSourceCompressions(cx->runtime()); + + return true; +} +bool RunInNewGlobal(JSContext* cx, RefPtr<JS::Stencil> stencil) { + JS::RootedObject otherGlobal(cx, createGlobal()); + CHECK(otherGlobal); + + JSAutoRealm ar(cx, otherGlobal); + + JS::InstantiateOptions instantiateOptions; + JS::RootedScript script( + cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + CHECK(script); + + JS::RootedValue rval(cx); + CHECK(JS_ExecuteScript(cx, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + + return true; +} +END_TEST(testStencil_MultiGlobal) + +BEGIN_TEST(testStencil_Transcode) { + JS::SetProcessBuildIdOp(TestGetBuildId); + + JS::TranscodeBuffer buffer; + + { + const char* chars = + "function f() { return 42; }" + "f();"; + + JS::SourceText<mozilla::Utf8Unit> srcBuf; + CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + RefPtr<JS::Stencil> stencil = + JS::CompileGlobalScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + // Encode Stencil to XDR + JS::TranscodeResult res = JS::EncodeStencil(cx, stencil, buffer); + CHECK(res == JS::TranscodeResult::Ok); + CHECK(!buffer.empty()); + + // Instantiate and Run + JS::InstantiateOptions instantiateOptions(options); + JS::RootedScript script( + cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + JS::RootedValue rval(cx); + CHECK(script); + CHECK(JS_ExecuteScript(cx, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + } + + // Create a new global + CHECK(createGlobal()); + JSAutoRealm ar(cx, global); + + // Confirm it doesn't have the old code + bool found = false; + CHECK(JS_HasOwnProperty(cx, global, "f", &found)); + CHECK(!found); + + { + // Decode the stencil into new range + RefPtr<JS::Stencil> stencil; + + { + JS::DecodeOptions decodeOptions; + JS::TranscodeRange range(buffer.begin(), buffer.length()); + JS::TranscodeResult res = + JS::DecodeStencil(cx, decodeOptions, range, getter_AddRefs(stencil)); + CHECK(res == JS::TranscodeResult::Ok); + } + + { + JS::FrontendContext* fc = JS::NewFrontendContext(); + JS::DecodeOptions decodeOptions; + JS::TranscodeRange range(buffer.begin(), buffer.length()); + JS::TranscodeResult res = + JS::DecodeStencil(fc, decodeOptions, range, getter_AddRefs(stencil)); + CHECK(res == JS::TranscodeResult::Ok); + JS::DestroyFrontendContext(fc); + } + + // Delete the buffer to verify that the decoded stencil has no dependency + // to the buffer. + memset(buffer.begin(), 0, buffer.length()); + buffer.clear(); + + // Instantiate and Run + JS::InstantiateOptions instantiateOptions; + JS::RootedScript script( + cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + stencil = nullptr; + JS::RootedValue rval(cx); + CHECK(script); + CHECK(JS_ExecuteScript(cx, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + } + + return true; +} +static bool TestGetBuildId(JS::BuildIdCharVector* buildId) { + const char buildid[] = "testXDR"; + return buildId->append(buildid, sizeof(buildid)); +} +END_TEST(testStencil_Transcode) + +BEGIN_TEST(testStencil_TranscodeBorrowing) { + JS::SetProcessBuildIdOp(TestGetBuildId); + + JS::TranscodeBuffer buffer; + + { + const char* chars = + "function f() { return 42; }" + "f();"; + + JS::SourceText<mozilla::Utf8Unit> srcBuf; + CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed)); + + JS::CompileOptions options(cx); + RefPtr<JS::Stencil> stencil = + JS::CompileGlobalScriptToStencil(cx, options, srcBuf); + CHECK(stencil); + + // Encode Stencil to XDR + JS::TranscodeResult res = JS::EncodeStencil(cx, stencil, buffer); + CHECK(res == JS::TranscodeResult::Ok); + CHECK(!buffer.empty()); + } + + JS::RootedScript script(cx); + { + JS::TranscodeRange range(buffer.begin(), buffer.length()); + JS::DecodeOptions decodeOptions; + decodeOptions.borrowBuffer = true; + RefPtr<JS::Stencil> stencil; + JS::TranscodeResult res = + JS::DecodeStencil(cx, decodeOptions, range, getter_AddRefs(stencil)); + CHECK(res == JS::TranscodeResult::Ok); + + JS::InstantiateOptions instantiateOptions; + script = JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil); + CHECK(script); + } + + // Delete the buffer to verify that the instantiated script has no dependency + // to the buffer. + memset(buffer.begin(), 0, buffer.length()); + buffer.clear(); + + JS::RootedValue rval(cx); + CHECK(JS_ExecuteScript(cx, script, &rval)); + CHECK(rval.isNumber() && rval.toNumber() == 42); + + return true; +} +static bool TestGetBuildId(JS::BuildIdCharVector* buildId) { + const char buildid[] = "testXDR"; + return buildId->append(buildid, sizeof(buildid)); +} +END_TEST(testStencil_TranscodeBorrowing) |