e1a948a6f8
This simplifies the handling of MachineTypes for parameters and returns used in tests, and overall improves the regularity with which they are handled in both tests and in CallDescriptor. R=bmeurer@chromium.org, jarin@chromium.org BUG= Review URL: https://codereview.chromium.org/530783002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23638 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
394 lines
12 KiB
C++
394 lines
12 KiB
C++
// Copyright 2014 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_CCTEST_COMPILER_CALL_TESTER_H_
|
|
#define V8_CCTEST_COMPILER_CALL_TESTER_H_
|
|
|
|
#include "src/v8.h"
|
|
|
|
#include "src/simulator.h"
|
|
|
|
#if V8_TARGET_ARCH_IA32
|
|
#if __GNUC__
|
|
#define V8_CDECL __attribute__((cdecl))
|
|
#else
|
|
#define V8_CDECL __cdecl
|
|
#endif
|
|
#else
|
|
#define V8_CDECL
|
|
#endif
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
// TODO(titzer): use c-signature.h instead of ReturnValueTraits
|
|
template <typename R>
|
|
struct ReturnValueTraits {
|
|
static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); }
|
|
static MachineType Representation() {
|
|
// TODO(dcarney): detect when R is of a subclass of Object* instead of this
|
|
// type check.
|
|
while (false) {
|
|
*(static_cast<Object* volatile*>(0)) = static_cast<R>(0);
|
|
}
|
|
return kMachAnyTagged;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<int32_t*> {
|
|
static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); }
|
|
static MachineType Representation() { return kMachPtr; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<void> {
|
|
static void Cast(uintptr_t r) {}
|
|
static MachineType Representation() { return kMachPtr; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<bool> {
|
|
static bool Cast(uintptr_t r) { return static_cast<bool>(r); }
|
|
static MachineType Representation() { return kRepBit; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<int32_t> {
|
|
static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); }
|
|
static MachineType Representation() { return kMachInt32; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<uint32_t> {
|
|
static uint32_t Cast(uintptr_t r) { return static_cast<uint32_t>(r); }
|
|
static MachineType Representation() { return kMachUint32; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<int64_t> {
|
|
static int64_t Cast(uintptr_t r) { return static_cast<int64_t>(r); }
|
|
static MachineType Representation() { return kMachInt64; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<uint64_t> {
|
|
static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); }
|
|
static MachineType Representation() { return kMachUint64; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<int16_t> {
|
|
static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); }
|
|
static MachineType Representation() { return kMachInt16; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<uint16_t> {
|
|
static uint16_t Cast(uintptr_t r) { return static_cast<uint16_t>(r); }
|
|
static MachineType Representation() { return kMachUint16; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<int8_t> {
|
|
static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); }
|
|
static MachineType Representation() { return kMachInt8; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<uint8_t> {
|
|
static uint8_t Cast(uintptr_t r) { return static_cast<uint8_t>(r); }
|
|
static MachineType Representation() { return kMachUint8; }
|
|
};
|
|
|
|
template <>
|
|
struct ReturnValueTraits<double> {
|
|
static double Cast(uintptr_t r) {
|
|
UNREACHABLE();
|
|
return 0.0;
|
|
}
|
|
static MachineType Representation() { return kMachFloat64; }
|
|
};
|
|
|
|
|
|
template <typename R>
|
|
struct ParameterTraits {
|
|
static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
|
|
};
|
|
|
|
template <>
|
|
struct ParameterTraits<int*> {
|
|
static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
|
|
};
|
|
|
|
template <typename T>
|
|
struct ParameterTraits<T*> {
|
|
static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
|
|
};
|
|
|
|
class CallHelper {
|
|
public:
|
|
explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig)
|
|
: machine_sig_(machine_sig), isolate_(isolate) {
|
|
USE(isolate_);
|
|
}
|
|
virtual ~CallHelper() {}
|
|
|
|
static MachineSignature* MakeMachineSignature(
|
|
Zone* zone, MachineType return_type, MachineType p0 = kMachNone,
|
|
MachineType p1 = kMachNone, MachineType p2 = kMachNone,
|
|
MachineType p3 = kMachNone, MachineType p4 = kMachNone) {
|
|
// Count the number of parameters.
|
|
size_t param_count = 5;
|
|
MachineType types[] = {p0, p1, p2, p3, p4};
|
|
while (param_count > 0 && types[param_count - 1] == kMachNone)
|
|
param_count--;
|
|
size_t return_count = return_type == kMachNone ? 0 : 1;
|
|
|
|
// Build the machine signature.
|
|
MachineSignature::Builder builder(zone, return_count, param_count);
|
|
if (return_count > 0) builder.AddReturn(return_type);
|
|
for (size_t i = 0; i < param_count; i++) {
|
|
builder.AddParam(types[i]);
|
|
}
|
|
return builder.Build();
|
|
}
|
|
|
|
protected:
|
|
MachineSignature* machine_sig_;
|
|
void VerifyParameters(size_t parameter_count, MachineType* parameter_types) {
|
|
CHECK(machine_sig_->parameter_count() == parameter_count);
|
|
for (size_t i = 0; i < parameter_count; i++) {
|
|
CHECK_EQ(machine_sig_->GetParam(i), parameter_types[i]);
|
|
}
|
|
}
|
|
virtual byte* Generate() = 0;
|
|
|
|
private:
|
|
#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
|
|
uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
|
|
Simulator* simulator = Simulator::current(isolate_);
|
|
return static_cast<uintptr_t>(simulator->CallInt64(f, args));
|
|
}
|
|
|
|
template <typename R, typename F>
|
|
R DoCall(F* f) {
|
|
Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
|
}
|
|
template <typename R, typename F, typename P1>
|
|
R DoCall(F* f, P1 p1) {
|
|
Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
|
|
Simulator::CallArgument::End()};
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2>
|
|
R DoCall(F* f, P1 p1, P2 p2) {
|
|
Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
|
|
Simulator::CallArgument(p2),
|
|
Simulator::CallArgument::End()};
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
|
Simulator::CallArgument args[] = {
|
|
Simulator::CallArgument(p1), Simulator::CallArgument(p2),
|
|
Simulator::CallArgument(p3), Simulator::CallArgument::End()};
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3,
|
|
typename P4>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
Simulator::CallArgument args[] = {
|
|
Simulator::CallArgument(p1), Simulator::CallArgument(p2),
|
|
Simulator::CallArgument(p3), Simulator::CallArgument(p4),
|
|
Simulator::CallArgument::End()};
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
|
|
}
|
|
#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
|
|
uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
|
|
int32_t p3 = 0, int32_t p4 = 0) {
|
|
Simulator* simulator = Simulator::current(isolate_);
|
|
return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
|
|
}
|
|
template <typename R, typename F>
|
|
R DoCall(F* f) {
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
|
|
}
|
|
template <typename R, typename F, typename P1>
|
|
R DoCall(F* f, P1 p1) {
|
|
return ReturnValueTraits<R>::Cast(
|
|
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2>
|
|
R DoCall(F* f, P1 p1, P2 p2) {
|
|
return ReturnValueTraits<R>::Cast(
|
|
CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
|
ParameterTraits<P2>::Cast(p2)));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(
|
|
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
|
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3,
|
|
typename P4>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
return ReturnValueTraits<R>::Cast(CallSimulator(
|
|
FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
|
|
ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
|
|
ParameterTraits<P4>::Cast(p4)));
|
|
}
|
|
#else
|
|
template <typename R, typename F>
|
|
R DoCall(F* f) {
|
|
return f();
|
|
}
|
|
template <typename R, typename F, typename P1>
|
|
R DoCall(F* f, P1 p1) {
|
|
return f(p1);
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2>
|
|
R DoCall(F* f, P1 p1, P2 p2) {
|
|
return f(p1, p2);
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
|
|
return f(p1, p2, p3);
|
|
}
|
|
template <typename R, typename F, typename P1, typename P2, typename P3,
|
|
typename P4>
|
|
R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
return f(p1, p2, p3, p4);
|
|
}
|
|
#endif
|
|
|
|
#ifndef DEBUG
|
|
void VerifyParameters0() {}
|
|
|
|
template <typename P1>
|
|
void VerifyParameters1() {}
|
|
|
|
template <typename P1, typename P2>
|
|
void VerifyParameters2() {}
|
|
|
|
template <typename P1, typename P2, typename P3>
|
|
void VerifyParameters3() {}
|
|
|
|
template <typename P1, typename P2, typename P3, typename P4>
|
|
void VerifyParameters4() {}
|
|
#else
|
|
void VerifyParameters0() { VerifyParameters(0, NULL); }
|
|
|
|
template <typename P1>
|
|
void VerifyParameters1() {
|
|
MachineType parameters[] = {ReturnValueTraits<P1>::Representation()};
|
|
VerifyParameters(arraysize(parameters), parameters);
|
|
}
|
|
|
|
template <typename P1, typename P2>
|
|
void VerifyParameters2() {
|
|
MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
|
|
ReturnValueTraits<P2>::Representation()};
|
|
VerifyParameters(arraysize(parameters), parameters);
|
|
}
|
|
|
|
template <typename P1, typename P2, typename P3>
|
|
void VerifyParameters3() {
|
|
MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
|
|
ReturnValueTraits<P2>::Representation(),
|
|
ReturnValueTraits<P3>::Representation()};
|
|
VerifyParameters(arraysize(parameters), parameters);
|
|
}
|
|
|
|
template <typename P1, typename P2, typename P3, typename P4>
|
|
void VerifyParameters4() {
|
|
MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
|
|
ReturnValueTraits<P2>::Representation(),
|
|
ReturnValueTraits<P3>::Representation(),
|
|
ReturnValueTraits<P4>::Representation()};
|
|
VerifyParameters(arraysize(parameters), parameters);
|
|
}
|
|
#endif
|
|
|
|
// TODO(dcarney): replace Call() in CallHelper2 with these.
|
|
template <typename R>
|
|
R Call0() {
|
|
typedef R V8_CDECL FType();
|
|
VerifyParameters0();
|
|
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()));
|
|
}
|
|
|
|
template <typename R, typename P1>
|
|
R Call1(P1 p1) {
|
|
typedef R V8_CDECL FType(P1);
|
|
VerifyParameters1<P1>();
|
|
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1);
|
|
}
|
|
|
|
template <typename R, typename P1, typename P2>
|
|
R Call2(P1 p1, P2 p2) {
|
|
typedef R V8_CDECL FType(P1, P2);
|
|
VerifyParameters2<P1, P2>();
|
|
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2);
|
|
}
|
|
|
|
template <typename R, typename P1, typename P2, typename P3>
|
|
R Call3(P1 p1, P2 p2, P3 p3) {
|
|
typedef R V8_CDECL FType(P1, P2, P3);
|
|
VerifyParameters3<P1, P2, P3>();
|
|
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
|
|
}
|
|
|
|
template <typename R, typename P1, typename P2, typename P3, typename P4>
|
|
R Call4(P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
typedef R V8_CDECL FType(P1, P2, P3, P4);
|
|
VerifyParameters4<P1, P2, P3, P4>();
|
|
return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
|
|
}
|
|
|
|
template <typename R, typename C>
|
|
friend class CallHelper2;
|
|
Isolate* isolate_;
|
|
};
|
|
|
|
|
|
// TODO(dcarney): replace CallHelper with CallHelper2 and rename.
|
|
template <typename R, typename C>
|
|
class CallHelper2 {
|
|
public:
|
|
R Call() { return helper()->template Call0<R>(); }
|
|
|
|
template <typename P1>
|
|
R Call(P1 p1) {
|
|
return helper()->template Call1<R>(p1);
|
|
}
|
|
|
|
template <typename P1, typename P2>
|
|
R Call(P1 p1, P2 p2) {
|
|
return helper()->template Call2<R>(p1, p2);
|
|
}
|
|
|
|
template <typename P1, typename P2, typename P3>
|
|
R Call(P1 p1, P2 p2, P3 p3) {
|
|
return helper()->template Call3<R>(p1, p2, p3);
|
|
}
|
|
|
|
template <typename P1, typename P2, typename P3, typename P4>
|
|
R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
return helper()->template Call4<R>(p1, p2, p3, p4);
|
|
}
|
|
|
|
private:
|
|
CallHelper* helper() { return static_cast<C*>(this); }
|
|
};
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_CCTEST_COMPILER_CALL_TESTER_H_
|