Commit 16ccef22 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[web snapshots] Add an experimiental flag for treating scripts as web snapshots

Scripts are treated as web snapshots if they start with a magic number.
This enables end-to-end web snapshot implementations without changing
the embedders.

Bug: v8:11525
Change-Id: Ib8b098bb8cf0b9f96894009414b1cea7646b60dd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3218977Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77389}
parent a7111acb
......@@ -120,6 +120,7 @@
#include "src/tracing/trace-event.h"
#include "src/utils/detachable-vector.h"
#include "src/utils/version.h"
#include "src/web-snapshot/web-snapshot.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/trap-handler/trap-handler.h"
......@@ -2044,7 +2045,8 @@ Local<Value> UnboundScript::GetSourceMappingURL() {
}
MaybeLocal<Value> Script::Run(Local<Context> context) {
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
auto v8_isolate = context->GetIsolate();
auto isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
ENTER_V8(isolate, context, Script, Run, MaybeLocal<Value>(),
InternalEscapableScope);
......@@ -2074,6 +2076,19 @@ MaybeLocal<Value> Script::Run(Local<Context> context) {
}
}
if (V8_UNLIKELY(i::FLAG_experimental_web_snapshots)) {
i::Handle<i::HeapObject> maybe_script =
handle(fun->shared().script(), isolate);
if (maybe_script->IsScript() &&
i::Script::cast(*maybe_script).type() == i::Script::TYPE_WEB_SNAPSHOT) {
i::WebSnapshotDeserializer deserializer(v8_isolate);
deserializer.UseWebSnapshot(i::Handle<i::Script>::cast(maybe_script));
RETURN_ON_FAILED_EXECUTION(Value);
Local<Value> result = v8::Undefined(v8_isolate);
RETURN_ESCAPED(result);
}
}
i::Handle<i::Object> receiver = isolate->global_proxy();
Local<Value> result;
has_pending_exception = !ToLocal<Value>(
......
......@@ -60,6 +60,7 @@
#include "src/parsing/scanner-character-streams.h"
#include "src/snapshot/code-serializer.h"
#include "src/utils/ostreams.h"
#include "src/web-snapshot/web-snapshot.h"
#include "src/zone/zone-list-inl.h" // crbug.com/v8/8816
namespace v8 {
......@@ -2855,6 +2856,27 @@ MaybeHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl(
isolate->counters()->total_load_size()->Increment(source_length);
isolate->counters()->total_compile_size()->Increment(source_length);
if (V8_UNLIKELY(
i::FLAG_experimental_web_snapshots &&
(source->IsExternalOneByteString() || source->IsSeqOneByteString()) &&
source_length > 4)) {
// Experimental: Treat the script as a web snapshot if it starts with the
// magic byte sequence. TODO(v8:11525): Remove this once proper embedder
// integration is done.
bool magic_matches = true;
for (size_t i = 0;
i < sizeof(WebSnapshotSerializerDeserializer::kMagicNumber); ++i) {
if (source->Get(static_cast<int>(i)) !=
WebSnapshotSerializerDeserializer::kMagicNumber[i]) {
magic_matches = false;
break;
}
}
if (magic_matches) {
return Compiler::GetSharedFunctionInfoForWebSnapshot(isolate, source);
}
}
LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
CompilationCache* compilation_cache = isolate->compilation_cache();
......@@ -3223,6 +3245,23 @@ Compiler::GetSharedFunctionInfoForStreamedScript(
return maybe_result;
}
// static
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForWebSnapshot(
Isolate* isolate, Handle<String> source) {
// This script won't hold the functions created from the web snapshot;
// reserving space only for the top-level SharedFunctionInfo is enough.
Handle<WeakFixedArray> shared_function_infos =
isolate->factory()->NewWeakFixedArray(1, AllocationType::kOld);
Handle<Script> script = isolate->factory()->NewScript(source);
script->set_type(Script::TYPE_WEB_SNAPSHOT);
script->set_shared_function_infos(*shared_function_infos);
Handle<SharedFunctionInfo> shared =
isolate->factory()->NewSharedFunctionInfoForWebSnapshot();
shared->SetScript(isolate->factory()->read_only_roots(), *script, 0, false);
return shared;
}
// static
template <typename IsolateT>
Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
......
......@@ -207,6 +207,9 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic {
Isolate* isolate, Handle<String> source,
const ScriptDetails& script_details, ScriptStreamingData* streaming_data);
static Handle<SharedFunctionInfo> GetSharedFunctionInfoForWebSnapshot(
Isolate* isolate, Handle<String> source);
// Create a shared function info object for the given function literal
// node (the code may be lazily compiled).
template <typename IsolateT>
......
......@@ -2162,6 +2162,13 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, parallel_scavenge)
DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_array_buffer_sweeping)
DEFINE_NEG_IMPLICATION(single_threaded_gc, stress_concurrent_allocation)
// Web snapshots
// TODO(v8:11525): Remove this flag once proper embedder integration is done.
DEFINE_BOOL(
experimental_web_snapshots, false,
"interpret scripts as web snapshots if they start with a magic number")
DEFINE_NEG_IMPLICATION(experimental_web_snapshots, script_streaming)
#undef FLAG
#ifdef VERIFY_PREDICTABLE
......
......@@ -2992,6 +2992,12 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForBuiltin(
return shared;
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForWebSnapshot() {
return NewSharedFunctionInfo(empty_string(), MaybeHandle<Code>(),
Builtin::kNoBuiltinId,
FunctionKind::kNormalFunction);
}
namespace {
V8_INLINE int NumberToStringCacheHash(Handle<FixedArray> cache, Smi number) {
int mask = (cache->length() >> 1) - 1;
......
......@@ -726,6 +726,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
MaybeHandle<String> name, Builtin builtin,
FunctionKind kind = kNormalFunction);
Handle<SharedFunctionInfo> NewSharedFunctionInfoForWebSnapshot();
static bool IsFunctionModeWithPrototype(FunctionMode function_mode) {
return (function_mode & kWithPrototypeBits) != 0;
}
......
......@@ -767,19 +767,51 @@ void WebSnapshotDeserializer::Throw(const char* message) {
bool WebSnapshotDeserializer::UseWebSnapshot(const uint8_t* data,
size_t buffer_size) {
deserializer_.reset(new ValueDeserializer(isolate_, data, buffer_size));
return Deserialize();
}
bool WebSnapshotDeserializer::UseWebSnapshot(
Handle<Script> snapshot_as_script) {
Handle<String> source =
handle(String::cast(snapshot_as_script->source()), isolate_);
if (source->IsExternalOneByteString()) {
const v8::String::ExternalOneByteStringResource* resource =
ExternalOneByteString::cast(*source).resource();
deserializer_.reset(new ValueDeserializer(
isolate_, reinterpret_cast<const uint8_t*>(resource->data()),
resource->length()));
return Deserialize();
}
DCHECK(source->IsSeqOneByteString());
SeqOneByteString source_as_seq = SeqOneByteString::cast(*source);
auto length = source_as_seq.length();
uint8_t* data_copy = new uint8_t[length];
{
DisallowGarbageCollection no_gc;
uint8_t* data = source_as_seq.GetChars(no_gc);
memcpy(data_copy, data, length);
}
deserializer_.reset(new ValueDeserializer(isolate_, data_copy, length));
bool return_value = Deserialize();
delete[] data_copy;
return return_value;
}
bool WebSnapshotDeserializer::Deserialize() {
RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize);
if (deserialized_) {
Throw("Web snapshot: Can't reuse WebSnapshotDeserializer");
return false;
}
deserialized_ = true;
auto buffer_size = deserializer_->end_ - deserializer_->position_;
base::ElapsedTimer timer;
if (FLAG_trace_web_snapshot) {
timer.Start();
}
deserializer_.reset(new ValueDeserializer(isolate_, data, buffer_size));
deferred_references_ = ArrayList::New(isolate_, 30);
const void* magic_bytes;
......
......@@ -200,6 +200,7 @@ class V8_EXPORT WebSnapshotDeserializer
explicit WebSnapshotDeserializer(v8::Isolate* v8_isolate);
~WebSnapshotDeserializer();
bool UseWebSnapshot(const uint8_t* data, size_t buffer_size);
bool UseWebSnapshot(Handle<Script> snapshot_as_script);
// For inspecting the state after deserializing a snapshot.
uint32_t string_count() const { return string_count_; }
......@@ -211,6 +212,8 @@ class V8_EXPORT WebSnapshotDeserializer
uint32_t object_count() const { return object_count_; }
private:
bool Deserialize();
WebSnapshotDeserializer(const WebSnapshotDeserializer&) = delete;
WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment