Reland "[fastcall] Enable float support on arm64 simulator"

This is a reland of b9ddcbc86f

The original CL was reverted due to an MSAN issue, that is fixed by
moving the signature mapping onto the Isolate (instead of having
per-thread storage, which got invalid on multithreaded compilation).

This CL also contains fixes for the Bazel config and for a data race
when obtaining the PerIsolateSimulatorData.

Original change's description:
> [fastcall] Enable float support on arm64 simulator
>
> This CL adds support for handling calls to C functions with arbitrary
> signatures on the arm64 simulator. It adds infrastructure for
> encoding the signature data from CallDescriptor and FunctionInfo
> classes into a compact representation, stored in the simulator and
> called EncodedCSignature.
>
> Design doc:
> https://docs.google.com/document/d/1ZxOF3GSyNmtU0C0YJvrsydPJj35W_tTJZymeXwfDxoI/edit
>
> This CL is a follow up on the native support added in
> https://chromium-review.googlesource.com/c/v8/v8/+/3182232
> and is partially based on the previous attempt:
> https://chromium-review.googlesource.com/c/v8/v8/+/2343072
>
> Bug: chromium:1052746
> Change-Id: I0991b47bd644b2fc2244c5eb923b085261f04765
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3060486
> Commit-Queue: Maya Lekova <mslekova@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#77744}

Bug: chromium:1052746, chromium:1267854
Change-Id: I89bbd01e33fb1080543d98bcfd4c2d17b5c76861
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3270541
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78018}
This commit is contained in:
Maya Lekova 2021-11-19 11:30:04 +01:00 committed by V8 LUCI CQ
parent e518a2b203
commit d7c3f1cd8a
27 changed files with 1470 additions and 518 deletions

View File

@ -1193,6 +1193,8 @@ filegroup(
"src/execution/arguments-inl.h",
"src/execution/arguments.cc",
"src/execution/arguments.h",
"src/execution/encoded-c-signature.cc",
"src/execution/encoded-c-signature.h",
"src/execution/execution.cc",
"src/execution/execution.h",
"src/execution/frame-constants.h",

View File

@ -2873,6 +2873,7 @@ v8_header_set("v8_internal_headers") {
"src/diagnostics/unwinder.h",
"src/execution/arguments-inl.h",
"src/execution/arguments.h",
"src/execution/encoded-c-signature.h",
"src/execution/execution.h",
"src/execution/frame-constants.h",
"src/execution/frames-inl.h",
@ -4087,6 +4088,7 @@ v8_source_set("v8_base_without_compiler") {
"src/diagnostics/perf-jit.cc",
"src/diagnostics/unwinder.cc",
"src/execution/arguments.cc",
"src/execution/encoded-c-signature.cc",
"src/execution/execution.cc",
"src/execution/frames.cc",
"src/execution/futex-emulation.cc",

View File

@ -249,6 +249,15 @@ class CTypeInfo {
kV8Value,
kApiObject, // This will be deprecated once all users have
// migrated from v8::ApiObject to v8::Local<v8::Value>.
kAny, // This is added to enable untyped representation of fast
// call arguments for test purposes. It can represent any of
// the other types stored in the same memory as a union (see
// the AnyCType struct declared below). This allows for
// uniform passing of arguments w.r.t. their location
// (in a register or on the stack), independent of their
// actual type. It's currently used by the arm64 simulator
// and can be added to the other simulators as well when fast
// calls having both GP and FP params need to be supported.
};
// kCallbackOptionsType is not part of the Type enum
@ -404,6 +413,37 @@ class V8_EXPORT CFunctionInfo {
const CTypeInfo* arg_info_;
};
struct FastApiCallbackOptions;
// Provided for testing.
struct AnyCType {
AnyCType() : int64_value(0) {}
union {
bool bool_value;
int32_t int32_value;
uint32_t uint32_value;
int64_t int64_value;
uint64_t uint64_value;
float float_value;
double double_value;
Local<Object> object_value;
Local<Array> sequence_value;
const FastApiTypedArray<int32_t>* int32_ta_value;
const FastApiTypedArray<uint32_t>* uint32_ta_value;
const FastApiTypedArray<int64_t>* int64_ta_value;
const FastApiTypedArray<uint64_t>* uint64_ta_value;
const FastApiTypedArray<float>* float_ta_value;
const FastApiTypedArray<double>* double_ta_value;
FastApiCallbackOptions* options_value;
};
};
static_assert(
sizeof(AnyCType) == 8,
"The AnyCType struct should have size == 64 bits, as this is assumed "
"by EffectControlLinearizer.");
class V8_EXPORT CFunction {
public:
constexpr CFunction() : address_(nullptr), type_info_(nullptr) {}
@ -460,6 +500,21 @@ class V8_EXPORT CFunction {
return ArgUnwrap<F*>::Make(func);
}
// Provided for testing purposes.
template <typename R, typename... Args, typename R_Patch,
typename... Args_Patch>
static CFunction Make(R (*func)(Args...),
R_Patch (*patching_func)(Args_Patch...)) {
CFunction c_func = ArgUnwrap<R (*)(Args...)>::Make(func);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static_assert(
sizeof...(Args_Patch) == sizeof...(Args),
"The patching function must have the same number of arguments.");
c_func.address_ = reinterpret_cast<void*>(patching_func);
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
return c_func;
}
CFunction(const void* address, const CFunctionInfo* type_info);
private:
@ -555,7 +610,8 @@ class CFunctionInfoImpl : public CFunctionInfo {
kReturnType == CTypeInfo::Type::kInt32 ||
kReturnType == CTypeInfo::Type::kUint32 ||
kReturnType == CTypeInfo::Type::kFloat32 ||
kReturnType == CTypeInfo::Type::kFloat64,
kReturnType == CTypeInfo::Type::kFloat64 ||
kReturnType == CTypeInfo::Type::kAny,
"64-bit int and api object values are not currently "
"supported return types.");
}
@ -606,7 +662,8 @@ struct CTypeInfoTraits {};
V(void, kVoid) \
V(v8::Local<v8::Value>, kV8Value) \
V(v8::Local<v8::Object>, kV8Value) \
V(ApiObject, kApiObject)
V(ApiObject, kApiObject) \
V(AnyCType, kAny)
// ApiObject was a temporary solution to wrap the pointer to the v8::Value.
// Please use v8::Local<v8::Value> in new code for the arguments and

View File

@ -591,6 +591,14 @@ V8 shared library set USING_V8_SHARED.
#define V8_CAGED_POINTERS
#endif
// Helper macros to enable handling of direct C calls in the simulator.
#if (V8_TARGET_ARCH_ARM64 && !V8_HOST_ARCH_ARM64)
#define V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define V8_IF_USE_SIMULATOR(V) , V
#else
#define V8_IF_USE_SIMULATOR(V)
#endif // (V8_TARGET_ARCH_ARM64 && !V8_HOST_ARCH_ARM64)
// clang-format on
#undef V8_HAS_CPP_ATTRIBUTE

View File

@ -4,6 +4,7 @@
#include "src/codegen/external-reference.h"
#include "include/v8-fast-api-calls.h"
#include "src/api/api.h"
#include "src/base/ieee754.h"
#include "src/codegen/cpu-features.h"
@ -11,10 +12,11 @@
#include "src/date/date.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/encoded-c-signature.h"
#include "src/execution/isolate-utils.h"
#include "src/execution/isolate.h"
#include "src/execution/microtask-queue.h"
#include "src/execution/simulator-base.h"
#include "src/execution/simulator.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap.h"
#include "src/ic/stub-cache.h"
@ -172,9 +174,19 @@ static ExternalReference::Type BuiltinCallTypeForResultSize(int result_size) {
UNREACHABLE();
}
// static
ExternalReference ExternalReference::Create(ApiFunction* fun, Type type) {
return ExternalReference(Redirect(fun->address(), type));
}
// static
ExternalReference ExternalReference::Create(
ApiFunction* fun, Type type = ExternalReference::BUILTIN_CALL) {
Isolate* isolate, ApiFunction* fun, Type type, Address* c_functions,
const CFunctionInfo* const* c_signatures, unsigned num_functions) {
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
isolate->simulator_data()->RegisterFunctionsAndSignatures(
c_functions, c_signatures, num_functions);
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
return ExternalReference(Redirect(fun->address(), type));
}

View File

@ -11,6 +11,7 @@
namespace v8 {
class ApiFunction;
class CFunctionInfo;
namespace internal {
@ -408,6 +409,15 @@ class ExternalReference {
static ExternalReference Create(StatsCounter* counter);
static V8_EXPORT_PRIVATE ExternalReference Create(ApiFunction* ptr,
Type type);
// The following version is used by JSCallReducer in the compiler
// to create a reference for a fast API call, with one or more
// overloads. In simulator builds, it additionally "registers"
// the overloads with the simulator to ensure it maintains a
// mapping of callable Address'es to a function signature, encoding
// GP and FP arguments.
static V8_EXPORT_PRIVATE ExternalReference
Create(Isolate* isolate, ApiFunction* ptr, Type type, Address* c_functions,
const CFunctionInfo* const* c_signatures, unsigned num_functions);
static ExternalReference Create(const Runtime::Function* f);
static ExternalReference Create(IsolateAddressId id, Isolate* isolate);
static ExternalReference Create(Runtime::FunctionId id);

View File

@ -4985,6 +4985,10 @@ MachineType MachineTypeFor(CTypeInfo::Type type) {
return MachineType::Uint32();
case CTypeInfo::Type::kInt64:
return MachineType::Int64();
case CTypeInfo::Type::kAny:
static_assert(sizeof(AnyCType) == 8,
"CTypeInfo::Type::kAny is assumed to be of size 64 bits.");
return MachineType::Int64();
case CTypeInfo::Type::kUint64:
return MachineType::Uint64();
case CTypeInfo::Type::kFloat32:
@ -5329,7 +5333,7 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
StoreRepresentation(MachineRepresentation::kWord32, kNoWriteBarrier),
stack_slot,
static_cast<int>(offsetof(v8::FastApiCallbackOptions, fallback)),
__ ZeroConstant());
__ Int32Constant(0));
__ Store(StoreRepresentation(MachineType::PointerRepresentation(),
kNoWriteBarrier),
stack_slot,
@ -5466,6 +5470,11 @@ Node* EffectControlLinearizer::LowerFastApiCall(Node* node) {
case CTypeInfo::Type::kV8Value:
case CTypeInfo::Type::kApiObject:
UNREACHABLE();
case CTypeInfo::Type::kAny:
fast_call_result =
ChangeFloat64ToTagged(__ ChangeInt64ToFloat64(c_call_result),
CheckForMinusZeroMode::kCheckForMinusZero);
break;
}
auto merge = __ MakeLabel(MachineRepresentation::kTagged);

View File

@ -27,6 +27,7 @@ ElementsKind GetTypedArrayElementsKind(CTypeInfo::Type type) {
case CTypeInfo::Type::kBool:
case CTypeInfo::Type::kV8Value:
case CTypeInfo::Type::kApiObject:
case CTypeInfo::Type::kAny:
UNREACHABLE();
}
}

View File

@ -92,8 +92,8 @@ const int kMaxFastLiteralProperties = JSObject::kMaxInObjectProperties;
// to add support for IA32, because it has a totally different approach
// (using FP stack). As support is added to more platforms, please make sure
// to list them here in order to enable tests of this functionality.
#if defined(V8_TARGET_ARCH_X64) || \
(defined(V8_TARGET_ARCH_ARM64) && !defined(USE_SIMULATOR))
// Make sure to sync the following with src/d8/d8-test.cc.
#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64)
#define V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#endif

View File

@ -963,7 +963,10 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
CallDescriptor::kNeedsFrameState);
ApiFunction api_function(call_handler_info.callback());
ExternalReference function_reference = ExternalReference::Create(
&api_function, ExternalReference::DIRECT_API_CALL);
isolate(), &api_function, ExternalReference::DIRECT_API_CALL,
function_template_info_.c_functions().data(),
function_template_info_.c_signatures().data(),
static_cast<unsigned>(function_template_info_.c_functions().size()));
Node* continuation_frame_state =
CreateGenericLazyDeoptContinuationFrameState(

View File

@ -208,6 +208,25 @@ int CallDescriptor::CalculateFixedFrameSize(CodeKind code_kind) const {
UNREACHABLE();
}
EncodedCSignature CallDescriptor::ToEncodedCSignature() const {
int parameter_count = static_cast<int>(ParameterCount());
EncodedCSignature sig(parameter_count);
CHECK_LT(parameter_count, EncodedCSignature::kInvalidParamCount);
for (int i = 0; i < parameter_count; ++i) {
if (IsFloatingPoint(GetParameterType(i).representation())) {
sig.SetFloat(i);
}
}
if (ReturnCount() > 0) {
DCHECK_EQ(1, ReturnCount());
if (IsFloatingPoint(GetReturnType(0).representation())) {
sig.SetFloat(EncodedCSignature::kReturnIndex);
}
}
return sig;
}
void CallDescriptor::ComputeParamCounts() const {
gp_param_count_ = 0;
fp_param_count_ = 0;

View File

@ -15,6 +15,7 @@
#include "src/common/globals.h"
#include "src/compiler/frame.h"
#include "src/compiler/operator.h"
#include "src/execution/encoded-c-signature.h"
#include "src/runtime/runtime.h"
#include "src/zone/zone.h"
@ -444,6 +445,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final
return allocatable_registers_ != 0;
}
EncodedCSignature ToEncodedCSignature() const;
private:
void ComputeParamCounts() const;

View File

@ -1821,6 +1821,7 @@ class RepresentationSelector {
// path.
case CTypeInfo::Type::kInt64:
case CTypeInfo::Type::kUint64:
case CTypeInfo::Type::kAny:
return UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, feedback);
case CTypeInfo::Type::kFloat32:
case CTypeInfo::Type::kFloat64:

View File

@ -17,8 +17,7 @@
// and resetting these counters.
// Make sure to sync the following with src/compiler/globals.h.
#if defined(V8_TARGET_ARCH_X64) || \
(defined(V8_TARGET_ARCH_ARM64) && !defined(USE_SIMULATOR))
#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64)
#define V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#endif
@ -40,6 +39,22 @@ namespace {
class FastCApiObject {
public:
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static AnyCType AddAllFastCallbackPatch(AnyCType receiver,
AnyCType should_fallback,
AnyCType arg_i32, AnyCType arg_u32,
AnyCType arg_i64, AnyCType arg_u64,
AnyCType arg_f32, AnyCType arg_f64,
AnyCType options) {
AnyCType ret;
ret.double_value = AddAllFastCallback(
receiver.object_value, should_fallback.bool_value, arg_i32.int32_value,
arg_u32.uint32_value, arg_i64.int64_value, arg_u64.uint64_value,
arg_f32.float_value, arg_f64.double_value, *options.options_value);
return ret;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static double AddAllFastCallback(Local<Object> receiver, bool should_fallback,
int32_t arg_i32, uint32_t arg_u32,
int64_t arg_i64, uint64_t arg_u64,
@ -52,6 +67,8 @@ class FastCApiObject {
if (should_fallback) {
options.fallback = 1;
return 0;
} else {
options.fallback = 0;
}
return static_cast<double>(arg_i32) + static_cast<double>(arg_u32) +
@ -99,6 +116,24 @@ class FastCApiObject {
#else
typedef int32_t Type;
#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static AnyCType AddAllSequenceFastCallbackPatch(AnyCType receiver,
AnyCType should_fallback,
AnyCType seq_arg,
AnyCType options) {
AnyCType ret;
#ifdef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
ret.double_value = AddAllSequenceFastCallback(
receiver.object_value, should_fallback.bool_value,
seq_arg.sequence_value, *options.options_value);
#else
ret.int32_value = AddAllSequenceFastCallback(
receiver.object_value, should_fallback.bool_value,
seq_arg.sequence_value, *options.options_value);
#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
return ret;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static Type AddAllSequenceFastCallback(Local<Object> receiver,
bool should_fallback,
Local<Array> seq_arg,
@ -192,6 +227,57 @@ class FastCApiObject {
}
args.GetReturnValue().Set(Number::New(isolate, sum));
}
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <typename T>
static const FastApiTypedArray<T>* AnyCTypeToTypedArray(AnyCType arg);
template <>
const FastApiTypedArray<int32_t>* AnyCTypeToTypedArray<int32_t>(
AnyCType arg) {
return arg.int32_ta_value;
}
template <>
const FastApiTypedArray<uint32_t>* AnyCTypeToTypedArray<uint32_t>(
AnyCType arg) {
return arg.uint32_ta_value;
}
template <>
const FastApiTypedArray<int64_t>* AnyCTypeToTypedArray<int64_t>(
AnyCType arg) {
return arg.int64_ta_value;
}
template <>
const FastApiTypedArray<uint64_t>* AnyCTypeToTypedArray<uint64_t>(
AnyCType arg) {
return arg.uint64_ta_value;
}
template <>
const FastApiTypedArray<float>* AnyCTypeToTypedArray<float>(AnyCType arg) {
return arg.float_ta_value;
}
template <>
const FastApiTypedArray<double>* AnyCTypeToTypedArray<double>(AnyCType arg) {
return arg.double_ta_value;
}
template <typename T>
static AnyCType AddAllTypedArrayFastCallbackPatch(AnyCType receiver,
AnyCType should_fallback,
AnyCType typed_array_arg,
AnyCType options) {
AnyCType ret;
#ifdef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
ret.double_value = AddAllTypedArrayFastCallback(
receiver.object_value, should_fallback.bool_value,
*AnyCTypeToTypedArray<T>(typed_array_arg), *options.options_value);
#else
ret.int32_value = AddAllTypedArrayFastCallback(
receiver.object_value, should_fallback.bool_value,
*AnyCTypeToTypedArray<T>(typed_array_arg), *options.options_value);
#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
return ret;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <typename T>
static Type AddAllTypedArrayFastCallback(
Local<Object> receiver, bool should_fallback,
@ -276,6 +362,20 @@ class FastCApiObject {
UNREACHABLE();
}
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static AnyCType Add32BitIntFastCallbackPatch(AnyCType receiver,
AnyCType should_fallback,
AnyCType arg_i32,
AnyCType arg_u32,
AnyCType options) {
AnyCType ret;
ret.int32_value = Add32BitIntFastCallback(
receiver.object_value, should_fallback.bool_value, arg_i32.int32_value,
arg_u32.uint32_value, *options.options_value);
return ret;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static int Add32BitIntFastCallback(v8::Local<v8::Object> receiver,
bool should_fallback, int32_t arg_i32,
uint32_t arg_u32,
@ -311,6 +411,30 @@ class FastCApiObject {
args.GetReturnValue().Set(Number::New(isolate, sum));
}
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static AnyCType AddAll32BitIntFastCallback_6ArgsPatch(
AnyCType receiver, AnyCType should_fallback, AnyCType arg1_i32,
AnyCType arg2_i32, AnyCType arg3_i32, AnyCType arg4_u32,
AnyCType arg5_u32, AnyCType arg6_u32, AnyCType options) {
AnyCType ret;
ret.int32_value = AddAll32BitIntFastCallback_6Args(
receiver.object_value, should_fallback.bool_value, arg1_i32.int32_value,
arg2_i32.int32_value, arg3_i32.int32_value, arg4_u32.uint32_value,
arg5_u32.uint32_value, arg6_u32.uint32_value, *options.options_value);
return ret;
}
static AnyCType AddAll32BitIntFastCallback_5ArgsPatch(
AnyCType receiver, AnyCType should_fallback, AnyCType arg1_i32,
AnyCType arg2_i32, AnyCType arg3_i32, AnyCType arg4_u32,
AnyCType arg5_u32, AnyCType options) {
AnyCType arg6;
arg6.uint32_value = 0;
return AddAll32BitIntFastCallback_6ArgsPatch(
receiver, should_fallback, arg1_i32, arg2_i32, arg3_i32, arg4_u32,
arg5_u32, arg6, options);
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
static int AddAll32BitIntFastCallback_6Args(
Local<Object> receiver, bool should_fallback, int32_t arg1_i32,
int32_t arg2_i32, int32_t arg3_i32, uint32_t arg4_u32, uint32_t arg5_u32,
@ -520,7 +644,8 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
Local<Signature> signature = Signature::New(isolate, api_obj_ctor);
{
CFunction add_all_c_func =
CFunction::Make(FastCApiObject::AddAllFastCallback);
CFunction::Make(FastCApiObject::AddAllFastCallback V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllFastCallbackPatch));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all",
FunctionTemplate::New(isolate, FastCApiObject::AddAllSlowCallback,
@ -528,8 +653,9 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_all_c_func));
CFunction add_all_seq_c_func =
CFunction::Make(FastCApiObject::AddAllSequenceFastCallback);
CFunction add_all_seq_c_func = CFunction::Make(
FastCApiObject::AddAllSequenceFastCallback V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllSequenceFastCallbackPatch));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_sequence",
FunctionTemplate::New(
@ -537,8 +663,11 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_all_seq_c_func));
CFunction add_all_int32_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<int32_t>);
CFunction add_all_int32_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<int32_t>
V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<int32_t>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_int32_typed_array",
FunctionTemplate::New(
@ -546,8 +675,10 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_all_int32_typed_array_c_func));
CFunction add_all_int64_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<int64_t>);
CFunction add_all_int64_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<int64_t>
V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<int64_t>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_int64_typed_array",
FunctionTemplate::New(
@ -555,8 +686,10 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
Local<Value>(), signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, &add_all_int64_typed_array_c_func));
CFunction add_all_uint64_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<uint64_t>);
CFunction add_all_uint64_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<uint64_t>
V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<uint64_t>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_uint64_typed_array",
FunctionTemplate::New(
@ -565,8 +698,10 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
SideEffectType::kHasSideEffect,
&add_all_uint64_typed_array_c_func));
CFunction add_all_uint32_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<uint32_t>);
CFunction add_all_uint32_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<uint32_t>
V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<uint32_t>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_uint32_typed_array",
FunctionTemplate::New(
@ -575,8 +710,9 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
SideEffectType::kHasSideEffect,
&add_all_uint32_typed_array_c_func));
CFunction add_all_float32_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<float>);
CFunction add_all_float32_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<float> V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<float>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_float32_typed_array",
FunctionTemplate::New(
@ -585,8 +721,10 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
SideEffectType::kHasSideEffect,
&add_all_float32_typed_array_c_func));
CFunction add_all_float64_typed_array_c_func =
CFunction::Make(FastCApiObject::AddAllTypedArrayFastCallback<double>);
CFunction add_all_float64_typed_array_c_func = CFunction::Make(
FastCApiObject::AddAllTypedArrayFastCallback<double>
V8_IF_USE_SIMULATOR(
FastCApiObject::AddAllTypedArrayFastCallbackPatch<double>));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_all_float64_typed_array",
FunctionTemplate::New(
@ -619,10 +757,12 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, {add_all_invalid_overloads, 2}));
CFunction add_all_32bit_int_6args_c_func =
CFunction::Make(FastCApiObject::AddAll32BitIntFastCallback_6Args);
CFunction add_all_32bit_int_5args_c_func =
CFunction::Make(FastCApiObject::AddAll32BitIntFastCallback_5Args);
CFunction add_all_32bit_int_6args_c_func = CFunction::Make(
FastCApiObject::AddAll32BitIntFastCallback_6Args V8_IF_USE_SIMULATOR(
FastCApiObject::AddAll32BitIntFastCallback_6ArgsPatch));
CFunction add_all_32bit_int_5args_c_func = CFunction::Make(
FastCApiObject::AddAll32BitIntFastCallback_5Args V8_IF_USE_SIMULATOR(
FastCApiObject::AddAll32BitIntFastCallback_5ArgsPatch));
const CFunction c_function_overloads[] = {add_all_32bit_int_6args_c_func,
add_all_32bit_int_5args_c_func};
api_obj_ctor->PrototypeTemplate()->Set(
@ -632,8 +772,9 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
signature, 1, ConstructorBehavior::kThrow,
SideEffectType::kHasSideEffect, {c_function_overloads, 2}));
CFunction add_32bit_int_c_func =
CFunction::Make(FastCApiObject::Add32BitIntFastCallback);
CFunction add_32bit_int_c_func = CFunction::Make(
FastCApiObject::Add32BitIntFastCallback V8_IF_USE_SIMULATOR(
FastCApiObject::Add32BitIntFastCallbackPatch));
api_obj_ctor->PrototypeTemplate()->Set(
isolate, "add_32bit_int",
FunctionTemplate::New(

View File

@ -14,7 +14,6 @@
#include <cstdarg>
#include <type_traits>
#include "src/base/lazy-instance.h"
#include "src/base/overflowing-math.h"
#include "src/base/platform/platform.h"
#include "src/base/platform/wrappers.h"
@ -503,6 +502,126 @@ void UnsafeDirectGetterCall(int64_t function, int64_t arg0, int64_t arg1) {
target(arg0, arg1);
}
using MixedRuntimeCall_0 = AnyCType (*)();
#define BRACKETS(ident, N) ident[N]
#define REP_0(expr, FMT)
#define REP_1(expr, FMT) FMT(expr, 0)
#define REP_2(expr, FMT) REP_1(expr, FMT), FMT(expr, 1)
#define REP_3(expr, FMT) REP_2(expr, FMT), FMT(expr, 2)
#define REP_4(expr, FMT) REP_3(expr, FMT), FMT(expr, 3)
#define REP_5(expr, FMT) REP_4(expr, FMT), FMT(expr, 4)
#define REP_6(expr, FMT) REP_5(expr, FMT), FMT(expr, 5)
#define REP_7(expr, FMT) REP_6(expr, FMT), FMT(expr, 6)
#define REP_8(expr, FMT) REP_7(expr, FMT), FMT(expr, 7)
#define REP_9(expr, FMT) REP_8(expr, FMT), FMT(expr, 8)
#define REP_10(expr, FMT) REP_9(expr, FMT), FMT(expr, 9)
#define REP_11(expr, FMT) REP_10(expr, FMT), FMT(expr, 10)
#define REP_12(expr, FMT) REP_11(expr, FMT), FMT(expr, 11)
#define REP_13(expr, FMT) REP_12(expr, FMT), FMT(expr, 12)
#define REP_14(expr, FMT) REP_13(expr, FMT), FMT(expr, 13)
#define REP_15(expr, FMT) REP_14(expr, FMT), FMT(expr, 14)
#define REP_16(expr, FMT) REP_15(expr, FMT), FMT(expr, 15)
#define REP_17(expr, FMT) REP_16(expr, FMT), FMT(expr, 16)
#define REP_18(expr, FMT) REP_17(expr, FMT), FMT(expr, 17)
#define REP_19(expr, FMT) REP_18(expr, FMT), FMT(expr, 18)
#define REP_20(expr, FMT) REP_19(expr, FMT), FMT(expr, 19)
#define GEN_MAX_PARAM_COUNT(V) \
V(0) \
V(1) \
V(2) \
V(3) \
V(4) \
V(5) \
V(6) \
V(7) \
V(8) \
V(9) \
V(10) \
V(11) \
V(12) \
V(13) \
V(14) \
V(15) \
V(16) \
V(17) \
V(18) \
V(19) \
V(20)
#define MIXED_RUNTIME_CALL(N) \
using MixedRuntimeCall_##N = AnyCType (*)(REP_##N(AnyCType arg, CONCAT));
GEN_MAX_PARAM_COUNT(MIXED_RUNTIME_CALL)
#undef MIXED_RUNTIME_CALL
#define CALL_ARGS(N) REP_##N(args, BRACKETS)
#define CALL_TARGET_VARARG(N) \
if (signature.ParameterCount() == N) { /* NOLINT */ \
MixedRuntimeCall_##N target = \
reinterpret_cast<MixedRuntimeCall_##N>(target_address); \
result = target(CALL_ARGS(N)); \
} else /* NOLINT */
void Simulator::CallAnyCTypeFunction(Address target_address,
const EncodedCSignature& signature) {
TraceSim("Type: mixed types BUILTIN_CALL\n");
const int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());
const double* double_stack_pointer = reinterpret_cast<double*>(sp());
int num_gp_params = 0, num_fp_params = 0, num_stack_params = 0;
CHECK_LE(signature.ParameterCount(), kMaxCParameters);
static_assert(sizeof(AnyCType) == 8, "AnyCType is assumed to be 64-bit.");
AnyCType args[kMaxCParameters];
// The first 8 parameters of each type (GP or FP) are placed in corresponding
// registers. The rest are expected to be on the stack, where each parameter
// type counts on its own. For example a function like:
// foo(int i1, ..., int i9, float f1, float f2) will use up all 8 GP
// registers, place i9 on the stack, and place f1 and f2 in FP registers.
// Source: https://developer.arm.com/documentation/ihi0055/d/, section
// "Parameter Passing".
for (int i = 0; i < signature.ParameterCount(); ++i) {
if (signature.IsFloat(i)) {
if (num_fp_params < 8) {
args[i].double_value = dreg(num_fp_params++);
} else {
args[i].double_value = double_stack_pointer[num_stack_params++];
}
} else {
if (num_gp_params < 8) {
args[i].int64_value = xreg(num_gp_params++);
} else {
args[i].int64_value = stack_pointer[num_stack_params++];
}
}
}
AnyCType result;
GEN_MAX_PARAM_COUNT(CALL_TARGET_VARARG)
/* else */ {
UNREACHABLE();
}
static_assert(20 == kMaxCParameters,
"If you've changed kMaxCParameters, please change the "
"GEN_MAX_PARAM_COUNT macro.");
#undef CALL_TARGET_VARARG
#undef CALL_ARGS
#undef GEN_MAX_PARAM_COUNT
#ifdef DEBUG
CorruptAllCallerSavedCPURegisters();
#endif
if (signature.IsReturnFloat()) {
set_dreg(0, result.double_value);
} else {
set_xreg(0, result.int64_value);
}
}
void Simulator::DoRuntimeCall(Instruction* instr) {
Redirection* redirection = Redirection::FromInstruction(instr);
@ -523,6 +642,20 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
FATAL("ALIGNMENT EXCEPTION");
}
Address func_addr =
reinterpret_cast<Address>(redirection->external_function());
SimulatorData* simulator_data = isolate_->simulator_data();
DCHECK_NOT_NULL(simulator_data);
const EncodedCSignature& signature =
simulator_data->GetSignatureForTarget(func_addr);
if (signature.IsValid()) {
CHECK(redirection->type() == ExternalReference::FAST_C_CALL);
CallAnyCTypeFunction(external, signature);
set_lr(return_address);
set_pc(return_address);
return;
}
int64_t* stack_pointer = reinterpret_cast<int64_t*>(sp());
const int64_t arg0 = xreg(0);
@ -552,17 +685,6 @@ void Simulator::DoRuntimeCall(Instruction* instr) {
TraceSim("Type: Unknown.\n");
UNREACHABLE();
// FAST_C_CALL is temporarily handled here as well, because we lack
// proper support for direct C calls with FP params in the simulator.
// The generic BUILTIN_CALL path assumes all parameters are passed in
// the GP registers, thus supporting calling the slow callback without
// crashing. The reason for that is that in the mjsunit tests we check
// the `fast_c_api.supports_fp_params` (which is false on non-simulator
// builds for arm/arm64), thus we expect that the slow path will be
// called. And since the slow path passes the arguments as a `const
// FunctionCallbackInfo<Value>&` (which is a GP argument), the call is
// made correctly.
case ExternalReference::FAST_C_CALL:
case ExternalReference::BUILTIN_CALL:
#if defined(V8_OS_WIN)
{
@ -6264,4 +6386,6 @@ V8_EXPORT_PRIVATE extern bool _v8_internal_Simulator_ExecDebugCommand(
return simulator->ExecDebugCommand(std::move(command_copy));
}
#undef BRACKETS
#endif // USE_SIMULATOR

View File

@ -2449,6 +2449,9 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
V8_EXPORT_PRIVATE void CallImpl(Address entry, CallArgument* args);
void CallAnyCTypeFunction(Address target_address,
const EncodedCSignature& signature);
// Read floating point return values.
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type

View File

@ -0,0 +1,41 @@
// 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.
#include "src/execution/encoded-c-signature.h"
#include "include/v8-fast-api-calls.h"
#include "src/base/bits.h"
#include "src/base/logging.h"
namespace v8 {
namespace internal {
int EncodedCSignature::FPParameterCount() const {
CHECK(IsValid());
return base::bits::CountPopulation(bitfield_ & ~(1 << kReturnIndex));
}
EncodedCSignature::EncodedCSignature(const CFunctionInfo* signature) {
parameter_count_ = static_cast<int>(signature->ArgumentCount());
for (int i = 0; i < parameter_count_; ++i) {
if (signature->ArgumentInfo(i).GetSequenceType() ==
CTypeInfo::SequenceType::kScalar &&
CTypeInfo::IsFloatingPointType(signature->ArgumentInfo(i).GetType())) {
SetFloat(i);
}
}
// The struct holding the options of the CFunction (e.g. callback) is not
// included in the number of regular parameters, so we add it manually here.
if (signature->HasOptions()) {
parameter_count_++;
}
if (signature->ReturnInfo().GetSequenceType() ==
CTypeInfo::SequenceType::kScalar &&
CTypeInfo::IsFloatingPointType(signature->ReturnInfo().GetType())) {
SetFloat(EncodedCSignature::kReturnIndex);
}
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,60 @@
// 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.
#ifndef V8_EXECUTION_ENCODED_C_SIGNATURE_H_
#define V8_EXECUTION_ENCODED_C_SIGNATURE_H_
#include <stdint.h>
namespace v8 {
class CFunctionInfo;
namespace internal {
namespace compiler {
class CallDescriptor;
} // namespace compiler
// This structure represents whether the parameters for a given function
// should be read from general purpose or FP registers. parameter_count =
// kInvalidParamCount represents "invalid" signature, a placeholder for
// non-existing elements in the mapping.
struct EncodedCSignature {
public:
EncodedCSignature() = default;
EncodedCSignature(uint32_t bitfield, int parameter_count)
: bitfield_(bitfield), parameter_count_(parameter_count) {}
explicit EncodedCSignature(int parameter_count)
: parameter_count_(parameter_count) {}
explicit EncodedCSignature(const CFunctionInfo* signature);
bool IsFloat(int index) const {
return (bitfield_ & (static_cast<uint32_t>(1) << index)) != 0;
}
bool IsReturnFloat() const { return IsFloat(kReturnIndex); }
void SetFloat(int index) { bitfield_ |= (static_cast<uint32_t>(1) << index); }
bool IsValid() const { return parameter_count_ < kInvalidParamCount; }
int ParameterCount() const { return parameter_count_; }
int FPParameterCount() const;
static const EncodedCSignature& Invalid() {
static EncodedCSignature kInvalid = {0, kInvalidParamCount};
return kInvalid;
}
static const int kReturnIndex = 31;
static const int kInvalidParamCount = kReturnIndex + 1;
private:
uint32_t bitfield_ = 0; // Bit i is set if floating point, unset if not.
int parameter_count_ = kInvalidParamCount;
};
} // namespace internal
} // namespace v8
#endif // V8_EXECUTION_ENCODED_C_SIGNATURE_H_

View File

@ -129,6 +129,10 @@
#include "src/heap/conservative-stack-visitor.h"
#endif
#if USE_SIMULATOR
#include "src/execution/simulator-base.h"
#endif
extern "C" const uint8_t* v8_Default_embedded_blob_code_;
extern "C" uint32_t v8_Default_embedded_blob_code_size_;
extern "C" const uint8_t* v8_Default_embedded_blob_data_;
@ -3264,6 +3268,11 @@ void Isolate::Deinit() {
string_table_.reset();
#if USE_SIMULATOR
delete simulator_data_;
simulator_data_ = nullptr;
#endif
// After all concurrent tasks are stopped, we know for sure that stats aren't
// updated anymore.
DumpAndResetStats();
@ -3733,6 +3742,10 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
}
baseline_batch_compiler_ = new baseline::BaselineBatchCompiler(this);
#if USE_SIMULATOR
simulator_data_ = new SimulatorData;
#endif
// Enable logging before setting up the heap
logger_->SetUp(this);

View File

@ -50,6 +50,15 @@ class UMemory;
} // namespace U_ICU_NAMESPACE
#endif // V8_INTL_SUPPORT
#if USE_SIMULATOR
#include "src/execution/encoded-c-signature.h"
namespace v8 {
namespace internal {
class SimulatorData;
}
} // namespace v8
#endif
namespace v8_inspector {
class V8Inspector;
} // namespace v8_inspector
@ -1871,6 +1880,10 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
bool OwnsStringTable() { return !FLAG_shared_string_table || is_shared(); }
#if USE_SIMULATOR
SimulatorData* simulator_data() { return simulator_data_; }
#endif
private:
explicit Isolate(std::unique_ptr<IsolateAllocator> isolate_allocator,
bool is_shared);
@ -2327,6 +2340,10 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
// Isolate::Delete() are used for Isolate creation and deletion.
void* operator new(size_t, void* ptr) { return ptr; }
#if USE_SIMULATOR
SimulatorData* simulator_data_ = nullptr;
#endif
friend class heap::HeapTester;
friend class GlobalSafepoint;
friend class TestSerializer;

View File

@ -96,6 +96,31 @@ Redirection* Redirection::Get(Address external_function,
return new Redirection(external_function, type);
}
void SimulatorData::RegisterFunctionsAndSignatures(
Address* c_functions, const CFunctionInfo* const* c_signatures,
unsigned num_functions) {
base::MutexGuard guard(&signature_map_mutex_);
for (unsigned i = 0; i < num_functions; ++i) {
EncodedCSignature sig(c_signatures[i]);
AddSignatureForTarget(c_functions[i], sig);
}
}
void SimulatorData::AddSignatureForTarget(Address target,
const EncodedCSignature& signature) {
target_to_signature_table_[target] = signature;
}
const EncodedCSignature& SimulatorData::GetSignatureForTarget(Address target) {
base::MutexGuard guard(&signature_map_mutex_);
auto entry = target_to_signature_table_.find(target);
if (entry != target_to_signature_table_.end()) {
const EncodedCSignature& sig = entry->second;
return sig;
}
return EncodedCSignature::Invalid();
}
} // namespace internal
} // namespace v8

View File

@ -7,6 +7,9 @@
#include <type_traits>
#ifdef V8_TARGET_ARCH_ARM64
#include "include/v8-fast-api-calls.h"
#endif // V8_TARGET_ARCH_ARM64
#include "src/base/hashmap.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
@ -68,6 +71,16 @@ class SimulatorBase {
return Object(ret);
}
#ifdef V8_TARGET_ARCH_ARM64
template <typename T>
static typename std::enable_if<std::is_same<T, v8::AnyCType>::value, T>::type
ConvertReturn(intptr_t ret) {
v8::AnyCType result;
result.int64_value = static_cast<int64_t>(ret);
return result;
}
#endif // V8_TARGET_ARCH_ARM64
// Convert back void return type (i.e. no return).
template <typename T>
static typename std::enable_if<std::is_void<T>::value, T>::type ConvertReturn(
@ -106,6 +119,13 @@ class SimulatorBase {
ConvertArg(T arg) {
return reinterpret_cast<intptr_t>(arg);
}
template <typename T>
static
typename std::enable_if<std::is_floating_point<T>::value, intptr_t>::type
ConvertArg(T arg) {
UNREACHABLE();
}
};
// When the generated code calls an external reference we need to catch that in
@ -176,6 +196,39 @@ class Redirection {
#endif
};
class SimulatorData {
public:
// Calls AddSignatureForTarget for each function and signature, registering
// an encoded version of the signature within a mapping maintained by the
// simulator (from function address -> encoded signature). The function
// is supposed to be called whenever one compiles a fast API function with
// possibly multiple overloads.
// Note that this function is called from one or more compiler threads,
// while the main thread might be reading at the same time from the map, so
// both Register* and Get* are guarded with a single mutex.
void RegisterFunctionsAndSignatures(Address* c_functions,
const CFunctionInfo* const* c_signatures,
unsigned num_functions);
// The following method is used by the simulator itself to query
// whether a signature is registered for the call target and use this
// information to address arguments correctly (load them from either GP or
// FP registers, or from the stack).
const EncodedCSignature& GetSignatureForTarget(Address target);
// This method is exposed only for tests, which don't need synchronisation.
void AddSignatureForTargetForTesting(Address target,
const EncodedCSignature& signature) {
AddSignatureForTarget(target, signature);
}
private:
void AddSignatureForTarget(Address target,
const EncodedCSignature& signature);
v8::base::Mutex signature_map_mutex_;
typedef std::unordered_map<Address, EncodedCSignature> TargetToSignatureTable;
TargetToSignatureTable target_to_signature_table_;
};
} // namespace internal
} // namespace v8

View File

@ -122,9 +122,13 @@ class GeneratedCode {
// Starboard is a platform abstraction interface that also include Windows
// platforms like UWP.
#if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) && \
!defined(V8_OS_STARBOARD)
FATAL("Generated code execution not possible during cross-compilation.");
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN)
!defined(V8_OS_STARBOARD) && !defined(V8_TARGET_ARCH_ARM)
FATAL(
"Generated code execution not possible during cross-compilation."
"Also, generic C function calls are not implemented on 32-bit arm "
"yet.");
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) &&
// !defined(V8_OS_STARBOARD) && !defined(V8_TARGET_ARCH_ARM)
return Simulator::current(isolate_)->template Call<Return>(
reinterpret_cast<Address>(fn_ptr_), args...);
}

View File

@ -5,6 +5,10 @@
#ifndef V8_COMPILER_C_SIGNATURE_H_
#define V8_COMPILER_C_SIGNATURE_H_
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#include "include/v8-fast-api-calls.h"
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#include "src/codegen/machine-type.h"
namespace v8 {
@ -42,6 +46,12 @@ inline constexpr MachineType MachineTypeForC() {
FOREACH_CTYPE_MACHINE_TYPE_MAPPING(DECLARE_TEMPLATE_SPECIALIZATION)
#undef DECLARE_TEMPLATE_SPECIALIZATION
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <>
inline MachineType constexpr MachineTypeForC<v8::AnyCType>() {
return MachineType::Int64();
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
// Helper for building machine signatures from C types.
class CSignature : public MachineSignature {
protected:

View File

@ -381,7 +381,12 @@ TEST(RunCallFloat64Pow) {
template <typename T>
MachineType MachineTypeForCType() {
UNREACHABLE();
return MachineType::AnyTagged();
}
template <>
MachineType MachineTypeForCType<int64_t>() {
return MachineType::Int64();
}
template <>
@ -394,93 +399,176 @@ MachineType MachineTypeForCType<double>() {
return MachineType::Float64();
}
template <>
MachineType MachineTypeForCType<float>() {
return MachineType::Float32();
}
#define SIGNATURE_TYPES(TYPE, IDX, VALUE) MachineTypeForCType<TYPE>()
#define SIGNATURE_TYPES_END(TYPE, IDX, VALUE) MachineTypeForCType<TYPE>()
#define SIGNATURE_TYPES(TYPE, IDX, VALUE) SIGNATURE_TYPES_END(TYPE, IDX, VALUE),
#define PARAM_PAIRS_END(TYPE, IDX, VALUE) \
#define PARAM_PAIRS(TYPE, IDX, VALUE) \
std::make_pair(MachineTypeForCType<TYPE>(), m.Parameter(IDX))
#define PARAM_PAIRS(TYPE, IDX, VALUE) PARAM_PAIRS_END(TYPE, IDX, VALUE),
#define CALL_ARGS(TYPE, IDX, VALUE) static_cast<TYPE>(VALUE)
#define CALL_ARGS_END(TYPE, IDX, VALUE) static_cast<TYPE>(VALUE)
#define CALL_ARGS(TYPE, IDX, VALUE) CALL_ARGS_END(TYPE, IDX, VALUE),
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
union Int64OrDoubleUnion {
int64_t int64_t_value;
double double_value;
};
#define COMPARE_ARG_I_END(TYPE, IDX, VALUE) (arg##IDX == VALUE)
#define COMPARE_ARG_I(TYPE, IDX, VALUE) COMPARE_ARG_I_END(TYPE, IDX, VALUE)&&
#define CHECK_ARG_I(TYPE, IDX, VALUE) \
(result = result && (arg##IDX.TYPE##_value == VALUE))
#define SIGNATURE_TEST(NAME, SIGNATURE, FUNC) \
TEST(NAME) { \
RawMachineAssemblerTester<int32_t> m(SIGNATURE(SIGNATURE_TYPES)); \
\
Address func_address = FUNCTION_ADDR(&FUNC); \
ExternalReference::Type dummy_type = ExternalReference::BUILTIN_CALL; \
ApiFunction func(func_address); \
ExternalReference ref = ExternalReference::Create(&func, dummy_type); \
\
Node* function = m.ExternalConstant(ref); \
m.Return(m.CallCFunction(function, MachineType::Int32(), \
SIGNATURE(PARAM_PAIRS))); \
\
int32_t c = m.Call(SIGNATURE(CALL_ARGS)); \
CHECK_EQ(c, 42); \
#define ReturnType v8::AnyCType
MachineType machine_type = MachineType::Int64();
#define CHECK_RESULT(CALL, EXPECT) \
v8::AnyCType ret = CALL; \
CHECK_EQ(ret.int64_value, EXPECT);
#define IF_SIMULATOR_ADD_SIGNATURE \
EncodedCSignature sig = m.call_descriptor()->ToEncodedCSignature(); \
m.main_isolate()->simulator_data()->AddSignatureForTargetForTesting( \
func_address, sig);
#else // def V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define IF_SIMULATOR_ADD_SIGNATURE
#ifdef V8_TARGET_ARCH_64_BIT
#define ReturnType int64_t
MachineType machine_type = MachineType::Int64();
#else // V8_TARGET_ARCH_64_BIT
#define ReturnType int32_t
MachineType machine_type = MachineType::Int32();
#endif // V8_TARGET_ARCH_64_BIT
#define CHECK_ARG_I(TYPE, IDX, VALUE) (result = result && (arg##IDX == VALUE))
#define CHECK_RESULT(CALL, EXPECT) \
int64_t ret = CALL; \
CHECK_EQ(ret, EXPECT);
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define SIGNATURE_TEST(NAME, SIGNATURE, FUNC) \
TEST(NAME) { \
RawMachineAssemblerTester<ReturnType> m(SIGNATURE(SIGNATURE_TYPES)); \
\
Address func_address = FUNCTION_ADDR(&FUNC); \
ExternalReference::Type func_type = ExternalReference::FAST_C_CALL; \
ApiFunction func(func_address); \
ExternalReference ref = ExternalReference::Create(&func, func_type); \
\
IF_SIMULATOR_ADD_SIGNATURE \
\
Node* function = m.ExternalConstant(ref); \
m.Return(m.CallCFunction(function, machine_type, SIGNATURE(PARAM_PAIRS))); \
\
CHECK_RESULT(m.Call(SIGNATURE(CALL_ARGS)), 42); \
}
#define SIGNATURE_ONLY_INT(V) \
V(int32_t, 0, 0) \
V(int32_t, 1, 1) \
V(int32_t, 2, 2) \
V(int32_t, 3, 3) \
V(int32_t, 4, 4) \
V(int32_t, 5, 5) \
V(int32_t, 6, 6) \
V(int32_t, 7, 7) \
V(int32_t, 8, 8) \
V##_END(int32_t, 9, 9)
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define SIGNATURE_ONLY_INT(V) \
V(int64_t, 0, 0), V(int64_t, 1, 1), V(int64_t, 2, 2), V(int64_t, 3, 3), \
V(int64_t, 4, 4), V(int64_t, 5, 5), V(int64_t, 6, 6), V(int64_t, 7, 7), \
V(int64_t, 8, 8), V(int64_t, 9, 9)
int32_t func_only_int(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7,
int32_t arg8, int32_t arg9) {
CHECK(SIGNATURE_ONLY_INT(COMPARE_ARG_I));
Int64OrDoubleUnion func_only_int(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9) {
#elif defined(V8_TARGET_ARCH_64_BIT)
#define SIGNATURE_ONLY_INT(V) \
V(int64_t, 0, 0), V(int64_t, 1, 1), V(int64_t, 2, 2), V(int64_t, 3, 3), \
V(int64_t, 4, 4), V(int64_t, 5, 5), V(int64_t, 6, 6), V(int64_t, 7, 7), \
V(int64_t, 8, 8), V(int64_t, 9, 9)
ReturnType func_only_int(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7,
int64_t arg8, int64_t arg9) {
#else // defined(V8_TARGET_ARCH_64_BIT)
#define SIGNATURE_ONLY_INT(V) \
V(int32_t, 0, 0), V(int32_t, 1, 1), V(int32_t, 2, 2), V(int32_t, 3, 3), \
V(int32_t, 4, 4), V(int32_t, 5, 5), V(int32_t, 6, 6), V(int32_t, 7, 7), \
V(int32_t, 8, 8), V(int32_t, 9, 9)
ReturnType func_only_int(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7,
int32_t arg8, int32_t arg9) {
#endif
bool result = true;
SIGNATURE_ONLY_INT(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithSignatureOnlyInt, SIGNATURE_ONLY_INT, func_only_int)
#define SIGNATURE_ONLY_INT_20(V) \
V(int32_t, 0, 0) \
V(int32_t, 1, 1) \
V(int32_t, 2, 2) \
V(int32_t, 3, 3) \
V(int32_t, 4, 4) \
V(int32_t, 5, 5) \
V(int32_t, 6, 6) \
V(int32_t, 7, 7) \
V(int32_t, 8, 8) \
V(int32_t, 9, 9) \
V(int32_t, 10, 10) \
V(int32_t, 11, 11) \
V(int32_t, 12, 12) \
V(int32_t, 13, 13) \
V(int32_t, 14, 14) \
V(int32_t, 15, 15) \
V(int32_t, 16, 16) \
V(int32_t, 17, 17) \
V(int32_t, 18, 18) \
V##_END(int32_t, 19, 19)
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define SIGNATURE_ONLY_INT_20(V) \
V(int64_t, 0, 0), V(int64_t, 1, 1), V(int64_t, 2, 2), V(int64_t, 3, 3), \
V(int64_t, 4, 4), V(int64_t, 5, 5), V(int64_t, 6, 6), V(int64_t, 7, 7), \
V(int64_t, 8, 8), V(int64_t, 9, 9), V(int64_t, 10, 10), \
V(int64_t, 11, 11), V(int64_t, 12, 12), V(int64_t, 13, 13), \
V(int64_t, 14, 14), V(int64_t, 15, 15), V(int64_t, 16, 16), \
V(int64_t, 17, 17), V(int64_t, 18, 18), V(int64_t, 19, 19)
int32_t func_only_int_20(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7,
int32_t arg8, int32_t arg9, int32_t arg10,
int32_t arg11, int32_t arg12, int32_t arg13,
int32_t arg14, int32_t arg15, int32_t arg16,
int32_t arg17, int32_t arg18, int32_t arg19) {
CHECK(SIGNATURE_ONLY_INT_20(COMPARE_ARG_I));
Int64OrDoubleUnion func_only_int_20(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10, Int64OrDoubleUnion arg11,
Int64OrDoubleUnion arg12, Int64OrDoubleUnion arg13,
Int64OrDoubleUnion arg14, Int64OrDoubleUnion arg15,
Int64OrDoubleUnion arg16, Int64OrDoubleUnion arg17,
Int64OrDoubleUnion arg18, Int64OrDoubleUnion arg19) {
#elif defined(V8_TARGET_ARCH_64_BIT)
#define SIGNATURE_ONLY_INT_20(V) \
V(int64_t, 0, 0), V(int64_t, 1, 1), V(int64_t, 2, 2), V(int64_t, 3, 3), \
V(int64_t, 4, 4), V(int64_t, 5, 5), V(int64_t, 6, 6), V(int64_t, 7, 7), \
V(int64_t, 8, 8), V(int64_t, 9, 9), V(int64_t, 10, 10), \
V(int64_t, 11, 11), V(int64_t, 12, 12), V(int64_t, 13, 13), \
V(int64_t, 14, 14), V(int64_t, 15, 15), V(int64_t, 16, 16), \
V(int64_t, 17, 17), V(int64_t, 18, 18), V(int64_t, 19, 19)
ReturnType func_only_int_20(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg3, int64_t arg4, int64_t arg5,
int64_t arg6, int64_t arg7, int64_t arg8,
int64_t arg9, int64_t arg10, int64_t arg11,
int64_t arg12, int64_t arg13, int64_t arg14,
int64_t arg15, int64_t arg16, int64_t arg17,
int64_t arg18, int64_t arg19) {
#else // defined(V8_TARGET_ARCH_64_BIT)
#define SIGNATURE_ONLY_INT_20(V) \
V(int32_t, 0, 0), V(int32_t, 1, 1), V(int32_t, 2, 2), V(int32_t, 3, 3), \
V(int32_t, 4, 4), V(int32_t, 5, 5), V(int32_t, 6, 6), V(int32_t, 7, 7), \
V(int32_t, 8, 8), V(int32_t, 9, 9), V(int32_t, 10, 10), \
V(int32_t, 11, 11), V(int32_t, 12, 12), V(int32_t, 13, 13), \
V(int32_t, 14, 14), V(int32_t, 15, 15), V(int32_t, 16, 16), \
V(int32_t, 17, 17), V(int32_t, 18, 18), V(int32_t, 19, 19)
ReturnType func_only_int_20(int32_t arg0, int32_t arg1, int32_t arg2,
int32_t arg3, int32_t arg4, int32_t arg5,
int32_t arg6, int32_t arg7, int32_t arg8,
int32_t arg9, int32_t arg10, int32_t arg11,
int32_t arg12, int32_t arg13, int32_t arg14,
int32_t arg15, int32_t arg16, int32_t arg17,
int32_t arg18, int32_t arg19) {
#endif
bool result = true;
SIGNATURE_ONLY_INT_20(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithSignatureOnlyInt20, SIGNATURE_ONLY_INT_20,
@ -489,453 +577,270 @@ SIGNATURE_TEST(RunCallWithSignatureOnlyInt20, SIGNATURE_ONLY_INT_20,
#ifdef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#define MIXED_SIGNATURE_SIMPLE(V) \
V(int32_t, 0, 0) \
V(double, 1, 1.5) \
V##_END(int32_t, 2, 2)
V(int64_t, 0, 0), V(double, 1, 1.5), V(int64_t, 2, 2)
int32_t test_api_func_simple(int32_t arg0, double arg1, int32_t arg2) {
CHECK(MIXED_SIGNATURE_SIMPLE(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion test_api_func_simple(Int64OrDoubleUnion arg0,
Int64OrDoubleUnion arg1,
Int64OrDoubleUnion arg2) {
#else
ReturnType test_api_func_simple(int64_t arg0, double arg1, int64_t arg2) {
#endif
bool result = true;
MIXED_SIGNATURE_SIMPLE(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithMixedSignatureSimple, MIXED_SIGNATURE_SIMPLE,
test_api_func_simple)
#define MIXED_SIGNATURE(V) \
V(int32_t, 0, 0) \
V(double, 1, 1.5) \
V(int32_t, 2, 2) \
V(double, 3, 3.5) \
V(int32_t, 4, 4) \
V(double, 5, 5.5) \
V(int32_t, 6, 6) \
V(double, 7, 7.5) \
V(int32_t, 8, 8) \
V(double, 9, 9.5) \
V##_END(int32_t, 10, 10)
#define MIXED_SIGNATURE(V) \
V(int64_t, 0, 0), V(double, 1, 1.5), V(int64_t, 2, 2), V(double, 3, 3.5), \
V(int64_t, 4, 4), V(double, 5, 5.5), V(int64_t, 6, 6), \
V(double, 7, 7.5), V(int64_t, 8, 8), V(double, 9, 9.5), \
V(int64_t, 10, 10)
int32_t test_api_func(int32_t arg0, double arg1, int32_t arg2, double arg3,
int32_t arg4, double arg5, int32_t arg6, double arg7,
int32_t arg8, double arg9, int32_t arg10) {
CHECK(MIXED_SIGNATURE(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion test_api_func(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10) {
#else
ReturnType test_api_func(int64_t arg0, double arg1, int64_t arg2, double arg3,
int64_t arg4, double arg5, int64_t arg6, double arg7,
int64_t arg8, double arg9, int64_t arg10) {
#endif
bool result = true;
MIXED_SIGNATURE(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithMixedSignature, MIXED_SIGNATURE, test_api_func)
#define MIXED_SIGNATURE_DOUBLE_INT(V) \
V(double, 0, 0.5) \
V(double, 1, 1.5) \
V(double, 2, 2.5) \
V(double, 3, 3.5) \
V(double, 4, 4.5) \
V(double, 5, 5.5) \
V(double, 6, 6.5) \
V(double, 7, 7.5) \
V(double, 8, 8.5) \
V(double, 9, 9.5) \
V(int32_t, 10, 10) \
V(int32_t, 11, 11) \
V(int32_t, 12, 12) \
V(int32_t, 13, 13) \
V(int32_t, 14, 14) \
V(int32_t, 15, 15) \
V(int32_t, 16, 16) \
V(int32_t, 17, 17) \
V(int32_t, 18, 18) \
V##_END(int32_t, 19, 19)
#define MIXED_SIGNATURE_DOUBLE_INT(V) \
V(double, 0, 0.5), V(double, 1, 1.5), V(double, 2, 2.5), V(double, 3, 3.5), \
V(double, 4, 4.5), V(double, 5, 5.5), V(double, 6, 6.5), \
V(double, 7, 7.5), V(double, 8, 8.5), V(double, 9, 9.5), \
V(int64_t, 10, 10), V(int64_t, 11, 11), V(int64_t, 12, 12), \
V(int64_t, 13, 13), V(int64_t, 14, 14), V(int64_t, 15, 15), \
V(int64_t, 16, 16), V(int64_t, 17, 17), V(int64_t, 18, 18), \
V(int64_t, 19, 19)
int32_t func_mixed_double_int(double arg0, double arg1, double arg2,
double arg3, double arg4, double arg5,
double arg6, double arg7, double arg8,
double arg9, int32_t arg10, int32_t arg11,
int32_t arg12, int32_t arg13, int32_t arg14,
int32_t arg15, int32_t arg16, int32_t arg17,
int32_t arg18, int32_t arg19) {
CHECK(MIXED_SIGNATURE_DOUBLE_INT(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion func_mixed_double_int(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10, Int64OrDoubleUnion arg11,
Int64OrDoubleUnion arg12, Int64OrDoubleUnion arg13,
Int64OrDoubleUnion arg14, Int64OrDoubleUnion arg15,
Int64OrDoubleUnion arg16, Int64OrDoubleUnion arg17,
Int64OrDoubleUnion arg18, Int64OrDoubleUnion arg19) {
#else
ReturnType func_mixed_double_int(double arg0, double arg1, double arg2,
double arg3, double arg4, double arg5,
double arg6, double arg7, double arg8,
double arg9, int64_t arg10, int64_t arg11,
int64_t arg12, int64_t arg13, int64_t arg14,
int64_t arg15, int64_t arg16, int64_t arg17,
int64_t arg18, int64_t arg19) {
#endif
bool result = true;
MIXED_SIGNATURE_DOUBLE_INT(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithMixedSignatureDoubleInt, MIXED_SIGNATURE_DOUBLE_INT,
func_mixed_double_int)
#define MIXED_SIGNATURE_INT_DOUBLE(V) \
V(int32_t, 0, 0) \
V(int32_t, 1, 1) \
V(int32_t, 2, 2) \
V(int32_t, 3, 3) \
V(int32_t, 4, 4) \
V(int32_t, 5, 5) \
V(int32_t, 6, 6) \
V(int32_t, 7, 7) \
V(int32_t, 8, 8) \
V(int32_t, 9, 9) \
V(double, 10, 10.5) \
V(double, 11, 11.5) \
V(double, 12, 12.5) \
V(double, 13, 13.5) \
V(double, 14, 14.5) \
V(double, 15, 15.5) \
V(double, 16, 16.5) \
V(double, 17, 17.5) \
V(double, 18, 18.5) \
V##_END(double, 19, 19.5)
#define MIXED_SIGNATURE_INT_DOUBLE(V) \
V(int64_t, 0, 0), V(int64_t, 1, 1), V(int64_t, 2, 2), V(int64_t, 3, 3), \
V(int64_t, 4, 4), V(int64_t, 5, 5), V(int64_t, 6, 6), V(int64_t, 7, 7), \
V(int64_t, 8, 8), V(int64_t, 9, 9), V(double, 10, 10.5), \
V(double, 11, 11.5), V(double, 12, 12.5), V(double, 13, 13.5), \
V(double, 14, 14.5), V(double, 15, 15.5), V(double, 16, 16.5), \
V(double, 17, 17.5), V(double, 18, 18.5), V(double, 19, 19.5)
int32_t func_mixed_int_double(int32_t arg0, int32_t arg1, int32_t arg2,
int32_t arg3, int32_t arg4, int32_t arg5,
int32_t arg6, int32_t arg7, int32_t arg8,
int32_t arg9, double arg10, double arg11,
double arg12, double arg13, double arg14,
double arg15, double arg16, double arg17,
double arg18, double arg19) {
CHECK(MIXED_SIGNATURE_INT_DOUBLE(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion func_mixed_int_double(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10, Int64OrDoubleUnion arg11,
Int64OrDoubleUnion arg12, Int64OrDoubleUnion arg13,
Int64OrDoubleUnion arg14, Int64OrDoubleUnion arg15,
Int64OrDoubleUnion arg16, Int64OrDoubleUnion arg17,
Int64OrDoubleUnion arg18, Int64OrDoubleUnion arg19) {
#else
ReturnType func_mixed_int_double(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg3, int64_t arg4, int64_t arg5,
int64_t arg6, int64_t arg7, int64_t arg8,
int64_t arg9, double arg10, double arg11,
double arg12, double arg13, double arg14,
double arg15, double arg16, double arg17,
double arg18, double arg19) {
#endif
bool result = true;
MIXED_SIGNATURE_INT_DOUBLE(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithMixedSignatureIntDouble, MIXED_SIGNATURE_INT_DOUBLE,
func_mixed_int_double)
#define MIXED_SIGNATURE_INT_DOUBLE_ALT(V) \
V(int32_t, 0, 0) \
V(double, 1, 1.5) \
V(int32_t, 2, 2) \
V(double, 3, 3.5) \
V(int32_t, 4, 4) \
V(double, 5, 5.5) \
V(int32_t, 6, 6) \
V(double, 7, 7.5) \
V(int32_t, 8, 8) \
V(double, 9, 9.5) \
V(int32_t, 10, 10) \
V(double, 11, 11.5) \
V(int32_t, 12, 12) \
V(double, 13, 13.5) \
V(int32_t, 14, 14) \
V(double, 15, 15.5) \
V(int32_t, 16, 16) \
V(double, 17, 17.5) \
V(int32_t, 18, 18) \
V##_END(double, 19, 19.5)
#define MIXED_SIGNATURE_INT_DOUBLE_ALT(V) \
V(int64_t, 0, 0), V(double, 1, 1.5), V(int64_t, 2, 2), V(double, 3, 3.5), \
V(int64_t, 4, 4), V(double, 5, 5.5), V(int64_t, 6, 6), \
V(double, 7, 7.5), V(int64_t, 8, 8), V(double, 9, 9.5), \
V(int64_t, 10, 10), V(double, 11, 11.5), V(int64_t, 12, 12), \
V(double, 13, 13.5), V(int64_t, 14, 14), V(double, 15, 15.5), \
V(int64_t, 16, 16), V(double, 17, 17.5), V(int64_t, 18, 18), \
V(double, 19, 19.5)
int32_t func_mixed_int_double_alt(int32_t arg0, double arg1, int32_t arg2,
double arg3, int32_t arg4, double arg5,
int32_t arg6, double arg7, int32_t arg8,
double arg9, int32_t arg10, double arg11,
int32_t arg12, double arg13, int32_t arg14,
double arg15, int32_t arg16, double arg17,
int32_t arg18, double arg19) {
CHECK(MIXED_SIGNATURE_INT_DOUBLE_ALT(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion func_mixed_int_double_alt(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10, Int64OrDoubleUnion arg11,
Int64OrDoubleUnion arg12, Int64OrDoubleUnion arg13,
Int64OrDoubleUnion arg14, Int64OrDoubleUnion arg15,
Int64OrDoubleUnion arg16, Int64OrDoubleUnion arg17,
Int64OrDoubleUnion arg18, Int64OrDoubleUnion arg19) {
#else
ReturnType func_mixed_int_double_alt(int64_t arg0, double arg1, int64_t arg2,
double arg3, int64_t arg4, double arg5,
int64_t arg6, double arg7, int64_t arg8,
double arg9, int64_t arg10, double arg11,
int64_t arg12, double arg13, int64_t arg14,
double arg15, int64_t arg16, double arg17,
int64_t arg18, double arg19) {
#endif
bool result = true;
MIXED_SIGNATURE_INT_DOUBLE_ALT(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithMixedSignatureIntDoubleAlt,
MIXED_SIGNATURE_INT_DOUBLE_ALT, func_mixed_int_double_alt)
#define SIGNATURE_ONLY_DOUBLE(V) \
V(double, 0, 0.5) \
V(double, 1, 1.5) \
V(double, 2, 2.5) \
V(double, 3, 3.5) \
V(double, 4, 4.5) \
V(double, 5, 5.5) \
V(double, 6, 6.5) \
V(double, 7, 7.5) \
V(double, 8, 8.5) \
V##_END(double, 9, 9.5)
#define SIGNATURE_ONLY_DOUBLE(V) \
V(double, 0, 0.5), V(double, 1, 1.5), V(double, 2, 2.5), V(double, 3, 3.5), \
V(double, 4, 4.5), V(double, 5, 5.5), V(double, 6, 6.5), \
V(double, 7, 7.5), V(double, 8, 8.5), V(double, 9, 9.5)
int32_t func_only_double(double arg0, double arg1, double arg2, double arg3,
double arg4, double arg5, double arg6, double arg7,
double arg8, double arg9) {
CHECK(SIGNATURE_ONLY_DOUBLE(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion func_only_double(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9) {
#else
ReturnType func_only_double(double arg0, double arg1, double arg2, double arg3,
double arg4, double arg5, double arg6, double arg7,
double arg8, double arg9) {
#endif
bool result = true;
SIGNATURE_ONLY_DOUBLE(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithSignatureOnlyDouble, SIGNATURE_ONLY_DOUBLE,
func_only_double)
#define SIGNATURE_ONLY_DOUBLE_20(V) \
V(double, 0, 0.5) \
V(double, 1, 1.5) \
V(double, 2, 2.5) \
V(double, 3, 3.5) \
V(double, 4, 4.5) \
V(double, 5, 5.5) \
V(double, 6, 6.5) \
V(double, 7, 7.5) \
V(double, 8, 8.5) \
V(double, 9, 9.5) \
V(double, 10, 10.5) \
V(double, 11, 11.5) \
V(double, 12, 12.5) \
V(double, 13, 13.5) \
V(double, 14, 14.5) \
V(double, 15, 15.5) \
V(double, 16, 16.5) \
V(double, 17, 17.5) \
V(double, 18, 18.5) \
V##_END(double, 19, 19.5)
#define SIGNATURE_ONLY_DOUBLE_20(V) \
V(double, 0, 0.5), V(double, 1, 1.5), V(double, 2, 2.5), V(double, 3, 3.5), \
V(double, 4, 4.5), V(double, 5, 5.5), V(double, 6, 6.5), \
V(double, 7, 7.5), V(double, 8, 8.5), V(double, 9, 9.5), \
V(double, 10, 10.5), V(double, 11, 11.5), V(double, 12, 12.5), \
V(double, 13, 13.5), V(double, 14, 14.5), V(double, 15, 15.5), \
V(double, 16, 16.5), V(double, 17, 17.5), V(double, 18, 18.5), \
V(double, 19, 19.5)
int32_t func_only_double_20(double arg0, double arg1, double arg2, double arg3,
double arg4, double arg5, double arg6, double arg7,
double arg8, double arg9, double arg10,
double arg11, double arg12, double arg13,
double arg14, double arg15, double arg16,
double arg17, double arg18, double arg19) {
CHECK(SIGNATURE_ONLY_DOUBLE_20(COMPARE_ARG_I));
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion func_only_double_20(
Int64OrDoubleUnion arg0, Int64OrDoubleUnion arg1, Int64OrDoubleUnion arg2,
Int64OrDoubleUnion arg3, Int64OrDoubleUnion arg4, Int64OrDoubleUnion arg5,
Int64OrDoubleUnion arg6, Int64OrDoubleUnion arg7, Int64OrDoubleUnion arg8,
Int64OrDoubleUnion arg9, Int64OrDoubleUnion arg10, Int64OrDoubleUnion arg11,
Int64OrDoubleUnion arg12, Int64OrDoubleUnion arg13,
Int64OrDoubleUnion arg14, Int64OrDoubleUnion arg15,
Int64OrDoubleUnion arg16, Int64OrDoubleUnion arg17,
Int64OrDoubleUnion arg18, Int64OrDoubleUnion arg19) {
#else
ReturnType func_only_double_20(double arg0, double arg1, double arg2,
double arg3, double arg4, double arg5,
double arg6, double arg7, double arg8,
double arg9, double arg10, double arg11,
double arg12, double arg13, double arg14,
double arg15, double arg16, double arg17,
double arg18, double arg19) {
#endif
bool result = true;
SIGNATURE_ONLY_DOUBLE_20(CHECK_ARG_I);
CHECK(result);
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
Int64OrDoubleUnion ret;
ret.int64_t_value = 42;
return ret;
#else
return 42;
#endif
}
SIGNATURE_TEST(RunCallWithSignatureOnlyDouble20, SIGNATURE_ONLY_DOUBLE_20,
func_only_double_20)
#define MIXED_SIGNATURE_SIMPLE_FLOAT(V) \
V(int32_t, 0, 0) \
V(float, 1, 1.5) \
V##_END(int32_t, 2, 2)
int32_t test_api_func_simple_float(int32_t arg0, float arg1, int32_t arg2) {
CHECK(MIXED_SIGNATURE_SIMPLE_FLOAT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureSimpleFloat,
MIXED_SIGNATURE_SIMPLE_FLOAT, test_api_func_simple_float)
#define MIXED_SIGNATURE_FLOAT(V) \
V(int32_t, 0, 0) \
V(float, 1, 1.5) \
V(int32_t, 2, 2) \
V(float, 3, 3.5) \
V(int32_t, 4, 4) \
V(float, 5, 5.5) \
V(int32_t, 6, 6) \
V(float, 7, 7.5) \
V(int32_t, 8, 8) \
V(float, 9, 9.5) \
V##_END(int32_t, 10, 10)
int32_t test_api_func_float(int32_t arg0, float arg1, int32_t arg2, float arg3,
int32_t arg4, float arg5, int32_t arg6, float arg7,
int32_t arg8, float arg9, int32_t arg10) {
CHECK(MIXED_SIGNATURE_FLOAT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureFloat, MIXED_SIGNATURE_FLOAT,
test_api_func_float)
#define MIXED_SIGNATURE_INT_FLOAT_ALT(V) \
V(int32_t, 0, 0) \
V(float, 1, 1.5) \
V(int32_t, 2, 2) \
V(float, 3, 3.5) \
V(int32_t, 4, 4) \
V(float, 5, 5.5) \
V(int32_t, 6, 6) \
V(float, 7, 7.5) \
V(int32_t, 8, 8) \
V(float, 9, 9.5) \
V(int32_t, 10, 10) \
V(float, 11, 11.5) \
V(int32_t, 12, 12) \
V(float, 13, 13.5) \
V(int32_t, 14, 14) \
V(float, 15, 15.5) \
V(int32_t, 16, 16) \
V(float, 17, 17.5) \
V(int32_t, 18, 18) \
V##_END(float, 19, 19.5)
int32_t func_mixed_int_float_alt(int32_t arg0, float arg1, int32_t arg2,
float arg3, int32_t arg4, float arg5,
int32_t arg6, float arg7, int32_t arg8,
float arg9, int32_t arg10, float arg11,
int32_t arg12, float arg13, int32_t arg14,
float arg15, int32_t arg16, float arg17,
int32_t arg18, float arg19) {
CHECK(MIXED_SIGNATURE_INT_FLOAT_ALT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureIntFloatAlt,
MIXED_SIGNATURE_INT_FLOAT_ALT, func_mixed_int_float_alt)
#define SIGNATURE_ONLY_FLOAT_20(V) \
V(float, 0, 0.5) \
V(float, 1, 1.5) \
V(float, 2, 2.5) \
V(float, 3, 3.5) \
V(float, 4, 4.5) \
V(float, 5, 5.5) \
V(float, 6, 6.5) \
V(float, 7, 7.5) \
V(float, 8, 8.5) \
V(float, 9, 9.5) \
V(float, 10, 10.5) \
V(float, 11, 11.5) \
V(float, 12, 12.5) \
V(float, 13, 13.5) \
V(float, 14, 14.5) \
V(float, 15, 15.5) \
V(float, 16, 16.5) \
V(float, 17, 17.5) \
V(float, 18, 18.5) \
V##_END(float, 19, 19.5)
int32_t func_only_float_20(float arg0, float arg1, float arg2, float arg3,
float arg4, float arg5, float arg6, float arg7,
float arg8, float arg9, float arg10, float arg11,
float arg12, float arg13, float arg14, float arg15,
float arg16, float arg17, float arg18, float arg19) {
CHECK(SIGNATURE_ONLY_FLOAT_20(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithSignatureOnlyFloat20, SIGNATURE_ONLY_FLOAT_20,
func_only_float_20)
#define MIXED_SIGNATURE_FLOAT_INT(V) \
V(float, 0, 0.5) \
V(float, 1, 1.5) \
V(float, 2, 2.5) \
V(float, 3, 3.5) \
V(float, 4, 4.5) \
V(float, 5, 5.5) \
V(float, 6, 6.5) \
V(float, 7, 7.5) \
V(float, 8, 8.5) \
V(float, 9, 9.5) \
V(int32_t, 10, 10) \
V(int32_t, 11, 11) \
V(int32_t, 12, 12) \
V(int32_t, 13, 13) \
V(int32_t, 14, 14) \
V(int32_t, 15, 15) \
V(int32_t, 16, 16) \
V(int32_t, 17, 17) \
V(int32_t, 18, 18) \
V##_END(int32_t, 19, 19)
int32_t func_mixed_float_int(float arg0, float arg1, float arg2, float arg3,
float arg4, float arg5, float arg6, float arg7,
float arg8, float arg9, int32_t arg10,
int32_t arg11, int32_t arg12, int32_t arg13,
int32_t arg14, int32_t arg15, int32_t arg16,
int32_t arg17, int32_t arg18, int32_t arg19) {
CHECK(MIXED_SIGNATURE_FLOAT_INT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureFloatInt, MIXED_SIGNATURE_FLOAT_INT,
func_mixed_float_int)
#define MIXED_SIGNATURE_INT_FLOAT(V) \
V(int32_t, 0, 0) \
V(int32_t, 1, 1) \
V(int32_t, 2, 2) \
V(int32_t, 3, 3) \
V(int32_t, 4, 4) \
V(int32_t, 5, 5) \
V(int32_t, 6, 6) \
V(int32_t, 7, 7) \
V(int32_t, 8, 8) \
V(int32_t, 9, 9) \
V(float, 10, 10.5) \
V(float, 11, 11.5) \
V(float, 12, 12.5) \
V(float, 13, 13.5) \
V(float, 14, 14.5) \
V(float, 15, 15.5) \
V(float, 16, 16.5) \
V(float, 17, 17.5) \
V(float, 18, 18.5) \
V##_END(float, 19, 19.5)
int32_t func_mixed_int_float(int32_t arg0, int32_t arg1, int32_t arg2,
int32_t arg3, int32_t arg4, int32_t arg5,
int32_t arg6, int32_t arg7, int32_t arg8,
int32_t arg9, float arg10, float arg11,
float arg12, float arg13, float arg14, float arg15,
float arg16, float arg17, float arg18,
float arg19) {
CHECK(MIXED_SIGNATURE_INT_FLOAT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureIntFloat, MIXED_SIGNATURE_INT_FLOAT,
func_mixed_int_float)
#define MIXED_SIGNATURE_FLOAT_DOUBLE(V) \
V(float, 0, 0.5) \
V(float, 1, 1.5) \
V(float, 2, 2.5) \
V(float, 3, 3.5) \
V(float, 4, 4.5) \
V(float, 5, 5.5) \
V(float, 6, 6.5) \
V(float, 7, 7.5) \
V(float, 8, 8.5) \
V(float, 9, 9.5) \
V(double, 10, 10.7) \
V(double, 11, 11.7) \
V(double, 12, 12.7) \
V(double, 13, 13.7) \
V(double, 14, 14.7) \
V(double, 15, 15.7) \
V(double, 16, 16.7) \
V(double, 17, 17.7) \
V(double, 18, 18.7) \
V##_END(double, 19, 19.7)
int32_t func_mixed_float_double(float arg0, float arg1, float arg2, float arg3,
float arg4, float arg5, float arg6, float arg7,
float arg8, float arg9, double arg10,
double arg11, double arg12, double arg13,
double arg14, double arg15, double arg16,
double arg17, double arg18, double arg19) {
CHECK(MIXED_SIGNATURE_FLOAT_DOUBLE(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureFloatDouble,
MIXED_SIGNATURE_FLOAT_DOUBLE, func_mixed_float_double)
#define MIXED_SIGNATURE_DOUBLE_FLOAT(V) \
V(double, 0, 0.7) \
V(double, 1, 1.7) \
V(double, 2, 2.7) \
V(double, 3, 3.7) \
V(double, 4, 4.7) \
V(double, 5, 5.7) \
V(double, 6, 6.7) \
V(double, 7, 7.7) \
V(double, 8, 8.7) \
V(double, 9, 9.7) \
V(float, 10, 10.5) \
V(float, 11, 11.5) \
V(float, 12, 12.5) \
V(float, 13, 13.5) \
V(float, 14, 14.5) \
V(float, 15, 15.5) \
V(float, 16, 16.5) \
V(float, 17, 17.5) \
V(float, 18, 18.5) \
V##_END(float, 19, 19.5)
int32_t func_mixed_double_float(double arg0, double arg1, double arg2,
double arg3, double arg4, double arg5,
double arg6, double arg7, double arg8,
double arg9, float arg10, float arg11,
float arg12, float arg13, float arg14,
float arg15, float arg16, float arg17,
float arg18, float arg19) {
CHECK(MIXED_SIGNATURE_DOUBLE_FLOAT(COMPARE_ARG_I));
return 42;
}
SIGNATURE_TEST(RunCallWithMixedSignatureDoubleFloat,
MIXED_SIGNATURE_DOUBLE_FLOAT, func_mixed_double_float)
#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
} // namespace compiler

View File

@ -6699,7 +6699,310 @@ TEST(RunCallCFunction9) {
m.Call(x));
}
}
#endif // USE_SIMULATOR
#endif // !USE_SIMULATOR
#ifdef V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define IF_SIMULATOR_ADD_SIGNATURE \
EncodedCSignature sig = m.call_descriptor()->ToEncodedCSignature(); \
m.main_isolate()->simulator_data()->AddSignatureForTargetForTesting( \
func_address, sig);
#else
#define IF_SIMULATOR_ADD_SIGNATURE
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#define EXTERNAL_REF_FROM_FUNC(FUNC) \
Address func_address = FUNCTION_ADDR(&FUNC); \
ExternalReference::Type func_type = ExternalReference::FAST_C_CALL; \
ApiFunction func(func_address); \
ExternalReference ref = ExternalReference::Create(&func, func_type);
namespace {
void CheckEqual(double expected, double actual) {
if (std::isnan(expected)) {
CHECK(std::isnan(actual));
} else {
CHECK_EQ(actual, expected);
}
}
void CheckLessOrEqual(double actual, double expected) {
if (std::isnan(expected)) {
CHECK(std::isnan(actual));
} else if (std::isnan(actual)) {
return;
} else {
CHECK_LE(actual, expected);
}
}
const double foo_result = 3.14;
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
union Int64OrDoubleUnion {
int64_t int64_value;
double double_value;
};
Int64OrDoubleUnion double_foo0() {
Int64OrDoubleUnion ret;
ret.double_value = foo_result;
return ret;
}
Int64OrDoubleUnion double_foo1(Int64OrDoubleUnion x) {
Int64OrDoubleUnion ret;
ret.double_value = x.double_value;
return ret;
}
Int64OrDoubleUnion double_foo2(Int64OrDoubleUnion x, Int64OrDoubleUnion y) {
Int64OrDoubleUnion ret;
ret.double_value = x.double_value * 10 + y.double_value;
return ret;
}
Int64OrDoubleUnion double_foo8(Int64OrDoubleUnion a, Int64OrDoubleUnion b,
Int64OrDoubleUnion c, Int64OrDoubleUnion d,
Int64OrDoubleUnion e, Int64OrDoubleUnion f,
Int64OrDoubleUnion g, Int64OrDoubleUnion h) {
Int64OrDoubleUnion ret;
ret.double_value = a.double_value + b.double_value + c.double_value +
d.double_value + e.double_value + f.double_value +
g.double_value + h.double_value;
return ret;
}
Int64OrDoubleUnion double_foo9(Int64OrDoubleUnion a, Int64OrDoubleUnion b,
Int64OrDoubleUnion c, Int64OrDoubleUnion d,
Int64OrDoubleUnion e, Int64OrDoubleUnion f,
Int64OrDoubleUnion g, Int64OrDoubleUnion h,
Int64OrDoubleUnion i) {
Int64OrDoubleUnion ret;
ret.double_value = a.double_value + b.double_value + c.double_value +
d.double_value + e.double_value + f.double_value +
g.double_value + h.double_value + i.double_value;
return ret;
}
Int64OrDoubleUnion double_foo10(Int64OrDoubleUnion a, Int64OrDoubleUnion b,
Int64OrDoubleUnion c, Int64OrDoubleUnion d,
Int64OrDoubleUnion e, Int64OrDoubleUnion f,
Int64OrDoubleUnion g, Int64OrDoubleUnion h,
Int64OrDoubleUnion i, Int64OrDoubleUnion j) {
Int64OrDoubleUnion ret;
ret.double_value = a.double_value + b.double_value + c.double_value +
d.double_value + e.double_value + f.double_value +
g.double_value + h.double_value + i.double_value +
j.int64_value;
return ret;
}
Int64OrDoubleUnion int_foo10(Int64OrDoubleUnion a, Int64OrDoubleUnion b,
Int64OrDoubleUnion c, Int64OrDoubleUnion d,
Int64OrDoubleUnion e, Int64OrDoubleUnion f,
Int64OrDoubleUnion g, Int64OrDoubleUnion h,
Int64OrDoubleUnion i, Int64OrDoubleUnion j) {
Int64OrDoubleUnion ret;
ret.double_value = a.int64_value + b.int64_value + c.int64_value +
d.int64_value + e.int64_value + f.int64_value +
g.int64_value + h.int64_value + i.int64_value +
j.double_value;
return ret;
}
#else // def V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
double double_foo0() { return foo_result; }
double double_foo1(double x) { return x; }
double double_foo2(double x, double y) { return x * 10 + y; }
double double_foo8(double a, double b, double c, double d, double e, double f,
double g, double h) {
return a + b + c + d + e + f + g + h;
}
double double_foo9(double a, double b, double c, double d, double e, double f,
double g, double h, double i) {
return a + b + c + d + e + f + g + h + i;
}
double double_foo10(double a, double b, double c, double d, double e, double f,
double g, double h, double i, int64_t j) {
return a + b + c + d + e + f + g + h + i + j;
}
double int_foo10(int64_t a, int64_t b, int64_t c, int64_t d, int64_t e,
int64_t f, int64_t g, int64_t h, int64_t i, double j) {
return a + b + c + d + e + f + g + h + i + j;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
} // namespace
TEST(RunCallDoubleCFunction0) {
RawMachineAssemblerTester<double> m;
EXTERNAL_REF_FROM_FUNC(double_foo0)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
m.Return(m.CallCFunction(function, MachineType::Float64()));
CheckEqual(foo_result, m.Call());
}
TEST(RunCallDoubleCFunction1) {
RawMachineAssemblerTester<double> m(MachineType::Float64());
EXTERNAL_REF_FROM_FUNC(double_foo1)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
m.Return(
m.CallCFunction(function, MachineType::Float64(),
std::make_pair(MachineType::Float64(), m.Parameter(0))));
FOR_FLOAT64_INPUTS(x) { CheckEqual(x, m.Call(x)); }
}
TEST(RunCallDoubleCFunction2) {
RawMachineAssemblerTester<double> m(MachineType::Float64(),
MachineType::Float64());
EXTERNAL_REF_FROM_FUNC(double_foo2)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
m.Return(
m.CallCFunction(function, MachineType::Float64(),
std::make_pair(MachineType::Float64(), m.Parameter(0)),
std::make_pair(MachineType::Float64(), m.Parameter(1))));
FOR_FLOAT64_INPUTS(x) {
if (std::isnan(x)) continue;
FOR_FLOAT64_INPUTS(y) { CheckEqual(x * 10 + y, m.Call(x, y)); }
}
}
TEST(RunCallDoubleCFunction8) {
RawMachineAssemblerTester<double> m(
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64());
EXTERNAL_REF_FROM_FUNC(double_foo8)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
Node* param = m.Parameter(0);
m.Return(m.CallCFunction(function, MachineType::Float64(),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(), param)));
FOR_FLOAT64_INPUTS(x) {
double diff = std::fabs(x * 8.0 - m.Call(x));
CheckLessOrEqual(diff, std::numeric_limits<double>::epsilon());
}
}
TEST(RunCallDoubleCFunction9) {
RawMachineAssemblerTester<double> m(
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64(), MachineType::Float64());
EXTERNAL_REF_FROM_FUNC(double_foo9)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
Node* param = m.Parameter(0);
m.Return(m.CallCFunction(
function, MachineType::Float64(),
std::make_pair(MachineType::Float64(), param),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(1))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(2))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(3))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(4))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(5))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(6))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(7))),
std::make_pair(MachineType::Float64(),
m.Float64Add(param, m.Float64Constant(8)))));
FOR_FLOAT64_INPUTS(x) {
double diff = x * 9.0 + 36.0 - m.Call(x);
CheckLessOrEqual(diff, std::numeric_limits<double>::epsilon());
}
}
TEST(RunCallDoubleCFunction10) {
RawMachineAssemblerTester<double> m(
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Float64(), MachineType::Float64(), MachineType::Float64(),
MachineType::Int64());
EXTERNAL_REF_FROM_FUNC(double_foo10)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
m.Return(
m.CallCFunction(function, MachineType::Float64(),
std::make_pair(MachineType::Float64(), m.Parameter(0)),
std::make_pair(MachineType::Float64(), m.Parameter(1)),
std::make_pair(MachineType::Float64(), m.Parameter(2)),
std::make_pair(MachineType::Float64(), m.Parameter(3)),
std::make_pair(MachineType::Float64(), m.Parameter(4)),
std::make_pair(MachineType::Float64(), m.Parameter(5)),
std::make_pair(MachineType::Float64(), m.Parameter(6)),
std::make_pair(MachineType::Float64(), m.Parameter(7)),
std::make_pair(MachineType::Float64(), m.Parameter(8)),
std::make_pair(MachineType::Int64(), m.Parameter(9))));
FOR_INT64_INPUTS(x) {
double c = m.Call(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, x);
double diff = 45.0 + x - c;
CheckLessOrEqual(fabs(diff), std::numeric_limits<double>::epsilon());
}
}
TEST(RunCallIntCFunction10) {
RawMachineAssemblerTester<double> m(
MachineType::Int64(), MachineType::Int64(), MachineType::Int64(),
MachineType::Int64(), MachineType::Int64(), MachineType::Int64(),
MachineType::Int64(), MachineType::Int64(), MachineType::Int64(),
MachineType::Float64());
EXTERNAL_REF_FROM_FUNC(int_foo10)
IF_SIMULATOR_ADD_SIGNATURE
Node* function = m.ExternalConstant(ref);
m.Return(
m.CallCFunction(function, MachineType::Float64(),
std::make_pair(MachineType::Int64(), m.Parameter(0)),
std::make_pair(MachineType::Int64(), m.Parameter(1)),
std::make_pair(MachineType::Int64(), m.Parameter(2)),
std::make_pair(MachineType::Int64(), m.Parameter(3)),
std::make_pair(MachineType::Int64(), m.Parameter(4)),
std::make_pair(MachineType::Int64(), m.Parameter(5)),
std::make_pair(MachineType::Int64(), m.Parameter(6)),
std::make_pair(MachineType::Int64(), m.Parameter(7)),
std::make_pair(MachineType::Int64(), m.Parameter(8)),
std::make_pair(MachineType::Float64(), m.Parameter(9))));
FOR_FLOAT64_INPUTS(x) {
double c = m.Call(static_cast<int64_t>(1), static_cast<int64_t>(2),
static_cast<int64_t>(3), static_cast<int64_t>(4),
static_cast<int64_t>(5), static_cast<int64_t>(6),
static_cast<int64_t>(7), static_cast<int64_t>(8),
static_cast<int64_t>(9), x);
double diff = 45.0 + x - c;
CheckLessOrEqual(fabs(diff), std::numeric_limits<double>::epsilon());
}
}
#endif // V8_ENABLE_FP_PARAMS_IN_C_LINKAGE
#if V8_TARGET_ARCH_64_BIT
// TODO(titzer): run int64 tests on all platforms when supported.

View File

@ -27873,6 +27873,81 @@ UNINITIALIZED_TEST(NestedIsolates) {
#ifndef V8_LITE_MODE
namespace {
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <typename Value>
Value PrimitiveFromMixedType(v8::AnyCType argument);
template <>
bool PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.bool_value;
}
template <>
int32_t PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.int32_value;
}
template <>
uint32_t PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.uint32_value;
}
template <>
int64_t PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.int64_value;
}
template <>
uint64_t PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.uint64_value;
}
template <>
float PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.float_value;
}
template <>
double PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.double_value;
}
template <>
v8::Local<v8::Value> PrimitiveFromMixedType(v8::AnyCType argument) {
return argument.object_value;
}
template <typename T>
v8::AnyCType PrimitiveToMixedType(T value) {
return v8::AnyCType();
}
template <>
v8::AnyCType PrimitiveToMixedType(bool value) {
v8::AnyCType ret;
ret.bool_value = value;
return ret;
}
template <>
v8::AnyCType PrimitiveToMixedType(int32_t value) {
v8::AnyCType ret;
ret.int32_value = value;
return ret;
}
template <>
v8::AnyCType PrimitiveToMixedType(uint32_t value) {
v8::AnyCType ret;
ret.uint32_value = value;
return ret;
}
template <>
v8::AnyCType PrimitiveToMixedType(float value) {
v8::AnyCType ret;
ret.float_value = value;
return ret;
}
template <>
v8::AnyCType PrimitiveToMixedType(double value) {
v8::AnyCType ret;
ret.double_value = value;
return ret;
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <typename Value, typename Impl, typename Ret>
struct BasicApiChecker {
static Ret FastCallback(v8::Local<v8::Object> receiver, Value argument,
@ -27888,6 +27963,7 @@ struct BasicApiChecker {
v8::FastApiCallbackOptions options = {false, {0}};
return Impl::FastCallback(receiver, argument, options);
}
static void SlowCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
Impl::SlowCallback(info);
}
@ -27904,6 +27980,44 @@ struct BasicApiChecker {
ApiCheckerResultFlags result_ = ApiCheckerResult::kNotCalled;
};
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <typename Value, typename Impl, typename Ret,
typename = std::enable_if_t<!std::is_void<Ret>::value>>
static v8::AnyCType FastCallbackPatch(v8::AnyCType receiver,
v8::AnyCType argument,
v8::AnyCType options) {
v8::AnyCType ret = PrimitiveToMixedType<Ret>(Impl::FastCallback(
receiver.object_value, PrimitiveFromMixedType<Value>(argument),
*(options.options_value)));
return ret;
}
template <typename Value, typename Impl, typename Ret,
typename = std::enable_if_t<!std::is_void<Ret>::value>>
static v8::AnyCType FastCallbackNoFallbackWrapper(v8::AnyCType receiver,
v8::AnyCType argument) {
v8::FastApiCallbackOptions options = {false, {0}};
v8::AnyCType ret = PrimitiveToMixedType<Ret>(Impl::FastCallback(
receiver.object_value, PrimitiveFromMixedType<Value>(argument), options));
return ret;
}
template <typename Value, typename Impl, typename Ret,
typename = std::enable_if_t<std::is_void<Ret>::value>>
static void FastCallbackPatch(v8::AnyCType receiver, v8::AnyCType argument,
v8::AnyCType options) {
return Impl::FastCallback(receiver.object_value,
PrimitiveFromMixedType<Value>(argument),
*(options.options_value));
}
template <typename Value, typename Impl, typename Ret,
typename = std::enable_if_t<std::is_void<Ret>::value>>
static void FastCallbackNoFallbackWrapper(v8::AnyCType receiver,
v8::AnyCType argument) {
v8::FastApiCallbackOptions options = {false, {0}};
return Impl::FastCallback(receiver.object_value,
PrimitiveFromMixedType<Value>(argument), options);
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
enum class Behavior {
kNoException,
kException, // An exception should be thrown by the callback function.
@ -28048,11 +28162,23 @@ bool SetupTest(v8::Local<v8::Value> initial_value, LocalContext* env,
v8::CFunction c_func;
if (supports_fallback) {
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
c_func =
v8::CFunction::Make(BasicApiChecker<Value, Impl, Ret>::FastCallback,
FastCallbackPatch<Value, Impl, Ret>);
#else // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
c_func =
v8::CFunction::Make(BasicApiChecker<Value, Impl, Ret>::FastCallback);
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
} else {
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
c_func = v8::CFunction::Make(
BasicApiChecker<Value, Impl, Ret>::FastCallbackNoFallback,
FastCallbackNoFallbackWrapper<Value, Impl, Ret>);
#else // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
c_func = v8::CFunction::Make(
BasicApiChecker<Value, Impl, Ret>::FastCallbackNoFallback);
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
}
CHECK_EQ(c_func.ArgumentInfo(0).GetType(), v8::CTypeInfo::Type::kV8Value);