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 <sys/stat.h>
|
||||||
|
|
||||||
#include "include/v8-extension.h"
|
#include "include/v8-extension.h"
|
||||||
|
#include "include/v8-fast-api-calls.h"
|
||||||
#include "include/v8-function.h"
|
#include "include/v8-function.h"
|
||||||
#include "include/v8-locker.h"
|
#include "include/v8-locker.h"
|
||||||
#include "src/api/api-inl.h"
|
#include "src/api/api-inl.h"
|
||||||
@ -3102,6 +3103,160 @@ UNINITIALIZED_TEST(SnapshotCreatorShortExternalReferences) {
|
|||||||
FreeCurrentEmbeddedBlob();
|
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::StartupData CreateSnapshotWithDefaultAndCustom() {
|
||||||
v8::SnapshotCreator creator(original_external_references);
|
v8::SnapshotCreator creator(original_external_references);
|
||||||
v8::Isolate* isolate = creator.GetIsolate();
|
v8::Isolate* isolate = creator.GetIsolate();
|
||||||
|
Loading…
Reference in New Issue
Block a user