v8/test/cctest/compiler/call-tester.h
bmeurer@chromium.org 90c8932596 Replace our homegrown ARRAY_SIZE() with Chrome's arraysize().
Our own ARRAY_SIZE() was pretty bad at error checking. If you use
arrasize() in a wrong way, the compiler will issue an error instead of
silently doing the wrong thing. The previous ARRAY_SIZE() macro is still
available as ARRAYSIZE_UNSAFE() similar to Chrome.

R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/501323002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23389 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2014-08-26 09:19:24 +00:00

388 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): move MachineType selection for C types into machine-type.h
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) : isolate_(isolate) { USE(isolate_); }
virtual ~CallHelper() {}
static MachineCallDescriptorBuilder* ToCallDescriptorBuilder(
Zone* zone, MachineType return_type, MachineType p0 = kMachNone,
MachineType p1 = kMachNone, MachineType p2 = kMachNone,
MachineType p3 = kMachNone, MachineType p4 = kMachNone) {
const int kSize = 5;
MachineType* params = zone->NewArray<MachineType>(kSize);
params[0] = p0;
params[1] = p1;
params[2] = p2;
params[3] = p3;
params[4] = p4;
int parameter_count = 0;
for (int i = 0; i < kSize; ++i) {
if (params[i] == kMachNone) {
break;
}
parameter_count++;
}
return new (zone)
MachineCallDescriptorBuilder(return_type, parameter_count, params);
}
protected:
virtual void VerifyParameters(int parameter_count,
MachineType* parameters) = 0;
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_