[turbofan] Remove object unwrapping for fast C calls
The object is passed now as an v8::ApiObject instead of unwrapped C++ pointer and the embedder should do the unwrapping. Bug: chromium:1052746 Change-Id: If5671c5fdbbe8d58435c7bd9aceccf5e17f8ea21 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2304571 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#68991}
This commit is contained in:
parent
b64cede5d8
commit
470b614608
@ -23,13 +23,7 @@
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* // Represents the way this type system maps C++ and JS values.
|
||||
* struct WrapperTypeInfo {
|
||||
* // Store e.g. a method to map from exposed C++ types to the already
|
||||
* // created v8::FunctionTemplate's for instantiating them.
|
||||
* };
|
||||
*
|
||||
* // Helper method with a sanity check.
|
||||
* // Helper method with a check for field count.
|
||||
* template <typename T, int offset>
|
||||
* inline T* GetInternalField(v8::Local<v8::Object> wrapper) {
|
||||
* assert(offset < wrapper->InternalFieldCount());
|
||||
@ -37,25 +31,19 @@
|
||||
* wrapper->GetAlignedPointerFromInternalField(offset));
|
||||
* }
|
||||
*
|
||||
* // Returns the type info from a wrapper JS object.
|
||||
* inline const WrapperTypeInfo* ToWrapperTypeInfo(
|
||||
* v8::Local<v8::Object> wrapper) {
|
||||
* return GetInternalField<WrapperTypeInfo,
|
||||
* kV8EmbedderWrapperTypeIndex>(wrapper);
|
||||
* }
|
||||
*
|
||||
* class CustomEmbedderType {
|
||||
* public:
|
||||
* static constexpr const WrapperTypeInfo* GetWrapperTypeInfo() {
|
||||
* return &custom_type_wrapper_type_info;
|
||||
* }
|
||||
* // Returns the raw C object from a wrapper JS object.
|
||||
* static CustomEmbedderType* Unwrap(v8::Local<v8::Object> wrapper) {
|
||||
* return GetInternalField<CustomEmbedderType,
|
||||
* kV8EmbedderWrapperObjectIndex>(wrapper);
|
||||
* }
|
||||
* static void FastMethod(CustomEmbedderType* receiver, int param) {
|
||||
* assert(receiver != nullptr);
|
||||
* 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));
|
||||
*
|
||||
* // Type checks are already done by the optimized code.
|
||||
* // Then call some performance-critical method like:
|
||||
* // receiver->Method(param);
|
||||
@ -67,25 +55,10 @@
|
||||
* v8::Local<v8::Object>::Cast(info.Holder());
|
||||
* CustomEmbedderType* receiver = Unwrap(instance);
|
||||
* // TODO: Do type checks and extract {param}.
|
||||
* FastMethod(receiver, param);
|
||||
* receiver->Method(param);
|
||||
* }
|
||||
*
|
||||
* private:
|
||||
* static const WrapperTypeInfo custom_type_wrapper_type_info;
|
||||
* };
|
||||
*
|
||||
* // Support for custom embedder types via specialization of WrapperTraits.
|
||||
* namespace v8 {
|
||||
* template <>
|
||||
* class WrapperTraits<CustomEmbedderType> {
|
||||
* public:
|
||||
* static const void* GetTypeInfo() {
|
||||
* // We use the already defined machinery for the custom type.
|
||||
* return CustomEmbedderType::GetWrapperTypeInfo();
|
||||
* }
|
||||
* };
|
||||
* } // namespace v8
|
||||
*
|
||||
* // The constants kV8EmbedderWrapperTypeIndex and
|
||||
* // kV8EmbedderWrapperObjectIndex describe the offsets for the type info
|
||||
* // struct (the one returned by WrapperTraits::GetTypeInfo) and the
|
||||
@ -179,7 +152,7 @@ class CTypeInfo {
|
||||
kUint64,
|
||||
kFloat32,
|
||||
kFloat64,
|
||||
kUnwrappedApiObject,
|
||||
kV8Value,
|
||||
};
|
||||
|
||||
enum class ArgFlags : uint8_t {
|
||||
@ -187,6 +160,7 @@ class CTypeInfo {
|
||||
kIsArrayBit = 1 << 0, // This argument is first in an array of values.
|
||||
};
|
||||
|
||||
// TODO(mslekova): Clean this up once V8's version in Node.js is updated
|
||||
static CTypeInfo FromWrapperType(const void* wrapper_type_info,
|
||||
ArgFlags flags = ArgFlags::kNone) {
|
||||
uintptr_t wrapper_type_info_ptr =
|
||||
@ -196,15 +170,15 @@ class CTypeInfo {
|
||||
wrapper_type_info_ptr & ~(static_cast<uintptr_t>(~0)
|
||||
<< static_cast<uintptr_t>(kIsWrapperTypeBit)),
|
||||
0u);
|
||||
// TODO(mslekova): Refactor the manual bit manipulations to use
|
||||
// PointerWithPayload instead.
|
||||
return CTypeInfo(wrapper_type_info_ptr | static_cast<int>(flags) |
|
||||
kIsWrapperTypeBit);
|
||||
}
|
||||
|
||||
static constexpr CTypeInfo FromCType(Type ctype,
|
||||
ArgFlags flags = ArgFlags::kNone) {
|
||||
// ctype cannot be Type::kUnwrappedApiObject.
|
||||
// TODO(mslekova): Refactor the manual bit manipulations to use
|
||||
// PointerWithPayload instead.
|
||||
// ctype cannot be Type::kV8Value.
|
||||
return CTypeInfo(
|
||||
((static_cast<uintptr_t>(ctype) << kTypeOffset) & kTypeMask) |
|
||||
static_cast<int>(flags));
|
||||
@ -214,7 +188,7 @@ class CTypeInfo {
|
||||
|
||||
constexpr Type GetType() const {
|
||||
if (payload_ & kIsWrapperTypeBit) {
|
||||
return Type::kUnwrappedApiObject;
|
||||
return Type::kV8Value;
|
||||
}
|
||||
return static_cast<Type>((payload_ & kTypeMask) >> kTypeOffset);
|
||||
}
|
||||
@ -246,21 +220,27 @@ class CFunctionInfo {
|
||||
virtual const CTypeInfo& ArgumentInfo(unsigned int index) const = 0;
|
||||
};
|
||||
|
||||
// TODO(mslekova): Clean this up once V8's version in Node.js is updated
|
||||
template <typename T>
|
||||
class WrapperTraits {
|
||||
public:
|
||||
static const void* GetTypeInfo() {
|
||||
static_assert(sizeof(T) != sizeof(T),
|
||||
"WrapperTraits must be specialized for this type.");
|
||||
return nullptr;
|
||||
static const int tag = 0;
|
||||
return reinterpret_cast<const void*>(&tag);
|
||||
}
|
||||
};
|
||||
|
||||
struct ApiObject {
|
||||
uintptr_t address;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct GetCType {
|
||||
static_assert(sizeof(T) != sizeof(T), "Unsupported CType");
|
||||
static constexpr CTypeInfo Get() {
|
||||
return CTypeInfo::FromCType(CTypeInfo::Type::kV8Value);
|
||||
}
|
||||
};
|
||||
|
||||
#define SPECIALIZE_GET_C_TYPE_FOR(ctype, ctypeinfo) \
|
||||
@ -279,19 +259,11 @@ struct GetCType {
|
||||
V(int64_t, kInt64) \
|
||||
V(uint64_t, kUint64) \
|
||||
V(float, kFloat32) \
|
||||
V(double, kFloat64)
|
||||
V(double, kFloat64) \
|
||||
V(ApiObject, kV8Value)
|
||||
|
||||
SUPPORTED_C_TYPES(SPECIALIZE_GET_C_TYPE_FOR)
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct EnableIfHasWrapperTypeInfo {};
|
||||
|
||||
template <typename T>
|
||||
struct EnableIfHasWrapperTypeInfo<T, decltype(WrapperTraits<T>::GetTypeInfo(),
|
||||
void())> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
// T* where T is a primitive (array of primitives).
|
||||
template <typename T, typename = void>
|
||||
struct GetCTypePointerImpl {
|
||||
@ -303,7 +275,7 @@ struct GetCTypePointerImpl {
|
||||
|
||||
// T* where T is an API object.
|
||||
template <typename T>
|
||||
struct GetCTypePointerImpl<T, typename EnableIfHasWrapperTypeInfo<T>::type> {
|
||||
struct GetCTypePointerImpl<T, void> {
|
||||
static constexpr CTypeInfo Get() {
|
||||
return CTypeInfo::FromWrapperType(WrapperTraits<T>::GetTypeInfo());
|
||||
}
|
||||
@ -317,8 +289,7 @@ struct GetCTypePointerPointerImpl {
|
||||
|
||||
// T** where T is an API object (array of API objects).
|
||||
template <typename T>
|
||||
struct GetCTypePointerPointerImpl<
|
||||
T, typename EnableIfHasWrapperTypeInfo<T>::type> {
|
||||
struct GetCTypePointerPointerImpl<T, void> {
|
||||
static constexpr CTypeInfo Get() {
|
||||
return CTypeInfo::FromWrapperType(WrapperTraits<T>::GetTypeInfo(),
|
||||
CTypeInfo::ArgFlags::kIsArrayBit);
|
||||
|
@ -4938,8 +4938,8 @@ static MachineType MachineTypeFor(CTypeInfo::Type type) {
|
||||
return MachineType::Float32();
|
||||
case CTypeInfo::Type::kFloat64:
|
||||
return MachineType::Float64();
|
||||
case CTypeInfo::Type::kUnwrappedApiObject:
|
||||
return MachineType::Pointer();
|
||||
case CTypeInfo::Type::kV8Value:
|
||||
return MachineType::AnyTagged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -908,17 +908,14 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
|
||||
kExtraInputsCount);
|
||||
inputs[cursor++] = ExternalConstant(ExternalReference::Create(c_function_));
|
||||
|
||||
inputs[cursor++] = MaybeUnwrapApiObject(
|
||||
c_signature_->ArgumentInfo(0).GetType(), n.receiver());
|
||||
inputs[cursor++] = n.receiver();
|
||||
|
||||
// TODO(turbofan): Consider refactoring CFunctionInfo to distinguish
|
||||
// between receiver and arguments, simplifying this (and related) spots.
|
||||
int js_args_count = c_argument_count - kReceiver;
|
||||
for (int i = 0; i < js_args_count; ++i) {
|
||||
if (i < n.ArgumentCount()) {
|
||||
CTypeInfo::Type type =
|
||||
c_signature_->ArgumentInfo(i + kReceiver).GetType();
|
||||
inputs[cursor++] = MaybeUnwrapApiObject(type, n.Argument(i));
|
||||
inputs[cursor++] = n.Argument(i);
|
||||
} else {
|
||||
inputs[cursor++] = UndefinedConstant();
|
||||
}
|
||||
@ -985,32 +982,6 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
|
||||
static_cast<int>(inputs_size), inputs));
|
||||
}
|
||||
|
||||
TNode<RawPtrT> UnwrapApiObject(TNode<JSObject> node) {
|
||||
CHECK_GE(isolate()->embedder_wrapper_object_index(), 0);
|
||||
const int offset = Internals::kJSObjectHeaderSize +
|
||||
(Internals::kEmbedderDataSlotSize *
|
||||
isolate()->embedder_wrapper_object_index());
|
||||
|
||||
FieldAccess access(
|
||||
kTaggedBase, offset, MaybeHandle<Name>(), MaybeHandle<Map>(),
|
||||
V8_HEAP_SANDBOX_BOOL ? Type::SandboxedExternalPointer() : Type::Any(),
|
||||
MachineType::Pointer(), WriteBarrierKind::kNoWriteBarrier);
|
||||
return LoadField<RawPtrT>(access, node);
|
||||
}
|
||||
|
||||
Node* MaybeUnwrapApiObject(CTypeInfo::Type type, TNode<Object> node) {
|
||||
switch (type) {
|
||||
case CTypeInfo::Type::kUnwrappedApiObject:
|
||||
// This call assumes that {node} is a JSObject with an internal field
|
||||
// set to a C pointer. It should fail in all other cases.
|
||||
// TODO(mslekova): Implement instanceOf check for the C pointer type.
|
||||
// TODO(mslekova): Introduce a GraphAssembler primitive for safe cast.
|
||||
return UnwrapApiObject(TNode<JSObject>::UncheckedCast(node));
|
||||
default:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
const Address c_function_;
|
||||
const CFunctionInfo* const c_signature_;
|
||||
const FunctionTemplateInfoRef function_template_info_;
|
||||
|
@ -1724,8 +1724,8 @@ class RepresentationSelector {
|
||||
return MachineType::Float32();
|
||||
case CTypeInfo::Type::kFloat64:
|
||||
return MachineType::Float64();
|
||||
case CTypeInfo::Type::kUnwrappedApiObject:
|
||||
return MachineType::Pointer();
|
||||
case CTypeInfo::Type::kV8Value:
|
||||
return MachineType::AnyTagged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1751,8 +1751,8 @@ class RepresentationSelector {
|
||||
// fall into that pit, but future changes may break this here.
|
||||
case CTypeInfo::Type::kUint64:
|
||||
return UseInfo::Word64();
|
||||
case CTypeInfo::Type::kUnwrappedApiObject:
|
||||
return UseInfo::Word();
|
||||
case CTypeInfo::Type::kV8Value:
|
||||
return UseInfo::AnyTagged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27364,9 +27364,9 @@ DEFINE_OPERATORS_FOR_FLAGS(ApiCheckerResultFlags)
|
||||
|
||||
template <typename Value, typename Impl>
|
||||
struct BasicApiChecker {
|
||||
static void FastCallback(BasicApiChecker<Value, Impl>* receiver,
|
||||
Value argument, int* fallback) {
|
||||
Impl::FastCallback(static_cast<Impl*>(receiver), argument, fallback);
|
||||
static void FastCallback(v8::ApiObject receiver, Value argument,
|
||||
int* fallback) {
|
||||
Impl::FastCallback(receiver, argument, fallback);
|
||||
}
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
Impl::SlowCallback(info);
|
||||
@ -27378,25 +27378,52 @@ struct BasicApiChecker {
|
||||
ApiCheckerResultFlags result_ = ApiCheckerResult::kNotCalled;
|
||||
};
|
||||
|
||||
bool IsValidUnwrapObject(v8::Object* object) {
|
||||
v8::internal::Address addr =
|
||||
*reinterpret_cast<v8::internal::Address*>(object);
|
||||
auto instance_type = v8::internal::Internals::GetInstanceType(addr);
|
||||
return (instance_type == v8::internal::Internals::kJSObjectType ||
|
||||
instance_type == v8::internal::Internals::kJSApiObjectType ||
|
||||
instance_type == v8::internal::Internals::kJSSpecialApiObjectType);
|
||||
}
|
||||
|
||||
template <typename T, int offset>
|
||||
T* GetInternalField(v8::Object* wrapper) {
|
||||
assert(offset < wrapper->InternalFieldCount());
|
||||
return reinterpret_cast<T*>(
|
||||
wrapper->GetAlignedPointerFromInternalField(offset));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>> {
|
||||
explicit ApiNumberChecker(T value, bool raise_exception = false,
|
||||
int args_count = 1)
|
||||
: raise_exception_(raise_exception), args_count_(args_count) {}
|
||||
|
||||
static void FastCallback(ApiNumberChecker<T>* receiver, T argument,
|
||||
int* fallback) {
|
||||
receiver->result_ |= ApiCheckerResult::kFastCalled;
|
||||
receiver->fast_value_ = argument;
|
||||
if (receiver->raise_exception_) {
|
||||
static void FastCallback(v8::ApiObject receiver, T argument, int* fallback) {
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
if (!IsValidUnwrapObject(receiver_obj)) {
|
||||
*fallback = 1;
|
||||
return;
|
||||
}
|
||||
ApiNumberChecker<T>* receiver_ptr =
|
||||
GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(
|
||||
receiver_obj);
|
||||
receiver_ptr->result_ |= ApiCheckerResult::kFastCalled;
|
||||
receiver_ptr->fast_value_ = argument;
|
||||
if (receiver_ptr->raise_exception_) {
|
||||
*fallback = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Object* receiver = v8::Object::Cast(*info.Holder());
|
||||
ApiNumberChecker<T>* checker = static_cast<ApiNumberChecker<T>*>(
|
||||
receiver->GetAlignedPointerFromInternalField(kV8WrapperObjectIndex));
|
||||
if (!IsValidUnwrapObject(receiver)) {
|
||||
info.GetIsolate()->ThrowException(v8_str("Called with a non-object."));
|
||||
return;
|
||||
}
|
||||
ApiNumberChecker<T>* checker =
|
||||
GetInternalField<ApiNumberChecker<T>, kV8WrapperObjectIndex>(receiver);
|
||||
CHECK_EQ(info.Length(), checker->args_count_);
|
||||
|
||||
checker->result_ |= ApiCheckerResult::kSlowCalled;
|
||||
@ -27415,6 +27442,35 @@ struct ApiNumberChecker : BasicApiChecker<T, ApiNumberChecker<T>> {
|
||||
int args_count_ = 1;
|
||||
};
|
||||
|
||||
struct UnexpectedObjectChecker
|
||||
: BasicApiChecker<v8::ApiObject, UnexpectedObjectChecker> {
|
||||
static void FastCallback(v8::ApiObject receiver, v8::ApiObject argument,
|
||||
int* fallback) {
|
||||
v8::Object* receiver_obj = reinterpret_cast<v8::Object*>(&receiver);
|
||||
UnexpectedObjectChecker* receiver_ptr =
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Object* receiver_obj = v8::Object::Cast(*info.Holder());
|
||||
UnexpectedObjectChecker* receiver_ptr =
|
||||
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));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum class Behavior {
|
||||
kNoException,
|
||||
kException, // An exception should be thrown by the callback function.
|
||||
@ -27428,8 +27484,7 @@ bool SetupTest(v8::Local<v8::Value> initial_value, LocalContext* env,
|
||||
|
||||
v8::CFunction c_func = v8::CFunction::MakeRaisesException(
|
||||
BasicApiChecker<Value, Impl>::FastCallback);
|
||||
CHECK_EQ(c_func.ArgumentInfo(0).GetType(),
|
||||
v8::CTypeInfo::Type::kUnwrappedApiObject);
|
||||
CHECK_EQ(c_func.ArgumentInfo(0).GetType(), v8::CTypeInfo::Type::kV8Value);
|
||||
|
||||
Local<v8::FunctionTemplate> checker_templ = v8::FunctionTemplate::New(
|
||||
isolate, BasicApiChecker<Value, Impl>::SlowCallback,
|
||||
@ -27554,6 +27609,35 @@ void CallWithMoreArguments() {
|
||||
CHECK(checker.DidCallFast());
|
||||
}
|
||||
|
||||
void CallWithUnexpectedReceiverType(v8::Local<v8::Value> receiver) {
|
||||
LocalContext env;
|
||||
ApiNumberChecker<int32_t> checker(42);
|
||||
bool has_caught =
|
||||
SetupTest(receiver, &env, &checker,
|
||||
"function func(arg) { receiver.api_func.apply(value, arg); }"
|
||||
"%PrepareFunctionForOptimization(func);"
|
||||
"func(value);"
|
||||
"%OptimizeFunctionOnNextCall(func);"
|
||||
"func(value);");
|
||||
CHECK(has_caught);
|
||||
// The slow and fast callbacks were called actually, but aborted early.
|
||||
CHECK(!checker.DidCallSlow());
|
||||
CHECK(!checker.DidCallFast());
|
||||
}
|
||||
|
||||
void CallWithUnexpectedObjectType(v8::Local<v8::Value> receiver) {
|
||||
LocalContext env;
|
||||
UnexpectedObjectChecker checker;
|
||||
SetupTest(receiver, &env, &checker,
|
||||
"function func(arg) { receiver.api_func(arg); }"
|
||||
"%PrepareFunctionForOptimization(func);"
|
||||
"func(value);"
|
||||
"%OptimizeFunctionOnNextCall(func);"
|
||||
"func(value);");
|
||||
CHECK(checker.DidCallFast());
|
||||
CHECK(checker.DidCallSlow());
|
||||
}
|
||||
|
||||
class TestCFunctionInfo : public v8::CFunctionInfo {
|
||||
const v8::CTypeInfo& ReturnInfo() const override {
|
||||
static v8::CTypeInfo return_info =
|
||||
@ -27565,7 +27649,7 @@ class TestCFunctionInfo : public v8::CFunctionInfo {
|
||||
|
||||
const v8::CTypeInfo& ArgumentInfo(unsigned int index) const override {
|
||||
static v8::CTypeInfo type_info0 =
|
||||
v8::CTypeInfo::FromCType(v8::CTypeInfo::Type::kUnwrappedApiObject);
|
||||
v8::CTypeInfo::FromCType(v8::CTypeInfo::Type::kV8Value);
|
||||
static v8::CTypeInfo type_info1 =
|
||||
v8::CTypeInfo::FromCType(v8::CTypeInfo::Type::kBool);
|
||||
switch (index) {
|
||||
@ -27586,31 +27670,11 @@ void CheckDynamicTypeInfo() {
|
||||
v8::CFunction c_func =
|
||||
v8::CFunction::Make(ApiNumberChecker<bool>::FastCallback, &type_info);
|
||||
CHECK_EQ(c_func.ArgumentCount(), 2);
|
||||
CHECK_EQ(c_func.ArgumentInfo(0).GetType(),
|
||||
v8::CTypeInfo::Type::kUnwrappedApiObject);
|
||||
CHECK_EQ(c_func.ArgumentInfo(0).GetType(), v8::CTypeInfo::Type::kV8Value);
|
||||
CHECK_EQ(c_func.ArgumentInfo(1).GetType(), v8::CTypeInfo::Type::kBool);
|
||||
CHECK_EQ(c_func.ReturnInfo().GetType(), v8::CTypeInfo::Type::kVoid);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace v8 {
|
||||
template <typename T>
|
||||
class WrapperTraits<BasicApiChecker<T, ApiNumberChecker<T>>> {
|
||||
public:
|
||||
static const void* GetTypeInfo() {
|
||||
static const int tag = 0;
|
||||
return reinterpret_cast<const void*>(&tag);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class WrapperTraits<int> {
|
||||
public:
|
||||
static const void* GetTypeInfo() {
|
||||
static const int tag = 0;
|
||||
return reinterpret_cast<const void*>(&tag);
|
||||
}
|
||||
};
|
||||
} // namespace v8
|
||||
#endif // V8_LITE_MODE
|
||||
|
||||
TEST(FastApiCalls) {
|
||||
@ -27663,6 +27727,9 @@ TEST(FastApiCalls) {
|
||||
v8_num(std::numeric_limits<double>::infinity()));
|
||||
CallAndCheck<int32_t>(0, Behavior::kNoException,
|
||||
ApiCheckerResult::kSlowCalled, v8_str("some_string"));
|
||||
CallAndCheck<int32_t>(0, Behavior::kNoException,
|
||||
ApiCheckerResult::kSlowCalled,
|
||||
CompileRun("new Proxy({}, {});"));
|
||||
CallAndCheck<int32_t>(0, Behavior::kNoException,
|
||||
ApiCheckerResult::kSlowCalled,
|
||||
v8::Object::New(isolate));
|
||||
@ -27749,9 +27816,20 @@ TEST(FastApiCalls) {
|
||||
CallWithLessArguments();
|
||||
CallWithMoreArguments();
|
||||
|
||||
// Wrong types of receiver
|
||||
CallWithUnexpectedReceiverType(v8_num(123));
|
||||
CallWithUnexpectedReceiverType(v8_str("str"));
|
||||
CallWithUnexpectedReceiverType(CompileRun("new Proxy({}, {});"));
|
||||
|
||||
// Wrong types for argument of type object
|
||||
CallWithUnexpectedObjectType(v8_num(123));
|
||||
CallWithUnexpectedObjectType(v8_str("str"));
|
||||
CallWithUnexpectedObjectType(CompileRun("new Proxy({}, {});"));
|
||||
|
||||
// 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.
|
||||
#endif // V8_LITE_MODE
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user