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:
parent
7564f6584e
commit
194672378b
@ -70,8 +70,8 @@
|
||||
* return GetInternalField<CustomEmbedderType,
|
||||
* kV8EmbedderWrapperObjectIndex>(wrapper);
|
||||
* }
|
||||
* static void FastMethod(v8::Value* receiver_obj, int param) {
|
||||
* v8::Object* v8_object = v8::Object::Cast(receiver_obj);
|
||||
* static void FastMethod(v8::ApiObject receiver_obj, int param) {
|
||||
* v8::Object* v8_object = reinterpret_cast<v8::Object*>(&api_object);
|
||||
* CustomEmbedderType* receiver = static_cast<CustomEmbedderType*>(
|
||||
* receiver_obj->GetAlignedPointerFromInternalField(
|
||||
* kV8EmbedderWrapperObjectIndex));
|
||||
@ -190,7 +190,6 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "v8.h" // NOLINT(build/include_directory)
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace v8 {
|
||||
@ -313,7 +312,7 @@ class V8_EXPORT CFunction {
|
||||
};
|
||||
};
|
||||
|
||||
struct V8_DEPRECATE_SOON("Use v8::Value* instead.") ApiObject {
|
||||
struct ApiObject {
|
||||
uintptr_t address;
|
||||
};
|
||||
|
||||
@ -347,12 +346,8 @@ struct FastApiCallbackOptions {
|
||||
|
||||
/**
|
||||
* The `data` passed to the FunctionTemplate constructor, or `undefined`.
|
||||
* `data_ptr` allows for default constructing FastApiCallbackOptions.
|
||||
*/
|
||||
union {
|
||||
uintptr_t data_ptr;
|
||||
v8::Value data;
|
||||
};
|
||||
const ApiObject data;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
@ -422,11 +417,7 @@ struct TypeInfoHelper {
|
||||
V(uint64_t, kUint64) \
|
||||
V(float, kFloat32) \
|
||||
V(double, kFloat64) \
|
||||
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.
|
||||
V(ApiObject, kV8Value)
|
||||
|
||||
BASIC_C_TYPES(SPECIALIZE_GET_TYPE_INFO_HELPER_FOR)
|
||||
|
||||
|
@ -6590,15 +6590,6 @@ class V8_EXPORT FunctionTemplate : public Template {
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
|
@ -6399,15 +6399,6 @@ bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
|
||||
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) {
|
||||
STATIC_ASSERT(sizeof(value) == sizeof(i::Address));
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
|
@ -193,7 +193,6 @@ class EffectControlLinearizer {
|
||||
void LowerTransitionElementsKind(Node* node);
|
||||
Node* LowerLoadFieldByIndex(Node* node);
|
||||
Node* LowerLoadMessage(Node* node);
|
||||
Node* AdaptFastCallArgument(Node* node, CTypeInfo::Type arg_type);
|
||||
Node* LowerFastApiCall(Node* node);
|
||||
Node* LowerLoadTypedElement(Node* node);
|
||||
Node* LowerLoadDataViewElement(Node* node);
|
||||
@ -4976,8 +4975,7 @@ void EffectControlLinearizer::LowerStoreMessage(Node* node) {
|
||||
__ StoreField(AccessBuilder::ForExternalIntPtr(), offset, object_pattern);
|
||||
}
|
||||
|
||||
namespace {
|
||||
MachineType MachineTypeFor(CTypeInfo::Type type) {
|
||||
static MachineType MachineTypeFor(CTypeInfo::Type type) {
|
||||
switch (type) {
|
||||
case CTypeInfo::Type::kVoid:
|
||||
return MachineType::AnyTagged();
|
||||
@ -4999,30 +4997,6 @@ MachineType MachineTypeFor(CTypeInfo::Type type) {
|
||||
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) {
|
||||
FastApiCallNode n(node);
|
||||
@ -5087,9 +5061,13 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
|
||||
inputs[0] = n.target();
|
||||
for (int i = FastApiCallNode::kFastTargetInputCount;
|
||||
i < c_arg_count + FastApiCallNode::kFastTargetInputCount; ++i) {
|
||||
inputs[i] =
|
||||
AdaptFastCallArgument(NodeProperties::GetValueInput(node, i),
|
||||
c_signature->ArgumentInfo(i - 1).GetType());
|
||||
if (c_signature->ArgumentInfo(i - 1).GetType() ==
|
||||
CTypeInfo::Type::kFloat32) {
|
||||
inputs[i] =
|
||||
__ TruncateFloat64ToFloat32(NodeProperties::GetValueInput(node, i));
|
||||
} else {
|
||||
inputs[i] = NodeProperties::GetValueInput(node, i);
|
||||
}
|
||||
}
|
||||
if (c_signature->HasOptions()) {
|
||||
inputs[c_arg_count + 1] = stack_slot;
|
||||
|
@ -21,18 +21,16 @@
|
||||
|
||||
namespace v8 {
|
||||
namespace {
|
||||
|
||||
thread_local Persistent<FunctionTemplate> api_obj_ctor;
|
||||
|
||||
class FastCApiObject {
|
||||
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,
|
||||
int64_t arg_i64, uint64_t arg_u64,
|
||||
float arg_f32, double arg_f64,
|
||||
FastApiCallbackOptions& options) {
|
||||
CHECK(receiver->IsObject());
|
||||
FastCApiObject* self = UnwrapObject(Object::Cast(receiver));
|
||||
Value* receiver_value = reinterpret_cast<Value*>(&receiver);
|
||||
CHECK(receiver_value->IsObject());
|
||||
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
|
||||
self->fast_call_count_++;
|
||||
|
||||
if (should_fallback) {
|
||||
@ -79,11 +77,12 @@ class FastCApiObject {
|
||||
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,
|
||||
FastApiCallbackOptions& options) {
|
||||
CHECK(receiver->IsObject());
|
||||
FastCApiObject* self = UnwrapObject(Object::Cast(receiver));
|
||||
Value* receiver_value = reinterpret_cast<Value*>(&receiver);
|
||||
CHECK(receiver_value->IsObject());
|
||||
FastCApiObject* self = UnwrapObject(Object::Cast(receiver_value));
|
||||
self->fast_call_count_++;
|
||||
|
||||
if (should_fallback) {
|
||||
@ -112,55 +111,6 @@ class FastCApiObject {
|
||||
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) {
|
||||
FastCApiObject* self = UnwrapObject(*args.This());
|
||||
args.GetReturnValue().Set(
|
||||
@ -191,14 +141,12 @@ class FastCApiObject {
|
||||
static const int kV8WrapperObjectIndex = 1;
|
||||
|
||||
private:
|
||||
static bool IsValidApiObject(Object* object) {
|
||||
static FastCApiObject* UnwrapObject(Object* object) {
|
||||
i::Address addr = *reinterpret_cast<i::Address*>(object);
|
||||
auto instance_type = i::Internals::GetInstanceType(addr);
|
||||
return (instance_type == i::Internals::kJSApiObjectType ||
|
||||
instance_type == i::Internals::kJSSpecialApiObjectType);
|
||||
}
|
||||
static FastCApiObject* UnwrapObject(Object* object) {
|
||||
if (!IsValidApiObject(object)) {
|
||||
if (instance_type != i::Internals::kJSObjectType &&
|
||||
instance_type != i::Internals::kJSApiObjectType &&
|
||||
instance_type != i::Internals::kJSSpecialApiObjectType) {
|
||||
return nullptr;
|
||||
}
|
||||
FastCApiObject* wrapped = reinterpret_cast<FastCApiObject*>(
|
||||
@ -219,7 +167,8 @@ class FastCApiObject {
|
||||
thread_local FastCApiObject kFastCApiObject;
|
||||
} // 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()) {
|
||||
info.GetIsolate()->ThrowError(
|
||||
"FastCAPI helper must be constructed with new.");
|
||||
@ -237,14 +186,13 @@ void CreateFastCAPIObject(const FunctionCallbackInfo<Value>& info) {
|
||||
}
|
||||
|
||||
Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
|
||||
api_obj_ctor.Reset(isolate,
|
||||
FunctionTemplate::New(isolate, CreateFastCAPIObject));
|
||||
Local<Signature> signature =
|
||||
Signature::New(isolate, api_obj_ctor.Get(isolate));
|
||||
Local<FunctionTemplate> api_obj_ctor =
|
||||
FunctionTemplate::New(isolate, CreateObject);
|
||||
Local<Signature> signature = Signature::New(isolate, api_obj_ctor);
|
||||
{
|
||||
CFunction add_all_c_func =
|
||||
CFunction::Make(FastCApiObject::AddAllFastCallback);
|
||||
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
|
||||
api_obj_ctor->PrototypeTemplate()->Set(
|
||||
isolate, "add_all",
|
||||
FunctionTemplate::New(isolate, FastCApiObject::AddAllSlowCallback,
|
||||
Local<Value>(), signature, 1,
|
||||
@ -252,53 +200,29 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
|
||||
SideEffectType::kHasSideEffect, &add_all_c_func));
|
||||
CFunction add_32bit_int_c_func =
|
||||
CFunction::Make(FastCApiObject::Add32BitIntFastCallback);
|
||||
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
|
||||
api_obj_ctor->PrototypeTemplate()->Set(
|
||||
isolate, "add_32bit_int",
|
||||
FunctionTemplate::New(
|
||||
isolate, FastCApiObject::Add32BitIntSlowCallback, Local<Value>(),
|
||||
signature, 1, ConstructorBehavior::kThrow,
|
||||
SideEffectType::kHasSideEffect, &add_32bit_int_c_func));
|
||||
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(
|
||||
api_obj_ctor->PrototypeTemplate()->Set(
|
||||
isolate, "fast_call_count",
|
||||
FunctionTemplate::New(isolate, FastCApiObject::FastCallCount,
|
||||
Local<Value>(), signature));
|
||||
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
|
||||
api_obj_ctor->PrototypeTemplate()->Set(
|
||||
isolate, "slow_call_count",
|
||||
FunctionTemplate::New(isolate, FastCApiObject::SlowCallCount,
|
||||
Local<Value>(), signature));
|
||||
api_obj_ctor.Get(isolate)->PrototypeTemplate()->Set(
|
||||
api_obj_ctor->PrototypeTemplate()->Set(
|
||||
isolate, "reset_counts",
|
||||
FunctionTemplate::New(isolate, FastCApiObject::ResetCounts,
|
||||
Local<Value>(), signature));
|
||||
}
|
||||
api_obj_ctor.Get(isolate)->InstanceTemplate()->SetInternalFieldCount(
|
||||
api_obj_ctor->InstanceTemplate()->SetInternalFieldCount(
|
||||
FastCApiObject::kV8WrapperObjectIndex + 1);
|
||||
|
||||
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;
|
||||
return api_obj_ctor;
|
||||
}
|
||||
|
||||
} // namespace v8
|
||||
|
@ -2733,10 +2733,8 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
|
||||
// constructor when --correctness_fuzzer_suppressions is on.
|
||||
if (i::FLAG_turbo_fast_api_calls &&
|
||||
!i::FLAG_correctness_fuzzer_suppressions) {
|
||||
test_template->Set(isolate, "FastCAPI",
|
||||
test_template->Set(isolate, "fast_c_api",
|
||||
Shell::CreateTestFastCApiTemplate(isolate));
|
||||
test_template->Set(isolate, "LeafInterfaceType",
|
||||
Shell::CreateLeafInterfaceTypeTemplate(isolate));
|
||||
}
|
||||
|
||||
d8_template->Set(isolate, "test", test_template);
|
||||
|
@ -635,8 +635,6 @@ class Shell : public i::AllStatic {
|
||||
static Local<ObjectTemplate> CreateRealmTemplate(Isolate* isolate);
|
||||
static Local<ObjectTemplate> CreateD8Template(Isolate* isolate);
|
||||
static Local<FunctionTemplate> CreateTestFastCApiTemplate(Isolate* isolate);
|
||||
static Local<FunctionTemplate> CreateLeafInterfaceTypeTemplate(
|
||||
Isolate* isolate);
|
||||
|
||||
static MaybeLocal<Context> CreateRealm(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args, int index,
|
||||
|
@ -1319,7 +1319,7 @@ Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FunctionTemplateInfo::IsTemplateFor(Map map) const {
|
||||
bool FunctionTemplateInfo::IsTemplateFor(Map map) {
|
||||
RCS_SCOPE(
|
||||
LocalHeap::Current() == nullptr
|
||||
? GetIsolate()->counters()->runtime_call_stats()
|
||||
@ -1349,26 +1349,6 @@ bool FunctionTemplateInfo::IsTemplateFor(Map map) const {
|
||||
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
|
||||
FunctionTemplateRareData FunctionTemplateInfo::AllocateFunctionTemplateRareData(
|
||||
Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
|
||||
|
@ -150,11 +150,7 @@ class FunctionTemplateInfo
|
||||
inline FunctionTemplateInfo GetParent(Isolate* isolate);
|
||||
// Returns true if |object| is an instance of this function template.
|
||||
inline bool IsTemplateFor(JSObject object);
|
||||
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;
|
||||
bool IsTemplateFor(Map map);
|
||||
inline bool instantiated();
|
||||
|
||||
inline bool BreakAtEntry();
|
||||
|
@ -842,11 +842,11 @@ DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags)
|
||||
|
||||
bool IsValidUnwrapObject(v8::Object* object);
|
||||
|
||||
template <typename T>
|
||||
template <typename T, int offset>
|
||||
T* GetInternalField(v8::Object* wrapper) {
|
||||
assert(kV8WrapperObjectIndex < wrapper->InternalFieldCount());
|
||||
assert(offset < wrapper->InternalFieldCount());
|
||||
return reinterpret_cast<T*>(
|
||||
wrapper->GetAlignedPointerFromInternalField(kV8WrapperObjectIndex));
|
||||
wrapper->GetAlignedPointerFromInternalField(offset));
|
||||
}
|
||||
|
||||
#endif // ifndef CCTEST_H_
|
||||
|
@ -20789,56 +20789,6 @@ THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
|
||||
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) {
|
||||
LocalContext context;
|
||||
@ -27676,15 +27626,14 @@ namespace {
|
||||
|
||||
template <typename Value, typename Impl, typename Ret>
|
||||
struct BasicApiChecker {
|
||||
static Ret FastCallback(v8::Value* receiver, Value argument,
|
||||
static Ret FastCallback(v8::ApiObject receiver, Value argument,
|
||||
v8::FastApiCallbackOptions& options) {
|
||||
// TODO(mslekova): Refactor the data checking.
|
||||
v8::Value* data = &(options.data);
|
||||
const v8::Value* data = reinterpret_cast<const v8::Value*>(&options.data);
|
||||
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);
|
||||
}
|
||||
static Ret FastCallbackNoFallback(v8::Value* receiver, Value argument) {
|
||||
static Ret FastCallbackNoFallback(v8::ApiObject receiver, Value argument) {
|
||||
v8::FastApiCallbackOptions options = {false, {0}};
|
||||
return Impl::FastCallback(receiver, argument, options);
|
||||
}
|
||||
@ -27695,12 +27644,6 @@ struct BasicApiChecker {
|
||||
bool DidCallFast() const { return (result_ & ApiCheckerResult::kFastCalled); }
|
||||
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;
|
||||
};
|
||||
|
||||
@ -27725,16 +27668,17 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>, void> {
|
||||
write_to_fallback_(write_to_fallback),
|
||||
args_count_(args_count) {}
|
||||
|
||||
static void FastCallback(v8::Value* receiver, T argument,
|
||||
static void FastCallback(v8::ApiObject receiver, T argument,
|
||||
v8::FastApiCallbackOptions& options) {
|
||||
v8::Object* receiver_obj = v8::Object::Cast(receiver);
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
if (!IsValidUnwrapObject(receiver_obj)) {
|
||||
options.fallback = 1;
|
||||
return;
|
||||
}
|
||||
ApiNumberChecker<T>* receiver_ptr =
|
||||
GetInternalField<ApiNumberChecker<T>>(receiver_obj);
|
||||
receiver_ptr->SetCallFast();
|
||||
GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
receiver_ptr->fast_value_ = argument;
|
||||
if (receiver_ptr->write_to_fallback_ == FallbackPolicy::kRequestFallback) {
|
||||
// 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;
|
||||
}
|
||||
ApiNumberChecker<T>* checker =
|
||||
GetInternalField<ApiNumberChecker<T>>(receiver);
|
||||
GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(receiver);
|
||||
CHECK_EQ(info.Length(), checker->args_count_);
|
||||
|
||||
checker->SetCallSlow();
|
||||
checker->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
|
||||
LocalContext env;
|
||||
checker->slow_value_ = ConvertJSValue<T>::Get(info[0], env.local());
|
||||
@ -27775,15 +27719,17 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>, void> {
|
||||
};
|
||||
|
||||
struct UnexpectedObjectChecker
|
||||
: BasicApiChecker<v8::Value*, UnexpectedObjectChecker, void> {
|
||||
static void FastCallback(v8::Value* receiver, v8::Value* argument,
|
||||
: BasicApiChecker<v8::ApiObject, UnexpectedObjectChecker, void> {
|
||||
static void FastCallback(v8::ApiObject receiver, v8::ApiObject argument,
|
||||
v8::FastApiCallbackOptions& options) {
|
||||
v8::Object* receiver_obj = v8::Object::Cast(receiver);
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
UnexpectedObjectChecker* receiver_ptr =
|
||||
GetInternalField<UnexpectedObjectChecker>(receiver_obj);
|
||||
receiver_ptr->SetCallFast();
|
||||
if (argument->IsObject()) {
|
||||
v8::Object* argument_obj = v8::Object::Cast(argument);
|
||||
GetInternalField<UnexpectedObjectChecker, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -27791,8 +27737,9 @@ struct UnexpectedObjectChecker
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
|
||||
UnexpectedObjectChecker* receiver_ptr =
|
||||
GetInternalField<UnexpectedObjectChecker>(receiver_obj);
|
||||
receiver_ptr->SetCallSlow();
|
||||
GetInternalField<UnexpectedObjectChecker, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
if (info[0]->IsObject()) {
|
||||
v8::Object* argument_obj = v8::Object::Cast(*info[0]);
|
||||
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>
|
||||
bool SetupTest(v8::Local<v8::Value> initial_value, LocalContext* env,
|
||||
BasicApiChecker<Value, Impl, Ret>* checker,
|
||||
@ -27928,7 +27838,7 @@ void CallAndCheck(
|
||||
"function func(arg) { return receiver.api_func(arg); }"
|
||||
"%PrepareFunctionForOptimization(func);"
|
||||
"func(value);");
|
||||
checker.Reset();
|
||||
checker.result_ = ApiCheckerResult::kNotCalled;
|
||||
|
||||
v8::Isolate* isolate = CcTest::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>
|
||||
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::Object* receiver_obj = v8::Object::Cast(receiver);
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
ReturnValueChecker<T>* receiver_ptr =
|
||||
GetInternalField<ReturnValueChecker<T>>(receiver_obj);
|
||||
receiver_ptr->SetCallFast();
|
||||
GetInternalField<ReturnValueChecker<T>, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
return arg;
|
||||
}
|
||||
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
|
||||
ReturnValueChecker<T>* receiver_ptr =
|
||||
GetInternalField<ReturnValueChecker<T>>(receiver_obj);
|
||||
receiver_ptr->SetCallSlow();
|
||||
GetInternalField<ReturnValueChecker<T>, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
info.GetReturnValue().Set(info[0]);
|
||||
}
|
||||
};
|
||||
@ -28025,7 +27901,7 @@ void CheckFastReturnValue(v8::Local<v8::Value> expected_value,
|
||||
"%PrepareFunctionForOptimization(func);"
|
||||
"func(value);");
|
||||
CHECK(!has_caught);
|
||||
checker.Reset();
|
||||
checker.result_ = ApiCheckerResult::kNotCalled;
|
||||
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::TryCatch try_catch(isolate);
|
||||
@ -28224,7 +28100,7 @@ TEST(FastApiStackSlot) {
|
||||
" };"
|
||||
" return foo;"
|
||||
"};");
|
||||
checker.Reset();
|
||||
checker.result_ = ApiCheckerResult::kNotCalled;
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
v8::Local<v8::Value> foo =
|
||||
@ -28700,8 +28576,8 @@ TEST(FastApiCalls) {
|
||||
CallWithUnexpectedObjectType(v8_str("str"));
|
||||
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
|
||||
// are compared against the slow optimized calls.
|
||||
// TODO(mslekova): Add tests for FTI that requires access check.
|
||||
|
@ -3934,17 +3934,17 @@ UNINITIALIZED_TEST(DetailedSourcePositionAPI_Inlining) {
|
||||
namespace {
|
||||
|
||||
struct FastApiReceiver {
|
||||
static void FastCallback(v8::Value* receiver, int argument,
|
||||
static void FastCallback(v8::ApiObject receiver, int argument,
|
||||
v8::FastApiCallbackOptions& options) {
|
||||
// TODO(mslekova): The fallback is not used by the test. Replace this
|
||||
// with a CHECK.
|
||||
v8::Object* receiver_obj = v8::Object::Cast(receiver);
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
if (!IsValidUnwrapObject(receiver_obj)) {
|
||||
options.fallback = 1;
|
||||
return;
|
||||
}
|
||||
FastApiReceiver* receiver_ptr =
|
||||
GetInternalField<FastApiReceiver>(receiver_obj);
|
||||
GetInternalField<FastApiReceiver, kV8WrapperObjectIndex>(receiver_obj);
|
||||
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
|
||||
@ -3960,7 +3960,8 @@ struct FastApiReceiver {
|
||||
info.GetIsolate()->ThrowError("Called with a non-object.");
|
||||
return;
|
||||
}
|
||||
FastApiReceiver* receiver = GetInternalField<FastApiReceiver>(receiver_obj);
|
||||
FastApiReceiver* receiver =
|
||||
GetInternalField<FastApiReceiver, kV8WrapperObjectIndex>(receiver_obj);
|
||||
|
||||
receiver->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
// it's not suitable for deoptimization fuzzing.
|
||||
// Flags: --deopt-every-n-times=0
|
||||
|
||||
assertThrows(() => d8.test.FastCAPI());
|
||||
const fast_c_api = new d8.test.FastCAPI();
|
||||
assertThrows(() => d8.test.fast_c_api());
|
||||
const fast_c_api = new d8.test.fast_c_api();
|
||||
|
||||
// ----------- add_all -----------
|
||||
// `add_all` has the following signature:
|
||||
|
@ -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());
|
Loading…
Reference in New Issue
Block a user