Bug 1773319 - Intro API to create/destroy FrontendContext, ParseScript r=arai

Need to fill out jsapi-test for more details and use cases.

ParseGlobalScript() has a stackLimit parameter because I don't expect to
know what the limit for the TaskController task is, or even that the function
is being run by TaskController.

Differential Revision: https://phabricator.services.mozilla.com/D167461
This commit is contained in:
Bryan Thrall 2023-04-04 17:36:45 +00:00
Родитель 00196ec53e
Коммит 9dfe84719a
9 изменённых файлов: 216 добавлений и 1 удалений

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- 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/. */
/* JavaScript API for compiling scripts to stencil without depending on
* JSContext. */
#ifndef js_experimental_ParseScript_h
#define js_experimental_ParseScript_h
#include "jspubtd.h"
#include "js/experimental/JSStencil.h"
#include "js/Stack.h"
namespace js {
class FrontendContext;
}
namespace JS {
using FrontendContext = js::FrontendContext;
// Create a new front-end context.
JS_PUBLIC_API JS::FrontendContext* NewFrontendContext();
// Destroy a front-end context allocated with JS_NewFrontendContext.
JS_PUBLIC_API void DestroyFrontendContext(JS::FrontendContext* fc);
extern JS_PUBLIC_API already_AddRefed<JS::Stencil> ParseGlobalScript(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::NativeStackLimit stackLimit, JS::SourceText<mozilla::Utf8Unit>& srcBuf);
extern JS_PUBLIC_API already_AddRefed<JS::Stencil> ParseGlobalScript(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::NativeStackLimit stackLimit, JS::SourceText<char16_t>& srcBuf);
} // namespace JS
#endif // js_experimental_ParseScript_h

Просмотреть файл

@ -312,7 +312,7 @@ template <typename Unit>
return false;
}
// TODO bug 1773339 maybeCx nullptr could crash here
// TODO bug 1773319 maybeCx nullptr could crash here
if (input.options.populateDelazificationCache() &&
!maybeCx->isHelperThreadContext()) {
BorrowingCompilationStencil borrowingStencil(compiler.stencil());

Просмотреть файл

@ -190,3 +190,18 @@ JS_PUBLIC_API bool js::CheckWasiRecursionLimit(FrontendContext* fc) {
return fc->checkWasiRecursionLimit();
}
#endif // __wasi__
FrontendContext* js::NewFrontendContext() {
UniquePtr<FrontendContext> fc = MakeUnique<FrontendContext>();
if (!fc) {
return nullptr;
}
if (!fc->allocateOwnedPool()) {
return nullptr;
}
return fc.release();
}
void js::DestroyFrontendContext(FrontendContext* fc) { js_delete_poison(fc); }

Просмотреть файл

@ -226,6 +226,14 @@ class ManualReportFrontendContext : public FrontendContext {
}
};
// Create function for FrontendContext, which is manually allocated and
// exclusively owned.
extern FrontendContext* NewFrontendContext();
// Destroy function for FrontendContext, which was allocated with
// NewFrontendContext.
extern void DestroyFrontendContext(FrontendContext* fc);
} // namespace js
#endif /* frontend_FrontendContext_h */

Просмотреть файл

@ -0,0 +1,67 @@
/* -*- 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 "js/experimental/ParseScript.h"
#include "frontend/BytecodeCompilation.h" // frontend::CompileGlobalScriptToStencil
#include "frontend/CompilationStencil.h" // frontend::{CompilationStencil,CompilationInput}
#include "frontend/FrontendContext.h" // frontend::FrontendContext
#include "frontend/ScopeBindingCache.h" // frontend::NoScopeBindingCache
#include "js/SourceText.h" // JS::SourceText
#include "js/Stack.h" // JS::GetNativeStackLimit
#include "util/NativeStack.h" // GetNativeStackBase
using namespace js;
JS_PUBLIC_API FrontendContext* JS::NewFrontendContext() {
MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running,
"must call JS_Init prior to creating any FrontendContexts");
return js::NewFrontendContext();
}
JS_PUBLIC_API void JS::DestroyFrontendContext(FrontendContext* fc) {
return js::DestroyFrontendContext(fc);
}
template <typename CharT>
static already_AddRefed<JS::Stencil> ParseGlobalScriptImpl(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::NativeStackLimit stackLimit, JS::SourceText<CharT>& srcBuf) {
ScopeKind scopeKind = ScopeKind::Global;
// TODO bug 1773319 nonsyntactic scope
JS::SourceText<CharT> data(std::move(srcBuf));
UniquePtr<frontend::CompilationInput> stencilInput_ =
fc->getAllocator()->make_unique<frontend::CompilationInput>(options);
if (!stencilInput_) {
return nullptr;
}
frontend::NoScopeBindingCache scopeCache;
LifoAlloc tempLifoAlloc(JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
RefPtr<frontend::CompilationStencil> stencil_ =
frontend::CompileGlobalScriptToStencil(nullptr, fc, stackLimit,
tempLifoAlloc, *stencilInput_,
&scopeCache, data, scopeKind);
return stencil_.forget();
}
// TODO bug 1773319 alloc instantiation storage
already_AddRefed<JS::Stencil> JS::ParseGlobalScript(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::NativeStackLimit stackLimit,
JS::SourceText<mozilla::Utf8Unit>& srcBuf) {
return ParseGlobalScriptImpl(fc, options, stackLimit, srcBuf);
}
already_AddRefed<JS::Stencil> JS::ParseGlobalScript(
JS::FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
JS::NativeStackLimit stackLimit, JS::SourceText<char16_t>& srcBuf) {
return ParseGlobalScriptImpl(fc, options, stackLimit, srcBuf);
}

Просмотреть файл

@ -64,6 +64,7 @@ UNIFIED_SOURCES += [
"ParseNode.cpp",
"ParseNodeVerify.cpp",
"ParserAtom.cpp",
"ParseScript.cpp",
"PrivateOpEmitter.cpp",
"PropOpEmitter.cpp",
"SharedContext.cpp",

Просмотреть файл

@ -90,6 +90,7 @@ UNIFIED_SOURCES += [
"testOOM.cpp",
"testParseJSON.cpp",
"testParserAtom.cpp",
"testParseScript.cpp",
"testPersistentRooted.cpp",
"testPreserveJitCode.cpp",
"testPrintf.cpp",

Просмотреть файл

@ -0,0 +1,82 @@
/* 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 "mozilla/RefPtr.h" // RefPtr
#include "mozilla/ScopeExit.h" // MakeScopeExit
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
#include "frontend/CompilationStencil.h" // JS::Stencil
#include "js/CompileOptions.h" // JS::CompileOptions, JS::InstantiateOptions
#include "js/experimental/ParseScript.h" // JS::NewFrontendContext
#include "js/SourceText.h" // JS::Source{Ownership,Text}
#include "jsapi-tests/tests.h"
#include "vm/ErrorReporting.h"
using namespace JS;
template <typename T>
static void dump(const T& data) {
js::Fprinter printer(stderr);
js::JSONPrinter json(printer, true);
data->dump(json);
printer.put("\n");
}
BEGIN_TEST(testParseScript) {
CHECK(testCompile());
return true;
}
bool testCompile() {
static constexpr std::string_view src = "42\n";
static constexpr std::u16string_view src_16 = u"42\n";
static_assert(src.length() == src_16.length(),
"Source buffers must be same length");
JS::CompileOptions options(cx);
JS::SourceText<char16_t> buf16;
CHECK(buf16.init(cx, src_16.data(), src_16.length(),
JS::SourceOwnership::Borrowed));
JS::SourceText<mozilla::Utf8Unit> buf8;
CHECK(buf8.init(cx, src.data(), src.length(), JS::SourceOwnership::Borrowed));
JS::FrontendContext* fc = JS::NewFrontendContext();
CHECK(fc);
auto destroyFc =
mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
RefPtr<JS::Stencil> stencil = ParseGlobalScript(
fc, options, cx->stackLimitForCurrentPrincipal(), buf16);
CHECK(stencil);
CHECK(stencil->scriptExtra.size() == 1);
CHECK(stencil->scriptExtra[0].extent.sourceStart == 0);
CHECK(stencil->scriptExtra[0].extent.sourceEnd == 3);
CHECK(stencil->scriptData.size() == 1);
CHECK(stencil->scriptData[0].hasSharedData()); // has generated bytecode
CHECK(stencil->scriptData[0].gcThingsLength == 1);
stencil =
ParseGlobalScript(fc, options, cx->stackLimitForCurrentPrincipal(), buf8);
CHECK(stencil);
{
JS::SourceText<char16_t> srcBuf;
CHECK(srcBuf.init(cx, src_16.data(), src_16.length(),
JS::SourceOwnership::Borrowed));
stencil = ParseGlobalScript(fc, options,
cx->stackLimitForCurrentPrincipal(), srcBuf);
CHECK(stencil);
}
// TODO bug 1773319 check failure is propagated out
return true;
}
END_TEST(testParseScript);

Просмотреть файл

@ -248,6 +248,7 @@ EXPORTS.js.experimental += [
"../public/experimental/Intl.h",
"../public/experimental/JitInfo.h",
"../public/experimental/JSStencil.h",
"../public/experimental/ParseScript.h",
"../public/experimental/PCCountProfiling.h",
"../public/experimental/SourceHook.h",
"../public/experimental/TypedData.h",