Commit 6124a534 authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[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: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73999}
parent 76d83daa
...@@ -70,8 +70,8 @@ ...@@ -70,8 +70,8 @@
* return GetInternalField<CustomEmbedderType, * return GetInternalField<CustomEmbedderType,
* kV8EmbedderWrapperObjectIndex>(wrapper); * kV8EmbedderWrapperObjectIndex>(wrapper);
* } * }
* static void FastMethod(v8::ApiObject receiver_obj, int param) { * static void FastMethod(v8::Value* receiver_obj, int param) {
* v8::Object* v8_object = reinterpret_cast<v8::Object*>(&api_object); * v8::Object* v8_object = v8::Object::Cast(receiver_obj);
* CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>( * CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>(
* receiver_obj->GetAlignedPointerFromInternalField( * receiver_obj->GetAlignedPointerFromInternalField(
* kV8EmbedderWrapperObjectIndex)); * kV8EmbedderWrapperObjectIndex));
...@@ -190,6 +190,7 @@ ...@@ -190,6 +190,7 @@
#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 {
...@@ -312,7 +313,7 @@ class V8_EXPORT CFunction { ...@@ -312,7 +313,7 @@ class V8_EXPORT CFunction {
}; };
}; };
struct ApiObject { struct V8_DEPRECATE_SOON("Use v8::Value* instead.") ApiObject {
uintptr_t address; uintptr_t address;
}; };
...@@ -346,8 +347,12 @@ struct FastApiCallbackOptions { ...@@ -346,8 +347,12 @@ 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.
*/ */
const ApiObject data; union {
uintptr_t data_ptr;
v8::Value data;
};
}; };
namespace internal { namespace internal {
...@@ -417,7 +422,11 @@ struct TypeInfoHelper { ...@@ -417,7 +422,11 @@ 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)
......
...@@ -6590,6 +6590,15 @@ class V8_EXPORT FunctionTemplate : public Template { ...@@ -6590,6 +6590,15 @@ 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:
......
...@@ -6399,6 +6399,15 @@ bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) { ...@@ -6399,6 +6399,15 @@ 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);
......
...@@ -193,6 +193,7 @@ class EffectControlLinearizer { ...@@ -193,6 +193,7 @@ 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);
...@@ -4975,7 +4976,8 @@ void EffectControlLinearizer::LowerStoreMessage(Node* node) { ...@@ -4975,7 +4976,8 @@ void EffectControlLinearizer::LowerStoreMessage(Node* node) {
__ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern); __ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern);
} }
static MachineType MachineTypeFor(CTypeInfo::Type type) { namespace {
MachineType MachineTypeFor(CTypeInfo::Type type) {
switch (type) { switch (type) {
case CTypeInfo::Type::kVoid: case CTypeInfo::Type::kVoid:
return MachineType::AnyTagged(); return MachineType::AnyTagged();
...@@ -4997,6 +4999,30 @@ static MachineType MachineTypeFor(CTypeInfo::Type type) { ...@@ -4997,6 +4999,30 @@ static 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);
...@@ -5061,13 +5087,9 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) { ...@@ -5061,13 +5087,9 @@ 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) {
if (c_signature->ArgumentInfo(i - 1).GetType() == inputs[i] =
CTypeInfo::Type::kFloat32) { AdaptFastCallArgument(NodeProperties::GetValueInput(node, i),
inputs[i] = c_signature->ArgumentInfo(i - 1).GetType());
__ 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;
......
...@@ -21,16 +21,18 @@ ...@@ -21,16 +21,18 @@
namespace v8 { namespace v8 {
namespace { namespace {
thread_local Persistent<FunctionTemplate> api_obj_ctor;
class FastCApiObject { class FastCApiObject {
public: public:
static double AddAllFastCallback(ApiObject receiver, bool should_fallback, static double AddAllFastCallback(v8::Value* 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) {
Value* receiver_value = reinterpret_cast<Value*>(&receiver); CHECK(receiver->IsObject());
CHECK(receiver_value->IsObject()); FastCApiObject* self = UnwrapObject(Object::Cast(receiver));
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
self->fast_call_count_++; self->fast_call_count_++;
if (should_fallback) { if (should_fallback) {
...@@ -77,12 +79,11 @@ class FastCApiObject { ...@@ -77,12 +79,11 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum)); args.GetReturnValue().Set(Number::New(isolate, sum));
} }
static int Add32BitIntFastCallback(ApiObject receiver, bool should_fallback, static int Add32BitIntFastCallback(v8::Value* receiver, bool should_fallback,
int32_t arg_i32, uint32_t arg_u32, int32_t arg_i32, uint32_t arg_u32,
FastApiCallbackOptions& options) { FastApiCallbackOptions& options) {
Value* receiver_value = reinterpret_cast<Value*>(&receiver); CHECK(receiver->IsObject());
CHECK(receiver_value->IsObject()); FastCApiObject* self = UnwrapObject(Object::Cast(receiver));
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
self->fast_call_count_++; self->fast_call_count_++;
if (should_fallback) { if (should_fallback) {
...@@ -111,6 +112,55 @@ class FastCApiObject { ...@@ -111,6 +112,55 @@ 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(
...@@ -141,12 +191,14 @@ class FastCApiObject { ...@@ -141,12 +191,14 @@ class FastCApiObject {
static const int kV8WrapperObjectIndex = 1; static const int kV8WrapperObjectIndex = 1;
private: private:
static FastCApiObject* UnwrapObject(Object* object) { static bool IsValidApiObject(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);
if (instance_type != i::Internals::kJSObjectType && return (instance_type == i::Internals::kJSApiObjectType ||
instance_type != i::Internals::kJSApiObjectType && instance_type == i::Internals::kJSSpecialApiObjectType);
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*>(
...@@ -167,8 +219,7 @@ class FastCApiObject { ...@@ -167,8 +219,7 @@ class FastCApiObject {
thread_local FastCApiObject kFastCApiObject; thread_local FastCApiObject kFastCApiObject;
} // namespace } // namespace
// TODO(mslekova): Rename the fast_c_api helper to FastCAPI. void CreateFastCAPIObject(const FunctionCallbackInfo<Value>& info) {
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.");
...@@ -186,13 +237,14 @@ void CreateObject(const FunctionCallbackInfo<Value>& info) { ...@@ -186,13 +237,14 @@ void CreateObject(const FunctionCallbackInfo<Value>& info) {
} }
Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) { Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
Local<FunctionTemplate> api_obj_ctor = api_obj_ctor.Reset(isolate,
FunctionTemplate::New(isolate, CreateObject); FunctionTemplate::New(isolate, CreateFastCAPIObject));
Local<Signature> signature = Signature::New(isolate, api_obj_ctor); Local<Signature> signature =
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->PrototypeTemplate()->Set( api_obj_ctor.Get(isolate)->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,
...@@ -200,29 +252,53 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) { ...@@ -200,29 +252,53 @@ 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->PrototypeTemplate()->Set( api_obj_ctor.Get(isolate)->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));
api_obj_ctor->PrototypeTemplate()->Set( CFunction is_valid_api_object_c_func =
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->PrototypeTemplate()->Set( api_obj_ctor.Get(isolate)->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->PrototypeTemplate()->Set( api_obj_ctor.Get(isolate)->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->InstanceTemplate()->SetInternalFieldCount( api_obj_ctor.Get(isolate)->InstanceTemplate()->SetInternalFieldCount(
FastCApiObject::kV8WrapperObjectIndex + 1); FastCApiObject::kV8WrapperObjectIndex + 1);
return api_obj_ctor; return api_obj_ctor.Get(isolate);
}
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
...@@ -2733,8 +2733,10 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) { ...@@ -2733,8 +2733,10 @@ 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, "fast_c_api", test_template->Set(isolate, "FastCAPI",
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);
......
...@@ -635,6 +635,8 @@ class Shell : public i::AllStatic { ...@@ -635,6 +635,8 @@ 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,
......
...@@ -1319,7 +1319,7 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( ...@@ -1319,7 +1319,7 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
return result; return result;
} }
bool FunctionTemplateInfo::IsTemplateFor(Map map) { bool FunctionTemplateInfo::IsTemplateFor(Map map) const {
RCS_SCOPE( RCS_SCOPE(
LocalHeap::Current() == nullptr LocalHeap::Current() == nullptr
? GetIsolate()->counters()->runtime_call_stats() ? GetIsolate()->counters()->runtime_call_stats()
...@@ -1349,6 +1349,26 @@ bool FunctionTemplateInfo::IsTemplateFor(Map map) { ...@@ -1349,6 +1349,26 @@ bool FunctionTemplateInfo::IsTemplateFor(Map map) {
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) {
......
...@@ -150,7 +150,11 @@ class FunctionTemplateInfo ...@@ -150,7 +150,11 @@ 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); bool IsTemplateFor(Map map) const;
// 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();
......
...@@ -842,11 +842,11 @@ DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags) ...@@ -842,11 +842,11 @@ DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags)
bool IsValidUnwrapObject(v8::Object* object); bool IsValidUnwrapObject(v8::Object* object);
template <typename T, int offset> template <typename T>
T* GetInternalField(v8::Object* wrapper) { T* GetInternalField(v8::Object* wrapper) {
assert(offset < wrapper->InternalFieldCount()); assert(kV8WrapperObjectIndex < wrapper->InternalFieldCount());
return reinterpret_cast<T*>( return reinterpret_cast<T*>(
wrapper->GetAlignedPointerFromInternalField(offset)); wrapper->GetAlignedPointerFromInternalField(kV8WrapperObjectIndex));
} }
#endif // ifndef CCTEST_H_ #endif // ifndef CCTEST_H_
This diff is collapsed.
...@@ -3934,17 +3934,17 @@ UNINITIALIZED_TEST(DetailedSourcePositionAPI_Inlining) { ...@@ -3934,17 +3934,17 @@ UNINITIALIZED_TEST(DetailedSourcePositionAPI_Inlining) {
namespace { namespace {
struct FastApiReceiver { struct FastApiReceiver {
static void FastCallback(v8::ApiObject receiver, int argument, static void FastCallback(v8::Value* 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 = reinterpret_cast<v8::Object*>(&receiver); v8::Object* receiver_obj = v8::Object::Cast(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, kV8WrapperObjectIndex>(receiver_obj); GetInternalField<FastApiReceiver>(receiver_obj);
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled; receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
...@@ -3960,8 +3960,7 @@ struct FastApiReceiver { ...@@ -3960,8 +3960,7 @@ struct FastApiReceiver {
info.GetIsolate()->ThrowError("Called with a non-object."); info.GetIsolate()->ThrowError("Called with a non-object.");
return; return;
} }
FastApiReceiver* receiver = FastApiReceiver* receiver = GetInternalField<FastApiReceiver>(receiver_obj);
GetInternalField<FastApiReceiver, kV8WrapperObjectIndex>(receiver_obj);
receiver->result_ |= ApiCheckerResult::kSlowCalled; receiver->result_ |= ApiCheckerResult::kSlowCalled;
} }
......
...@@ -13,8 +13,8 @@ ...@@ -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.fast_c_api()); assertThrows(() => d8.test.FastCAPI());
const fast_c_api = new d8.test.fast_c_api(); const fast_c_api = new d8.test.FastCAPI();
// ----------- add_all ----------- // ----------- add_all -----------
// `add_all` has the following signature: // `add_all` has the following signature:
......
// 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());
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