v8/test/unittests/api/v8-object-unittest.cc
Dan Elphick ec06bb6ce5 Reland "[include] Split out v8.h"
This is a reland of d1b27019d3

Fixes include:
Adding missing file to bazel build
Forward-declaring classing before friend-classing them to fix win/gcc
Add missing v8-isolate.h include for vtune builds

Original change's description:
> [include] Split out v8.h
>
> This moves every single class/function out of include/v8.h into a
> separate header in include/, which v8.h then includes so that
> externally nothing appears to have changed.
>
> Every include of v8.h from inside v8 has been changed to a more
> fine-grained include.
>
> Previously inline functions defined at the bottom of v8.h would call
> private non-inline functions in the V8 class. Since that class is now
> in v8-initialization.h and is rarely included (as that would create
> dependency cycles), this is not possible and so those methods have been
> moved out of the V8 class into the namespace v8::api_internal.
>
> None of the previous files in include/ now #include v8.h, which means
> if embedders were relying on this transitive dependency then it will
> give compile failures.
>
> v8-inspector.h does depend on v8-scripts.h for the time being to ensure
> that Chrome continue to compile but that change will be reverted once
> those transitive #includes in chrome are changed to include it directly.
>
> Full design:
> https://docs.google.com/document/d/1rTD--I8hCAr-Rho1WTumZzFKaDpEp0IJ8ejZtk4nJdA/edit?usp=sharing
>
> Bug: v8:11965
> Change-Id: I53b84b29581632710edc80eb11f819c2097a2877
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3097448
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Commit-Queue: Dan Elphick <delphick@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#76424}

Cq-Include-Trybots: luci.v8.try:v8_linux_vtunejit
Bug: v8:11965
Change-Id: I99f5d3a73bf8fe25b650adfaf9567dc4e44a09e6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3113629
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Commit-Queue: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76460}
2021-08-24 13:08:55 +00:00

218 lines
8.5 KiB
C++

// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/v8-context.h"
#include "include/v8-function.h"
#include "include/v8-isolate.h"
#include "include/v8-local-handle.h"
#include "include/v8-primitive.h"
#include "include/v8-template.h"
#include "src/api/api.h"
#include "src/objects/objects-inl.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace {
using ObjectTest = TestWithContext;
void accessor_name_getter_callback(Local<Name>,
const PropertyCallbackInfo<Value>&) {}
TEST_F(ObjectTest, SetAccessorWhenUnconfigurablePropAlreadyDefined) {
TryCatch try_catch(isolate());
Local<Object> global = context()->Global();
Local<String> property_name = String::NewFromUtf8Literal(isolate(), "foo");
PropertyDescriptor prop_desc;
prop_desc.set_configurable(false);
global->DefineProperty(context(), property_name, prop_desc).ToChecked();
Maybe<bool> result = global->SetAccessor(context(), property_name,
accessor_name_getter_callback);
ASSERT_TRUE(result.IsJust());
ASSERT_FALSE(result.FromJust());
ASSERT_FALSE(try_catch.HasCaught());
}
using LapContextTest = TestWithIsolate;
TEST_F(LapContextTest, CurrentContextInLazyAccessorOnPrototype) {
// The receiver object is created in |receiver_context|, but its prototype
// object is created in |prototype_context|, and the property is accessed
// from |caller_context|.
Local<Context> receiver_context = Context::New(isolate());
Local<Context> prototype_context = Context::New(isolate());
Local<Context> caller_context = Context::New(isolate());
static int call_count; // The number of calls of the accessor callback.
call_count = 0;
Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
Local<Signature> signature = Signature::New(isolate(), function_template);
Local<String> property_key =
String::NewFromUtf8Literal(isolate(), "property");
Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
isolate(),
[](const FunctionCallbackInfo<Value>& info) {
++call_count;
Local<Context> prototype_context = *reinterpret_cast<Local<Context>*>(
info.Data().As<External>()->Value());
EXPECT_EQ(prototype_context, info.GetIsolate()->GetCurrentContext());
},
External::New(isolate(), &prototype_context), signature);
function_template->PrototypeTemplate()->SetAccessorProperty(
property_key, get_or_set, get_or_set);
// |object| is created in |receiver_context|, and |prototype| is created
// in |prototype_context|. And then, object.__proto__ = prototype.
Local<Function> interface_for_receiver =
function_template->GetFunction(receiver_context).ToLocalChecked();
Local<Function> interface_for_prototype =
function_template->GetFunction(prototype_context).ToLocalChecked();
Local<String> prototype_key =
String::NewFromUtf8Literal(isolate(), "prototype");
Local<Object> prototype =
interface_for_prototype->Get(caller_context, prototype_key)
.ToLocalChecked()
.As<Object>();
Local<Object> object =
interface_for_receiver->NewInstance(receiver_context).ToLocalChecked();
object->SetPrototype(caller_context, prototype).ToChecked();
EXPECT_EQ(receiver_context, object->GetCreationContext().ToLocalChecked());
EXPECT_EQ(prototype_context,
prototype->GetCreationContext().ToLocalChecked());
EXPECT_EQ(0, call_count);
object->Get(caller_context, property_key).ToLocalChecked();
EXPECT_EQ(1, call_count);
object->Set(caller_context, property_key, Null(isolate())).ToChecked();
EXPECT_EQ(2, call_count);
// Test with a compiled version.
Local<String> object_key = String::NewFromUtf8Literal(isolate(), "object");
caller_context->Global()->Set(caller_context, object_key, object).ToChecked();
const char script[] =
"function f() { object.property; object.property = 0; } "
"%PrepareFunctionForOptimization(f); "
"f(); f(); "
"%OptimizeFunctionOnNextCall(f); "
"f();";
Context::Scope scope(caller_context);
internal::FLAG_allow_natives_syntax = true;
Script::Compile(caller_context, String::NewFromUtf8Literal(isolate(), script))
.ToLocalChecked()
->Run(caller_context)
.ToLocalChecked();
EXPECT_EQ(8, call_count);
}
TEST_F(LapContextTest, CurrentContextInLazyAccessorOnPlatformObject) {
Local<Context> receiver_context = Context::New(isolate());
Local<Context> caller_context = Context::New(isolate());
static int call_count; // The number of calls of the accessor callback.
call_count = 0;
Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
Local<Signature> signature = Signature::New(isolate(), function_template);
Local<String> property_key =
String::NewFromUtf8Literal(isolate(), "property");
Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
isolate(),
[](const FunctionCallbackInfo<Value>& info) {
++call_count;
Local<Context> receiver_context = *reinterpret_cast<Local<Context>*>(
info.Data().As<External>()->Value());
EXPECT_EQ(receiver_context, info.GetIsolate()->GetCurrentContext());
},
External::New(isolate(), &receiver_context), signature);
function_template->InstanceTemplate()->SetAccessorProperty(
property_key, get_or_set, get_or_set);
Local<Function> interface =
function_template->GetFunction(receiver_context).ToLocalChecked();
Local<Object> object =
interface->NewInstance(receiver_context).ToLocalChecked();
EXPECT_EQ(0, call_count);
object->Get(caller_context, property_key).ToLocalChecked();
EXPECT_EQ(1, call_count);
object->Set(caller_context, property_key, Null(isolate())).ToChecked();
EXPECT_EQ(2, call_count);
// Test with a compiled version.
Local<String> object_key = String::NewFromUtf8Literal(isolate(), "object");
caller_context->Global()->Set(caller_context, object_key, object).ToChecked();
const char script[] =
"function f() { object.property; object.property = 0; } "
"%PrepareFunctionForOptimization(f);"
"f(); f(); "
"%OptimizeFunctionOnNextCall(f); "
"f();";
Context::Scope scope(caller_context);
internal::FLAG_allow_natives_syntax = true;
Script::Compile(caller_context, String::NewFromUtf8Literal(isolate(), script))
.ToLocalChecked()
->Run(caller_context)
.ToLocalChecked();
EXPECT_EQ(8, call_count);
}
TEST_F(LapContextTest, CurrentContextInLazyAccessorOnInterface) {
Local<Context> interface_context = Context::New(isolate());
Local<Context> caller_context = Context::New(isolate());
static int call_count; // The number of calls of the accessor callback.
call_count = 0;
Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate());
Local<String> property_key =
String::NewFromUtf8Literal(isolate(), "property");
Local<FunctionTemplate> get_or_set = FunctionTemplate::New(
isolate(),
[](const FunctionCallbackInfo<Value>& info) {
++call_count;
Local<Context> interface_context = *reinterpret_cast<Local<Context>*>(
info.Data().As<External>()->Value());
EXPECT_EQ(interface_context, info.GetIsolate()->GetCurrentContext());
},
External::New(isolate(), &interface_context), Local<Signature>());
function_template->SetAccessorProperty(property_key, get_or_set, get_or_set);
Local<Function> interface =
function_template->GetFunction(interface_context).ToLocalChecked();
EXPECT_EQ(0, call_count);
interface->Get(caller_context, property_key).ToLocalChecked();
EXPECT_EQ(1, call_count);
interface->Set(caller_context, property_key, Null(isolate())).ToChecked();
EXPECT_EQ(2, call_count);
// Test with a compiled version.
Local<String> interface_key =
String::NewFromUtf8Literal(isolate(), "Interface");
caller_context->Global()
->Set(caller_context, interface_key, interface)
.ToChecked();
const char script[] =
"function f() { Interface.property; Interface.property = 0; } "
"%PrepareFunctionForOptimization(f);"
"f(); f(); "
"%OptimizeFunctionOnNextCall(f); "
"f();";
Context::Scope scope(caller_context);
internal::FLAG_allow_natives_syntax = true;
Script::Compile(caller_context, String::NewFromUtf8Literal(isolate(), script))
.ToLocalChecked()
->Run(caller_context)
.ToLocalChecked();
EXPECT_EQ(8, call_count);
}
} // namespace
} // namespace v8