Revert "[fastcall] Add support for leaf interface type checks"

This reverts commit 6124a534b2.

Reason for revert: On suspicion of blocking V8 roll: https://ci.chromium.org/ui/p/chromium/builders/try/win10_chromium_x64_rel_ng/839568/overview

Original change's description:
> [fastcall] Add support for leaf interface type checks
>
> This CL adds an IsTemplateForApiObject method to FunctionTemplate
> allowing the embedder to check whether a given API object was
> instantiated by this template without including parent templates
> in the search. It also replaces the v8::ApiObject in the fast API
> with a raw v8::Value pointer to allow use of standard C++ casts.
>
> Bug: chromium:1052746
> Change-Id: I0812ec8b4daaa5f5005aabf10b63e1e84e0b8f03
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2595310
> Commit-Queue: Maya Lekova <mslekova@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Sathya Gunasekaran  <gsathya@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73999}

Bug: chromium:1052746
Change-Id: Ic99ec616310f0f75800c3dad393b5d2d685b76ab
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2829988
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/master@{#74016}
This commit is contained in:
Shu-yu Guo 2021-04-16 21:33:46 +00:00 committed by Commit Bot
parent 7564f6584e
commit 194672378b
14 changed files with 86 additions and 423 deletions

View File

@ -70,8 +70,8 @@
* return GetInternalField<CustomEmbedderType, * return GetInternalField<CustomEmbedderType,
* kV8EmbedderWrapperObjectIndex>(wrapper); * kV8EmbedderWrapperObjectIndex>(wrapper);
* } * }
* static void FastMethod(v8::Value* receiver_obj, int param) { * static void FastMethod(v8::ApiObject receiver_obj, int param) {
* v8::Object* v8_object = v8::Object::Cast(receiver_obj); * v8::Object* v8_object = reinterpret_cast<v8::Object*>(&api_object);
* CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>( * CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>(
* receiver_obj->GetAlignedPointerFromInternalField( * receiver_obj->GetAlignedPointerFromInternalField(
* kV8EmbedderWrapperObjectIndex)); * kV8EmbedderWrapperObjectIndex));
@ -190,7 +190,6 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include "v8.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory) #include "v8config.h" // NOLINT(build/include_directory)
namespace v8 { namespace v8 {
@ -313,7 +312,7 @@ class V8_EXPORT CFunction {
}; };
}; };
struct V8_DEPRECATE_SOON("Use v8::Value* instead.") ApiObject { struct ApiObject {
uintptr_t address; uintptr_t address;
}; };
@ -347,12 +346,8 @@ struct FastApiCallbackOptions {
/** /**
* The `data` passed to the FunctionTemplate constructor, or `undefined`. * The `data` passed to the FunctionTemplate constructor, or `undefined`.
* `data_ptr` allows for default constructing FastApiCallbackOptions.
*/ */
union { const ApiObject data;
uintptr_t data_ptr;
v8::Value data;
};
}; };
namespace internal { namespace internal {
@ -422,11 +417,7 @@ struct TypeInfoHelper {
V(uint64_t, kUint64) \ V(uint64_t, kUint64) \
V(float, kFloat32) \ V(float, kFloat32) \
V(double, kFloat64) \ V(double, kFloat64) \
V(ApiObject, kV8Value) \ V(ApiObject, kV8Value)
V(v8::Value*, kV8Value)
// ApiObject was a temporary solution to wrap the pointer to the v8::Value.
// Please use v8::Value* in new code, as ApiObject will be deprecated soon.
BASIC_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR) BASIC_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR)

View File

@ -6590,15 +6590,6 @@ class V8_EXPORT FunctionTemplate : public Template {
*/ */
bool HasInstance(Local<Value> object); bool HasInstance(Local<Value> object);
/**
* Returns true if the given value is an API object that was constructed by an
* instance of this function template (without checking for inheriting
* function templates).
*
* This is an experimental feature and may still change significantly.
*/
bool IsLeafTemplateForApiObject(Value* value) const;
V8_INLINE static FunctionTemplate* Cast(Data* data); V8_INLINE static FunctionTemplate* Cast(Data* data);
private: private:

View File

@ -6399,15 +6399,6 @@ bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
return false; return false;
} }
bool FunctionTemplate::IsLeafTemplateForApiObject(v8::Value* value) const {
i::DisallowGarbageCollection no_gc;
i::Object object = *Utils::OpenHandle(value);
auto self = Utils::OpenHandle(this);
return self->IsLeafTemplateForApiObject(object);
}
Local<External> v8::External::New(Isolate* isolate, void* value) { Local<External> v8::External::New(Isolate* isolate, void* value) {
STATIC_ASSERT(sizeof(value) == sizeof(i::Address)); STATIC_ASSERT(sizeof(value) == sizeof(i::Address));
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);

View File

@ -193,7 +193,6 @@ class EffectControlLinearizer {
void LowerTransitionElementsKind(Node* node); void LowerTransitionElementsKind(Node* node);
Node* LowerLoadFieldByIndex(Node* node); Node* LowerLoadFieldByIndex(Node* node);
Node* LowerLoadMessage(Node* node); Node* LowerLoadMessage(Node* node);
Node* AdaptFastCallArgument(Node* node, CTypeInfo::Type arg_type);
Node* LowerFastApiCall(Node* node); Node* LowerFastApiCall(Node* node);
Node* LowerLoadTypedElement(Node* node); Node* LowerLoadTypedElement(Node* node);
Node* LowerLoadDataViewElement(Node* node); Node* LowerLoadDataViewElement(Node* node);
@ -4976,8 +4975,7 @@ void EffectControlLinearizer::LowerStoreMessage(Node* node) {
__ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern); __ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern);
} }
namespace { static MachineType MachineTypeFor(CTypeInfo::Type type) {
MachineType MachineTypeFor(CTypeInfo::Type type) {
switch (type) { switch (type) {
case CTypeInfo::Type::kVoid: case CTypeInfo::Type::kVoid:
return MachineType::AnyTagged(); return MachineType::AnyTagged();
@ -4999,30 +4997,6 @@ MachineType MachineTypeFor(CTypeInfo::Type type) {
return MachineType::AnyTagged(); return MachineType::AnyTagged();
} }
} }
} // namespace
Node* EffectControlLinearizer::AdaptFastCallArgument(Node* node,
CTypeInfo::Type arg_type) {
switch (arg_type) {
case CTypeInfo::Type::kV8Value: {
int kAlign = alignof(uintptr_t);
int kSize = sizeof(uintptr_t);
Node* stack_slot = __ StackSlot(kSize, kAlign);
__ Store(StoreRepresentation(MachineType::PointerRepresentation(),
kNoWriteBarrier),
stack_slot, 0, node);
return stack_slot;
}
case CTypeInfo::Type::kFloat32: {
return __ TruncateFloat64ToFloat32(node);
}
default: {
return node;
}
}
}
Node* EffectControlLinearizer::LowerFastApiCall(Node* node) { Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
FastApiCallNode n(node); FastApiCallNode n(node);
@ -5087,9 +5061,13 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
inputs[0] = n.target(); inputs[0] = n.target();
for (int i = FastApiCallNode::kFastTargetInputCount; for (int i = FastApiCallNode::kFastTargetInputCount;
i < c_arg_count + FastApiCallNode::kFastTargetInputCount; ++i) { i < c_arg_count + FastApiCallNode::kFastTargetInputCount; ++i) {
inputs[i] = if (c_signature->ArgumentInfo(i - 1).GetType() ==
AdaptFastCallArgument(NodeProperties::GetValueInput(node, i), CTypeInfo::Type::kFloat32) {
c_signature->ArgumentInfo(i - 1).GetType()); inputs[i] =
__ TruncateFloat64ToFloat32(NodeProperties::GetValueInput(node, i));
} else {
inputs[i] = NodeProperties::GetValueInput(node, i);
}
} }
if (c_signature->HasOptions()) { if (c_signature->HasOptions()) {
inputs[c_arg_count + 1] = stack_slot; inputs[c_arg_count + 1] = stack_slot;

View File

@ -21,18 +21,16 @@
namespace v8 { namespace v8 {
namespace { namespace {
thread_local Persistent<FunctionTemplate> api_obj_ctor;
class FastCApiObject { class FastCApiObject {
public: public:
static double AddAllFastCallback(v8::Value* receiver, bool should_fallback, static double AddAllFastCallback(ApiObject receiver, bool should_fallback,
int32_t arg_i32, uint32_t arg_u32, int32_t arg_i32, uint32_t arg_u32,
int64_t arg_i64, uint64_t arg_u64, int64_t arg_i64, uint64_t arg_u64,
float arg_f32, double arg_f64, float arg_f32, double arg_f64,
FastApiCallbackOptions& options) { FastApiCallbackOptions& options) {
CHECK(receiver->IsObject()); Value* receiver_value = reinterpret_cast<Value*>(&receiver);
FastCApiObject* self = UnwrapObject(Object::Cast(receiver)); CHECK(receiver_value->IsObject());
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
self->fast_call_count_++; self->fast_call_count_++;
if (should_fallback) { if (should_fallback) {
@ -79,11 +77,12 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum)); args.GetReturnValue().Set(Number::New(isolate, sum));
} }
static int Add32BitIntFastCallback(v8::Value* receiver, bool should_fallback, static int Add32BitIntFastCallback(ApiObject receiver, bool should_fallback,
int32_t arg_i32, uint32_t arg_u32, int32_t arg_i32, uint32_t arg_u32,
FastApiCallbackOptions& options) { FastApiCallbackOptions& options) {
CHECK(receiver->IsObject()); Value* receiver_value = reinterpret_cast<Value*>(&receiver);
FastCApiObject* self = UnwrapObject(Object::Cast(receiver)); CHECK(receiver_value->IsObject());
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
self->fast_call_count_++; self->fast_call_count_++;
if (should_fallback) { if (should_fallback) {
@ -112,55 +111,6 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum)); args.GetReturnValue().Set(Number::New(isolate, sum));
} }
static bool IsFastCApiObjectFastCallback(v8::Value* receiver,
bool should_fallback, v8::Value* arg,
FastApiCallbackOptions& options) {
CHECK(receiver->IsObject());
FastCApiObject* self = UnwrapObject(Object::Cast(receiver));
self->fast_call_count_++;
if (should_fallback) {
options.fallback = 1;
return false;
}
Object* object = Object::Cast(arg);
if (!IsValidApiObject(object)) return false;
internal::Isolate* i_isolate =
internal::IsolateFromNeverReadOnlySpaceObject(
*reinterpret_cast<internal::Address*>(object));
CHECK_NOT_NULL(i_isolate);
Isolate* isolate = reinterpret_cast<Isolate*>(i_isolate);
HandleScope handle_scope(isolate);
return api_obj_ctor.Get(isolate)->IsLeafTemplateForApiObject(object);
}
static void IsFastCApiObjectSlowCallback(
const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
FastCApiObject* self = UnwrapObject(*args.This());
self->slow_call_count_++;
HandleScope handle_scope(isolate);
bool result = false;
if (args.Length() < 2) {
args.GetIsolate()->ThrowError(
"is_valid_api_object should be called with 2 arguments");
return;
}
Object* object = Object::Cast(*args[1]);
if (!IsValidApiObject(object)) {
result = false;
} else {
result = api_obj_ctor.Get(args.GetIsolate())
->IsLeafTemplateForApiObject(object);
}
args.GetReturnValue().Set(Boolean::New(isolate, result));
}
static void FastCallCount(const FunctionCallbackInfo<Value>& args) { static void FastCallCount(const FunctionCallbackInfo<Value>& args) {
FastCApiObject* self = UnwrapObject(*args.This()); FastCApiObject* self = UnwrapObject(*args.This());
args.GetReturnValue().Set( args.GetReturnValue().Set(
@ -191,14 +141,12 @@ class FastCApiObject {
static const int kV8WrapperObjectIndex = 1; static const int kV8WrapperObjectIndex = 1;
private: private:
static bool IsValidApiObject(Object* object) { static FastCApiObject* UnwrapObject(Object* object) {
i::Address addr = *reinterpret_cast<i::Address*>(object); i::Address addr = *reinterpret_cast<i::Address*>(object);
auto instance_type = i::Internals::GetInstanceType(addr); auto instance_type = i::Internals::GetInstanceType(addr);
return (instance_type == i::Internals::kJSApiObjectType || if (instance_type != i::Internals::kJSObjectType &&
instance_type == i::Internals::kJSSpecialApiObjectType); instance_type != i::Internals::kJSApiObjectType &&
} instance_type != i::Internals::kJSSpecialApiObjectType) {
static FastCApiObject* UnwrapObject(Object* object) {
if (!IsValidApiObject(object)) {
return nullptr; return nullptr;
} }
FastCApiObject* wrapped = reinterpret_cast<FastCApiObject*>( FastCApiObject* wrapped = reinterpret_cast<FastCApiObject*>(
@ -219,7 +167,8 @@ class FastCApiObject {
thread_local FastCApiObject kFastCApiObject; thread_local FastCApiObject kFastCApiObject;
} // namespace } // namespace
void CreateFastCAPIObject(const FunctionCallbackInfo<Value>& info) { // TODO(mslekova): Rename the fast_c_api helper to FastCAPI.
void CreateObject(const FunctionCallbackInfo<Value>& info) {
if (!info.IsConstructCall()) { if (!info.IsConstructCall()) {
info.GetIsolate()->ThrowError( info.GetIsolate()->ThrowError(
"FastCAPI helper must be constructed with new."); "FastCAPI helper must be constructed with new.");
@ -237,14 +186,13 @@ void CreateFastCAPIObject(const FunctionCallbackInfo<Value>& info) {
} }
Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) { Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
api_obj_ctor.Reset(isolate, Local<FunctionTemplate> api_obj_ctor =
FunctionTemplate::New(isolate, CreateFastCAPIObject)); FunctionTemplate::New(isolate, CreateObject);
Local<Signature> signature = Local<Signature> signature = Signature::New(isolate, api_obj_ctor);
Signature::New(isolate, api_obj_ctor.Get(isolate));
{ {
CFunction add_all_c_func = CFunction add_all_c_func =
CFunction::Make(FastCApiObject::AddAllFastCallback); CFunction::Make(FastCApiObject::AddAllFastCallback);
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set( api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all", isolate, "add_all",
FunctionTemplate::New(isolate, FastCApiObject::AddAllSlowCallback, FunctionTemplate::New(isolate, FastCApiObject::AddAllSlowCallback,
Local<Value>(), signature, 1, Local<Value>(), signature, 1,
@ -252,53 +200,29 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
SideEffectType::kHasSideEffect, &add_all_c_func)); SideEffectType::kHasSideEffect, &add_all_c_func));
CFunction add_32bit_int_c_func = CFunction add_32bit_int_c_func =
CFunction::Make(FastCApiObject::Add32BitIntFastCallback); CFunction::Make(FastCApiObject::Add32BitIntFastCallback);
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set( api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_32bit_int", isolate, "add_32bit_int",
FunctionTemplate::New( FunctionTemplate::New(
isolate, FastCApiObject::Add32BitIntSlowCallback, Local<Value>(), isolate, FastCApiObject::Add32BitIntSlowCallback, Local<Value>(),
signature, 1, ConstructorBehavior::kThrow, signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_32bit_int_c_func)); SideEffectType::kHasSideEffect, &add_32bit_int_c_func));
CFunction is_valid_api_object_c_func = api_obj_ctor->PrototypeTemplate()->Set(
CFunction::Make(FastCApiObject::IsFastCApiObjectFastCallback);
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
isolate, "is_fast_c_api_object",
FunctionTemplate::New(
isolate, FastCApiObject::IsFastCApiObjectSlowCallback,
Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &is_valid_api_object_c_func));
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
isolate, "fast_call_count", isolate, "fast_call_count",
FunctionTemplate::New(isolate, FastCApiObject::FastCallCount, FunctionTemplate::New(isolate, FastCApiObject::FastCallCount,
Local<Value>(), signature)); Local<Value>(), signature));
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set( api_obj_ctor->PrototypeTemplate()->Set(
isolate, "slow_call_count", isolate, "slow_call_count",
FunctionTemplate::New(isolate, FastCApiObject::SlowCallCount, FunctionTemplate::New(isolate, FastCApiObject::SlowCallCount,
Local<Value>(), signature)); Local<Value>(), signature));
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set( api_obj_ctor->PrototypeTemplate()->Set(
isolate, "reset_counts", isolate, "reset_counts",
FunctionTemplate::New(isolate, FastCApiObject::ResetCounts, FunctionTemplate::New(isolate, FastCApiObject::ResetCounts,
Local<Value>(), signature)); Local<Value>(), signature));
} }
api_obj_ctor.Get(isolate)->InstanceTemplate()->SetInternalFieldCount( api_obj_ctor->InstanceTemplate()->SetInternalFieldCount(
FastCApiObject::kV8WrapperObjectIndex + 1); FastCApiObject::kV8WrapperObjectIndex + 1);
return api_obj_ctor.Get(isolate); return api_obj_ctor;
}
void CreateLeafInterfaceObject(const FunctionCallbackInfo<Value>& info) {
if (!info.IsConstructCall()) {
info.GetIsolate()->ThrowError(
"LeafInterfaceType helper must be constructed with new.");
}
}
Local<FunctionTemplate> Shell::CreateLeafInterfaceTypeTemplate(
Isolate* isolate) {
Local<FunctionTemplate> leaf_object_ctor =
FunctionTemplate::New(isolate, CreateLeafInterfaceObject);
leaf_object_ctor->SetClassName(
String::NewFromUtf8Literal(isolate, "LeafInterfaceType"));
return leaf_object_ctor;
} }
} // namespace v8 } // namespace v8

View File

@ -2733,10 +2733,8 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
// constructor when --correctness_fuzzer_suppressions is on. // constructor when --correctness_fuzzer_suppressions is on.
if (i::FLAG_turbo_fast_api_calls && if (i::FLAG_turbo_fast_api_calls &&
!i::FLAG_correctness_fuzzer_suppressions) { !i::FLAG_correctness_fuzzer_suppressions) {
test_template->Set(isolate, "FastCAPI", test_template->Set(isolate, "fast_c_api",
Shell::CreateTestFastCApiTemplate(isolate)); Shell::CreateTestFastCApiTemplate(isolate));
test_template->Set(isolate, "LeafInterfaceType",
Shell::CreateLeafInterfaceTypeTemplate(isolate));
} }
d8_template->Set(isolate, "test", test_template); d8_template->Set(isolate, "test", test_template);

View File

@ -635,8 +635,6 @@ class Shell : public i::AllStatic {
static Local<ObjectTemplate> CreateRealmTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateRealmTemplate(Isolate* isolate);
static Local<ObjectTemplate> CreateD8Template(Isolate* isolate); static Local<ObjectTemplate> CreateD8Template(Isolate* isolate);
static Local<FunctionTemplate> CreateTestFastCApiTemplate(Isolate* isolate); static Local<FunctionTemplate> CreateTestFastCApiTemplate(Isolate* isolate);
static Local<FunctionTemplate> CreateLeafInterfaceTypeTemplate(
Isolate* isolate);
static MaybeLocal<Context> CreateRealm( static MaybeLocal<Context> CreateRealm(
const v8::FunctionCallbackInfo<v8::Value>& args, int index, const v8::FunctionCallbackInfo<v8::Value>& args, int index,

View File

@ -1319,7 +1319,7 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
return result; return result;
} }
bool FunctionTemplateInfo::IsTemplateFor(Map map) const { bool FunctionTemplateInfo::IsTemplateFor(Map map) {
RCS_SCOPE( RCS_SCOPE(
LocalHeap::Current() == nullptr LocalHeap::Current() == nullptr
? GetIsolate()->counters()->runtime_call_stats() ? GetIsolate()->counters()->runtime_call_stats()
@ -1349,26 +1349,6 @@ bool FunctionTemplateInfo::IsTemplateFor(Map map) const {
return false; return false;
} }
bool FunctionTemplateInfo::IsLeafTemplateForApiObject(Object object) const {
i::DisallowGarbageCollection no_gc;
if (!object.IsJSApiObject()) {
return false;
}
bool result = false;
Map map = HeapObject::cast(object).map();
Object constructor_obj = map.GetConstructor();
if (constructor_obj.IsJSFunction()) {
JSFunction fun = JSFunction::cast(constructor_obj);
result = (*this == fun.shared().function_data(kAcquireLoad));
} else if (constructor_obj.IsFunctionTemplateInfo()) {
result = (*this == constructor_obj);
}
DCHECK_IMPLIES(result, IsTemplateFor(map));
return result;
}
// static // static
FunctionTemplateRareData FunctionTemplateInfo::AllocateFunctionTemplateRareData( FunctionTemplateRareData FunctionTemplateInfo::AllocateFunctionTemplateRareData(
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) { Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {

View File

@ -150,11 +150,7 @@ class FunctionTemplateInfo
inline FunctionTemplateInfo GetParent(Isolate* isolate); inline FunctionTemplateInfo GetParent(Isolate* isolate);
// Returns true if |object| is an instance of this function template. // Returns true if |object| is an instance of this function template.
inline bool IsTemplateFor(JSObject object); inline bool IsTemplateFor(JSObject object);
bool IsTemplateFor(Map map) const; bool IsTemplateFor(Map map);
// Returns true if |object| is an API object and is constructed by this
// particular function template (skips walking up the chain of inheriting
// functions that is done by IsTemplateFor).
bool IsLeafTemplateForApiObject(Object object) const;
inline bool instantiated(); inline bool instantiated();
inline bool BreakAtEntry(); inline bool BreakAtEntry();

View File

@ -842,11 +842,11 @@ DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags)
bool IsValidUnwrapObject(v8::Object* object); bool IsValidUnwrapObject(v8::Object* object);
template <typename T> template <typename T, int offset>
T* GetInternalField(v8::Object* wrapper) { T* GetInternalField(v8::Object* wrapper) {
assert(kV8WrapperObjectIndex < wrapper->InternalFieldCount()); assert(offset < wrapper->InternalFieldCount());
return reinterpret_cast<T*>( return reinterpret_cast<T*>(
wrapper->GetAlignedPointerFromInternalField(kV8WrapperObjectIndex)); wrapper->GetAlignedPointerFromInternalField(offset));
} }
#endif // ifndef CCTEST_H_ #endif // ifndef CCTEST_H_

View File

@ -20789,56 +20789,6 @@ THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
CheckInstanceCheckedAccessors(true); CheckInstanceCheckedAccessors(true);
} }
THREADED_TEST(CheckIsLeafTemplateForApiObject) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
CHECK(context->Global()
->Set(context.local(), v8_str("f"),
templ->GetFunction(context.local()).ToLocalChecked())
.FromJust());
printf("Testing positive ...\n");
CompileRun("var obj = new f();");
CHECK(templ->IsLeafTemplateForApiObject(
*context->Global()
->Get(context.local(), v8_str("obj"))
.ToLocalChecked()));
printf("Testing negative ...\n");
CompileRun(
"var obj = {};"
"obj.__proto__ = new f();");
CHECK(!templ->IsLeafTemplateForApiObject(
*context->Global()
->Get(context.local(), v8_str("obj"))
.ToLocalChecked()));
printf("Testing positive with modified prototype chain ...\n");
CompileRun(
"var obj = new f();"
"var pro = {};"
"pro.__proto__ = obj.__proto__;"
"obj.__proto__ = pro;");
CHECK(templ->IsLeafTemplateForApiObject(
*context->Global()
->Get(context.local(), v8_str("obj"))
.ToLocalChecked()));
Local<FunctionTemplate> child_templ =
FunctionTemplate::New(context->GetIsolate());
child_templ->Inherit(templ);
Local<Object> instance = child_templ->GetFunction(context.local())
.ToLocalChecked()
->NewInstance(context.local())
.ToLocalChecked();
printf("Testing positive for child ...\n");
CHECK(child_templ->IsLeafTemplateForApiObject(*instance));
printf("Testing negative for parent ...\n");
CHECK(!templ->IsLeafTemplateForApiObject(*instance));
}
TEST(TryFinallyMessage) { TEST(TryFinallyMessage) {
LocalContext context; LocalContext context;
@ -27676,15 +27626,14 @@ namespace {
template <typename Value, typename Impl, typename Ret> template <typename Value, typename Impl, typename Ret>
struct BasicApiChecker { struct BasicApiChecker {
static Ret FastCallback(v8::Value* receiver, Value argument, static Ret FastCallback(v8::ApiObject receiver, Value argument,
v8::FastApiCallbackOptions& options) { v8::FastApiCallbackOptions& options) {
// TODO(mslekova): Refactor the data checking. const v8::Value* data = reinterpret_cast<const v8::Value*>(&options.data);
v8::Value* data = &(options.data);
CHECK(data->IsNumber()); CHECK(data->IsNumber());
CHECK_EQ(v8::Number::Cast(data)->Value(), 42.0); CHECK_EQ(reinterpret_cast<const v8::Number*>(data)->Value(), 42.0);
return Impl::FastCallback(receiver, argument, options); return Impl::FastCallback(receiver, argument, options);
} }
static Ret FastCallbackNoFallback(v8::Value* receiver, Value argument) { static Ret FastCallbackNoFallback(v8::ApiObject receiver, Value argument) {
v8::FastApiCallbackOptions options = {false, {0}}; v8::FastApiCallbackOptions options = {false, {0}};
return Impl::FastCallback(receiver, argument, options); return Impl::FastCallback(receiver, argument, options);
} }
@ -27695,12 +27644,6 @@ struct BasicApiChecker {
bool DidCallFast() const { return (result_ & ApiCheckerResult::kFastCalled); } bool DidCallFast() const { return (result_ & ApiCheckerResult::kFastCalled); }
bool DidCallSlow() const { return (result_ & ApiCheckerResult::kSlowCalled); } bool DidCallSlow() const { return (result_ & ApiCheckerResult::kSlowCalled); }
void SetCallFast() { result_ |= ApiCheckerResult::kFastCalled; }
void SetCallSlow() { result_ |= ApiCheckerResult::kSlowCalled; }
void Reset() { result_ = ApiCheckerResult::kNotCalled; }
private:
ApiCheckerResultFlags result_ = ApiCheckerResult::kNotCalled; ApiCheckerResultFlags result_ = ApiCheckerResult::kNotCalled;
}; };
@ -27725,16 +27668,17 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>, void> {
write_to_fallback_(write_to_fallback), write_to_fallback_(write_to_fallback),
args_count_(args_count) {} args_count_(args_count) {}
static void FastCallback(v8::Value* receiver, T argument, static void FastCallback(v8::ApiObject receiver, T argument,
v8::FastApiCallbackOptions& options) { v8::FastApiCallbackOptions& options) {
v8::Object* receiver_obj = v8::Object::Cast(receiver); v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
if (!IsValidUnwrapObject(receiver_obj)) { if (!IsValidUnwrapObject(receiver_obj)) {
options.fallback = 1; options.fallback = 1;
return; return;
} }
ApiNumberChecker<T>* receiver_ptr = ApiNumberChecker<T>* receiver_ptr =
GetInternalField<ApiNumberChecker<T>>(receiver_obj); GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(
receiver_ptr->SetCallFast(); receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
receiver_ptr->fast_value_ = argument; receiver_ptr->fast_value_ = argument;
if (receiver_ptr->write_to_fallback_ == FallbackPolicy::kRequestFallback) { if (receiver_ptr->write_to_fallback_ == FallbackPolicy::kRequestFallback) {
// Anything != 0 has the same effect here, but we're writing 1 to match // Anything != 0 has the same effect here, but we're writing 1 to match
@ -27753,10 +27697,10 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>, void> {
return; return;
} }
ApiNumberChecker<T>* checker = ApiNumberChecker<T>* checker =
GetInternalField<ApiNumberChecker<T>>(receiver); GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(receiver);
CHECK_EQ(info.Length(), checker->args_count_); CHECK_EQ(info.Length(), checker->args_count_);
checker->SetCallSlow(); checker->result_ |= ApiCheckerResult::kSlowCalled;
LocalContext env; LocalContext env;
checker->slow_value_ = ConvertJSValue<T>::Get(info[0], env.local()); checker->slow_value_ = ConvertJSValue<T>::Get(info[0], env.local());
@ -27775,15 +27719,17 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>, void> {
}; };
struct UnexpectedObjectChecker struct UnexpectedObjectChecker
: BasicApiChecker<v8::Value*, UnexpectedObjectChecker, void> { : BasicApiChecker<v8::ApiObject, UnexpectedObjectChecker, void> {
static void FastCallback(v8::Value* receiver, v8::Value* argument, static void FastCallback(v8::ApiObject receiver, v8::ApiObject argument,
v8::FastApiCallbackOptions& options) { v8::FastApiCallbackOptions& options) {
v8::Object* receiver_obj = v8::Object::Cast(receiver); v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
UnexpectedObjectChecker* receiver_ptr = UnexpectedObjectChecker* receiver_ptr =
GetInternalField<UnexpectedObjectChecker>(receiver_obj); GetInternalField<UnexpectedObjectChecker, kV8WrapperObjectIndex>(
receiver_ptr->SetCallFast(); receiver_obj);
if (argument->IsObject()) { receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
v8::Object* argument_obj = v8::Object::Cast(argument); v8::Value* argument_value = reinterpret_cast<v8::Value*>(&argument);
if (argument_value->IsObject()) {
v8::Object* argument_obj = reinterpret_cast<v8::Object*>(&argument);
CHECK(!IsValidUnwrapObject(argument_obj)); CHECK(!IsValidUnwrapObject(argument_obj));
} }
} }
@ -27791,8 +27737,9 @@ struct UnexpectedObjectChecker
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder()); v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
UnexpectedObjectChecker* receiver_ptr = UnexpectedObjectChecker* receiver_ptr =
GetInternalField<UnexpectedObjectChecker>(receiver_obj); GetInternalField<UnexpectedObjectChecker, kV8WrapperObjectIndex>(
receiver_ptr->SetCallSlow(); receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kSlowCalled;
if (info[0]->IsObject()) { if (info[0]->IsObject()) {
v8::Object* argument_obj = v8::Object::Cast(*info[0]); v8::Object* argument_obj = v8::Object::Cast(*info[0]);
CHECK(!IsValidUnwrapObject(argument_obj)); CHECK(!IsValidUnwrapObject(argument_obj));
@ -27800,43 +27747,6 @@ struct UnexpectedObjectChecker
} }
}; };
struct EmbedderType {
int data;
};
struct ApiObjectChecker : BasicApiChecker<v8::Value*, ApiObjectChecker, void> {
ApiObjectChecker(v8::FunctionTemplate* ctor, int data)
: ctor_(ctor), initial_data_(data) {}
static void FastCallback(v8::Value* receiver, v8::Value* argument,
v8::FastApiCallbackOptions& options) {
v8::Object* receiver_obj = v8::Object::Cast(receiver);
ApiObjectChecker* receiver_ptr =
GetInternalField<ApiObjectChecker>(receiver_obj);
receiver_ptr->SetCallFast();
v8::Object* argument_obj = v8::Object::Cast(argument);
EmbedderType* argument_ptr = GetInternalField<EmbedderType>(argument_obj);
CHECK(receiver_ptr->ctor_->IsLeafTemplateForApiObject(argument));
argument_ptr->data = receiver_ptr->initial_data_;
}
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
ApiObjectChecker* receiver_ptr =
GetInternalField<ApiObjectChecker>(receiver_obj);
receiver_ptr->SetCallSlow();
CHECK(info[0]->IsObject());
v8::Object* argument_obj = v8::Object::Cast(*info[0]);
CHECK(receiver_ptr->ctor_->IsLeafTemplateForApiObject(argument_obj));
}
v8::FunctionTemplate* ctor_;
int fast_value_ = 0;
int initial_data_;
};
template <typename Value, typename Impl, typename Ret> template <typename Value, typename Impl, typename Ret>
bool SetupTest(v8::Local<v8::Value> initial_value, LocalContext* env, bool SetupTest(v8::Local<v8::Value> initial_value, LocalContext* env,
BasicApiChecker<Value, Impl, Ret>* checker, BasicApiChecker<Value, Impl, Ret>* checker,
@ -27928,7 +27838,7 @@ void CallAndCheck(
"function func(arg) { return receiver.api_func(arg); }" "function func(arg) { return receiver.api_func(arg); }"
"%PrepareFunctionForOptimization(func);" "%PrepareFunctionForOptimization(func);"
"func(value);"); "func(value);");
checker.Reset(); checker.result_ = ApiCheckerResult::kNotCalled;
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::TryCatch try_catch(isolate); v8::TryCatch try_catch(isolate);
@ -27957,58 +27867,24 @@ void CallAndCheck(
} }
} }
void CheckApiObjectArg() {
LocalContext env;
v8::Isolate* isolate = CcTest::isolate();
Local<v8::FunctionTemplate> api_obj_ctor = v8::FunctionTemplate::New(isolate);
v8::Local<v8::ObjectTemplate> api_obj_template =
api_obj_ctor->InstanceTemplate();
api_obj_template->SetInternalFieldCount(kV8WrapperObjectIndex + 1);
EmbedderType embedder_obj;
v8::Local<v8::Object> api_obj =
api_obj_template->NewInstance(env.local()).ToLocalChecked();
api_obj->SetAlignedPointerInInternalField(
kV8WrapperObjectIndex, reinterpret_cast<void*>(&embedder_obj));
CHECK(env->Global()
->Set(env.local(), v8_str("api_object"), api_obj)
.FromJust());
const int data = 42;
ApiObjectChecker checker(*api_obj_ctor, data);
bool has_caught =
SetupTest(v8_num(data), &env, &checker,
"function func() { return receiver.api_func(api_object); }"
"%PrepareFunctionForOptimization(func);"
"func();");
checker.Reset();
CHECK(!has_caught);
CompileRun(
"%OptimizeFunctionOnNextCall(func);"
"func();");
CHECK(checker.DidCallFast());
CHECK_EQ(embedder_obj.data, data);
CHECK(!checker.DidCallSlow());
}
template <typename T> template <typename T>
struct ReturnValueChecker : BasicApiChecker<T, ReturnValueChecker<T>, T> { struct ReturnValueChecker : BasicApiChecker<T, ReturnValueChecker<T>, T> {
static T FastCallback(v8::Value* receiver, T arg, static T FastCallback(v8::ApiObject receiver, T arg,
v8::FastApiCallbackOptions& options) { v8::FastApiCallbackOptions& options) {
v8::Object* receiver_obj = v8::Object::Cast(receiver); v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
ReturnValueChecker<T>* receiver_ptr = ReturnValueChecker<T>* receiver_ptr =
GetInternalField<ReturnValueChecker<T>>(receiver_obj); GetInternalField<ReturnValueChecker<T>, kV8WrapperObjectIndex>(
receiver_ptr->SetCallFast(); receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
return arg; return arg;
} }
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder()); v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
ReturnValueChecker<T>* receiver_ptr = ReturnValueChecker<T>* receiver_ptr =
GetInternalField<ReturnValueChecker<T>>(receiver_obj); GetInternalField<ReturnValueChecker<T>, kV8WrapperObjectIndex>(
receiver_ptr->SetCallSlow(); receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kSlowCalled;
info.GetReturnValue().Set(info[0]); info.GetReturnValue().Set(info[0]);
} }
}; };
@ -28025,7 +27901,7 @@ void CheckFastReturnValue(v8::Local<v8::Value> expected_value,
"%PrepareFunctionForOptimization(func);" "%PrepareFunctionForOptimization(func);"
"func(value);"); "func(value);");
CHECK(!has_caught); CHECK(!has_caught);
checker.Reset(); checker.result_ = ApiCheckerResult::kNotCalled;
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::TryCatch try_catch(isolate); v8::TryCatch try_catch(isolate);
@ -28224,7 +28100,7 @@ TEST(FastApiStackSlot) {
" };" " };"
" return foo;" " return foo;"
"};"); "};");
checker.Reset(); checker.result_ = ApiCheckerResult::kNotCalled;
v8::TryCatch try_catch(isolate); v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> foo = v8::Local<v8::Value> foo =
@ -28700,8 +28576,8 @@ TEST(FastApiCalls) {
CallWithUnexpectedObjectType(v8_str("str")); CallWithUnexpectedObjectType(v8_str("str"));
CallWithUnexpectedObjectType(CompileRun("new Proxy({}, {});")); CallWithUnexpectedObjectType(CompileRun("new Proxy({}, {});"));
CheckApiObjectArg(); // TODO(mslekova): Add corner cases for 64-bit values.
// TODO(mslekova): Add main cases for float and double.
// TODO(mslekova): Restructure the tests so that the fast optimized calls // TODO(mslekova): Restructure the tests so that the fast optimized calls
// are compared against the slow optimized calls. // are compared against the slow optimized calls.
// TODO(mslekova): Add tests for FTI that requires access check. // TODO(mslekova): Add tests for FTI that requires access check.

View File

@ -3934,17 +3934,17 @@ UNINITIALIZED_TEST(DetailedSourcePositionAPI_Inlining) {
namespace { namespace {
struct FastApiReceiver { struct FastApiReceiver {
static void FastCallback(v8::Value* receiver, int argument, static void FastCallback(v8::ApiObject receiver, int argument,
v8::FastApiCallbackOptions& options) { v8::FastApiCallbackOptions& options) {
// TODO(mslekova): The fallback is not used by the test. Replace this // TODO(mslekova): The fallback is not used by the test. Replace this
// with a CHECK. // with a CHECK.
v8::Object* receiver_obj = v8::Object::Cast(receiver); v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
if (!IsValidUnwrapObject(receiver_obj)) { if (!IsValidUnwrapObject(receiver_obj)) {
options.fallback = 1; options.fallback = 1;
return; return;
} }
FastApiReceiver* receiver_ptr = FastApiReceiver* receiver_ptr =
GetInternalField<FastApiReceiver>(receiver_obj); GetInternalField<FastApiReceiver, kV8WrapperObjectIndex>(receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled; receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
@ -3960,7 +3960,8 @@ struct FastApiReceiver {
info.GetIsolate()->ThrowError("Called with a non-object."); info.GetIsolate()->ThrowError("Called with a non-object.");
return; return;
} }
FastApiReceiver* receiver = GetInternalField<FastApiReceiver>(receiver_obj); FastApiReceiver* receiver =
GetInternalField<FastApiReceiver, kV8WrapperObjectIndex>(receiver_obj);
receiver->result_ |= ApiCheckerResult::kSlowCalled; receiver->result_ |= ApiCheckerResult::kSlowCalled;
} }

View File

@ -13,8 +13,8 @@
// it's not suitable for deoptimization fuzzing. // it's not suitable for deoptimization fuzzing.
// Flags: --deopt-every-n-times=0 // Flags: --deopt-every-n-times=0
assertThrows(() => d8.test.FastCAPI()); assertThrows(() => d8.test.fast_c_api());
const fast_c_api = new d8.test.FastCAPI(); const fast_c_api = new d8.test.fast_c_api();
// ----------- add_all ----------- // ----------- add_all -----------
// `add_all` has the following signature: // `add_all` has the following signature:

View File

@ -1,61 +0,0 @@
// Copyright 2021 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.
// This file interface types used with fast API calls.
// Flags: --turbo-fast-api-calls --allow-natives-syntax --opt
// Flags: --no-always-opt
// Flags: --deopt-every-n-times=0
const fast_c_api = new d8.test.FastCAPI();
// We create another API object to avoid migrating the map of fast_c_api
// when using it as a prototype.
const another_fast_c_api = new d8.test.FastCAPI();
function is_fast_c_api_object(obj, should_fallback = false) {
return fast_c_api.is_fast_c_api_object(should_fallback, obj);
}
%PrepareFunctionForOptimization(is_fast_c_api_object);
assertTrue(is_fast_c_api_object(another_fast_c_api));
%OptimizeFunctionOnNextCall(is_fast_c_api_object);
// Test that fast_c_api is an API object wrapping a C++ one.
fast_c_api.reset_counts();
assertTrue(is_fast_c_api_object(another_fast_c_api));
assertOptimized(is_fast_c_api_object);
assertEquals(1, fast_c_api.fast_call_count());
assertEquals(0, fast_c_api.slow_call_count());
// Same test but taking the fallback to the slow path.
fast_c_api.reset_counts();
assertTrue(is_fast_c_api_object(another_fast_c_api, true));
assertOptimized(is_fast_c_api_object);
assertEquals(1, fast_c_api.fast_call_count());
assertEquals(1, fast_c_api.slow_call_count());
// Test that a regular JS object returns false.
fast_c_api.reset_counts();
assertFalse(is_fast_c_api_object({}));
assertOptimized(is_fast_c_api_object);
assertEquals(1, fast_c_api.fast_call_count());
assertEquals(0, fast_c_api.slow_call_count());
// Test that a subclassed object returns false.
const child = Object.create(another_fast_c_api);
fast_c_api.reset_counts();
assertFalse(is_fast_c_api_object(child));
assertOptimized(is_fast_c_api_object);
assertEquals(1, fast_c_api.fast_call_count());
assertEquals(0, fast_c_api.slow_call_count());
// Test that passing an API object of an unrelated (leaf) type
// causes the function to return false, because an object of
// FastCAPI type is expected as an argument.
const leaf_interface_obj = new d8.test.LeafInterfaceType();
fast_c_api.reset_counts();
assertFalse(is_fast_c_api_object(leaf_interface_obj));
assertOptimized(is_fast_c_api_object);
assertEquals(1, fast_c_api.fast_call_count());
assertEquals(0, fast_c_api.slow_call_count());