Add tests for serialization of v8::CFunction
The tests are modeled after another patch that includes v8::CFunctions into Node.js's builtin snapshot. Refs: https://github.com/nodejs/node/pull/40649 Change-Id: I5a91682f7944ef06a0d3caf7333b09f974bcd64b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3251138 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Commit-Queue: Joyee Cheung <joyee@igalia.com> Cr-Commit-Position: refs/heads/main@{#77726}
This commit is contained in:
parent
1b4d3b6393
commit
5dd16ca0fb
@ -29,6 +29,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "include/v8-extension.h"
|
||||
#include "include/v8-fast-api-calls.h"
|
||||
#include "include/v8-function.h"
|
||||
#include "include/v8-locker.h"
|
||||
#include "src/api/api-inl.h"
|
||||
@ -3102,6 +3103,160 @@ UNINITIALIZED_TEST(SnapshotCreatorShortExternalReferences) {
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
class FastApiReceiver {
|
||||
public:
|
||||
static void FastCallback(v8::Local<v8::Object> receiver) {
|
||||
FastApiReceiver* receiver_ptr = static_cast<FastApiReceiver*>(
|
||||
receiver->GetAlignedPointerFromInternalField(0));
|
||||
CHECK_EQ(receiver_ptr, &instance);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
}
|
||||
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Object* receiver = v8::Object::Cast(*info.Holder());
|
||||
FastApiReceiver* receiver_ptr = static_cast<FastApiReceiver*>(
|
||||
receiver->GetAlignedPointerFromInternalField(0));
|
||||
CHECK_EQ(receiver_ptr, &instance);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
}
|
||||
|
||||
static v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder,
|
||||
int index, void* data) {
|
||||
void* ptr = holder->GetAlignedPointerFromInternalField(index);
|
||||
if (ptr != &instance) {
|
||||
return {nullptr, 0};
|
||||
}
|
||||
// Use a 1-byte payload to tell that it's a FastApiReceiver.
|
||||
char* payload = new char[1];
|
||||
return {payload, 1};
|
||||
}
|
||||
|
||||
static void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
|
||||
v8::StartupData payload, void* data) {
|
||||
if (payload.raw_size == 0) {
|
||||
holder->SetAlignedPointerInInternalField(index, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the state for testing.
|
||||
instance.result_ = ApiCheckerResult::kNotCalled;
|
||||
holder->SetAlignedPointerInInternalField(index, &instance);
|
||||
}
|
||||
|
||||
bool DidCallFast() const { return (result_ & ApiCheckerResult::kFastCalled); }
|
||||
bool DidCallSlow() const { return (result_ & ApiCheckerResult::kSlowCalled); }
|
||||
|
||||
static FastApiReceiver instance;
|
||||
v8::CFunction c_function = v8::CFunction::Make(FastCallback);
|
||||
|
||||
private:
|
||||
ApiCheckerResultFlags result_ = ApiCheckerResult::kNotCalled;
|
||||
};
|
||||
|
||||
FastApiReceiver FastApiReceiver::instance;
|
||||
// A CFunction comes with three external references: the fast calback,
|
||||
// the slow callback, and the type info.
|
||||
intptr_t c_function_external_references[] = {
|
||||
reinterpret_cast<intptr_t>(FastApiReceiver::FastCallback),
|
||||
reinterpret_cast<intptr_t>(FastApiReceiver::SlowCallback),
|
||||
reinterpret_cast<intptr_t>(
|
||||
FastApiReceiver::instance.c_function.GetTypeInfo()),
|
||||
0};
|
||||
|
||||
UNINITIALIZED_TEST(CFunction) {
|
||||
#ifndef V8_LITE_MODE
|
||||
if (i::FLAG_jitless) return;
|
||||
if (!i::FLAG_opt) return;
|
||||
|
||||
i::FLAG_turbo_fast_api_calls = true;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
// Disable --always_opt, otherwise we haven't generated the necessary
|
||||
// feedback to go down the "best optimization" path for the fast call.
|
||||
// No optimization should be done before serialization, but after
|
||||
// deserialization we need optimization to check the fast calls.
|
||||
i::FLAG_always_opt = false;
|
||||
i::FlagList::EnforceFlagImplications();
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator(c_function_external_references);
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
v8::Local<v8::FunctionTemplate> callback = v8::FunctionTemplate::New(
|
||||
isolate, FastApiReceiver::SlowCallback, v8::Local<v8::Value>(),
|
||||
v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow,
|
||||
v8::SideEffectType::kHasSideEffect,
|
||||
&(FastApiReceiver::instance.c_function));
|
||||
|
||||
v8::Local<v8::ObjectTemplate> object_template =
|
||||
v8::ObjectTemplate::New(isolate);
|
||||
object_template->SetInternalFieldCount(1);
|
||||
object_template->Set(isolate, "api_func", callback);
|
||||
|
||||
v8::Local<v8::Object> object =
|
||||
object_template->NewInstance(context).ToLocalChecked();
|
||||
object->SetAlignedPointerInInternalField(0, &(FastApiReceiver::instance));
|
||||
CHECK(context->Global()
|
||||
->Set(context, v8_str("receiver"), object)
|
||||
.FromJust());
|
||||
|
||||
CHECK(!FastApiReceiver::instance.DidCallFast());
|
||||
CHECK(!FastApiReceiver::instance.DidCallSlow());
|
||||
|
||||
CompileRun("receiver.api_func();");
|
||||
CHECK(FastApiReceiver::instance.DidCallSlow());
|
||||
|
||||
creator.SetDefaultContext(
|
||||
context, v8::SerializeInternalFieldsCallback(
|
||||
FastApiReceiver::SerializeInternalFields, nullptr));
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
{
|
||||
v8::Isolate::CreateParams params;
|
||||
params.snapshot_blob = &blob;
|
||||
params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
params.external_references = c_function_external_references;
|
||||
|
||||
// Test-appropriate equivalent of v8::Isolate::New.
|
||||
v8::Isolate* isolate = TestSerializer::NewIsolate(params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(
|
||||
isolate, nullptr, v8::MaybeLocal<v8::ObjectTemplate>(),
|
||||
v8::MaybeLocal<v8::Value>(),
|
||||
v8::DeserializeInternalFieldsCallback(
|
||||
FastApiReceiver::DeserializeInternalFields, nullptr));
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
// Deserialize callback should reset the state of the instance.
|
||||
CHECK(!FastApiReceiver::instance.DidCallFast());
|
||||
CHECK(!FastApiReceiver::instance.DidCallSlow());
|
||||
CompileRun(
|
||||
"function foo(arg) {"
|
||||
" for (let i = 0; i < arg; ++i) { receiver.api_func(); }"
|
||||
"}"
|
||||
"%PrepareFunctionForOptimization(foo);"
|
||||
"foo(42); foo(42);"
|
||||
"%OptimizeFunctionOnNextCall(foo);"
|
||||
"foo(42);");
|
||||
CHECK(FastApiReceiver::instance.DidCallFast());
|
||||
}
|
||||
isolate->Dispose();
|
||||
}
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
#endif
|
||||
}
|
||||
|
||||
v8::StartupData CreateSnapshotWithDefaultAndCustom() {
|
||||
v8::SnapshotCreator creator(original_external_references);
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
|
Loading…
Reference in New Issue
Block a user