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

[web snapshots] Support arrow / async / generator funcs

Bug: v8:11525
Change-Id: I0ac9f252e0de16480036e3630edf7efefe8d8571
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2928501Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74968}
parent d33df161
......@@ -60,6 +60,7 @@ enum FunctionKind : uint8_t {
kClassMembersInitializerFunction,
kClassStaticInitializerFunction,
// END concise methods 2
kInvalid,
kLastFunctionKind = kClassStaticInitializerFunction,
};
......@@ -243,6 +244,8 @@ inline const char* FunctionKind2String(FunctionKind kind) {
return "StaticAsyncConciseGeneratorMethod";
case FunctionKind::kAsyncGeneratorFunction:
return "AsyncGeneratorFunction";
case FunctionKind::kInvalid:
return "Invalid";
}
UNREACHABLE();
}
......
......@@ -40,6 +40,49 @@ void WebSnapshotSerializerDeserializer::Throw(const char* message) {
}
}
uint32_t WebSnapshotSerializerDeserializer::FunctionKindToFunctionFlags(
FunctionKind kind) {
// TODO(v8:11525): Support more function kinds.
switch (kind) {
case FunctionKind::kNormalFunction:
case FunctionKind::kArrowFunction:
case FunctionKind::kGeneratorFunction:
case FunctionKind::kAsyncFunction:
case FunctionKind::kAsyncArrowFunction:
case FunctionKind::kAsyncGeneratorFunction:
break;
default:
Throw("Web Snapshot: Unsupported function kind");
}
auto thing = ArrowFunctionBitField::encode(IsArrowFunction(kind)) +
AsyncFunctionBitField::encode(IsAsyncFunction(kind)) +
GeneratorFunctionBitField::encode(IsGeneratorFunction(kind));
return thing;
}
FunctionKind WebSnapshotSerializerDeserializer::FunctionFlagsToFunctionKind(
uint32_t flags) {
static const FunctionKind kFunctionKinds[] = {
// is_generator = false, is_async = false
FunctionKind::kNormalFunction, // is_arrow = false
FunctionKind::kArrowFunction, // is_arrow = true
// is_generator = false, is_async = true
FunctionKind::kAsyncFunction, // is_arrow = false
FunctionKind::kAsyncArrowFunction, // is_arrow = true
// is_generator = true, is_async = false
FunctionKind::kGeneratorFunction, // is_arrow = false
FunctionKind::kInvalid, // is_arrow = true
// is_generator = true, is_async = true
FunctionKind::kAsyncGeneratorFunction, // is_arrow = false
FunctionKind::kInvalid}; // is_arrow = true
FunctionKind kind = kFunctionKinds[flags];
if (kind == FunctionKind::kInvalid) {
Throw("Web Snapshots: Invalid function flags\n");
}
return kind;
}
WebSnapshotSerializer::WebSnapshotSerializer(v8::Isolate* isolate)
: WebSnapshotSerializerDeserializer(
reinterpret_cast<v8::internal::Isolate*>(isolate)),
......@@ -243,6 +286,7 @@ void WebSnapshotSerializer::SerializeMap(Handle<Map> map, uint32_t& id) {
// - String id (source snippet)
// - Start position in the source snippet
// - Length in the source snippet
// - Flags (see FunctionFlags)
// TODO(v8:11525): Investigate whether the length is really needed.
void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function,
uint32_t& id) {
......@@ -278,6 +322,9 @@ void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function,
function_serializer_.WriteUint32(start);
int end = function->shared().EndPosition();
function_serializer_.WriteUint32(end - start);
function_serializer_.WriteUint32(
FunctionKindToFunctionFlags(function->shared().kind()));
// TODO(v8:11525): Serialize .prototype.
// TODO(v8:11525): Support properties in functions.
}
......@@ -748,13 +795,14 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
uint32_t start_position;
uint32_t length;
uint32_t flags;
if (!deserializer_->ReadUint32(&start_position) ||
!deserializer_->ReadUint32(&length)) {
!deserializer_->ReadUint32(&length) ||
!deserializer_->ReadUint32(&flags)) {
Throw("Web snapshot: Malformed function");
return;
}
// TODO(v8:11525): Support other function kinds.
// TODO(v8:11525): Support (exported) top level functions.
// TODO(v8:11525): Deduplicate the SFIs for inner functions the user creates
......@@ -763,7 +811,7 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
Handle<SharedFunctionInfo> shared =
isolate_->factory()->NewSharedFunctionInfo(
isolate_->factory()->empty_string(), MaybeHandle<Code>(),
Builtins::kCompileLazy, FunctionKind::kNormalFunction);
Builtins::kCompileLazy, FunctionFlagsToFunctionKind(flags));
shared->set_script(*script);
// Index 0 is reserved for top-level shared function info (which web
// snapshot scripts don't have).
......
......@@ -54,6 +54,9 @@ class WebSnapshotSerializerDeserializer {
REGEXP
};
uint32_t FunctionKindToFunctionFlags(FunctionKind kind);
FunctionKind FunctionFlagsToFunctionKind(uint32_t flags);
// The maximum count of items for each value type (strings, objects etc.)
static constexpr uint32_t kMaxItemCount =
static_cast<uint32_t>(FixedArray::kMaxLength - 1);
......@@ -74,6 +77,12 @@ class WebSnapshotSerializerDeserializer {
delete;
WebSnapshotSerializerDeserializer& operator=(
const WebSnapshotSerializerDeserializer&) = delete;
// Keep most common function kinds in the 7 least significant bits to make the
// flags fit in 1 byte.
using ArrowFunctionBitField = base::BitField<bool, 0, 1>;
using AsyncFunctionBitField = ArrowFunctionBitField::Next<bool, 1>;
using GeneratorFunctionBitField = AsyncFunctionBitField::Next<bool, 1>;
};
class V8_EXPORT WebSnapshotSerializer
......
......@@ -505,5 +505,56 @@ TEST(SFIDeduplicationOfFunctionsNotInSnapshot) {
}
}
namespace {
void VerifyFunctionKind(const v8::Local<v8::Object>& result,
const v8::Local<v8::Context>& context,
const char* property_name, FunctionKind expected_kind) {
v8::Local<v8::Function> v8_function =
result->Get(context, v8_str(property_name))
.ToLocalChecked()
.As<v8::Function>();
Handle<JSFunction> function =
Handle<JSFunction>::cast(Utils::OpenHandle(*v8_function));
CHECK_EQ(function->shared().kind(), expected_kind);
}
} // namespace
TEST(FunctionKinds) {
const char* snapshot_source =
"var foo = {a: function() {},\n"
" b: () => {},\n"
" c: async function() {},\n"
" d: async () => {},\n"
" e: function*() {},\n"
" f: async function*() {}\n"
"}";
const char* test_source = "foo";
uint32_t kStringCount = 8; // 'foo', 'a', ..., 'f', source code
uint32_t kMapCount = 1;
uint32_t kContextCount = 0;
uint32_t kFunctionCount = 6;
uint32_t kObjectCount = 1;
std::function<void(v8::Isolate*, v8::Local<v8::Context>)> tester =
[test_source](v8::Isolate* isolate, v8::Local<v8::Context> new_context) {
v8::Local<v8::Object> result = CompileRun(test_source).As<v8::Object>();
// Verify all FunctionKinds.
VerifyFunctionKind(result, new_context, "a",
FunctionKind::kNormalFunction);
VerifyFunctionKind(result, new_context, "b",
FunctionKind::kArrowFunction);
VerifyFunctionKind(result, new_context, "c",
FunctionKind::kAsyncFunction);
VerifyFunctionKind(result, new_context, "d",
FunctionKind::kAsyncArrowFunction);
VerifyFunctionKind(result, new_context, "e",
FunctionKind::kGeneratorFunction);
VerifyFunctionKind(result, new_context, "f",
FunctionKind::kAsyncGeneratorFunction);
};
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
kMapCount, kContextCount, kFunctionCount,
kObjectCount);
}
} // namespace internal
} // namespace v8
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