diff options
author | Ali Ijaz Sheikh <ofrobots@google.com> | 2015-08-23 06:09:40 -0700 |
---|---|---|
committer | Rod Vagg <rod@vagg.org> | 2015-09-06 21:38:01 +1000 |
commit | 9fddd83cf9adf505bce2e2373881df0c4d41b261 (patch) | |
tree | 4272ce14c10fea496af2e78fc6debb187d613451 /deps/v8/test/cctest | |
parent | 46b7d151674d138e7ea4342d5f3ada1208b87ff2 (diff) | |
download | node-new-9fddd83cf9adf505bce2e2373881df0c4d41b261.tar.gz |
deps: upgrade V8 to 4.5.103.24
Upgrade to the latest branch-head for V8 4.5. For the full commit log see
https://github.com/v8/v8-git-mirror/commits/4.5.103.24
PR-URL: https://github.com/nodejs/node/pull/2509
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/test/cctest')
82 files changed, 12316 insertions, 4980 deletions
diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 276ebd2f97..bcbbe7b226 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -54,8 +54,6 @@ 'compiler/test-basic-block-profiler.cc', 'compiler/test-branch-combine.cc', 'compiler/test-changes-lowering.cc', - 'compiler/test-codegen-deopt.cc', - 'compiler/test-control-reducer.cc', 'compiler/test-gap-resolver.cc', 'compiler/test-graph-visualizer.cc', 'compiler/test-instruction.cc', diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index bade26308f..cc9edc801f 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -93,6 +93,7 @@ class TestHeap : public i::Heap { using i::Heap::AllocateByteArray; using i::Heap::AllocateFixedArray; using i::Heap::AllocateHeapNumber; + using i::Heap::AllocateFloat32x4; using i::Heap::AllocateJSObject; using i::Heap::AllocateJSObjectFromMap; using i::Heap::AllocateMap; @@ -397,6 +398,13 @@ static inline v8::Local<v8::Value> CompileRun(const char* source) { } +// Helper functions that compile and run the source. +static inline v8::MaybeLocal<v8::Value> CompileRun( + v8::Local<v8::Context> context, const char* source) { + return v8::Script::Compile(v8_str(source))->Run(context); +} + + // Compiles source as an ES6 module. static inline v8::Local<v8::Value> CompileRunModule(const char* source) { v8::ScriptCompiler::Source script_source(v8_str(source)); @@ -504,8 +512,8 @@ static inline void ExpectUndefined(const char* code) { // Helper function that simulates a full new-space in the heap. static inline bool FillUpOnePage(v8::internal::NewSpace* space) { - v8::internal::AllocationResult allocation = - space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize); + v8::internal::AllocationResult allocation = space->AllocateRawUnaligned( + v8::internal::Page::kMaxRegularHeapObjectSize); if (allocation.IsRetry()) return false; v8::internal::HeapObject* free_space = NULL; CHECK(allocation.To(&free_space)); @@ -524,7 +532,7 @@ static inline void AllocateAllButNBytes(v8::internal::NewSpace* space, int new_linear_size = space_remaining - extra_bytes; if (new_linear_size == 0) return; v8::internal::AllocationResult allocation = - space->AllocateRaw(new_linear_size); + space->AllocateRawUnaligned(new_linear_size); v8::internal::HeapObject* free_space = NULL; CHECK(allocation.To(&free_space)); space->heap()->CreateFillerObjectAt(free_space->address(), new_linear_size); @@ -561,7 +569,7 @@ static inline void SimulateIncrementalMarking(i::Heap* heap) { } CHECK(marking->IsMarking() || marking->IsStopped()); if (marking->IsStopped()) { - marking->Start(); + marking->Start(i::Heap::kNoGCFlags); } CHECK(marking->IsMarking()); while (!marking->IsComplete()) { @@ -574,6 +582,18 @@ static inline void SimulateIncrementalMarking(i::Heap* heap) { } +static void DummyDebugEventListener( + const v8::Debug::EventDetails& event_details) {} + + +static inline void EnableDebugger() { + v8::Debug::SetDebugEventListener(&DummyDebugEventListener); +} + + +static inline void DisableDebugger() { v8::Debug::SetDebugEventListener(NULL); } + + // Helper class for new allocations tracking and checking. // To use checking of JS allocations tracking in a test, // just create an instance of this class. diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 9c4f6ccf05..68c570edcc 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -64,11 +64,13 @@ # are actually 13 * 38 * 5 * 128 = 316160 individual tests hidden here. 'test-parsing/ParserSync': [PASS, NO_VARIANTS], - # This tests only the type system, so there is no point in running several - # variants. + # This tests only the type system, no point in running several variants. 'test-hydrogen-types/*': [PASS, NO_VARIANTS], 'test-types/*': [PASS, NO_VARIANTS], + # This tests API threading, no point in running several variants. + 'test-api/Threading*': [PASS, NO_VARIANTS], + # The cpu profiler tests are notoriously flaky. # BUG(2999). (test/cpu-profiler/CollectCpuProfile) # BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup) @@ -97,11 +99,7 @@ ############################################################################## # TurboFan compiler failures. - # TODO(mstarzinger): control edges are messed up in exception tests. - 'test-run-jsexceptions/*': [PASS, NO_VARIANTS], - # Some tests are just too slow to run for now. - 'test-api/Threading*': [PASS, NO_VARIANTS], 'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [PASS, NO_VARIANTS], 'test-heap-profiler/ManyLocalsInSharedContext': [PASS, NO_VARIANTS], 'test-serialize/SerializeToplevelLargeCodeObject': [PASS, NO_VARIANTS], @@ -119,12 +117,6 @@ 'test-debug/ScriptBreakPointByIdThroughJavaScript': [PASS, NO_VARIANTS], 'test-debug/ScriptBreakPointByNameThroughJavaScript': [PASS, NO_VARIANTS], - # TODO(jarin): Cannot lazy-deoptimize from conversions before comparisons. - 'test-js-typed-lowering/OrderCompareEffects': [SKIP], - - # TODO(jochen): Reenable after we removed the CHECK() from the marking queue. - 'test-mark-compact/MarkingDeque': [SKIP], - ############################################################################ # Slow tests. 'test-api/Threading1': [PASS, ['mode == debug', SLOW]], @@ -194,6 +186,12 @@ ['msan == True', { # ICU upstream issues. 'test-strings/CountBreakIterator': [SKIP], + + # Slow tests. + 'test-api/Threading1': [PASS, SLOW], + 'test-api/Threading2': [PASS, SLOW], + 'test-api/Threading3': [PASS, SLOW], + 'test-api/Threading4': [PASS, SLOW], }], # 'msan == True' ############################################################################## @@ -258,6 +256,9 @@ ['arch == mipsel or arch == mips', { 'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL], + # TODO(mips-team): Improve code-size on large RegExp's. + 'test-heap/TestSizeOfRegExpCode': [SKIP], + # BUG(1075): Unresolved crashes on MIPS also. 'test-serialize/Deserialize': [SKIP], 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP], @@ -271,12 +272,8 @@ 'test-api/ExternalArrays': [PASS, NO_VARIANTS], # TODO(mips-team): Currently fails on mips board. - 'test-simplified-lowering/RunNumberMultiply_TruncatingToUint32': [SKIP], - 'test-simplified-lowering/RunNumberDivide_2_TruncatingToUint32': [SKIP], 'test-parsing/TooManyArguments': [SKIP], 'test-api/Threading3': [SKIP], - 'test-api/RequestInterruptTestWithNativeAccessor': [SKIP], - 'test-api/RequestInterruptTestWithAccessor': [SKIP], }], # 'arch == mips' ############################################################################## @@ -295,12 +292,7 @@ ############################################################################## ['arch == x87', { - - # Test requires turbofan: - 'codegen-tester/CompareWrapper': [SKIP], - 'codegen-tester/ParametersEqual': [SKIP], - 'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP], - 'test-serialize/SerializeInternalReference': [FAIL], + 'test-run-machops/RunFloat64InsertLowWord32': [SKIP] }], # 'arch == x87' ############################################################################## diff --git a/deps/v8/test/cctest/compiler/c-signature.h b/deps/v8/test/cctest/compiler/c-signature.h index 5d161dbe7a..83b3328a3b 100644 --- a/deps/v8/test/cctest/compiler/c-signature.h +++ b/deps/v8/test/cctest/compiler/c-signature.h @@ -11,76 +11,103 @@ namespace v8 { namespace internal { namespace compiler { +#define FOREACH_CTYPE_MACHINE_TYPE_MAPPING(V) \ + V(void, kMachNone) \ + V(bool, kMachBool) \ + V(int8_t, kMachInt8) \ + V(uint8_t, kMachUint8) \ + V(int16_t, kMachInt16) \ + V(uint16_t, kMachUint16) \ + V(int32_t, kMachInt32) \ + V(uint32_t, kMachUint32) \ + V(int64_t, kMachInt64) \ + V(uint64_t, kMachUint64) \ + V(float, kMachFloat32) \ + V(double, kMachFloat64) \ + V(void*, kMachPtr) \ + V(int*, kMachPtr) + template <typename T> inline MachineType MachineTypeForC() { - CHECK(false); // Instantiated with invalid type. - return kMachNone; -} - -template <> -inline MachineType MachineTypeForC<void>() { - return kMachNone; -} - -template <> -inline MachineType MachineTypeForC<int8_t>() { - return kMachInt8; -} - -template <> -inline MachineType MachineTypeForC<uint8_t>() { - return kMachUint8; -} - -template <> -inline MachineType MachineTypeForC<int16_t>() { - return kMachInt16; -} - -template <> -inline MachineType MachineTypeForC<uint16_t>() { - return kMachUint16; -} - -template <> -inline MachineType MachineTypeForC<int32_t>() { - return kMachInt32; + while (false) { + // All other types T must be assignable to Object* + *(static_cast<Object* volatile*>(0)) = static_cast<T>(0); + } + return kMachAnyTagged; } -template <> -inline MachineType MachineTypeForC<uint32_t>() { - return kMachUint32; -} +#define DECLARE_TEMPLATE_SPECIALIZATION(ctype, mtype) \ + template <> \ + inline MachineType MachineTypeForC<ctype>() { \ + return mtype; \ + } +FOREACH_CTYPE_MACHINE_TYPE_MAPPING(DECLARE_TEMPLATE_SPECIALIZATION) +#undef DECLARE_TEMPLATE_SPECIALIZATION -template <> -inline MachineType MachineTypeForC<int64_t>() { - return kMachInt64; -} +// Helper for building machine signatures from C types. +class CSignature : public MachineSignature { + protected: + CSignature(size_t return_count, size_t parameter_count, MachineType* reps) + : MachineSignature(return_count, parameter_count, reps) {} -template <> -inline MachineType MachineTypeForC<uint64_t>() { - return kMachUint64; -} + public: + template <typename P1 = void, typename P2 = void, typename P3 = void, + typename P4 = void, typename P5 = void> + void VerifyParams() { + // Verifies the C signature against the machine types. Maximum {5} params. + CHECK_LT(parameter_count(), 6u); + const int kMax = 5; + MachineType params[] = {MachineTypeForC<P1>(), MachineTypeForC<P2>(), + MachineTypeForC<P3>(), MachineTypeForC<P4>(), + MachineTypeForC<P5>()}; + for (int p = kMax - 1; p >= 0; p--) { + if (p < static_cast<int>(parameter_count())) { + CHECK_EQ(GetParam(p), params[p]); + } else { + CHECK_EQ(kMachNone, params[p]); + } + } + } -template <> -inline MachineType MachineTypeForC<double>() { - return kMachFloat64; -} + static CSignature* New(Zone* zone, MachineType ret, + MachineType p1 = kMachNone, MachineType p2 = kMachNone, + MachineType p3 = kMachNone, MachineType p4 = kMachNone, + MachineType p5 = kMachNone) { + MachineType* buffer = zone->NewArray<MachineType>(6); + int pos = 0; + size_t return_count = 0; + if (ret != kMachNone) { + buffer[pos++] = ret; + return_count++; + } + buffer[pos++] = p1; + buffer[pos++] = p2; + buffer[pos++] = p3; + buffer[pos++] = p4; + buffer[pos++] = p5; + size_t param_count = 5; + if (p5 == kMachNone) param_count--; + if (p4 == kMachNone) param_count--; + if (p3 == kMachNone) param_count--; + if (p2 == kMachNone) param_count--; + if (p1 == kMachNone) param_count--; + for (size_t i = 0; i < param_count; i++) { + // Check that there are no kMachNone's in the middle of parameters. + CHECK_NE(kMachNone, buffer[return_count + i]); + } + return new (zone) CSignature(return_count, param_count, buffer); + } +}; -template <> -inline MachineType MachineTypeForC<Object*>() { - return kMachAnyTagged; -} template <typename Ret, uint16_t kParamCount> -class CSignatureOf : public MachineSignature { +class CSignatureOf : public CSignature { protected: MachineType storage_[1 + kParamCount]; CSignatureOf() - : MachineSignature(MachineTypeForC<Ret>() != kMachNone ? 1 : 0, - kParamCount, - reinterpret_cast<MachineType*>(&storage_)) { + : CSignature(MachineTypeForC<Ret>() != kMachNone ? 1 : 0, kParamCount, + reinterpret_cast<MachineType*>(&storage_)) { if (return_count_ == 1) storage_[0] = MachineTypeForC<Ret>(); } void Set(int index, MachineType type) { @@ -123,9 +150,11 @@ class CSignature3 : public CSignatureOf<Ret, 3> { } }; -static const CSignature2<int32_t, int32_t, int32_t> int32_int32_to_int32; -static const CSignature2<uint32_t, uint32_t, uint32_t> uint32_uint32_to_uint32; -static const CSignature2<double, double, double> float64_float64_to_float64; +typedef CSignature2<int32_t, int32_t, int32_t> CSignature_i_ii; +typedef CSignature2<uint32_t, uint32_t, uint32_t> CSignature_u_uu; +typedef CSignature2<float, float, float> CSignature_f_ff; +typedef CSignature2<double, double, double> CSignature_d_dd; +typedef CSignature2<Object*, Object*, Object*> CSignature_o_oo; } } } // namespace v8::internal::compiler diff --git a/deps/v8/test/cctest/compiler/call-tester.h b/deps/v8/test/cctest/compiler/call-tester.h index 6d8c761452..dc265ea5fa 100644 --- a/deps/v8/test/cctest/compiler/call-tester.h +++ b/deps/v8/test/cctest/compiler/call-tester.h @@ -9,6 +9,8 @@ #include "src/simulator.h" +#include "test/cctest/compiler/c-signature.h" + #if V8_TARGET_ARCH_IA32 #if __GNUC__ #define V8_CDECL __attribute__((cdecl)) @@ -23,95 +25,64 @@ 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; - } -}; +inline R CastReturnValue(uintptr_t r) { + return reinterpret_cast<R>(r); +} template <> -struct ReturnValueTraits<int32_t*> { - static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); } - static MachineType Representation() { return kMachPtr; } -}; +inline void CastReturnValue(uintptr_t r) {} template <> -struct ReturnValueTraits<void> { - static void Cast(uintptr_t r) {} - static MachineType Representation() { return kMachPtr; } -}; +inline bool CastReturnValue(uintptr_t r) { + return static_cast<bool>(r); +} template <> -struct ReturnValueTraits<bool> { - static bool Cast(uintptr_t r) { return static_cast<bool>(r); } - static MachineType Representation() { return kRepBit; } -}; +inline int32_t CastReturnValue(uintptr_t r) { + return static_cast<int32_t>(r); +} template <> -struct ReturnValueTraits<int32_t> { - static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); } - static MachineType Representation() { return kMachInt32; } -}; +inline uint32_t CastReturnValue(uintptr_t r) { + return static_cast<uint32_t>(r); +} 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; } -}; +inline int64_t CastReturnValue(uintptr_t r) { + return static_cast<int64_t>(r); +} template <> -struct ReturnValueTraits<uint64_t> { - static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); } - static MachineType Representation() { return kMachUint64; } -}; +inline uint64_t CastReturnValue(uintptr_t r) { + return static_cast<uint64_t>(r); +} template <> -struct ReturnValueTraits<int16_t> { - static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); } - static MachineType Representation() { return kMachInt16; } -}; +inline int16_t CastReturnValue(uintptr_t r) { + return static_cast<int16_t>(r); +} template <> -struct ReturnValueTraits<uint16_t> { - static uint16_t Cast(uintptr_t r) { return static_cast<uint16_t>(r); } - static MachineType Representation() { return kMachUint16; } -}; +inline uint16_t CastReturnValue(uintptr_t r) { + return static_cast<uint16_t>(r); +} template <> -struct ReturnValueTraits<int8_t> { - static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); } - static MachineType Representation() { return kMachInt8; } -}; +inline int8_t CastReturnValue(uintptr_t r) { + return static_cast<int8_t>(r); +} template <> -struct ReturnValueTraits<uint8_t> { - static uint8_t Cast(uintptr_t r) { return static_cast<uint8_t>(r); } - static MachineType Representation() { return kMachUint8; } -}; +inline uint8_t CastReturnValue(uintptr_t r) { + return static_cast<uint8_t>(r); +} template <> -struct ReturnValueTraits<double> { - static double Cast(uintptr_t r) { - UNREACHABLE(); - return 0.0; - } - static MachineType Representation() { return kMachFloat64; } -}; - +inline double CastReturnValue(uintptr_t r) { + UNREACHABLE(); + return 0.0; +} template <typename R> struct ParameterTraits { @@ -148,42 +119,52 @@ struct ParameterTraits<uint32_t> { #endif // !V8_TARGET_ARCH_64_BIT +template <typename R> class CallHelper { public: - explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig) - : machine_sig_(machine_sig), isolate_(isolate) { + explicit CallHelper(Isolate* isolate, CSignature* csig) + : csig_(csig), 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(); + R Call() { + typedef R V8_CDECL FType(); + csig_->VerifyParams(); + return DoCall(FUNCTION_CAST<FType*>(Generate())); } - 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]); - } + template <typename P1> + R Call(P1 p1) { + typedef R V8_CDECL FType(P1); + csig_->VerifyParams<P1>(); + return DoCall(FUNCTION_CAST<FType*>(Generate()), p1); + } + + template <typename P1, typename P2> + R Call(P1 p1, P2 p2) { + typedef R V8_CDECL FType(P1, P2); + csig_->VerifyParams<P1, P2>(); + return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2); + } + + template <typename P1, typename P2, typename P3> + R Call(P1 p1, P2 p2, P3 p3) { + typedef R V8_CDECL FType(P1, P2, P3); + csig_->VerifyParams<P1, P2, P3>(); + return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3); + } + + template <typename P1, typename P2, typename P3, typename P4> + R Call(P1 p1, P2 p2, P3 p3, P4 p4) { + typedef R V8_CDECL FType(P1, P2, P3, P4); + csig_->VerifyParams<P1, P2, P3, P4>(); + return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4); } + + protected: + CSignature* csig_; + virtual byte* Generate() = 0; private: @@ -193,39 +174,38 @@ class CallHelper { return static_cast<uintptr_t>(simulator->CallInt64(f, args)); } - template <typename R, typename F> + template <typename F> R DoCall(F* f) { Simulator::CallArgument args[] = {Simulator::CallArgument::End()}; - return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); } - template <typename R, typename F, typename P1> + template <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)); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); } - template <typename R, typename F, typename P1, typename P2> + template <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)); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); } - template <typename R, typename F, typename P1, typename P2, typename P3> + template <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)); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); } - template <typename R, typename F, typename P1, typename P2, typename P3, - typename P4> + template <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)); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args)); } #elif USE_SIMULATOR && (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64) uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0, @@ -235,31 +215,30 @@ class CallHelper { } - template <typename R, typename F> + template <typename F> R DoCall(F* f) { - return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f))); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f))); } - template <typename R, typename F, typename P1> + template <typename F, typename P1> R DoCall(F* f, P1 p1) { - return ReturnValueTraits<R>::Cast( + return CastReturnValue<R>( CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1))); } - template <typename R, typename F, typename P1, typename P2> + template <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))); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), + ParameterTraits<P1>::Cast(p1), + ParameterTraits<P2>::Cast(p2))); } - template <typename R, typename F, typename P1, typename P2, typename P3> + template <typename F, typename P1, typename P2, typename P3> R DoCall(F* f, P1 p1, P2 p2, P3 p3) { - return ReturnValueTraits<R>::Cast(CallSimulator( + return CastReturnValue<R>(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> + template <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( + return CastReturnValue<R>(CallSimulator( FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1), ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3), ParameterTraits<P4>::Cast(p4))); @@ -271,179 +250,60 @@ class CallHelper { Simulator* simulator = Simulator::current(isolate_); return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4)); } - template <typename R, typename F> + template <typename F> R DoCall(F* f) { - return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f))); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f))); } - template <typename R, typename F, typename P1> + template <typename F, typename P1> R DoCall(F* f, P1 p1) { - return ReturnValueTraits<R>::Cast( + return CastReturnValue<R>( CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1))); } - template <typename R, typename F, typename P1, typename P2> + template <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))); + return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), + ParameterTraits<P1>::Cast(p1), + ParameterTraits<P2>::Cast(p2))); } - template <typename R, typename F, typename P1, typename P2, typename P3> + template <typename F, typename P1, typename P2, typename P3> R DoCall(F* f, P1 p1, P2 p2, P3 p3) { - return ReturnValueTraits<R>::Cast(CallSimulator( + return CastReturnValue<R>(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> + template <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( + return CastReturnValue<R>(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> + template <typename F> R DoCall(F* f) { return f(); } - template <typename R, typename F, typename P1> + template <typename F, typename P1> R DoCall(F* f, P1 p1) { return f(p1); } - template <typename R, typename F, typename P1, typename P2> + template <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> + template <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> + template <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 diff --git a/deps/v8/test/cctest/compiler/codegen-tester.h b/deps/v8/test/cctest/compiler/codegen-tester.h index f2fc48a479..bc6d938ce1 100644 --- a/deps/v8/test/cctest/compiler/codegen-tester.h +++ b/deps/v8/test/cctest/compiler/codegen-tester.h @@ -17,38 +17,26 @@ namespace v8 { namespace internal { namespace compiler { -template <typename MachineAssembler> -class MachineAssemblerTester : public HandleAndZoneScope, - public CallHelper, - public MachineAssembler { +template <typename ReturnType> +class RawMachineAssemblerTester : public HandleAndZoneScope, + public CallHelper<ReturnType>, + public RawMachineAssembler { public: - MachineAssemblerTester(MachineType return_type, MachineType p0, - MachineType p1, MachineType p2, MachineType p3, - MachineType p4, - MachineOperatorBuilder::Flags flags = - MachineOperatorBuilder::Flag::kNoFlags) + RawMachineAssemblerTester(MachineType p0 = kMachNone, + MachineType p1 = kMachNone, + MachineType p2 = kMachNone, + MachineType p3 = kMachNone, + MachineType p4 = kMachNone) : HandleAndZoneScope(), - CallHelper( + CallHelper<ReturnType>( main_isolate(), - MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4)), - MachineAssembler( + CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, p1, + p2, p3, p4)), + RawMachineAssembler( main_isolate(), new (main_zone()) Graph(main_zone()), - MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4), - kMachPtr, flags) {} - - Node* LoadFromPointer(void* address, MachineType rep, int32_t offset = 0) { - return this->Load(rep, this->PointerConstant(address), - this->Int32Constant(offset)); - } - - void StoreToPointer(void* address, MachineType rep, Node* node) { - this->Store(rep, this->PointerConstant(address), node); - } - - Node* StringConstant(const char* string) { - return this->HeapConstant( - this->isolate()->factory()->InternalizeUtf8String(string)); - } + CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, p1, + p2, p3, p4), + kMachPtr, InstructionSelector::SupportedMachineOperatorFlags()) {} void CheckNumber(double expected, Object* number) { CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number)); @@ -79,41 +67,6 @@ class MachineAssemblerTester : public HandleAndZoneScope, }; -template <typename ReturnType> -class RawMachineAssemblerTester - : public MachineAssemblerTester<RawMachineAssembler>, - public CallHelper2<ReturnType, RawMachineAssemblerTester<ReturnType> > { - public: - RawMachineAssemblerTester(MachineType p0 = kMachNone, - MachineType p1 = kMachNone, - MachineType p2 = kMachNone, - MachineType p3 = kMachNone, - MachineType p4 = kMachNone) - : MachineAssemblerTester<RawMachineAssembler>( - ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, p4, - InstructionSelector::SupportedMachineOperatorFlags()) {} - - template <typename Ci, typename Fn> - void Run(const Ci& ci, const Fn& fn) { - typename Ci::const_iterator i; - for (i = ci.begin(); i != ci.end(); ++i) { - CHECK_EQ(fn(*i), this->Call(*i)); - } - } - - template <typename Ci, typename Cj, typename Fn> - void Run(const Ci& ci, const Cj& cj, const Fn& fn) { - typename Ci::const_iterator i; - typename Cj::const_iterator j; - for (i = ci.begin(); i != ci.end(); ++i) { - for (j = cj.begin(); j != cj.end(); ++j) { - CHECK_EQ(fn(*i, *j), this->Call(*i, *j)); - } - } - } -}; - - static const bool USE_RESULT_BUFFER = true; static const bool USE_RETURN_REGISTER = false; static const int32_t CHECK_VALUE = 0x99BEEDCE; diff --git a/deps/v8/test/cctest/compiler/function-tester.h b/deps/v8/test/cctest/compiler/function-tester.h index 20efd1e304..54c62ab634 100644 --- a/deps/v8/test/cctest/compiler/function-tester.h +++ b/deps/v8/test/cctest/compiler/function-tester.h @@ -34,15 +34,16 @@ class FunctionTester : public InitializedHandleScope { flags_(flags) { Compile(function); const uint32_t supported_flags = CompilationInfo::kContextSpecializing | - CompilationInfo::kBuiltinInliningEnabled | CompilationInfo::kInliningEnabled | CompilationInfo::kTypingEnabled; CHECK_EQ(0u, flags_ & ~supported_flags); } + // TODO(turbofan): generalize FunctionTester to work with N arguments. Now, it + // can handle up to four. explicit FunctionTester(Graph* graph) : isolate(main_isolate()), - function(NewFunction("(function(a,b){})")), + function(NewFunction("(function(a,b,c,d){})")), flags_(0) { CompileGraph(graph); } @@ -55,8 +56,14 @@ class FunctionTester : public InitializedHandleScope { return Execution::Call(isolate, function, undefined(), 2, args, false); } + MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b, Handle<Object> c, + Handle<Object> d) { + Handle<Object> args[] = {a, b, c, d}; + return Execution::Call(isolate, function, undefined(), 4, args, false); + } + void CheckThrows(Handle<Object> a, Handle<Object> b) { - TryCatch try_catch; + TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); MaybeHandle<Object> no_result = Call(a, b); CHECK(isolate->has_pending_exception()); CHECK(try_catch.HasCaught()); @@ -66,7 +73,7 @@ class FunctionTester : public InitializedHandleScope { v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a, Handle<Object> b) { - TryCatch try_catch; + TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); MaybeHandle<Object> no_result = Call(a, b); CHECK(isolate->has_pending_exception()); CHECK(try_catch.HasCaught()); @@ -153,6 +160,7 @@ class FunctionTester : public InitializedHandleScope { Zone zone; ParseInfo parse_info(&zone, function); CompilationInfo info(&parse_info); + info.MarkAsDeoptimizationEnabled(); CHECK(Parser::ParseStatic(info.parse_info())); info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); @@ -170,11 +178,8 @@ class FunctionTester : public InitializedHandleScope { Pipeline pipeline(&info); Handle<Code> code = pipeline.GenerateCode(); - if (FLAG_turbo_deoptimization) { - info.context()->native_context()->AddOptimizedCode(*code); - } - CHECK(!code.is_null()); + info.context()->native_context()->AddOptimizedCode(*code); function->ReplaceCode(*code); #elif USE_CRANKSHAFT Handle<Code> unoptimized = Handle<Code>(function->code()); diff --git a/deps/v8/test/cctest/compiler/graph-builder-tester.h b/deps/v8/test/cctest/compiler/graph-builder-tester.h index 9a5174c1d7..7270293e0f 100644 --- a/deps/v8/test/cctest/compiler/graph-builder-tester.h +++ b/deps/v8/test/cctest/compiler/graph-builder-tester.h @@ -39,12 +39,10 @@ class GraphAndBuilders { template <typename ReturnType> -class GraphBuilderTester - : public HandleAndZoneScope, - private GraphAndBuilders, - public CallHelper, - public SimplifiedGraphBuilder, - public CallHelper2<ReturnType, GraphBuilderTester<ReturnType> > { +class GraphBuilderTester : public HandleAndZoneScope, + private GraphAndBuilders, + public CallHelper<ReturnType>, + public SimplifiedGraphBuilder { public: explicit GraphBuilderTester(MachineType p0 = kMachNone, MachineType p1 = kMachNone, @@ -52,11 +50,10 @@ class GraphBuilderTester MachineType p3 = kMachNone, MachineType p4 = kMachNone) : GraphAndBuilders(main_zone()), - CallHelper( + CallHelper<ReturnType>( main_isolate(), - MakeMachineSignature( - main_zone(), ReturnValueTraits<ReturnType>::Representation(), - p0, p1, p2, p3, p4)), + CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, p1, + p2, p3, p4)), SimplifiedGraphBuilder(main_isolate(), main_graph_, &main_common_, &main_machine_, &main_simplified_), parameters_(main_zone()->template NewArray<Node*>(parameter_count())) { @@ -79,7 +76,7 @@ class GraphBuilderTester if (code_.is_null()) { Zone* zone = graph()->zone(); CallDescriptor* desc = - Linkage::GetSimplifiedCDescriptor(zone, machine_sig_); + Linkage::GetSimplifiedCDescriptor(zone, this->csig_); code_ = Pipeline::GenerateCodeForTesting(main_isolate(), desc, graph()); } return code_.ToHandleChecked()->entry(); @@ -92,7 +89,7 @@ class GraphBuilderTester } } - size_t parameter_count() const { return machine_sig_->parameter_count(); } + size_t parameter_count() const { return this->csig_->parameter_count(); } private: Node** parameters_; diff --git a/deps/v8/test/cctest/compiler/simplified-graph-builder.cc b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc index 6afdc0a211..4d57719eff 100644 --- a/deps/v8/test/cctest/compiler/simplified-graph-builder.cc +++ b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc @@ -23,7 +23,7 @@ SimplifiedGraphBuilder::SimplifiedGraphBuilder( void SimplifiedGraphBuilder::Begin(int num_parameters) { DCHECK(graph()->start() == NULL); - Node* start = graph()->NewNode(common()->Start(num_parameters)); + Node* start = graph()->NewNode(common()->Start(num_parameters + 3)); graph()->SetStart(start); effect_ = start; } @@ -37,7 +37,7 @@ void SimplifiedGraphBuilder::Return(Node* value) { void SimplifiedGraphBuilder::End() { - Node* end = graph()->NewNode(common()->End(), return_); + Node* end = graph()->NewNode(common()->End(1), return_); graph()->SetEnd(end); } diff --git a/deps/v8/test/cctest/compiler/simplified-graph-builder.h b/deps/v8/test/cctest/compiler/simplified-graph-builder.h index c9ba002c25..50c51d5ed8 100644 --- a/deps/v8/test/cctest/compiler/simplified-graph-builder.h +++ b/deps/v8/test/cctest/compiler/simplified-graph-builder.h @@ -92,9 +92,6 @@ class SimplifiedGraphBuilder : public GraphBuilder { Node* StringLessThanOrEqual(Node* a, Node* b) { return NewNode(simplified()->StringLessThanOrEqual(), a, b); } - Node* StringAdd(Node* a, Node* b) { - return NewNode(simplified()->StringAdd(), a, b); - } Node* ChangeTaggedToInt32(Node* a) { return NewNode(simplified()->ChangeTaggedToInt32(), a); diff --git a/deps/v8/test/cctest/compiler/test-changes-lowering.cc b/deps/v8/test/cctest/compiler/test-changes-lowering.cc index d11210bb8b..04b5b9176b 100644 --- a/deps/v8/test/cctest/compiler/test-changes-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-changes-lowering.cc @@ -88,7 +88,7 @@ class ChangesLoweringTester : public GraphBuilderTester<ReturnType> { Node* change = this->graph()->NewNode(op, p0); Node* ret = this->graph()->NewNode(this->common()->Return(), change, this->start(), this->start()); - Node* end = this->graph()->NewNode(this->common()->End(), ret); + Node* end = this->graph()->NewNode(this->common()->End(1), ret); this->graph()->SetEnd(end); LowerChange(change); } @@ -104,7 +104,7 @@ class ChangesLoweringTester : public GraphBuilderTester<ReturnType> { change, this->start(), this->start()); Node* ret = this->graph()->NewNode( this->common()->Return(), this->Int32Constant(0), store, this->start()); - Node* end = this->graph()->NewNode(this->common()->End(), ret); + Node* end = this->graph()->NewNode(this->common()->End(1), ret); this->graph()->SetEnd(end); LowerChange(change); } @@ -119,18 +119,18 @@ class ChangesLoweringTester : public GraphBuilderTester<ReturnType> { Node* change = this->graph()->NewNode(op, load); Node* ret = this->graph()->NewNode(this->common()->Return(), change, this->start(), this->start()); - Node* end = this->graph()->NewNode(this->common()->End(), ret); + Node* end = this->graph()->NewNode(this->common()->End(1), ret); this->graph()->SetEnd(end); LowerChange(change); } void LowerChange(Node* change) { // Run the graph reducer with changes lowering on a single node. - Typer typer(this->isolate(), this->graph(), Handle<Context>()); + Typer typer(this->isolate(), this->graph()); typer.Run(); ChangeLowering change_lowering(&jsgraph); SelectLowering select_lowering(this->graph(), this->common()); - GraphReducer reducer(this->graph(), this->zone()); + GraphReducer reducer(this->zone(), this->graph()); reducer.AddReducer(&change_lowering); reducer.AddReducer(&select_lowering); reducer.ReduceNode(change); diff --git a/deps/v8/test/cctest/compiler/test-codegen-deopt.cc b/deps/v8/test/cctest/compiler/test-codegen-deopt.cc deleted file mode 100644 index 0b59308216..0000000000 --- a/deps/v8/test/cctest/compiler/test-codegen-deopt.cc +++ /dev/null @@ -1,301 +0,0 @@ -// 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. - -#include "src/v8.h" -#include "test/cctest/cctest.h" - -#include "src/compiler/code-generator.h" -#include "src/compiler/common-operator.h" -#include "src/compiler/graph.h" -#include "src/compiler/instruction-selector.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node.h" -#include "src/compiler/operator.h" -#include "src/compiler/raw-machine-assembler.h" -#include "src/compiler/register-allocator.h" -#include "src/compiler/schedule.h" - -#include "src/ast-numbering.h" -#include "src/full-codegen.h" -#include "src/parser.h" -#include "src/rewriter.h" - -#include "test/cctest/compiler/c-signature.h" -#include "test/cctest/compiler/function-tester.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - - -#if V8_TURBOFAN_TARGET - -typedef RawMachineAssembler::Label MLabel; -typedef v8::internal::compiler::InstructionSequence TestInstrSeq; - -static Handle<JSFunction> NewFunction(const char* source) { - return v8::Utils::OpenHandle( - *v8::Handle<v8::Function>::Cast(CompileRun(source))); -} - - -class DeoptCodegenTester { - public: - explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src) - : scope_(scope), - function(NewFunction(src)), - parse_info(scope->main_zone(), function), - info(&parse_info), - bailout_id(-1), - tagged_type(1, kMachAnyTagged, zone()), - empty_types(zone()) { - CHECK(Parser::ParseStatic(&parse_info)); - info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); - CHECK(Compiler::Analyze(&parse_info)); - CHECK(Compiler::EnsureDeoptimizationSupport(&info)); - - DCHECK(info.shared_info()->has_deoptimization_support()); - - graph = new (scope_->main_zone()) Graph(scope_->main_zone()); - } - - virtual ~DeoptCodegenTester() {} - - void GenerateCodeFromSchedule(Schedule* schedule) { - OFStream os(stdout); - if (FLAG_trace_turbo) { - os << *schedule; - } - result_code = Pipeline::GenerateCodeForTesting(&info, graph, schedule); -#ifdef OBJECT_PRINT - if (FLAG_print_opt_code || FLAG_trace_turbo) { - result_code->Print(); - } -#endif - } - - Zone* zone() { return scope_->main_zone(); } - Isolate* isolate() { return scope_->main_isolate(); } - - HandleAndZoneScope* scope_; - Handle<JSFunction> function; - ParseInfo parse_info; - CompilationInfo info; - BailoutId bailout_id; - Handle<Code> result_code; - TestInstrSeq* code; - Graph* graph; - ZoneVector<MachineType> tagged_type; - ZoneVector<MachineType> empty_types; -}; - - -class TrivialDeoptCodegenTester : public DeoptCodegenTester { - public: - explicit TrivialDeoptCodegenTester(HandleAndZoneScope* scope) - : DeoptCodegenTester(scope, - "function foo() { deopt(); return 42; }; foo") {} - - void GenerateCode() { - GenerateCodeFromSchedule(BuildGraphAndSchedule(graph)); - } - - Schedule* BuildGraphAndSchedule(Graph* graph) { - CommonOperatorBuilder common(zone()); - - // Manually construct a schedule for the function below: - // function foo() { - // deopt(); - // } - - CSignature1<Object*, Object*> sig; - RawMachineAssembler m(isolate(), graph, &sig); - - Handle<JSFunction> deopt_function = - NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt"); - Unique<JSFunction> deopt_fun_constant = - Unique<JSFunction>::CreateUninitialized(deopt_function); - Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant)); - - Handle<Context> caller_context(function->context(), CcTest::i_isolate()); - Unique<Context> caller_context_constant = - Unique<Context>::CreateUninitialized(caller_context); - Node* caller_context_node = - m.NewNode(common.HeapConstant(caller_context_constant)); - - bailout_id = GetCallBailoutId(); - Node* parameters = - m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); - Node* locals = m.NewNode(common.TypedStateValues(&empty_types)); - Node* stack = m.NewNode(common.TypedStateValues(&empty_types)); - - Node* state_node = m.NewNode( - common.FrameState(JS_FRAME, bailout_id, - OutputFrameStateCombine::Ignore()), - parameters, locals, stack, caller_context_node, m.UndefinedConstant()); - - Handle<Context> context(deopt_function->context(), CcTest::i_isolate()); - Unique<Context> context_constant = - Unique<Context>::CreateUninitialized(context); - Node* context_node = m.NewNode(common.HeapConstant(context_constant)); - - m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node); - - m.Return(m.UndefinedConstant()); - - // Schedule the graph: - Schedule* schedule = m.Export(); - - return schedule; - } - - BailoutId GetCallBailoutId() { - ZoneList<Statement*>* body = info.function()->body(); - for (int i = 0; i < body->length(); i++) { - if (body->at(i)->IsExpressionStatement() && - body->at(i)->AsExpressionStatement()->expression()->IsCall()) { - return body->at(i)->AsExpressionStatement()->expression()->id(); - } - } - CHECK(false); - return BailoutId(-1); - } -}; - - -TEST(TurboTrivialDeoptCodegen) { - HandleAndZoneScope scope; - InitializedHandleScope handles; - - FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; - - TrivialDeoptCodegenTester t(&scope); - t.GenerateCode(); - - DeoptimizationInputData* data = - DeoptimizationInputData::cast(t.result_code->deoptimization_data()); - - // TODO(jarin) Find a way to test the safepoint. - - // Check that we deoptimize to the right AST id. - CHECK_EQ(1, data->DeoptCount()); - CHECK_EQ(t.bailout_id.ToInt(), data->AstId(0).ToInt()); -} - - -TEST(TurboTrivialDeoptCodegenAndRun) { - HandleAndZoneScope scope; - InitializedHandleScope handles; - - FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; - - TrivialDeoptCodegenTester t(&scope); - t.GenerateCode(); - - t.function->ReplaceCode(*t.result_code); - t.info.context()->native_context()->AddOptimizedCode(*t.result_code); - - Isolate* isolate = scope.main_isolate(); - Handle<Object> result; - bool has_pending_exception = - !Execution::Call(isolate, t.function, - isolate->factory()->undefined_value(), 0, NULL, - false).ToHandle(&result); - CHECK(!has_pending_exception); - CHECK(result->SameValue(Smi::FromInt(42))); -} - - -class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { - public: - explicit TrivialRuntimeDeoptCodegenTester(HandleAndZoneScope* scope) - : DeoptCodegenTester( - scope, - "function foo() { %DeoptimizeFunction(foo); return 42; }; foo") {} - - void GenerateCode() { - GenerateCodeFromSchedule(BuildGraphAndSchedule(graph)); - } - - Schedule* BuildGraphAndSchedule(Graph* graph) { - CommonOperatorBuilder common(zone()); - - // Manually construct a schedule for the function below: - // function foo() { - // %DeoptimizeFunction(foo); - // } - - CSignature1<Object*, Object*> sig; - RawMachineAssembler m(isolate(), graph, &sig); - - Unique<HeapObject> this_fun_constant = - Unique<HeapObject>::CreateUninitialized(function); - Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant)); - - Handle<Context> context(function->context(), CcTest::i_isolate()); - Unique<HeapObject> context_constant = - Unique<HeapObject>::CreateUninitialized(context); - Node* context_node = m.NewNode(common.HeapConstant(context_constant)); - - bailout_id = GetCallBailoutId(); - Node* parameters = - m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); - Node* locals = m.NewNode(common.TypedStateValues(&empty_types)); - Node* stack = m.NewNode(common.TypedStateValues(&empty_types)); - - Node* state_node = m.NewNode( - common.FrameState(JS_FRAME, bailout_id, - OutputFrameStateCombine::Ignore()), - parameters, locals, stack, context_node, m.UndefinedConstant()); - - m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node, - state_node); - - m.Return(m.UndefinedConstant()); - - // Schedule the graph: - Schedule* schedule = m.Export(); - - return schedule; - } - - BailoutId GetCallBailoutId() { - ZoneList<Statement*>* body = info.function()->body(); - for (int i = 0; i < body->length(); i++) { - if (body->at(i)->IsExpressionStatement() && - body->at(i)->AsExpressionStatement()->expression()->IsCallRuntime()) { - return body->at(i)->AsExpressionStatement()->expression()->id(); - } - } - CHECK(false); - return BailoutId(-1); - } -}; - - -TEST(TurboTrivialRuntimeDeoptCodegenAndRun) { - HandleAndZoneScope scope; - InitializedHandleScope handles; - - FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; - - TrivialRuntimeDeoptCodegenTester t(&scope); - t.GenerateCode(); - - t.function->ReplaceCode(*t.result_code); - t.info.context()->native_context()->AddOptimizedCode(*t.result_code); - - Isolate* isolate = scope.main_isolate(); - Handle<Object> result; - bool has_pending_exception = - !Execution::Call(isolate, t.function, - isolate->factory()->undefined_value(), 0, NULL, - false).ToHandle(&result); - CHECK(!has_pending_exception); - CHECK(result->SameValue(Smi::FromInt(42))); -} - -#endif diff --git a/deps/v8/test/cctest/compiler/test-control-reducer.cc b/deps/v8/test/cctest/compiler/test-control-reducer.cc deleted file mode 100644 index e969e27106..0000000000 --- a/deps/v8/test/cctest/compiler/test-control-reducer.cc +++ /dev/null @@ -1,1641 +0,0 @@ -// 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. - -#include "src/v8.h" -#include "test/cctest/cctest.h" - -#include "src/base/bits.h" -#include "src/compiler/all-nodes.h" -#include "src/compiler/common-operator.h" -#include "src/compiler/control-reducer.h" -#include "src/compiler/graph.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/node-properties.h" - -using namespace v8::internal; -using namespace v8::internal::compiler; - -static const size_t kNumLeafs = 4; - -enum Decision { kFalse, kUnknown, kTrue }; - -// TODO(titzer): convert this whole file into unit tests. - -static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL, - Node* i2 = NULL) { - int count = 3; - if (i2 == NULL) count = 2; - if (i1 == NULL) count = 1; - if (i0 == NULL) count = 0; - CHECK_EQ(count, node->InputCount()); - if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0)); - if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1)); - if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2)); - return count; -} - - -static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL, - Node* i2 = NULL) { - CHECK_EQ(IrOpcode::kMerge, node->opcode()); - int count = CheckInputs(node, i0, i1, i2); - CHECK_EQ(count, node->op()->ControlInputCount()); - return count; -} - - -static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL, - Node* i2 = NULL) { - CHECK_EQ(IrOpcode::kLoop, node->opcode()); - int count = CheckInputs(node, i0, i1, i2); - CHECK_EQ(count, node->op()->ControlInputCount()); - return count; -} - - -bool IsUsedBy(Node* a, Node* b) { - auto const uses = a->uses(); - return std::find(uses.begin(), uses.end(), b) != uses.end(); -} - - -// A helper for all tests dealing with ControlTester. -class ControlReducerTester : HandleAndZoneScope { - public: - ControlReducerTester() - : isolate(main_isolate()), - common(main_zone()), - graph(main_zone()), - jsgraph(main_isolate(), &graph, &common, NULL, NULL), - start(graph.NewNode(common.Start(1))), - end(graph.NewNode(common.End(), start)), - p0(graph.NewNode(common.Parameter(0), start)), - zero(jsgraph.Int32Constant(0)), - one(jsgraph.OneConstant()), - half(jsgraph.Constant(0.5)), - self(graph.NewNode(common.Int32Constant(0xaabbccdd))), - dead(graph.NewNode(common.Dead())) { - graph.SetEnd(end); - graph.SetStart(start); - leaf[0] = zero; - leaf[1] = one; - leaf[2] = half; - leaf[3] = p0; - } - - Isolate* isolate; - CommonOperatorBuilder common; - Graph graph; - JSGraph jsgraph; - Node* start; - Node* end; - Node* p0; - Node* zero; - Node* one; - Node* half; - Node* self; - Node* dead; - Node* leaf[kNumLeafs]; - - Node* Phi(Node* a) { - return SetSelfReferences(graph.NewNode(op(1, false), a, start)); - } - - Node* Phi(Node* a, Node* b) { - return SetSelfReferences(graph.NewNode(op(2, false), a, b, start)); - } - - Node* Phi(Node* a, Node* b, Node* c) { - return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start)); - } - - Node* Phi(Node* a, Node* b, Node* c, Node* d) { - return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start)); - } - - Node* EffectPhi(Node* a) { - return SetSelfReferences(graph.NewNode(op(1, true), a, start)); - } - - Node* EffectPhi(Node* a, Node* b) { - return SetSelfReferences(graph.NewNode(op(2, true), a, b, start)); - } - - Node* EffectPhi(Node* a, Node* b, Node* c) { - return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start)); - } - - Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) { - return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start)); - } - - Node* SetSelfReferences(Node* node) { - for (Edge edge : node->input_edges()) { - if (edge.to() == self) node->ReplaceInput(edge.index(), node); - } - return node; - } - - const Operator* op(int count, bool effect) { - return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count); - } - - void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } - - void ReduceGraph() { ControlReducer::ReduceGraph(main_zone(), &jsgraph); } - - // Checks one-step reduction of a phi. - void ReducePhi(Node* expect, Node* phi) { - Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, phi); - CHECK_EQ(expect, result); - ReducePhiIterative(expect, phi); // iterative should give the same result. - } - - // Checks one-step reduction of a phi. - void ReducePhiNonIterative(Node* expect, Node* phi) { - Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, phi); - CHECK_EQ(expect, result); - } - - void ReducePhiIterative(Node* expect, Node* phi) { - p0->ReplaceInput(0, start); // hack: parameters may be trimmed. - Node* ret = graph.NewNode(common.Return(), phi, start, start); - Node* end = graph.NewNode(common.End(), ret); - graph.SetEnd(end); - ControlReducer::ReduceGraph(main_zone(), &jsgraph); - CheckInputs(end, ret); - CheckInputs(ret, expect, start, start); - } - - void ReduceMerge(Node* expect, Node* merge) { - Node* result = ControlReducer::ReduceMerge(&jsgraph, merge); - CHECK_EQ(expect, result); - } - - void ReduceMergeIterative(Node* expect, Node* merge) { - p0->ReplaceInput(0, start); // hack: parameters may be trimmed. - Node* end = graph.NewNode(common.End(), merge); - graph.SetEnd(end); - ReduceGraph(); - CheckInputs(end, expect); - } - - void ReduceBranch(Decision expected, Node* branch) { - Node* control = branch->InputAt(1); - for (Node* use : branch->uses()) { - if (use->opcode() == IrOpcode::kIfTrue) { - Node* result = ControlReducer::ReduceIfNodeForTesting(&jsgraph, use); - if (expected == kTrue) CHECK_EQ(control, result); - if (expected == kFalse) CHECK_EQ(IrOpcode::kDead, result->opcode()); - if (expected == kUnknown) CHECK_EQ(use, result); - } else if (use->opcode() == IrOpcode::kIfFalse) { - Node* result = ControlReducer::ReduceIfNodeForTesting(&jsgraph, use); - if (expected == kFalse) CHECK_EQ(control, result); - if (expected == kTrue) CHECK_EQ(IrOpcode::kDead, result->opcode()); - if (expected == kUnknown) CHECK_EQ(use, result); - } else { - UNREACHABLE(); - } - } - } - - Node* Return(Node* val, Node* effect, Node* control) { - Node* ret = graph.NewNode(common.Return(), val, effect, control); - end->ReplaceInput(0, ret); - return ret; - } -}; - - -struct Branch { - Node* branch; - Node* if_true; - Node* if_false; - - Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) { - if (control == NULL) control = R.start; - branch = R.graph.NewNode(R.common.Branch(), cond, control); - if_true = R.graph.NewNode(R.common.IfTrue(), branch); - if_false = R.graph.NewNode(R.common.IfFalse(), branch); - } -}; - - -// TODO(titzer): use the diamonds from src/compiler/diamond.h here. -struct Diamond { - Node* branch; - Node* if_true; - Node* if_false; - Node* merge; - Node* phi; - - Diamond(ControlReducerTester& R, Node* cond) { - branch = R.graph.NewNode(R.common.Branch(), cond, R.start); - if_true = R.graph.NewNode(R.common.IfTrue(), branch); - if_false = R.graph.NewNode(R.common.IfFalse(), branch); - merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); - phi = NULL; - } - - Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) { - branch = R.graph.NewNode(R.common.Branch(), cond, R.start); - if_true = R.graph.NewNode(R.common.IfTrue(), branch); - if_false = R.graph.NewNode(R.common.IfFalse(), branch); - merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); - phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge); - } - - void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); } - - // Nest {this} into either the if_true or if_false branch of {that}. - void nest(Diamond& that, bool if_true) { - if (if_true) { - branch->ReplaceInput(1, that.if_true); - that.merge->ReplaceInput(0, merge); - } else { - branch->ReplaceInput(1, that.if_false); - that.merge->ReplaceInput(1, merge); - } - } -}; - - -struct While { - Node* branch; - Node* if_true; - Node* exit; - Node* loop; - - While(ControlReducerTester& R, Node* cond) { - loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); - branch = R.graph.NewNode(R.common.Branch(), cond, loop); - if_true = R.graph.NewNode(R.common.IfTrue(), branch); - exit = R.graph.NewNode(R.common.IfFalse(), branch); - loop->ReplaceInput(1, if_true); - } - - void chain(Node* control) { loop->ReplaceInput(0, control); } -}; - - -// Helper for checking that nodes are *not* reachable from end. -struct DeadChecker { - Zone zone; - AllNodes nodes; - explicit DeadChecker(Graph* graph) : zone(), nodes(&zone, graph) {} - - void Check(Node* node) { CHECK(!nodes.IsLive(node)); } - - void Check(Diamond& d) { - Check(d.branch); - Check(d.if_true); - Check(d.if_false); - Check(d.merge); - if (d.phi != NULL) Check(d.phi); - } - - void CheckLive(Diamond& d, bool live_phi = true) { - CheckInputs(d.merge, d.if_true, d.if_false); - CheckInputs(d.if_true, d.branch); - CheckInputs(d.if_false, d.branch); - if (d.phi != NULL) { - if (live_phi) { - CHECK_EQ(3, d.phi->InputCount()); - CHECK_EQ(d.merge, d.phi->InputAt(2)); - } else { - Check(d.phi); - } - } - } -}; - - -TEST(Trim1_live) { - ControlReducerTester T; - CHECK(IsUsedBy(T.start, T.p0)); - T.graph.SetEnd(T.p0); - T.Trim(); - CHECK(IsUsedBy(T.start, T.p0)); - CheckInputs(T.p0, T.start); -} - - -TEST(Trim1_dead) { - ControlReducerTester T; - CHECK(IsUsedBy(T.start, T.p0)); - T.Trim(); - CHECK(!IsUsedBy(T.start, T.p0)); - CHECK(!T.p0->InputAt(0)); -} - - -TEST(Trim2_live) { - ControlReducerTester T; - Node* phi = - T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); - CHECK(IsUsedBy(T.one, phi)); - CHECK(IsUsedBy(T.half, phi)); - CHECK(IsUsedBy(T.start, phi)); - T.graph.SetEnd(phi); - T.Trim(); - CHECK(IsUsedBy(T.one, phi)); - CHECK(IsUsedBy(T.half, phi)); - CHECK(IsUsedBy(T.start, phi)); - CheckInputs(phi, T.one, T.half, T.start); -} - - -TEST(Trim2_dead) { - ControlReducerTester T; - Node* phi = - T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); - CHECK(IsUsedBy(T.one, phi)); - CHECK(IsUsedBy(T.half, phi)); - CHECK(IsUsedBy(T.start, phi)); - T.Trim(); - CHECK(!IsUsedBy(T.one, phi)); - CHECK(!IsUsedBy(T.half, phi)); - CHECK(!IsUsedBy(T.start, phi)); - CHECK(!phi->InputAt(0)); - CHECK(!phi->InputAt(1)); - CHECK(!phi->InputAt(2)); -} - - -TEST(Trim_chain1) { - ControlReducerTester T; - const int kDepth = 15; - Node* live[kDepth]; - Node* dead[kDepth]; - Node* end = T.start; - for (int i = 0; i < kDepth; i++) { - live[i] = end = T.graph.NewNode(T.common.Merge(1), end); - dead[i] = T.graph.NewNode(T.common.Merge(1), end); - } - // end -> live[last] -> live[last-1] -> ... -> start - // dead[last] ^ dead[last-1] ^ ... ^ - T.graph.SetEnd(end); - T.Trim(); - for (int i = 0; i < kDepth; i++) { - CHECK(!IsUsedBy(live[i], dead[i])); - CHECK(!dead[i]->InputAt(0)); - CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); - } -} - - -TEST(Trim_chain2) { - ControlReducerTester T; - const int kDepth = 15; - Node* live[kDepth]; - Node* dead[kDepth]; - Node* l = T.start; - Node* d = T.start; - for (int i = 0; i < kDepth; i++) { - live[i] = l = T.graph.NewNode(T.common.Merge(1), l); - dead[i] = d = T.graph.NewNode(T.common.Merge(1), d); - } - // end -> live[last] -> live[last-1] -> ... -> start - // dead[last] -> dead[last-1] -> ... -> start - T.graph.SetEnd(l); - T.Trim(); - CHECK(!IsUsedBy(T.start, dead[0])); - for (int i = 0; i < kDepth; i++) { - CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0)); - CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); - } -} - - -TEST(Trim_cycle1) { - ControlReducerTester T; - Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start); - loop->ReplaceInput(1, loop); - Node* end = T.graph.NewNode(T.common.End(), loop); - T.graph.SetEnd(end); - - CHECK(IsUsedBy(T.start, loop)); - CHECK(IsUsedBy(loop, end)); - CHECK(IsUsedBy(loop, loop)); - - T.Trim(); - - // nothing should have happened to the loop itself. - CHECK(IsUsedBy(T.start, loop)); - CHECK(IsUsedBy(loop, end)); - CHECK(IsUsedBy(loop, loop)); - CheckInputs(loop, T.start, loop); - CheckInputs(end, loop); -} - - -TEST(Trim_cycle2) { - ControlReducerTester T; - Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start); - loop->ReplaceInput(1, loop); - Node* end = T.graph.NewNode(T.common.End(), loop); - Node* phi = - T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop); - T.graph.SetEnd(end); - - CHECK(IsUsedBy(T.start, loop)); - CHECK(IsUsedBy(loop, end)); - CHECK(IsUsedBy(loop, loop)); - CHECK(IsUsedBy(loop, phi)); - CHECK(IsUsedBy(T.one, phi)); - CHECK(IsUsedBy(T.half, phi)); - - T.Trim(); - - // nothing should have happened to the loop itself. - CHECK(IsUsedBy(T.start, loop)); - CHECK(IsUsedBy(loop, end)); - CHECK(IsUsedBy(loop, loop)); - CheckInputs(loop, T.start, loop); - CheckInputs(end, loop); - - // phi should have been trimmed away. - CHECK(!IsUsedBy(loop, phi)); - CHECK(!IsUsedBy(T.one, phi)); - CHECK(!IsUsedBy(T.half, phi)); - CHECK(!phi->InputAt(0)); - CHECK(!phi->InputAt(1)); - CHECK(!phi->InputAt(2)); -} - - -void CheckTrimConstant(ControlReducerTester* T, Node* k) { - Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start); - CHECK(IsUsedBy(k, phi)); - T->Trim(); - CHECK(!IsUsedBy(k, phi)); - CHECK(!phi->InputAt(0)); - CHECK(!phi->InputAt(1)); -} - - -TEST(Trim_constants) { - ControlReducerTester T; - int32_t int32_constants[] = { - 0, -1, -2, 2, 2, 3, 3, 4, 4, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8, 9, - 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9}; - - for (size_t i = 0; i < arraysize(int32_constants); i++) { - CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i])); - CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i])); - CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i])); - } - - Node* other_constants[] = { - T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(), - T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(), - T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(), - T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(), - T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)}; - - for (size_t i = 0; i < arraysize(other_constants); i++) { - CheckTrimConstant(&T, other_constants[i]); - } -} - - -TEST(Trim_EmptyFrameState1) { - ControlReducerTester T; - - Node* node = T.jsgraph.EmptyFrameState(); - T.Trim(); - - for (Node* input : node->inputs()) { - CHECK_NOT_NULL(input); - } -} - - -TEST(Trim_EmptyFrameState2) { - ControlReducerTester T; - CheckTrimConstant(&T, T.jsgraph.EmptyFrameState()); -} - - -TEST(CReducePhi1) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0])); - R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1])); - R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2])); - R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3])); -} - - -TEST(CReducePhi1_dead) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead)); - R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead)); - R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead)); - R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead)); - - R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0])); - R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1])); - R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2])); - R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3])); -} - - -TEST(CReducePhi1_dead2) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead)); - R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead)); - R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0])); -} - - -TEST(CReducePhi2a) { - ControlReducerTester R; - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(a, a)); - } -} - - -TEST(CReducePhi2b) { - ControlReducerTester R; - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(R.self, a)); - R.ReducePhi(a, R.Phi(a, R.self)); - } -} - - -TEST(CReducePhi2c) { - ControlReducerTester R; - - for (size_t i = 1; i < kNumLeafs; i++) { - Node* a = R.leaf[i], *b = R.leaf[0]; - Node* phi1 = R.Phi(b, a); - R.ReducePhi(phi1, phi1); - - Node* phi2 = R.Phi(a, b); - R.ReducePhi(phi2, phi2); - } -} - - -TEST(CReducePhi2_dead) { - ControlReducerTester R; - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(a, a, R.dead)); - R.ReducePhi(a, R.Phi(a, R.dead, a)); - R.ReducePhi(a, R.Phi(R.dead, a, a)); - } - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(R.self, a)); - R.ReducePhi(a, R.Phi(a, R.self)); - R.ReducePhi(a, R.Phi(R.self, a, R.dead)); - R.ReducePhi(a, R.Phi(a, R.self, R.dead)); - } - - for (size_t i = 1; i < kNumLeafs; i++) { - Node* a = R.leaf[i], *b = R.leaf[0]; - Node* phi1 = R.Phi(b, a, R.dead); - R.ReducePhiNonIterative(phi1, phi1); - - Node* phi2 = R.Phi(a, b, R.dead); - R.ReducePhiNonIterative(phi2, phi2); - } -} - - -TEST(CReducePhi3) { - ControlReducerTester R; - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(a, a, a)); - } - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(R.self, a, a)); - R.ReducePhi(a, R.Phi(a, R.self, a)); - R.ReducePhi(a, R.Phi(a, a, R.self)); - } - - for (size_t i = 1; i < kNumLeafs; i++) { - Node* a = R.leaf[i], *b = R.leaf[0]; - Node* phi1 = R.Phi(b, a, a); - R.ReducePhi(phi1, phi1); - - Node* phi2 = R.Phi(a, b, a); - R.ReducePhi(phi2, phi2); - - Node* phi3 = R.Phi(a, a, b); - R.ReducePhi(phi3, phi3); - } -} - - -TEST(CReducePhi4) { - ControlReducerTester R; - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(a, a, a, a)); - } - - for (size_t i = 0; i < kNumLeafs; i++) { - Node* a = R.leaf[i]; - R.ReducePhi(a, R.Phi(R.self, a, a, a)); - R.ReducePhi(a, R.Phi(a, R.self, a, a)); - R.ReducePhi(a, R.Phi(a, a, R.self, a)); - R.ReducePhi(a, R.Phi(a, a, a, R.self)); - - R.ReducePhi(a, R.Phi(R.self, R.self, a, a)); - R.ReducePhi(a, R.Phi(a, R.self, R.self, a)); - R.ReducePhi(a, R.Phi(a, a, R.self, R.self)); - R.ReducePhi(a, R.Phi(R.self, a, a, R.self)); - } - - for (size_t i = 1; i < kNumLeafs; i++) { - Node* a = R.leaf[i], *b = R.leaf[0]; - Node* phi1 = R.Phi(b, a, a, a); - R.ReducePhi(phi1, phi1); - - Node* phi2 = R.Phi(a, b, a, a); - R.ReducePhi(phi2, phi2); - - Node* phi3 = R.Phi(a, a, b, a); - R.ReducePhi(phi3, phi3); - - Node* phi4 = R.Phi(a, a, a, b); - R.ReducePhi(phi4, phi4); - } -} - - -TEST(CReducePhi_iterative1) { - ControlReducerTester R; - - R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0]))); - R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0])); -} - - -TEST(CReducePhi_iterative2) { - ControlReducerTester R; - - R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0]))); -} - - -TEST(CReducePhi_iterative3) { - ControlReducerTester R; - - R.ReducePhiIterative(R.leaf[0], - R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0]))); - R.ReducePhiIterative(R.leaf[0], - R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0])); -} - - -TEST(CReducePhi_iterative4) { - ControlReducerTester R; - - R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]), - R.Phi(R.leaf[0], R.leaf[0]))); - - Node* p1 = R.Phi(R.leaf[0], R.leaf[0]); - R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); - - Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); - R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2)); - - Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); - R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0])); -} - - -TEST(CReducePhi_iterative_self1) { - ControlReducerTester R; - - R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self))); - R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0])); -} - - -TEST(CReducePhi_iterative_self2) { - ControlReducerTester R; - - R.ReducePhiIterative( - R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self))); - R.ReducePhiIterative( - R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0]))); - - Node* p1 = R.Phi(R.leaf[0], R.self); - R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); - - Node* p2 = R.Phi(R.self, R.leaf[0]); - R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2)); -} - - -TEST(EReducePhi1) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0])); - R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1])); - R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2])); - R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3])); -} - - -TEST(EReducePhi1_dead) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead)); - R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead)); - R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead)); - R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead)); - - R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0])); - R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1])); - R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2])); - R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3])); -} - - -TEST(EReducePhi1_dead2) { - ControlReducerTester R; - - R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead)); - R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead)); - R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0])); -} - - -TEST(CMergeReduce_simple1) { - ControlReducerTester R; - - Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); - R.ReduceMerge(R.start, merge); -} - - -TEST(CMergeReduce_simple2) { - ControlReducerTester R; - - Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); - Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1); - R.ReduceMerge(merge1, merge2); - R.ReduceMergeIterative(R.start, merge2); -} - - -TEST(CMergeReduce_none1) { - ControlReducerTester R; - - Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start); - R.ReduceMerge(merge, merge); -} - - -TEST(CMergeReduce_none2) { - ControlReducerTester R; - - Node* t1 = R.graph.NewNode(R.common.IfTrue(), R.start); - Node* t2 = R.graph.NewNode(R.common.IfTrue(), R.start); - Node* merge = R.graph.NewNode(R.common.Merge(2), t1, t2); - R.ReduceMerge(merge, merge); -} - - -TEST(CMergeReduce_self3) { - ControlReducerTester R; - - Node* merge = - R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self)); - R.ReduceMerge(merge, merge); -} - - -TEST(CMergeReduce_dead1) { - ControlReducerTester R; - - Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead); - R.ReduceMerge(R.start, merge); -} - - -TEST(CMergeReduce_dead2) { - ControlReducerTester R; - - Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); - Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead); - R.ReduceMerge(merge1, merge2); - R.ReduceMergeIterative(R.start, merge2); -} - - -TEST(CMergeReduce_dead_rm1a) { - ControlReducerTester R; - - for (int i = 0; i < 3; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); - merge->ReplaceInput(i, R.dead); - R.ReduceMerge(merge, merge); - CheckMerge(merge, R.start, R.start); - } -} - - -TEST(CMergeReduce_dead_rm1b) { - ControlReducerTester R; - - Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); - Node* f = R.graph.NewNode(R.common.IfTrue(), R.start); - for (int i = 0; i < 2; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); - for (int j = i + 1; j < 3; j++) { - merge->ReplaceInput(i, t); - merge->ReplaceInput(j, f); - R.ReduceMerge(merge, merge); - CheckMerge(merge, t, f); - } - } -} - - -TEST(CMergeReduce_dead_rm2) { - ControlReducerTester R; - - for (int i = 0; i < 3; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); - merge->ReplaceInput(i, R.start); - R.ReduceMerge(R.start, merge); - } -} - - -TEST(CLoopReduce_dead_rm1) { - ControlReducerTester R; - - for (int i = 0; i < 3; i++) { - Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start); - R.ReduceMerge(loop, loop); - CheckLoop(loop, R.start, R.start); - } -} - - -TEST(CMergeReduce_edit_phi1) { - ControlReducerTester R; - - for (int i = 0; i < 3; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); - merge->ReplaceInput(i, R.dead); - Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], - R.leaf[1], R.leaf[2], merge); - R.ReduceMerge(merge, merge); - CHECK_EQ(IrOpcode::kPhi, phi->opcode()); - CHECK_EQ(2, phi->op()->ValueInputCount()); - CHECK_EQ(3, phi->InputCount()); - CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); - CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); - CHECK_EQ(merge, phi->InputAt(2)); - } -} - - -TEST(CMergeReduce_edit_effect_phi1) { - ControlReducerTester R; - - for (int i = 0; i < 3; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); - merge->ReplaceInput(i, R.dead); - Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1], - R.leaf[2], merge); - R.ReduceMerge(merge, merge); - CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode()); - CHECK_EQ(0, phi->op()->ValueInputCount()); - CHECK_EQ(2, phi->op()->EffectInputCount()); - CHECK_EQ(3, phi->InputCount()); - CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); - CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); - CHECK_EQ(merge, phi->InputAt(2)); - } -} - - -static const int kSelectorSize = 4; - -// Helper to select K of N nodes according to a mask, useful for the test below. -struct Selector { - int mask; - int count; - explicit Selector(int m) { - mask = m; - count = v8::base::bits::CountPopulation32(m); - } - bool is_selected(int i) { return (mask & (1 << i)) != 0; } - void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs, - Node* control) { - CHECK_EQ(opcode, node->opcode()); - CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount()); - int index = 0; - for (int i = 0; i < kSelectorSize; i++) { - if (mask & (1 << i)) { - CHECK_EQ(inputs[i], node->InputAt(index++)); - } - } - CHECK_EQ(count, index); - if (control != NULL) CHECK_EQ(control, node->InputAt(index++)); - } - int single_index() { - CHECK_EQ(1, count); - return WhichPowerOf2(mask); - } -}; - - -TEST(CMergeReduce_exhaustive_4) { - ControlReducerTester R; - Node* controls[] = { - R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)), - R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))}; - Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22), - R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)}; - Node* effects[] = { - R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4), - R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)}; - - for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) { - // Reduce a single merge with a given mask. - Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1], - controls[2], controls[3]); - Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0], - values[1], values[2], values[3], merge); - Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1], - effects[2], effects[3], merge); - - Node* phi_use = - R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start); - Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start); - - Selector selector(mask); - - for (int i = 0; i < kSelectorSize; i++) { // set up dead merge inputs. - if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead); - } - - Node* result = ControlReducer::ReduceMerge(&R.jsgraph, merge); - - int count = selector.count; - if (count == 0) { - // result should be dead. - CHECK_EQ(IrOpcode::kDead, result->opcode()); - } else if (count == 1) { - // merge should be replaced with one of the controls. - CHECK_EQ(controls[selector.single_index()], result); - // Phis should have been directly replaced. - CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0)); - CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0)); - } else { - // Otherwise, nodes should be edited in place. - CHECK_EQ(merge, result); - selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL); - selector.CheckNode(phi, IrOpcode::kPhi, values, merge); - selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge); - CHECK_EQ(phi, phi_use->InputAt(0)); - CHECK_EQ(ephi, ephi_use->InputAt(0)); - CHECK_EQ(count, phi->op()->ValueInputCount()); - CHECK_EQ(count + 1, phi->InputCount()); - CHECK_EQ(count, ephi->op()->EffectInputCount()); - CHECK_EQ(count + 1, ephi->InputCount()); - } - } -} - - -TEST(CMergeReduce_edit_many_phis1) { - ControlReducerTester R; - - const int kPhiCount = 10; - Node* phis[kPhiCount]; - - for (int i = 0; i < 3; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); - merge->ReplaceInput(i, R.dead); - for (int j = 0; j < kPhiCount; j++) { - phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], - R.leaf[1], R.leaf[2], merge); - } - R.ReduceMerge(merge, merge); - for (int j = 0; j < kPhiCount; j++) { - Node* phi = phis[j]; - CHECK_EQ(IrOpcode::kPhi, phi->opcode()); - CHECK_EQ(2, phi->op()->ValueInputCount()); - CHECK_EQ(3, phi->InputCount()); - CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); - CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); - CHECK_EQ(merge, phi->InputAt(2)); - } - } -} - - -TEST(CMergeReduce_simple_chain1) { - ControlReducerTester R; - for (int i = 0; i < 5; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); - for (int j = 0; j < i; j++) { - merge = R.graph.NewNode(R.common.Merge(1), merge); - } - R.ReduceMergeIterative(R.start, merge); - } -} - - -TEST(CMergeReduce_dead_chain1) { - ControlReducerTester R; - for (int i = 0; i < 5; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead); - for (int j = 0; j < i; j++) { - merge = R.graph.NewNode(R.common.Merge(1), merge); - } - Node* end = R.graph.NewNode(R.common.End(), merge); - R.graph.SetEnd(end); - R.ReduceGraph(); - CHECK(merge->IsDead()); - CHECK(!end->InputAt(0)); // end dies. - } -} - - -TEST(CMergeReduce_dead_chain2) { - ControlReducerTester R; - for (int i = 0; i < 5; i++) { - Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); - for (int j = 0; j < i; j++) { - merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead); - } - R.ReduceMergeIterative(R.start, merge); - } -} - - -TEST(CBranchReduce_none1) { - ControlReducerTester R; - Diamond d(R, R.p0); - R.ReduceBranch(kUnknown, d.branch); -} - - -TEST(CBranchReduce_none2) { - ControlReducerTester R; - Diamond d1(R, R.p0); - Diamond d2(R, R.p0); - d2.chain(d1); - R.ReduceBranch(kUnknown, d2.branch); -} - - -TEST(CBranchReduce_true) { - ControlReducerTester R; - Node* true_values[] = { - R.one, R.jsgraph.Int32Constant(2), - R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0), - R.jsgraph.Constant(22.1), R.jsgraph.TrueConstant()}; - - for (size_t i = 0; i < arraysize(true_values); i++) { - Diamond d(R, true_values[i]); - R.ReduceBranch(kTrue, d.branch); - } -} - - -TEST(CBranchReduce_false) { - ControlReducerTester R; - Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0), - R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()}; - - for (size_t i = 0; i < arraysize(false_values); i++) { - Diamond d(R, false_values[i]); - R.ReduceBranch(kFalse, d.branch); - } -} - - -TEST(CDiamondReduce_true) { - ControlReducerTester R; - Diamond d1(R, R.one); - R.ReduceMergeIterative(R.start, d1.merge); -} - - -TEST(CDiamondReduce_false) { - ControlReducerTester R; - Diamond d2(R, R.zero); - R.ReduceMergeIterative(R.start, d2.merge); -} - - -TEST(CChainedDiamondsReduce_true_false) { - ControlReducerTester R; - Diamond d1(R, R.one); - Diamond d2(R, R.zero); - d2.chain(d1); - - R.ReduceMergeIterative(R.start, d2.merge); -} - - -TEST(CChainedDiamondsReduce_x_false) { - ControlReducerTester R; - Diamond d1(R, R.p0); - Diamond d2(R, R.zero); - d2.chain(d1); - - R.ReduceMergeIterative(R.start, d2.merge); -} - - -TEST(CChainedDiamondsReduce_false_x) { - ControlReducerTester R; - Diamond d1(R, R.zero); - Diamond d2(R, R.p0); - d2.chain(d1); - - R.ReduceMergeIterative(R.start, d2.merge); -} - - -TEST(CChainedDiamondsReduce_phi1) { - ControlReducerTester R; - Diamond d1(R, R.zero, R.one, R.zero); // foldable branch, phi. - Diamond d2(R, d1.phi); - d2.chain(d1); - - R.ReduceMergeIterative(R.start, d2.merge); -} - - -TEST(CChainedDiamondsReduce_phi2) { - ControlReducerTester R; - Diamond d1(R, R.p0, R.one, R.one); // redundant phi. - Diamond d2(R, d1.phi); - d2.chain(d1); - - R.ReduceMergeIterative(d1.merge, d2.merge); -} - - -TEST(CNestedDiamondsReduce_true_true_false) { - ControlReducerTester R; - Diamond d1(R, R.one); - Diamond d2(R, R.zero); - d2.nest(d1, true); - - R.ReduceMergeIterative(R.start, d1.merge); -} - - -TEST(CNestedDiamondsReduce_false_true_false) { - ControlReducerTester R; - Diamond d1(R, R.one); - Diamond d2(R, R.zero); - d2.nest(d1, false); - - R.ReduceMergeIterative(R.start, d1.merge); -} - - -TEST(CNestedDiamonds_xyz) { - ControlReducerTester R; - - for (int a = 0; a < 2; a++) { - for (int b = 0; b < 2; b++) { - for (int c = 0; c < 2; c++) { - Diamond d1(R, R.jsgraph.Int32Constant(a)); - Diamond d2(R, R.jsgraph.Int32Constant(b)); - d2.nest(d1, c); - - R.ReduceMergeIterative(R.start, d1.merge); - } - } - } -} - - -TEST(CUnusedDiamond1) { - ControlReducerTester R; - // if (p0) { } else { } - Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start); - Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch); - Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch); - Node* merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); - R.ReduceMergeIterative(R.start, merge); -} - - -TEST(CUnusedDiamond2) { - ControlReducerTester R; - // if (p0) { } else { } - Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start); - Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch); - Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch); - Node* merge = R.graph.NewNode(R.common.Merge(2), if_false, if_true); - R.ReduceMergeIterative(R.start, merge); -} - - -TEST(CDeadLoop1) { - ControlReducerTester R; - - Node* loop = R.graph.NewNode(R.common.Loop(1), R.start); - Branch b(R, R.p0, loop); - loop->ReplaceInput(0, b.if_true); // loop is not connected to start. - Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false); - R.ReduceMergeIterative(R.start, merge); - - DeadChecker dead(&R.graph); - dead.Check(b.if_true); - dead.Check(b.if_false); - dead.Check(b.branch); - dead.Check(loop); -} - - -TEST(CDeadLoop2) { - ControlReducerTester R; - - While w(R, R.p0); - Diamond d(R, R.zero); - // if (0) { while (p0) ; } else { } - w.branch->ReplaceInput(1, d.if_true); - d.merge->ReplaceInput(0, w.exit); - - R.ReduceMergeIterative(R.start, d.merge); - - DeadChecker dead(&R.graph); - dead.Check(d); - dead.Check(w.loop); -} - - -TEST(Return1) { - ControlReducerTester R; - Node* ret = R.Return(R.one, R.start, R.start); - R.ReduceGraph(); - CheckInputs(R.graph.end(), ret); - CheckInputs(ret, R.one, R.start, R.start); -} - - -TEST(Return2) { - ControlReducerTester R; - Diamond d(R, R.one); - Node* ret = R.Return(R.half, R.start, d.merge); - R.ReduceGraph(); - - DeadChecker dead(&R.graph); - dead.Check(d.branch); - dead.Check(d.if_true); - dead.Check(d.if_false); - dead.Check(d.merge); - - CheckInputs(R.graph.end(), ret); - CheckInputs(ret, R.half, R.start, R.start); -} - - -TEST(Return_true1) { - ControlReducerTester R; - Diamond d(R, R.one, R.half, R.zero); - Node* ret = R.Return(d.phi, R.start, d.merge); - R.ReduceGraph(); - - DeadChecker dead(&R.graph); - dead.Check(d.branch); - dead.Check(d.if_true); - dead.Check(d.if_false); - dead.Check(d.merge); - dead.Check(d.phi); - - CheckInputs(R.graph.end(), ret); - CheckInputs(ret, R.half, R.start, R.start); -} - - -TEST(Return_false1) { - ControlReducerTester R; - Diamond d(R, R.zero, R.one, R.half); - Node* ret = R.Return(d.phi, R.start, d.merge); - R.ReduceGraph(); - - DeadChecker dead(&R.graph); - dead.Check(d.branch); - dead.Check(d.if_true); - dead.Check(d.if_false); - dead.Check(d.merge); - dead.Check(d.phi); - - CheckInputs(R.graph.end(), ret); - CheckInputs(ret, R.half, R.start, R.start); -} - - -TEST(Return_effect1) { - ControlReducerTester R; - Diamond d(R, R.one); - Node* e1 = R.jsgraph.Float64Constant(-100.1); - Node* e2 = R.jsgraph.Float64Constant(+100.1); - Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge); - Node* ret = R.Return(R.p0, effect, d.merge); - R.ReduceGraph(); - - DeadChecker dead(&R.graph); - dead.Check(d); - dead.Check(effect); - - CheckInputs(R.graph.end(), ret); - CheckInputs(ret, R.p0, e1, R.start); -} - - -TEST(Return_nested_diamonds1) { - ControlReducerTester R; - Diamond d2(R, R.p0, R.one, R.zero); - Diamond d3(R, R.p0, R.one, R.zero); - Diamond d1(R, R.p0, d2.phi, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // nothing should happen. - - CheckInputs(ret, d1.phi, R.start, d1.merge); - CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge); - CheckInputs(d1.merge, d2.merge, d3.merge); - - DeadChecker dead(&R.graph); - dead.CheckLive(d2); - dead.CheckLive(d3); -} - - -TEST(Return_nested_diamonds1_dead1) { - ControlReducerTester R; - Diamond d2(R, R.p0); // dead diamond - Diamond d3(R, R.p0, R.one, R.zero); - Diamond d1(R, R.p0, R.one, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); - - CheckInputs(ret, d1.phi, R.start, d1.merge); - CheckInputs(d1.phi, R.one, d3.phi, d1.merge); - CheckInputs(d1.merge, d1.if_true, d3.merge); - - DeadChecker dead(&R.graph); - dead.Check(d2); // d2 was a dead diamond. - dead.CheckLive(d3); -} - - -TEST(Return_nested_diamonds1_dead2) { - ControlReducerTester R; - Diamond d2(R, R.p0); // dead diamond - Diamond d3(R, R.p0); // dead diamond - Diamond d1(R, R.p0, R.one, R.zero); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); - - CheckInputs(ret, d1.phi, R.start, d1.merge); - CheckInputs(d1.phi, R.one, R.zero, d1.merge); - CheckInputs(d1.merge, d1.if_true, d1.if_false); - - DeadChecker dead(&R.graph); - dead.Check(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds_true1) { - ControlReducerTester R; - Diamond d2(R, R.p0, R.one, R.zero); - Diamond d1(R, R.one, d2.phi, R.zero); - Diamond d3(R, R.p0); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded true. - - CheckInputs(ret, d2.phi, R.start, d2.merge); - CheckInputs(d2.branch, R.p0, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.CheckLive(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds_false1) { - ControlReducerTester R; - Diamond d3(R, R.p0, R.one, R.zero); - Diamond d1(R, R.zero, R.one, d3.phi); - Diamond d2(R, R.p0); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded false. - - CheckInputs(ret, d3.phi, R.start, d3.merge); - CheckInputs(d3.branch, R.p0, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.Check(d2); - dead.CheckLive(d3); -} - - -TEST(Return_nested_diamonds_true_true1) { - ControlReducerTester R; - Diamond d1(R, R.one, R.one, R.zero); - Diamond d2(R, R.one); - Diamond d3(R, R.p0); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 and d2 both get folded true. - - CheckInputs(ret, R.one, R.start, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.Check(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds_true_false1) { - ControlReducerTester R; - Diamond d1(R, R.one, R.one, R.zero); - Diamond d2(R, R.zero); - Diamond d3(R, R.p0); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded true and d2 gets folded false. - - CheckInputs(ret, R.one, R.start, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.Check(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds2) { - ControlReducerTester R; - Node* x2 = R.jsgraph.Float64Constant(11.1); - Node* y2 = R.jsgraph.Float64Constant(22.2); - Node* x3 = R.jsgraph.Float64Constant(33.3); - Node* y3 = R.jsgraph.Float64Constant(44.4); - - Diamond d2(R, R.p0, x2, y2); - Diamond d3(R, R.p0, x3, y3); - Diamond d1(R, R.p0, d2.phi, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // nothing should happen. - - CheckInputs(ret, d1.phi, R.start, d1.merge); - CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge); - CheckInputs(d1.merge, d2.merge, d3.merge); - - DeadChecker dead(&R.graph); - dead.CheckLive(d2); - dead.CheckLive(d3); -} - - -TEST(Return_nested_diamonds_true2) { - ControlReducerTester R; - Node* x2 = R.jsgraph.Float64Constant(11.1); - Node* y2 = R.jsgraph.Float64Constant(22.2); - Node* x3 = R.jsgraph.Float64Constant(33.3); - Node* y3 = R.jsgraph.Float64Constant(44.4); - - Diamond d2(R, R.p0, x2, y2); - Diamond d3(R, R.p0, x3, y3); - Diamond d1(R, R.one, d2.phi, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded true. - - CheckInputs(ret, d2.phi, R.start, d2.merge); - CheckInputs(d2.branch, R.p0, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.CheckLive(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds_true_true2) { - ControlReducerTester R; - Node* x2 = R.jsgraph.Float64Constant(11.1); - Node* y2 = R.jsgraph.Float64Constant(22.2); - Node* x3 = R.jsgraph.Float64Constant(33.3); - Node* y3 = R.jsgraph.Float64Constant(44.4); - - Diamond d2(R, R.one, x2, y2); - Diamond d3(R, R.p0, x3, y3); - Diamond d1(R, R.one, d2.phi, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded true. - - CheckInputs(ret, x2, R.start, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.Check(d2); - dead.Check(d3); -} - - -TEST(Return_nested_diamonds_true_false2) { - ControlReducerTester R; - Node* x2 = R.jsgraph.Float64Constant(11.1); - Node* y2 = R.jsgraph.Float64Constant(22.2); - Node* x3 = R.jsgraph.Float64Constant(33.3); - Node* y3 = R.jsgraph.Float64Constant(44.4); - - Diamond d2(R, R.zero, x2, y2); - Diamond d3(R, R.p0, x3, y3); - Diamond d1(R, R.one, d2.phi, d3.phi); - - d2.nest(d1, true); - d3.nest(d1, false); - - Node* ret = R.Return(d1.phi, R.start, d1.merge); - - R.ReduceGraph(); // d1 gets folded true. - - CheckInputs(ret, y2, R.start, R.start); - - DeadChecker dead(&R.graph); - dead.Check(d1); - dead.Check(d2); - dead.Check(d3); -} diff --git a/deps/v8/test/cctest/compiler/test-js-constant-cache.cc b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc index 630f911c5e..8774a9a9e3 100644 --- a/deps/v8/test/cctest/compiler/test-js-constant-cache.cc +++ b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc @@ -21,7 +21,7 @@ class JSCacheTesterHelper { : main_graph_(zone), main_common_(zone), main_javascript_(zone), - main_typer_(isolate, &main_graph_, MaybeHandle<Context>()), + main_typer_(isolate, &main_graph_), main_machine_(zone) {} Graph main_graph_; CommonOperatorBuilder main_common_; @@ -41,7 +41,7 @@ class JSConstantCacheTester : public HandleAndZoneScope, JSGraph(main_isolate(), &main_graph_, &main_common_, &main_javascript_, &main_machine_) { main_graph_.SetStart(main_graph_.NewNode(common()->Start(0))); - main_graph_.SetEnd(main_graph_.NewNode(common()->End())); + main_graph_.SetEnd(main_graph_.NewNode(common()->End(1))); main_typer_.Run(); } @@ -335,7 +335,7 @@ TEST(JSGraph_GetCachedNodes_int32) { 25, 15, 30, 31, 45, 46, 47, 48}; for (size_t i = 0; i < arraysize(constants); i++) { - int count_before = T.graph()->NodeCount(); + size_t count_before = T.graph()->NodeCount(); NodeVector nodes_before(T.main_zone()); T.GetCachedNodes(&nodes_before); Node* n = T.Int32Constant(constants[i]); @@ -357,7 +357,7 @@ TEST(JSGraph_GetCachedNodes_float64) { 11, 11, -33.3, -33.3, -22, -11}; for (size_t i = 0; i < arraysize(constants); i++) { - int count_before = T.graph()->NodeCount(); + size_t count_before = T.graph()->NodeCount(); NodeVector nodes_before(T.main_zone()); T.GetCachedNodes(&nodes_before); Node* n = T.Float64Constant(constants[i]); @@ -379,7 +379,7 @@ TEST(JSGraph_GetCachedNodes_int64) { 19, 20, 20, 21, 21, 22, 23, 24, 25}; for (size_t i = 0; i < arraysize(constants); i++) { - int count_before = T.graph()->NodeCount(); + size_t count_before = T.graph()->NodeCount(); NodeVector nodes_before(T.main_zone()); T.GetCachedNodes(&nodes_before); Node* n = T.Int64Constant(constants[i]); @@ -401,7 +401,7 @@ TEST(JSGraph_GetCachedNodes_number) { 11, 11, -33.3, -33.3, -22, -11}; for (size_t i = 0; i < arraysize(constants); i++) { - int count_before = T.graph()->NodeCount(); + size_t count_before = T.graph()->NodeCount(); NodeVector nodes_before(T.main_zone()); T.GetCachedNodes(&nodes_before); Node* n = T.Constant(constants[i]); @@ -428,7 +428,7 @@ TEST(JSGraph_GetCachedNodes_external) { ExternalReference::address_of_one_half()}; for (size_t i = 0; i < arraysize(constants); i++) { - int count_before = T.graph()->NodeCount(); + size_t count_before = T.graph()->NodeCount(); NodeVector nodes_before(T.main_zone()); T.GetCachedNodes(&nodes_before); Node* n = T.ExternalConstant(constants[i]); diff --git a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc index 2450e7cf57..328b0aefdd 100644 --- a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc +++ b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/compiler/js-context-specialization.h" +#include "src/compiler/js-graph.h" #include "src/compiler/js-operator.h" #include "src/compiler/node-matchers.h" #include "src/compiler/node-properties.h" @@ -22,8 +23,11 @@ class ContextSpecializationTester : public HandleAndZoneScope { javascript_(main_zone()), machine_(main_zone()), simplified_(main_zone()), - jsgraph_(main_isolate(), graph(), common(), &javascript_, &machine_) {} + jsgraph_(main_isolate(), graph(), common(), &javascript_, &machine_), + reducer_(main_zone(), graph()), + spec_(&reducer_, jsgraph(), MaybeHandle<Context>()) {} + JSContextSpecialization* spec() { return &spec_; } Factory* factory() { return main_isolate()->factory(); } CommonOperatorBuilder* common() { return &common_; } JSOperatorBuilder* javascript() { return &javascript_; } @@ -38,6 +42,8 @@ class ContextSpecializationTester : public HandleAndZoneScope { MachineOperatorBuilder machine_; SimplifiedOperatorBuilder simplified_; JSGraph jsgraph_; + GraphReducer reducer_; + JSContextSpecialization spec_; }; @@ -60,13 +66,12 @@ TEST(ReduceJSLoadContext) { Node* const_context = t.jsgraph()->Constant(native); Node* deep_const_context = t.jsgraph()->Constant(subcontext2); Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start); - JSContextSpecializer spec(t.jsgraph()); { // Mutable slot, constant context, depth = 0 => do nothing. Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false), const_context, const_context, start); - Reduction r = spec.ReduceJSLoadContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(!r.Changed()); } @@ -74,7 +79,7 @@ TEST(ReduceJSLoadContext) { // Mutable slot, non-constant context, depth = 0 => do nothing. Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, 0, false), param_context, param_context, start); - Reduction r = spec.ReduceJSLoadContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(!r.Changed()); } @@ -83,11 +88,11 @@ TEST(ReduceJSLoadContext) { Node* load = t.graph()->NewNode( t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false), deep_const_context, deep_const_context, start); - Reduction r = spec.ReduceJSLoadContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(r.Changed()); Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); - HeapObjectMatcher<Context> match(new_context_input); + HeapObjectMatcher match(new_context_input); CHECK_EQ(*native, *match.Value().handle()); ContextAccess access = OpParameter<ContextAccess>(r.replacement()); CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index())); @@ -99,11 +104,11 @@ TEST(ReduceJSLoadContext) { // Immutable slot, constant context, depth = 0 => specialize. Node* load = t.graph()->NewNode(t.javascript()->LoadContext(0, slot, true), const_context, const_context, start); - Reduction r = spec.ReduceJSLoadContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(r.Changed()); CHECK(r.replacement() != load); - HeapObjectMatcher<Object> match(r.replacement()); + HeapObjectMatcher match(r.replacement()); CHECK(match.HasValue()); CHECK_EQ(*expected, *match.Value().handle()); } @@ -132,13 +137,12 @@ TEST(ReduceJSStoreContext) { Node* const_context = t.jsgraph()->Constant(native); Node* deep_const_context = t.jsgraph()->Constant(subcontext2); Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start); - JSContextSpecializer spec(t.jsgraph()); { // Mutable slot, constant context, depth = 0 => do nothing. Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0), const_context, const_context, start); - Reduction r = spec.ReduceJSStoreContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(!r.Changed()); } @@ -146,7 +150,7 @@ TEST(ReduceJSStoreContext) { // Mutable slot, non-constant context, depth = 0 => do nothing. Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, 0), param_context, param_context, start); - Reduction r = spec.ReduceJSStoreContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(!r.Changed()); } @@ -154,7 +158,7 @@ TEST(ReduceJSStoreContext) { // Immutable slot, constant context, depth = 0 => do nothing. Node* load = t.graph()->NewNode(t.javascript()->StoreContext(0, slot), const_context, const_context, start); - Reduction r = spec.ReduceJSStoreContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(!r.Changed()); } @@ -163,11 +167,11 @@ TEST(ReduceJSStoreContext) { Node* load = t.graph()->NewNode( t.javascript()->StoreContext(2, Context::GLOBAL_EVAL_FUN_INDEX), deep_const_context, deep_const_context, start); - Reduction r = spec.ReduceJSStoreContext(load); + Reduction r = t.spec()->Reduce(load); CHECK(r.Changed()); Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); - HeapObjectMatcher<Context> match(new_context_input); + HeapObjectMatcher match(new_context_input); CHECK_EQ(*native, *match.Value().handle()); ContextAccess access = OpParameter<ContextAccess>(r.replacement()); CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index())); @@ -197,7 +201,6 @@ TEST(SpecializeToContext) { Node* const_context = t.jsgraph()->Constant(native); Node* param_context = t.graph()->NewNode(t.common()->Parameter(0), start); - JSContextSpecializer spec(t.jsgraph()); { // Check that specialization replaces values and forwards effects @@ -222,7 +225,7 @@ TEST(SpecializeToContext) { Node* ret = t.graph()->NewNode(t.common()->Return(), add, effect_use, start); - Node* end = t.graph()->NewNode(t.common()->End(), ret); + Node* end = t.graph()->NewNode(t.common()->End(1), ret); USE(end); t.graph()->SetEnd(end); @@ -231,7 +234,9 @@ TEST(SpecializeToContext) { CheckEffectInput(load, effect_use); // Perform the reduction on the entire graph. - GraphReducer graph_reducer(t.graph(), t.main_zone()); + GraphReducer graph_reducer(t.main_zone(), t.graph()); + JSContextSpecialization spec(&graph_reducer, t.jsgraph(), + MaybeHandle<Context>()); graph_reducer.AddReducer(&spec); graph_reducer.ReduceGraph(); @@ -242,7 +247,7 @@ TEST(SpecializeToContext) { CHECK_EQ(other_load, other_use->InputAt(0)); Node* replacement = value_use->InputAt(0); - HeapObjectMatcher<Object> match(replacement); + HeapObjectMatcher match(replacement); CHECK(match.HasValue()); CHECK_EQ(*expected, *match.Value().handle()); } diff --git a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc index 92fdb6e874..e512de89b2 100644 --- a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc @@ -38,10 +38,10 @@ class JSTypedLoweringTester : public HandleAndZoneScope { simplified(main_zone()), common(main_zone()), graph(main_zone()), - typer(main_isolate(), &graph, MaybeHandle<Context>()), + typer(main_isolate(), &graph), context_node(NULL) { graph.SetStart(graph.NewNode(common.Start(num_parameters))); - graph.SetEnd(graph.NewNode(common.End())); + graph.SetEnd(graph.NewNode(common.End(1))); typer.Run(); } @@ -79,17 +79,19 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* locals = graph.NewNode(common.StateValues(0)); Node* stack = graph.NewNode(common.StateValues(0)); - Node* state_node = - graph.NewNode(common.FrameState(JS_FRAME, BailoutId::None(), - OutputFrameStateCombine::Ignore()), - parameters, locals, stack, context, UndefinedConstant()); + Node* state_node = graph.NewNode( + common.FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(), + nullptr), + parameters, locals, stack, context, UndefinedConstant()); return state_node; } Node* reduce(Node* node) { JSGraph jsgraph(main_isolate(), &graph, &common, &javascript, &machine); - JSTypedLowering reducer(&jsgraph, main_zone()); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(main_zone(), &graph); + JSTypedLowering reducer(&graph_reducer, &jsgraph, main_zone()); Reduction reduction = reducer.Reduce(node); if (reduction.Changed()) return reduction.replacement(); return node; @@ -318,11 +320,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { : JSTypedLoweringTester(), language_mode_(language_mode) { int i = 0; set(i++, javascript.ShiftLeft(language_mode_), true); - set(i++, machine.Word32Shl(), false); + set(i++, simplified.NumberShiftLeft(), false); set(i++, javascript.ShiftRight(language_mode_), true); - set(i++, machine.Word32Sar(), false); + set(i++, simplified.NumberShiftRight(), false); set(i++, javascript.ShiftRightLogical(language_mode_), false); - set(i++, machine.Word32Shr(), false); + set(i++, simplified.NumberShiftRightLogical(), false); } static const int kNumberOps = 6; const Operator* ops[kNumberOps]; @@ -362,14 +364,7 @@ TEST(Int32BitwiseShifts) { Node* r1 = r->InputAt(1); CheckToI32(p0, r0, R.signedness[k]); - - if (r1->opcode() == IrOpcode::kWord32And) { - R.CheckPureBinop(IrOpcode::kWord32And, r1); - CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]); - R.CheckInt32Constant(0x1F, r1->InputAt(1)); - } else { - CheckToI32(p1, r1, R.signedness[k]); - } + CheckToI32(p1, r1, false); } } } @@ -460,8 +455,9 @@ TEST(JSToNumber_replacement) { for (size_t i = 0; i < arraysize(types); i++) { Node* n = R.Parameter(types[i]); - Node* c = R.graph.NewNode(R.javascript.ToNumber(), n, R.context(), - R.start(), R.start()); + Node* c = + R.graph.NewNode(R.javascript.ToNumber(), n, R.context(), + R.EmptyFrameState(R.context()), R.start(), R.start()); Node* effect_use = R.UseForEffect(c); Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c); @@ -688,18 +684,20 @@ TEST_WITH_STRONG(MixedComparison1) { for (size_t j = 0; j < arraysize(types); j++) { Node* p1 = R.Parameter(types[j], 1); { - Node* cmp = R.Binop(R.javascript.LessThan(language_mode), p0, p1); + const Operator* less_than = R.javascript.LessThan(language_mode); + Node* cmp = R.Binop(less_than, p0, p1); Node* r = R.reduce(cmp); - - if (!types[i]->Maybe(Type::String()) || - !types[j]->Maybe(Type::String())) { - if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) { - R.CheckPureBinop(R.simplified.StringLessThan(), r); - } else { - R.CheckPureBinop(R.simplified.NumberLessThan(), r); - } + if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) { + R.CheckPureBinop(R.simplified.StringLessThan(), r); + } else if ((types[i]->Is(Type::Number()) && + types[j]->Is(Type::Number())) || + (!is_strong(language_mode) && + (!types[i]->Maybe(Type::String()) || + !types[j]->Maybe(Type::String())))) { + R.CheckPureBinop(R.simplified.NumberLessThan(), r); } else { - CHECK_EQ(cmp, r); // No reduction of mixed types. + // No reduction of mixed types. + CHECK_EQ(r->op(), less_than); } } } @@ -708,8 +706,6 @@ TEST_WITH_STRONG(MixedComparison1) { TEST_WITH_STRONG(RemoveToNumberEffects) { - FLAG_turbo_deoptimization = true; - JSTypedLoweringTester R; Node* effect_use = NULL; @@ -721,27 +717,16 @@ TEST_WITH_STRONG(RemoveToNumberEffects) { switch (i) { case 0: - if (FLAG_turbo_deoptimization) { - DCHECK(OperatorProperties::GetFrameStateInputCount( - R.javascript.ToNumber()) == 1); - effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(), - frame_state, ton, R.start()); - } else { + DCHECK(OperatorProperties::GetFrameStateInputCount( + R.javascript.ToNumber()) == 1); effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(), - ton, R.start()); - } + frame_state, ton, R.start()); break; case 1: - if (FLAG_turbo_deoptimization) { - DCHECK(OperatorProperties::GetFrameStateInputCount( - R.javascript.ToNumber()) == 1); - effect_use = - R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(), - frame_state, ton, R.start()); - } else { - effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, - R.context(), ton, R.start()); - } + DCHECK(OperatorProperties::GetFrameStateInputCount( + R.javascript.ToNumber()) == 1); + effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(), + frame_state, ton, R.start()); break; case 2: effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); @@ -950,8 +935,6 @@ TEST(OrderNumberBinopEffects1) { R.simplified.NumberMultiply(), R.javascript.Divide(LanguageMode::SLOPPY), R.simplified.NumberDivide(), - R.javascript.Modulus(LanguageMode::SLOPPY), - R.simplified.NumberModulus(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { @@ -982,8 +965,6 @@ TEST(OrderNumberBinopEffects2) { R.simplified.NumberMultiply(), R.javascript.Divide(LanguageMode::SLOPPY), R.simplified.NumberDivide(), - R.javascript.Modulus(LanguageMode::SLOPPY), - R.simplified.NumberModulus(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { diff --git a/deps/v8/test/cctest/compiler/test-jump-threading.cc b/deps/v8/test/cctest/compiler/test-jump-threading.cc index e0a4a2fc62..9fa3c9f28a 100644 --- a/deps/v8/test/cctest/compiler/test-jump-threading.cc +++ b/deps/v8/test/cctest/compiler/test-jump-threading.cc @@ -85,7 +85,7 @@ class TestCode : public HandleAndZoneScope { if (current_ == NULL) { current_ = new (main_zone()) InstructionBlock(main_zone(), rpo_number_, RpoNumber::Invalid(), - RpoNumber::Invalid(), deferred); + RpoNumber::Invalid(), deferred, false); blocks_.push_back(current_); sequence_.StartBlock(rpo_number_); } diff --git a/deps/v8/test/cctest/compiler/test-linkage.cc b/deps/v8/test/cctest/compiler/test-linkage.cc index 212ff3a8f2..252c43133e 100644 --- a/deps/v8/test/cctest/compiler/test-linkage.cc +++ b/deps/v8/test/cctest/compiler/test-linkage.cc @@ -34,8 +34,8 @@ static Handle<JSFunction> Compile(const char* source) { ->NewStringFromUtf8(CStrVector(source)) .ToHandleChecked(); Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( - source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(), - Handle<Context>(isolate->native_context()), NULL, NULL, + source_code, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), + Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, NULL, v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false); return isolate->factory()->NewFunctionFromSharedFunctionInfo( shared_function, isolate->native_context()); @@ -114,5 +114,4 @@ TEST(TestLinkageStubCall) { // TODO(titzer): test linkage creation for outgoing stub calls. } - #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-loop-analysis.cc b/deps/v8/test/cctest/compiler/test-loop-analysis.cc index 06682ef5a9..6560ae337b 100644 --- a/deps/v8/test/cctest/compiler/test-loop-analysis.cc +++ b/deps/v8/test/cctest/compiler/test-loop-analysis.cc @@ -41,7 +41,7 @@ class LoopFinderTester : HandleAndZoneScope { graph(main_zone()), jsgraph(main_isolate(), &graph, &common, NULL, NULL), start(graph.NewNode(common.Start(1))), - end(graph.NewNode(common.End(), start)), + end(graph.NewNode(common.End(1), start)), p0(graph.NewNode(common.Parameter(0), start)), zero(jsgraph.Int32Constant(0)), one(jsgraph.OneConstant()), diff --git a/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc b/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc index 5f9820c72a..ad05273995 100644 --- a/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc +++ b/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc @@ -51,7 +51,7 @@ struct TestHelper : public HandleAndZoneScope { i::Variable* var = scope->Lookup(name); CHECK(var); - if (var->location() == Variable::UNALLOCATED) { + if (var->location() == VariableLocation::UNALLOCATED) { CHECK_EQ(0, expected); } else { CHECK(var->IsStackAllocated()); diff --git a/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc index beedc459e7..299f0c02ab 100644 --- a/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc +++ b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc @@ -60,7 +60,7 @@ class ReducerTester : public HandleAndZoneScope { common(main_zone()), graph(main_zone()), javascript(main_zone()), - typer(isolate, &graph, MaybeHandle<Context>()), + typer(isolate, &graph), jsgraph(isolate, &graph, &common, &javascript, &machine), maxuint32(Constant<int32_t>(kMaxUInt32)) { Node* s = graph.NewNode(common.Start(num_parameters)); diff --git a/deps/v8/test/cctest/compiler/test-osr.cc b/deps/v8/test/cctest/compiler/test-osr.cc index d2171188f8..80dbccc633 100644 --- a/deps/v8/test/cctest/compiler/test-osr.cc +++ b/deps/v8/test/cctest/compiler/test-osr.cc @@ -51,7 +51,7 @@ class OsrDeconstructorTester : public HandleAndZoneScope { jsgraph(main_isolate(), &graph, &common, NULL, NULL), start(graph.NewNode(common.Start(1))), p0(graph.NewNode(common.Parameter(0), start)), - end(graph.NewNode(common.End(), start)), + end(graph.NewNode(common.End(1), start)), osr_normal_entry(graph.NewNode(common.OsrNormalEntry(), start, start)), osr_loop_entry(graph.NewNode(common.OsrLoopEntry(), start, start)), self(graph.NewNode(common.Int32Constant(0xaabbccdd))) { @@ -165,30 +165,6 @@ TEST(Deconstruct_osr1) { } -TEST(Deconstruct_osr1_type) { - OsrDeconstructorTester T(1); - - Node* loop = T.NewOsrLoop(1); - Node* osr_phi = - T.NewOsrPhi(loop, T.jsgraph.OneConstant(), 0, T.jsgraph.ZeroConstant()); - Type* type = Type::Signed32(); - NodeProperties::SetBounds(osr_phi, Bounds(type, type)); - - Node* ret = T.graph.NewNode(T.common.Return(), osr_phi, T.start, loop); - T.graph.SetEnd(ret); - - OsrHelper helper(0, 0); - helper.Deconstruct(&T.jsgraph, &T.common, T.main_zone()); - - CHECK_EQ(type, NodeProperties::GetBounds(T.osr_values[0]).lower); - CHECK_EQ(type, NodeProperties::GetBounds(T.osr_values[0]).upper); - - CheckInputs(loop, T.start, loop); - CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), loop); - CheckInputs(ret, osr_phi, T.start, loop); -} - - TEST(Deconstruct_osr_remove_prologue) { OsrDeconstructorTester T(1); Diamond d(&T.graph, &T.common, T.p0); @@ -370,14 +346,14 @@ TEST(Deconstruct_osr_nested1) { Node* outer_phi = outer.Phi(T.p0, T.p0, nullptr); outer.branch->ReplaceInput(0, outer_phi); - Node* osr_phi = inner.Phi(T.jsgraph.OneConstant(), T.osr_values[0], - T.jsgraph.ZeroConstant()); + Node* osr_phi = inner.Phi(T.jsgraph.TrueConstant(), T.osr_values[0], + T.jsgraph.FalseConstant()); inner.branch->ReplaceInput(0, osr_phi); outer_phi->ReplaceInput(1, osr_phi); Node* ret = T.graph.NewNode(T.common.Return(), outer_phi, T.start, outer.exit); - Node* end = T.graph.NewNode(T.common.End(), ret); + Node* end = T.graph.NewNode(T.common.End(1), ret); T.graph.SetEnd(end); T.DeconstructOsr(); @@ -385,7 +361,7 @@ TEST(Deconstruct_osr_nested1) { // Check structure of deconstructed graph. // Check inner OSR loop is directly connected to start. CheckInputs(inner.loop, T.start, inner.if_true); - CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), inner.loop); + CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.FalseConstant(), inner.loop); // Check control transfer to copy of outer loop. Node* new_outer_loop = FindSuccessor(inner.exit, IrOpcode::kLoop); @@ -412,8 +388,8 @@ TEST(Deconstruct_osr_nested1) { Node* new_inner_loop = FindSuccessor(new_outer_if_true, IrOpcode::kLoop); Node* new_inner_phi = FindSuccessor(new_inner_loop, IrOpcode::kPhi); - CheckInputs(new_inner_phi, T.jsgraph.OneConstant(), T.jsgraph.ZeroConstant(), - new_inner_loop); + CheckInputs(new_inner_phi, T.jsgraph.TrueConstant(), + T.jsgraph.FalseConstant(), new_inner_loop); CheckInputs(new_outer_phi, osr_phi, new_inner_phi, new_outer_loop); } @@ -429,11 +405,11 @@ TEST(Deconstruct_osr_nested2) { Node* outer_phi = outer.Phi(T.p0, T.p0, T.p0); outer.branch->ReplaceInput(0, outer_phi); - Node* osr_phi = inner.Phi(T.jsgraph.OneConstant(), T.osr_values[0], - T.jsgraph.ZeroConstant()); + Node* osr_phi = inner.Phi(T.jsgraph.TrueConstant(), T.osr_values[0], + T.jsgraph.FalseConstant()); inner.branch->ReplaceInput(0, osr_phi); outer_phi->ReplaceInput(1, osr_phi); - outer_phi->ReplaceInput(2, T.jsgraph.ZeroConstant()); + outer_phi->ReplaceInput(2, T.jsgraph.FalseConstant()); Node* x_branch = T.graph.NewNode(T.common.Branch(), osr_phi, inner.exit); Node* x_true = T.graph.NewNode(T.common.IfTrue(), x_branch); @@ -444,7 +420,7 @@ TEST(Deconstruct_osr_nested2) { Node* ret = T.graph.NewNode(T.common.Return(), outer_phi, T.start, outer.exit); - Node* end = T.graph.NewNode(T.common.End(), ret); + Node* end = T.graph.NewNode(T.common.End(1), ret); T.graph.SetEnd(end); T.DeconstructOsr(); @@ -452,7 +428,7 @@ TEST(Deconstruct_osr_nested2) { // Check structure of deconstructed graph. // Check inner OSR loop is directly connected to start. CheckInputs(inner.loop, T.start, inner.if_true); - CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.ZeroConstant(), inner.loop); + CheckInputs(osr_phi, T.osr_values[0], T.jsgraph.FalseConstant(), inner.loop); // Check control transfer to copy of outer loop. Node* new_merge = FindSuccessor(x_true, IrOpcode::kMerge); @@ -465,7 +441,7 @@ TEST(Deconstruct_osr_nested2) { CHECK_NE(new_outer_phi, outer_phi); Node* new_entry_phi = FindSuccessor(new_merge, IrOpcode::kPhi); - CheckInputs(new_entry_phi, osr_phi, T.jsgraph.ZeroConstant(), new_merge); + CheckInputs(new_entry_phi, osr_phi, T.jsgraph.FalseConstant(), new_merge); CHECK_EQ(new_merge, new_outer_loop->InputAt(0)); @@ -486,10 +462,10 @@ TEST(Deconstruct_osr_nested2) { Node* new_inner_loop = FindSuccessor(new_outer_if_true, IrOpcode::kLoop); Node* new_inner_phi = FindSuccessor(new_inner_loop, IrOpcode::kPhi); - CheckInputs(new_inner_phi, T.jsgraph.OneConstant(), T.jsgraph.ZeroConstant(), - new_inner_loop); + CheckInputs(new_inner_phi, T.jsgraph.TrueConstant(), + T.jsgraph.FalseConstant(), new_inner_loop); CheckInputs(new_outer_phi, new_entry_phi, new_inner_phi, - T.jsgraph.ZeroConstant(), new_outer_loop); + T.jsgraph.FalseConstant(), new_outer_loop); } @@ -523,8 +499,8 @@ TEST(Deconstruct_osr_nested3) { // middle loop. Node* loop1 = T.graph.NewNode(T.common.Loop(2), loop0.if_true, T.self); loop1->ReplaceInput(0, loop0.if_true); - Node* loop1_phi = - T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), loop0_cntr, loop0_cntr); + Node* loop1_phi = T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), loop0_cntr, + loop0_cntr, loop1); // innermost (OSR) loop. While loop2(T, T.p0, true, 1); @@ -549,7 +525,7 @@ TEST(Deconstruct_osr_nested3) { Node* ret = T.graph.NewNode(T.common.Return(), loop0_cntr, T.start, loop0.exit); - Node* end = T.graph.NewNode(T.common.End(), ret); + Node* end = T.graph.NewNode(T.common.End(1), ret); T.graph.SetEnd(end); T.DeconstructOsr(); diff --git a/deps/v8/test/cctest/compiler/test-pipeline.cc b/deps/v8/test/cctest/compiler/test-pipeline.cc index b67af6ecf7..84550d502a 100644 --- a/deps/v8/test/cctest/compiler/test-pipeline.cc +++ b/deps/v8/test/cctest/compiler/test-pipeline.cc @@ -5,23 +5,18 @@ #include "src/v8.h" #include "test/cctest/cctest.h" -#include "src/ast-numbering.h" #include "src/compiler.h" #include "src/compiler/pipeline.h" #include "src/handles.h" #include "src/parser.h" -#include "src/rewriter.h" -#include "src/scopes.h" using namespace v8::internal; using namespace v8::internal::compiler; -TEST(PipelineAdd) { - HandleAndZoneScope handles; - const char* source = "(function(a,b) { return a + b; })"; +static void RunPipeline(Zone* zone, const char* source) { Handle<JSFunction> function = v8::Utils::OpenHandle( *v8::Handle<v8::Function>::Cast(CompileRun(source))); - ParseInfo parse_info(handles.main_zone(), function); + ParseInfo parse_info(zone, function); CHECK(Compiler::ParseAndAnalyze(&parse_info)); CompilationInfo info(&parse_info); @@ -34,3 +29,17 @@ TEST(PipelineAdd) { USE(pipeline); #endif } + + +TEST(PipelineTyped) { + HandleAndZoneScope handles; + FLAG_turbo_types = true; + RunPipeline(handles.main_zone(), "(function(a,b) { return a + b; })"); +} + + +TEST(PipelineGeneric) { + HandleAndZoneScope handles; + FLAG_turbo_types = false; + RunPipeline(handles.main_zone(), "(function(a,b) { return a + b; })"); +} diff --git a/deps/v8/test/cctest/compiler/test-representation-change.cc b/deps/v8/test/cctest/compiler/test-representation-change.cc index 55f054a74b..216f9fd847 100644 --- a/deps/v8/test/cctest/compiler/test-representation-change.cc +++ b/deps/v8/test/cctest/compiler/test-representation-change.cc @@ -69,7 +69,7 @@ class RepresentationChangerTester : public HandleAndZoneScope, } void CheckHeapConstant(Node* n, HeapObject* expected) { - HeapObjectMatcher<HeapObject> m(n); + HeapObjectMatcher m(n); CHECK(m.HasValue()); CHECK_EQ(expected, *m.Value().handle()); } @@ -100,9 +100,9 @@ class RepresentationChangerTester : public HandleAndZoneScope, CHECK_EQ(n, c); } }; -} -} -} // namespace v8::internal::compiler +} // namespace compiler +} // namespace internal +} // namespace v8 static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64, diff --git a/deps/v8/test/cctest/compiler/test-run-deopt.cc b/deps/v8/test/cctest/compiler/test-run-deopt.cc index 14c024cdbc..d895924324 100644 --- a/deps/v8/test/cctest/compiler/test-run-deopt.cc +++ b/deps/v8/test/cctest/compiler/test-run-deopt.cc @@ -7,13 +7,12 @@ #include "test/cctest/cctest.h" #include "test/cctest/compiler/function-tester.h" -using namespace v8; using namespace v8::internal; using namespace v8::internal::compiler; #if V8_TURBOFAN_TARGET -static void IsOptimized(const FunctionCallbackInfo<v8::Value>& args) { +static void IsOptimized(const v8::FunctionCallbackInfo<v8::Value>& args) { JavaScriptFrameIterator it(CcTest::i_isolate()); JavaScriptFrame* frame = it.frame(); return args.GetReturnValue().Set(frame->is_optimized()); @@ -21,56 +20,99 @@ static void IsOptimized(const FunctionCallbackInfo<v8::Value>& args) { static void InstallIsOptimizedHelper(v8::Isolate* isolate) { - Local<v8::Context> context = isolate->GetCurrentContext(); - Local<v8::FunctionTemplate> t = FunctionTemplate::New(isolate, IsOptimized); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + v8::Local<v8::FunctionTemplate> t = + v8::FunctionTemplate::New(isolate, IsOptimized); context->Global()->Set(v8_str("IsOptimized"), t->GetFunction()); } -TEST(TurboSimpleDeopt) { +TEST(DeoptSimple) { FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; FunctionTester T( "(function f(a) {" - "var b = 1;" - "if (!IsOptimized()) return 0;" - "%DeoptimizeFunction(f);" - "if (IsOptimized()) return 0;" - "return a + b; })"); + " var b = 1;" + " if (!IsOptimized()) return 0;" + " %DeoptimizeFunction(f);" + " if (IsOptimized()) return 0;" + " return a + b;" + "})"); InstallIsOptimizedHelper(CcTest::isolate()); T.CheckCall(T.Val(2), T.Val(1)); } -TEST(TurboSimpleDeoptInExpr) { +TEST(DeoptSimpleInExpr) { FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; FunctionTester T( "(function f(a) {" - "var b = 1;" - "var c = 2;" - "if (!IsOptimized()) return 0;" - "var d = b + (%DeoptimizeFunction(f), c);" - "if (IsOptimized()) return 0;" - "return d + a; })"); + " var b = 1;" + " var c = 2;" + " if (!IsOptimized()) return 0;" + " var d = b + (%DeoptimizeFunction(f), c);" + " if (IsOptimized()) return 0;" + " return d + a;" + "})"); InstallIsOptimizedHelper(CcTest::isolate()); T.CheckCall(T.Val(6), T.Val(3)); } + +TEST(DeoptExceptionHandlerCatch) { + FLAG_allow_natives_syntax = true; + FLAG_turbo_try_catch = true; + + FunctionTester T( + "(function f() {" + " var is_opt = IsOptimized;" + " try {" + " DeoptAndThrow(f);" + " } catch (e) {" + " return is_opt();" + " }" + "})"); + + CompileRun("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }"); + InstallIsOptimizedHelper(CcTest::isolate()); + T.CheckCall(T.false_value()); +} + + +TEST(DeoptExceptionHandlerFinally) { + FLAG_allow_natives_syntax = true; + FLAG_turbo_try_finally = true; + + FunctionTester T( + "(function f() {" + " var is_opt = IsOptimized;" + " try {" + " DeoptAndThrow(f);" + " } finally {" + " return is_opt();" + " }" + "})"); + + CompileRun("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }"); + InstallIsOptimizedHelper(CcTest::isolate()); +#if 0 // TODO(4195,mstarzinger): Reproduces on MIPS64, re-enable once fixed. + T.CheckCall(T.false_value()); +#endif +} + #endif -TEST(TurboTrivialDeopt) { +TEST(DeoptTrivial) { FLAG_allow_natives_syntax = true; - FLAG_turbo_deoptimization = true; FunctionTester T( "(function foo() {" - "%DeoptimizeFunction(foo);" - "return 1; })"); + " %DeoptimizeFunction(foo);" + " return 1;" + "})"); T.CheckCall(T.Val(1)); } diff --git a/deps/v8/test/cctest/compiler/test-run-inlining.cc b/deps/v8/test/cctest/compiler/test-run-inlining.cc index a6d76e4d57..7f8ae25619 100644 --- a/deps/v8/test/cctest/compiler/test-run-inlining.cc +++ b/deps/v8/test/cctest/compiler/test-run-inlining.cc @@ -13,7 +13,7 @@ using namespace v8::internal::compiler; namespace { -// Helper to determine inline count via JavaScriptFrame::GetInlineCount. +// Helper to determine inline count via JavaScriptFrame::GetFunctions. // Note that a count of 1 indicates that no inlining has occured. void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { StackTraceFrameIterator it(CcTest::i_isolate()); @@ -21,14 +21,17 @@ void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { JavaScriptFrame* topmost = it.frame(); while (!it.done()) { JavaScriptFrame* frame = it.frame(); + List<JSFunction*> functions(2); + frame->GetFunctions(&functions); PrintF("%d %s, inline count: %d\n", frames_seen, frame->function()->shared()->DebugName()->ToCString().get(), - frame->GetInlineCount()); + functions.length()); frames_seen++; it.Advance(); } - CHECK_EQ(args[0]->ToInt32(args.GetIsolate())->Value(), - topmost->GetInlineCount()); + List<JSFunction*> functions(2); + topmost->GetFunctions(&functions); + CHECK_EQ(args[0]->ToInt32(args.GetIsolate())->Value(), functions.length()); } @@ -40,9 +43,8 @@ void InstallAssertInlineCountHelper(v8::Isolate* isolate) { } -const uint32_t kBuiltinInlineFlags = CompilationInfo::kBuiltinInliningEnabled | - CompilationInfo::kContextSpecializing | - CompilationInfo::kTypingEnabled; +const uint32_t kRestrictedInliningFlags = + CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled; const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled | CompilationInfo::kContextSpecializing | @@ -52,7 +54,6 @@ const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled | TEST(SimpleInlining) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function(){" " function foo(s) { AssertInlineCount(2); return s; };" @@ -67,7 +68,6 @@ TEST(SimpleInlining) { TEST(SimpleInliningDeopt) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function(){" " function foo(s) { %DeoptimizeFunction(bar); return s; };" @@ -81,8 +81,21 @@ TEST(SimpleInliningDeopt) { } +TEST(SimpleInliningDeoptSelf) { + FunctionTester T( + "(function(){" + " function foo(s) { %_DeoptimizeNow(); return s; };" + " function bar(s, t) { return foo(s); };" + " return bar;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(1), T.Val(1), T.Val(2)); +} + + TEST(SimpleInliningContext) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };" @@ -97,7 +110,6 @@ TEST(SimpleInliningContext) { TEST(SimpleInliningContextDeopt) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) {" @@ -115,7 +127,6 @@ TEST(SimpleInliningContextDeopt) { TEST(CaptureContext) { - FLAG_turbo_deoptimization = true; FunctionTester T( "var f = (function () {" " var x = 42;" @@ -133,7 +144,6 @@ TEST(CaptureContext) { // TODO(sigurds) For now we do not inline any native functions. If we do at // some point, change this test. TEST(DontInlineEval) { - FLAG_turbo_deoptimization = true; FunctionTester T( "var x = 42;" "(function () {" @@ -148,7 +158,6 @@ TEST(DontInlineEval) { TEST(InlineOmitArguments) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -163,7 +172,6 @@ TEST(InlineOmitArguments) { TEST(InlineOmitArgumentsDeopt) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t,u,v) { AssertInlineCount(2);" @@ -181,7 +189,6 @@ TEST(InlineOmitArgumentsDeopt) { TEST(InlineSurplusArguments) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -197,7 +204,6 @@ TEST(InlineSurplusArguments) { TEST(InlineSurplusArgumentsDeopt) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);" @@ -217,7 +223,6 @@ TEST(InlineSurplusArgumentsDeopt) { TEST(InlineTwice) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -232,7 +237,6 @@ TEST(InlineTwice) { TEST(InlineTwiceDependent) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -248,7 +252,6 @@ TEST(InlineTwiceDependent) { TEST(InlineTwiceDependentDiamond) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 41;" @@ -265,7 +268,6 @@ TEST(InlineTwiceDependentDiamond) { TEST(InlineTwiceDependentDiamondDifferent) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 41;" @@ -282,7 +284,6 @@ TEST(InlineTwiceDependentDiamondDifferent) { TEST(InlineLoopGuardedEmpty) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };" @@ -297,7 +298,6 @@ TEST(InlineLoopGuardedEmpty) { TEST(InlineLoopGuardedOnce) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {" @@ -313,7 +313,6 @@ TEST(InlineLoopGuardedOnce) { TEST(InlineLoopGuardedTwice) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {" @@ -329,7 +328,6 @@ TEST(InlineLoopGuardedTwice) { TEST(InlineLoopUnguardedEmpty) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); while (s); return s; };" @@ -344,7 +342,6 @@ TEST(InlineLoopUnguardedEmpty) { TEST(InlineLoopUnguardedOnce) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); while (s) {" @@ -360,7 +357,6 @@ TEST(InlineLoopUnguardedOnce) { TEST(InlineLoopUnguardedTwice) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s) { AssertInlineCount(2); while (s > 0) {" @@ -376,7 +372,6 @@ TEST(InlineLoopUnguardedTwice) { TEST(InlineStrictIntoNonStrict) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = Object.create({}, { y: { value:42, writable:false } });" @@ -393,7 +388,6 @@ TEST(InlineStrictIntoNonStrict) { TEST(InlineNonStrictIntoStrict) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = Object.create({}, { y: { value:42, writable:false } });" @@ -409,7 +403,6 @@ TEST(InlineNonStrictIntoStrict) { TEST(InlineIntrinsicIsSmi) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -424,7 +417,6 @@ TEST(InlineIntrinsicIsSmi) { TEST(InlineIntrinsicIsNonNegativeSmi) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = 42;" @@ -439,7 +431,6 @@ TEST(InlineIntrinsicIsNonNegativeSmi) { TEST(InlineIntrinsicIsArray) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " var x = [1,2,3];" @@ -474,7 +465,6 @@ TEST(InlineIntrinsicIsArray) { TEST(InlineWithArguments) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t,u) { AssertInlineCount(2);" @@ -494,15 +484,14 @@ TEST(InlineWithArguments) { TEST(InlineBuiltin) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t,u) { AssertInlineCount(2); return true; }" " function bar() { return foo(); };" - " %SetInlineBuiltinFlag(foo);" + " %SetForceInlineFlag(foo);" " return bar;" "})();", - kBuiltinInlineFlags); + kRestrictedInliningFlags); InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.true_value()); @@ -510,20 +499,80 @@ TEST(InlineBuiltin) { TEST(InlineNestedBuiltin) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function () {" " function foo(s,t,u) { AssertInlineCount(3); return true; }" " function baz(s,t,u) { return foo(s,t,u); }" " function bar() { return baz(); };" - " %SetInlineBuiltinFlag(foo);" - " %SetInlineBuiltinFlag(baz);" + " %SetForceInlineFlag(foo);" + " %SetForceInlineFlag(baz);" " return bar;" "})();", - kBuiltinInlineFlags); + kRestrictedInliningFlags); InstallAssertInlineCountHelper(CcTest::isolate()); T.CheckCall(T.true_value()); } + +TEST(StrongModeArity) { + FLAG_strong_mode = true; + FunctionTester T( + "(function () {" + " function foo(x, y) { 'use strong'; return x; }" + " function bar(x, y) { return foo(x); }" + " return bar;" + "})();", + kInlineFlags); + T.CheckThrows(T.undefined(), T.undefined()); +} + + +TEST(StrongModeArityOuter) { + FLAG_strong_mode = true; + FunctionTester T( + "(function () {" + " 'use strong';" + " function foo(x, y) { return x; }" + " function bar(x, y) { return foo(x); }" + " return bar;" + "})();", + kInlineFlags); + T.CheckThrows(T.undefined(), T.undefined()); +} + + +TEST(InlineSelfRecursive) { + FunctionTester T( + "(function () {" + " function foo(x) { " + " AssertInlineCount(1);" + " if (x == 1) return foo(12);" + " return x;" + " }" + " return foo;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(12), T.Val(1)); +} + + +TEST(InlineMutuallyRecursive) { + FunctionTester T( + "(function () {" + " function bar(x) { AssertInlineCount(2); return foo(x); }" + " function foo(x) { " + " if (x == 1) return bar(42);" + " return x;" + " }" + " return foo;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(42), T.Val(1)); +} + #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc index 7fc5cc9758..1fa37748c6 100644 --- a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc +++ b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc @@ -12,7 +12,6 @@ uint32_t flags = CompilationInfo::kInliningEnabled; TEST(CallFunction) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })", flags); CompileRun("function f(a,b,c) { return a + b + c + this.d; }"); @@ -23,7 +22,6 @@ TEST(CallFunction) { TEST(ClassOf) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_ClassOf(a); })", flags); T.CheckCall(T.Val("Function"), T.NewObject("(function() {})")); @@ -38,7 +36,6 @@ TEST(ClassOf) { TEST(HeapObjectGetMap) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_HeapObjectGetMap(a); })", flags); Factory* factory = T.main_isolate()->factory(); @@ -58,7 +55,6 @@ static int* LookupCounter(const char* name) { TEST(IncrementStatsCounter) { - FLAG_turbo_deoptimization = true; FLAG_native_code_counters = true; reinterpret_cast<v8::Isolate*>(CcTest::InitIsolateOnce()) ->SetCounterFunction(LookupCounter); @@ -76,9 +72,9 @@ TEST(IncrementStatsCounter) { TEST(IsArray) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsArray(a); })", flags); + T.CheckFalse(T.NewObject("new Date()")); T.CheckFalse(T.NewObject("(function() {})")); T.CheckTrue(T.NewObject("([1])")); T.CheckFalse(T.NewObject("({})")); @@ -90,10 +86,25 @@ TEST(IsArray) { } +TEST(IsDate) { + FunctionTester T("(function(a) { return %_IsDate(a); })", flags); + + T.CheckTrue(T.NewObject("new Date()")); + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckFalse(T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})")); + T.CheckFalse(T.NewObject("(/x/)")); + T.CheckFalse(T.undefined()); + T.CheckFalse(T.null()); + T.CheckFalse(T.Val("x")); + T.CheckFalse(T.Val(1)); +} + + TEST(IsFunction) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsFunction(a); })", flags); + T.CheckFalse(T.NewObject("new Date()")); T.CheckTrue(T.NewObject("(function() {})")); T.CheckFalse(T.NewObject("([1])")); T.CheckFalse(T.NewObject("({})")); @@ -106,7 +117,6 @@ TEST(IsFunction) { TEST(IsMinusZero) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags); T.CheckFalse(T.Val(1)); @@ -119,7 +129,6 @@ TEST(IsMinusZero) { TEST(IsNonNegativeSmi) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags); T.CheckTrue(T.Val(1)); @@ -132,7 +141,6 @@ TEST(IsNonNegativeSmi) { TEST(IsObject) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsObject(a); })", flags); T.CheckFalse(T.NewObject("(function() {})")); @@ -147,9 +155,9 @@ TEST(IsObject) { TEST(IsRegExp) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags); + T.CheckFalse(T.NewObject("new Date()")); T.CheckFalse(T.NewObject("(function() {})")); T.CheckFalse(T.NewObject("([1])")); T.CheckFalse(T.NewObject("({})")); @@ -162,20 +170,23 @@ TEST(IsRegExp) { TEST(IsSmi) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_IsSmi(a); })", flags); + T.CheckFalse(T.NewObject("new Date()")); + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckFalse(T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})")); + T.CheckFalse(T.NewObject("(/x/)")); + T.CheckFalse(T.undefined()); T.CheckTrue(T.Val(1)); T.CheckFalse(T.Val(1.1)); T.CheckFalse(T.Val(-0.0)); T.CheckTrue(T.Val(-2)); T.CheckFalse(T.Val(-2.3)); - T.CheckFalse(T.undefined()); } TEST(MapGetInstanceType) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function(a) { return %_MapGetInstanceType(%_HeapObjectGetMap(a)); })", flags); @@ -189,7 +200,6 @@ TEST(MapGetInstanceType) { TEST(ObjectEquals) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags); CompileRun("var o = {}"); @@ -203,7 +213,6 @@ TEST(ObjectEquals) { TEST(OneByteSeqStringGetChar) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_OneByteSeqStringGetChar(a,b); })", flags); @@ -219,7 +228,6 @@ TEST(OneByteSeqStringGetChar) { TEST(OneByteSeqStringSetChar) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { %_OneByteSeqStringSetChar(a,88,b); })", flags); @@ -236,7 +244,6 @@ TEST(OneByteSeqStringSetChar) { TEST(NewConsString) { - FLAG_turbo_deoptimization = true; FunctionTester T( "(function() { " " return %_NewConsString(14, true, 'abcdefghi', 'jklmn');" @@ -248,7 +255,6 @@ TEST(NewConsString) { TEST(SetValueOf) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags); T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a")); @@ -258,7 +264,6 @@ TEST(SetValueOf) { TEST(StringAdd) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags); T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb")); @@ -268,7 +273,6 @@ TEST(StringAdd) { TEST(StringCharAt) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags); T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3)); @@ -278,7 +282,6 @@ TEST(StringCharAt) { TEST(StringCharCodeAt) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })", flags); @@ -289,7 +292,6 @@ TEST(StringCharCodeAt) { TEST(StringCharFromCode) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags); T.CheckCall(T.Val("a"), T.Val(97)); @@ -299,7 +301,6 @@ TEST(StringCharFromCode) { TEST(StringCompare) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags); T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb")); @@ -309,7 +310,6 @@ TEST(StringCompare) { TEST(SubString) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags); T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0)); @@ -319,7 +319,6 @@ TEST(SubString) { TEST(TwoByteSeqStringGetChar) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_TwoByteSeqStringGetChar(a,b); })", flags); @@ -335,7 +334,6 @@ TEST(TwoByteSeqStringGetChar) { TEST(TwoByteSeqStringSetChar) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { %_TwoByteSeqStringSetChar(a,88,b); })", flags); @@ -352,7 +350,6 @@ TEST(TwoByteSeqStringSetChar) { TEST(ValueOf) { - FLAG_turbo_deoptimization = true; FunctionTester T("(function(a) { return %_ValueOf(a); })", flags); T.CheckCall(T.Val("a"), T.Val("a")); diff --git a/deps/v8/test/cctest/compiler/test-run-jscalls.cc b/deps/v8/test/cctest/compiler/test-run-jscalls.cc index a622af8995..8de2d7a214 100644 --- a/deps/v8/test/cctest/compiler/test-run-jscalls.cc +++ b/deps/v8/test/cctest/compiler/test-run-jscalls.cc @@ -242,6 +242,7 @@ TEST(ContextLoadedFromActivation) { i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value); i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun); jsfun->set_code(T.function->code()); + jsfun->set_shared(T.function->shared()); context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun)); CompileRun("var x = 24;"); ExpectInt32("foo();", 24); @@ -263,6 +264,7 @@ TEST(BuiltinLoadedFromActivation) { i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value); i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun); jsfun->set_code(T.function->code()); + jsfun->set_shared(T.function->shared()); context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun)); CompileRun("var x = 24;"); ExpectObject("foo()", context->Global()); diff --git a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc index 2e2e10e9de..0e1977b720 100644 --- a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc +++ b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc @@ -10,19 +10,14 @@ using namespace v8::internal; using namespace v8::internal::compiler; TEST(Throw) { - i::FLAG_turbo_exceptions = true; FunctionTester T("(function(a,b) { if (a) { throw b; } else { return b; }})"); -// TODO(mstarzinger) -#if 0 T.CheckThrows(T.true_value(), T.NewObject("new Error")); -#endif T.CheckCall(T.Val(23), T.false_value(), T.Val(23)); } TEST(ThrowMessagePosition) { - i::FLAG_turbo_exceptions = true; static const char* src = "(function(a, b) { \n" " if (a == 1) throw 1; \n" @@ -48,7 +43,6 @@ TEST(ThrowMessagePosition) { TEST(ThrowMessageDirectly) { - i::FLAG_turbo_exceptions = true; static const char* src = "(function(a, b) {" " if (a) { throw b; } else { throw new Error(b); }" @@ -56,19 +50,17 @@ TEST(ThrowMessageDirectly) { FunctionTester T(src); v8::Handle<v8::Message> message; -// TODO(mstarzinger) -#if 0 message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?")); CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?"))); message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!")); CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!"))); -#endif } TEST(ThrowMessageIndirectly) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_catch = true; + i::FLAG_turbo_try_finally = true; static const char* src = "(function(a, b) {" " try {" @@ -80,23 +72,16 @@ TEST(ThrowMessageIndirectly) { FunctionTester T(src); v8::Handle<v8::Message> message; -// TODO(mstarzinger) -#if 0 message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?")); CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?"))); message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!")); CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!"))); -#endif } -// TODO(mstarzinger): Increase test coverage by having similar tests within the -// mjsunit suite to also test integration with other components (e.g. OSR). - - TEST(Catch) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -115,7 +100,7 @@ TEST(Catch) { TEST(CatchNested) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -139,7 +124,7 @@ TEST(CatchNested) { TEST(CatchBreak) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -164,7 +149,7 @@ TEST(CatchBreak) { TEST(CatchCall) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function(fun) {" " var r = '-';" @@ -186,7 +171,7 @@ TEST(CatchCall) { TEST(Finally) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_finally = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -204,7 +189,7 @@ TEST(Finally) { TEST(FinallyBreak) { - i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_try_finally = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -228,8 +213,7 @@ TEST(FinallyBreak) { TEST(DeoptTry) { - i::FLAG_turbo_exceptions = true; - i::FLAG_turbo_deoptimization = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function f(a) {" " try {" @@ -246,8 +230,7 @@ TEST(DeoptTry) { TEST(DeoptCatch) { - i::FLAG_turbo_exceptions = true; - i::FLAG_turbo_deoptimization = true; + i::FLAG_turbo_try_catch = true; const char* src = "(function f(a) {" " try {" @@ -264,8 +247,7 @@ TEST(DeoptCatch) { TEST(DeoptFinallyReturn) { - i::FLAG_turbo_exceptions = true; - i::FLAG_turbo_deoptimization = true; + i::FLAG_turbo_try_finally = true; const char* src = "(function f(a) {" " try {" @@ -282,8 +264,7 @@ TEST(DeoptFinallyReturn) { TEST(DeoptFinallyReThrow) { - i::FLAG_turbo_exceptions = true; - i::FLAG_turbo_deoptimization = true; + i::FLAG_turbo_try_finally = true; const char* src = "(function f(a) {" " try {" diff --git a/deps/v8/test/cctest/compiler/test-run-jsops.cc b/deps/v8/test/cctest/compiler/test-run-jsops.cc index 032db82db3..56ac31cbc9 100644 --- a/deps/v8/test/cctest/compiler/test-run-jsops.cc +++ b/deps/v8/test/cctest/compiler/test-run-jsops.cc @@ -523,9 +523,7 @@ TEST(RegExpLiteral) { TEST(ClassLiteral) { - FLAG_harmony_classes = true; FLAG_harmony_sloppy = true; - FLAG_harmony_object_literals = true; const char* src = "(function(a,b) {" " class C {" diff --git a/deps/v8/test/cctest/compiler/test-run-machops.cc b/deps/v8/test/cctest/compiler/test-run-machops.cc index 8d051bc90b..b1fc36968f 100644 --- a/deps/v8/test/cctest/compiler/test-run-machops.cc +++ b/deps/v8/test/cctest/compiler/test-run-machops.cc @@ -82,6 +82,63 @@ TEST(CodeGenInt32Binop) { } +#if V8_TURBOFAN_BACKEND_64 +static Node* Int64Input(RawMachineAssemblerTester<int64_t>* m, int index) { + switch (index) { + case 0: + return m->Parameter(0); + case 1: + return m->Parameter(1); + case 2: + return m->Int64Constant(0); + case 3: + return m->Int64Constant(1); + case 4: + return m->Int64Constant(-1); + case 5: + return m->Int64Constant(0xff); + case 6: + return m->Int64Constant(0x0123456789abcdefLL); + case 7: + return m->Load(kMachInt64, m->PointerConstant(NULL)); + default: + return NULL; + } +} + + +TEST(CodeGenInt64Binop) { + RawMachineAssemblerTester<void> m; + + const Operator* kOps[] = { + m.machine()->Word64And(), m.machine()->Word64Or(), + m.machine()->Word64Xor(), m.machine()->Word64Shl(), + m.machine()->Word64Shr(), m.machine()->Word64Sar(), + m.machine()->Word64Equal(), m.machine()->Int64Add(), + m.machine()->Int64Sub(), m.machine()->Int64Mul(), m.machine()->Int64Div(), + m.machine()->Uint64Div(), m.machine()->Int64Mod(), + m.machine()->Uint64Mod(), m.machine()->Int64LessThan(), + m.machine()->Int64LessThanOrEqual(), m.machine()->Uint64LessThan(), + m.machine()->Uint64LessThanOrEqual()}; + + for (size_t i = 0; i < arraysize(kOps); ++i) { + for (int j = 0; j < 8; j++) { + for (int k = 0; k < 8; k++) { + RawMachineAssemblerTester<int64_t> m(kMachInt64, kMachInt64); + Node* a = Int64Input(&m, j); + Node* b = Int64Input(&m, k); + m.Return(m.NewNode(kOps[i], a, b)); + m.GenerateCode(); + } + } + } +} + + +// TODO(titzer): add tests that run 64-bit integer operations. +#endif // V8_TURBOFAN_BACKEND_64 + + TEST(RunGoto) { RawMachineAssemblerTester<int32_t> m; int constant = 99999; @@ -164,15 +221,14 @@ template <typename R> static void BuildDiamondPhi(RawMachineAssemblerTester<R>* m, Node* cond_node, MachineType type, Node* true_node, Node* false_node) { - MLabel blocka, blockb; - MLabel* end = m->Exit(); + MLabel blocka, blockb, end; m->Branch(cond_node, &blocka, &blockb); m->Bind(&blocka); - m->Goto(end); + m->Goto(&end); m->Bind(&blockb); - m->Goto(end); + m->Goto(&end); - m->Bind(end); + m->Bind(&end); Node* phi = m->Phi(type, true_node, false_node); m->Return(phi); } @@ -237,16 +293,15 @@ TEST(RunLoopPhiConst) { Node* false_node = m.Int32Constant(false_val); // x = false_val; while(false) { x = true_val; } return x; - MLabel body, header; - MLabel* end = m.Exit(); + MLabel body, header, end; m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, false_node, true_node); - m.Branch(cond_node, &body, end); + m.Branch(cond_node, &body, &end); m.Bind(&body); m.Goto(&header); - m.Bind(end); + m.Bind(&end); m.Return(phi); CHECK_EQ(false_val, m.Call()); @@ -256,20 +311,19 @@ TEST(RunLoopPhiConst) { TEST(RunLoopPhiParam) { RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32); - MLabel blocka, blockb; - MLabel* end = m.Exit(); + MLabel blocka, blockb, end; m.Goto(&blocka); m.Bind(&blocka); Node* phi = m.Phi(kMachInt32, m.Parameter(1), m.Parameter(2)); Node* cond = m.Phi(kMachInt32, m.Parameter(0), m.Int32Constant(0)); - m.Branch(cond, &blockb, end); + m.Branch(cond, &blockb, &end); m.Bind(&blockb); m.Goto(&blocka); - m.Bind(end); + m.Bind(&end); m.Return(phi); int32_t c1 = 0xa81903b4; @@ -287,22 +341,21 @@ TEST(RunLoopPhiInduction) { int false_val = 0x10777; // x = false_val; while(false) { x++; } return x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* false_node = m.Int32Constant(false_val); m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, false_node, false_node); - m.Branch(m.Int32Constant(0), &body, end); + m.Branch(m.Int32Constant(0), &body, &end); m.Bind(&body); Node* add = m.Int32Add(phi, m.Int32Constant(1)); phi->ReplaceInput(1, add); m.Goto(&header); - m.Bind(end); + m.Bind(&end); m.Return(phi); CHECK_EQ(false_val, m.Call()); @@ -314,21 +367,20 @@ TEST(RunLoopIncrement) { Int32BinopTester bt(&m); // x = 0; while(x ^ param) { x++; } return x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* zero = m.Int32Constant(0); m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, zero, zero); - m.Branch(m.WordXor(phi, bt.param0), &body, end); + m.Branch(m.WordXor(phi, bt.param0), &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); bt.AddReturn(phi); CHECK_EQ(11, bt.call(11, 0)); @@ -342,21 +394,20 @@ TEST(RunLoopIncrement2) { Int32BinopTester bt(&m); // x = 0; while(x < param) { x++; } return x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* zero = m.Int32Constant(0); m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, zero, zero); - m.Branch(m.Int32LessThan(phi, bt.param0), &body, end); + m.Branch(m.Int32LessThan(phi, bt.param0), &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); bt.AddReturn(phi); CHECK_EQ(11, bt.call(11, 0)); @@ -371,21 +422,20 @@ TEST(RunLoopIncrement3) { Int32BinopTester bt(&m); // x = 0; while(x < param) { x++; } return x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* zero = m.Int32Constant(0); m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, zero, zero); - m.Branch(m.Uint32LessThan(phi, bt.param0), &body, end); + m.Branch(m.Uint32LessThan(phi, bt.param0), &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Int32Add(phi, m.Int32Constant(1))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); bt.AddReturn(phi); CHECK_EQ(11, bt.call(11, 0)); @@ -400,20 +450,19 @@ TEST(RunLoopDecrement) { Int32BinopTester bt(&m); // x = param; while(x) { x--; } return x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; m.Goto(&header); m.Bind(&header); Node* phi = m.Phi(kMachInt32, bt.param0, m.Int32Constant(0)); - m.Branch(phi, &body, end); + m.Branch(phi, &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Int32Sub(phi, m.Int32Constant(1))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); bt.AddReturn(phi); CHECK_EQ(0, bt.call(11, 0)); @@ -426,8 +475,7 @@ TEST(RunLoopIncrementFloat32) { RawMachineAssemblerTester<int32_t> m; // x = -3.0f; while(x < 10f) { x = x + 0.5f; } return (int) (double) x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* minus_3 = m.Float32Constant(-3.0f); Node* ten = m.Float32Constant(10.0f); @@ -435,13 +483,13 @@ TEST(RunLoopIncrementFloat32) { m.Bind(&header); Node* phi = m.Phi(kMachFloat32, minus_3, ten); - m.Branch(m.Float32LessThan(phi, ten), &body, end); + m.Branch(m.Float32LessThan(phi, ten), &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Float32Add(phi, m.Float32Constant(0.5f))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); m.Return(m.ChangeFloat64ToInt32(m.ChangeFloat32ToFloat64(phi))); CHECK_EQ(10, m.Call()); @@ -452,8 +500,7 @@ TEST(RunLoopIncrementFloat64) { RawMachineAssemblerTester<int32_t> m; // x = -3.0; while(x < 10) { x = x + 0.5; } return (int) x; - MLabel header, body; - MLabel* end = m.Exit(); + MLabel header, body, end; Node* minus_3 = m.Float64Constant(-3.0); Node* ten = m.Float64Constant(10.0); @@ -461,13 +508,13 @@ TEST(RunLoopIncrementFloat64) { m.Bind(&header); Node* phi = m.Phi(kMachFloat64, minus_3, ten); - m.Branch(m.Float64LessThan(phi, ten), &body, end); + m.Branch(m.Float64LessThan(phi, ten), &body, &end); m.Bind(&body); phi->ReplaceInput(1, m.Float64Add(phi, m.Float64Constant(0.5))); m.Goto(&header); - m.Bind(end); + m.Bind(&end); m.Return(m.ChangeFloat64ToInt32(phi)); CHECK_EQ(10, m.Call()); @@ -4395,7 +4442,7 @@ TEST(RunTestIntPtrArithmetic) { RawMachineAssemblerTester<int32_t*> m; Node* input = m.PointerConstant(&inputs[0]); Node* output = m.PointerConstant(&outputs[kInputSize - 1]); - Node* elem_size = m.ConvertInt32ToIntPtr(m.Int32Constant(sizeof(inputs[0]))); + Node* elem_size = m.IntPtrConstant(sizeof(inputs[0])); for (int i = 0; i < kInputSize; i++) { m.Store(kMachInt32, output, m.Load(kMachInt32, input)); input = m.IntPtrAdd(input, elem_size); @@ -4412,7 +4459,7 @@ TEST(RunTestIntPtrArithmetic) { TEST(RunSpillLotsOfThings) { static const int kInputSize = 1000; - RawMachineAssemblerTester<void> m; + RawMachineAssemblerTester<int32_t> m; Node* accs[kInputSize]; int32_t outputs[kInputSize]; Node* one = m.Int32Constant(1); @@ -4793,7 +4840,8 @@ TEST(RunTruncateFloat64ToInt32P) { {-1.7976931348623157e+308, 0}}; double input = -1.0; RawMachineAssemblerTester<int32_t> m; - m.Return(m.TruncateFloat64ToInt32(m.LoadFromPointer(&input, kMachFloat64))); + m.Return(m.TruncateFloat64ToInt32(TruncationMode::kJavaScript, + m.LoadFromPointer(&input, kMachFloat64))); for (size_t i = 0; i < arraysize(kValues); ++i) { input = kValues[i].from; uint64_t expected = static_cast<int64_t>(kValues[i].raw); @@ -5080,7 +5128,7 @@ TEST(RunFloat64RoundDown1) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64RoundDown()) return; + if (!m.machine()->Float64RoundDown().IsSupported()) return; m.StoreToPointer(&result, kMachFloat64, m.Float64RoundDown(m.LoadFromPointer(&input, kMachFloat64))); m.Return(m.Int32Constant(0)); @@ -5097,7 +5145,7 @@ TEST(RunFloat64RoundDown2) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64RoundDown()) return; + if (!m.machine()->Float64RoundDown().IsSupported()) return; m.StoreToPointer(&result, kMachFloat64, m.Float64Sub(m.Float64Constant(-0.0), m.Float64RoundDown(m.Float64Sub( @@ -5117,7 +5165,7 @@ TEST(RunFloat64RoundTruncate) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64RoundTruncate()) return; + if (!m.machine()->Float64RoundTruncate().IsSupported()) return; m.StoreToPointer( &result, kMachFloat64, m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64))); @@ -5135,7 +5183,7 @@ TEST(RunFloat64RoundTiesAway) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64RoundTiesAway()) return; + if (!m.machine()->Float64RoundTiesAway().IsSupported()) return; m.StoreToPointer( &result, kMachFloat64, m.Float64RoundTiesAway(m.LoadFromPointer(&input, kMachFloat64))); @@ -5148,4 +5196,83 @@ TEST(RunFloat64RoundTiesAway) { } } + +#if !USE_SIMULATOR + +namespace { + +int32_t const kMagicFoo0 = 0xdeadbeef; + + +int32_t foo0() { return kMagicFoo0; } + + +int32_t foo1(int32_t x) { return x; } + + +int32_t foo2(int32_t x, int32_t y) { return x - y; } + + +int32_t foo8(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f, + int32_t g, int32_t h) { + return a + b + c + d + e + f + g + h; +} + +} // namespace + + +TEST(RunCallCFunction0) { + auto* foo0_ptr = &foo0; + RawMachineAssemblerTester<int32_t> m; + Node* function = m.LoadFromPointer(&foo0_ptr, kMachPtr); + m.Return(m.CallCFunction0(kMachInt32, function)); + CHECK_EQ(kMagicFoo0, m.Call()); +} + + +TEST(RunCallCFunction1) { + auto* foo1_ptr = &foo1; + RawMachineAssemblerTester<int32_t> m(kMachInt32); + Node* function = m.LoadFromPointer(&foo1_ptr, kMachPtr); + m.Return(m.CallCFunction1(kMachInt32, kMachInt32, function, m.Parameter(0))); + FOR_INT32_INPUTS(i) { + int32_t const expected = *i; + CHECK_EQ(expected, m.Call(expected)); + } +} + + +TEST(RunCallCFunction2) { + auto* foo2_ptr = &foo2; + RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32); + Node* function = m.LoadFromPointer(&foo2_ptr, kMachPtr); + m.Return(m.CallCFunction2(kMachInt32, kMachInt32, kMachInt32, function, + m.Parameter(0), m.Parameter(1))); + FOR_INT32_INPUTS(i) { + int32_t const x = *i; + FOR_INT32_INPUTS(j) { + int32_t const y = *j; + CHECK_EQ(x - y, m.Call(x, y)); + } + } +} + + +TEST(RunCallCFunction8) { + auto* foo8_ptr = &foo8; + RawMachineAssemblerTester<int32_t> m(kMachInt32); + Node* function = m.LoadFromPointer(&foo8_ptr, kMachPtr); + Node* param = m.Parameter(0); + m.Return(m.CallCFunction8(kMachInt32, kMachInt32, kMachInt32, kMachInt32, + kMachInt32, kMachInt32, kMachInt32, kMachInt32, + kMachInt32, function, param, param, param, param, + param, param, param, param)); + FOR_INT32_INPUTS(i) { + int32_t const x = *i; + CHECK_EQ(x * 8, m.Call(x)); + } +} + +#endif // USE_SIMULATOR + #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-stubs.cc b/deps/v8/test/cctest/compiler/test-run-stubs.cc index c81f0f184d..9c7998d7af 100644 --- a/deps/v8/test/cctest/compiler/test-run-stubs.cc +++ b/deps/v8/test/cctest/compiler/test-run-stubs.cc @@ -6,7 +6,10 @@ #include "src/code-stubs.h" #include "src/compiler/common-operator.h" #include "src/compiler/graph.h" +#include "src/compiler/js-graph.h" +#include "src/compiler/js-operator.h" #include "src/compiler/linkage.h" +#include "src/compiler/machine-operator.h" #include "src/compiler/pipeline.h" #include "src/parser.h" #include "test/cctest/compiler/function-tester.h" @@ -17,60 +20,54 @@ using namespace v8::internal; using namespace v8::internal::compiler; -static Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) { - v8::ExtensionConfiguration no_extensions; - Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment( - MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(), - &no_extensions); - Handle<JSBuiltinsObject> builtins = handle(ctx->builtins()); - MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name); - Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked()); - // Just to make sure nobody calls this... - function->set_code(isolate->builtins()->builtin(Builtins::kIllegal)); - return function; -} - - -class StringLengthStubTF : public CodeStub { - public: - explicit StringLengthStubTF(Isolate* isolate) : CodeStub(isolate) {} +TEST(RunMathFloorStub) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); - StringLengthStubTF(uint32_t key, Isolate* isolate) : CodeStub(key, isolate) {} + // Create code and an accompanying descriptor. + MathFloorStub stub(isolate); + Handle<Code> code = stub.GenerateCode(); + Zone* zone = scope.main_zone(); - CallInterfaceDescriptor GetCallInterfaceDescriptor() override { - return LoadDescriptor(isolate()); - }; + CompilationInfo info(&stub, isolate, zone); + CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); - Handle<Code> GenerateCode() override { - Zone zone; - // Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair. - ParseInfo parse_info(&zone, GetFunction(isolate(), "STRING_LENGTH_STUB")); - CompilationInfo info(&parse_info); - info.SetStub(this); - // Run a "mini pipeline", extracted from compiler.cc. - CHECK(Parser::ParseStatic(info.parse_info())); - CHECK(Compiler::Analyze(info.parse_info())); - return Pipeline(&info).GenerateCode(); - } + // Create a function to call the code using the descriptor. + Graph graph(zone); + CommonOperatorBuilder common(zone); + JSOperatorBuilder javascript(zone); + MachineOperatorBuilder machine(zone); + JSGraph js(isolate, &graph, &common, &javascript, &machine); - Major MajorKey() const override { return StringLength; }; - Code::Kind GetCodeKind() const override { return Code::HANDLER; } - InlineCacheState GetICState() const override { return MONOMORPHIC; } - ExtraICState GetExtraICState() const override { return Code::LOAD_IC; } - Code::StubType GetStubType() const override { return Code::FAST; } + // FunctionTester (ab)uses a 2-argument function + Node* start = graph.NewNode(common.Start(4)); + // Parameter 0 is the number to round + Node* numberParam = graph.NewNode(common.Parameter(1), start); + Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code); + Node* theCode = graph.NewNode(common.HeapConstant(u)); + Node* dummyContext = graph.NewNode(common.NumberConstant(0.0)); + Node* call = graph.NewNode(common.Call(descriptor), theCode, + js.UndefinedConstant(), js.UndefinedConstant(), + numberParam, dummyContext, start, start); + Node* ret = graph.NewNode(common.Return(), call, call, start); + Node* end = graph.NewNode(common.End(1), ret); + graph.SetStart(start); + graph.SetEnd(end); + FunctionTester ft(&graph); - private: - DISALLOW_COPY_AND_ASSIGN(StringLengthStubTF); -}; + Handle<Object> value = ft.Val(1.5); + Handle<Object> result = ft.Call(value, value).ToHandleChecked(); + CHECK_EQ(1, Smi::cast(*result)->value()); +} -TEST(RunStringLengthStubTF) { +TEST(RunStringLengthTFStub) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); // Create code and an accompanying descriptor. - StringLengthStubTF stub(isolate); + StringLengthTFStub stub(isolate); Handle<Code> code = stub.GenerateCode(); CompilationInfo info(&stub, isolate, zone); CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); @@ -78,18 +75,21 @@ TEST(RunStringLengthStubTF) { // Create a function to call the code using the descriptor. Graph graph(zone); CommonOperatorBuilder common(zone); - // FunctionTester (ab)uses a 2-argument function - Node* start = graph.NewNode(common.Start(2)); + // FunctionTester (ab)uses a 4-argument function + Node* start = graph.NewNode(common.Start(6)); // Parameter 0 is the receiver Node* receiverParam = graph.NewNode(common.Parameter(1), start); Node* nameParam = graph.NewNode(common.Parameter(2), start); + Node* slotParam = graph.NewNode(common.Parameter(3), start); + Node* vectorParam = graph.NewNode(common.Parameter(4), start); Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code); Node* theCode = graph.NewNode(common.HeapConstant(u)); Node* dummyContext = graph.NewNode(common.NumberConstant(0.0)); - Node* call = graph.NewNode(common.Call(descriptor), theCode, receiverParam, - nameParam, dummyContext, start, start); + Node* call = + graph.NewNode(common.Call(descriptor), theCode, receiverParam, nameParam, + slotParam, vectorParam, dummyContext, start, start); Node* ret = graph.NewNode(common.Return(), call, call, start); - Node* end = graph.NewNode(common.End(), ret); + Node* end = graph.NewNode(common.End(1), ret); graph.SetStart(start); graph.SetEnd(end); FunctionTester ft(&graph); @@ -99,8 +99,49 @@ TEST(RunStringLengthStubTF) { Handle<JSReceiver> receiverArg = Object::ToObject(isolate, ft.Val(testString)).ToHandleChecked(); Handle<String> nameArg = ft.Val("length"); - Handle<Object> result = ft.Call(receiverArg, nameArg).ToHandleChecked(); + Handle<Object> slot = ft.Val(0.0); + Handle<Object> vector = ft.Val(0.0); + Handle<Object> result = + ft.Call(receiverArg, nameArg, slot, vector).ToHandleChecked(); CHECK_EQ(static_cast<int>(strlen(testString)), Smi::cast(*result)->value()); } + +TEST(RunStringAddTFStub) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + // Create code and an accompanying descriptor. + StringAddTFStub stub(isolate, STRING_ADD_CHECK_BOTH, NOT_TENURED); + Handle<Code> code = stub.GenerateCode(); + CompilationInfo info(&stub, isolate, zone); + CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); + + // Create a function to call the code using the descriptor. + Graph graph(zone); + CommonOperatorBuilder common(zone); + // FunctionTester (ab)uses a 2-argument function + Node* start = graph.NewNode(common.Start(4)); + // Parameter 0 is the receiver + Node* leftParam = graph.NewNode(common.Parameter(1), start); + Node* rightParam = graph.NewNode(common.Parameter(2), start); + Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code); + Node* theCode = graph.NewNode(common.HeapConstant(u)); + Node* dummyContext = graph.NewNode(common.NumberConstant(0.0)); + Node* call = graph.NewNode(common.Call(descriptor), theCode, leftParam, + rightParam, dummyContext, start, start); + Node* ret = graph.NewNode(common.Return(), call, call, start); + Node* end = graph.NewNode(common.End(1), ret); + graph.SetStart(start); + graph.SetEnd(end); + FunctionTester ft(&graph); + + // Actuall call through to the stub, verifying its result. + Handle<String> leftArg = ft.Val("links"); + Handle<String> rightArg = ft.Val("rechts"); + Handle<Object> result = ft.Call(leftArg, rightArg).ToHandleChecked(); + CHECK(String::Equals(ft.Val("linksrechts"), Handle<String>::cast(result))); +} + #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc index 9242248d60..022e01690b 100644 --- a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc @@ -33,12 +33,9 @@ template <typename ReturnType> class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> { public: SimplifiedLoweringTester(MachineType p0 = kMachNone, - MachineType p1 = kMachNone, - MachineType p2 = kMachNone, - MachineType p3 = kMachNone, - MachineType p4 = kMachNone) - : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4), - typer(this->isolate(), this->graph(), MaybeHandle<Context>()), + MachineType p1 = kMachNone) + : GraphBuilderTester<ReturnType>(p0, p1), + typer(this->isolate(), this->graph()), javascript(this->zone()), jsgraph(this->isolate(), this->graph(), this->common(), &javascript, this->machine()), @@ -63,7 +60,7 @@ class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> { lowering.LowerAllNodes(); ChangeLowering lowering(&jsgraph); - GraphReducer reducer(this->graph(), this->zone()); + GraphReducer reducer(this->zone(), this->graph()); reducer.AddReducer(&lowering); reducer.ReduceGraph(); Verifier::Run(this->graph()); @@ -538,8 +535,7 @@ class AccessTester : public HandleAndZoneScope { E GetElement(int index) { BoundsCheck(index); if (tagged) { - E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); - return raw[index]; + return GetTaggedElement(index); } else { return untagged_array[index]; } @@ -572,8 +568,19 @@ class AccessTester : public HandleAndZoneScope { CHECK_LT(index, static_cast<int>(num_elements)); CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length()); } + + E GetTaggedElement(int index) { + E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); + return raw[index]; + } }; +template <> +double AccessTester<double>::GetTaggedElement(int index) { + return ReadDoubleValue(tagged_array->GetDataStartAddress() + + index * sizeof(double)); +} + template <typename E> static void RunAccessTest(MachineType rep, E* original_elements, size_t num) { @@ -703,14 +710,14 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(), Type* p2_type = Type::None()) : GraphAndBuilders(main_zone()), - typer(main_isolate(), graph(), MaybeHandle<Context>()), + typer(main_isolate(), graph()), javascript(main_zone()), jsgraph(main_isolate(), graph(), common(), &javascript, machine()) { start = graph()->NewNode(common()->Start(2)); graph()->SetStart(start); ret = graph()->NewNode(common()->Return(), jsgraph.Constant(0), start, start); - end = graph()->NewNode(common()->End(), ret); + end = graph()->NewNode(common()->End(1), ret); graph()->SetEnd(end); p0 = graph()->NewNode(common()->Parameter(0), start); p1 = graph()->NewNode(common()->Parameter(1), start); @@ -1269,7 +1276,6 @@ TEST(LowerStringOps_to_call_and_compare) { t.CheckLoweringBinop(compare_eq, t.simplified()->StringEqual()); t.CheckLoweringBinop(compare_lt, t.simplified()->StringLessThan()); t.CheckLoweringBinop(compare_le, t.simplified()->StringLessThanOrEqual()); - t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringAdd()); } } @@ -1443,8 +1449,8 @@ TEST(LowerLoadField_to_load) { FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), Type::Any(), kMachineReps[i]}; - Node* load = - t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); + Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, + t.start, t.start); Node* use = t.Use(load, kMachineReps[i]); t.Return(use); t.Lower(); @@ -1624,8 +1630,8 @@ TEST(InsertChangeForLoadField) { FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), Type::Any(), kMachFloat64}; - Node* load = - t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); + Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, + t.start, t.start); t.Return(load); t.Lower(); CHECK_EQ(IrOpcode::kLoad, load->opcode()); @@ -1679,10 +1685,10 @@ TEST(UpdatePhi) { FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Handle<Name>::null(), kTypes[i], kMachineTypes[i]}; - Node* load0 = - t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); - Node* load1 = - t.graph()->NewNode(t.simplified()->LoadField(access), t.p1, t.start); + Node* load0 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, + t.start, t.start); + Node* load1 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p1, + t.start, t.start); Node* phi = t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), load0, load1, t.start); t.Return(t.Use(phi, kMachineTypes[i])); diff --git a/deps/v8/test/cctest/gay-fixed.cc b/deps/v8/test/cctest/gay-fixed.cc index 81463ac1fa..86ebb24cd8 100644 --- a/deps/v8/test/cctest/gay-fixed.cc +++ b/deps/v8/test/cctest/gay-fixed.cc @@ -100046,4 +100046,5 @@ Vector<const PrecomputedFixed> PrecomputedFixedRepresentations() { } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/gay-precision.cc b/deps/v8/test/cctest/gay-precision.cc index 6ab2715fea..68d29f8cd5 100644 --- a/deps/v8/test/cctest/gay-precision.cc +++ b/deps/v8/test/cctest/gay-precision.cc @@ -100047,4 +100047,5 @@ Vector<const PrecomputedPrecision> PrecomputedPrecisionRepresentations() { number_elements); } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/gay-shortest.cc b/deps/v8/test/cctest/gay-shortest.cc index 896ea4c514..456055392c 100644 --- a/deps/v8/test/cctest/gay-shortest.cc +++ b/deps/v8/test/cctest/gay-shortest.cc @@ -100047,4 +100047,5 @@ Vector<const PrecomputedShortest> PrecomputedShortestRepresentations() { number_elements); } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/print-extension.cc b/deps/v8/test/cctest/print-extension.cc index d1af3596e8..33f33cafc2 100644 --- a/deps/v8/test/cctest/print-extension.cc +++ b/deps/v8/test/cctest/print-extension.cc @@ -48,4 +48,5 @@ void PrintExtension::Print(const v8::FunctionCallbackInfo<v8::Value>& args) { printf("\n"); } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/profiler-extension.cc b/deps/v8/test/cctest/profiler-extension.cc index 263fc4f38d..c8cb0fb7ca 100644 --- a/deps/v8/test/cctest/profiler-extension.cc +++ b/deps/v8/test/cctest/profiler-extension.cc @@ -72,4 +72,5 @@ void ProfilerExtension::StopProfiling( : v8::String::Empty(args.GetIsolate())); } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index ac631757b2..14303e2371 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -552,7 +552,7 @@ THREADED_TEST(AccessorPropertyCrossContext) { v8::Handle<v8::Function> fun = v8::Function::New(isolate, check_contexts); LocalContext switch_context; switch_context->Global()->Set(v8_str("fun"), fun); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); expected_current_context = env.local(); expected_calling_context = switch_context.local(); CompileRun( diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc index aba08e23d7..2e9bc74a92 100644 --- a/deps/v8/test/cctest/test-api-interceptors.cc +++ b/deps/v8/test/cctest/test-api-interceptors.cc @@ -1007,10 +1007,11 @@ THREADED_TEST(PropertyHandlerInPrototype) { } +bool is_bootstrapping = false; static void PrePropertyHandlerGet( Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); - if (v8_str("pre")->Equals(key)) { + if (!is_bootstrapping && v8_str("pre")->Equals(key)) { info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre")); } } @@ -1018,7 +1019,7 @@ static void PrePropertyHandlerGet( static void PrePropertyHandlerQuery( Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) { - if (v8_str("pre")->Equals(key)) { + if (!is_bootstrapping && v8_str("pre")->Equals(key)) { info.GetReturnValue().Set(static_cast<int32_t>(v8::None)); } } @@ -1030,7 +1031,9 @@ THREADED_TEST(PrePropertyHandler) { v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration( PrePropertyHandlerGet, 0, PrePropertyHandlerQuery)); + is_bootstrapping = true; LocalContext env(NULL, desc->InstanceTemplate()); + is_bootstrapping = false; CompileRun("var pre = 'Object: pre'; var on = 'Object: on';"); v8::Handle<Value> result_pre = CompileRun("pre"); CHECK(v8_str("PrePropertyHandler: pre")->Equals(result_pre)); @@ -1658,6 +1661,12 @@ THREADED_TEST(IndexedInterceptorWithNoSetter) { } +static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { + return false; +} + + THREADED_TEST(IndexedInterceptorWithAccessorCheck) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); @@ -1665,9 +1674,10 @@ THREADED_TEST(IndexedInterceptorWithAccessorCheck) { templ->SetHandler( v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter)); + templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, nullptr); + LocalContext context; Local<v8::Object> obj = templ->NewInstance(); - obj->TurnOnAccessCheck(); context->Global()->Set(v8_str("obj"), obj); const char* code = @@ -1686,46 +1696,6 @@ THREADED_TEST(IndexedInterceptorWithAccessorCheck) { } -THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { - i::FLAG_allow_natives_syntax = true; - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetHandler( - v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter)); - - LocalContext context; - Local<v8::Object> obj = templ->NewInstance(); - context->Global()->Set(v8_str("obj"), obj); - - const char* code = - "var result = 'PASSED';" - "for (var i = 0; i < 100; i++) {" - " var expected = i;" - " if (i == 5) {" - " %EnableAccessChecks(obj);" - " }" - " try {" - " var v = obj[i];" - " if (i == 5) {" - " result = 'Should not have reached this!';" - " break;" - " } else if (v != expected) {" - " result = 'Wrong value ' + v + ' at iteration ' + i;" - " break;" - " }" - " } catch (e) {" - " if (i != 5) {" - " result = e;" - " }" - " }" - " if (i == 5) %DisableAccessChecks(obj);" - "}" - "result"; - ExpectString(code, "PASSED"); -} - - THREADED_TEST(IndexedInterceptorWithDifferentIndices) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); @@ -2021,9 +1991,9 @@ THREADED_TEST(Enumerators) { "k.a = 0;" "k[5] = 0;" "k.b = 0;" - "k[4294967295] = 0;" + "k[4294967294] = 0;" "k.c = 0;" - "k[4294967296] = 0;" + "k[4294967295] = 0;" "k.d = 0;" "k[140000] = 0;" "k.e = 0;" @@ -2046,7 +2016,7 @@ THREADED_TEST(Enumerators) { CHECK(v8_str("10")->Equals(result->Get(v8::Integer::New(isolate, 1)))); CHECK(v8_str("140000")->Equals(result->Get(v8::Integer::New(isolate, 2)))); CHECK( - v8_str("4294967295")->Equals(result->Get(v8::Integer::New(isolate, 3)))); + v8_str("4294967294")->Equals(result->Get(v8::Integer::New(isolate, 3)))); // Indexed interceptor properties in the order they are returned // from the enumerator interceptor. CHECK(v8_str("0")->Equals(result->Get(v8::Integer::New(isolate, 4)))); @@ -2056,7 +2026,7 @@ THREADED_TEST(Enumerators) { CHECK(v8_str("b")->Equals(result->Get(v8::Integer::New(isolate, 7)))); CHECK(v8_str("c")->Equals(result->Get(v8::Integer::New(isolate, 8)))); CHECK( - v8_str("4294967296")->Equals(result->Get(v8::Integer::New(isolate, 9)))); + v8_str("4294967295")->Equals(result->Get(v8::Integer::New(isolate, 9)))); CHECK(v8_str("d")->Equals(result->Get(v8::Integer::New(isolate, 10)))); CHECK(v8_str("e")->Equals(result->Get(v8::Integer::New(isolate, 11)))); CHECK(v8_str("30000000000") @@ -2533,7 +2503,8 @@ static int interceptor_call_count = 0; static void InterceptorICRefErrorGetter( Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); - if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { + if (!is_bootstrapping && v8_str("x")->Equals(name) && + interceptor_call_count++ < 20) { info.GetReturnValue().Set(call_ic_function2); } } @@ -2548,7 +2519,9 @@ THREADED_TEST(InterceptorICReferenceErrors) { v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); templ->SetHandler( v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter)); + is_bootstrapping = true; LocalContext context(0, templ, v8::Handle<Value>()); + is_bootstrapping = false; call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); v8::Handle<Value> value = CompileRun( "function f() {" @@ -2577,6 +2550,7 @@ static int interceptor_ic_exception_get_count = 0; static void InterceptorICExceptionGetter( Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); + if (is_bootstrapping) return; if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { info.GetReturnValue().Set(call_ic_function3); } @@ -2596,7 +2570,9 @@ THREADED_TEST(InterceptorICGetterExceptions) { v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); templ->SetHandler( v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter)); + is_bootstrapping = true; LocalContext context(0, templ, v8::Handle<Value>()); + is_bootstrapping = false; call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); v8::Handle<Value> value = CompileRun( "function f() {" @@ -2975,7 +2951,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) { LocalContext context; AccessCheckData access_check_data; - access_check_data.result = false; + access_check_data.result = true; access_check_data.count = 0; ShouldInterceptData intercept_data_0; @@ -3007,7 +2983,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) { auto checked = v8::ObjectTemplate::New(isolate); checked->SetAccessCheckCallbacks( SimpleAccessChecker, nullptr, - BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); + BuildWrappedObject<AccessCheckData>(isolate, &access_check_data)); context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance()); @@ -3018,14 +2994,12 @@ THREADED_TEST(NamedAllCanReadInterceptor) { "checked.__proto__ = intercepted_1;" "intercepted_1.__proto__ = intercepted_0;"); - checked_instance->TurnOnAccessCheck(); - CHECK_EQ(0, access_check_data.count); + CHECK_EQ(3, access_check_data.count); - access_check_data.result = true; ExpectInt32("checked.whatever", 17); CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')") ->IsUndefined()); - CHECK_EQ(2, access_check_data.count); + CHECK_EQ(5, access_check_data.count); access_check_data.result = false; ExpectInt32("checked.whatever", intercept_data_0.value); @@ -3034,7 +3008,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) { CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')"); CHECK(try_catch.HasCaught()); } - CHECK_EQ(4, access_check_data.count); + CHECK_EQ(7, access_check_data.count); intercept_data_1.should_intercept = true; ExpectInt32("checked.whatever", intercept_data_1.value); @@ -3043,7 +3017,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) { CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')"); CHECK(try_catch.HasCaught()); } - CHECK_EQ(6, access_check_data.count); + CHECK_EQ(9, access_check_data.count); } @@ -3053,7 +3027,7 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { LocalContext context; AccessCheckData access_check_data; - access_check_data.result = false; + access_check_data.result = true; access_check_data.count = 0; ShouldInterceptData intercept_data_0; @@ -3085,7 +3059,7 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { auto checked = v8::ObjectTemplate::New(isolate); checked->SetAccessCheckCallbacks( SimpleAccessChecker, nullptr, - BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); + BuildWrappedObject<AccessCheckData>(isolate, &access_check_data)); context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); context->Global()->Set(v8_str("intercepted_1"), intercepted_1->NewInstance()); @@ -3096,27 +3070,30 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { "checked.__proto__ = intercepted_1;" "intercepted_1.__proto__ = intercepted_0;"); - checked_instance->TurnOnAccessCheck(); - CHECK_EQ(0, access_check_data.count); + CHECK_EQ(3, access_check_data.count); access_check_data.result = true; ExpectInt32("checked[15]", 17); CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") ->IsUndefined()); - CHECK_EQ(3, access_check_data.count); + CHECK_EQ(5, access_check_data.count); access_check_data.result = false; ExpectInt32("checked[15]", intercept_data_0.value); - // Note: this should throw but without a LookupIterator it's complicated. - CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") - ->IsUndefined()); - CHECK_EQ(6, access_check_data.count); + { + v8::TryCatch try_catch(isolate); + CompileRun("Object.getOwnPropertyDescriptor(checked, '15')"); + CHECK(try_catch.HasCaught()); + } + CHECK_EQ(7, access_check_data.count); intercept_data_1.should_intercept = true; ExpectInt32("checked[15]", intercept_data_1.value); - // Note: this should throw but without a LookupIterator it's complicated. - CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") - ->IsUndefined()); + { + v8::TryCatch try_catch(isolate); + CompileRun("Object.getOwnPropertyDescriptor(checked, '15')"); + CHECK(try_catch.HasCaught()); + } CHECK_EQ(9, access_check_data.count); } diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 145d9bc64d..e464a67e00 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -190,7 +190,7 @@ static void TestSignature(const char* loop_js, Local<Value> receiver, signature_callback_count = 0; signature_expected_receiver = receiver; bool expected_to_throw = receiver.IsEmpty(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun(source.start()); CHECK_EQ(expected_to_throw, try_catch.HasCaught()); if (!expected_to_throw) { @@ -697,7 +697,7 @@ THREADED_TEST(NewExternalForVeryLongString) { auto isolate = CcTest::isolate(); { v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); RandomLengthOneByteResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); @@ -706,7 +706,7 @@ THREADED_TEST(NewExternalForVeryLongString) { { v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); RandomLengthResource r(1 << 30); v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); @@ -1590,6 +1590,17 @@ THREADED_TEST(StringObject) { } +TEST(StringObjectDelete) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); + CHECK(boxed_string->IsStringObject()); + v8::Handle<v8::Object> str_obj = boxed_string.As<v8::Object>(); + CHECK(!str_obj->Delete(2)); + CHECK(!str_obj->Delete(v8_num(2))); +} + + THREADED_TEST(NumberObject) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -2248,12 +2259,24 @@ THREADED_TEST(IdentityHash) { } -THREADED_TEST(GlobalProxyIdentityHash) { +void GlobalProxyIdentityHash(bool set_in_js) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); v8::HandleScope scope(isolate); Handle<Object> global_proxy = env->Global(); - int hash1 = global_proxy->GetIdentityHash(); + i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy); + env->Global()->Set(v8_str("global"), global_proxy); + i::Handle<i::Object> original_hash; + if (set_in_js) { + CompileRun("var m = new Set(); m.add(global);"); + original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate); + } else { + original_hash = i::Handle<i::Object>( + i::Object::GetOrCreateHash(i_isolate, i_global_proxy)); + } + CHECK(original_hash->IsSmi()); + int32_t hash1 = i::Handle<i::Smi>::cast(original_hash)->value(); // Hash should be retained after being detached. env->DetachGlobal(); int hash2 = global_proxy->GetIdentityHash(); @@ -2267,6 +2290,12 @@ THREADED_TEST(GlobalProxyIdentityHash) { } +THREADED_TEST(GlobalProxyIdentityHash) { + GlobalProxyIdentityHash(true); + GlobalProxyIdentityHash(false); +} + + TEST(SymbolIdentityHash) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); @@ -2434,65 +2463,6 @@ THREADED_TEST(SymbolTemplateProperties) { } -THREADED_TEST(PrivateProperties) { - LocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - - v8::Local<v8::Object> obj = v8::Object::New(isolate); - v8::Local<v8::Private> priv1 = v8::Private::New(isolate); - v8::Local<v8::Private> priv2 = - v8::Private::New(isolate, v8_str("my-private")); - - CcTest::heap()->CollectAllGarbage(); - - CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private"))); - - // Make sure delete of a non-existent private symbol property works. - CHECK(obj->DeletePrivate(priv1)); - CHECK(!obj->HasPrivate(priv1)); - - CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503))); - CHECK(obj->HasPrivate(priv1)); - CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value()); - CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002))); - CHECK(obj->HasPrivate(priv1)); - CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); - - CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length()); - unsigned num_props = obj->GetPropertyNames()->Length(); - CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"), - v8::Integer::New(isolate, 20))); - CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length()); - CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); - - CcTest::heap()->CollectAllGarbage(); - - // Add another property and delete it afterwards to force the object in - // slow case. - CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008))); - CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); - CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value()); - CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); - CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length()); - - CHECK(obj->HasPrivate(priv1)); - CHECK(obj->HasPrivate(priv2)); - CHECK(obj->DeletePrivate(priv2)); - CHECK(obj->HasPrivate(priv1)); - CHECK(!obj->HasPrivate(priv2)); - CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); - CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length()); - - // Private properties are inherited (for the time being). - v8::Local<v8::Object> child = v8::Object::New(isolate); - child->SetPrototype(obj); - CHECK(child->HasPrivate(priv1)); - CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value()); - CHECK_EQ(0u, child->GetOwnPropertyNames()->Length()); -} - - THREADED_TEST(GlobalSymbols) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); @@ -2541,28 +2511,6 @@ THREADED_TEST(WellKnownSymbols) { } -THREADED_TEST(GlobalPrivates) { - LocalContext env; - v8::Isolate* isolate = env->GetIsolate(); - v8::HandleScope scope(isolate); - - v8::Local<String> name = v8_str("my-private"); - v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name); - v8::Local<v8::Object> obj = v8::Object::New(isolate); - CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3))); - - v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name); - CHECK(obj->HasPrivate(glob2)); - - v8::Local<v8::Private> priv = v8::Private::New(isolate, name); - CHECK(!obj->HasPrivate(priv)); - - CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')"); - v8::Local<Value> intern = env->Global()->Get(v8_str("intern")); - CHECK(!obj->Has(intern)); -} - - class ScopedArrayBufferContents { public: explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents) @@ -2846,6 +2794,136 @@ THREADED_TEST(ArrayBuffer_NeuteringScript) { } +class ScopedSharedArrayBufferContents { + public: + explicit ScopedSharedArrayBufferContents( + const v8::SharedArrayBuffer::Contents& contents) + : contents_(contents) {} + ~ScopedSharedArrayBufferContents() { free(contents_.Data()); } + void* Data() const { return contents_.Data(); } + size_t ByteLength() const { return contents_.ByteLength(); } + + private: + const v8::SharedArrayBuffer::Contents contents_; +}; + + +THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) { + i::FLAG_harmony_sharedarraybuffer = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024); + CheckInternalFieldsAreZero(ab); + CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); + CHECK(!ab->IsExternal()); + CcTest::heap()->CollectAllGarbage(); + + ScopedSharedArrayBufferContents ab_contents(ab->Externalize()); + CHECK(ab->IsExternal()); + + CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); + uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); + DCHECK(data != NULL); + env->Global()->Set(v8_str("ab"), ab); + + v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); + CHECK_EQ(1024, result->Int32Value()); + + result = CompileRun( + "var u8 = new Uint8Array(ab);" + "u8[0] = 0xFF;" + "u8[1] = 0xAA;" + "u8.length"); + CHECK_EQ(1024, result->Int32Value()); + CHECK_EQ(0xFF, data[0]); + CHECK_EQ(0xAA, data[1]); + data[0] = 0xCC; + data[1] = 0x11; + result = CompileRun("u8[0] + u8[1]"); + CHECK_EQ(0xDD, result->Int32Value()); +} + + +THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) { + i::FLAG_harmony_sharedarraybuffer = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + + v8::Local<v8::Value> result = CompileRun( + "var ab1 = new SharedArrayBuffer(2);" + "var u8_a = new Uint8Array(ab1);" + "u8_a[0] = 0xAA;" + "u8_a[1] = 0xFF; u8_a.buffer"); + Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result); + CheckInternalFieldsAreZero(ab1); + CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); + CHECK(!ab1->IsExternal()); + ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize()); + CHECK(ab1->IsExternal()); + + result = CompileRun("ab1.byteLength"); + CHECK_EQ(2, result->Int32Value()); + result = CompileRun("u8_a[0]"); + CHECK_EQ(0xAA, result->Int32Value()); + result = CompileRun("u8_a[1]"); + CHECK_EQ(0xFF, result->Int32Value()); + result = CompileRun( + "var u8_b = new Uint8Array(ab1);" + "u8_b[0] = 0xBB;" + "u8_a[0]"); + CHECK_EQ(0xBB, result->Int32Value()); + result = CompileRun("u8_b[1]"); + CHECK_EQ(0xFF, result->Int32Value()); + + CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); + uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); + CHECK_EQ(0xBB, ab1_data[0]); + CHECK_EQ(0xFF, ab1_data[1]); + ab1_data[0] = 0xCC; + ab1_data[1] = 0x11; + result = CompileRun("u8_a[0] + u8_a[1]"); + CHECK_EQ(0xDD, result->Int32Value()); +} + + +THREADED_TEST(SharedArrayBuffer_External) { + i::FLAG_harmony_sharedarraybuffer = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + i::ScopedVector<uint8_t> my_data(100); + memset(my_data.start(), 0, 100); + Local<v8::SharedArrayBuffer> ab3 = + v8::SharedArrayBuffer::New(isolate, my_data.start(), 100); + CheckInternalFieldsAreZero(ab3); + CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); + CHECK(ab3->IsExternal()); + + env->Global()->Set(v8_str("ab3"), ab3); + + v8::Handle<v8::Value> result = CompileRun("ab3.byteLength"); + CHECK_EQ(100, result->Int32Value()); + + result = CompileRun( + "var u8_b = new Uint8Array(ab3);" + "u8_b[0] = 0xBB;" + "u8_b[1] = 0xCC;" + "u8_b.length"); + CHECK_EQ(100, result->Int32Value()); + CHECK_EQ(0xBB, my_data[0]); + CHECK_EQ(0xCC, my_data[1]); + my_data[0] = 0xCC; + my_data[1] = 0x11; + result = CompileRun("u8_b[0] + u8_b[1]"); + CHECK_EQ(0xDD, result->Int32Value()); +} + + THREADED_TEST(HiddenProperties) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); @@ -3934,7 +4012,7 @@ THREADED_TEST(ScriptException) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); Local<Script> script = v8_compile("throw 'panama!';"); - v8::TryCatch try_catch; + v8::TryCatch try_catch(env->GetIsolate()); Local<Value> result = script->Run(); CHECK(result.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -3947,7 +4025,7 @@ TEST(TryCatchCustomException) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "function CustomError() { this.a = 'b'; }" "(function f() { throw new CustomError(); })();"); @@ -4039,8 +4117,9 @@ TEST(MessageHandler2) { static void check_message_3(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK(message->IsSharedCrossOrigin()); - CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value()); - CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value()); + CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin()); + CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript()); + CHECK(message->GetScriptOrigin().Options().IsOpaque()); CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue()); message_received = true; @@ -4057,7 +4136,7 @@ TEST(MessageHandler3) { v8::ScriptOrigin origin = v8::ScriptOrigin( v8_str("6.75"), v8::Integer::New(isolate, 1), v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(), - v8::True(isolate), v8_str("7.40")); + v8::True(isolate), v8_str("7.40"), v8::True(isolate)); v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), &origin); script->Run(); @@ -4117,11 +4196,11 @@ TEST(MessageHandler5) { CHECK(!message_received); v8::V8::AddMessageListener(check_message_5a); LocalContext context; - v8::ScriptOrigin origin = + v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), v8::Integer::New(isolate, 2), v8::True(isolate)); v8::Handle<v8::Script> script = - Script::Compile(v8_str("throw 'error'"), &origin); + Script::Compile(v8_str("throw 'error'"), &origin1); script->Run(); CHECK(message_received); // clear out the message listener @@ -4129,9 +4208,10 @@ TEST(MessageHandler5) { message_received = false; v8::V8::AddMessageListener(check_message_5b); - origin = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), - v8::Integer::New(isolate, 2), v8::False(isolate)); - script = Script::Compile(v8_str("throw 'error'"), &origin); + v8::ScriptOrigin origin2 = + v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), + v8::Integer::New(isolate, 2), v8::False(isolate)); + script = Script::Compile(v8_str("throw 'error'"), &origin2); script->Run(); CHECK(message_received); // clear out the message listener @@ -4277,7 +4357,7 @@ THREADED_TEST(PropertyAttributes) { Local<Value> fake_prop = v8_num(1); CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); // exception - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); Local<Value> exception = CompileRun("({ toString: function() { throw 'exception';} })"); CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); @@ -4672,7 +4752,7 @@ void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { return; } v8::HandleScope scope(args.GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate())); CHECK(!try_catch.HasCaught() || result.IsEmpty()); args.GetReturnValue().Set(try_catch.HasCaught()); @@ -4705,7 +4785,7 @@ THREADED_TEST(APIThrowTryCatch) { templ->Set(v8_str("ThrowFromC"), v8::FunctionTemplate::New(isolate, ThrowFromC)); LocalContext context(0, templ); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun("ThrowFromC();"); CHECK(try_catch.HasCaught()); } @@ -4870,6 +4950,26 @@ TEST(CustomErrorMessage) { } +static void check_custom_rethrowing_message(v8::Handle<v8::Message> message, + v8::Handle<v8::Value> data) { + const char* uncaught_error = "Uncaught exception"; + CHECK(message->Get()->Equals(v8_str(uncaught_error))); +} + + +TEST(CustomErrorRethrowsOnToString) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + v8::V8::AddMessageListener(check_custom_rethrowing_message); + + CompileRun( + "var e = { toString: function() { throw e; } };" + "try { throw e; } finally {}"); + + v8::V8::RemoveMessageListeners(check_custom_rethrowing_message); +} + + static void receive_message(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { message->Get(); @@ -4901,7 +5001,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) { templ->Set(v8_str("ThrowFromC"), v8::FunctionTemplate::New(isolate, ThrowFromC)); LocalContext context(0, templ); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); try_catch.SetVerbose(true); Local<Value> result = CompileRun("ThrowFromC();"); CHECK(try_catch.HasCaught()); @@ -4916,7 +5016,7 @@ TEST(APIStackOverflowAndVerboseTryCatch) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); v8::V8::AddMessageListener(receive_message); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); try_catch.SetVerbose(true); Local<Value> result = CompileRun("function foo() { foo(); } foo();"); CHECK(try_catch.HasCaught()); @@ -4934,7 +5034,7 @@ THREADED_TEST(ExternalScriptException) { v8::FunctionTemplate::New(isolate, ThrowFromC)); LocalContext context(0, templ); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';"); CHECK(result.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -4956,7 +5056,7 @@ void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]}; if (count % cInterval == 0) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); Local<Value> result = fun.As<Function>()->Call(global, 4, argv); int expected = args[3]->Int32Value(); if (try_catch.HasCaught()) { @@ -4993,7 +5093,7 @@ void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { THREADED_TEST(EvalInTryFinally) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CompileRun( "(function() {" " try {" @@ -5121,7 +5221,7 @@ THREADED_TEST(ThrowValues) { THREADED_TEST(CatchZero) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CHECK(!try_catch.HasCaught()); CompileRun("throw 10"); CHECK(try_catch.HasCaught()); @@ -5137,7 +5237,7 @@ THREADED_TEST(CatchZero) { THREADED_TEST(CatchExceptionFromWith) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CHECK(!try_catch.HasCaught()); CompileRun("var o = {}; with (o) { throw 42; }"); CHECK(try_catch.HasCaught()); @@ -5147,7 +5247,7 @@ THREADED_TEST(CatchExceptionFromWith) { THREADED_TEST(TryCatchAndFinallyHidingException) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CHECK(!try_catch.HasCaught()); CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); CompileRun("f({toString: function() { throw 42; }});"); @@ -5156,7 +5256,7 @@ THREADED_TEST(TryCatchAndFinallyHidingException) { void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); } @@ -5167,7 +5267,7 @@ THREADED_TEST(TryCatchAndFinally) { context->Global()->Set( v8_str("native_with_try_catch"), v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(!try_catch.HasCaught()); CompileRun( "try {\n" @@ -5181,7 +5281,7 @@ THREADED_TEST(TryCatchAndFinally) { static void TryCatchNested1Helper(int depth) { if (depth > 0) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); try_catch.SetVerbose(true); TryCatchNested1Helper(depth - 1); CHECK(try_catch.HasCaught()); @@ -5194,7 +5294,7 @@ static void TryCatchNested1Helper(int depth) { static void TryCatchNested2Helper(int depth) { if (depth > 0) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); try_catch.SetVerbose(true); TryCatchNested2Helper(depth - 1); CHECK(try_catch.HasCaught()); @@ -5212,7 +5312,7 @@ TEST(TryCatchNested) { { // Test nested try-catch with a native throw in the end. - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); TryCatchNested1Helper(5); CHECK(try_catch.HasCaught()); CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1")); @@ -5220,7 +5320,7 @@ TEST(TryCatchNested) { { // Test nested try-catch with a JavaScript throw in the end. - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); TryCatchNested2Helper(5); CHECK(try_catch.HasCaught()); CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2")); @@ -5243,7 +5343,7 @@ void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { void TryCatchMixedNestingHelper( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); CHECK(try_catch.HasCaught()); TryCatchMixedNestingCheck(&try_catch); @@ -5260,7 +5360,7 @@ TEST(TryCatchMixedNesting) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::V8::Initialize(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); templ->Set(v8_str("TryCatchMixedNestingHelper"), v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper)); @@ -5272,7 +5372,7 @@ TEST(TryCatchMixedNesting) { void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); args.GetIsolate()->ThrowException(v8_str("boom")); CHECK(try_catch.HasCaught()); } @@ -5282,7 +5382,7 @@ TEST(TryCatchNative) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::V8::Initialize(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); templ->Set(v8_str("TryCatchNativeHelper"), v8::FunctionTemplate::New(isolate, TryCatchNativeHelper)); @@ -5295,7 +5395,7 @@ TEST(TryCatchNative) { void TryCatchNativeResetHelper( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); args.GetIsolate()->ThrowException(v8_str("boom")); CHECK(try_catch.HasCaught()); try_catch.Reset(); @@ -5307,7 +5407,7 @@ TEST(TryCatchNativeReset) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::V8::Initialize(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); templ->Set(v8_str("TryCatchNativeResetHelper"), v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper)); @@ -5433,7 +5533,7 @@ THREADED_TEST(DefinePropertyOnAPIAccessor) { CHECK_EQ(result->BooleanValue(), false); // Make sure that it is not possible to redefine again - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); result = script_define->Run(); CHECK(try_catch.HasCaught()); String::Utf8Value exception_value(try_catch.Exception()); @@ -5482,7 +5582,7 @@ THREADED_TEST(DefinePropertyOnDefineGetterSetter) { CHECK_EQ(result->BooleanValue(), false); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); result = script_define->Run(); CHECK(try_catch.HasCaught()); String::Utf8Value exception_value(try_catch.Exception()); @@ -5604,7 +5704,7 @@ THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "Object.defineProperty(obj1, 'x'," "{get: function() { return 'func'; }})"); @@ -5614,7 +5714,7 @@ THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x")); } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "Object.defineProperty(obj2, 'x'," "{get: function() { return 'func'; }})"); @@ -7384,10 +7484,10 @@ THREADED_TEST(ToArrayIndex) { str = v8_str("-42"); index = str->ToArrayIndex(); CHECK(index.IsEmpty()); - str = v8_str("4294967295"); + str = v8_str("4294967294"); index = str->ToArrayIndex(); CHECK(!index.IsEmpty()); - CHECK_EQ(4294967295.0, index->Uint32Value()); + CHECK_EQ(4294967294.0, index->Uint32Value()); v8::Handle<v8::Number> num = v8::Number::New(isolate, 1); index = num->ToArrayIndex(); CHECK(!index.IsEmpty()); @@ -7450,7 +7550,7 @@ THREADED_TEST(ExceptionCreateMessage) { v8::Local<v8::Object> global = context->Global(); global->Set(v8_str("throwV8Exception"), fun->GetFunction()); - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); CompileRun( "function f1() {\n" " throwV8Exception();\n" @@ -7504,6 +7604,22 @@ THREADED_TEST(ExceptionCreateMessage) { } +THREADED_TEST(ExceptionCreateMessageLength) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + + // Test that the message is not truncated. + TryCatch try_catch(context->GetIsolate()); + CompileRun( + "var message = 'm';" + "while (message.length < 1000) message += message;" + "throw message;"); + CHECK(try_catch.HasCaught()); + + CHECK_LT(1000, try_catch.Message()->Get()->Length()); +} + + static void YGetter(Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { ApiTestFuzzer::Fuzz(); @@ -7684,7 +7800,7 @@ TEST(ExceptionInNativeScript) { TEST(CompilationErrorUsingTryCatchHandler) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(env->GetIsolate()); v8_compile("This doesn't &*&@#$&*^ compile."); CHECK(*try_catch.Exception()); CHECK(try_catch.HasCaught()); @@ -7694,7 +7810,7 @@ TEST(CompilationErrorUsingTryCatchHandler) { TEST(TryCatchFinallyUsingTryCatchHandler) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(env->GetIsolate()); CompileRun("try { throw ''; } catch (e) {}"); CHECK(!try_catch.HasCaught()); CompileRun("try { throw ''; } finally {}"); @@ -7726,7 +7842,7 @@ TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { templ->Set(v8_str("CEvaluate"), v8::FunctionTemplate::New(isolate, CEvaluate)); LocalContext context(0, templ); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun("try {" " CEvaluate('throw 1;');" "} finally {" @@ -7853,7 +7969,7 @@ THREADED_TEST(SecurityChecks) { Context::Scope scope_env2(env2); // Call cross_domain_call, it should throw an exception - v8::TryCatch try_catch; + v8::TryCatch try_catch(env1->GetIsolate()); Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); CHECK(try_catch.HasCaught()); } @@ -8105,7 +8221,7 @@ TEST(ContextDetachGlobal) { { Local<Value> get_prop = global1->Get(v8_str("getProp")); CHECK(get_prop->IsFunction()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(env1->GetIsolate()); Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); CHECK(!try_catch.HasCaught()); CHECK_EQ(1, r->Int32Value()); @@ -8229,7 +8345,6 @@ TEST(DetachedAccesses) { } Local<Object> env2_global = env2->Global(); - env2_global->TurnOnAccessCheck(); env2->DetachGlobal(); Local<Value> result; @@ -8639,8 +8754,6 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) { TEST(SuperAccessControl) { i::FLAG_allow_natives_syntax = true; - i::FLAG_harmony_classes = true; - i::FLAG_harmony_object_literals = true; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> obj_template = @@ -8650,7 +8763,7 @@ TEST(SuperAccessControl) { env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "var f = { m() { return super.hasOwnProperty; } }.m;" "var m = %ToMethod(f, prohibited);" @@ -8659,7 +8772,7 @@ TEST(SuperAccessControl) { } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "var f = {m() { return super[42]; } }.m;" "var m = %ToMethod(f, prohibited);" @@ -8668,7 +8781,7 @@ TEST(SuperAccessControl) { } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "var f = {m() { super.hasOwnProperty = function () {}; } }.m;" "var m = %ToMethod(f, prohibited);" @@ -8677,7 +8790,7 @@ TEST(SuperAccessControl) { } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "Object.defineProperty(Object.prototype, 'x', { set : function(){}});" "var f = {" @@ -8694,8 +8807,6 @@ TEST(SuperAccessControl) { TEST(Regress470113) { - i::FLAG_harmony_classes = true; - i::FLAG_harmony_object_literals = true; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> obj_template = @@ -8705,7 +8816,7 @@ TEST(Regress470113) { env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "'use strict';\n" "class C extends Object {\n" @@ -9446,7 +9557,7 @@ THREADED_TEST(SetPrototypeThrows) { CHECK(o0->SetPrototype(o1)); // If setting the prototype leads to the cycle, SetPrototype should // return false and keep VM in sane state. - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(!o1->SetPrototype(o0)); CHECK(!try_catch.HasCaught()); DCHECK(!CcTest::i_isolate()->has_pending_exception()); @@ -9466,7 +9577,7 @@ THREADED_TEST(FunctionRemovePrototype) { context->Global()->Set(v8_str("fun"), fun); CHECK(!CompileRun("'prototype' in fun")->BooleanValue()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun("new fun()"); CHECK(try_catch.HasCaught()); @@ -9488,7 +9599,7 @@ THREADED_TEST(GetterSetterExceptions) { "x.__defineGetter__('get', Throw);"); Local<v8::Object> x = Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); x->Get(v8_str("get")); x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); @@ -9554,7 +9665,7 @@ THREADED_TEST(ConstructorForObject) { instance_template->SetCallAsFunctionHandler(ConstructorCallback); Local<Object> instance = instance_template->NewInstance(); context->Global()->Set(v8_str("obj"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -9630,7 +9741,7 @@ THREADED_TEST(ConstructorForObject) { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); Local<Object> instance = instance_template->NewInstance(); context->Global()->Set(v8_str("obj2"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -9655,7 +9766,7 @@ THREADED_TEST(ConstructorForObject) { instance_template->SetCallAsFunctionHandler(ThrowValue); Local<Object> instance = instance_template->NewInstance(); context->Global()->Set(v8_str("obj3"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -9680,7 +9791,7 @@ THREADED_TEST(ConstructorForObject) { Local<Function> function = function_template->GetFunction(); Local<Object> instance1 = function; context->Global()->Set(v8_str("obj4"), instance1); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -9764,7 +9875,7 @@ THREADED_TEST(EvalAliasedDynamic) { CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(current->GetIsolate()); script = v8_compile( "function f(x) { " " var bar = 2;" @@ -9807,7 +9918,7 @@ THREADED_TEST(CrossEval) { // Check that global variables in current context are not visible in other // context. - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); script = v8_compile("var bar = 42; other.eval('bar');"); Local<Value> result = script->Run(); CHECK(try_catch.HasCaught()); @@ -9881,7 +9992,7 @@ THREADED_TEST(EvalInDetachedGlobal) { v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); CHECK_EQ(42, x_value->Int32Value()); context0->DetachGlobal(); - v8::TryCatch catcher; + v8::TryCatch catcher(isolate); x_value = CompileRun("fun('x')"); CHECK_EQ(42, x_value->Int32Value()); context1->Exit(); @@ -9939,7 +10050,7 @@ THREADED_TEST(CallAsFunction) { instance_template->SetCallAsFunctionHandler(call_as_function); Local<v8::Object> instance = t->GetFunction()->NewInstance(); context->Global()->Set(v8_str("obj"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -9994,7 +10105,7 @@ THREADED_TEST(CallAsFunction) { USE(instance_template); Local<v8::Object> instance = t->GetFunction()->NewInstance(); context->Global()->Set(v8_str("obj2"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -10025,7 +10136,7 @@ THREADED_TEST(CallAsFunction) { instance_template->SetCallAsFunctionHandler(ThrowValue); Local<v8::Object> instance = t->GetFunction()->NewInstance(); context->Global()->Set(v8_str("obj3"), instance); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); Local<Value> value; CHECK(!try_catch.HasCaught()); @@ -10123,7 +10234,7 @@ THREADED_TEST(CallableObject) { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); instance_template->SetCallAsFunctionHandler(call_as_function); Local<Object> instance = instance_template->NewInstance(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(instance->IsCallable()); CHECK(!try_catch.HasCaught()); @@ -10132,7 +10243,7 @@ THREADED_TEST(CallableObject) { { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); Local<Object> instance = instance_template->NewInstance(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(!instance->IsCallable()); CHECK(!try_catch.HasCaught()); @@ -10143,7 +10254,7 @@ THREADED_TEST(CallableObject) { FunctionTemplate::New(isolate, call_as_function); Local<Function> function = function_template->GetFunction(); Local<Object> instance = function; - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(instance->IsCallable()); CHECK(!try_catch.HasCaught()); @@ -10153,7 +10264,7 @@ THREADED_TEST(CallableObject) { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate); Local<Function> function = function_template->GetFunction(); Local<Object> instance = function; - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(instance->IsCallable()); CHECK(!try_catch.HasCaught()); @@ -10544,7 +10655,7 @@ THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { v8::Handle<v8::Function> fun = fun_templ->GetFunction(); GenerateSomeGarbage(); context->Global()->Set(v8_str("o"), fun->NewInstance()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "o.foo = 17;" "var receiver = {};" @@ -10587,7 +10698,7 @@ THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { v8::Handle<v8::Function> fun = fun_templ->GetFunction(); GenerateSomeGarbage(); context->Global()->Set(v8_str("o"), fun->NewInstance()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "o.foo = 17;" "var receiver = {};" @@ -10719,7 +10830,7 @@ THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { v8::Handle<v8::Function> fun = fun_templ->GetFunction(); GenerateSomeGarbage(); context->Global()->Set(v8_str("o"), fun->NewInstance()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "o.foo = 17;" "var receiver = {};" @@ -10758,7 +10869,7 @@ THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { v8::Handle<v8::Function> fun = fun_templ->GetFunction(); GenerateSomeGarbage(); context->Global()->Set(v8_str("o"), fun->NewInstance()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "o.foo = 17;" "var receiver = {};" @@ -10806,7 +10917,7 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { "o\n").As<Object>(); CHECK(!with_js_getter.IsEmpty()); - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); CHECK(try_catch.HasCaught()); @@ -10859,7 +10970,7 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { static void ThrowingCallbackWithTryCatch( const v8::FunctionCallbackInfo<v8::Value>& args) { - TryCatch try_catch; + TryCatch try_catch(args.GetIsolate()); // Verboseness is important: it triggers message delivery which can call into // external code. try_catch.SetVerbose(true); @@ -10874,7 +10985,7 @@ static int call_depth; static void WithTryCatch(Handle<Message> message, Handle<Value> data) { - TryCatch try_catch; + TryCatch try_catch(CcTest::isolate()); } @@ -11163,7 +11274,7 @@ TEST(ObjectProtoToStringES6) { Local<Value> obj = v8::Object::New(isolate); obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter); { - TryCatch try_catch; + TryCatch try_catch(isolate); value = obj.As<v8::Object>()->ObjectProtoToString(); CHECK(value.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -11174,7 +11285,7 @@ TEST(ObjectProtoToStringES6) { obj.As<v8::Object>()->SetAccessor( toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test")); { - TryCatch try_catch; + TryCatch try_catch(isolate); value = obj.As<v8::Object>()->ObjectProtoToString(); CHECK(value->IsString() && value->Equals(v8_str("[object Test]"))); CHECK(!try_catch.HasCaught()); @@ -11183,7 +11294,7 @@ TEST(ObjectProtoToStringES6) { // JS @@toStringTag value obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj"); { - TryCatch try_catch; + TryCatch try_catch(isolate); value = obj.As<v8::Object>()->ObjectProtoToString(); CHECK(value->IsString() && value->Equals(v8_str("[object Test]"))); CHECK(!try_catch.HasCaught()); @@ -11195,7 +11306,7 @@ TEST(ObjectProtoToStringES6) { " get: function() { throw 'Test'; }" "}); obj"); { - TryCatch try_catch; + TryCatch try_catch(isolate); value = obj.As<v8::Object>()->ObjectProtoToString(); CHECK(value.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -11207,7 +11318,7 @@ TEST(ObjectProtoToStringES6) { " get: function() { return 'Test'; }" "}); obj"); { - TryCatch try_catch; + TryCatch try_catch(isolate); value = obj.As<v8::Object>()->ObjectProtoToString(); CHECK(value->IsString() && value->Equals(v8_str("[object Test]"))); CHECK(!try_catch.HasCaught()); @@ -11421,7 +11532,8 @@ static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { v8::Locker nested_locker(isolate); v8::HandleScope scope(isolate); v8::Handle<Value> exception; - { v8::TryCatch try_catch; + { + v8::TryCatch try_catch(isolate); v8::Handle<Value> value = CompileRun(code); CHECK(value.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -12447,7 +12559,7 @@ THREADED_TEST(Regress54) { TEST(CatchStackOverflow) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); v8::Handle<v8::Value> result = CompileRun( "function f() {" " return f();" @@ -12462,7 +12574,7 @@ static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, const char* resource_name, int line_offset) { v8::HandleScope scope(CcTest::isolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); v8::Handle<v8::Value> result = script->Run(); CHECK(result.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -12522,7 +12634,7 @@ THREADED_TEST(TryCatchSourceInfo) { THREADED_TEST(TryCatchSourceInfoForEOSError) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); v8::Script::Compile(v8_str("!\n")); CHECK(try_catch.HasCaught()); v8::Handle<v8::Message> message = try_catch.Message(); @@ -12714,71 +12826,6 @@ THREADED_TEST(AccessChecksReenabledCorrectly) { } -THREADED_TEST(TurnOnAccessCheck) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - - // Create an environment with access check to the global object disabled by - // default. - v8::Handle<v8::ObjectTemplate> global_template = - v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL, - v8::Handle<v8::Value>(), false); - v8::Local<Context> context = Context::New(isolate, NULL, global_template); - Context::Scope context_scope(context); - - // Set up a property and a number of functions. - context->Global()->Set(v8_str("a"), v8_num(1)); - CompileRun("function f1() {return a;}" - "function f2() {return a;}" - "function g1() {return h();}" - "function g2() {return h();}" - "function h() {return 1;}"); - Local<Function> f1 = - Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); - Local<Function> f2 = - Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); - Local<Function> g1 = - Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); - Local<Function> g2 = - Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); - Local<Function> h = - Local<Function>::Cast(context->Global()->Get(v8_str("h"))); - - // Get the global object. - v8::Handle<v8::Object> global = context->Global(); - - // Call f1 one time and f2 a number of times. This will ensure that f1 still - // uses the runtime system to retreive property a whereas f2 uses global load - // inline cache. - CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); - for (int i = 0; i < 4; i++) { - CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); - } - - // Same for g1 and g2. - CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); - for (int i = 0; i < 4; i++) { - CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); - } - - // Detach the global and turn on access check. - Local<Object> hidden_global = Local<Object>::Cast( - context->Global()->GetPrototype()); - context->DetachGlobal(); - hidden_global->TurnOnAccessCheck(); - - // Failing access check results in exception. - CHECK(f1->Call(global, 0, NULL).IsEmpty()); - CHECK(f2->Call(global, 0, NULL).IsEmpty()); - CHECK(g1->Call(global, 0, NULL).IsEmpty()); - CHECK(g2->Call(global, 0, NULL).IsEmpty()); - - // No failing access check when just returning a constant. - CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); -} - - // Tests that ScriptData can be serialized and deserialized. TEST(PreCompileSerialization) { v8::V8::Initialize(); @@ -13106,7 +13153,7 @@ TEST(RegExpInterruption) { regexp_interruption_data.string_resource = new UC16VectorResource( i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content))); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); timeout_thread.Start(); CompileRun("/((a*)*)*b/.exec(a)"); @@ -13216,8 +13263,9 @@ TEST(ForceSet) { CHECK_EQ(3, global->Get(access_property)->Int32Value()); CHECK_EQ(1, force_set_set_count); CHECK_EQ(2, force_set_get_count); - // Forcing the property to be set should override the accessor without - // calling it + // ForceSet doesn't call the accessors for now. + // TODO(verwaest): Update once blink doesn't rely on ForceSet to delete api + // accessors. global->ForceSet(access_property, v8::Int32::New(isolate, 8)); CHECK_EQ(8, global->Get(access_property)->Int32Value()); CHECK_EQ(1, force_set_set_count); @@ -13226,18 +13274,19 @@ TEST(ForceSet) { TEST(ForceSetWithInterceptor) { - force_set_get_count = 0; - force_set_set_count = 0; - pass_on_get = false; - v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); templ->SetHandler(v8::NamedPropertyHandlerConfiguration( ForceSetInterceptGetter, ForceSetInterceptSetter)); + pass_on_get = true; LocalContext context(NULL, templ); v8::Handle<v8::Object> global = context->Global(); + force_set_get_count = 0; + force_set_set_count = 0; + pass_on_get = false; + v8::Handle<v8::String> some_property = v8::String::NewFromUtf8(isolate, "a"); CHECK_EQ(0, force_set_set_count); @@ -13276,6 +13325,228 @@ TEST(ForceSetWithInterceptor) { } +TEST(CreateDataProperty) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + CompileRun( + "var a = {};" + "var b = [];" + "Object.defineProperty(a, 'foo', {value: 23});" + "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); + + v8::Local<v8::Object> obj = + v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a"))); + v8::Local<v8::Array> arr = + v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b"))); + { + // Can't change a non-configurable properties. + v8::TryCatch try_catch(isolate); + CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = + obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set a regular property. + v8::TryCatch try_catch(isolate); + CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = + obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set an indexed property. + v8::TryCatch try_catch(isolate); + CHECK(obj->CreateDataProperty(env.local(), v8_str("1"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Special cases for arrays. + v8::TryCatch try_catch(isolate); + CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"), + v8::Integer::New(isolate, 1)).FromJust()); + CHECK(!try_catch.HasCaught()); + } + { + // Special cases for arrays: index exceeds the array's length + v8::TryCatch try_catch(isolate); + CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23)) + .FromJust()); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(2U, arr->Length()); + v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); + + // Set an existing entry. + CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42)) + .FromJust()); + CHECK(!try_catch.HasCaught()); + val = arr->Get(env.local(), 0).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + CompileRun("Object.freeze(a);"); + { + // Can't change non-extensible objects. + v8::TryCatch try_catch(isolate); + CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); + v8::Local<v8::Object> access_checked = + templ->NewInstance(env.local()).ToLocalChecked(); + { + v8::TryCatch try_catch(isolate); + CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"), + v8::Integer::New(isolate, 42)) + .IsNothing()); + CHECK(try_catch.HasCaught()); + } +} + + +TEST(DefineOwnProperty) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + CompileRun( + "var a = {};" + "var b = [];" + "Object.defineProperty(a, 'foo', {value: 23});" + "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); + + v8::Local<v8::Object> obj = + v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a"))); + v8::Local<v8::Array> arr = + v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b"))); + { + // Can't change a non-configurable properties. + v8::TryCatch try_catch(isolate); + CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = + obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set a regular property. + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = + obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set an indexed property. + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Special cases for arrays. + v8::TryCatch try_catch(isolate); + CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"), + v8::Integer::New(isolate, 1)).FromJust()); + CHECK(!try_catch.HasCaught()); + } + { + // Special cases for arrays: index exceeds the array's length + v8::TryCatch try_catch(isolate); + CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"), + v8::Integer::New(isolate, 23)).FromJust()); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(2U, arr->Length()); + v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); + + // Set an existing entry. + CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + val = arr->Get(env.local(), 0).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + } + + { + // Set a non-writable property. + v8::TryCatch try_catch(isolate); + CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"), + v8::Integer::New(isolate, 42), + v8::ReadOnly).FromJust()); + CHECK(!try_catch.HasCaught()); + v8::Local<v8::Value> val = + obj->Get(env.local(), v8_str("lala")).ToLocalChecked(); + CHECK(val->IsNumber()); + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); + CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes( + env.local(), v8_str("lala")).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + CompileRun("Object.freeze(a);"); + { + // Can't change non-extensible objects. + v8::TryCatch try_catch(isolate); + CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"), + v8::Integer::New(isolate, 42)).FromJust()); + CHECK(!try_catch.HasCaught()); + } + + v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); + v8::Local<v8::Object> access_checked = + templ->NewInstance(env.local()).ToLocalChecked(); + { + v8::TryCatch try_catch(isolate); + CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"), + v8::Integer::New(isolate, 42)) + .IsNothing()); + CHECK(try_catch.HasCaught()); + } +} + + static v8::Local<Context> calling_context0; static v8::Local<Context> calling_context1; static v8::Local<Context> calling_context2; @@ -13789,7 +14060,8 @@ THREADED_TEST(FixedFloat64Array) { } -template <typename ElementType, typename TypedArray, class ExternalArrayClass> +template <typename ElementType, typename TypedArray, class ExternalArrayClass, + class ArrayBufferType> void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, int64_t high) { const int kElementCount = 50; @@ -13800,8 +14072,8 @@ void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope handle_scope(isolate); - Local<v8::ArrayBuffer> ab = - v8::ArrayBuffer::New(isolate, backing_store.start(), + Local<ArrayBufferType> ab = + ArrayBufferType::New(isolate, backing_store.start(), (kElementCount + 2) * sizeof(ElementType)); Local<TypedArray> ta = TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); @@ -13822,56 +14094,58 @@ void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, THREADED_TEST(Uint8Array) { - TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>( - i::kExternalUint8Array, 0, 0xFF); + TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array, + v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); } THREADED_TEST(Int8Array) { - TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>( - i::kExternalInt8Array, -0x80, 0x7F); + TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array, + v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F); } THREADED_TEST(Uint16Array) { - TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array>( - i::kExternalUint16Array, 0, 0xFFFF); + TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array, + v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF); } THREADED_TEST(Int16Array) { - TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>( - i::kExternalInt16Array, -0x8000, 0x7FFF); + TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array, + v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000, + 0x7FFF); } THREADED_TEST(Uint32Array) { - TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>( - i::kExternalUint32Array, 0, UINT_MAX); + TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array, + v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX); } THREADED_TEST(Int32Array) { - TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>( - i::kExternalInt32Array, INT_MIN, INT_MAX); + TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array, + v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN, + INT_MAX); } THREADED_TEST(Float32Array) { - TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>( - i::kExternalFloat32Array, -500, 500); + TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array, + v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500); } THREADED_TEST(Float64Array) { - TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>( - i::kExternalFloat64Array, -500, 500); + TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array, + v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500); } THREADED_TEST(Uint8ClampedArray) { TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, - i::ExternalUint8ClampedArray>( + i::ExternalUint8ClampedArray, v8::ArrayBuffer>( i::kExternalUint8ClampedArray, 0, 0xFF); } @@ -13887,6 +14161,97 @@ THREADED_TEST(DataView) { Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); + Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize); + CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); + CHECK_EQ(2u, dv->ByteOffset()); + CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); + CHECK(ab->Equals(dv->Buffer())); +} + + +THREADED_TEST(SharedUint8Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array, + v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); +} + + +THREADED_TEST(SharedInt8Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array, + v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80, + 0x7F); +} + + +THREADED_TEST(SharedUint16Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array, + v8::SharedArrayBuffer>(i::kExternalUint16Array, 0, + 0xFFFF); +} + + +THREADED_TEST(SharedInt16Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array, + v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000, + 0x7FFF); +} + + +THREADED_TEST(SharedUint32Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array, + v8::SharedArrayBuffer>(i::kExternalUint32Array, 0, + UINT_MAX); +} + + +THREADED_TEST(SharedInt32Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array, + v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN, + INT_MAX); +} + + +THREADED_TEST(SharedFloat32Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array, + v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500, + 500); +} + + +THREADED_TEST(SharedFloat64Array) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array, + v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500, + 500); +} + + +THREADED_TEST(SharedUint8ClampedArray) { + i::FLAG_harmony_sharedarraybuffer = true; + TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, + i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>( + i::kExternalUint8ClampedArray, 0, 0xFF); +} + + +THREADED_TEST(SharedDataView) { + i::FLAG_harmony_sharedarraybuffer = true; + const int kSize = 50; + + i::ScopedVector<uint8_t> backing_store(kSize + 2); + + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + Local<v8::SharedArrayBuffer> ab = + v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize); CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); @@ -13949,7 +14314,7 @@ THREADED_TEST(ScriptContextDependence) { THREADED_TEST(StackTrace) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); const char *source = "function foo() { FAIL.FAIL; }; foo();"; v8::Handle<v8::String> src = v8::String::NewFromUtf8(context->GetIsolate(), source); @@ -14928,7 +15293,7 @@ TEST(DynamicWithSourceURLInStackTraceString) { i::ScopedVector<char> code(1024); i::SNPrintF(code, source, "//# sourceURL=source_url"); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CompileRunWithOrigin(code.start(), "", 0, 0); CHECK(try_catch.HasCaught()); v8::String::Utf8Value stack(try_catch.StackTrace()); @@ -14949,7 +15314,7 @@ TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) { "outer();\n" "//# sourceURL=outer_url"; - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CompileRun(source); CHECK(try_catch.HasCaught()); @@ -14973,7 +15338,7 @@ TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) { "outer();\n" "//# sourceURL=outer_url"; - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); CompileRun(source); CHECK(try_catch.HasCaught()); @@ -14996,6 +15361,7 @@ static void CreateGarbageInOldSpace() { // Test that idle notification can be handled and eventually collects garbage. TEST(TestIdleNotification) { + if (!i::FLAG_incremental_marking) return; const intptr_t MB = 1024 * 1024; const double IdlePauseInSeconds = 1.0; LocalContext env; @@ -15006,6 +15372,9 @@ TEST(TestIdleNotification) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { + if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) { + CcTest::heap()->StartIdleIncrementalMarking(); + } finished = env->GetIsolate()->IdleNotificationDeadline( (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + @@ -15284,9 +15653,6 @@ TEST(ExternalInternalizedStringCollectedAtTearDown) { TEST(ExternalInternalizedStringCollectedAtGC) { - // TODO(mvstanton): vector ics need weak support. - if (i::FLAG_vector_ics) return; - int destroyed = 0; { LocalContext env; v8::HandleScope handle_scope(env->GetIsolate()); @@ -15345,7 +15711,7 @@ THREADED_TEST(QuietSignalingNaNs) { LocalContext context; v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); // Special double values. double snan = DoubleFromBits(0x7ff00000, 0x00000001); @@ -15432,7 +15798,7 @@ THREADED_TEST(QuietSignalingNaNs) { static void SpaghettiIncident( const v8::FunctionCallbackInfo<v8::Value>& args) { v8::HandleScope scope(args.GetIsolate()); - v8::TryCatch tc; + v8::TryCatch tc(args.GetIsolate()); v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate())); USE(str); if (tc.HasCaught()) @@ -15449,7 +15815,7 @@ THREADED_TEST(SpaghettiStackReThrow) { context->Global()->Set( v8::String::NewFromUtf8(isolate, "s"), v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "var i = 0;" "var o = {" @@ -15535,7 +15901,7 @@ TEST(Regress528) { v8::Local<Context> context = Context::New(isolate); context->Enter(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun(source_exception); CHECK(try_catch.HasCaught()); v8::Handle<v8::Message> message = try_catch.Message(); @@ -15566,7 +15932,8 @@ THREADED_TEST(ScriptOrigin) { v8::Integer::New(env->GetIsolate(), 1), v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()), v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()), - v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl")); + v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"), + v8::True(env->GetIsolate())); v8::Handle<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), "function f() {}\n\nfunction g() {}"); v8::Script::Compile(script, &origin)->Run(); @@ -15579,8 +15946,9 @@ THREADED_TEST(ScriptOrigin) { CHECK_EQ(0, strcmp("test", *v8::String::Utf8Value(script_origin_f.ResourceName()))); CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value()); - CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value()); - CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value()); + CHECK(script_origin_f.Options().IsSharedCrossOrigin()); + CHECK(script_origin_f.Options().IsEmbedderDebugScript()); + CHECK(script_origin_f.Options().IsOpaque()); printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined()); CHECK_EQ(0, strcmp("http://sourceMapUrl", @@ -15590,8 +15958,9 @@ THREADED_TEST(ScriptOrigin) { CHECK_EQ(0, strcmp("test", *v8::String::Utf8Value(script_origin_g.ResourceName()))); CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value()); - CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value()); - CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value()); + CHECK(script_origin_g.Options().IsSharedCrossOrigin()); + CHECK(script_origin_g.Options().IsEmbedderDebugScript()); + CHECK(script_origin_g.Options().IsOpaque()); CHECK_EQ(0, strcmp("http://sourceMapUrl", *v8::String::Utf8Value(script_origin_g.SourceMapUrl()))); } @@ -16419,6 +16788,8 @@ void FailedAccessCheckCallbackGC(Local<v8::Object> target, v8::AccessType type, Local<v8::Value> data) { CcTest::heap()->CollectAllGarbage(); + CcTest::isolate()->ThrowException( + v8::Exception::Error(v8_str("cross context"))); } @@ -16437,7 +16808,7 @@ TEST(GCInFailedAccessCheckCallback) { v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL, - v8::Handle<v8::Value>(), false); + v8::Handle<v8::Value>()); // Create a context and set an x property on it's global object. LocalContext context0(NULL, global_template); @@ -16449,28 +16820,42 @@ TEST(GCInFailedAccessCheckCallback) { LocalContext context1(NULL, global_template); context1->Global()->Set(v8_str("other"), global0); + v8::TryCatch try_catch(isolate); + // Get property with failed access check. - ExpectUndefined("other.x"); + CHECK(CompileRun("other.x").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Get element with failed access check. - ExpectUndefined("other[0]"); + CHECK(CompileRun("other[0]").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Set property with failed access check. - v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); - CHECK(result->IsObject()); + CHECK(CompileRun("other.x = new Object()").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Set element with failed access check. - result = CompileRun("other[0] = new Object()"); - CHECK(result->IsObject()); + CHECK(CompileRun("other[0] = new Object()").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Get property attribute with failed access check. - ExpectFalse("\'x\' in other"); + CHECK(CompileRun("\'x\' in other").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Get property attribute for element with failed access check. - ExpectFalse("0 in other"); + CHECK(CompileRun("0 in other").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Delete property. - ExpectFalse("delete other.x"); + CHECK(CompileRun("delete other.x").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // Delete element. CHECK_EQ(false, global0->Delete(0)); @@ -16480,15 +16865,25 @@ TEST(GCInFailedAccessCheckCallback) { global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); // Define JavaScript accessor. - ExpectUndefined("Object.prototype.__defineGetter__.call(" - " other, \'x\', function() { return 42; })"); + CHECK(CompileRun( + "Object.prototype.__defineGetter__.call(" + " other, \'x\', function() { return 42; })").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // LookupAccessor. - ExpectUndefined("Object.prototype.__lookupGetter__.call(" - " other, \'x\')"); + CHECK(CompileRun( + "Object.prototype.__lookupGetter__.call(" + " other, \'x\')").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); // HasOwnElement. - ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); + CHECK(CompileRun( + "Object.prototype.hasOwnProperty.call(" + "other, \'0\')").IsEmpty()); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); CHECK_EQ(false, global0->HasRealIndexedProperty(0)); CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); @@ -17145,7 +17540,7 @@ TEST(RegExp) { v8::Handle<v8::Value> value(CompileRun("re.property")); CHECK_EQ(32, value->Int32Value()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(context->GetIsolate()); re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); CHECK(re.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -17485,7 +17880,7 @@ void CheckCodeGenerationAllowed() { void CheckCodeGenerationDisallowed() { - TryCatch try_catch; + TryCatch try_catch(CcTest::isolate()); Handle<Value> result = CompileRun("eval('42')"); CHECK(result.IsEmpty()); @@ -17548,7 +17943,7 @@ THREADED_TEST(AllowCodeGenFromStrings) { TEST(SetErrorMessageForCodeGenFromStrings) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); Handle<String> message = v8_str("Message") ; Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); @@ -17575,7 +17970,7 @@ THREADED_TEST(CallAPIFunctionOnNonObject) { v8::FunctionTemplate::New(isolate, NonObjectThis); Handle<Function> function = templ->GetFunction(); context->Global()->Set(v8_str("f"), function); - TryCatch try_catch; + TryCatch try_catch(isolate); CompileRun("f.call(2)"); } @@ -18024,7 +18419,7 @@ TEST(RunMicrotasksIgnoresThrownExceptions) { Function::New(isolate, MicrotaskExceptionOne)); isolate->EnqueueMicrotask( Function::New(isolate, MicrotaskExceptionTwo)); - TryCatch try_catch; + TryCatch try_catch(isolate); CompileRun("1+1;"); CHECK(!try_catch.HasCaught()); CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value()); @@ -18345,7 +18740,7 @@ static void CheckInstanceCheckedResult(int getters, int setters, static void CheckInstanceCheckedAccessors(bool expects_callbacks) { instance_checked_getter_count = 0; instance_checked_setter_count = 0; - TryCatch try_catch; + TryCatch try_catch(CcTest::isolate()); // Test path through generic runtime code. CompileRun("obj.foo"); @@ -18493,7 +18888,7 @@ TEST(TryFinallyMessage) { // Test that the original error message is not lost if there is a // recursive call into Javascript is done in the finally block, e.g. to // initialize an IC. (crbug.com/129171) - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); const char* trigger_ic = "try { \n" " throw new Error('test'); \n" @@ -18511,7 +18906,7 @@ TEST(TryFinallyMessage) { { // Test that the original exception message is indeed overwritten if // a new error is thrown in the finally block. - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); const char* throw_again = "try { \n" " throw new Error('test'); \n" @@ -18681,7 +19076,7 @@ THREADED_TEST(Regress137496) { // Compile a try-finally clause where the finally block causes a GC // while there still is a message pending for external reporting. - TryCatch try_catch; + TryCatch try_catch(context->GetIsolate()); try_catch.SetVerbose(true); CompileRun("try { throw new Error(); } finally { gc(); }"); CHECK(try_catch.HasCaught()); @@ -18859,16 +19254,6 @@ TEST(JSONStringifyAccessCheck) { CHECK(CompileRun("JSON.stringify(other)").IsEmpty()); CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty()); CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty()); - - v8::Handle<v8::Array> array = v8::Array::New(isolate, 2); - array->Set(0, v8_str("a")); - array->Set(1, v8_str("b")); - context1->Global()->Set(v8_str("array"), array); - ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); - array->TurnOnAccessCheck(); - CHECK(CompileRun("JSON.stringify(array)").IsEmpty()); - CHECK(CompileRun("JSON.stringify([array])").IsEmpty()); - CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty()); } } @@ -18924,6 +19309,7 @@ void CheckCorrectThrow(const char* script) { TEST(AccessCheckThrows) { i::FLAG_allow_natives_syntax = true; + i::FLAG_turbo_try_catch = true; v8::V8::Initialize(); v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); v8::Isolate* isolate = CcTest::isolate(); @@ -18953,7 +19339,8 @@ TEST(AccessCheckThrows) { context1->Global()->Set(v8_str("has_own_property"), has_own_property_fun->GetFunction()); - { v8::TryCatch try_catch; + { + v8::TryCatch try_catch(isolate); access_check_fail_thrown = false; CompileRun("other.x;"); CHECK(access_check_fail_thrown); @@ -19570,7 +19957,7 @@ class ApiCallOptimizationChecker { "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" "check(wrap_set());\n", wrap_function.start(), key, key, key, key, key, key); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun(source.start()); DCHECK(!try_catch.HasCaught()); CHECK_EQ(9, count); @@ -19994,7 +20381,7 @@ TEST(ThrowOnJavascriptExecution) { LocalContext context; v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::Isolate::DisallowJavascriptExecutionScope throw_js( isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); CompileRun("1+1"); @@ -20054,7 +20441,7 @@ TEST(CaptureStackTraceForStackOverflow) { v8::HandleScope scope(isolate); V8::SetCaptureStackTraceForUncaughtExceptions( true, 10, v8::StackTrace::kDetailed); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun("(function f(x) { f(x+1); })(0)"); CHECK(try_catch.HasCaught()); } @@ -20295,7 +20682,7 @@ void RunStreamingTest(const char** chunks, LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks), encoding); @@ -20568,6 +20955,7 @@ TEST(StreamingWithDebuggingDoesNotProduceParserCache) { CompileRun("function break_here() { }"); i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast( v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here")))); + EnableDebugger(); v8::internal::Debug* debug = CcTest::i_isolate()->debug(); int position = 0; debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1), @@ -20588,6 +20976,7 @@ TEST(StreamingWithDebuggingDoesNotProduceParserCache) { // Check that we got no cached data. CHECK(source.GetCachedData() == NULL); + DisableDebugger(); } @@ -20667,7 +21056,7 @@ TEST(StreamingWithHarmonyScopes) { // variable again. const char* chunks[] = {"\"use strict\"; let x = 2;", NULL}; - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::ScriptCompiler::StreamedSource source( new TestSourceStream(chunks), v8::ScriptCompiler::StreamedSource::ONE_BYTE); @@ -20695,6 +21084,58 @@ TEST(StreamingWithHarmonyScopes) { } +TEST(CodeCache) { + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + + const char* source = "Math.sqrt(4)"; + const char* origin = "code cache test"; + v8::ScriptCompiler::CachedData* cache; + + v8::Isolate* isolate1 = v8::Isolate::New(create_params); + { + v8::Isolate::Scope iscope(isolate1); + v8::HandleScope scope(isolate1); + v8::Local<v8::Context> context = v8::Context::New(isolate1); + v8::Context::Scope cscope(context); + v8::Local<v8::String> source_string = v8_str(source); + v8::ScriptOrigin script_origin(v8_str(origin)); + v8::ScriptCompiler::Source source(source_string, script_origin); + v8::ScriptCompiler::CompileOptions option = + v8::ScriptCompiler::kProduceCodeCache; + v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked(); + int length = source.GetCachedData()->length; + uint8_t* cache_data = new uint8_t[length]; + memcpy(cache_data, source.GetCachedData()->data, length); + cache = new v8::ScriptCompiler::CachedData( + cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned); + } + isolate1->Dispose(); + + v8::Isolate* isolate2 = v8::Isolate::New(create_params); + { + v8::Isolate::Scope iscope(isolate2); + v8::HandleScope scope(isolate2); + v8::Local<v8::Context> context = v8::Context::New(isolate2); + v8::Context::Scope cscope(context); + v8::Local<v8::String> source_string = v8_str(source); + v8::ScriptOrigin script_origin(v8_str(origin)); + v8::ScriptCompiler::Source source(source_string, script_origin, cache); + v8::ScriptCompiler::CompileOptions option = + v8::ScriptCompiler::kConsumeCodeCache; + v8::Local<v8::Script> script; + { + i::DisallowCompilation no_compile( + reinterpret_cast<i::Isolate*>(isolate2)); + script = v8::ScriptCompiler::Compile(context, &source, option) + .ToLocalChecked(); + } + CHECK_EQ(2, script->Run()->ToInt32(isolate2)->Int32Value()); + } + isolate2->Dispose(); +} + + void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) { const char* garbage = "garbage garbage garbage garbage garbage garbage"; const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage); @@ -20782,7 +21223,7 @@ TEST(StringConcatOverflow) { new RandomLengthOneByteResource(i::String::kMaxLength); v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r); CHECK(!str.IsEmpty()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); v8::Local<v8::String> result = v8::String::Concat(str, str); CHECK(result.IsEmpty()); CHECK(!try_catch.HasCaught()); @@ -20843,7 +21284,7 @@ TEST(GetPrototypeAccessControl) { env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun( "function f() { %_GetPrototype(prohibited); }" "%OptimizeFunctionOnNextCall(f);" @@ -20883,7 +21324,6 @@ TEST(GetPrototypeHidden) { TEST(ClassPrototypeCreationContext) { - i::FLAG_harmony_classes = true; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); LocalContext env; @@ -20927,21 +21367,21 @@ TEST(NewStringRangeError) { if (buffer == NULL) return; memset(buffer, 'A', buffer_size); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); char* data = reinterpret_cast<char*>(buffer); CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString, length).IsEmpty()); CHECK(!try_catch.HasCaught()); } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); uint8_t* data = reinterpret_cast<uint8_t*>(buffer); CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString, length).IsEmpty()); CHECK(!try_catch.HasCaught()); } { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); uint16_t* data = reinterpret_cast<uint16_t*>(buffer); CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString, length).IsEmpty()); @@ -20983,6 +21423,404 @@ TEST(SealHandleScopeNested) { } +static bool access_was_called = false; + + +static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global, + Local<Value> name, v8::AccessType type, + Local<Value> data) { + access_was_called = true; + return true; +} + + +static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global, + Local<Value> name, v8::AccessType type, + Local<Value> data) { + access_was_called = true; + return false; +} + + +TEST(StrongModeAccessCheckAllowed) { + i::FLAG_strong_mode = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle<Value> value; + access_was_called = false; + + v8::Handle<v8::ObjectTemplate> obj_template = + v8::ObjectTemplate::New(isolate); + + obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); + obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL); + + // Create an environment + v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); + context0->Enter(); + v8::Handle<v8::Object> global0 = context0->Global(); + global0->Set(v8_str("object"), obj_template->NewInstance()); + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.x"); + CHECK(!try_catch.HasCaught()); + CHECK(!access_was_called); + CHECK_EQ(42, value->Int32Value()); + } + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.foo"); + CHECK(try_catch.HasCaught()); + CHECK(!access_was_called); + } + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object[10]"); + CHECK(try_catch.HasCaught()); + CHECK(!access_was_called); + } + + // Create an environment + v8::Local<Context> context1 = Context::New(isolate); + context1->Enter(); + v8::Handle<v8::Object> global1 = context1->Global(); + global1->Set(v8_str("object"), obj_template->NewInstance()); + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.x"); + CHECK(!try_catch.HasCaught()); + CHECK(access_was_called); + CHECK_EQ(42, value->Int32Value()); + } + access_was_called = false; + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.foo"); + CHECK(try_catch.HasCaught()); + CHECK(access_was_called); + } + access_was_called = false; + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object[10]"); + CHECK(try_catch.HasCaught()); + CHECK(access_was_called); + } + + context1->Exit(); + context0->Exit(); +} + + +TEST(StrongModeAccessCheckBlocked) { + i::FLAG_strong_mode = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle<Value> value; + access_was_called = false; + + v8::Handle<v8::ObjectTemplate> obj_template = + v8::ObjectTemplate::New(isolate); + + obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); + obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL); + + // Create an environment + v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); + context0->Enter(); + v8::Handle<v8::Object> global0 = context0->Global(); + global0->Set(v8_str("object"), obj_template->NewInstance()); + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.x"); + CHECK(!try_catch.HasCaught()); + CHECK(!access_was_called); + CHECK_EQ(42, value->Int32Value()); + } + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.foo"); + CHECK(try_catch.HasCaught()); + CHECK(!access_was_called); + } + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object[10]"); + CHECK(try_catch.HasCaught()); + CHECK(!access_was_called); + } + + // Create an environment + v8::Local<Context> context1 = Context::New(isolate); + context1->Enter(); + v8::Handle<v8::Object> global1 = context1->Global(); + global1->Set(v8_str("object"), obj_template->NewInstance()); + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.x"); + CHECK(try_catch.HasCaught()); + CHECK(access_was_called); + } + access_was_called = false; + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object.foo"); + CHECK(try_catch.HasCaught()); + CHECK(access_was_called); + } + access_was_called = false; + { + v8::TryCatch try_catch(isolate); + value = CompileRun("'use strong'; object[10]"); + CHECK(try_catch.HasCaught()); + CHECK(access_was_called); + } + + context1->Exit(); + context0->Exit(); +} + + +TEST(StrongModeArityCallFromApi) { + i::FLAG_strong_mode = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + Local<Function> fun; + { + v8::TryCatch try_catch(isolate); + fun = Local<Function>::Cast(CompileRun( + "function f(x) { 'use strong'; }" + "f")); + + CHECK(!try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + fun->Call(v8::Undefined(isolate), 0, nullptr); + CHECK(try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + v8::Handle<Value> args[] = {v8_num(42)}; + fun->Call(v8::Undefined(isolate), arraysize(args), args); + CHECK(!try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + v8::Handle<Value> args[] = {v8_num(42), v8_num(555)}; + fun->Call(v8::Undefined(isolate), arraysize(args), args); + CHECK(!try_catch.HasCaught()); + } +} + + +TEST(StrongModeArityCallFromApi2) { + i::FLAG_strong_mode = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + Local<Function> fun; + { + v8::TryCatch try_catch(isolate); + fun = Local<Function>::Cast(CompileRun( + "'use strong';" + "function f(x) {}" + "f")); + + CHECK(!try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + fun->Call(v8::Undefined(isolate), 0, nullptr); + CHECK(try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + v8::Handle<Value> args[] = {v8_num(42)}; + fun->Call(v8::Undefined(isolate), arraysize(args), args); + CHECK(!try_catch.HasCaught()); + } + + { + v8::TryCatch try_catch(isolate); + v8::Handle<Value> args[] = {v8_num(42), v8_num(555)}; + fun->Call(v8::Undefined(isolate), arraysize(args), args); + CHECK(!try_catch.HasCaught()); + } +} + + +TEST(StrongObjectDelete) { + i::FLAG_strong_mode = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + Local<Object> obj; + { + v8::TryCatch try_catch; + obj = Local<Object>::Cast(CompileRun( + "'use strong';" + "({});")); + CHECK(!try_catch.HasCaught()); + } + obj->ForceSet(v8_str("foo"), v8_num(1), v8::None); + obj->ForceSet(v8_str("2"), v8_num(1), v8::None); + CHECK(obj->HasOwnProperty(v8_str("foo"))); + CHECK(obj->HasOwnProperty(v8_str("2"))); + CHECK(!obj->Delete(v8_str("foo"))); + CHECK(!obj->Delete(2)); +} + + +static void ExtrasExportsTestRuntimeFunction( + const v8::FunctionCallbackInfo<v8::Value>& args) { + CHECK_EQ(3, args[0]->Int32Value()); + args.GetReturnValue().Set(v8_num(7)); +} + + +TEST(ExtrasExportsObject) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + // standalone.gypi ensures we include the test-extra.js file, which should + // export the tested functions. + v8::Local<v8::Object> exports = env->GetExtrasExportsObject(); + + auto func = + exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>(); + auto undefined = v8::Undefined(isolate); + auto result = func->Call(undefined, 0, {}).As<v8::Number>(); + CHECK_EQ(5, result->Int32Value()); + + v8::Handle<v8::FunctionTemplate> runtimeFunction = + v8::FunctionTemplate::New(isolate, ExtrasExportsTestRuntimeFunction); + exports->Set(v8_str("runtime"), runtimeFunction->GetFunction()); + func = + exports->Get(v8_str("testExtraShouldCallToRuntime")).As<v8::Function>(); + result = func->Call(undefined, 0, {}).As<v8::Number>(); + CHECK_EQ(7, result->Int32Value()); +} + + +TEST(Map) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::Local<v8::Map> map = v8::Map::New(isolate); + CHECK(map->IsObject()); + CHECK(map->IsMap()); + CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype"))); + CHECK_EQ(0U, map->Size()); + + v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])"); + CHECK(val->IsMap()); + map = v8::Local<v8::Map>::Cast(val); + CHECK_EQ(2U, map->Size()); + + v8::Local<v8::Array> contents = map->AsArray(); + CHECK_EQ(4U, contents->Length()); + CHECK_EQ(1, contents->Get(0).As<v8::Int32>()->Value()); + CHECK_EQ(2, contents->Get(1).As<v8::Int32>()->Value()); + CHECK_EQ(3, contents->Get(2).As<v8::Int32>()->Value()); + CHECK_EQ(4, contents->Get(3).As<v8::Int32>()->Value()); + + map = v8::Map::FromArray(env.local(), contents).ToLocalChecked(); + CHECK_EQ(2U, map->Size()); + + CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); + CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); + + CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); + CHECK(!map->Has(env.local(), map).FromJust()); + + CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1)) + .ToLocalChecked() + ->Int32Value()); + CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3)) + .ToLocalChecked() + ->Int32Value()); + + CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42)) + .ToLocalChecked() + ->IsUndefined()); + + CHECK(!map->Set(env.local(), map, map).IsEmpty()); + CHECK_EQ(3U, map->Size()); + CHECK(map->Has(env.local(), map).FromJust()); + + CHECK(map->Delete(env.local(), map).FromJust()); + CHECK_EQ(2U, map->Size()); + CHECK(!map->Has(env.local(), map).FromJust()); + CHECK(!map->Delete(env.local(), map).FromJust()); + + map->Clear(); + CHECK_EQ(0U, map->Size()); +} + + +TEST(MapFromArrayOddLength) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + // Odd lengths result in a null MaybeLocal. + Local<v8::Array> contents = v8::Array::New(isolate, 41); + CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty()); +} + + +TEST(Set) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::Local<v8::Set> set = v8::Set::New(isolate); + CHECK(set->IsObject()); + CHECK(set->IsSet()); + CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype"))); + CHECK_EQ(0U, set->Size()); + + v8::Local<v8::Value> val = CompileRun("new Set([1, 2])"); + CHECK(val->IsSet()); + set = v8::Local<v8::Set>::Cast(val); + CHECK_EQ(2U, set->Size()); + + v8::Local<v8::Array> keys = set->AsArray(); + CHECK_EQ(2U, keys->Length()); + CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value()); + CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value()); + + set = v8::Set::FromArray(env.local(), keys).ToLocalChecked(); + CHECK_EQ(2U, set->Size()); + + CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); + CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); + + CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); + CHECK(!set->Has(env.local(), set).FromJust()); + + CHECK(!set->Add(env.local(), set).IsEmpty()); + CHECK_EQ(3U, set->Size()); + CHECK(set->Has(env.local(), set).FromJust()); + + CHECK(set->Delete(env.local(), set).FromJust()); + CHECK_EQ(2U, set->Size()); + CHECK(!set->Has(env.local(), set).FromJust()); + CHECK(!set->Delete(env.local(), set).FromJust()); + + set->Clear(); + CHECK_EQ(0U, set->Size()); +} + + TEST(CompatibleReceiverCheckOnCachedICHandler) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 059c04ad40..8f93150fad 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -175,17 +175,17 @@ TEST(3) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); __ mov(r4, Operand(r0)); - __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i))); + __ ldr(r0, MemOperand(r4, offsetof(T, i))); __ mov(r2, Operand(r0, ASR, 1)); - __ str(r2, MemOperand(r4, OFFSET_OF(T, i))); - __ ldrsb(r2, MemOperand(r4, OFFSET_OF(T, c))); + __ str(r2, MemOperand(r4, offsetof(T, i))); + __ ldrsb(r2, MemOperand(r4, offsetof(T, c))); __ add(r0, r2, Operand(r0)); __ mov(r2, Operand(r2, LSL, 2)); - __ strb(r2, MemOperand(r4, OFFSET_OF(T, c))); - __ ldrsh(r2, MemOperand(r4, OFFSET_OF(T, s))); + __ strb(r2, MemOperand(r4, offsetof(T, c))); + __ ldrsh(r2, MemOperand(r4, offsetof(T, s))); __ add(r0, r2, Operand(r0)); __ mov(r2, Operand(r2, ASR, 3)); - __ strh(r2, MemOperand(r4, OFFSET_OF(T, s))); + __ strh(r2, MemOperand(r4, offsetof(T, s))); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); CodeDesc desc; @@ -247,68 +247,68 @@ TEST(4) { __ sub(fp, ip, Operand(4)); __ mov(r4, Operand(r0)); - __ vldr(d6, r4, OFFSET_OF(T, a)); - __ vldr(d7, r4, OFFSET_OF(T, b)); + __ vldr(d6, r4, offsetof(T, a)); + __ vldr(d7, r4, offsetof(T, b)); __ vadd(d5, d6, d7); - __ vstr(d5, r4, OFFSET_OF(T, c)); + __ vstr(d5, r4, offsetof(T, c)); __ vmla(d5, d6, d7); __ vmls(d5, d5, d6); __ vmov(r2, r3, d5); __ vmov(d4, r2, r3); - __ vstr(d4, r4, OFFSET_OF(T, b)); + __ vstr(d4, r4, offsetof(T, b)); // Load t.x and t.y, switch values, and store back to the struct. - __ vldr(s0, r4, OFFSET_OF(T, x)); - __ vldr(s31, r4, OFFSET_OF(T, y)); + __ vldr(s0, r4, offsetof(T, x)); + __ vldr(s31, r4, offsetof(T, y)); __ vmov(s16, s0); __ vmov(s0, s31); __ vmov(s31, s16); - __ vstr(s0, r4, OFFSET_OF(T, x)); - __ vstr(s31, r4, OFFSET_OF(T, y)); + __ vstr(s0, r4, offsetof(T, x)); + __ vstr(s31, r4, offsetof(T, y)); // Move a literal into a register that can be encoded in the instruction. __ vmov(d4, 1.0); - __ vstr(d4, r4, OFFSET_OF(T, e)); + __ vstr(d4, r4, offsetof(T, e)); // Move a literal into a register that requires 64 bits to encode. // 0x3ff0000010000000 = 1.000000059604644775390625 __ vmov(d4, 1.000000059604644775390625); - __ vstr(d4, r4, OFFSET_OF(T, d)); + __ vstr(d4, r4, offsetof(T, d)); // Convert from floating point to integer. __ vmov(d4, 2.0); __ vcvt_s32_f64(s31, d4); - __ vstr(s31, r4, OFFSET_OF(T, i)); + __ vstr(s31, r4, offsetof(T, i)); // Convert from integer to floating point. __ mov(lr, Operand(42)); __ vmov(s31, lr); __ vcvt_f64_s32(d4, s31); - __ vstr(d4, r4, OFFSET_OF(T, f)); + __ vstr(d4, r4, offsetof(T, f)); // Convert from fixed point to floating point. __ mov(lr, Operand(2468)); __ vmov(s8, lr); __ vcvt_f64_s32(d4, 2); - __ vstr(d4, r4, OFFSET_OF(T, j)); + __ vstr(d4, r4, offsetof(T, j)); // Test vabs. - __ vldr(d1, r4, OFFSET_OF(T, g)); + __ vldr(d1, r4, offsetof(T, g)); __ vabs(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, g)); - __ vldr(d2, r4, OFFSET_OF(T, h)); + __ vstr(d0, r4, offsetof(T, g)); + __ vldr(d2, r4, offsetof(T, h)); __ vabs(d0, d2); - __ vstr(d0, r4, OFFSET_OF(T, h)); + __ vstr(d0, r4, offsetof(T, h)); // Test vneg. - __ vldr(d1, r4, OFFSET_OF(T, m)); + __ vldr(d1, r4, offsetof(T, m)); __ vneg(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, m)); - __ vldr(d1, r4, OFFSET_OF(T, n)); + __ vstr(d0, r4, offsetof(T, m)); + __ vldr(d1, r4, offsetof(T, n)); __ vneg(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, n)); + __ vstr(d0, r4, offsetof(T, n)); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); @@ -647,19 +647,19 @@ TEST(8) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ add(r4, r0, Operand(OFFSET_OF(D, a))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, a)))); __ vldm(ia_w, r4, d0, d3); __ vldm(ia_w, r4, d4, d7); - __ add(r4, r0, Operand(OFFSET_OF(D, a))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, a)))); __ vstm(ia_w, r4, d6, d7); __ vstm(ia_w, r4, d0, d5); - __ add(r4, r1, Operand(OFFSET_OF(F, a))); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, a)))); __ vldm(ia_w, r4, s0, s3); __ vldm(ia_w, r4, s4, s7); - __ add(r4, r1, Operand(OFFSET_OF(F, a))); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, a)))); __ vstm(ia_w, r4, s6, s7); __ vstm(ia_w, r4, s0, s5); @@ -753,22 +753,22 @@ TEST(9) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ add(r4, r0, Operand(OFFSET_OF(D, a))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, a)))); __ vldm(ia, r4, d0, d3); __ add(r4, r4, Operand(4 * 8)); __ vldm(ia, r4, d4, d7); - __ add(r4, r0, Operand(OFFSET_OF(D, a))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, a)))); __ vstm(ia, r4, d6, d7); __ add(r4, r4, Operand(2 * 8)); __ vstm(ia, r4, d0, d5); - __ add(r4, r1, Operand(OFFSET_OF(F, a))); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, a)))); __ vldm(ia, r4, s0, s3); __ add(r4, r4, Operand(4 * 4)); __ vldm(ia, r4, s4, s7); - __ add(r4, r1, Operand(OFFSET_OF(F, a))); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, a)))); __ vstm(ia, r4, s6, s7); __ add(r4, r4, Operand(2 * 4)); __ vstm(ia, r4, s0, s5); @@ -863,19 +863,19 @@ TEST(10) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8)); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, h)) + 8)); __ vldm(db_w, r4, d4, d7); __ vldm(db_w, r4, d0, d3); - __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8)); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(D, h)) + 8)); __ vstm(db_w, r4, d0, d5); __ vstm(db_w, r4, d6, d7); - __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4)); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, h)) + 4)); __ vldm(db_w, r4, s4, s7); __ vldm(db_w, r4, s0, s3); - __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4)); + __ add(r4, r1, Operand(static_cast<int32_t>(offsetof(F, h)) + 4)); __ vstm(db_w, r4, s0, s5); __ vstm(db_w, r4, s6, s7); @@ -951,28 +951,28 @@ TEST(11) { Assembler assm(isolate, NULL, 0); // Test HeapObject untagging. - __ ldr(r1, MemOperand(r0, OFFSET_OF(I, a))); + __ ldr(r1, MemOperand(r0, offsetof(I, a))); __ mov(r1, Operand(r1, ASR, 1), SetCC); __ adc(r1, r1, Operand(r1), LeaveCC, cs); - __ str(r1, MemOperand(r0, OFFSET_OF(I, a))); + __ str(r1, MemOperand(r0, offsetof(I, a))); - __ ldr(r2, MemOperand(r0, OFFSET_OF(I, b))); + __ ldr(r2, MemOperand(r0, offsetof(I, b))); __ mov(r2, Operand(r2, ASR, 1), SetCC); __ adc(r2, r2, Operand(r2), LeaveCC, cs); - __ str(r2, MemOperand(r0, OFFSET_OF(I, b))); + __ str(r2, MemOperand(r0, offsetof(I, b))); // Test corner cases. __ mov(r1, Operand(0xffffffff)); __ mov(r2, Operand::Zero()); __ mov(r3, Operand(r1, ASR, 1), SetCC); // Set the carry. __ adc(r3, r1, Operand(r2)); - __ str(r3, MemOperand(r0, OFFSET_OF(I, c))); + __ str(r3, MemOperand(r0, offsetof(I, c))); __ mov(r1, Operand(0xffffffff)); __ mov(r2, Operand::Zero()); __ mov(r3, Operand(r2, ASR, 1), SetCC); // Unset the carry. __ adc(r3, r1, Operand(r2)); - __ str(r3, MemOperand(r0, OFFSET_OF(I, d))); + __ str(r3, MemOperand(r0, offsetof(I, d))); __ mov(pc, Operand(lr)); @@ -1048,9 +1048,9 @@ TEST(13) { // Load a, b, c into d16, d17, d18. __ mov(r4, Operand(r0)); - __ vldr(d16, r4, OFFSET_OF(T, a)); - __ vldr(d17, r4, OFFSET_OF(T, b)); - __ vldr(d18, r4, OFFSET_OF(T, c)); + __ vldr(d16, r4, offsetof(T, a)); + __ vldr(d17, r4, offsetof(T, b)); + __ vldr(d18, r4, offsetof(T, c)); __ vneg(d25, d16); __ vadd(d25, d25, d17); @@ -1066,12 +1066,12 @@ TEST(13) { // Store d16, d17, d18 into a, b, c. __ mov(r4, Operand(r0)); - __ vstr(d16, r4, OFFSET_OF(T, a)); - __ vstr(d17, r4, OFFSET_OF(T, b)); - __ vstr(d18, r4, OFFSET_OF(T, c)); + __ vstr(d16, r4, offsetof(T, a)); + __ vstr(d17, r4, offsetof(T, b)); + __ vstr(d18, r4, offsetof(T, c)); // Load x, y, z into d29-d31. - __ add(r4, r0, Operand(OFFSET_OF(T, x))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, x)))); __ vldm(ia_w, r4, d29, d31); // Swap d29 and d30 via r registers. @@ -1084,7 +1084,7 @@ TEST(13) { __ vcvt_f64_u32(d31, s1); // Store d29-d31 into x, y, z. - __ add(r4, r0, Operand(OFFSET_OF(T, x))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, x)))); __ vstm(ia_w, r4, d29, d31); // Move constants into d20, d21, d22 and store into i, j, k. @@ -1094,13 +1094,13 @@ TEST(13) { __ mov(r2, Operand(1079146608)); __ vmov(d22, VmovIndexLo, r1); __ vmov(d22, VmovIndexHi, r2); - __ add(r4, r0, Operand(OFFSET_OF(T, i))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, i)))); __ vstm(ia_w, r4, d20, d22); // Move d22 into low and high. __ vmov(r4, VmovIndexLo, d22); - __ str(r4, MemOperand(r0, OFFSET_OF(T, low))); + __ str(r4, MemOperand(r0, offsetof(T, low))); __ vmov(r4, VmovIndexHi, d22); - __ str(r4, MemOperand(r0, OFFSET_OF(T, high))); + __ str(r4, MemOperand(r0, offsetof(T, high))); __ ldm(ia_w, sp, r4.bit() | pc.bit()); @@ -1164,16 +1164,16 @@ TEST(14) { __ vmsr(r1); __ bind(&fpscr_done); - __ vldr(d0, r0, OFFSET_OF(T, left)); - __ vldr(d1, r0, OFFSET_OF(T, right)); + __ vldr(d0, r0, offsetof(T, left)); + __ vldr(d1, r0, offsetof(T, right)); __ vadd(d2, d0, d1); - __ vstr(d2, r0, OFFSET_OF(T, add_result)); + __ vstr(d2, r0, offsetof(T, add_result)); __ vsub(d2, d0, d1); - __ vstr(d2, r0, OFFSET_OF(T, sub_result)); + __ vstr(d2, r0, offsetof(T, sub_result)); __ vmul(d2, d0, d1); - __ vstr(d2, r0, OFFSET_OF(T, mul_result)); + __ vstr(d2, r0, offsetof(T, mul_result)); __ vdiv(d2, d0, d1); - __ vstr(d2, r0, OFFSET_OF(T, div_result)); + __ vstr(d2, r0, offsetof(T, div_result)); __ mov(pc, Operand(lr)); @@ -1264,23 +1264,23 @@ TEST(15) { __ stm(db_w, sp, r4.bit() | lr.bit()); // Move 32 bytes with neon. - __ add(r4, r0, Operand(OFFSET_OF(T, src0))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, src0)))); __ vld1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(r4)); - __ add(r4, r0, Operand(OFFSET_OF(T, dst0))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, dst0)))); __ vst1(Neon8, NeonListOperand(d0, 4), NeonMemOperand(r4)); // Expand 8 bytes into 8 words(16 bits). - __ add(r4, r0, Operand(OFFSET_OF(T, srcA0))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, srcA0)))); __ vld1(Neon8, NeonListOperand(d0), NeonMemOperand(r4)); __ vmovl(NeonU8, q0, d0); - __ add(r4, r0, Operand(OFFSET_OF(T, dstA0))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, dstA0)))); __ vst1(Neon8, NeonListOperand(d0, 2), NeonMemOperand(r4)); // The same expansion, but with different source and destination registers. - __ add(r4, r0, Operand(OFFSET_OF(T, srcA0))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, srcA0)))); __ vld1(Neon8, NeonListOperand(d1), NeonMemOperand(r4)); __ vmovl(NeonU8, q1, d1); - __ add(r4, r0, Operand(OFFSET_OF(T, dstA4))); + __ add(r4, r0, Operand(static_cast<int32_t>(offsetof(T, dstA4)))); __ vst1(Neon8, NeonListOperand(d2, 2), NeonMemOperand(r4)); __ ldm(ia_w, sp, r4.bit() | pc.bit()); @@ -1367,24 +1367,24 @@ TEST(16) { __ stm(db_w, sp, r4.bit() | lr.bit()); __ mov(r4, Operand(r0)); - __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src0))); - __ ldr(r1, MemOperand(r4, OFFSET_OF(T, src1))); + __ ldr(r0, MemOperand(r4, offsetof(T, src0))); + __ ldr(r1, MemOperand(r4, offsetof(T, src1))); __ pkhbt(r2, r0, Operand(r1, LSL, 8)); - __ str(r2, MemOperand(r4, OFFSET_OF(T, dst0))); + __ str(r2, MemOperand(r4, offsetof(T, dst0))); __ pkhtb(r2, r0, Operand(r1, ASR, 8)); - __ str(r2, MemOperand(r4, OFFSET_OF(T, dst1))); + __ str(r2, MemOperand(r4, offsetof(T, dst1))); __ uxtb16(r2, r0, 8); - __ str(r2, MemOperand(r4, OFFSET_OF(T, dst2))); + __ str(r2, MemOperand(r4, offsetof(T, dst2))); __ uxtb(r2, r0, 8); - __ str(r2, MemOperand(r4, OFFSET_OF(T, dst3))); + __ str(r2, MemOperand(r4, offsetof(T, dst3))); - __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2))); + __ ldr(r0, MemOperand(r4, offsetof(T, src2))); __ uxtab(r2, r0, r1, 8); - __ str(r2, MemOperand(r4, OFFSET_OF(T, dst4))); + __ str(r2, MemOperand(r4, offsetof(T, dst4))); __ ldm(ia_w, sp, r4.bit() | pc.bit()); @@ -1461,11 +1461,11 @@ TEST(sdiv) { __ mov(r3, Operand(r0)); - __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend))); - __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor))); + __ ldr(r0, MemOperand(r3, offsetof(T, dividend))); + __ ldr(r1, MemOperand(r3, offsetof(T, divisor))); __ sdiv(r2, r0, r1); - __ str(r2, MemOperand(r3, OFFSET_OF(T, result))); + __ str(r2, MemOperand(r3, offsetof(T, result))); __ bx(lr); @@ -1525,11 +1525,11 @@ TEST(udiv) { __ mov(r3, Operand(r0)); - __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend))); - __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor))); + __ ldr(r0, MemOperand(r3, offsetof(T, dividend))); + __ ldr(r1, MemOperand(r3, offsetof(T, divisor))); __ sdiv(r2, r0, r1); - __ str(r2, MemOperand(r3, OFFSET_OF(T, result))); + __ str(r2, MemOperand(r3, offsetof(T, result))); __ bx(lr); @@ -1917,29 +1917,29 @@ TEST(ARMv8_vrintX) { __ mov(r4, Operand(r0)); // Test vrinta - __ vldr(d6, r4, OFFSET_OF(T, input)); + __ vldr(d6, r4, offsetof(T, input)); __ vrinta(d5, d6); - __ vstr(d5, r4, OFFSET_OF(T, ar)); + __ vstr(d5, r4, offsetof(T, ar)); // Test vrintn - __ vldr(d6, r4, OFFSET_OF(T, input)); + __ vldr(d6, r4, offsetof(T, input)); __ vrintn(d5, d6); - __ vstr(d5, r4, OFFSET_OF(T, nr)); + __ vstr(d5, r4, offsetof(T, nr)); // Test vrintp - __ vldr(d6, r4, OFFSET_OF(T, input)); + __ vldr(d6, r4, offsetof(T, input)); __ vrintp(d5, d6); - __ vstr(d5, r4, OFFSET_OF(T, pr)); + __ vstr(d5, r4, offsetof(T, pr)); // Test vrintm - __ vldr(d6, r4, OFFSET_OF(T, input)); + __ vldr(d6, r4, offsetof(T, input)); __ vrintm(d5, d6); - __ vstr(d5, r4, OFFSET_OF(T, mr)); + __ vstr(d5, r4, offsetof(T, mr)); // Test vrintz - __ vldr(d6, r4, OFFSET_OF(T, input)); + __ vldr(d6, r4, offsetof(T, input)); __ vrintz(d5, d6); - __ vstr(d5, r4, OFFSET_OF(T, zr)); + __ vstr(d5, r4, offsetof(T, zr)); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc index 7a8beaa578..13abbbb447 100644 --- a/deps/v8/test/cctest/test-assembler-mips.cc +++ b/deps/v8/test/cctest/test-assembler-mips.cc @@ -278,61 +278,61 @@ TEST(MIPS3) { Label L, C; // Double precision floating point instructions. - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); __ add_d(f8, f4, f6); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b. + __ sdc1(f8, MemOperand(a0, offsetof(T, c)) ); // c = a + b. __ mov_d(f10, f8); // c __ neg_d(f12, f6); // -b __ sub_d(f10, f10, f12); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b). + __ sdc1(f10, MemOperand(a0, offsetof(T, d)) ); // d = c - (-b). - __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a. + __ sdc1(f4, MemOperand(a0, offsetof(T, b)) ); // b = a. __ li(t0, 120); __ mtc1(t0, f14); __ cvt_d_w(f14, f14); // f14 = 120.0. __ mul_d(f10, f10, f14); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16. + __ sdc1(f10, MemOperand(a0, offsetof(T, e)) ); // e = d * 120 = 1.8066e16. __ div_d(f12, f10, f4); - __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44. + __ sdc1(f12, MemOperand(a0, offsetof(T, f)) ); // f = e / a = 120.44. __ sqrt_d(f14, f12); - __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) ); + __ sdc1(f14, MemOperand(a0, offsetof(T, g)) ); // g = sqrt(f) = 10.97451593465515908537 if (IsMipsArchVariant(kMips32r2)) { - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, h)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, i)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, h)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, i)) ); __ madd_d(f14, f6, f4, f6); - __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) ); + __ sdc1(f14, MemOperand(a0, offsetof(T, h)) ); } // Single precision floating point instructions. - __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fa)) ); - __ lwc1(f6, MemOperand(a0, OFFSET_OF(T, fb)) ); + __ lwc1(f4, MemOperand(a0, offsetof(T, fa)) ); + __ lwc1(f6, MemOperand(a0, offsetof(T, fb)) ); __ add_s(f8, f4, f6); - __ swc1(f8, MemOperand(a0, OFFSET_OF(T, fc)) ); // fc = fa + fb. + __ swc1(f8, MemOperand(a0, offsetof(T, fc)) ); // fc = fa + fb. __ neg_s(f10, f6); // -fb __ sub_s(f10, f8, f10); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, fd)) ); // fd = fc - (-fb). + __ swc1(f10, MemOperand(a0, offsetof(T, fd)) ); // fd = fc - (-fb). - __ swc1(f4, MemOperand(a0, OFFSET_OF(T, fb)) ); // fb = fa. + __ swc1(f4, MemOperand(a0, offsetof(T, fb)) ); // fb = fa. __ li(t0, 120); __ mtc1(t0, f14); __ cvt_s_w(f14, f14); // f14 = 120.0. __ mul_s(f10, f10, f14); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, fe)) ); // fe = fd * 120 + __ swc1(f10, MemOperand(a0, offsetof(T, fe)) ); // fe = fd * 120 __ div_s(f12, f10, f4); - __ swc1(f12, MemOperand(a0, OFFSET_OF(T, ff)) ); // ff = fe / fa + __ swc1(f12, MemOperand(a0, offsetof(T, ff)) ); // ff = fe / fa __ sqrt_s(f14, f12); - __ swc1(f14, MemOperand(a0, OFFSET_OF(T, fg)) ); + __ swc1(f14, MemOperand(a0, offsetof(T, fg)) ); __ jr(ra); __ nop(); @@ -398,8 +398,8 @@ TEST(MIPS4) { Assembler assm(isolate, NULL, 0); Label L, C; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); // Swap f4 and f6, by using four integer registers, t0-t3. if (!IsFp64Mode()) { @@ -425,8 +425,8 @@ TEST(MIPS4) { __ mthc1(t3, f4); } // Store the swapped f4 and f5 back to memory. - __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ sdc1(f6, MemOperand(a0, OFFSET_OF(T, c)) ); + __ sdc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ sdc1(f6, MemOperand(a0, offsetof(T, c)) ); __ jr(ra); __ nop(); @@ -466,30 +466,30 @@ TEST(MIPS5) { Label L, C; // Load all structure elements to registers. - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(T, i)) ); - __ lw(t1, MemOperand(a0, OFFSET_OF(T, j)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); + __ lw(t0, MemOperand(a0, offsetof(T, i)) ); + __ lw(t1, MemOperand(a0, offsetof(T, j)) ); // Convert double in f4 to int in element i. __ cvt_w_d(f8, f4); __ mfc1(t2, f8); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, i)) ); + __ sw(t2, MemOperand(a0, offsetof(T, i)) ); // Convert double in f6 to int in element j. __ cvt_w_d(f10, f6); __ mfc1(t3, f10); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, j)) ); + __ sw(t3, MemOperand(a0, offsetof(T, j)) ); // Convert int in original i (t0) to double in a. __ mtc1(t0, f12); __ cvt_d_w(f0, f12); - __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) ); + __ sdc1(f0, MemOperand(a0, offsetof(T, a)) ); // Convert int in original j (t1) to double in b. __ mtc1(t1, f14); __ cvt_d_w(f2, f14); - __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) ); + __ sdc1(f2, MemOperand(a0, offsetof(T, b)) ); __ jr(ra); __ nop(); @@ -535,31 +535,31 @@ TEST(MIPS6) { Label L, C; // Basic word load/store. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, ui)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, r1)) ); + __ lw(t0, MemOperand(a0, offsetof(T, ui)) ); + __ sw(t0, MemOperand(a0, offsetof(T, r1)) ); // lh with positive data. - __ lh(t1, MemOperand(a0, OFFSET_OF(T, ui)) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, r2)) ); + __ lh(t1, MemOperand(a0, offsetof(T, ui)) ); + __ sw(t1, MemOperand(a0, offsetof(T, r2)) ); // lh with negative data. - __ lh(t2, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, r3)) ); + __ lh(t2, MemOperand(a0, offsetof(T, si)) ); + __ sw(t2, MemOperand(a0, offsetof(T, r3)) ); // lhu with negative data. - __ lhu(t3, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, r4)) ); + __ lhu(t3, MemOperand(a0, offsetof(T, si)) ); + __ sw(t3, MemOperand(a0, offsetof(T, r4)) ); // lb with negative data. - __ lb(t4, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(t4, MemOperand(a0, OFFSET_OF(T, r5)) ); + __ lb(t4, MemOperand(a0, offsetof(T, si)) ); + __ sw(t4, MemOperand(a0, offsetof(T, r5)) ); // sh writes only 1/2 of word. __ lui(t5, 0x3333); __ ori(t5, t5, 0x3333); - __ sw(t5, MemOperand(a0, OFFSET_OF(T, r6)) ); - __ lhu(t5, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sh(t5, MemOperand(a0, OFFSET_OF(T, r6)) ); + __ sw(t5, MemOperand(a0, offsetof(T, r6)) ); + __ lhu(t5, MemOperand(a0, offsetof(T, si)) ); + __ sh(t5, MemOperand(a0, offsetof(T, r6)) ); __ jr(ra); __ nop(); @@ -615,8 +615,8 @@ TEST(MIPS7) { MacroAssembler assm(isolate, NULL, 0); Label neither_is_nan, less_than, outa_here; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); if (!IsMipsArchVariant(kMips32r6)) { __ c(UN, D, f4, f6); __ bc1f(&neither_is_nan); @@ -625,7 +625,7 @@ TEST(MIPS7) { __ bc1eqz(&neither_is_nan, f2); } __ nop(); - __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ sw(zero_reg, MemOperand(a0, offsetof(T, result)) ); __ Branch(&outa_here); __ bind(&neither_is_nan); @@ -642,12 +642,12 @@ TEST(MIPS7) { } __ nop(); - __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ sw(zero_reg, MemOperand(a0, offsetof(T, result)) ); __ Branch(&outa_here); __ bind(&less_than); __ Addu(t0, zero_reg, Operand(1)); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true. + __ sw(t0, MemOperand(a0, offsetof(T, result)) ); // Set true. // This test-case should have additional tests. @@ -706,7 +706,7 @@ TEST(MIPS8) { MacroAssembler assm(isolate, NULL, 0); // Basic word load. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, input)) ); + __ lw(t0, MemOperand(a0, offsetof(T, input)) ); // ROTR instruction (called through the Ror macro). __ Ror(t1, t0, 0x0004); @@ -718,13 +718,13 @@ TEST(MIPS8) { __ Ror(t7, t0, 0x001c); // Basic word store. - __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotr_4)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotr_8)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotr_12)) ); - __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotr_16)) ); - __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotr_20)) ); - __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotr_24)) ); - __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotr_28)) ); + __ sw(t1, MemOperand(a0, offsetof(T, result_rotr_4)) ); + __ sw(t2, MemOperand(a0, offsetof(T, result_rotr_8)) ); + __ sw(t3, MemOperand(a0, offsetof(T, result_rotr_12)) ); + __ sw(t4, MemOperand(a0, offsetof(T, result_rotr_16)) ); + __ sw(t5, MemOperand(a0, offsetof(T, result_rotr_20)) ); + __ sw(t6, MemOperand(a0, offsetof(T, result_rotr_24)) ); + __ sw(t7, MemOperand(a0, offsetof(T, result_rotr_28)) ); // ROTRV instruction (called through the Ror macro). __ li(t7, 0x0004); @@ -743,13 +743,13 @@ TEST(MIPS8) { __ Ror(t7, t0, t7); // Basic word store. - __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotrv_4)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotrv_8)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotrv_12)) ); - __ sw(t4, MemOperand(a0, OFFSET_OF(T, result_rotrv_16)) ); - __ sw(t5, MemOperand(a0, OFFSET_OF(T, result_rotrv_20)) ); - __ sw(t6, MemOperand(a0, OFFSET_OF(T, result_rotrv_24)) ); - __ sw(t7, MemOperand(a0, OFFSET_OF(T, result_rotrv_28)) ); + __ sw(t1, MemOperand(a0, offsetof(T, result_rotrv_4)) ); + __ sw(t2, MemOperand(a0, offsetof(T, result_rotrv_8)) ); + __ sw(t3, MemOperand(a0, offsetof(T, result_rotrv_12)) ); + __ sw(t4, MemOperand(a0, offsetof(T, result_rotrv_16)) ); + __ sw(t5, MemOperand(a0, offsetof(T, result_rotrv_20)) ); + __ sw(t6, MemOperand(a0, offsetof(T, result_rotrv_24)) ); + __ sw(t7, MemOperand(a0, offsetof(T, result_rotrv_28)) ); __ jr(ra); __ nop(); @@ -808,8 +808,9 @@ TEST(MIPS9) { TEST(MIPS10) { - // Test conversions between doubles and long integers. - // Test hos the long ints map to FP regs pairs. + // Test conversions between doubles and words. + // Test maps double to FP reg pairs in fp32 mode + // and into FP reg in fp64 mode. CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -830,24 +831,32 @@ TEST(MIPS10) { if (!IsMipsArchVariant(kMips32r2)) return; // Load all structure elements to registers. - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a))); - - // Save the raw bits of the double. - __ mfc1(t0, f0); - __ mfc1(t1, f1); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, dbl_mant))); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, dbl_exp))); + // (f0, f1) = a (fp32), f0 = a (fp64) + __ ldc1(f0, MemOperand(a0, offsetof(T, a))); + + if (IsFp64Mode()) { + __ mfc1(t0, f0); // t0 = f0(31..0) + __ mfhc1(t1, f0); // t1 = sign_extend(f0(63..32)) + __ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0 + __ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1 + } else { + // Save the raw bits of the double. + __ mfc1(t0, f0); // t0 = a1 + __ mfc1(t1, f1); // t1 = a2 + __ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0 + __ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1 + } - // Convert double in f0 to long, save hi/lo parts. - __ cvt_w_d(f0, f0); - __ mfc1(t0, f0); // f0 has a 32-bits word. - __ sw(t0, MemOperand(a0, OFFSET_OF(T, word))); + // Convert double in f0 to word, save hi/lo parts. + __ cvt_w_d(f0, f0); // a_word = (word)a + __ mfc1(t0, f0); // f0 has a 32-bits word. t0 = a_word + __ sw(t0, MemOperand(a0, offsetof(T, word))); // word = a_word - // Convert the b long integers to double b. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, b_word))); + // Convert the b word to double b. + __ lw(t0, MemOperand(a0, offsetof(T, b_word))); __ mtc1(t0, f8); // f8 has a 32-bits word. __ cvt_d_w(f10, f8); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, b))); + __ sdc1(f10, MemOperand(a0, offsetof(T, b))); __ jr(ra); __ nop(); @@ -861,7 +870,6 @@ TEST(MIPS10) { t.b_word = 0x0ff00ff0; // 0x0FF00FF0 -> 0x as double. Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); USE(dummy); - CHECK_EQ(static_cast<int32_t>(0x41DFFFFF), t.dbl_exp); CHECK_EQ(static_cast<int32_t>(0xFF800000), t.dbl_mant); CHECK_EQ(static_cast<int32_t>(0x7FFFFFFE), t.word); @@ -903,80 +911,80 @@ TEST(MIPS11) { Assembler assm(isolate, NULL, 0); // Test all combinations of LWL and vAddr. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwl(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwl_0)) ); + __ lw(t0, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwl(t0, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t0, MemOperand(a0, offsetof(T, lwl_0)) ); - __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwl(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwl_1)) ); + __ lw(t1, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwl(t1, MemOperand(a0, offsetof(T, mem_init) + 1) ); + __ sw(t1, MemOperand(a0, offsetof(T, lwl_1)) ); - __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwl(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwl_2)) ); + __ lw(t2, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwl(t2, MemOperand(a0, offsetof(T, mem_init) + 2) ); + __ sw(t2, MemOperand(a0, offsetof(T, lwl_2)) ); - __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwl(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwl_3)) ); + __ lw(t3, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwl(t3, MemOperand(a0, offsetof(T, mem_init) + 3) ); + __ sw(t3, MemOperand(a0, offsetof(T, lwl_3)) ); // Test all combinations of LWR and vAddr. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwr(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, lwr_0)) ); + __ lw(t0, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwr(t0, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t0, MemOperand(a0, offsetof(T, lwr_0)) ); - __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwr(t1, MemOperand(a0, OFFSET_OF(T, mem_init) + 1) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, lwr_1)) ); + __ lw(t1, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwr(t1, MemOperand(a0, offsetof(T, mem_init) + 1) ); + __ sw(t1, MemOperand(a0, offsetof(T, lwr_1)) ); - __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwr(t2, MemOperand(a0, OFFSET_OF(T, mem_init) + 2) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, lwr_2)) ); + __ lw(t2, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwr(t2, MemOperand(a0, offsetof(T, mem_init) + 2) ); + __ sw(t2, MemOperand(a0, offsetof(T, lwr_2)) ); - __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ lwr(t3, MemOperand(a0, OFFSET_OF(T, mem_init) + 3) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, lwr_3)) ); + __ lw(t3, MemOperand(a0, offsetof(T, reg_init)) ); + __ lwr(t3, MemOperand(a0, offsetof(T, mem_init) + 3) ); + __ sw(t3, MemOperand(a0, offsetof(T, lwr_3)) ); // Test all combinations of SWL and vAddr. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swl(t0, MemOperand(a0, OFFSET_OF(T, swl_0)) ); - - __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, swl_1)) ); - __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swl(t1, MemOperand(a0, OFFSET_OF(T, swl_1) + 1) ); - - __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, swl_2)) ); - __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swl(t2, MemOperand(a0, OFFSET_OF(T, swl_2) + 2) ); - - __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, swl_3)) ); - __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swl(t3, MemOperand(a0, OFFSET_OF(T, swl_3) + 3) ); + __ lw(t0, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t0, MemOperand(a0, offsetof(T, swl_0)) ); + __ lw(t0, MemOperand(a0, offsetof(T, reg_init)) ); + __ swl(t0, MemOperand(a0, offsetof(T, swl_0)) ); + + __ lw(t1, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t1, MemOperand(a0, offsetof(T, swl_1)) ); + __ lw(t1, MemOperand(a0, offsetof(T, reg_init)) ); + __ swl(t1, MemOperand(a0, offsetof(T, swl_1) + 1) ); + + __ lw(t2, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t2, MemOperand(a0, offsetof(T, swl_2)) ); + __ lw(t2, MemOperand(a0, offsetof(T, reg_init)) ); + __ swl(t2, MemOperand(a0, offsetof(T, swl_2) + 2) ); + + __ lw(t3, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t3, MemOperand(a0, offsetof(T, swl_3)) ); + __ lw(t3, MemOperand(a0, offsetof(T, reg_init)) ); + __ swl(t3, MemOperand(a0, offsetof(T, swl_3) + 3) ); // Test all combinations of SWR and vAddr. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swr(t0, MemOperand(a0, OFFSET_OF(T, swr_0)) ); - - __ lw(t1, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, swr_1)) ); - __ lw(t1, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swr(t1, MemOperand(a0, OFFSET_OF(T, swr_1) + 1) ); - - __ lw(t2, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, swr_2)) ); - __ lw(t2, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swr(t2, MemOperand(a0, OFFSET_OF(T, swr_2) + 2) ); - - __ lw(t3, MemOperand(a0, OFFSET_OF(T, mem_init)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, swr_3)) ); - __ lw(t3, MemOperand(a0, OFFSET_OF(T, reg_init)) ); - __ swr(t3, MemOperand(a0, OFFSET_OF(T, swr_3) + 3) ); + __ lw(t0, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t0, MemOperand(a0, offsetof(T, swr_0)) ); + __ lw(t0, MemOperand(a0, offsetof(T, reg_init)) ); + __ swr(t0, MemOperand(a0, offsetof(T, swr_0)) ); + + __ lw(t1, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t1, MemOperand(a0, offsetof(T, swr_1)) ); + __ lw(t1, MemOperand(a0, offsetof(T, reg_init)) ); + __ swr(t1, MemOperand(a0, offsetof(T, swr_1) + 1) ); + + __ lw(t2, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t2, MemOperand(a0, offsetof(T, swr_2)) ); + __ lw(t2, MemOperand(a0, offsetof(T, reg_init)) ); + __ swr(t2, MemOperand(a0, offsetof(T, swr_2) + 2) ); + + __ lw(t3, MemOperand(a0, offsetof(T, mem_init)) ); + __ sw(t3, MemOperand(a0, offsetof(T, swr_3)) ); + __ lw(t3, MemOperand(a0, offsetof(T, reg_init)) ); + __ swr(t3, MemOperand(a0, offsetof(T, swr_3) + 3) ); __ jr(ra); __ nop(); @@ -1013,7 +1021,7 @@ TEST(MIPS11) { CHECK_EQ(static_cast<int32_t>(0xccdd3344), t.swr_2); CHECK_EQ(static_cast<int32_t>(0xdd223344), t.swr_3); #elif __BYTE_ORDER == __BIG_ENDIAN - 11223344, t.lwl_0); + CHECK_EQ(static_cast<int32_t>(0x11223344), t.lwl_0); CHECK_EQ(static_cast<int32_t>(0x223344dd), t.lwl_1); CHECK_EQ(static_cast<int32_t>(0x3344ccdd), t.lwl_2); CHECK_EQ(static_cast<int32_t>(0x44bbccdd), t.lwl_3); @@ -1057,8 +1065,8 @@ TEST(MIPS12) { __ mov(t6, fp); // Save frame pointer. __ mov(fp, a0); // Access struct T by fp. - __ lw(t0, MemOperand(a0, OFFSET_OF(T, y)) ); - __ lw(t3, MemOperand(a0, OFFSET_OF(T, y4)) ); + __ lw(t0, MemOperand(a0, offsetof(T, y)) ); + __ lw(t3, MemOperand(a0, offsetof(T, y4)) ); __ addu(t1, t0, t3); __ subu(t4, t0, t3); @@ -1076,30 +1084,30 @@ TEST(MIPS12) { __ push(t3); __ pop(t4); __ nop(); - __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) ); - __ lw(t0, MemOperand(fp, OFFSET_OF(T, y)) ); + __ sw(t0, MemOperand(fp, offsetof(T, y)) ); + __ lw(t0, MemOperand(fp, offsetof(T, y)) ); __ nop(); - __ sw(t0, MemOperand(fp, OFFSET_OF(T, y)) ); - __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) ); + __ sw(t0, MemOperand(fp, offsetof(T, y)) ); + __ lw(t1, MemOperand(fp, offsetof(T, y)) ); __ nop(); __ push(t1); - __ lw(t1, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(t1, MemOperand(fp, offsetof(T, y)) ); __ pop(t1); __ nop(); __ push(t1); - __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(t2, MemOperand(fp, offsetof(T, y)) ); __ pop(t1); __ nop(); __ push(t1); - __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(t2, MemOperand(fp, offsetof(T, y)) ); __ pop(t2); __ nop(); __ push(t2); - __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(t2, MemOperand(fp, offsetof(T, y)) ); __ pop(t1); __ nop(); __ push(t1); - __ lw(t2, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(t2, MemOperand(fp, offsetof(T, y)) ); __ pop(t3); __ nop(); @@ -1144,19 +1152,19 @@ TEST(MIPS13) { MacroAssembler assm(isolate, NULL, 0); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_small_in))); + __ sw(t0, MemOperand(a0, offsetof(T, cvt_small_in))); __ Cvt_d_uw(f10, t0, f22); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out))); + __ sdc1(f10, MemOperand(a0, offsetof(T, cvt_small_out))); __ Trunc_uw_d(f10, f10, f22); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out))); + __ swc1(f10, MemOperand(a0, offsetof(T, trunc_small_out))); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, cvt_big_in))); + __ sw(t0, MemOperand(a0, offsetof(T, cvt_big_in))); __ Cvt_d_uw(f8, t0, f22); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out))); + __ sdc1(f8, MemOperand(a0, offsetof(T, cvt_big_out))); __ Trunc_uw_d(f8, f8, f22); - __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out))); + __ swc1(f8, MemOperand(a0, offsetof(T, trunc_big_out))); __ jr(ra); __ nop(); @@ -1226,46 +1234,46 @@ TEST(MIPS14) { // Disable FPU exceptions. __ ctc1(zero_reg, FCSR); #define RUN_ROUND_TEST(x) \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, round_up_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_up_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, round_down_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_down_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, neg_round_up_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, neg_##x##_up_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, neg_round_down_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, neg_##x##_down_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err1_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err1_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err2_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err2_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err3_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err3_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err4_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result))); + __ sw(a2, MemOperand(a0, offsetof(T, x##_err4_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_invalid_result))); RUN_ROUND_TEST(round) RUN_ROUND_TEST(floor) @@ -1329,7 +1337,8 @@ TEST(MIPS15) { } -TEST(MIPS16) { +// ----------------------mips32r6 specific tests---------------------- +TEST(seleqz_selnez) { if (IsMipsArchVariant(kMips32r6)) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -1345,26 +1354,36 @@ TEST(MIPS16) { double f; double g; double h; + float i; + float j; + float k; + float l; } Test; Test test; // Integer part of test. __ addiu(t1, zero_reg, 1); // t1 = 1 __ seleqz(t3, t1, zero_reg); // t3 = 1 - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, a))); // a = 1 + __ sw(t3, MemOperand(a0, offsetof(Test, a))); // a = 1 __ seleqz(t2, t1, t1); // t2 = 0 - __ sw(t2, MemOperand(a0, OFFSET_OF(Test, b))); // b = 0 + __ sw(t2, MemOperand(a0, offsetof(Test, b))); // b = 0 __ selnez(t3, t1, zero_reg); // t3 = 1; - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, c))); // c = 0 + __ sw(t3, MemOperand(a0, offsetof(Test, c))); // c = 0 __ selnez(t3, t1, t1); // t3 = 1 - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, d))); // d = 1 + __ sw(t3, MemOperand(a0, offsetof(Test, d))); // d = 1 // Floating point part of test. - __ ldc1(f0, MemOperand(a0, OFFSET_OF(Test, e)) ); // src - __ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, f)) ); // test - __ seleqz(D, f4, f0, f2); - __ selnez(D, f6, f0, f2); - __ sdc1(f4, MemOperand(a0, OFFSET_OF(Test, g)) ); // src - __ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, h)) ); // src + __ ldc1(f0, MemOperand(a0, offsetof(Test, e)) ); // src + __ ldc1(f2, MemOperand(a0, offsetof(Test, f)) ); // test + __ lwc1(f8, MemOperand(a0, offsetof(Test, i)) ); // src + __ lwc1(f10, MemOperand(a0, offsetof(Test, j)) ); // test + __ seleqz_d(f4, f0, f2); + __ selnez_d(f6, f0, f2); + __ seleqz_s(f12, f8, f10); + __ selnez_s(f14, f8, f10); + __ sdc1(f4, MemOperand(a0, offsetof(Test, g)) ); // src + __ sdc1(f6, MemOperand(a0, offsetof(Test, h)) ); // src + __ swc1(f12, MemOperand(a0, offsetof(Test, k)) ); // src + __ swc1(f14, MemOperand(a0, offsetof(Test, l)) ); // src __ jr(ra); __ nop(); CodeDesc desc; @@ -1383,31 +1402,44 @@ TEST(MIPS16) { const int test_size = 3; const int input_size = 5; - double inputs[input_size] = {0.0, 65.2, -70.32, + double inputs_D[input_size] = {0.0, 65.2, -70.32, 18446744073709551621.0, -18446744073709551621.0}; - double outputs[input_size] = {0.0, 65.2, -70.32, + double outputs_D[input_size] = {0.0, 65.2, -70.32, 18446744073709551621.0, -18446744073709551621.0}; - double tests[test_size*2] = {2.8, 2.9, -2.8, -2.9, + double tests_D[test_size*2] = {2.8, 2.9, -2.8, -2.9, 18446744073709551616.0, 18446744073709555712.0}; + float inputs_S[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float outputs_S[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float tests_S[test_size*2] = {2.9, 2.8, -2.9, -2.8, + 18446744073709551616.0, 18446746272732807168.0}; for (int j=0; j < test_size; j+=2) { for (int i=0; i < input_size; i++) { - test.e = inputs[i]; - test.f = tests[j]; + test.e = inputs_D[i]; + test.f = tests_D[j]; + test.i = inputs_S[i]; + test.j = tests_S[j]; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.g, outputs[i]); + CHECK_EQ(test.g, outputs_D[i]); CHECK_EQ(test.h, 0); + CHECK_EQ(test.k, outputs_S[i]); + CHECK_EQ(test.l, 0); - test.f = tests[j+1]; + test.f = tests_D[j+1]; + test.j = tests_S[j+1]; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.g, 0); - CHECK_EQ(test.h, outputs[i]); + CHECK_EQ(test.h, outputs_D[i]); + CHECK_EQ(test.k, 0); + CHECK_EQ(test.l, outputs_S[i]); } } } } -TEST(MIPS17) { +TEST(min_max) { if (IsMipsArchVariant(kMips32r6)) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -1419,16 +1451,38 @@ TEST(MIPS17) { double b; double c; double d; + float e; + float f; + float g; + float h; } TestFloat; TestFloat test; - - __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a))); - __ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b))); + const double dblNaN = std::numeric_limits<double>::quiet_NaN(); + const float fltNaN = std::numeric_limits<float>::quiet_NaN(); + const int tableLength = 5; + double inputsa[tableLength] = {2.0, 3.0, dblNaN, 3.0, dblNaN}; + double inputsb[tableLength] = {3.0, 2.0, 3.0, dblNaN, dblNaN}; + double outputsdmin[tableLength] = {2.0, 2.0, 3.0, 3.0, dblNaN}; + double outputsdmax[tableLength] = {3.0, 3.0, 3.0, 3.0, dblNaN}; + + float inputse[tableLength] = {2.0, 3.0, fltNaN, 3.0, fltNaN}; + float inputsf[tableLength] = {3.0, 2.0, 3.0, fltNaN, fltNaN}; + float outputsfmin[tableLength] = {2.0, 2.0, 3.0, 3.0, fltNaN}; + float outputsfmax[tableLength] = {3.0, 3.0, 3.0, 3.0, fltNaN}; + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, e))); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, f))); __ min_d(f10, f4, f8); __ max_d(f12, f4, f8); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c))); - __ sdc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, d))); + __ min_s(f14, f2, f6); + __ max_s(f16, f2, f6); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c))); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, d))); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, g))); + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, h))); __ jr(ra); __ nop(); @@ -1437,40 +1491,31 @@ TEST(MIPS17) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); - test.a = 2.0; // a goes to fs - test.b = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 2.0); - CHECK_EQ(test.d, 3.0); - - test.a = 3.0; // a goes to fs - test.b = 2.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 2.0); - CHECK_EQ(test.d, 3.0); - - test.a = std::numeric_limits<double>::quiet_NaN(); - test.b = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 3.0); - CHECK_EQ(test.d, 3.0); + for (int i = 0; i < tableLength; i++) { + test.a = inputsa[i]; + test.b = inputsb[i]; + test.e = inputse[i]; + test.f = inputsf[i]; - test.b = std::numeric_limits<double>::quiet_NaN(); - test.a = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 3.0); - CHECK_EQ(test.d, 3.0); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - test.a = std::numeric_limits<double>::quiet_NaN(); - test.b = std::numeric_limits<double>::quiet_NaN(); - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - DCHECK(std::isnan(test.c)); - DCHECK(std::isnan(test.d)); + if (i < tableLength - 1) { + CHECK_EQ(test.c, outputsdmin[i]); + CHECK_EQ(test.d, outputsdmax[i]); + CHECK_EQ(test.g, outputsfmin[i]); + CHECK_EQ(test.h, outputsfmax[i]); + } else { + DCHECK(std::isnan(test.c)); + DCHECK(std::isnan(test.d)); + DCHECK(std::isnan(test.g)); + DCHECK(std::isnan(test.h)); + } + } } } -TEST(MIPS18) { +TEST(rint_d) { if (IsMipsArchVariant(kMips32r6)) { const int tableLength = 30; CcTest::InitializeVM(); @@ -1548,12 +1593,191 @@ TEST(MIPS18) { int fcsr_inputs[4] = {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; double* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(TestFloat, fcsr)) ); + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, fcsr)) ); __ cfc1(t1, FCSR); __ ctc1(t0, FCSR); __ rint_d(f8, f4); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)) ); + __ sdc1(f8, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ctc1(t1, FCSR); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + for (int j = 0; j < 4; j++) { + test.fcsr = fcsr_inputs[j]; + for (int i = 0; i < tableLength; i++) { + test.a = inputs[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs[j][i]); + } + } + } +} + + +TEST(sel) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test { + double dd; + double ds; + double dt; + float fd; + float fs; + float ft; + } Test; + + Test test; + __ ldc1(f0, MemOperand(a0, offsetof(Test, dd)) ); // test + __ ldc1(f2, MemOperand(a0, offsetof(Test, ds)) ); // src1 + __ ldc1(f4, MemOperand(a0, offsetof(Test, dt)) ); // src2 + __ lwc1(f6, MemOperand(a0, offsetof(Test, fd)) ); // test + __ lwc1(f8, MemOperand(a0, offsetof(Test, fs)) ); // src1 + __ lwc1(f10, MemOperand(a0, offsetof(Test, ft)) ); // src2 + __ sel_d(f0, f2, f4); + __ sel_s(f6, f8, f10); + __ sdc1(f0, MemOperand(a0, offsetof(Test, dd)) ); + __ swc1(f6, MemOperand(a0, offsetof(Test, fd)) ); + __ jr(ra); + __ nop(); + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + const int test_size = 3; + const int input_size = 5; + + double inputs_dt[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + double inputs_ds[input_size] = {0.1, 69.88, -91.325, + 18446744073709551625.0, -18446744073709551625.0}; + float inputs_ft[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float inputs_fs[input_size] = {0.1, 69.88, -91.325, + 18446744073709551625.0, -18446744073709551625.0}; + double tests_D[test_size*2] = {2.8, 2.9, -2.8, -2.9, + 18446744073709551616.0, 18446744073709555712.0}; + float tests_S[test_size*2] = {2.9, 2.8, -2.9, -2.8, + 18446744073709551616.0, 18446746272732807168.0}; + for (int j=0; j < test_size; j+=2) { + for (int i=0; i < input_size; i++) { + test.dt = inputs_dt[i]; + test.dd = tests_D[j]; + test.ds = inputs_ds[i]; + test.ft = inputs_ft[i]; + test.fd = tests_S[j]; + test.fs = inputs_fs[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dd, inputs_ds[i]); + CHECK_EQ(test.fd, inputs_fs[i]); + + test.dd = tests_D[j+1]; + test.fd = tests_S[j+1]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dd, inputs_dt[i]); + CHECK_EQ(test.fd, inputs_ft[i]); + } + } + } +} + + +TEST(rint_s) { + if (IsMipsArchVariant(kMips32r6)) { + const int tableLength = 30; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + int fcsr; + }TestFloat; + + TestFloat test; + float inputs[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E+38, 6.27463370218383111104242366943E-37, + 309485009821345068724781056.89, + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RN[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RZ[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RP[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 1, + 309485009821345068724781057.0, + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RM[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + int fcsr_inputs[4] = + {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; + float* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, fcsr)) ); + __ cfc1(t1, FCSR); + __ ctc1(t0, FCSR); + __ rint_s(f8, f4); + __ swc1(f8, MemOperand(a0, offsetof(TestFloat, b)) ); __ ctc1(t1, FCSR); __ jr(ra); __ nop(); @@ -1568,7 +1792,6 @@ TEST(MIPS18) { test.fcsr = fcsr_inputs[j]; for (int i = 0; i < tableLength; i++) { test.a = inputs[i]; - std::cout << j << " " << i << "\n"; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.b, outputs[j][i]); } @@ -1577,7 +1800,356 @@ TEST(MIPS18) { } -TEST(MIPS19) { +TEST(mina_maxa) { + if (IsMipsArchVariant(kMips32r6)) { + const int tableLength = 12; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + double resd; + double resd1; + float c; + float d; + float resf; + float resf1; + }TestFloat; + + TestFloat test; + double inputsa[tableLength] = { + 5.3, 4.8, 6.1, + 9.8, 9.8, 9.8, + -10.0, -8.9, -9.8, + -10.0, -8.9, -9.8 + }; + double inputsb[tableLength] = { + 4.8, 5.3, 6.1, + -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, + -9.8, -11.2, -9.8 + }; + double resd[tableLength] = { + 4.8, 4.8, 6.1, + 9.8, -8.9, 9.8, + 9.8, -8.9, 9.8, + -9.8, -8.9, -9.8 + }; + double resd1[tableLength] = { + 5.3, 5.3, 6.1, + -10.0, 9.8, 9.8, + -10.0, 9.8, 9.8, + -10.0, -11.2, -9.8 + }; + float inputsc[tableLength] = { + 5.3, 4.8, 6.1, + 9.8, 9.8, 9.8, + -10.0, -8.9, -9.8, + -10.0, -8.9, -9.8 + }; + float inputsd[tableLength] = { + 4.8, 5.3, 6.1, + -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, + -9.8, -11.2, -9.8 + }; + float resf[tableLength] = { + 4.8, 4.8, 6.1, + 9.8, -8.9, 9.8, + 9.8, -8.9, 9.8, + -9.8, -8.9, -9.8 + }; + float resf1[tableLength] = { + 5.3, 5.3, 6.1, + -10.0, 9.8, 9.8, + -10.0, 9.8, 9.8, + -10.0, -11.2, -9.8 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ lwc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ lwc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ mina_d(f6, f2, f4); + __ mina_s(f12, f8, f10); + __ maxa_d(f14, f2, f4); + __ maxa_s(f16, f8, f10); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, resf)) ); + __ sdc1(f6, MemOperand(a0, offsetof(TestFloat, resd)) ); + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, resf1)) ); + __ sdc1(f14, MemOperand(a0, offsetof(TestFloat, resd1)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputsa[i]; + test.b = inputsb[i]; + test.c = inputsc[i]; + test.d = inputsd[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resd, resd[i]); + CHECK_EQ(test.resf, resf[i]); + CHECK_EQ(test.resd1, resd1[i]); + CHECK_EQ(test.resf1, resf1[i]); + } + } +} + + +// ----------------------mips32r2 specific tests---------------------- +TEST(trunc_l) { + if (IsMipsArchVariant(kMips32r2) && IsFp64Mode()) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; // a trunc result + int64_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ trunc_l_d(f8, f4); + __ trunc_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } + } +} + + +TEST(movz_movn) { + if (IsMipsArchVariant(kMips32r2)) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + int64_t rt; + double a; + double b; + double bold; + double b1; + double bold1; + float c; + float d; + float dold; + float d1; + float dold1; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, rt)) ); + __ li(t1, 0x0); + __ mtc1(t1, f12); + __ mtc1(t1, f10); + __ mtc1(t1, f16); + __ mtc1(t1, f14); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, bold)) ); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, dold)) ); + __ sdc1(f16, MemOperand(a0, offsetof(TestFloat, bold1)) ); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, dold1)) ); + __ movz_s(f10, f6, t0); + __ movz_d(f12, f2, t0); + __ movn_s(f14, f6, t0); + __ movn_d(f16, f2, t0); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, b)) ); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, d1)) ); + __ sdc1(f16, MemOperand(a0, offsetof(TestFloat, b1)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.c = inputs_S[i]; + + test.rt = 1; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, test.bold); + CHECK_EQ(test.d, test.dold); + CHECK_EQ(test.b1, outputs_D[i]); + CHECK_EQ(test.d1, outputs_S[i]); + + test.rt = 0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs_D[i]); + CHECK_EQ(test.d, outputs_S[i]); + CHECK_EQ(test.b1, test.bold1); + CHECK_EQ(test.d1, test.dold1); + } + } +} + + +TEST(movt_movd) { + if (IsMipsArchVariant(kMips32r2)) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + + typedef struct test_float { + double srcd; + double dstd; + double dstdold; + double dstd1; + double dstdold1; + float srcf; + float dstf; + float dstfold; + float dstf1; + float dstfold1; + int32_t cc; + int32_t fcsr; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 20.8, -2.9 + }; + double inputs_S[tableLength] = { + 4.88, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.88, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 20.8, -2.9 + }; + int condition_flags[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + + for (int i = 0; i < tableLength; i++) { + test.srcd = inputs_D[i]; + test.srcf = inputs_S[i]; + + for (int j = 0; j< 8; j++) { + test.cc = condition_flags[j]; + if (test.cc == 0) { + test.fcsr = 1 << 23; + } else { + test.fcsr = 1 << (24+condition_flags[j]); + } + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, srcd)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, srcf)) ); + __ lw(t1, MemOperand(a0, offsetof(TestFloat, fcsr)) ); + __ cfc1(t0, FCSR); + __ ctc1(t1, FCSR); + __ li(t2, 0x0); + __ mtc1(t2, f12); + __ mtc1(t2, f10); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstdold)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstfold)) ); + __ movt_s(f12, f4, test.cc); + __ movt_d(f10, f2, test.cc); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstf)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstd)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstdold1)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstfold1)) ); + __ movf_s(f12, f4, test.cc); + __ movf_d(f10, f2, test.cc); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstf1)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstd1)) ); + __ ctc1(t0, FCSR); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dstf, outputs_S[i]); + CHECK_EQ(test.dstd, outputs_D[i]); + CHECK_EQ(test.dstf1, test.dstfold1); + CHECK_EQ(test.dstd1, test.dstdold1); + test.fcsr = 0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dstf, test.dstfold); + CHECK_EQ(test.dstd, test.dstdold); + CHECK_EQ(test.dstf1, outputs_S[i]); + CHECK_EQ(test.dstd1, outputs_D[i]); + } + } + } +} + + +// ----------------------tests for all archs-------------------------- +TEST(cvt_w_d) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -1628,12 +2200,12 @@ TEST(MIPS19) { int fcsr_inputs[4] = {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; double* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(Test, fcsr)) ); + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lw(t0, MemOperand(a0, offsetof(Test, fcsr)) ); __ cfc1(t1, FCSR); __ ctc1(t0, FCSR); __ cvt_w_d(f8, f4); - __ swc1(f8, MemOperand(a0, OFFSET_OF(Test, b)) ); + __ swc1(f8, MemOperand(a0, offsetof(Test, b)) ); __ ctc1(t1, FCSR); __ jr(ra); __ nop(); @@ -1647,7 +2219,6 @@ TEST(MIPS19) { test.fcsr = fcsr_inputs[j]; for (int i = 0; i < tableLength; i++) { test.a = inputs[i]; - std::cout << i << " " << j << "\n"; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.b, outputs[j][i]); } @@ -1655,6 +2226,750 @@ TEST(MIPS19) { } +TEST(trunc_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a trunc result + int32_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ trunc_w_d(f8, f4); + __ trunc_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(round_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a trunc result + int32_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ round_w_d(f8, f4); + __ round_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(round_l) { + if (IsFp64Mode()) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ round_l_d(f8, f4); + __ round_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } + } +} + + +TEST(sub) { + const int tableLength = 12; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + float resultS; + double c; + double d; + double resultD; + }TestFloat; + + TestFloat test; + double inputfs_D[tableLength] = { + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9, + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9 + }; + double inputft_D[tableLength] = { + 4.8, 5.3, 2.9, 4.8, 5.3, 2.9, + -4.8, -5.3, -2.9, -4.8, -5.3, -2.9 + }; + double outputs_D[tableLength] = { + 0.5, -0.5, 0.0, -10.1, -10.1, -5.8, + 10.1, 10.1, 5.8, -0.5, 0.5, 0.0 + }; + float inputfs_S[tableLength] = { + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9, + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9 + }; + float inputft_S[tableLength] = { + 4.8, 5.3, 2.9, 4.8, 5.3, 2.9, + -4.8, -5.3, -2.9, -4.8, -5.3, -2.9 + }; + float outputs_S[tableLength] = { + 0.5, -0.5, 0.0, -10.1, -10.1, -5.8, + 10.1, 10.1, 5.8, -0.5, 0.5, 0.0 + }; + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ ldc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sub_s(f6, f2, f4); + __ sub_d(f12, f8, f10); + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputfs_S[i]; + test.b = inputft_S[i]; + test.c = inputfs_D[i]; + test.d = inputft_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + } +} + + +TEST(sqrt_rsqrt_recip) { + const int tableLength = 4; + const double deltaDouble = 2E-15; + const float deltaFloat = 2E-7; + const float sqrt2_s = sqrt(2); + const double sqrt2_d = sqrt(2); + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float resultS; + float resultS1; + float resultS2; + double c; + double resultD; + double resultD1; + double resultD2; + }TestFloat; + TestFloat test; + + double inputs_D[tableLength] = { + 0.0L, 4.0L, 2.0L, 4e-28L + }; + + double outputs_D[tableLength] = { + 0.0L, 2.0L, sqrt2_d, 2e-14L + }; + float inputs_S[tableLength] = { + 0.0, 4.0, 2.0, 4e-28 + }; + + float outputs_S[tableLength] = { + 0.0, 2.0, sqrt2_s, 2e-14 + }; + + + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ sqrt_s(f6, f2); + __ sqrt_d(f12, f8); + + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + __ rsqrt_d(f14, f8); + __ rsqrt_s(f16, f2); + __ recip_d(f18, f8); + __ recip_s(f20, f2); + } + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, resultS1)) ); + __ sdc1(f14, MemOperand(a0, offsetof(TestFloat, resultD1)) ); + __ swc1(f20, MemOperand(a0, offsetof(TestFloat, resultS2)) ); + __ sdc1(f18, MemOperand(a0, offsetof(TestFloat, resultD2)) ); + } + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + for (int i = 0; i < tableLength; i++) { + float f1; + double d1; + test.a = inputs_S[i]; + test.c = inputs_D[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + if (i != 0) { + f1 = test.resultS1 - 1.0F/outputs_S[i]; + f1 = (f1 < 0) ? f1 : -f1; + CHECK(f1 <= deltaFloat); + d1 = test.resultD1 - 1.0L/outputs_D[i]; + d1 = (d1 < 0) ? d1 : -d1; + CHECK(d1 <= deltaDouble); + f1 = test.resultS2 - 1.0F/inputs_S[i]; + f1 = (f1 < 0) ? f1 : -f1; + CHECK(f1 <= deltaFloat); + d1 = test.resultD2 - 1.0L/inputs_D[i]; + d1 = (d1 < 0) ? d1 : -d1; + CHECK(d1 <= deltaDouble); + } else { + CHECK_EQ(test.resultS1, 1.0F/outputs_S[i]); + CHECK_EQ(test.resultD1, 1.0L/outputs_D[i]); + CHECK_EQ(test.resultS2, 1.0F/inputs_S[i]); + CHECK_EQ(test.resultD2, 1.0L/inputs_D[i]); + } + } + } +} + + +TEST(neg) { + const int tableLength = 3; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float resultS; + double c; + double resultD; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 0.0, 4.0, -2.0 + }; + + double outputs_D[tableLength] = { + 0.0, -4.0, 2.0 + }; + float inputs_S[tableLength] = { + 0.0, 4.0, -2.0 + }; + + float outputs_S[tableLength] = { + 0.0, -4.0, 2.0 + }; + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ neg_s(f6, f2); + __ neg_d(f12, f8); + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_S[i]; + test.c = inputs_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + } +} + + +TEST(mul) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + float resultS; + double c; + double d; + double resultD; + }TestFloat; + + TestFloat test; + double inputfs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputft_D[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float inputfs_S[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + float inputft_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, d)) ); + __ mul_s(f10, f2, f4); + __ mul_d(f12, f6, f8); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputfs_S[i]; + test.b = inputft_S[i]; + test.c = inputfs_D[i]; + test.d = inputft_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, inputfs_S[i]*inputft_S[i]); + CHECK_EQ(test.resultD, inputfs_D[i]*inputft_D[i]); + } +} + + +TEST(mov) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + float c; + float d; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ mov_s(f18, f6); + __ mov_d(f20, f2); + __ swc1(f18, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sdc1(f20, MemOperand(a0, offsetof(TestFloat, b)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.c = inputs_S[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs_D[i]); + CHECK_EQ(test.d, outputs_S[i]); + } +} + + +TEST(floor_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a floor result + int32_t d; // b floor result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ floor_w_d(f8, f4); + __ floor_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(floor_l) { + if (IsFp64Mode()) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ floor_l_d(f8, f4); + __ floor_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } + } +} + + +TEST(ceil_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a floor result + int32_t d; // b floor result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ ceil_w_d(f8, f4); + __ ceil_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(ceil_l) { + if (IsFp64Mode()) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ ceil_l_d(f8, f4); + __ ceil_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } + } +} + + TEST(jump_tables1) { // Test jump tables with forward jumps. CcTest::InitializeVM(); @@ -1869,4 +3184,1879 @@ TEST(jump_tables3) { } +TEST(BITSWAP) { + // Test BITSWAP + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + int32_t r1; + int32_t r2; + int32_t r3; + int32_t r4; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + + __ lw(a2, MemOperand(a0, offsetof(T, r1))); + __ nop(); + __ bitswap(a1, a2); + __ sw(a1, MemOperand(a0, offsetof(T, r1))); + + __ lw(a2, MemOperand(a0, offsetof(T, r2))); + __ nop(); + __ bitswap(a1, a2); + __ sw(a1, MemOperand(a0, offsetof(T, r2))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + t.r1 = 0x781A15C3; + t.r2 = 0x8B71FCDE; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(static_cast<int32_t>(0x1E58A8C3), t.r1); + CHECK_EQ(static_cast<int32_t>(0xD18E3F7B), t.r2); + } +} + + +TEST(class_fmt) { + if (IsMipsArchVariant(kMips32r6)) { + // Test CLASS.fmt instruction. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double dSignalingNan; + double dQuietNan; + double dNegInf; + double dNegNorm; + double dNegSubnorm; + double dNegZero; + double dPosInf; + double dPosNorm; + double dPosSubnorm; + double dPosZero; + float fSignalingNan; + float fQuietNan; + float fNegInf; + float fNegNorm; + float fNegSubnorm; + float fNegZero; + float fPosInf; + float fPosNorm; + float fPosSubnorm; + float fPosZero; } T; + T t; + + // Create a function that accepts &t, and loads, manipulates, and stores + // the doubles t.a ... t.f. + MacroAssembler assm(isolate, NULL, 0); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dSignalingNan))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dSignalingNan))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dQuietNan))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dQuietNan))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegInf))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegInf))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegNorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegNorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegSubnorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegSubnorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegZero))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegZero))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosInf))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosInf))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosNorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosNorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosSubnorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosSubnorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosZero))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosZero))); + + // Testing instruction CLASS.S + __ lwc1(f4, MemOperand(a0, offsetof(T, fSignalingNan))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fSignalingNan))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fQuietNan))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fQuietNan))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegInf))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegInf))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegNorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegNorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegSubnorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegSubnorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegZero))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegZero))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosInf))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosInf))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosNorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosNorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosSubnorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosSubnorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosZero))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosZero))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + t.dSignalingNan = std::numeric_limits<double>::signaling_NaN(); + t.dQuietNan = std::numeric_limits<double>::quiet_NaN(); + t.dNegInf = -1.0 / 0.0; + t.dNegNorm = -5.0; + t.dNegSubnorm = -DBL_MIN / 2.0; + t.dNegZero = -0.0; + t.dPosInf = 2.0 / 0.0; + t.dPosNorm = 275.35; + t.dPosSubnorm = DBL_MIN / 2.0; + t.dPosZero = +0.0; + // Float test values + + t.fSignalingNan = std::numeric_limits<float>::signaling_NaN(); + t.fQuietNan = std::numeric_limits<float>::quiet_NaN(); + t.fNegInf = -0.5/0.0; + t.fNegNorm = -FLT_MIN; + t.fNegSubnorm = -FLT_MIN / 1.5; + t.fNegZero = -0.0; + t.fPosInf = 100000.0 / 0.0; + t.fPosNorm = FLT_MAX; + t.fPosSubnorm = FLT_MIN / 20.0; + t.fPosZero = +0.0; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + // Expected double results. + CHECK_EQ(bit_cast<int64_t>(t.dSignalingNan), 0x001); + CHECK_EQ(bit_cast<int64_t>(t.dQuietNan), 0x002); + CHECK_EQ(bit_cast<int64_t>(t.dNegInf), 0x004); + CHECK_EQ(bit_cast<int64_t>(t.dNegNorm), 0x008); + CHECK_EQ(bit_cast<int64_t>(t.dNegSubnorm), 0x010); + CHECK_EQ(bit_cast<int64_t>(t.dNegZero), 0x020); + CHECK_EQ(bit_cast<int64_t>(t.dPosInf), 0x040); + CHECK_EQ(bit_cast<int64_t>(t.dPosNorm), 0x080); + CHECK_EQ(bit_cast<int64_t>(t.dPosSubnorm), 0x100); + CHECK_EQ(bit_cast<int64_t>(t.dPosZero), 0x200); + + // Expected float results. + CHECK_EQ(bit_cast<int32_t>(t.fSignalingNan), 0x001); + CHECK_EQ(bit_cast<int32_t>(t.fQuietNan), 0x002); + CHECK_EQ(bit_cast<int32_t>(t.fNegInf), 0x004); + CHECK_EQ(bit_cast<int32_t>(t.fNegNorm), 0x008); + CHECK_EQ(bit_cast<int32_t>(t.fNegSubnorm), 0x010); + CHECK_EQ(bit_cast<int32_t>(t.fNegZero), 0x020); + CHECK_EQ(bit_cast<int32_t>(t.fPosInf), 0x040); + CHECK_EQ(bit_cast<int32_t>(t.fPosNorm), 0x080); + CHECK_EQ(bit_cast<int32_t>(t.fPosSubnorm), 0x100); + CHECK_EQ(bit_cast<int32_t>(t.fPosZero), 0x200); + } +} + + +TEST(ABS) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + int64_t fir; + double a; + float b; + double fcsr; + } TestFloat; + + TestFloat test; + + // Save FIR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ abs_d(f10, f4); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, a))); + + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b))); + __ abs_s(f10, f4); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, b))); + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.a = -2.0; + test.b = -2.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, 2.0); + CHECK_EQ(test.b, 2.0); + + test.a = 2.0; + test.b = 2.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, 2.0); + CHECK_EQ(test.b, 2.0); + + // Testing biggest positive number + test.a = std::numeric_limits<double>::max(); + test.b = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max()); + CHECK_EQ(test.b, std::numeric_limits<float>::max()); + + // Testing smallest negative number + test.a = -std::numeric_limits<double>::max(); // lowest() + test.b = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max()); + CHECK_EQ(test.b, std::numeric_limits<float>::max()); + + // Testing smallest positive number + test.a = -std::numeric_limits<double>::min(); + test.b = -std::numeric_limits<float>::min(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::min()); + CHECK_EQ(test.b, std::numeric_limits<float>::min()); + + // Testing infinity + test.a = -std::numeric_limits<double>::max() + / std::numeric_limits<double>::min(); + test.b = -std::numeric_limits<float>::max() + / std::numeric_limits<float>::min(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max() + / std::numeric_limits<double>::min()); + CHECK_EQ(test.b, std::numeric_limits<float>::max() + / std::numeric_limits<float>::min()); + + test.a = std::numeric_limits<double>::quiet_NaN(); + test.b = std::numeric_limits<float>::quiet_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.a), true); + CHECK_EQ(std::isnan(test.b), true); + + test.a = std::numeric_limits<double>::signaling_NaN(); + test.b = std::numeric_limits<float>::signaling_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.a), true); + CHECK_EQ(std::isnan(test.b), true); +} + + +TEST(ADD_FMT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + double c; + float fa; + float fb; + float fc; + } TestFloat; + + TestFloat test; + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); + __ add_d(f10, f8, f4); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c))); + + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, fa))); + __ lwc1(f8, MemOperand(a0, offsetof(TestFloat, fb))); + __ add_s(f10, f8, f4); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, fc))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.a = 2.0; + test.b = 3.0; + test.fa = 2.0; + test.fb = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, 5.0); + CHECK_EQ(test.fc, 5.0); + + test.a = std::numeric_limits<double>::max(); + test.b = -std::numeric_limits<double>::max(); // lowest() + test.fa = std::numeric_limits<float>::max(); + test.fb = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, 0.0); + CHECK_EQ(test.fc, 0.0); + + test.a = std::numeric_limits<double>::max(); + test.b = std::numeric_limits<double>::max(); + test.fa = std::numeric_limits<float>::max(); + test.fb = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isfinite(test.c), false); + CHECK_EQ(std::isfinite(test.fc), false); + + test.a = 5.0; + test.b = std::numeric_limits<double>::signaling_NaN(); + test.fa = 5.0; + test.fb = std::numeric_limits<float>::signaling_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.c), true); + CHECK_EQ(std::isnan(test.fc), true); +} + + +TEST(C_COND_FMT) { + if ((IsMipsArchVariant(kMips32r1)) || (IsMipsArchVariant(kMips32r2))) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double dOp1; + double dOp2; + uint32_t dF; + uint32_t dUn; + uint32_t dEq; + uint32_t dUeq; + uint32_t dOlt; + uint32_t dUlt; + uint32_t dOle; + uint32_t dUle; + float fOp1; + float fOp2; + uint32_t fF; + uint32_t fUn; + uint32_t fEq; + uint32_t fUeq; + uint32_t fOlt; + uint32_t fUlt; + uint32_t fOle; + uint32_t fUle; + } TestFloat; + + TestFloat test; + + __ li(t1, 1); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, dOp1))); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, dOp2))); + + __ lwc1(f14, MemOperand(a0, offsetof(TestFloat, fOp1))); + __ lwc1(f16, MemOperand(a0, offsetof(TestFloat, fOp2))); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(F, f4, f6, 0); + __ c_s(F, f14, f16, 2); + __ movt(t2, t1, 0); + __ movt(t3, t1, 2); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dF)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fF)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(UN, f4, f6, 2); + __ c_s(UN, f14, f16, 4); + __ movt(t2, t1, 2); + __ movt(t3, t1, 4); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUn)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUn)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(EQ, f4, f6, 4); + __ c_s(EQ, f14, f16, 6); + __ movt(t2, t1, 4); + __ movt(t3, t1, 6); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dEq)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fEq)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(UEQ, f4, f6, 6); + __ c_s(UEQ, f14, f16, 0); + __ movt(t2, t1, 6); + __ movt(t3, t1, 0); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUeq)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUeq)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(OLT, f4, f6, 0); + __ c_s(OLT, f14, f16, 2); + __ movt(t2, t1, 0); + __ movt(t3, t1, 2); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dOlt)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fOlt)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(ULT, f4, f6, 2); + __ c_s(ULT, f14, f16, 4); + __ movt(t2, t1, 2); + __ movt(t3, t1, 4); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUlt)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUlt)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(OLE, f4, f6, 4); + __ c_s(OLE, f14, f16, 6); + __ movt(t2, t1, 4); + __ movt(t3, t1, 6); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dOle)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fOle)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(ULE, f4, f6, 6); + __ c_s(ULE, f14, f16, 0); + __ movt(t2, t1, 6); + __ movt(t3, t1, 0); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUle)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUle)) ); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.dOp1 = 2.0; + test.dOp2 = 3.0; + test.fOp1 = 2.0; + test.fOp2 = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 0U); + CHECK_EQ(test.dOlt, 1U); + CHECK_EQ(test.dUlt, 1U); + CHECK_EQ(test.dOle, 1U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 0U); + CHECK_EQ(test.fOlt, 1U); + CHECK_EQ(test.fUlt, 1U); + CHECK_EQ(test.fOle, 1U); + CHECK_EQ(test.fUle, 1U); + + test.dOp1 = std::numeric_limits<double>::max(); + test.dOp2 = std::numeric_limits<double>::min(); + test.fOp1 = std::numeric_limits<float>::min(); + test.fOp2 = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 0U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 0U); + CHECK_EQ(test.dOle, 0U); + CHECK_EQ(test.dUle, 0U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 0U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 0U); + CHECK_EQ(test.fOle, 0U); + CHECK_EQ(test.fUle, 0U); + + test.dOp1 = -std::numeric_limits<double>::max(); // lowest() + test.dOp2 = -std::numeric_limits<double>::max(); // lowest() + test.fOp1 = std::numeric_limits<float>::max(); + test.fOp2 = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 1U); + CHECK_EQ(test.dUeq, 1U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 0U); + CHECK_EQ(test.dOle, 1U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 1U); + CHECK_EQ(test.fUeq, 1U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 0U); + CHECK_EQ(test.fOle, 1U); + CHECK_EQ(test.fUle, 1U); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = 0.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = 0.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 1U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 1U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 1U); + CHECK_EQ(test.dOle, 0U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 1U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 1U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 1U); + CHECK_EQ(test.fOle, 0U); + CHECK_EQ(test.fUle, 1U); + } +} + + +TEST(CMP_COND_FMT) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double dOp1; + double dOp2; + double dF; + double dUn; + double dEq; + double dUeq; + double dOlt; + double dUlt; + double dOle; + double dUle; + double dOr; + double dUne; + double dNe; + float fOp1; + float fOp2; + float fF; + float fUn; + float fEq; + float fUeq; + float fOlt; + float fUlt; + float fOle; + float fUle; + float fOr; + float fUne; + float fNe; + } TestFloat; + + TestFloat test; + + __ li(t1, 1); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, dOp1))); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, dOp2))); + + __ lwc1(f14, MemOperand(a0, offsetof(TestFloat, fOp1))); + __ lwc1(f16, MemOperand(a0, offsetof(TestFloat, fOp2))); + + __ cmp_d(F, f2, f4, f6); + __ cmp_s(F, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dF)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fF)) ); + + __ cmp_d(UN, f2, f4, f6); + __ cmp_s(UN, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUn)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUn)) ); + + __ cmp_d(EQ, f2, f4, f6); + __ cmp_s(EQ, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dEq)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fEq)) ); + + __ cmp_d(UEQ, f2, f4, f6); + __ cmp_s(UEQ, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUeq)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUeq)) ); + + __ cmp_d(LT, f2, f4, f6); + __ cmp_s(LT, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOlt)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOlt)) ); + + __ cmp_d(ULT, f2, f4, f6); + __ cmp_s(ULT, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUlt)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUlt)) ); + + __ cmp_d(LE, f2, f4, f6); + __ cmp_s(LE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOle)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOle)) ); + + __ cmp_d(ULE, f2, f4, f6); + __ cmp_s(ULE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUle)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUle)) ); + + __ cmp_d(ORD, f2, f4, f6); + __ cmp_s(ORD, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOr)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOr)) ); + + __ cmp_d(UNE, f2, f4, f6); + __ cmp_s(UNE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUne)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUne)) ); + + __ cmp_d(NE, f2, f4, f6); + __ cmp_s(NE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dNe)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fNe)) ); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + uint64_t dTrue = 0xFFFFFFFFFFFFFFFF; + uint64_t dFalse = 0x0000000000000000; + uint32_t fTrue = 0xFFFFFFFF; + uint32_t fFalse = 0x00000000; + + test.dOp1 = 2.0; + test.dOp2 = 3.0; + test.fOp1 = 2.0; + test.fOp2 = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + + test.dOp1 = std::numeric_limits<double>::max(); + test.dOp2 = std::numeric_limits<double>::min(); + test.fOp1 = std::numeric_limits<float>::min(); + test.fOp2 = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fFalse); + + test.dOp1 = -std::numeric_limits<double>::max(); // lowest() + test.dOp2 = -std::numeric_limits<double>::max(); // lowest() + test.fOp1 = std::numeric_limits<float>::max(); + test.fOp2 = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = 0.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = 0.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + } +} + + +TEST(CVT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float cvt_d_s_in; + double cvt_d_s_out; + int32_t cvt_d_w_in; + double cvt_d_w_out; + int64_t cvt_d_l_in; + double cvt_d_l_out; + + float cvt_l_s_in; + int64_t cvt_l_s_out; + double cvt_l_d_in; + int64_t cvt_l_d_out; + + double cvt_s_d_in; + float cvt_s_d_out; + int32_t cvt_s_w_in; + float cvt_s_w_out; + int64_t cvt_s_l_in; + float cvt_s_l_out; + + float cvt_w_s_in; + int32_t cvt_w_s_out; + double cvt_w_d_in; + int32_t cvt_w_d_out; + } TestFloat; + + TestFloat test; + + // Save FCSR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + +#define GENERATE_CVT_TEST(x, y, z) \ + __ y##c1(f0, MemOperand(a0, offsetof(TestFloat, x##_in))); \ + __ x(f0, f0); \ + __ nop(); \ + __ z##c1(f0, MemOperand(a0, offsetof(TestFloat, x##_out))); + + GENERATE_CVT_TEST(cvt_d_s, lw, sd) + GENERATE_CVT_TEST(cvt_d_w, lw, sd) + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + GENERATE_CVT_TEST(cvt_d_l, ld, sd) + } + + if (IsFp64Mode()) { + GENERATE_CVT_TEST(cvt_l_s, lw, sd) + GENERATE_CVT_TEST(cvt_l_d, ld, sd) + } + + GENERATE_CVT_TEST(cvt_s_d, ld, sw) + GENERATE_CVT_TEST(cvt_s_w, lw, sw) + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + GENERATE_CVT_TEST(cvt_s_l, ld, sw) + } + + GENERATE_CVT_TEST(cvt_w_s, lw, sw) + GENERATE_CVT_TEST(cvt_w_d, ld, sw) + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + test.cvt_d_s_in = -0.51; + test.cvt_d_w_in = -1; + test.cvt_d_l_in = -1; + test.cvt_l_s_in = -0.51; + test.cvt_l_d_in = -0.51; + test.cvt_s_d_in = -0.51; + test.cvt_s_w_in = -1; + test.cvt_s_l_in = -1; + test.cvt_w_s_in = -0.51; + test.cvt_w_d_in = -0.51; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + } + if (IsFp64Mode()) { + CHECK_EQ(test.cvt_l_s_out, -1); + CHECK_EQ(test.cvt_l_d_out, -1); + } + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + } + CHECK_EQ(test.cvt_w_s_out, -1); + CHECK_EQ(test.cvt_w_d_out, -1); + + + test.cvt_d_s_in = 0.49; + test.cvt_d_w_in = 1; + test.cvt_d_l_in = 1; + test.cvt_l_s_in = 0.49; + test.cvt_l_d_in = 0.49; + test.cvt_s_d_in = 0.49; + test.cvt_s_w_in = 1; + test.cvt_s_l_in = 1; + test.cvt_w_s_in = 0.49; + test.cvt_w_d_in = 0.49; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + } + if (IsFp64Mode()) { + CHECK_EQ(test.cvt_l_s_out, 0); + CHECK_EQ(test.cvt_l_d_out, 0); + } + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + } + CHECK_EQ(test.cvt_w_s_out, 0); + CHECK_EQ(test.cvt_w_d_out, 0); + + test.cvt_d_s_in = std::numeric_limits<float>::max(); + test.cvt_d_w_in = std::numeric_limits<int32_t>::max(); + test.cvt_d_l_in = std::numeric_limits<int64_t>::max(); + test.cvt_l_s_in = std::numeric_limits<float>::max(); + test.cvt_l_d_in = std::numeric_limits<double>::max(); + test.cvt_s_d_in = std::numeric_limits<double>::max(); + test.cvt_s_w_in = std::numeric_limits<int32_t>::max(); + test.cvt_s_l_in = std::numeric_limits<int64_t>::max(); + test.cvt_w_s_in = std::numeric_limits<float>::max(); + test.cvt_w_d_in = std::numeric_limits<double>::max(); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + } + if (IsFp64Mode()) { + CHECK_EQ(test.cvt_l_s_out, std::numeric_limits<int64_t>::max()); + CHECK_EQ(test.cvt_l_d_out, std::numeric_limits<int64_t>::max()); + } + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + } + CHECK_EQ(test.cvt_w_s_out, std::numeric_limits<int32_t>::max()); + CHECK_EQ(test.cvt_w_d_out, std::numeric_limits<int32_t>::max()); + + + test.cvt_d_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_d_w_in = std::numeric_limits<int32_t>::min(); // lowest() + test.cvt_d_l_in = std::numeric_limits<int64_t>::min(); // lowest() + test.cvt_l_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_l_d_in = -std::numeric_limits<double>::max(); // lowest() + test.cvt_s_d_in = -std::numeric_limits<double>::max(); // lowest() + test.cvt_s_w_in = std::numeric_limits<int32_t>::min(); // lowest() + test.cvt_s_l_in = std::numeric_limits<int64_t>::min(); // lowest() + test.cvt_w_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_w_d_in = -std::numeric_limits<double>::max(); // lowest() + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + } + // The returned value when converting from fixed-point to float-point + // is not consistent between board, simulator and specification + // in this test case, therefore modifying the test + if (IsFp64Mode()) { + CHECK(test.cvt_l_s_out == std::numeric_limits<int64_t>::min() || + test.cvt_l_s_out == std::numeric_limits<int64_t>::max()); + CHECK(test.cvt_l_d_out == std::numeric_limits<int64_t>::min() || + test.cvt_l_d_out == std::numeric_limits<int64_t>::max()); + } + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + } + CHECK(test.cvt_w_s_out == std::numeric_limits<int32_t>::min() || + test.cvt_w_s_out == std::numeric_limits<int32_t>::max()); + CHECK(test.cvt_w_d_out == std::numeric_limits<int32_t>::min() || + test.cvt_w_d_out == std::numeric_limits<int32_t>::max()); + + + test.cvt_d_s_in = std::numeric_limits<float>::min(); + test.cvt_d_w_in = std::numeric_limits<int32_t>::min(); + test.cvt_d_l_in = std::numeric_limits<int64_t>::min(); + test.cvt_l_s_in = std::numeric_limits<float>::min(); + test.cvt_l_d_in = std::numeric_limits<double>::min(); + test.cvt_s_d_in = std::numeric_limits<double>::min(); + test.cvt_s_w_in = std::numeric_limits<int32_t>::min(); + test.cvt_s_l_in = std::numeric_limits<int64_t>::min(); + test.cvt_w_s_in = std::numeric_limits<float>::min(); + test.cvt_w_d_in = std::numeric_limits<double>::min(); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + } + if (IsFp64Mode()) { + CHECK_EQ(test.cvt_l_s_out, 0); + CHECK_EQ(test.cvt_l_d_out, 0); + } + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + } + CHECK_EQ(test.cvt_w_s_out, 0); + CHECK_EQ(test.cvt_w_d_out, 0); +} + + +TEST(DIV_FMT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test { + double dOp1; + double dOp2; + double dRes; + float fOp1; + float fOp2; + float fRes; + } Test; + + Test test; + + // Save FCSR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + + __ ldc1(f4, MemOperand(a0, offsetof(Test, dOp1)) ); + __ ldc1(f2, MemOperand(a0, offsetof(Test, dOp2)) ); + __ nop(); + __ div_d(f6, f4, f2); + __ sdc1(f6, MemOperand(a0, offsetof(Test, dRes)) ); + + __ lwc1(f4, MemOperand(a0, offsetof(Test, fOp1)) ); + __ lwc1(f2, MemOperand(a0, offsetof(Test, fOp2)) ); + __ nop(); + __ div_s(f6, f4, f2); + __ swc1(f6, MemOperand(a0, offsetof(Test, fRes)) ); + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + + const int test_size = 3; + + double dOp1[test_size] = { + 5.0, + DBL_MAX, + DBL_MAX, + }; + double dOp2[test_size] = { + 2.0, + 2.0, + -DBL_MAX, + }; + double dRes[test_size] = { + 2.5, + DBL_MAX / 2.0, + -1.0, + }; + float fOp1[test_size] = { + 5.0, + FLT_MAX, + FLT_MAX, + }; + float fOp2[test_size] = { + 2.0, + 2.0, + -FLT_MAX, + }; + float fRes[test_size] = { + 2.5, + FLT_MAX / 2.0, + -1.0, + }; + + for (int i = 0; i < test_size; i++) { + test.dOp1 = dOp1[i]; + test.dOp2 = dOp2[i]; + test.fOp1 = fOp1[i]; + test.fOp2 = fOp2[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dRes, dRes[i]); + CHECK_EQ(test.fRes, fRes[i]); + } + + test.dOp1 = DBL_MAX; + test.dOp2 = -0.0; + test.fOp1 = FLT_MAX; + test.fOp2 = -0.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(false, std::isfinite(test.dRes)); + CHECK_EQ(false, std::isfinite(test.fRes)); + + test.dOp1 = 0.0; + test.dOp2 = -0.0; + test.fOp1 = 0.0; + test.fOp2 = -0.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(true, std::isnan(test.dRes)); + CHECK_EQ(true, std::isnan(test.fRes)); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = -5.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = -5.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(true, std::isnan(test.dRes)); + CHECK_EQ(true, std::isnan(test.fRes)); +} + + +uint32_t run_align(uint32_t rs_value, uint32_t rt_value, uint8_t bp) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ align(v0, a0, a1, bp); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, rs_value, + rt_value, + 0, 0, 0)); + + return res; +} + + +TEST(r6_align) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseAlign { + uint32_t rs_value; + uint32_t rt_value; + uint8_t bp; + uint32_t expected_res; + }; + + struct TestCaseAlign tc[] = { + // rs_value, rt_value, bp, expected_res + { 0x11223344, 0xaabbccdd, 0, 0xaabbccdd }, + { 0x11223344, 0xaabbccdd, 1, 0xbbccdd11 }, + { 0x11223344, 0xaabbccdd, 2, 0xccdd1122 }, + { 0x11223344, 0xaabbccdd, 3, 0xdd112233 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign); + for (size_t i = 0; i < nr_test_cases; ++i) { + CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value, + tc[i].rt_value, tc[i].bp)); + } + } +} + +uint32_t PC; // The program counter. + +uint32_t run_aluipc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ aluipc(v0, offset); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint32_t) f; // Set the program counter. + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_aluipc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseAluipc { + int16_t offset; + }; + + struct TestCaseAluipc tc[] = { + // offset + { -32768 }, // 0x8000 + { -1 }, // 0xFFFF + { 0 }, + { 1 }, + { 32767 }, // 0x7FFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint32_t res = run_aluipc(tc[i].offset); + // Now, the program_counter (PC) is set. + uint32_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16)); + CHECK_EQ(expected_res, res); + } + } +} + + +uint32_t run_auipc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ auipc(v0, offset); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint32_t) f; // Set the program counter. + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_auipc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseAuipc { + int16_t offset; + }; + + struct TestCaseAuipc tc[] = { + // offset + { -32768 }, // 0x8000 + { -1 }, // 0xFFFF + { 0 }, + { 1 }, + { 32767 }, // 0x7FFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint32_t res = run_auipc(tc[i].offset); + // Now, the program_counter (PC) is set. + uint32_t expected_res = PC + (tc[i].offset << 16); + CHECK_EQ(expected_res, res); + } + } +} + + +uint32_t run_lwpc(int offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + // 256k instructions; 2^8k + // addiu t7, t0, 0xffff; (0x250fffff) + // ... + // addiu t4, t0, 0x0000; (0x250c0000) + uint32_t addiu_start_1 = 0x25000000; + for (int32_t i = 0xfffff; i >= 0xc0000; --i) { + uint32_t addiu_new = addiu_start_1 + i; + __ dd(addiu_new); + } + + __ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register) + __ mov(v0, t8); + + // 256k instructions; 2^8k + // addiu t0, t0, 0x0000; (0x25080000) + // ... + // addiu t3, t0, 0xffff; (0x250bffff) + uint32_t addiu_start_2 = 0x25000000; + for (int32_t i = 0x80000; i <= 0xbffff; ++i) { + uint32_t addiu_new = addiu_start_2 + i; + __ dd(addiu_new); + } + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_lwpc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseLwpc { + int offset; + uint32_t expected_res; + }; + + struct TestCaseLwpc tc[] = { + // offset, expected_res + { -262144, 0x250fffff }, // offset 0x40000 + { -4, 0x250c0003 }, + { -1, 0x250c0000 }, + { 0, 0xef080000 }, + { 1, 0x03001025 }, // mov(v0, t8) + { 2, 0x25080000 }, + { 4, 0x25080002 }, + { 262143, 0x250bfffd }, // offset 0x3ffff + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint32_t res = run_lwpc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint32_t run_jic(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label get_program_counter, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t1, 0x66); + + __ addiu(v0, v0, 0x1); // <-- offset = -32 + __ addiu(v0, v0, 0x2); + __ addiu(v0, v0, 0x10); + __ addiu(v0, v0, 0x20); + __ beq(v0, t1, &stop_execution); + __ nop(); + + __ bal(&get_program_counter); // t0 <- program counter + __ nop(); + __ jic(t0, offset); + + __ addiu(v0, v0, 0x100); + __ addiu(v0, v0, 0x200); + __ addiu(v0, v0, 0x1000); + __ addiu(v0, v0, 0x2000); // <--- offset = 16 + __ pop(ra); + __ jr(ra); + __ nop(); + + __ bind(&get_program_counter); + __ mov(t0, ra); + __ jr(ra); + __ nop(); + + __ bind(&stop_execution); + __ pop(ra); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_jic) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseJic { + // As rt will be used t0 register which will have value of + // the program counter for the jic instruction. + int16_t offset; + uint32_t expected_res; + }; + + struct TestCaseJic tc[] = { + // offset, expected_result + { 16, 0x2033 }, + { 4, 0x3333 }, + { -32, 0x66 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint32_t res = run_jic(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_beqzc(int32_t value, int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label stop_execution; + __ li(v0, 0); + __ li(t1, 0x66); + __ push(ra); + + __ addiu(v0, v0, 0x1); // <-- offset = -32 + __ addiu(v0, v0, 0x2); + __ addiu(v0, v0, 0x10); + __ addiu(v0, v0, 0x20); + __ beq(v0, t1, &stop_execution); + __ nop(); + + __ beqzc(a0, offset); // BEQZC rs, offset + + __ addiu(v0, v0, 0x1); + __ addiu(v0, v0, 0x100); + __ addiu(v0, v0, 0x200); + __ addiu(v0, v0, 0x1000); + __ addiu(v0, v0, 0x2000); // <--- offset = 16 + __ jr(ra); + __ nop(); + + __ bind(&stop_execution); + __ pop(ra); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_beqzc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseBeqzc { + uint32_t value; + int32_t offset; + uint32_t expected_res; + }; + + struct TestCaseBeqzc tc[] = { + // value, offset, expected_res + { 0x0, -8, 0x66 }, + { 0x0, 0, 0x3334 }, + { 0x0, 1, 0x3333 }, + { 0xabc, 1, 0x3334 }, + { 0x0, 4, 0x2033 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint32_t res = run_beqzc(tc[i].value, tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint32_t run_jialc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label main_block, get_program_counter; + __ push(ra); + __ li(v0, 0); + __ beq(v0, v0, &main_block); + __ nop(); + + // Block 1 + __ addiu(v0, v0, 0x1); // <-- offset = -40 + __ addiu(v0, v0, 0x2); + __ jr(ra); + __ nop(); + + // Block 2 + __ addiu(v0, v0, 0x10); // <-- offset = -24 + __ addiu(v0, v0, 0x20); + __ jr(ra); + __ nop(); + + // Block 3 (Main) + __ bind(&main_block); + __ bal(&get_program_counter); // t0 <- program counter + __ nop(); + __ jialc(t0, offset); + __ addiu(v0, v0, 0x4); + __ pop(ra); + __ jr(ra); + __ nop(); + + // Block 4 + __ addiu(v0, v0, 0x100); // <-- offset = 20 + __ addiu(v0, v0, 0x200); + __ jr(ra); + __ nop(); + + // Block 5 + __ addiu(v0, v0, 0x1000); // <--- offset = 36 + __ addiu(v0, v0, 0x2000); + __ jr(ra); + __ nop(); + + __ bind(&get_program_counter); + __ mov(t0, ra); + __ jr(ra); + __ nop(); + + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint32_t res = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_jialc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseJialc { + int16_t offset; + uint32_t expected_res; + }; + + struct TestCaseJialc tc[] = { + // offset, expected_res + { -40, 0x7 }, + { -24, 0x34 }, + { 20, 0x304 }, + { 36, 0x3004 } + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint32_t res = run_jialc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_addiupc(int32_t imm19) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ addiupc(v0, imm19); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint32_t) f; // Set the program counter. + + uint32_t rs = + reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, imm19, 0, 0, 0, 0)); + + return rs; +} + + +TEST(r6_addiupc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseAddiupc { + int32_t imm19; + }; + + struct TestCaseAddiupc tc[] = { + // imm19 + { -262144 }, // 0x40000 + { -1 }, // 0x7FFFF + { 0 }, + { 1 }, // 0x00001 + { 262143 } // 0x3FFFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint32_t res = run_addiupc(tc[i].imm19); + // Now, the program_counter (PC) is set. + uint32_t expected_res = PC + (tc[i].imm19 << 2); + CHECK_EQ(expected_res, res); + } + } +} + + +int32_t run_bc(int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label continue_1, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t8, 0); + __ li(t9, 2); // A condition for stopping execution. + + uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1 + for (int32_t i = -100; i <= -11; ++i) { + __ dd(instruction_addiu); + } + + __ addiu(t8, t8, 1); // -10 + + __ beq(t8, t9, &stop_execution); // -9 + __ nop(); // -8 + __ beq(t8, t8, &continue_1); // -7 + __ nop(); // -6 + + __ bind(&stop_execution); + __ pop(ra); // -5, -4 + __ jr(ra); // -3 + __ nop(); // -2 + + __ bind(&continue_1); + __ bc(offset); // -1 + + for (int32_t i = 0; i <= 99; ++i) { + __ dd(instruction_addiu); + } + + __ pop(ra); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + int32_t res = + reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_bc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseBc { + int32_t offset; + int32_t expected_res; + }; + + struct TestCaseBc tc[] = { + // offset, expected_result + { -100, (abs(-100) - 10) * 2 }, + { -11, (abs(-100) - 10 + 1) }, + { 0, (abs(-100) - 10 + 1 + 99) }, + { 1, (abs(-100) - 10 + 99) }, + { 99, (abs(-100) - 10 + 1) }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc); + for (size_t i = 0; i < nr_test_cases; ++i) { + int32_t res = run_bc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +int32_t run_balc(int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label continue_1, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t8, 0); + __ li(t9, 2); // A condition for stopping execution. + + __ beq(t8, t8, &continue_1); + __ nop(); + + uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1 + for (int32_t i = -117; i <= -57; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); // -56 + __ nop(); // -55 + + for (int32_t i = -54; i <= -4; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); // -3 + __ nop(); // -2 + + __ bind(&continue_1); + __ balc(offset); // -1 + + __ pop(ra); // 0, 1 + __ jr(ra); // 2 + __ nop(); // 3 + + for (int32_t i = 4; i <= 44; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + int32_t res = + reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_balc) { + if (IsMipsArchVariant(kMips32r6)) { + CcTest::InitializeVM(); + + struct TestCaseBalc { + int32_t offset; + int32_t expected_res; + }; + + struct TestCaseBalc tc[] = { + // offset, expected_result + { -117, 61 }, + { -54, 51 }, + { 0, 0 }, + { 4, 41 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc); + for (size_t i = 0; i < nr_test_cases; ++i) { + int32_t res = run_balc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + #undef __ diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc index 3b422a2716..bb7b05ca76 100644 --- a/deps/v8/test/cctest/test-assembler-mips64.cc +++ b/deps/v8/test/cctest/test-assembler-mips64.cc @@ -45,6 +45,7 @@ using namespace v8::internal; typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4); typedef Object* (*F2)(int x, int y, int p2, int p3, int p4); typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); +typedef Object* (*F4)(int64_t x, int64_t y, int64_t p2, int64_t p3, int64_t p4); // clang-format off @@ -289,61 +290,61 @@ TEST(MIPS3) { Label L, C; // Double precision floating point instructions. - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); __ add_d(f8, f4, f6); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, c)) ); // c = a + b. + __ sdc1(f8, MemOperand(a0, offsetof(T, c)) ); // c = a + b. __ mov_d(f10, f8); // c __ neg_d(f12, f6); // -b __ sub_d(f10, f10, f12); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, d)) ); // d = c - (-b). + __ sdc1(f10, MemOperand(a0, offsetof(T, d)) ); // d = c - (-b). - __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, b)) ); // b = a. + __ sdc1(f4, MemOperand(a0, offsetof(T, b)) ); // b = a. __ li(a4, 120); __ mtc1(a4, f14); __ cvt_d_w(f14, f14); // f14 = 120.0. __ mul_d(f10, f10, f14); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, e)) ); // e = d * 120 = 1.8066e16. + __ sdc1(f10, MemOperand(a0, offsetof(T, e)) ); // e = d * 120 = 1.8066e16. __ div_d(f12, f10, f4); - __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44. + __ sdc1(f12, MemOperand(a0, offsetof(T, f)) ); // f = e / a = 120.44. __ sqrt_d(f14, f12); - __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, g)) ); + __ sdc1(f14, MemOperand(a0, offsetof(T, g)) ); // g = sqrt(f) = 10.97451593465515908537 if (kArchVariant == kMips64r2) { - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, h)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, i)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, h)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, i)) ); __ madd_d(f14, f6, f4, f6); - __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) ); + __ sdc1(f14, MemOperand(a0, offsetof(T, h)) ); } // Single precision floating point instructions. - __ lwc1(f4, MemOperand(a0, OFFSET_OF(T, fa)) ); - __ lwc1(f6, MemOperand(a0, OFFSET_OF(T, fb)) ); + __ lwc1(f4, MemOperand(a0, offsetof(T, fa)) ); + __ lwc1(f6, MemOperand(a0, offsetof(T, fb)) ); __ add_s(f8, f4, f6); - __ swc1(f8, MemOperand(a0, OFFSET_OF(T, fc)) ); // fc = fa + fb. + __ swc1(f8, MemOperand(a0, offsetof(T, fc)) ); // fc = fa + fb. __ neg_s(f10, f6); // -fb __ sub_s(f10, f8, f10); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, fd)) ); // fd = fc - (-fb). + __ swc1(f10, MemOperand(a0, offsetof(T, fd)) ); // fd = fc - (-fb). - __ swc1(f4, MemOperand(a0, OFFSET_OF(T, fb)) ); // fb = fa. + __ swc1(f4, MemOperand(a0, offsetof(T, fb)) ); // fb = fa. __ li(t0, 120); __ mtc1(t0, f14); __ cvt_s_w(f14, f14); // f14 = 120.0. __ mul_s(f10, f10, f14); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, fe)) ); // fe = fd * 120 + __ swc1(f10, MemOperand(a0, offsetof(T, fe)) ); // fe = fd * 120 __ div_s(f12, f10, f4); - __ swc1(f12, MemOperand(a0, OFFSET_OF(T, ff)) ); // ff = fe / fa + __ swc1(f12, MemOperand(a0, offsetof(T, ff)) ); // ff = fe / fa __ sqrt_s(f14, f12); - __ swc1(f14, MemOperand(a0, OFFSET_OF(T, fg)) ); + __ swc1(f14, MemOperand(a0, offsetof(T, fg)) ); __ jr(ra); __ nop(); @@ -412,8 +413,8 @@ TEST(MIPS4) { Assembler assm(isolate, NULL, 0); Label L, C; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a))); - __ ldc1(f5, MemOperand(a0, OFFSET_OF(T, b))); + __ ldc1(f4, MemOperand(a0, offsetof(T, a))); + __ ldc1(f5, MemOperand(a0, offsetof(T, b))); // Swap f4 and f5, by using 3 integer registers, a4-a6, // both two 32-bit chunks, and one 64-bit chunk. @@ -428,16 +429,16 @@ TEST(MIPS4) { __ dmtc1(a6, f4); // Store the swapped f4 and f5 back to memory. - __ sdc1(f4, MemOperand(a0, OFFSET_OF(T, a))); - __ sdc1(f5, MemOperand(a0, OFFSET_OF(T, c))); + __ sdc1(f4, MemOperand(a0, offsetof(T, a))); + __ sdc1(f5, MemOperand(a0, offsetof(T, c))); // Test sign extension of move operations from coprocessor. - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, d))); + __ ldc1(f4, MemOperand(a0, offsetof(T, d))); __ mfhc1(a4, f4); __ mfc1(a5, f4); - __ sd(a4, MemOperand(a0, OFFSET_OF(T, high))); - __ sd(a5, MemOperand(a0, OFFSET_OF(T, low))); + __ sd(a4, MemOperand(a0, offsetof(T, high))); + __ sd(a5, MemOperand(a0, offsetof(T, low))); __ jr(ra); __ nop(); @@ -480,30 +481,30 @@ TEST(MIPS5) { Label L, C; // Load all structure elements to registers. - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); - __ lw(a4, MemOperand(a0, OFFSET_OF(T, i)) ); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, j)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); + __ lw(a4, MemOperand(a0, offsetof(T, i)) ); + __ lw(a5, MemOperand(a0, offsetof(T, j)) ); // Convert double in f4 to int in element i. __ cvt_w_d(f8, f4); __ mfc1(a6, f8); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, i)) ); + __ sw(a6, MemOperand(a0, offsetof(T, i)) ); // Convert double in f6 to int in element j. __ cvt_w_d(f10, f6); __ mfc1(a7, f10); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, j)) ); + __ sw(a7, MemOperand(a0, offsetof(T, j)) ); // Convert int in original i (a4) to double in a. __ mtc1(a4, f12); __ cvt_d_w(f0, f12); - __ sdc1(f0, MemOperand(a0, OFFSET_OF(T, a)) ); + __ sdc1(f0, MemOperand(a0, offsetof(T, a)) ); // Convert int in original j (a5) to double in b. __ mtc1(a5, f14); __ cvt_d_w(f2, f14); - __ sdc1(f2, MemOperand(a0, OFFSET_OF(T, b)) ); + __ sdc1(f2, MemOperand(a0, offsetof(T, b)) ); __ jr(ra); __ nop(); @@ -549,31 +550,31 @@ TEST(MIPS6) { Label L, C; // Basic word load/store. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, ui)) ); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, r1)) ); + __ lw(a4, MemOperand(a0, offsetof(T, ui)) ); + __ sw(a4, MemOperand(a0, offsetof(T, r1)) ); // lh with positive data. - __ lh(a5, MemOperand(a0, OFFSET_OF(T, ui)) ); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, r2)) ); + __ lh(a5, MemOperand(a0, offsetof(T, ui)) ); + __ sw(a5, MemOperand(a0, offsetof(T, r2)) ); // lh with negative data. - __ lh(a6, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, r3)) ); + __ lh(a6, MemOperand(a0, offsetof(T, si)) ); + __ sw(a6, MemOperand(a0, offsetof(T, r3)) ); // lhu with negative data. - __ lhu(a7, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, r4)) ); + __ lhu(a7, MemOperand(a0, offsetof(T, si)) ); + __ sw(a7, MemOperand(a0, offsetof(T, r4)) ); // lb with negative data. - __ lb(t0, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, r5)) ); + __ lb(t0, MemOperand(a0, offsetof(T, si)) ); + __ sw(t0, MemOperand(a0, offsetof(T, r5)) ); // sh writes only 1/2 of word. __ lui(t1, 0x3333); __ ori(t1, t1, 0x3333); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, r6)) ); - __ lhu(t1, MemOperand(a0, OFFSET_OF(T, si)) ); - __ sh(t1, MemOperand(a0, OFFSET_OF(T, r6)) ); + __ sw(t1, MemOperand(a0, offsetof(T, r6)) ); + __ lhu(t1, MemOperand(a0, offsetof(T, si)) ); + __ sh(t1, MemOperand(a0, offsetof(T, r6)) ); __ jr(ra); __ nop(); @@ -619,8 +620,8 @@ TEST(MIPS7) { MacroAssembler assm(isolate, NULL, 0); Label neither_is_nan, less_than, outa_here; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); - __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ ldc1(f4, MemOperand(a0, offsetof(T, a)) ); + __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); if (kArchVariant != kMips64r6) { __ c(UN, D, f4, f6); __ bc1f(&neither_is_nan); @@ -629,7 +630,7 @@ TEST(MIPS7) { __ bc1eqz(&neither_is_nan, f2); } __ nop(); - __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ sw(zero_reg, MemOperand(a0, offsetof(T, result)) ); __ Branch(&outa_here); __ bind(&neither_is_nan); @@ -643,12 +644,12 @@ TEST(MIPS7) { } __ nop(); - __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ sw(zero_reg, MemOperand(a0, offsetof(T, result)) ); __ Branch(&outa_here); __ bind(&less_than); __ Addu(a4, zero_reg, Operand(1)); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true. + __ sw(a4, MemOperand(a0, offsetof(T, result)) ); // Set true. // This test-case should have additional tests. @@ -707,7 +708,7 @@ TEST(MIPS8) { MacroAssembler assm(isolate, NULL, 0); // Basic word load. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, input)) ); + __ lw(a4, MemOperand(a0, offsetof(T, input)) ); // ROTR instruction (called through the Ror macro). __ Ror(a5, a4, 0x0004); @@ -719,13 +720,13 @@ TEST(MIPS8) { __ Ror(t3, a4, 0x001c); // Basic word store. - __ sw(a5, MemOperand(a0, OFFSET_OF(T, result_rotr_4)) ); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, result_rotr_8)) ); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, result_rotr_12)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, result_rotr_16)) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotr_20)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotr_24)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotr_28)) ); + __ sw(a5, MemOperand(a0, offsetof(T, result_rotr_4)) ); + __ sw(a6, MemOperand(a0, offsetof(T, result_rotr_8)) ); + __ sw(a7, MemOperand(a0, offsetof(T, result_rotr_12)) ); + __ sw(t0, MemOperand(a0, offsetof(T, result_rotr_16)) ); + __ sw(t1, MemOperand(a0, offsetof(T, result_rotr_20)) ); + __ sw(t2, MemOperand(a0, offsetof(T, result_rotr_24)) ); + __ sw(t3, MemOperand(a0, offsetof(T, result_rotr_28)) ); // ROTRV instruction (called through the Ror macro). __ li(t3, 0x0004); @@ -744,13 +745,13 @@ TEST(MIPS8) { __ Ror(t3, a4, t3); // Basic word store. - __ sw(a5, MemOperand(a0, OFFSET_OF(T, result_rotrv_4)) ); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, result_rotrv_8)) ); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, result_rotrv_12)) ); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, result_rotrv_16)) ); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, result_rotrv_20)) ); - __ sw(t2, MemOperand(a0, OFFSET_OF(T, result_rotrv_24)) ); - __ sw(t3, MemOperand(a0, OFFSET_OF(T, result_rotrv_28)) ); + __ sw(a5, MemOperand(a0, offsetof(T, result_rotrv_4)) ); + __ sw(a6, MemOperand(a0, offsetof(T, result_rotrv_8)) ); + __ sw(a7, MemOperand(a0, offsetof(T, result_rotrv_12)) ); + __ sw(t0, MemOperand(a0, offsetof(T, result_rotrv_16)) ); + __ sw(t1, MemOperand(a0, offsetof(T, result_rotrv_20)) ); + __ sw(t2, MemOperand(a0, offsetof(T, result_rotrv_24)) ); + __ sw(t3, MemOperand(a0, offsetof(T, result_rotrv_28)) ); __ jr(ra); __ nop(); @@ -838,42 +839,42 @@ TEST(MIPS10) { // - 32 FP regs of 64-bits each, no odd/even pairs. // - Note that cvt_l_d/cvt_d_l ARE legal in FR=1 mode. // Load all structure elements to registers. - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, a))); + __ ldc1(f0, MemOperand(a0, offsetof(T, a))); // Save the raw bits of the double. __ mfc1(a4, f0); __ mfhc1(a5, f0); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, dbl_mant))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, dbl_exp))); + __ sw(a4, MemOperand(a0, offsetof(T, dbl_mant))); + __ sw(a5, MemOperand(a0, offsetof(T, dbl_exp))); // Convert double in f0 to long, save hi/lo parts. __ cvt_l_d(f0, f0); __ mfc1(a4, f0); // f0 LS 32 bits of long. __ mfhc1(a5, f0); // f0 MS 32 bits of long. - __ sw(a4, MemOperand(a0, OFFSET_OF(T, long_lo))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, long_hi))); + __ sw(a4, MemOperand(a0, offsetof(T, long_lo))); + __ sw(a5, MemOperand(a0, offsetof(T, long_hi))); // Combine the high/low ints, convert back to double. __ dsll32(a6, a5, 0); // Move a5 to high bits of a6. __ or_(a6, a6, a4); __ dmtc1(a6, f1); __ cvt_d_l(f1, f1); - __ sdc1(f1, MemOperand(a0, OFFSET_OF(T, a_converted))); + __ sdc1(f1, MemOperand(a0, offsetof(T, a_converted))); // Convert the b long integers to double b. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, b_long_lo))); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, b_long_hi))); + __ lw(a4, MemOperand(a0, offsetof(T, b_long_lo))); + __ lw(a5, MemOperand(a0, offsetof(T, b_long_hi))); __ mtc1(a4, f8); // f8 LS 32-bits. __ mthc1(a5, f8); // f8 MS 32-bits. __ cvt_d_l(f10, f8); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, b))); + __ sdc1(f10, MemOperand(a0, offsetof(T, b))); // Convert double b back to long-int. - __ ldc1(f31, MemOperand(a0, OFFSET_OF(T, b))); + __ ldc1(f31, MemOperand(a0, offsetof(T, b))); __ cvt_l_d(f31, f31); __ dmfc1(a7, f31); - __ sd(a7, MemOperand(a0, OFFSET_OF(T, b_long_as_int64))); + __ sd(a7, MemOperand(a0, offsetof(T, b_long_as_int64))); __ jr(ra); @@ -936,80 +937,80 @@ TEST(MIPS11) { Assembler assm(isolate, NULL, 0); // Test all combinations of LWL and vAddr. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwl(a4, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, lwl_0))); + __ lw(a4, MemOperand(a0, offsetof(T, reg_init))); + __ lwl(a4, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a4, MemOperand(a0, offsetof(T, lwl_0))); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwl(a5, MemOperand(a0, OFFSET_OF(T, mem_init) + 1)); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, lwl_1))); + __ lw(a5, MemOperand(a0, offsetof(T, reg_init))); + __ lwl(a5, MemOperand(a0, offsetof(T, mem_init) + 1)); + __ sw(a5, MemOperand(a0, offsetof(T, lwl_1))); - __ lw(a6, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwl(a6, MemOperand(a0, OFFSET_OF(T, mem_init) + 2)); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, lwl_2))); + __ lw(a6, MemOperand(a0, offsetof(T, reg_init))); + __ lwl(a6, MemOperand(a0, offsetof(T, mem_init) + 2)); + __ sw(a6, MemOperand(a0, offsetof(T, lwl_2))); - __ lw(a7, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwl(a7, MemOperand(a0, OFFSET_OF(T, mem_init) + 3)); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, lwl_3))); + __ lw(a7, MemOperand(a0, offsetof(T, reg_init))); + __ lwl(a7, MemOperand(a0, offsetof(T, mem_init) + 3)); + __ sw(a7, MemOperand(a0, offsetof(T, lwl_3))); // Test all combinations of LWR and vAddr. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwr(a4, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, lwr_0))); + __ lw(a4, MemOperand(a0, offsetof(T, reg_init))); + __ lwr(a4, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a4, MemOperand(a0, offsetof(T, lwr_0))); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwr(a5, MemOperand(a0, OFFSET_OF(T, mem_init) + 1)); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, lwr_1))); + __ lw(a5, MemOperand(a0, offsetof(T, reg_init))); + __ lwr(a5, MemOperand(a0, offsetof(T, mem_init) + 1)); + __ sw(a5, MemOperand(a0, offsetof(T, lwr_1))); - __ lw(a6, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwr(a6, MemOperand(a0, OFFSET_OF(T, mem_init) + 2)); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, lwr_2)) ); + __ lw(a6, MemOperand(a0, offsetof(T, reg_init))); + __ lwr(a6, MemOperand(a0, offsetof(T, mem_init) + 2)); + __ sw(a6, MemOperand(a0, offsetof(T, lwr_2)) ); - __ lw(a7, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ lwr(a7, MemOperand(a0, OFFSET_OF(T, mem_init) + 3)); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, lwr_3)) ); + __ lw(a7, MemOperand(a0, offsetof(T, reg_init))); + __ lwr(a7, MemOperand(a0, offsetof(T, mem_init) + 3)); + __ sw(a7, MemOperand(a0, offsetof(T, lwr_3)) ); // Test all combinations of SWL and vAddr. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, swl_0))); - __ lw(a4, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swl(a4, MemOperand(a0, OFFSET_OF(T, swl_0))); - - __ lw(a5, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, swl_1))); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swl(a5, MemOperand(a0, OFFSET_OF(T, swl_1) + 1)); - - __ lw(a6, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, swl_2))); - __ lw(a6, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swl(a6, MemOperand(a0, OFFSET_OF(T, swl_2) + 2)); - - __ lw(a7, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, swl_3))); - __ lw(a7, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swl(a7, MemOperand(a0, OFFSET_OF(T, swl_3) + 3)); + __ lw(a4, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a4, MemOperand(a0, offsetof(T, swl_0))); + __ lw(a4, MemOperand(a0, offsetof(T, reg_init))); + __ swl(a4, MemOperand(a0, offsetof(T, swl_0))); + + __ lw(a5, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a5, MemOperand(a0, offsetof(T, swl_1))); + __ lw(a5, MemOperand(a0, offsetof(T, reg_init))); + __ swl(a5, MemOperand(a0, offsetof(T, swl_1) + 1)); + + __ lw(a6, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a6, MemOperand(a0, offsetof(T, swl_2))); + __ lw(a6, MemOperand(a0, offsetof(T, reg_init))); + __ swl(a6, MemOperand(a0, offsetof(T, swl_2) + 2)); + + __ lw(a7, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a7, MemOperand(a0, offsetof(T, swl_3))); + __ lw(a7, MemOperand(a0, offsetof(T, reg_init))); + __ swl(a7, MemOperand(a0, offsetof(T, swl_3) + 3)); // Test all combinations of SWR and vAddr. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, swr_0))); - __ lw(a4, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swr(a4, MemOperand(a0, OFFSET_OF(T, swr_0))); - - __ lw(a5, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, swr_1))); - __ lw(a5, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swr(a5, MemOperand(a0, OFFSET_OF(T, swr_1) + 1)); - - __ lw(a6, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, swr_2))); - __ lw(a6, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swr(a6, MemOperand(a0, OFFSET_OF(T, swr_2) + 2)); - - __ lw(a7, MemOperand(a0, OFFSET_OF(T, mem_init))); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, swr_3))); - __ lw(a7, MemOperand(a0, OFFSET_OF(T, reg_init))); - __ swr(a7, MemOperand(a0, OFFSET_OF(T, swr_3) + 3)); + __ lw(a4, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a4, MemOperand(a0, offsetof(T, swr_0))); + __ lw(a4, MemOperand(a0, offsetof(T, reg_init))); + __ swr(a4, MemOperand(a0, offsetof(T, swr_0))); + + __ lw(a5, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a5, MemOperand(a0, offsetof(T, swr_1))); + __ lw(a5, MemOperand(a0, offsetof(T, reg_init))); + __ swr(a5, MemOperand(a0, offsetof(T, swr_1) + 1)); + + __ lw(a6, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a6, MemOperand(a0, offsetof(T, swr_2))); + __ lw(a6, MemOperand(a0, offsetof(T, reg_init))); + __ swr(a6, MemOperand(a0, offsetof(T, swr_2) + 2)); + + __ lw(a7, MemOperand(a0, offsetof(T, mem_init))); + __ sw(a7, MemOperand(a0, offsetof(T, swr_3))); + __ lw(a7, MemOperand(a0, offsetof(T, reg_init))); + __ swr(a7, MemOperand(a0, offsetof(T, swr_3) + 3)); __ jr(ra); __ nop(); @@ -1067,8 +1068,8 @@ TEST(MIPS12) { __ mov(t2, fp); // Save frame pointer. __ mov(fp, a0); // Access struct T by fp. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, y))); - __ lw(a7, MemOperand(a0, OFFSET_OF(T, y4))); + __ lw(a4, MemOperand(a0, offsetof(T, y))); + __ lw(a7, MemOperand(a0, offsetof(T, y4))); __ addu(a5, a4, a7); __ subu(t0, a4, a7); @@ -1086,30 +1087,30 @@ TEST(MIPS12) { __ push(a7); __ pop(t0); __ nop(); - __ sw(a4, MemOperand(fp, OFFSET_OF(T, y))); - __ lw(a4, MemOperand(fp, OFFSET_OF(T, y))); + __ sw(a4, MemOperand(fp, offsetof(T, y))); + __ lw(a4, MemOperand(fp, offsetof(T, y))); __ nop(); - __ sw(a4, MemOperand(fp, OFFSET_OF(T, y))); - __ lw(a5, MemOperand(fp, OFFSET_OF(T, y))); + __ sw(a4, MemOperand(fp, offsetof(T, y))); + __ lw(a5, MemOperand(fp, offsetof(T, y))); __ nop(); __ push(a5); - __ lw(a5, MemOperand(fp, OFFSET_OF(T, y))); + __ lw(a5, MemOperand(fp, offsetof(T, y))); __ pop(a5); __ nop(); __ push(a5); - __ lw(a6, MemOperand(fp, OFFSET_OF(T, y))); + __ lw(a6, MemOperand(fp, offsetof(T, y))); __ pop(a5); __ nop(); __ push(a5); - __ lw(a6, MemOperand(fp, OFFSET_OF(T, y))); + __ lw(a6, MemOperand(fp, offsetof(T, y))); __ pop(a6); __ nop(); __ push(a6); - __ lw(a6, MemOperand(fp, OFFSET_OF(T, y))); + __ lw(a6, MemOperand(fp, offsetof(T, y))); __ pop(a5); __ nop(); __ push(a5); - __ lw(a6, MemOperand(fp, OFFSET_OF(T, y))); + __ lw(a6, MemOperand(fp, offsetof(T, y))); __ pop(a7); __ nop(); @@ -1154,19 +1155,19 @@ TEST(MIPS13) { MacroAssembler assm(isolate, NULL, 0); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, cvt_small_in))); + __ sw(a4, MemOperand(a0, offsetof(T, cvt_small_in))); __ Cvt_d_uw(f10, a4, f22); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out))); + __ sdc1(f10, MemOperand(a0, offsetof(T, cvt_small_out))); __ Trunc_uw_d(f10, f10, f22); - __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out))); + __ swc1(f10, MemOperand(a0, offsetof(T, trunc_small_out))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, cvt_big_in))); + __ sw(a4, MemOperand(a0, offsetof(T, cvt_big_in))); __ Cvt_d_uw(f8, a4, f22); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out))); + __ sdc1(f8, MemOperand(a0, offsetof(T, cvt_big_out))); __ Trunc_uw_d(f8, f8, f22); - __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out))); + __ swc1(f8, MemOperand(a0, offsetof(T, trunc_big_out))); __ jr(ra); __ nop(); @@ -1236,46 +1237,46 @@ TEST(MIPS14) { // Disable FPU exceptions. __ ctc1(zero_reg, FCSR); #define RUN_ROUND_TEST(x) \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, round_up_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_up_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, round_down_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_down_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, neg_round_up_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, neg_##x##_up_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, neg_round_down_in))); \ __ x##_w_d(f0, f0); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, neg_##x##_down_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err1_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err1_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err1_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err1_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err2_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err2_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err2_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err2_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err3_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err3_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err3_out))); \ + __ sw(a2, MemOperand(a0, offsetof(T, x##_err3_out))); \ \ - __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, err4_in))); \ + __ ldc1(f0, MemOperand(a0, offsetof(T, err4_in))); \ __ ctc1(zero_reg, FCSR); \ __ x##_w_d(f0, f0); \ __ cfc1(a2, FCSR); \ - __ sw(a2, MemOperand(a0, OFFSET_OF(T, x##_err4_out))); \ - __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_invalid_result))); + __ sw(a2, MemOperand(a0, offsetof(T, x##_err4_out))); \ + __ swc1(f0, MemOperand(a0, offsetof(T, x##_invalid_result))); RUN_ROUND_TEST(round) RUN_ROUND_TEST(floor) @@ -1363,48 +1364,48 @@ TEST(MIPS16) { Label L, C; // Basic 32-bit word load/store, with un-signed data. - __ lw(a4, MemOperand(a0, OFFSET_OF(T, ui))); - __ sw(a4, MemOperand(a0, OFFSET_OF(T, r1))); + __ lw(a4, MemOperand(a0, offsetof(T, ui))); + __ sw(a4, MemOperand(a0, offsetof(T, r1))); // Check that the data got zero-extended into 64-bit a4. - __ sd(a4, MemOperand(a0, OFFSET_OF(T, r2))); + __ sd(a4, MemOperand(a0, offsetof(T, r2))); // Basic 32-bit word load/store, with SIGNED data. - __ lw(a5, MemOperand(a0, OFFSET_OF(T, si))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, r3))); + __ lw(a5, MemOperand(a0, offsetof(T, si))); + __ sw(a5, MemOperand(a0, offsetof(T, r3))); // Check that the data got sign-extended into 64-bit a4. - __ sd(a5, MemOperand(a0, OFFSET_OF(T, r4))); + __ sd(a5, MemOperand(a0, offsetof(T, r4))); // 32-bit UNSIGNED word load/store, with SIGNED data. - __ lwu(a6, MemOperand(a0, OFFSET_OF(T, si))); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, r5))); + __ lwu(a6, MemOperand(a0, offsetof(T, si))); + __ sw(a6, MemOperand(a0, offsetof(T, r5))); // Check that the data got zero-extended into 64-bit a4. - __ sd(a6, MemOperand(a0, OFFSET_OF(T, r6))); + __ sd(a6, MemOperand(a0, offsetof(T, r6))); // lh with positive data. - __ lh(a5, MemOperand(a0, OFFSET_OF(T, ui))); - __ sw(a5, MemOperand(a0, OFFSET_OF(T, r2))); + __ lh(a5, MemOperand(a0, offsetof(T, ui))); + __ sw(a5, MemOperand(a0, offsetof(T, r2))); // lh with negative data. - __ lh(a6, MemOperand(a0, OFFSET_OF(T, si))); - __ sw(a6, MemOperand(a0, OFFSET_OF(T, r3))); + __ lh(a6, MemOperand(a0, offsetof(T, si))); + __ sw(a6, MemOperand(a0, offsetof(T, r3))); // lhu with negative data. - __ lhu(a7, MemOperand(a0, OFFSET_OF(T, si))); - __ sw(a7, MemOperand(a0, OFFSET_OF(T, r4))); + __ lhu(a7, MemOperand(a0, offsetof(T, si))); + __ sw(a7, MemOperand(a0, offsetof(T, r4))); // lb with negative data. - __ lb(t0, MemOperand(a0, OFFSET_OF(T, si))); - __ sw(t0, MemOperand(a0, OFFSET_OF(T, r5))); + __ lb(t0, MemOperand(a0, offsetof(T, si))); + __ sw(t0, MemOperand(a0, offsetof(T, r5))); // // sh writes only 1/2 of word. __ lui(t1, 0x3333); __ ori(t1, t1, 0x3333); - __ sw(t1, MemOperand(a0, OFFSET_OF(T, r6))); - __ lhu(t1, MemOperand(a0, OFFSET_OF(T, si))); - __ sh(t1, MemOperand(a0, OFFSET_OF(T, r6))); + __ sw(t1, MemOperand(a0, offsetof(T, r6))); + __ lhu(t1, MemOperand(a0, offsetof(T, si))); + __ sh(t1, MemOperand(a0, offsetof(T, r6))); __ jr(ra); __ nop(); @@ -1439,7 +1440,8 @@ TEST(MIPS16) { } -TEST(MIPS17) { +// ----------------------mips32r6 specific tests---------------------- +TEST(seleqz_selnez) { if (kArchVariant == kMips64r6) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -1455,26 +1457,36 @@ TEST(MIPS17) { double f; double g; double h; + float i; + float j; + float k; + float l; } Test; Test test; // Integer part of test. __ addiu(t1, zero_reg, 1); // t1 = 1 __ seleqz(t3, t1, zero_reg); // t3 = 1 - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, a))); // a = 1 + __ sw(t3, MemOperand(a0, offsetof(Test, a))); // a = 1 __ seleqz(t2, t1, t1); // t2 = 0 - __ sw(t2, MemOperand(a0, OFFSET_OF(Test, b))); // b = 0 + __ sw(t2, MemOperand(a0, offsetof(Test, b))); // b = 0 __ selnez(t3, t1, zero_reg); // t3 = 1; - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, c))); // c = 0 + __ sw(t3, MemOperand(a0, offsetof(Test, c))); // c = 0 __ selnez(t3, t1, t1); // t3 = 1 - __ sw(t3, MemOperand(a0, OFFSET_OF(Test, d))); // d = 1 + __ sw(t3, MemOperand(a0, offsetof(Test, d))); // d = 1 // Floating point part of test. - __ ldc1(f0, MemOperand(a0, OFFSET_OF(Test, e)) ); // src - __ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, f)) ); // test - __ seleqz(D, f4, f0, f2); - __ selnez(D, f6, f0, f2); - __ sdc1(f4, MemOperand(a0, OFFSET_OF(Test, g)) ); // src - __ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, h)) ); // src + __ ldc1(f0, MemOperand(a0, offsetof(Test, e)) ); // src + __ ldc1(f2, MemOperand(a0, offsetof(Test, f)) ); // test + __ lwc1(f8, MemOperand(a0, offsetof(Test, i)) ); // src + __ lwc1(f10, MemOperand(a0, offsetof(Test, j)) ); // test + __ seleqz_d(f4, f0, f2); + __ selnez_d(f6, f0, f2); + __ seleqz_s(f12, f8, f10); + __ selnez_s(f14, f8, f10); + __ sdc1(f4, MemOperand(a0, offsetof(Test, g)) ); // src + __ sdc1(f6, MemOperand(a0, offsetof(Test, h)) ); // src + __ swc1(f12, MemOperand(a0, offsetof(Test, k)) ); // src + __ swc1(f14, MemOperand(a0, offsetof(Test, l)) ); // src __ jr(ra); __ nop(); CodeDesc desc; @@ -1493,31 +1505,45 @@ TEST(MIPS17) { const int test_size = 3; const int input_size = 5; - double inputs[input_size] = {0.0, 65.2, -70.32, + double inputs_D[input_size] = {0.0, 65.2, -70.32, 18446744073709551621.0, -18446744073709551621.0}; - double outputs[input_size] = {0.0, 65.2, -70.32, + double outputs_D[input_size] = {0.0, 65.2, -70.32, 18446744073709551621.0, -18446744073709551621.0}; - double tests[test_size*2] = {2.8, 2.9, -2.8, -2.9, + double tests_D[test_size*2] = {2.8, 2.9, -2.8, -2.9, 18446744073709551616.0, 18446744073709555712.0}; - for (int j=0;j < test_size;j+=2) { - for (int i=0;i < input_size;i++) { - test.e = inputs[i]; - test.f = tests[j]; + float inputs_S[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float outputs_S[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float tests_S[test_size*2] = {2.9, 2.8, -2.9, -2.8, + 18446744073709551616.0, 18446746272732807168.0}; + for (int j=0; j < test_size; j+=2) { + for (int i=0; i < input_size; i++) { + test.e = inputs_D[i]; + test.f = tests_D[j]; + test.i = inputs_S[i]; + test.j = tests_S[j]; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.g, outputs[i]); + CHECK_EQ(test.g, outputs_D[i]); CHECK_EQ(test.h, 0); + CHECK_EQ(test.k, outputs_S[i]); + CHECK_EQ(test.l, 0); - test.f = tests[j+1]; + test.f = tests_D[j+1]; + test.j = tests_S[j+1]; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.g, 0); - CHECK_EQ(test.h, outputs[i]); + CHECK_EQ(test.h, outputs_D[i]); + CHECK_EQ(test.k, 0); + CHECK_EQ(test.l, outputs_S[i]); } } } } -TEST(MIPS18) { + +TEST(min_max) { if (kArchVariant == kMips64r6) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -1529,16 +1555,38 @@ TEST(MIPS18) { double b; double c; double d; + float e; + float f; + float g; + float h; } TestFloat; TestFloat test; - - __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a))); - __ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b))); + const double dblNaN = std::numeric_limits<double>::quiet_NaN(); + const float fltNaN = std::numeric_limits<float>::quiet_NaN(); + const int tableLength = 5; + double inputsa[tableLength] = {2.0, 3.0, dblNaN, 3.0, dblNaN}; + double inputsb[tableLength] = {3.0, 2.0, 3.0, dblNaN, dblNaN}; + double outputsdmin[tableLength] = {2.0, 2.0, 3.0, 3.0, dblNaN}; + double outputsdmax[tableLength] = {3.0, 3.0, 3.0, 3.0, dblNaN}; + + float inputse[tableLength] = {2.0, 3.0, fltNaN, 3.0, fltNaN}; + float inputsf[tableLength] = {3.0, 2.0, 3.0, fltNaN, fltNaN}; + float outputsfmin[tableLength] = {2.0, 2.0, 3.0, 3.0, fltNaN}; + float outputsfmax[tableLength] = {3.0, 3.0, 3.0, 3.0, fltNaN}; + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, e))); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, f))); __ min_d(f10, f4, f8); __ max_d(f12, f4, f8); - __ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c))); - __ sdc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, d))); + __ min_s(f14, f2, f6); + __ max_s(f16, f2, f6); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c))); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, d))); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, g))); + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, h))); __ jr(ra); __ nop(); @@ -1547,40 +1595,31 @@ TEST(MIPS18) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); - test.a = 2.0; // a goes to fs - test.b = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 2.0); - CHECK_EQ(test.d, 3.0); + for (int i = 0; i < tableLength; i++) { + test.a = inputsa[i]; + test.b = inputsb[i]; + test.e = inputse[i]; + test.f = inputsf[i]; - test.a = 3.0; // a goes to fs - test.b = 2.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 2.0); - CHECK_EQ(test.d, 3.0); - - test.a = std::numeric_limits<double>::quiet_NaN(); - test.b = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 3.0); - CHECK_EQ(test.d, 3.0); - - test.b = std::numeric_limits<double>::quiet_NaN(); - test.a = 3.0; // b goes to ft - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.c, 3.0); - CHECK_EQ(test.d, 3.0); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - test.a = std::numeric_limits<double>::quiet_NaN(); - test.b = std::numeric_limits<double>::quiet_NaN(); - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - DCHECK(std::isnan(test.c)); - DCHECK(std::isnan(test.d)); + if (i < tableLength - 1) { + CHECK_EQ(test.c, outputsdmin[i]); + CHECK_EQ(test.d, outputsdmax[i]); + CHECK_EQ(test.g, outputsfmin[i]); + CHECK_EQ(test.h, outputsfmax[i]); + } else { + DCHECK(std::isnan(test.c)); + DCHECK(std::isnan(test.d)); + DCHECK(std::isnan(test.g)); + DCHECK(std::isnan(test.h)); + } + } } } -TEST(MIPS19) { +TEST(rint_d) { if (kArchVariant == kMips64r6) { const int tableLength = 30; CcTest::InitializeVM(); @@ -1658,11 +1697,190 @@ TEST(MIPS19) { int fcsr_inputs[4] = {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; double* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(TestFloat, fcsr)) ); + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, fcsr)) ); __ ctc1(t0, FCSR); __ rint_d(f8, f4); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)) ); + __ sdc1(f8, MemOperand(a0, offsetof(TestFloat, b)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + for (int j = 0; j < 4; j++) { + test.fcsr = fcsr_inputs[j]; + for (int i = 0; i < tableLength; i++) { + test.a = inputs[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs[j][i]); + } + } + } +} + + +TEST(sel) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test { + double dd; + double ds; + double dt; + float fd; + float fs; + float ft; + } Test; + + Test test; + __ ldc1(f0, MemOperand(a0, offsetof(Test, dd)) ); // test + __ ldc1(f2, MemOperand(a0, offsetof(Test, ds)) ); // src1 + __ ldc1(f4, MemOperand(a0, offsetof(Test, dt)) ); // src2 + __ lwc1(f6, MemOperand(a0, offsetof(Test, fd)) ); // test + __ lwc1(f8, MemOperand(a0, offsetof(Test, fs)) ); // src1 + __ lwc1(f10, MemOperand(a0, offsetof(Test, ft)) ); // src2 + __ sel_d(f0, f2, f4); + __ sel_s(f6, f8, f10); + __ sdc1(f0, MemOperand(a0, offsetof(Test, dd)) ); + __ swc1(f6, MemOperand(a0, offsetof(Test, fd)) ); + __ jr(ra); + __ nop(); + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + const int test_size = 3; + const int input_size = 5; + + double inputs_dt[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + double inputs_ds[input_size] = {0.1, 69.88, -91.325, + 18446744073709551625.0, -18446744073709551625.0}; + float inputs_ft[input_size] = {0.0, 65.2, -70.32, + 18446744073709551621.0, -18446744073709551621.0}; + float inputs_fs[input_size] = {0.1, 69.88, -91.325, + 18446744073709551625.0, -18446744073709551625.0}; + double tests_D[test_size*2] = {2.8, 2.9, -2.8, -2.9, + 18446744073709551616.0, 18446744073709555712.0}; + float tests_S[test_size*2] = {2.9, 2.8, -2.9, -2.8, + 18446744073709551616.0, 18446746272732807168.0}; + for (int j=0; j < test_size; j+=2) { + for (int i=0; i < input_size; i++) { + test.dt = inputs_dt[i]; + test.dd = tests_D[j]; + test.ds = inputs_ds[i]; + test.ft = inputs_ft[i]; + test.fd = tests_S[j]; + test.fs = inputs_fs[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dd, inputs_ds[i]); + CHECK_EQ(test.fd, inputs_fs[i]); + + test.dd = tests_D[j+1]; + test.fd = tests_S[j+1]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dd, inputs_dt[i]); + CHECK_EQ(test.fd, inputs_ft[i]); + } + } + } +} + + +TEST(rint_s) { + if (kArchVariant == kMips64r6) { + const int tableLength = 30; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + int fcsr; + }TestFloat; + + TestFloat test; + float inputs[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E+38, 6.27463370218383111104242366943E-37, + 309485009821345068724781056.89, + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RN[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RZ[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RP[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 1, + 309485009821345068724781057.0, + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + float outputs_RM[tableLength] = {18446744073709551617.0, + 4503599627370496.0, -4503599627370496.0, + 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E37, + 1.7976931348623157E38, 0, + 309485009821345068724781057.0, + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, + 37778931862957161709568.0, 37778931862957161709569.0, + 37778931862957161709580.0, 37778931862957161709581.0, + 37778931862957161709582.0, 37778931862957161709583.0, + 37778931862957161709584.0, 37778931862957161709585.0, + 37778931862957161709586.0, 37778931862957161709587.0}; + int fcsr_inputs[4] = + {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; + float* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, fcsr)) ); + __ cfc1(t1, FCSR); + __ ctc1(t0, FCSR); + __ rint_s(f8, f4); + __ swc1(f8, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ctc1(t1, FCSR); __ jr(ra); __ nop(); @@ -1672,11 +1890,10 @@ TEST(MIPS19) { desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); - for (int j = 0;j < 4;j++) { + for (int j = 0; j < 4; j++) { test.fcsr = fcsr_inputs[j]; - for (int i = 0;i < tableLength;i++) { + for (int i = 0; i < tableLength; i++) { test.a = inputs[i]; - std::cout << j << " " << i << "\n"; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.b, outputs[j][i]); } @@ -1685,7 +1902,358 @@ TEST(MIPS19) { } -TEST(MIPS20) { +TEST(mina_maxa) { + if (kArchVariant == kMips64r6) { + const int tableLength = 12; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + double resd; + double resd1; + float c; + float d; + float resf; + float resf1; + }TestFloat; + + TestFloat test; + double inputsa[tableLength] = { + 5.3, 4.8, 6.1, + 9.8, 9.8, 9.8, + -10.0, -8.9, -9.8, + -10.0, -8.9, -9.8 + }; + double inputsb[tableLength] = { + 4.8, 5.3, 6.1, + -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, + -9.8, -11.2, -9.8 + }; + double resd[tableLength] = { + 4.8, 4.8, 6.1, + 9.8, -8.9, 9.8, + 9.8, -8.9, 9.8, + -9.8, -8.9, -9.8 + }; + double resd1[tableLength] = { + 5.3, 5.3, 6.1, + -10.0, 9.8, 9.8, + -10.0, 9.8, 9.8, + -10.0, -11.2, -9.8 + }; + float inputsc[tableLength] = { + 5.3, 4.8, 6.1, + 9.8, 9.8, 9.8, + -10.0, -8.9, -9.8, + -10.0, -8.9, -9.8 + }; + float inputsd[tableLength] = { + 4.8, 5.3, 6.1, + -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, + -9.8, -11.2, -9.8 + }; + float resf[tableLength] = { + 4.8, 4.8, 6.1, + 9.8, -8.9, 9.8, + 9.8, -8.9, 9.8, + -9.8, -8.9, -9.8 + }; + float resf1[tableLength] = { + 5.3, 5.3, 6.1, + -10.0, 9.8, 9.8, + -10.0, 9.8, 9.8, + -10.0, -11.2, -9.8 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ lwc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ lwc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ mina_d(f6, f2, f4); + __ mina_s(f12, f8, f10); + __ maxa_d(f14, f2, f4); + __ maxa_s(f16, f8, f10); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, resf)) ); + __ sdc1(f6, MemOperand(a0, offsetof(TestFloat, resd)) ); + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, resf1)) ); + __ sdc1(f14, MemOperand(a0, offsetof(TestFloat, resd1)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputsa[i]; + test.b = inputsb[i]; + test.c = inputsc[i]; + test.d = inputsd[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + + CHECK_EQ(test.resd, resd[i]); + CHECK_EQ(test.resf, resf[i]); + CHECK_EQ(test.resd1, resd1[i]); + CHECK_EQ(test.resf1, resf1[i]); + } + } +} + + + +// ----------------------mips32r2 specific tests---------------------- +TEST(trunc_l) { + if (kArchVariant == kMips64r2) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; // a trunc result + int64_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ trunc_l_d(f8, f4); + __ trunc_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } + } +} + + +TEST(movz_movn) { + if (kArchVariant == kMips64r2) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + int64_t rt; + double a; + double b; + double bold; + double b1; + double bold1; + float c; + float d; + float dold; + float d1; + float dold1; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ lw(t0, MemOperand(a0, offsetof(TestFloat, rt)) ); + __ li(t1, 0x0); + __ mtc1(t1, f12); + __ mtc1(t1, f10); + __ mtc1(t1, f16); + __ mtc1(t1, f14); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, bold)) ); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, dold)) ); + __ sdc1(f16, MemOperand(a0, offsetof(TestFloat, bold1)) ); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, dold1)) ); + __ movz_s(f10, f6, t0); + __ movz_d(f12, f2, t0); + __ movn_s(f14, f6, t0); + __ movn_d(f16, f2, t0); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, b)) ); + __ swc1(f14, MemOperand(a0, offsetof(TestFloat, d1)) ); + __ sdc1(f16, MemOperand(a0, offsetof(TestFloat, b1)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.c = inputs_S[i]; + + test.rt = 1; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, test.bold); + CHECK_EQ(test.d, test.dold); + CHECK_EQ(test.b1, outputs_D[i]); + CHECK_EQ(test.d1, outputs_S[i]); + + test.rt = 0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs_D[i]); + CHECK_EQ(test.d, outputs_S[i]); + CHECK_EQ(test.b1, test.bold1); + CHECK_EQ(test.d1, test.dold1); + } + } +} + + +TEST(movt_movd) { + if (kArchVariant == kMips64r2) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + typedef struct test_float { + double srcd; + double dstd; + double dstdold; + double dstd1; + double dstdold1; + float srcf; + float dstf; + float dstfold; + float dstf1; + float dstfold1; + int32_t cc; + int32_t fcsr; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 20.8, -2.9 + }; + double inputs_S[tableLength] = { + 4.88, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.88, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 20.8, -2.9 + }; + int condition_flags[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + + for (int i = 0; i < tableLength; i++) { + test.srcd = inputs_D[i]; + test.srcf = inputs_S[i]; + + for (int j = 0; j< 8; j++) { + test.cc = condition_flags[j]; + if (test.cc == 0) { + test.fcsr = 1 << 23; + } else { + test.fcsr = 1 << (24+condition_flags[j]); + } + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, srcd)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, srcf)) ); + __ lw(t1, MemOperand(a0, offsetof(TestFloat, fcsr)) ); + __ cfc1(t0, FCSR); + __ ctc1(t1, FCSR); + __ li(t2, 0x0); + __ mtc1(t2, f12); + __ mtc1(t2, f10); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstdold)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstfold)) ); + __ movt_s(f12, f4, test.cc); + __ movt_d(f10, f2, test.cc); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstf)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstd)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstdold1)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstfold1)) ); + __ movf_s(f12, f4, test.cc); + __ movf_d(f10, f2, test.cc); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, dstf1)) ); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, dstd1)) ); + __ ctc1(t0, FCSR); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dstf, outputs_S[i]); + CHECK_EQ(test.dstd, outputs_D[i]); + CHECK_EQ(test.dstf1, test.dstfold1); + CHECK_EQ(test.dstd1, test.dstdold1); + test.fcsr = 0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dstf, test.dstfold); + CHECK_EQ(test.dstd, test.dstdold); + CHECK_EQ(test.dstf1, outputs_S[i]); + CHECK_EQ(test.dstd1, outputs_D[i]); + } + } + } +} + + + +// ----------------------tests for all archs-------------------------- +TEST(cvt_w_d) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -1736,12 +2304,12 @@ TEST(MIPS20) { int fcsr_inputs[4] = {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; double* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(Test, a)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(Test, fcsr)) ); + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lw(t0, MemOperand(a0, offsetof(Test, fcsr)) ); __ cfc1(t1, FCSR); __ ctc1(t0, FCSR); __ cvt_w_d(f8, f4); - __ swc1(f8, MemOperand(a0, OFFSET_OF(Test, b)) ); + __ swc1(f8, MemOperand(a0, offsetof(Test, b)) ); __ ctc1(t1, FCSR); __ jr(ra); __ nop(); @@ -1751,9 +2319,9 @@ TEST(MIPS20) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); - for (int j = 0;j < 4;j++) { + for (int j = 0; j < 4; j++) { test.fcsr = fcsr_inputs[j]; - for (int i = 0;i < tableLength;i++) { + for (int i = 0; i < tableLength; i++) { test.a = inputs[i]; (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); CHECK_EQ(test.b, outputs[j][i]); @@ -1762,111 +2330,736 @@ TEST(MIPS20) { } -TEST(MIPS21) { - if (kArchVariant == kMips64r6) { - const int tableLength = 30; +TEST(trunc_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a trunc result + int32_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ trunc_w_d(f8, f4); + __ trunc_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(round_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a trunc result + int32_t d; // b trunc result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ round_w_d(f8, f4); + __ round_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(round_l) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); MacroAssembler assm(isolate, NULL, 0); - + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); typedef struct test_float { double a; - double b; - int fcsr; - }TestFloat; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, + -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ round_l_d(f8, f4); + __ round_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + std::cout<< i<< "\n"; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} - TestFloat test; - double inputs[tableLength] = {18446744073709551617.0, - 4503599627370496.0, -4503599627370496.0, - 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E147, - 1.7976931348623157E308, 6.27463370218383111104242366943E-307, - 309485009821345068724781056.89, + +TEST(sub) { + const int tableLength = 12; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + float resultS; + double c; + double d; + double resultD; + }TestFloat; + + TestFloat test; + double inputfs_D[tableLength] = { + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9, + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9 + }; + double inputft_D[tableLength] = { + 4.8, 5.3, 2.9, 4.8, 5.3, 2.9, + -4.8, -5.3, -2.9, -4.8, -5.3, -2.9 + }; + double outputs_D[tableLength] = { + 0.5, -0.5, 0.0, -10.1, -10.1, -5.8, + 10.1, 10.1, 5.8, -0.5, 0.5, 0.0 + }; + float inputfs_S[tableLength] = { + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9, + 5.3, 4.8, 2.9, -5.3, -4.8, -2.9 + }; + float inputft_S[tableLength] = { + 4.8, 5.3, 2.9, 4.8, 5.3, 2.9, + -4.8, -5.3, -2.9, -4.8, -5.3, -2.9 + }; + float outputs_S[tableLength] = { + 0.5, -0.5, 0.0, -10.1, -10.1, -5.8, + 10.1, 10.1, 5.8, -0.5, 0.5, 0.0 + }; + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ ldc1(f10, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sub_s(f6, f2, f4); + __ sub_d(f12, f8, f10); + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputfs_S[i]; + test.b = inputft_S[i]; + test.c = inputfs_D[i]; + test.d = inputft_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + } +} + + +TEST(sqrt_rsqrt_recip) { + const int tableLength = 4; + const double deltaDouble = 2E-15; + const float deltaFloat = 2E-7; + const float sqrt2_s = sqrt(2); + const double sqrt2_d = sqrt(2); + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float resultS; + float resultS1; + float resultS2; + double c; + double resultD; + double resultD1; + double resultD2; + }TestFloat; + TestFloat test; + + double inputs_D[tableLength] = { + 0.0L, 4.0L, 2.0L, 4e-28L + }; + + double outputs_D[tableLength] = { + 0.0L, 2.0L, sqrt2_d, 2e-14L + }; + float inputs_S[tableLength] = { + 0.0, 4.0, 2.0, 4e-28 + }; + + float outputs_S[tableLength] = { + 0.0, 2.0, sqrt2_s, 2e-14 + }; + + + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ sqrt_s(f6, f2); + __ sqrt_d(f12, f8); + __ rsqrt_d(f14, f8); + __ rsqrt_s(f16, f2); + __ recip_d(f18, f8); + __ recip_s(f20, f2); + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ swc1(f16, MemOperand(a0, offsetof(TestFloat, resultS1)) ); + __ sdc1(f14, MemOperand(a0, offsetof(TestFloat, resultD1)) ); + __ swc1(f20, MemOperand(a0, offsetof(TestFloat, resultS2)) ); + __ sdc1(f18, MemOperand(a0, offsetof(TestFloat, resultD2)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + for (int i = 0; i < tableLength; i++) { + float f1; + double d1; + test.a = inputs_S[i]; + test.c = inputs_D[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + + if (i != 0) { + f1 = test.resultS1 - 1.0F/outputs_S[i]; + f1 = (f1 < 0) ? f1 : -f1; + CHECK(f1 <= deltaFloat); + d1 = test.resultD1 - 1.0L/outputs_D[i]; + d1 = (d1 < 0) ? d1 : -d1; + CHECK(d1 <= deltaDouble); + f1 = test.resultS2 - 1.0F/inputs_S[i]; + f1 = (f1 < 0) ? f1 : -f1; + CHECK(f1 <= deltaFloat); + d1 = test.resultD2 - 1.0L/inputs_D[i]; + d1 = (d1 < 0) ? d1 : -d1; + CHECK(d1 <= deltaDouble); + } else { + CHECK_EQ(test.resultS1, 1.0F/outputs_S[i]); + CHECK_EQ(test.resultD1, 1.0L/outputs_D[i]); + CHECK_EQ(test.resultS2, 1.0F/inputs_S[i]); + CHECK_EQ(test.resultD2, 1.0L/inputs_D[i]); + } + } +} + + +TEST(neg) { + const int tableLength = 2; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float resultS; + double c; + double resultD; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 4.0, -2.0 + }; + + double outputs_D[tableLength] = { + -4.0, 2.0 + }; + float inputs_S[tableLength] = { + 4.0, -2.0 + }; + + float outputs_S[tableLength] = { + -4.0, 2.0 + }; + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, c)) ); + __ neg_s(f6, f2); + __ neg_d(f12, f8); + __ swc1(f6, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_S[i]; + test.c = inputs_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, outputs_S[i]); + CHECK_EQ(test.resultD, outputs_D[i]); + } +} + + + +TEST(mul) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float a; + float b; + float resultS; + double c; + double d; + double resultD; + }TestFloat; + + TestFloat test; + double inputfs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputft_D[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float inputfs_S[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + float inputft_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + __ lwc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, d)) ); + __ mul_s(f10, f2, f4); + __ mul_d(f12, f6, f8); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, resultS)) ); + __ sdc1(f12, MemOperand(a0, offsetof(TestFloat, resultD)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputfs_S[i]; + test.b = inputft_S[i]; + test.c = inputfs_D[i]; + test.d = inputft_D[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.resultS, inputfs_S[i]*inputft_S[i]); + CHECK_EQ(test.resultD, inputfs_D[i]*inputft_D[i]); + } +} + + +TEST(mov) { + const int tableLength = 4; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + float c; + float d; + }TestFloat; + + TestFloat test; + double inputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + double inputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + + float outputs_S[tableLength] = { + 4.8, 4.8, -4.8, -0.29 + }; + double outputs_D[tableLength] = { + 5.3, -5.3, 5.3, -2.9 + }; + + __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(TestFloat, c)) ); + __ mov_s(f18, f6); + __ mov_d(f20, f2); + __ swc1(f18, MemOperand(a0, offsetof(TestFloat, d)) ); + __ sdc1(f20, MemOperand(a0, offsetof(TestFloat, b)) ); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.c = inputs_S[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.b, outputs_D[i]); + CHECK_EQ(test.d, outputs_S[i]); + } +} + + +TEST(floor_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a floor result + int32_t d; // b floor result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, - 37778931862957161709568.0, 37778931862957161709569.0, - 37778931862957161709580.0, 37778931862957161709581.0, - 37778931862957161709582.0, 37778931862957161709583.0, - 37778931862957161709584.0, 37778931862957161709585.0, - 37778931862957161709586.0, 37778931862957161709587.0}; - double outputs_RN[tableLength] = {18446744073709551617.0, - 4503599627370496.0, -4503599627370496.0, - 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E147, - 1.7976931348623157E308, 0, - 309485009821345068724781057.0, - 2.0, 3.0, 2.0, 3.0, 4.0, 4.0, - -2.0, -3.0, -2.0, -3.0, -4.0, -4.0, - 37778931862957161709568.0, 37778931862957161709569.0, - 37778931862957161709580.0, 37778931862957161709581.0, - 37778931862957161709582.0, 37778931862957161709583.0, - 37778931862957161709584.0, 37778931862957161709585.0, - 37778931862957161709586.0, 37778931862957161709587.0}; - double outputs_RZ[tableLength] = {18446744073709551617.0, - 4503599627370496.0, -4503599627370496.0, - 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E147, - 1.7976931348623157E308, 0, - 309485009821345068724781057.0, - 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, - -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, - 37778931862957161709568.0, 37778931862957161709569.0, - 37778931862957161709580.0, 37778931862957161709581.0, - 37778931862957161709582.0, 37778931862957161709583.0, - 37778931862957161709584.0, 37778931862957161709585.0, - 37778931862957161709586.0, 37778931862957161709587.0}; - double outputs_RP[tableLength] = {18446744073709551617.0, - 4503599627370496.0, -4503599627370496.0, - 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E147, - 1.7976931348623157E308, 1, - 309485009821345068724781057.0, - 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, - -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, - 37778931862957161709568.0, 37778931862957161709569.0, - 37778931862957161709580.0, 37778931862957161709581.0, - 37778931862957161709582.0, 37778931862957161709583.0, - 37778931862957161709584.0, 37778931862957161709585.0, - 37778931862957161709586.0, 37778931862957161709587.0}; - double outputs_RM[tableLength] = {18446744073709551617.0, - 4503599627370496.0, -4503599627370496.0, - 1.26782468584154733584017312973E30, 1.44860108245951772690707170478E147, - 1.7976931348623157E308, 0, - 309485009821345068724781057.0, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, - 37778931862957161709568.0, 37778931862957161709569.0, - 37778931862957161709580.0, 37778931862957161709581.0, - 37778931862957161709582.0, 37778931862957161709583.0, - 37778931862957161709584.0, 37778931862957161709585.0, - 37778931862957161709586.0, 37778931862957161709587.0}; - int fcsr_inputs[4] = - {kRoundToNearest, kRoundToZero, kRoundToPlusInf, kRoundToMinusInf}; - double* outputs[4] = {outputs_RN, outputs_RZ, outputs_RP, outputs_RM}; - __ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)) ); - __ lw(t0, MemOperand(a0, OFFSET_OF(TestFloat, fcsr)) ); - __ cfc1(t1, FCSR); - __ ctc1(t0, FCSR); - __ rint_d(f8, f4); - __ sdc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)) ); - __ ctc1(t1, FCSR); + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ floor_w_d(f8, f4); + __ floor_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} + + +TEST(floor_l) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, + -3.0, -3.0, -3.0, -4.0, -4.0, -4.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ floor_l_d(f8, f4); + __ floor_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); __ jr(ra); __ nop(); - + Test test; CodeDesc desc; assm.GetCode(&desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); - for (int j = 0;j < 4;j++) { - test.fcsr = fcsr_inputs[j]; - for (int i = 0;i < tableLength;i++) { - test.a = inputs[i]; - (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); - CHECK_EQ(test.b, outputs[j][i]); - } + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); } +} + + +TEST(ceil_w) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + float b; + int32_t c; // a floor result + int32_t d; // b floor result + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + kFPUInvalidResult, kFPUInvalidResult, + kFPUInvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ ceil_w_d(f8, f4); + __ ceil_w_s(f10, f6); + __ swc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ swc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); } } +TEST(ceil_l) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + const double dFPU64InvalidResult = static_cast<double>(kFPU64InvalidResult); + typedef struct test_float { + double a; + float b; + int64_t c; + int64_t d; + }Test; + const int tableLength = 15; + double inputs_D[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity() + }; + float inputs_S[tableLength] = { + 2.1, 2.6, 2.5, 3.1, 3.6, 3.5, + -2.1, -2.6, -2.5, -3.1, -3.6, -3.5, + 2147483648.0, + std::numeric_limits<float>::quiet_NaN(), + std::numeric_limits<float>::infinity() + }; + double outputs[tableLength] = { + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, + -2.0, -2.0, -2.0, -3.0, -3.0, -3.0, + 2147483648.0, dFPU64InvalidResult, + dFPU64InvalidResult}; + + __ ldc1(f4, MemOperand(a0, offsetof(Test, a)) ); + __ lwc1(f6, MemOperand(a0, offsetof(Test, b)) ); + __ ceil_l_d(f8, f4); + __ ceil_l_s(f10, f6); + __ sdc1(f8, MemOperand(a0, offsetof(Test, c)) ); + __ sdc1(f10, MemOperand(a0, offsetof(Test, d)) ); + __ jr(ra); + __ nop(); + Test test; + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + for (int i = 0; i < tableLength; i++) { + test.a = inputs_D[i]; + test.b = inputs_S[i]; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, outputs[i]); + CHECK_EQ(test.d, test.c); + } +} TEST(jump_tables1) { @@ -1930,8 +3123,9 @@ TEST(jump_tables1) { #endif F1 f = FUNCTION_CAST<F1>(code->entry()); for (int i = 0; i < kNumCases; ++i) { - int res = reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0)); - ::printf("f(%d) = %d\n", i, res); + int64_t res = reinterpret_cast<int64_t>( + CALL_GENERATED_CODE(f, i, 0, 0, 0, 0)); + ::printf("f(%d) = %" PRId64 "\n", i, res); CHECK_EQ(values[i], static_cast<int>(res)); } } @@ -2002,8 +3196,9 @@ TEST(jump_tables2) { #endif F1 f = FUNCTION_CAST<F1>(code->entry()); for (int i = 0; i < kNumCases; ++i) { - int res = reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0)); - ::printf("f(%d) = %d\n", i, res); + int64_t res = reinterpret_cast<int64_t>( + CALL_GENERATED_CODE(f, i, 0, 0, 0, 0)); + ::printf("f(%d) = %" PRId64 "\n", i, res); CHECK_EQ(values[i], res); } } @@ -2095,4 +3290,2080 @@ TEST(jump_tables3) { } +TEST(BITSWAP) { + // Test BITSWAP + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + int64_t r1; + int64_t r2; + int64_t r3; + int64_t r4; + int64_t r5; + int64_t r6; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + + __ ld(a4, MemOperand(a0, offsetof(T, r1))); + __ nop(); + __ bitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r1))); + + __ ld(a4, MemOperand(a0, offsetof(T, r2))); + __ nop(); + __ bitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r2))); + + __ ld(a4, MemOperand(a0, offsetof(T, r3))); + __ nop(); + __ bitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r3))); + + __ ld(a4, MemOperand(a0, offsetof(T, r4))); + __ nop(); + __ bitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r4))); + + __ ld(a4, MemOperand(a0, offsetof(T, r5))); + __ nop(); + __ dbitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r5))); + + __ ld(a4, MemOperand(a0, offsetof(T, r6))); + __ nop(); + __ dbitswap(a6, a4); + __ sd(a6, MemOperand(a0, offsetof(T, r6))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + t.r1 = 0x00102100781A15C3; + t.r2 = 0x001021008B71FCDE; + t.r3 = 0xFF8017FF781A15C3; + t.r4 = 0xFF8017FF8B71FCDE; + t.r5 = 0x10C021098B71FCDE; + t.r6 = 0xFB8017FF781A15C3; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(static_cast<int64_t>(0x000000001E58A8C3L), t.r1); + CHECK_EQ(static_cast<int64_t>(0xFFFFFFFFD18E3F7BL), t.r2); + CHECK_EQ(static_cast<int64_t>(0x000000001E58A8C3L), t.r3); + CHECK_EQ(static_cast<int64_t>(0xFFFFFFFFD18E3F7BL), t.r4); + CHECK_EQ(static_cast<int64_t>(0x08038490D18E3F7BL), t.r5); + CHECK_EQ(static_cast<int64_t>(0xDF01E8FF1E58A8C3L), t.r6); + } +} + + +TEST(class_fmt) { + if (kArchVariant == kMips64r6) { + // Test CLASS.fmt instruction. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double dSignalingNan; + double dQuietNan; + double dNegInf; + double dNegNorm; + double dNegSubnorm; + double dNegZero; + double dPosInf; + double dPosNorm; + double dPosSubnorm; + double dPosZero; + float fSignalingNan; + float fQuietNan; + float fNegInf; + float fNegNorm; + float fNegSubnorm; + float fNegZero; + float fPosInf; + float fPosNorm; + float fPosSubnorm; + float fPosZero; } T; + T t; + + // Create a function that accepts &t, and loads, manipulates, and stores + // the doubles t.a ... t.f. + MacroAssembler assm(isolate, NULL, 0); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dSignalingNan))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dSignalingNan))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dQuietNan))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dQuietNan))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegInf))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegInf))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegNorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegNorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegSubnorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegSubnorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dNegZero))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dNegZero))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosInf))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosInf))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosNorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosNorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosSubnorm))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosSubnorm))); + + __ ldc1(f4, MemOperand(a0, offsetof(T, dPosZero))); + __ class_d(f6, f4); + __ sdc1(f6, MemOperand(a0, offsetof(T, dPosZero))); + + // Testing instruction CLASS.S + __ lwc1(f4, MemOperand(a0, offsetof(T, fSignalingNan))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fSignalingNan))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fQuietNan))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fQuietNan))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegInf))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegInf))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegNorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegNorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegSubnorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegSubnorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fNegZero))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fNegZero))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosInf))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosInf))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosNorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosNorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosSubnorm))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosSubnorm))); + + __ lwc1(f4, MemOperand(a0, offsetof(T, fPosZero))); + __ class_s(f6, f4); + __ swc1(f6, MemOperand(a0, offsetof(T, fPosZero))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + // Double test values. + t.dSignalingNan = std::numeric_limits<double>::signaling_NaN(); + t.dQuietNan = std::numeric_limits<double>::quiet_NaN(); + t.dNegInf = -1.0 / 0.0; + t.dNegNorm = -5.0; + t.dNegSubnorm = -DBL_MIN / 2.0; + t.dNegZero = -0.0; + t.dPosInf = 2.0 / 0.0; + t.dPosNorm = 275.35; + t.dPosSubnorm = DBL_MIN / 2.0; + t.dPosZero = +0.0; + // Float test values + + t.fSignalingNan = std::numeric_limits<float>::signaling_NaN(); + t.fQuietNan = std::numeric_limits<float>::quiet_NaN(); + t.fNegInf = -0.5/0.0; + t.fNegNorm = -FLT_MIN; + t.fNegSubnorm = -FLT_MIN / 1.5; + t.fNegZero = -0.0; + t.fPosInf = 100000.0 / 0.0; + t.fPosNorm = FLT_MAX; + t.fPosSubnorm = FLT_MIN / 20.0; + t.fPosZero = +0.0; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + // Expected double results. + CHECK_EQ(bit_cast<int64_t>(t.dNegInf), 0x004); + CHECK_EQ(bit_cast<int64_t>(t.dNegNorm), 0x008); + CHECK_EQ(bit_cast<int64_t>(t.dNegSubnorm), 0x010); + CHECK_EQ(bit_cast<int64_t>(t.dNegZero), 0x020); + CHECK_EQ(bit_cast<int64_t>(t.dPosInf), 0x040); + CHECK_EQ(bit_cast<int64_t>(t.dPosNorm), 0x080); + CHECK_EQ(bit_cast<int64_t>(t.dPosSubnorm), 0x100); + CHECK_EQ(bit_cast<int64_t>(t.dPosZero), 0x200); + + // Expected float results. + CHECK_EQ(bit_cast<int32_t>(t.fNegInf), 0x004); + CHECK_EQ(bit_cast<int32_t>(t.fNegNorm), 0x008); + CHECK_EQ(bit_cast<int32_t>(t.fNegSubnorm), 0x010); + CHECK_EQ(bit_cast<int32_t>(t.fNegZero), 0x020); + CHECK_EQ(bit_cast<int32_t>(t.fPosInf), 0x040); + CHECK_EQ(bit_cast<int32_t>(t.fPosNorm), 0x080); + CHECK_EQ(bit_cast<int32_t>(t.fPosSubnorm), 0x100); + CHECK_EQ(bit_cast<int32_t>(t.fPosZero), 0x200); + } +} + + +TEST(ABS) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + int64_t fir; + double a; + float b; + double fcsr; + } TestFloat; + + TestFloat test; + + // Save FIR. + __ cfc1(a1, FCSR); + __ sd(a1, MemOperand(a0, offsetof(TestFloat, fcsr))); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ abs_d(f10, f4); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, a))); + + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, b))); + __ abs_s(f10, f4); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, b))); + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.a = -2.0; + test.b = -2.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, 2.0); + CHECK_EQ(test.b, 2.0); + + test.a = 2.0; + test.b = 2.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, 2.0); + CHECK_EQ(test.b, 2.0); + + // Testing biggest positive number + test.a = std::numeric_limits<double>::max(); + test.b = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max()); + CHECK_EQ(test.b, std::numeric_limits<float>::max()); + + // Testing smallest negative number + test.a = -std::numeric_limits<double>::max(); // lowest() + test.b = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max()); + CHECK_EQ(test.b, std::numeric_limits<float>::max()); + + // Testing smallest positive number + test.a = -std::numeric_limits<double>::min(); + test.b = -std::numeric_limits<float>::min(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::min()); + CHECK_EQ(test.b, std::numeric_limits<float>::min()); + + // Testing infinity + test.a = -std::numeric_limits<double>::max() + / std::numeric_limits<double>::min(); + test.b = -std::numeric_limits<float>::max() + / std::numeric_limits<float>::min(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.a, std::numeric_limits<double>::max() + / std::numeric_limits<double>::min()); + CHECK_EQ(test.b, std::numeric_limits<float>::max() + / std::numeric_limits<float>::min()); + + test.a = std::numeric_limits<double>::quiet_NaN(); + test.b = std::numeric_limits<float>::quiet_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.a), true); + CHECK_EQ(std::isnan(test.b), true); + + test.a = std::numeric_limits<double>::signaling_NaN(); + test.b = std::numeric_limits<float>::signaling_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.a), true); + CHECK_EQ(std::isnan(test.b), true); +} + + +TEST(ADD_FMT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double a; + double b; + double c; + float fa; + float fb; + float fc; + } TestFloat; + + TestFloat test; + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); + __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); + __ add_d(f10, f8, f4); + __ sdc1(f10, MemOperand(a0, offsetof(TestFloat, c))); + + __ lwc1(f4, MemOperand(a0, offsetof(TestFloat, fa))); + __ lwc1(f8, MemOperand(a0, offsetof(TestFloat, fb))); + __ add_s(f10, f8, f4); + __ swc1(f10, MemOperand(a0, offsetof(TestFloat, fc))); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.a = 2.0; + test.b = 3.0; + test.fa = 2.0; + test.fb = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, 5.0); + CHECK_EQ(test.fc, 5.0); + + test.a = std::numeric_limits<double>::max(); + test.b = -std::numeric_limits<double>::max(); // lowest() + test.fa = std::numeric_limits<float>::max(); + test.fb = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.c, 0.0); + CHECK_EQ(test.fc, 0.0); + + test.a = std::numeric_limits<double>::max(); + test.b = std::numeric_limits<double>::max(); + test.fa = std::numeric_limits<float>::max(); + test.fb = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isfinite(test.c), false); + CHECK_EQ(std::isfinite(test.fc), false); + + test.a = 5.0; + test.b = std::numeric_limits<double>::signaling_NaN(); + test.fa = 5.0; + test.fb = std::numeric_limits<float>::signaling_NaN(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(std::isnan(test.c), true); + CHECK_EQ(std::isnan(test.fc), true); +} + + +TEST(C_COND_FMT) { + if (kArchVariant == kMips64r2) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double dOp1; + double dOp2; + uint32_t dF; + uint32_t dUn; + uint32_t dEq; + uint32_t dUeq; + uint32_t dOlt; + uint32_t dUlt; + uint32_t dOle; + uint32_t dUle; + float fOp1; + float fOp2; + uint32_t fF; + uint32_t fUn; + uint32_t fEq; + uint32_t fUeq; + uint32_t fOlt; + uint32_t fUlt; + uint32_t fOle; + uint32_t fUle; + } TestFloat; + + TestFloat test; + + __ li(t1, 1); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, dOp1))); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, dOp2))); + + __ lwc1(f14, MemOperand(a0, offsetof(TestFloat, fOp1))); + __ lwc1(f16, MemOperand(a0, offsetof(TestFloat, fOp2))); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(F, f4, f6, 0); + __ c_s(F, f14, f16, 2); + __ movt(t2, t1, 0); + __ movt(t3, t1, 2); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dF)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fF)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(UN, f4, f6, 2); + __ c_s(UN, f14, f16, 4); + __ movt(t2, t1, 2); + __ movt(t3, t1, 4); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUn)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUn)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(EQ, f4, f6, 4); + __ c_s(EQ, f14, f16, 6); + __ movt(t2, t1, 4); + __ movt(t3, t1, 6); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dEq)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fEq)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(UEQ, f4, f6, 6); + __ c_s(UEQ, f14, f16, 0); + __ movt(t2, t1, 6); + __ movt(t3, t1, 0); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUeq)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUeq)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(OLT, f4, f6, 0); + __ c_s(OLT, f14, f16, 2); + __ movt(t2, t1, 0); + __ movt(t3, t1, 2); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dOlt)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fOlt)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(ULT, f4, f6, 2); + __ c_s(ULT, f14, f16, 4); + __ movt(t2, t1, 2); + __ movt(t3, t1, 4); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUlt)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUlt)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(OLE, f4, f6, 4); + __ c_s(OLE, f14, f16, 6); + __ movt(t2, t1, 4); + __ movt(t3, t1, 6); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dOle)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fOle)) ); + + __ mov(t2, zero_reg); + __ mov(t3, zero_reg); + __ c_d(ULE, f4, f6, 6); + __ c_s(ULE, f14, f16, 0); + __ movt(t2, t1, 6); + __ movt(t3, t1, 0); + __ sw(t2, MemOperand(a0, offsetof(TestFloat, dUle)) ); + __ sw(t3, MemOperand(a0, offsetof(TestFloat, fUle)) ); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + test.dOp1 = 2.0; + test.dOp2 = 3.0; + test.fOp1 = 2.0; + test.fOp2 = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 0U); + CHECK_EQ(test.dOlt, 1U); + CHECK_EQ(test.dUlt, 1U); + CHECK_EQ(test.dOle, 1U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 0U); + CHECK_EQ(test.fOlt, 1U); + CHECK_EQ(test.fUlt, 1U); + CHECK_EQ(test.fOle, 1U); + CHECK_EQ(test.fUle, 1U); + + test.dOp1 = std::numeric_limits<double>::max(); + test.dOp2 = std::numeric_limits<double>::min(); + test.fOp1 = std::numeric_limits<float>::min(); + test.fOp2 = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 0U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 0U); + CHECK_EQ(test.dOle, 0U); + CHECK_EQ(test.dUle, 0U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 0U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 0U); + CHECK_EQ(test.fOle, 0U); + CHECK_EQ(test.fUle, 0U); + + test.dOp1 = -std::numeric_limits<double>::max(); // lowest() + test.dOp2 = -std::numeric_limits<double>::max(); // lowest() + test.fOp1 = std::numeric_limits<float>::max(); + test.fOp2 = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 0U); + CHECK_EQ(test.dEq, 1U); + CHECK_EQ(test.dUeq, 1U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 0U); + CHECK_EQ(test.dOle, 1U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 0U); + CHECK_EQ(test.fEq, 1U); + CHECK_EQ(test.fUeq, 1U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 0U); + CHECK_EQ(test.fOle, 1U); + CHECK_EQ(test.fUle, 1U); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = 0.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = 0.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dF, 0U); + CHECK_EQ(test.dUn, 1U); + CHECK_EQ(test.dEq, 0U); + CHECK_EQ(test.dUeq, 1U); + CHECK_EQ(test.dOlt, 0U); + CHECK_EQ(test.dUlt, 1U); + CHECK_EQ(test.dOle, 0U); + CHECK_EQ(test.dUle, 1U); + CHECK_EQ(test.fF, 0U); + CHECK_EQ(test.fUn, 1U); + CHECK_EQ(test.fEq, 0U); + CHECK_EQ(test.fUeq, 1U); + CHECK_EQ(test.fOlt, 0U); + CHECK_EQ(test.fUlt, 1U); + CHECK_EQ(test.fOle, 0U); + CHECK_EQ(test.fUle, 1U); + } +} + + +TEST(CMP_COND_FMT) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + double dOp1; + double dOp2; + double dF; + double dUn; + double dEq; + double dUeq; + double dOlt; + double dUlt; + double dOle; + double dUle; + double dOr; + double dUne; + double dNe; + float fOp1; + float fOp2; + float fF; + float fUn; + float fEq; + float fUeq; + float fOlt; + float fUlt; + float fOle; + float fUle; + float fOr; + float fUne; + float fNe; + } TestFloat; + + TestFloat test; + + __ li(t1, 1); + + __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, dOp1))); + __ ldc1(f6, MemOperand(a0, offsetof(TestFloat, dOp2))); + + __ lwc1(f14, MemOperand(a0, offsetof(TestFloat, fOp1))); + __ lwc1(f16, MemOperand(a0, offsetof(TestFloat, fOp2))); + + __ cmp_d(F, f2, f4, f6); + __ cmp_s(F, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dF)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fF)) ); + + __ cmp_d(UN, f2, f4, f6); + __ cmp_s(UN, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUn)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUn)) ); + + __ cmp_d(EQ, f2, f4, f6); + __ cmp_s(EQ, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dEq)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fEq)) ); + + __ cmp_d(UEQ, f2, f4, f6); + __ cmp_s(UEQ, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUeq)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUeq)) ); + + __ cmp_d(LT, f2, f4, f6); + __ cmp_s(LT, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOlt)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOlt)) ); + + __ cmp_d(ULT, f2, f4, f6); + __ cmp_s(ULT, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUlt)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUlt)) ); + + __ cmp_d(LE, f2, f4, f6); + __ cmp_s(LE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOle)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOle)) ); + + __ cmp_d(ULE, f2, f4, f6); + __ cmp_s(ULE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUle)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUle)) ); + + __ cmp_d(ORD, f2, f4, f6); + __ cmp_s(ORD, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dOr)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fOr)) ); + + __ cmp_d(UNE, f2, f4, f6); + __ cmp_s(UNE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dUne)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fUne)) ); + + __ cmp_d(NE, f2, f4, f6); + __ cmp_s(NE, f12, f14, f16); + __ sdc1(f2, MemOperand(a0, offsetof(TestFloat, dNe)) ); + __ swc1(f12, MemOperand(a0, offsetof(TestFloat, fNe)) ); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + uint64_t dTrue = 0xFFFFFFFFFFFFFFFF; + uint64_t dFalse = 0x0000000000000000; + uint32_t fTrue = 0xFFFFFFFF; + uint32_t fFalse = 0x00000000; + + test.dOp1 = 2.0; + test.dOp2 = 3.0; + test.fOp1 = 2.0; + test.fOp2 = 3.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + + test.dOp1 = std::numeric_limits<double>::max(); + test.dOp2 = std::numeric_limits<double>::min(); + test.fOp1 = std::numeric_limits<float>::min(); + test.fOp2 = -std::numeric_limits<float>::max(); // lowest() + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fFalse); + + test.dOp1 = -std::numeric_limits<double>::max(); // lowest() + test.dOp2 = -std::numeric_limits<double>::max(); // lowest() + test.fOp1 = std::numeric_limits<float>::max(); + test.fOp2 = std::numeric_limits<float>::max(); + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = 0.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = 0.0; + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(bit_cast<uint64_t>(test.dF), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUn), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dEq), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUeq), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOlt), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUlt), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOle), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUle), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dOr), dFalse); + CHECK_EQ(bit_cast<uint64_t>(test.dUne), dTrue); + CHECK_EQ(bit_cast<uint64_t>(test.dNe), dFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fF), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUn), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fEq), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUeq), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOlt), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUlt), fTrue); + CHECK_EQ(bit_cast<uint32_t>(test.fOle), fFalse); + CHECK_EQ(bit_cast<uint32_t>(test.fUle), fTrue); + } +} + + +TEST(CVT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test_float { + float cvt_d_s_in; + double cvt_d_s_out; + int32_t cvt_d_w_in; + double cvt_d_w_out; + int64_t cvt_d_l_in; + double cvt_d_l_out; + + float cvt_l_s_in; + int64_t cvt_l_s_out; + double cvt_l_d_in; + int64_t cvt_l_d_out; + + double cvt_s_d_in; + float cvt_s_d_out; + int32_t cvt_s_w_in; + float cvt_s_w_out; + int64_t cvt_s_l_in; + float cvt_s_l_out; + + float cvt_w_s_in; + int32_t cvt_w_s_out; + double cvt_w_d_in; + int32_t cvt_w_d_out; + } TestFloat; + + TestFloat test; + + // Save FCSR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + +#define GENERATE_CVT_TEST(x, y, z) \ + __ y##c1(f0, MemOperand(a0, offsetof(TestFloat, x##_in))); \ + __ x(f0, f0); \ + __ nop(); \ + __ z##c1(f0, MemOperand(a0, offsetof(TestFloat, x##_out))); + + GENERATE_CVT_TEST(cvt_d_s, lw, sd) + GENERATE_CVT_TEST(cvt_d_w, lw, sd) + GENERATE_CVT_TEST(cvt_d_l, ld, sd) + + GENERATE_CVT_TEST(cvt_l_s, lw, sd) + GENERATE_CVT_TEST(cvt_l_d, ld, sd) + + GENERATE_CVT_TEST(cvt_s_d, ld, sw) + GENERATE_CVT_TEST(cvt_s_w, lw, sw) + GENERATE_CVT_TEST(cvt_s_l, ld, sw) + + GENERATE_CVT_TEST(cvt_w_s, lw, sw) + GENERATE_CVT_TEST(cvt_w_d, ld, sw) + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + test.cvt_d_s_in = -0.51; + test.cvt_d_w_in = -1; + test.cvt_d_l_in = -1; + test.cvt_l_s_in = -0.51; + test.cvt_l_d_in = -0.51; + test.cvt_s_d_in = -0.51; + test.cvt_s_w_in = -1; + test.cvt_s_l_in = -1; + test.cvt_w_s_in = -0.51; + test.cvt_w_d_in = -0.51; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + CHECK_EQ(test.cvt_l_s_out, -1); + CHECK_EQ(test.cvt_l_d_out, -1); + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + CHECK_EQ(test.cvt_w_s_out, -1); + CHECK_EQ(test.cvt_w_d_out, -1); + + + test.cvt_d_s_in = 0.49; + test.cvt_d_w_in = 1; + test.cvt_d_l_in = 1; + test.cvt_l_s_in = 0.49; + test.cvt_l_d_in = 0.49; + test.cvt_s_d_in = 0.49; + test.cvt_s_w_in = 1; + test.cvt_s_l_in = 1; + test.cvt_w_s_in = 0.49; + test.cvt_w_d_in = 0.49; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + CHECK_EQ(test.cvt_l_s_out, 0); + CHECK_EQ(test.cvt_l_d_out, 0); + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + CHECK_EQ(test.cvt_w_s_out, 0); + CHECK_EQ(test.cvt_w_d_out, 0); + + test.cvt_d_s_in = std::numeric_limits<float>::max(); + test.cvt_d_w_in = std::numeric_limits<int32_t>::max(); + test.cvt_d_l_in = std::numeric_limits<int64_t>::max(); + test.cvt_l_s_in = std::numeric_limits<float>::max(); + test.cvt_l_d_in = std::numeric_limits<double>::max(); + test.cvt_s_d_in = std::numeric_limits<double>::max(); + test.cvt_s_w_in = std::numeric_limits<int32_t>::max(); + test.cvt_s_l_in = std::numeric_limits<int64_t>::max(); + test.cvt_w_s_in = std::numeric_limits<float>::max(); + test.cvt_w_d_in = std::numeric_limits<double>::max(); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + CHECK_EQ(test.cvt_l_s_out, std::numeric_limits<int64_t>::max()); + CHECK_EQ(test.cvt_l_d_out, std::numeric_limits<int64_t>::max()); + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + CHECK_EQ(test.cvt_w_s_out, std::numeric_limits<int32_t>::max()); + CHECK_EQ(test.cvt_w_d_out, std::numeric_limits<int32_t>::max()); + + + test.cvt_d_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_d_w_in = std::numeric_limits<int32_t>::min(); // lowest() + test.cvt_d_l_in = std::numeric_limits<int64_t>::min(); // lowest() + test.cvt_l_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_l_d_in = -std::numeric_limits<double>::max(); // lowest() + test.cvt_s_d_in = -std::numeric_limits<double>::max(); // lowest() + test.cvt_s_w_in = std::numeric_limits<int32_t>::min(); // lowest() + test.cvt_s_l_in = std::numeric_limits<int64_t>::min(); // lowest() + test.cvt_w_s_in = -std::numeric_limits<float>::max(); // lowest() + test.cvt_w_d_in = -std::numeric_limits<double>::max(); // lowest() + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + // The returned value when converting from fixed-point to float-point + // is not consistent between board, simulator and specification + // in this test case, therefore modifying the test + CHECK(test.cvt_l_s_out == std::numeric_limits<int64_t>::min() || + test.cvt_l_s_out == std::numeric_limits<int64_t>::max()); + CHECK(test.cvt_l_d_out == std::numeric_limits<int64_t>::min() || + test.cvt_l_d_out == std::numeric_limits<int64_t>::max()); + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + CHECK(test.cvt_w_s_out == std::numeric_limits<int32_t>::min() || + test.cvt_w_s_out == std::numeric_limits<int32_t>::max()); + CHECK(test.cvt_w_d_out == std::numeric_limits<int32_t>::min() || + test.cvt_w_d_out == std::numeric_limits<int32_t>::max()); + + + test.cvt_d_s_in = std::numeric_limits<float>::min(); + test.cvt_d_w_in = std::numeric_limits<int32_t>::min(); + test.cvt_d_l_in = std::numeric_limits<int64_t>::min(); + test.cvt_l_s_in = std::numeric_limits<float>::min(); + test.cvt_l_d_in = std::numeric_limits<double>::min(); + test.cvt_s_d_in = std::numeric_limits<double>::min(); + test.cvt_s_w_in = std::numeric_limits<int32_t>::min(); + test.cvt_s_l_in = std::numeric_limits<int64_t>::min(); + test.cvt_w_s_in = std::numeric_limits<float>::min(); + test.cvt_w_d_in = std::numeric_limits<double>::min(); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.cvt_d_s_out, static_cast<double>(test.cvt_d_s_in)); + CHECK_EQ(test.cvt_d_w_out, static_cast<double>(test.cvt_d_w_in)); + CHECK_EQ(test.cvt_d_l_out, static_cast<double>(test.cvt_d_l_in)); + CHECK_EQ(test.cvt_l_s_out, 0); + CHECK_EQ(test.cvt_l_d_out, 0); + CHECK_EQ(test.cvt_s_d_out, static_cast<float>(test.cvt_s_d_in)); + CHECK_EQ(test.cvt_s_w_out, static_cast<float>(test.cvt_s_w_in)); + CHECK_EQ(test.cvt_s_l_out, static_cast<float>(test.cvt_s_l_in)); + CHECK_EQ(test.cvt_w_s_out, 0); + CHECK_EQ(test.cvt_w_d_out, 0); +} + + +TEST(DIV_FMT) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0); + + typedef struct test { + double dOp1; + double dOp2; + double dRes; + float fOp1; + float fOp2; + float fRes; + } Test; + + Test test; + + // Save FCSR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); + + __ ldc1(f4, MemOperand(a0, offsetof(Test, dOp1)) ); + __ ldc1(f2, MemOperand(a0, offsetof(Test, dOp2)) ); + __ nop(); + __ div_d(f6, f4, f2); + __ sdc1(f6, MemOperand(a0, offsetof(Test, dRes)) ); + + __ lwc1(f4, MemOperand(a0, offsetof(Test, fOp1)) ); + __ lwc1(f2, MemOperand(a0, offsetof(Test, fOp2)) ); + __ nop(); + __ div_s(f6, f4, f2); + __ swc1(f6, MemOperand(a0, offsetof(Test, fRes)) ); + + // Restore FCSR. + __ ctc1(a1, FCSR); + + __ jr(ra); + __ nop(); + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + + const int test_size = 3; + + double dOp1[test_size] = { + 5.0, + DBL_MAX, + DBL_MAX, + }; + double dOp2[test_size] = { + 2.0, + 2.0, + -DBL_MAX, + }; + double dRes[test_size] = { + 2.5, + DBL_MAX / 2.0, + -1.0, + }; + float fOp1[test_size] = { + 5.0, + FLT_MAX, + FLT_MAX, + }; + float fOp2[test_size] = { + 2.0, + 2.0, + -FLT_MAX, + }; + float fRes[test_size] = { + 2.5, + FLT_MAX / 2.0, + -1.0, + }; + + for (int i = 0; i < test_size; i++) { + test.dOp1 = dOp1[i]; + test.dOp2 = dOp2[i]; + test.fOp1 = fOp1[i]; + test.fOp2 = fOp2[i]; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(test.dRes, dRes[i]); + CHECK_EQ(test.fRes, fRes[i]); + } + + test.dOp1 = DBL_MAX; + test.dOp2 = -0.0; + test.fOp1 = FLT_MAX; + test.fOp2 = -0.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(false, std::isfinite(test.dRes)); + CHECK_EQ(false, std::isfinite(test.fRes)); + + test.dOp1 = 0.0; + test.dOp2 = -0.0; + test.fOp1 = 0.0; + test.fOp2 = -0.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(true, std::isnan(test.dRes)); + CHECK_EQ(true, std::isnan(test.fRes)); + + test.dOp1 = std::numeric_limits<double>::quiet_NaN(); + test.dOp2 = -5.0; + test.fOp1 = std::numeric_limits<float>::quiet_NaN(); + test.fOp2 = -5.0; + + (CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0)); + CHECK_EQ(true, std::isnan(test.dRes)); + CHECK_EQ(true, std::isnan(test.fRes)); +} + + +uint64_t run_align(uint64_t rs_value, uint64_t rt_value, uint8_t bp) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ align(v0, a0, a1, bp); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value, + rt_value, + 0, 0, 0)); + + return res; +} + + +TEST(r6_align) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseAlign { + uint64_t rs_value; + uint64_t rt_value; + uint8_t bp; + uint64_t expected_res; + }; + + struct TestCaseAlign tc[] = { + // rs_value, rt_value, bp, expected_res + { 0x11223344, 0xaabbccdd, 0, 0xffffffffaabbccdd }, + { 0x11223344, 0xaabbccdd, 1, 0xffffffffbbccdd11 }, + { 0x11223344, 0xaabbccdd, 2, 0xffffffffccdd1122 }, + { 0x11223344, 0xaabbccdd, 3, 0xffffffffdd112233 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign); + for (size_t i = 0; i < nr_test_cases; ++i) { + CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value, + tc[i].rt_value, + tc[i].bp)); + } + } +} + + +uint64_t run_dalign(uint64_t rs_value, uint64_t rt_value, uint8_t bp) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ dalign(v0, a0, a1, bp); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F4 f = FUNCTION_CAST<F4>(code->entry()); + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value, + rt_value, + 0, 0, 0)); + + return res; +} + + +TEST(r6_dalign) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseDalign { + uint64_t rs_value; + uint64_t rt_value; + uint8_t bp; + uint64_t expected_res; + }; + + struct TestCaseDalign tc[] = { + // rs_value, rt_value, bp, expected_res + { 0x1122334455667700, 0xaabbccddeeff8899, 0, 0xaabbccddeeff8899 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 1, 0xbbccddeeff889911 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 2, 0xccddeeff88991122 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 3, 0xddeeff8899112233 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 4, 0xeeff889911223344 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 5, 0xff88991122334455 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 6, 0x8899112233445566 }, + { 0x1122334455667700, 0xaabbccddeeff8899, 7, 0x9911223344556677 } + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseDalign); + for (size_t i = 0; i < nr_test_cases; ++i) { + CHECK_EQ(tc[i].expected_res, run_dalign(tc[i].rs_value, + tc[i].rt_value, + tc[i].bp)); + } + } +} + + +uint64_t PC; // The program counter. + +uint64_t run_aluipc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ aluipc(v0, offset); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint64_t) f; // Set the program counter. + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_aluipc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseAluipc { + int16_t offset; + }; + + struct TestCaseAluipc tc[] = { + // offset + { -32768 }, // 0x8000 + { -1 }, // 0xFFFF + { 0 }, + { 1 }, + { 32767 }, // 0x7FFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint64_t res = run_aluipc(tc[i].offset); + // Now, the program_counter (PC) is set. + uint64_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16)); + CHECK_EQ(expected_res, res); + } + } +} + + +uint64_t run_auipc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ auipc(v0, offset); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint64_t) f; // Set the program counter. + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_auipc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseAuipc { + int16_t offset; + }; + + struct TestCaseAuipc tc[] = { + // offset + { -32768 }, // 0x8000 + { -1 }, // 0xFFFF + { 0 }, + { 1 }, + { 32767 }, // 0x7FFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint64_t res = run_auipc(tc[i].offset); + // Now, the program_counter (PC) is set. + uint64_t expected_res = PC + (tc[i].offset << 16); + CHECK_EQ(expected_res, res); + } + } +} + + +uint64_t run_lwpc(int offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + // 256k instructions; 2^8k + // addiu t3, a4, 0xffff; (0x250fffff) + // ... + // addiu t0, a4, 0x0000; (0x250c0000) + uint32_t addiu_start_1 = 0x25000000; + for (int32_t i = 0xfffff; i >= 0xc0000; --i) { + uint32_t addiu_new = addiu_start_1 + i; + __ dd(addiu_new); + } + + __ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register) + __ mov(v0, t8); + + // 256k instructions; 2^8k + // addiu a4, a4, 0x0000; (0x25080000) + // ... + // addiu a7, a4, 0xffff; (0x250bffff) + uint32_t addiu_start_2 = 0x25000000; + for (int32_t i = 0x80000; i <= 0xbffff; ++i) { + uint32_t addiu_new = addiu_start_2 + i; + __ dd(addiu_new); + } + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_lwpc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseLwpc { + int offset; + uint64_t expected_res; + }; + + struct TestCaseLwpc tc[] = { + // offset, expected_res + { -262144, 0x250fffff }, // offset 0x40000 + { -4, 0x250c0003 }, + { -1, 0x250c0000 }, + { 0, 0xffffffffef080000 }, + { 1, 0x03001025 }, // mov(v0, t8) + { 2, 0x25080000 }, + { 4, 0x25080002 }, + { 262143, 0x250bfffd }, // offset 0x3ffff + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_lwpc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_lwupc(int offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + // 256k instructions; 2^8k + // addiu t3, a4, 0xffff; (0x250fffff) + // ... + // addiu t0, a4, 0x0000; (0x250c0000) + uint32_t addiu_start_1 = 0x25000000; + for (int32_t i = 0xfffff; i >= 0xc0000; --i) { + uint32_t addiu_new = addiu_start_1 + i; + __ dd(addiu_new); + } + + __ lwupc(t8, offset); // offset 0; 0xef080000 (t8 register) + __ mov(v0, t8); + + // 256k instructions; 2^8k + // addiu a4, a4, 0x0000; (0x25080000) + // ... + // addiu a7, a4, 0xffff; (0x250bffff) + uint32_t addiu_start_2 = 0x25000000; + for (int32_t i = 0x80000; i <= 0xbffff; ++i) { + uint32_t addiu_new = addiu_start_2 + i; + __ dd(addiu_new); + } + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_lwupc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseLwupc { + int offset; + uint64_t expected_res; + }; + + struct TestCaseLwupc tc[] = { + // offset, expected_res + { -262144, 0x250fffff }, // offset 0x40000 + { -4, 0x250c0003 }, + { -1, 0x250c0000 }, + { 0, 0xef100000 }, + { 1, 0x03001025 }, // mov(v0, t8) + { 2, 0x25080000 }, + { 4, 0x25080002 }, + { 262143, 0x250bfffd }, // offset 0x3ffff + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwupc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_lwupc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_jic(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label get_program_counter, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t1, 0x66); + + __ addiu(v0, v0, 0x1); // <-- offset = -32 + __ addiu(v0, v0, 0x2); + __ addiu(v0, v0, 0x10); + __ addiu(v0, v0, 0x20); + __ beq(v0, t1, &stop_execution); + __ nop(); + + __ bal(&get_program_counter); // t0 <- program counter + __ nop(); + __ jic(t0, offset); + + __ addiu(v0, v0, 0x100); + __ addiu(v0, v0, 0x200); + __ addiu(v0, v0, 0x1000); + __ addiu(v0, v0, 0x2000); // <--- offset = 16 + __ pop(ra); + __ jr(ra); + __ nop(); + + __ bind(&get_program_counter); + __ mov(t0, ra); + __ jr(ra); + __ nop(); + + __ bind(&stop_execution); + __ pop(ra); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_jic) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseJic { + // As rt will be used t0 register which will have value of + // the program counter for the jic instruction. + int16_t offset; + uint32_t expected_res; + }; + + struct TestCaseJic tc[] = { + // offset, expected_result + { 16, 0x2033 }, + { 4, 0x3333 }, + { -32, 0x66 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_jic(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_beqzc(int32_t value, int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label stop_execution; + __ li(v0, 0); + __ li(t1, 0x66); + + __ addiu(v0, v0, 0x1); // <-- offset = -8 + __ addiu(v0, v0, 0x2); + __ addiu(v0, v0, 0x10); + __ addiu(v0, v0, 0x20); + __ beq(v0, t1, &stop_execution); + __ nop(); + + __ beqzc(a0, offset); + + __ addiu(v0, v0, 0x1); + __ addiu(v0, v0, 0x100); + __ addiu(v0, v0, 0x200); + __ addiu(v0, v0, 0x1000); + __ addiu(v0, v0, 0x2000); // <--- offset = 4 + __ jr(ra); + __ nop(); + + __ bind(&stop_execution); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_beqzc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseBeqzc { + uint32_t value; + int32_t offset; + uint32_t expected_res; + }; + + struct TestCaseBeqzc tc[] = { + // value, offset, expected_res + { 0x0, -8, 0x66 }, + { 0x0, 0, 0x3334 }, + { 0x0, 1, 0x3333 }, + { 0xabc, 1, 0x3334 }, + { 0x0, 4, 0x2033 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_beqzc(tc[i].value, tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_jialc(int16_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label main_block, get_program_counter; + __ push(ra); + __ li(v0, 0); + __ beq(v0, v0, &main_block); + __ nop(); + + // Block 1 + __ addiu(v0, v0, 0x1); // <-- offset = -40 + __ addiu(v0, v0, 0x2); + __ jr(ra); + __ nop(); + + // Block 2 + __ addiu(v0, v0, 0x10); // <-- offset = -24 + __ addiu(v0, v0, 0x20); + __ jr(ra); + __ nop(); + + // Block 3 (Main) + __ bind(&main_block); + __ bal(&get_program_counter); // t0 <- program counter + __ nop(); + __ jialc(t0, offset); + __ addiu(v0, v0, 0x4); + __ pop(ra); + __ jr(ra); + __ nop(); + + // Block 4 + __ addiu(v0, v0, 0x100); // <-- offset = 20 + __ addiu(v0, v0, 0x200); + __ jr(ra); + __ nop(); + + // Block 5 + __ addiu(v0, v0, 0x1000); // <--- offset = 36 + __ addiu(v0, v0, 0x2000); + __ jr(ra); + __ nop(); + + __ bind(&get_program_counter); + __ mov(t0, ra); + __ jr(ra); + __ nop(); + + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_jialc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseJialc { + // As rt will be used t0 register which will have value of + // the program counter for the jialc instruction. + int16_t offset; + uint32_t expected_res; + }; + + struct TestCaseJialc tc[] = { + // offset, expected_res + { -40, 0x7 }, + { -24, 0x34 }, + { 20, 0x304 }, + { 36, 0x3004 } + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_jialc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +uint64_t run_addiupc(int32_t imm19) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + __ addiupc(v0, imm19); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + PC = (uint64_t) f; // Set the program counter. + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_addiupc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseAddiupc { + int32_t imm19; + }; + + struct TestCaseAddiupc tc[] = { + // imm19 + { -262144 }, // 0x40000 + { -1 }, // 0x7FFFF + { 0 }, + { 1 }, // 0x00001 + { 262143 } // 0x3FFFF + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc); + for (size_t i = 0; i < nr_test_cases; ++i) { + PC = 0; + uint64_t res = run_addiupc(tc[i].imm19); + // Now, the program_counter (PC) is set. + uint64_t expected_res = PC + (tc[i].imm19 << 2); + CHECK_EQ(expected_res, res); + } + } +} + + +uint64_t run_ldpc(int offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + // 256k instructions; 2 * 2^7k = 2^8k + // addiu t3, a4, 0xffff; (0x250fffff) + // ... + // addiu t0, a4, 0x0000; (0x250c0000) + uint32_t addiu_start_1 = 0x25000000; + for (int32_t i = 0xfffff; i >= 0xc0000; --i) { + uint32_t addiu_new = addiu_start_1 + i; + __ dd(addiu_new); + } + + __ ldpc(t8, offset); // offset 0; 0xef080000 (t8 register) + __ mov(v0, t8); + + // 256k instructions; 2 * 2^7k = 2^8k + // addiu a4, a4, 0x0000; (0x25080000) + // ... + // addiu a7, a4, 0xffff; (0x250bffff) + uint32_t addiu_start_2 = 0x25000000; + for (int32_t i = 0x80000; i <= 0xbffff; ++i) { + uint32_t addiu_new = addiu_start_2 + i; + __ dd(addiu_new); + } + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = + reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_ldpc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseLdpc { + int offset; + uint64_t expected_res; + }; + + struct TestCaseLdpc tc[] = { + // offset, expected_res + { -131072, 0x250ffffe250fffff }, + { -4, 0x250c0006250c0007 }, + { -1, 0x250c0000250c0001 }, + { 0, 0x03001025ef180000 }, + { 1, 0x2508000125080000 }, + { 4, 0x2508000725080006 }, + { 131071, 0x250bfffd250bfffc }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLdpc); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_ldpc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +int64_t run_bc(int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label continue_1, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t8, 0); + __ li(t9, 2); // Condition for the stopping execution. + + uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1 + for (int32_t i = -100; i <= -11; ++i) { + __ dd(instruction_addiu); + } + + __ addiu(t8, t8, 1); // -10 + + __ beq(t8, t9, &stop_execution); // -9 + __ nop(); // -8 + __ beq(t8, t8, &continue_1); // -7 + __ nop(); // -6 + + __ bind(&stop_execution); + __ pop(ra); // -5, -4 + __ jr(ra); // -3 + __ nop(); // -2 + + __ bind(&continue_1); + __ bc(offset); // -1 + + for (int32_t i = 0; i <= 99; ++i) { + __ dd(instruction_addiu); + } + + __ pop(ra); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + int64_t res = + reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_bc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseBc { + int32_t offset; + int64_t expected_res; + }; + + struct TestCaseBc tc[] = { + // offset, expected_result + { -100, (abs(-100) - 10) * 2 }, + { -11, (abs(-100) - 10 + 1) }, + { 0, (abs(-100) - 10 + 1 + 99) }, + { 1, (abs(-100) - 10 + 99) }, + { 99, (abs(-100) - 10 + 1) }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc); + for (size_t i = 0; i < nr_test_cases; ++i) { + int64_t res = run_bc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + +int64_t run_balc(int32_t offset) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label continue_1, stop_execution; + __ push(ra); + __ li(v0, 0); + __ li(t8, 0); + __ li(t9, 2); // Condition for stopping execution. + + __ beq(t8, t8, &continue_1); + __ nop(); + + uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1 + for (int32_t i = -117; i <= -57; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); // -56 + __ nop(); // -55 + + for (int32_t i = -54; i <= -4; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); // -3 + __ nop(); // -2 + + __ bind(&continue_1); + __ balc(offset); // -1 + + __ pop(ra); // 0, 1 + __ jr(ra); // 2 + __ nop(); // 3 + + for (int32_t i = 4; i <= 44; ++i) { + __ dd(instruction_addiu); + } + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + int64_t res = + reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(r6_balc) { + if (kArchVariant == kMips64r6) { + CcTest::InitializeVM(); + + struct TestCaseBalc { + int32_t offset; + int64_t expected_res; + }; + + struct TestCaseBalc tc[] = { + // offset, expected_result + { -117, 61 }, + { -54, 51 }, + { 0, 0 }, + { 4, 41 }, + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc); + for (size_t i = 0; i < nr_test_cases; ++i) { + int64_t res = run_balc(tc[i].offset); + CHECK_EQ(tc[i].expected_res, res); + } + } +} + + #undef __ diff --git a/deps/v8/test/cctest/test-assembler-ppc.cc b/deps/v8/test/cctest/test-assembler-ppc.cc index 4a2e7d3983..b2dca6a9fc 100644 --- a/deps/v8/test/cctest/test-assembler-ppc.cc +++ b/deps/v8/test/cctest/test-assembler-ppc.cc @@ -194,21 +194,21 @@ TEST(3) { __ mr(r4, r3); // modify field int i of struct - __ lwz(r3, MemOperand(r4, OFFSET_OF(T, i))); + __ lwz(r3, MemOperand(r4, offsetof(T, i))); __ srwi(r5, r3, Operand(1)); - __ stw(r5, MemOperand(r4, OFFSET_OF(T, i))); + __ stw(r5, MemOperand(r4, offsetof(T, i))); // modify field char c of struct - __ lbz(r5, MemOperand(r4, OFFSET_OF(T, c))); + __ lbz(r5, MemOperand(r4, offsetof(T, c))); __ add(r3, r5, r3); __ slwi(r5, r5, Operand(2)); - __ stb(r5, MemOperand(r4, OFFSET_OF(T, c))); + __ stb(r5, MemOperand(r4, offsetof(T, c))); // modify field int16_t s of struct - __ lhz(r5, MemOperand(r4, OFFSET_OF(T, s))); + __ lhz(r5, MemOperand(r4, offsetof(T, s))); __ add(r3, r5, r3); __ srwi(r5, r5, Operand(3)); - __ sth(r5, MemOperand(r4, OFFSET_OF(T, s))); + __ sth(r5, MemOperand(r4, offsetof(T, s))); // restore frame #if V8_TARGET_ARCH_PPC64 @@ -278,59 +278,59 @@ TEST(4) { __ sub(fp, ip, Operand(4)); __ mov(r4, Operand(r0)); - __ vldr(d6, r4, OFFSET_OF(T, a)); - __ vldr(d7, r4, OFFSET_OF(T, b)); + __ vldr(d6, r4, offsetof(T, a)); + __ vldr(d7, r4, offsetof(T, b)); __ vadd(d5, d6, d7); - __ vstr(d5, r4, OFFSET_OF(T, c)); + __ vstr(d5, r4, offsetof(T, c)); __ vmov(r2, r3, d5); __ vmov(d4, r2, r3); - __ vstr(d4, r4, OFFSET_OF(T, b)); + __ vstr(d4, r4, offsetof(T, b)); // Load t.x and t.y, switch values, and store back to the struct. - __ vldr(s0, r4, OFFSET_OF(T, x)); - __ vldr(s31, r4, OFFSET_OF(T, y)); + __ vldr(s0, r4, offsetof(T, x)); + __ vldr(s31, r4, offsetof(T, y)); __ vmov(s16, s0); __ vmov(s0, s31); __ vmov(s31, s16); - __ vstr(s0, r4, OFFSET_OF(T, x)); - __ vstr(s31, r4, OFFSET_OF(T, y)); + __ vstr(s0, r4, offsetof(T, x)); + __ vstr(s31, r4, offsetof(T, y)); // Move a literal into a register that can be encoded in the instruction. __ vmov(d4, 1.0); - __ vstr(d4, r4, OFFSET_OF(T, e)); + __ vstr(d4, r4, offsetof(T, e)); // Move a literal into a register that requires 64 bits to encode. // 0x3ff0000010000000 = 1.000000059604644775390625 __ vmov(d4, 1.000000059604644775390625); - __ vstr(d4, r4, OFFSET_OF(T, d)); + __ vstr(d4, r4, offsetof(T, d)); // Convert from floating point to integer. __ vmov(d4, 2.0); __ vcvt_s32_f64(s31, d4); - __ vstr(s31, r4, OFFSET_OF(T, i)); + __ vstr(s31, r4, offsetof(T, i)); // Convert from integer to floating point. __ mov(lr, Operand(42)); __ vmov(s31, lr); __ vcvt_f64_s32(d4, s31); - __ vstr(d4, r4, OFFSET_OF(T, f)); + __ vstr(d4, r4, offsetof(T, f)); // Test vabs. - __ vldr(d1, r4, OFFSET_OF(T, g)); + __ vldr(d1, r4, offsetof(T, g)); __ vabs(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, g)); - __ vldr(d2, r4, OFFSET_OF(T, h)); + __ vstr(d0, r4, offsetof(T, g)); + __ vldr(d2, r4, offsetof(T, h)); __ vabs(d0, d2); - __ vstr(d0, r4, OFFSET_OF(T, h)); + __ vstr(d0, r4, offsetof(T, h)); // Test vneg. - __ vldr(d1, r4, OFFSET_OF(T, m)); + __ vldr(d1, r4, offsetof(T, m)); __ vneg(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, m)); - __ vldr(d1, r4, OFFSET_OF(T, n)); + __ vstr(d0, r4, offsetof(T, m)); + __ vldr(d1, r4, offsetof(T, n)); __ vneg(d0, d1); - __ vstr(d0, r4, OFFSET_OF(T, n)); + __ vstr(d0, r4, offsetof(T, n)); __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); @@ -677,19 +677,19 @@ TEST(8) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ addi(r4, r0, Operand(OFFSET_OF(D, a))); + __ addi(r4, r0, Operand(offsetof(D, a))); __ vldm(ia_w, r4, d0, d3); __ vldm(ia_w, r4, d4, d7); - __ addi(r4, r0, Operand(OFFSET_OF(D, a))); + __ addi(r4, r0, Operand(offsetof(D, a))); __ vstm(ia_w, r4, d6, d7); __ vstm(ia_w, r4, d0, d5); - __ addi(r4, r1, Operand(OFFSET_OF(F, a))); + __ addi(r4, r1, Operand(offsetof(F, a))); __ vldm(ia_w, r4, s0, s3); __ vldm(ia_w, r4, s4, s7); - __ addi(r4, r1, Operand(OFFSET_OF(F, a))); + __ addi(r4, r1, Operand(offsetof(F, a))); __ vstm(ia_w, r4, s6, s7); __ vstm(ia_w, r4, s0, s5); @@ -789,22 +789,22 @@ TEST(9) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ addi(r4, r0, Operand(OFFSET_OF(D, a))); + __ addi(r4, r0, Operand(offsetof(D, a))); __ vldm(ia, r4, d0, d3); __ addi(r4, r4, Operand(4 * 8)); __ vldm(ia, r4, d4, d7); - __ addi(r4, r0, Operand(OFFSET_OF(D, a))); + __ addi(r4, r0, Operand(offsetof(D, a))); __ vstm(ia, r4, d6, d7); __ addi(r4, r4, Operand(2 * 8)); __ vstm(ia, r4, d0, d5); - __ addi(r4, r1, Operand(OFFSET_OF(F, a))); + __ addi(r4, r1, Operand(offsetof(F, a))); __ vldm(ia, r4, s0, s3); __ addi(r4, r4, Operand(4 * 4)); __ vldm(ia, r4, s4, s7); - __ addi(r4, r1, Operand(OFFSET_OF(F, a))); + __ addi(r4, r1, Operand(offsetof(F, a))); __ vstm(ia, r4, s6, s7); __ addi(r4, r4, Operand(2 * 4)); __ vstm(ia, r4, s0, s5); @@ -905,19 +905,19 @@ TEST(10) { __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); - __ addi(r4, r0, Operand(OFFSET_OF(D, h) + 8)); + __ addi(r4, r0, Operand(offsetof(D, h) + 8)); __ vldm(db_w, r4, d4, d7); __ vldm(db_w, r4, d0, d3); - __ addi(r4, r0, Operand(OFFSET_OF(D, h) + 8)); + __ addi(r4, r0, Operand(offsetof(D, h) + 8)); __ vstm(db_w, r4, d0, d5); __ vstm(db_w, r4, d6, d7); - __ addi(r4, r1, Operand(OFFSET_OF(F, h) + 4)); + __ addi(r4, r1, Operand(offsetof(F, h) + 4)); __ vldm(db_w, r4, s4, s7); __ vldm(db_w, r4, s0, s3); - __ addi(r4, r1, Operand(OFFSET_OF(F, h) + 4)); + __ addi(r4, r1, Operand(offsetof(F, h) + 4)); __ vstm(db_w, r4, s0, s5); __ vstm(db_w, r4, s6, s7); @@ -996,28 +996,28 @@ TEST(11) { Assembler assm(isolate, NULL, 0); // Test HeapObject untagging. - __ ldr(r1, MemOperand(r0, OFFSET_OF(I, a))); + __ ldr(r1, MemOperand(r0, offsetof(I, a))); __ mov(r1, Operand(r1, ASR, 1), SetCC); __ adc(r1, r1, Operand(r1), LeaveCC, cs); - __ str(r1, MemOperand(r0, OFFSET_OF(I, a))); + __ str(r1, MemOperand(r0, offsetof(I, a))); - __ ldr(r2, MemOperand(r0, OFFSET_OF(I, b))); + __ ldr(r2, MemOperand(r0, offsetof(I, b))); __ mov(r2, Operand(r2, ASR, 1), SetCC); __ adc(r2, r2, Operand(r2), LeaveCC, cs); - __ str(r2, MemOperand(r0, OFFSET_OF(I, b))); + __ str(r2, MemOperand(r0, offsetof(I, b))); // Test corner cases. __ mov(r1, Operand(0xffffffff)); __ mov(r2, Operand::Zero()); __ mov(r3, Operand(r1, ASR, 1), SetCC); // Set the carry. __ adc(r3, r1, Operand(r2)); - __ str(r3, MemOperand(r0, OFFSET_OF(I, c))); + __ str(r3, MemOperand(r0, offsetof(I, c))); __ mov(r1, Operand(0xffffffff)); __ mov(r2, Operand::Zero()); __ mov(r3, Operand(r2, ASR, 1), SetCC); // Unset the carry. __ adc(r3, r1, Operand(r2)); - __ str(r3, MemOperand(r0, OFFSET_OF(I, d))); + __ str(r3, MemOperand(r0, offsetof(I, d))); __ mov(pc, Operand(lr)); diff --git a/deps/v8/test/cctest/test-code-stubs-arm64.cc b/deps/v8/test/cctest/test-code-stubs-arm64.cc index 6d5b0f49be..8b38b96600 100644 --- a/deps/v8/test/cctest/test-code-stubs-arm64.cc +++ b/deps/v8/test/cctest/test-code-stubs-arm64.cc @@ -142,8 +142,8 @@ int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func, Simulator::CallArgument(from), Simulator::CallArgument::End() }; - return Simulator::current(Isolate::Current())->CallInt64( - FUNCTION_ADDR(func), args); + return static_cast<int32_t>(Simulator::current(Isolate::Current()) + ->CallInt64(FUNCTION_ADDR(func), args)); #else return (*func)(from); #endif diff --git a/deps/v8/test/cctest/test-code-stubs-mips64.cc b/deps/v8/test/cctest/test-code-stubs-mips64.cc index 1f7df380e1..9f146f65fd 100644 --- a/deps/v8/test/cctest/test-code-stubs-mips64.cc +++ b/deps/v8/test/cctest/test-code-stubs-mips64.cc @@ -144,7 +144,8 @@ int32_t RunGeneratedCodeCallWrapper(ConvertDToIFunc func, double from) { #ifdef USE_SIMULATOR Simulator::current(Isolate::Current())->CallFP(FUNCTION_ADDR(func), from, 0.); - return Simulator::current(Isolate::Current())->get_register(v0.code()); + return static_cast<int32_t>( + Simulator::current(Isolate::Current())->get_register(v0.code())); #else return (*func)(from); #endif diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index ed8b1c6d99..3b25480a4a 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -60,8 +60,8 @@ static Handle<JSFunction> Compile(const char* source) { Handle<String> source_code = isolate->factory()->NewStringFromUtf8( CStrVector(source)).ToHandleChecked(); Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( - source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(), - Handle<Context>(isolate->native_context()), NULL, NULL, + source_code, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), + Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, NULL, v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false); return isolate->factory()->NewFunctionFromSharedFunctionInfo( shared_function, isolate->native_context()); @@ -362,7 +362,7 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) { // Now a feedback vector is allocated. CHECK(f->shared()->is_compiled()); int expected_slots = 0; - int expected_ic_slots = FLAG_vector_ics ? 2 : 1; + int expected_ic_slots = 2; CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots()); CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots()); } @@ -370,40 +370,92 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) { // Test that optimized code for different closures is actually shared // immediately by the FastNewClosureStub when run in the same context. -TEST(OptimizedCodeSharing) { - // Skip test if --cache-optimized-code is not activated by default because - // FastNewClosureStub that is baked into the snapshot is incorrect. - if (!FLAG_cache_optimized_code) return; +TEST(OptimizedCodeSharing1) { FLAG_stress_compaction = false; FLAG_allow_natives_syntax = true; + FLAG_cache_optimized_code = true; CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); for (int i = 0; i < 10; i++) { LocalContext env; env->Global()->Set(v8::String::NewFromUtf8(CcTest::isolate(), "x"), v8::Integer::New(CcTest::isolate(), i)); - CompileRun("function MakeClosure() {" - " return function() { return x; };" - "}" - "var closure0 = MakeClosure();" - "%DebugPrint(closure0());" - "%OptimizeFunctionOnNextCall(closure0);" - "%DebugPrint(closure0());" - "var closure1 = MakeClosure();" - "var closure2 = MakeClosure();"); + CompileRun( + "function MakeClosure() {" + " return function() { return x; };" + "}" + "var closure0 = MakeClosure();" + "%DebugPrint(closure0());" + "%OptimizeFunctionOnNextCall(closure0);" + "%DebugPrint(closure0());" + "var closure1 = MakeClosure();" + "var closure2 = MakeClosure();"); Handle<JSFunction> fun1 = v8::Utils::OpenHandle( *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure1")))); Handle<JSFunction> fun2 = v8::Utils::OpenHandle( *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure2")))); - CHECK(fun1->IsOptimized() - || !CcTest::i_isolate()->use_crankshaft() || !fun1->IsOptimizable()); - CHECK(fun2->IsOptimized() - || !CcTest::i_isolate()->use_crankshaft() || !fun2->IsOptimizable()); + CHECK(fun1->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); + CHECK(fun2->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); CHECK_EQ(fun1->code(), fun2->code()); } } +// Test that optimized code for different closures is actually shared +// immediately by the FastNewClosureStub when run different contexts. +TEST(OptimizedCodeSharing2) { + if (FLAG_stress_compaction) return; + FLAG_allow_natives_syntax = true; + FLAG_cache_optimized_code = true; + FLAG_turbo_cache_shared_code = true; + const char* flag = "--turbo-filter=*"; + FlagList::SetFlagsFromString(flag, StrLength(flag)); + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Script> script = v8_compile( + "function MakeClosure() {" + " return function() { return x; };" + "}"); + Handle<Code> reference_code; + { + LocalContext env; + env->Global()->Set(v8::String::NewFromUtf8(CcTest::isolate(), "x"), + v8::Integer::New(CcTest::isolate(), 23)); + script->GetUnboundScript()->BindToCurrentContext()->Run(); + CompileRun( + "var closure0 = MakeClosure();" + "%DebugPrint(closure0());" + "%OptimizeFunctionOnNextCall(closure0);" + "%DebugPrint(closure0());"); + Handle<JSFunction> fun0 = v8::Utils::OpenHandle( + *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure0")))); + CHECK(fun0->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); + reference_code = handle(fun0->code()); + } + for (int i = 0; i < 10; i++) { + LocalContext env; + env->Global()->Set(v8::String::NewFromUtf8(CcTest::isolate(), "x"), + v8::Integer::New(CcTest::isolate(), i)); + script->GetUnboundScript()->BindToCurrentContext()->Run(); + CompileRun( + "var closure0 = MakeClosure();" + "%DebugPrint(closure0());" + "%OptimizeFunctionOnNextCall(closure0);" + "%DebugPrint(closure0());" + "var closure1 = MakeClosure();" + "var closure2 = MakeClosure();"); + Handle<JSFunction> fun1 = v8::Utils::OpenHandle( + *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure1")))); + Handle<JSFunction> fun2 = v8::Utils::OpenHandle( + *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure2")))); + CHECK(fun1->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); + CHECK(fun2->IsOptimized() || !CcTest::i_isolate()->use_crankshaft()); + CHECK_EQ(*reference_code, fun1->code()); + CHECK_EQ(*reference_code, fun2->code()); + } +} + + TEST(CompileFunctionInContext) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); @@ -533,6 +585,9 @@ static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) { int decode_size = Min(f->code()->instruction_size(), static_cast<int>(f->code()->back_edge_table_offset())); + if (FLAG_enable_embedded_constant_pool) { + decode_size = Min(decode_size, f->code()->constant_pool_offset()); + } Address end = pc + decode_size; v8::internal::EmbeddedVector<char, 128> decode_buffer; diff --git a/deps/v8/test/cctest/test-constantpool.cc b/deps/v8/test/cctest/test-constantpool.cc index 4592074742..ce3abb0edb 100644 --- a/deps/v8/test/cctest/test-constantpool.cc +++ b/deps/v8/test/cctest/test-constantpool.cc @@ -1,337 +1,247 @@ -// Copyright 2013 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Test constant pool array code. +// Copyright 2015 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. + +// Test embedded constant pool builder code. #include "src/v8.h" -#include "src/factory.h" -#include "src/objects.h" +#include "src/assembler.h" #include "test/cctest/cctest.h" using namespace v8::internal; -static ConstantPoolArray::Type kTypes[] = { ConstantPoolArray::INT64, - ConstantPoolArray::CODE_PTR, - ConstantPoolArray::HEAP_PTR, - ConstantPoolArray::INT32 }; -static ConstantPoolArray::LayoutSection kSmall = - ConstantPoolArray::SMALL_SECTION; -static ConstantPoolArray::LayoutSection kExtended = - ConstantPoolArray::EXTENDED_SECTION; - -Code* DummyCode(LocalContext* context) { - CompileRun("function foo() {};"); - i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle( - *v8::Local<v8::Function>::Cast( - (*context)->Global()->Get(v8_str("foo")))); - return fun->code(); -} +const ConstantPoolEntry::Type kPtrType = ConstantPoolEntry::INTPTR; +const ConstantPoolEntry::Type kDblType = ConstantPoolEntry::DOUBLE; +const ConstantPoolEntry::Access kRegAccess = ConstantPoolEntry::REGULAR; +const ConstantPoolEntry::Access kOvflAccess = ConstantPoolEntry::OVERFLOWED; +const int kReachBits = 6; // Use reach of 64-bytes to test overflow. +const int kReach = 1 << kReachBits; -TEST(ConstantPoolSmall) { - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - // Check construction. - ConstantPoolArray::NumberOfEntries small(3, 1, 2, 1); - Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); +TEST(ConstantPoolPointers) { + ConstantPoolBuilder builder(kReachBits, kReachBits); + const int kRegularCount = kReach / kPointerSize; + ConstantPoolEntry::Access access; + int pos = 0; + intptr_t value = 0; + bool sharing_ok = true; - int expected_counts[] = { 3, 1, 2, 1 }; - int expected_first_idx[] = { 0, 3, 4, 6 }; - int expected_last_idx[] = { 2, 3, 5, 6 }; - for (int i = 0; i < 4; i++) { - CHECK_EQ(expected_counts[i], array->number_of_entries(kTypes[i], kSmall)); - CHECK_EQ(expected_first_idx[i], array->first_index(kTypes[i], kSmall)); - CHECK_EQ(expected_last_idx[i], array->last_index(kTypes[i], kSmall)); + CHECK(builder.IsEmpty()); + while (builder.NextAccess(kPtrType) == kRegAccess) { + access = builder.AddEntry(pos++, value++, sharing_ok); + CHECK_EQ(access, kRegAccess); } - CHECK(!array->is_extended_layout()); - - // Check getters and setters. - int64_t big_number = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0); - Handle<Object> object = factory->NewHeapNumber(4.0, IMMUTABLE, TENURED); - Code* code = DummyCode(&context); - array->set(0, big_number); - array->set(1, 0.5); - array->set(2, 3e-24); - array->set(3, code->entry()); - array->set(4, code); - array->set(5, *object); - array->set(6, 50); - CHECK_EQ(big_number, array->get_int64_entry(0)); - CHECK_EQ(0.5, array->get_int64_entry_as_double(1)); - CHECK_EQ(3e-24, array->get_int64_entry_as_double(2)); - CHECK_EQ(code->entry(), array->get_code_ptr_entry(3)); - CHECK_EQ(code, array->get_heap_ptr_entry(4)); - CHECK_EQ(*object, array->get_heap_ptr_entry(5)); - CHECK_EQ(50, array->get_int32_entry(6)); + CHECK(!builder.IsEmpty()); + CHECK_EQ(pos, kRegularCount); + + access = builder.AddEntry(pos, value, sharing_ok); + CHECK_EQ(access, kOvflAccess); } -TEST(ConstantPoolExtended) { - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - - // Check construction. - ConstantPoolArray::NumberOfEntries small(1, 2, 3, 4); - ConstantPoolArray::NumberOfEntries extended(5, 6, 7, 8); - Handle<ConstantPoolArray> array = - factory->NewExtendedConstantPoolArray(small, extended); - - // Check small section. - int small_counts[] = { 1, 2, 3, 4 }; - int small_first_idx[] = { 0, 1, 3, 6 }; - int small_last_idx[] = { 0, 2, 5, 9 }; - for (int i = 0; i < 4; i++) { - CHECK_EQ(small_counts[i], array->number_of_entries(kTypes[i], kSmall)); - CHECK_EQ(small_first_idx[i], array->first_index(kTypes[i], kSmall)); - CHECK_EQ(small_last_idx[i], array->last_index(kTypes[i], kSmall)); - } +TEST(ConstantPoolDoubles) { + ConstantPoolBuilder builder(kReachBits, kReachBits); + const int kRegularCount = kReach / kDoubleSize; + ConstantPoolEntry::Access access; + int pos = 0; + double value = 0.0; - // Check extended layout. - CHECK(array->is_extended_layout()); - int extended_counts[] = { 5, 6, 7, 8 }; - int extended_first_idx[] = { 10, 15, 21, 28 }; - int extended_last_idx[] = { 14, 20, 27, 35 }; - for (int i = 0; i < 4; i++) { - CHECK_EQ(extended_counts[i], - array->number_of_entries(kTypes[i], kExtended)); - CHECK_EQ(extended_first_idx[i], array->first_index(kTypes[i], kExtended)); - CHECK_EQ(extended_last_idx[i], array->last_index(kTypes[i], kExtended)); + CHECK(builder.IsEmpty()); + while (builder.NextAccess(kDblType) == kRegAccess) { + access = builder.AddEntry(pos++, value); + value += 0.5; + CHECK_EQ(access, kRegAccess); } + CHECK(!builder.IsEmpty()); + CHECK_EQ(pos, kRegularCount); - // Check small and large section's don't overlap. - int64_t small_section_int64 = V8_2PART_UINT64_C(0x56781234, DEF09ABC); - Code* small_section_code_ptr = DummyCode(&context); - Handle<Object> small_section_heap_ptr = - factory->NewHeapNumber(4.0, IMMUTABLE, TENURED); - int32_t small_section_int32 = 0xab12cd45; - - int64_t extended_section_int64 = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0); - Code* extended_section_code_ptr = DummyCode(&context); - Handle<Object> extended_section_heap_ptr = - factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); - int32_t extended_section_int32 = 0xef67ab89; - - for (int i = array->first_index(ConstantPoolArray::INT64, kSmall); - i <= array->last_index(ConstantPoolArray::INT32, kSmall); i++) { - if (i <= array->last_index(ConstantPoolArray::INT64, kSmall)) { - array->set(i, small_section_int64); - } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kSmall)) { - array->set(i, small_section_code_ptr->entry()); - } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kSmall)) { - array->set(i, *small_section_heap_ptr); - } else { - CHECK(i <= array->last_index(ConstantPoolArray::INT32, kSmall)); - array->set(i, small_section_int32); - } - } - for (int i = array->first_index(ConstantPoolArray::INT64, kExtended); - i <= array->last_index(ConstantPoolArray::INT32, kExtended); i++) { - if (i <= array->last_index(ConstantPoolArray::INT64, kExtended)) { - array->set(i, extended_section_int64); - } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kExtended)) { - array->set(i, extended_section_code_ptr->entry()); - } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kExtended)) { - array->set(i, *extended_section_heap_ptr); - } else { - CHECK(i <= array->last_index(ConstantPoolArray::INT32, kExtended)); - array->set(i, extended_section_int32); - } - } + access = builder.AddEntry(pos, value); + CHECK_EQ(access, kOvflAccess); +} - for (int i = array->first_index(ConstantPoolArray::INT64, kSmall); - i <= array->last_index(ConstantPoolArray::INT32, kSmall); i++) { - if (i <= array->last_index(ConstantPoolArray::INT64, kSmall)) { - CHECK_EQ(small_section_int64, array->get_int64_entry(i)); - } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kSmall)) { - CHECK_EQ(small_section_code_ptr->entry(), array->get_code_ptr_entry(i)); - } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kSmall)) { - CHECK_EQ(*small_section_heap_ptr, array->get_heap_ptr_entry(i)); - } else { - CHECK(i <= array->last_index(ConstantPoolArray::INT32, kSmall)); - CHECK_EQ(small_section_int32, array->get_int32_entry(i)); - } - } - for (int i = array->first_index(ConstantPoolArray::INT64, kExtended); - i <= array->last_index(ConstantPoolArray::INT32, kExtended); i++) { - if (i <= array->last_index(ConstantPoolArray::INT64, kExtended)) { - CHECK_EQ(extended_section_int64, array->get_int64_entry(i)); - } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kExtended)) { - CHECK_EQ(extended_section_code_ptr->entry(), - array->get_code_ptr_entry(i)); - } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kExtended)) { - CHECK_EQ(*extended_section_heap_ptr, array->get_heap_ptr_entry(i)); + +TEST(ConstantPoolMixedTypes) { + ConstantPoolBuilder builder(kReachBits, kReachBits); + const int kRegularCount = (((kReach / (kDoubleSize + kPointerSize)) * 2) + + ((kPointerSize < kDoubleSize) ? 1 : 0)); + ConstantPoolEntry::Type type = kPtrType; + ConstantPoolEntry::Access access; + int pos = 0; + intptr_t ptrValue = 0; + double dblValue = 0.0; + bool sharing_ok = true; + + CHECK(builder.IsEmpty()); + while (builder.NextAccess(type) == kRegAccess) { + if (type == kPtrType) { + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + type = kDblType; } else { - CHECK(i <= array->last_index(ConstantPoolArray::INT32, kExtended)); - CHECK_EQ(extended_section_int32, array->get_int32_entry(i)); + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + type = kPtrType; } + CHECK_EQ(access, kRegAccess); } + CHECK(!builder.IsEmpty()); + CHECK_EQ(pos, kRegularCount); + + access = builder.AddEntry(pos++, ptrValue, sharing_ok); + CHECK_EQ(access, kOvflAccess); + access = builder.AddEntry(pos, dblValue); + CHECK_EQ(access, kOvflAccess); } -static void CheckIterator(Handle<ConstantPoolArray> array, - ConstantPoolArray::Type type, - int expected_indexes[], - int count) { - int i = 0; - ConstantPoolArray::Iterator iter(*array, type); - while (!iter.is_finished()) { - CHECK_EQ(expected_indexes[i++], iter.next_index()); +TEST(ConstantPoolMixedReach) { + const int ptrReachBits = kReachBits + 2; + const int ptrReach = 1 << ptrReachBits; + const int dblReachBits = kReachBits; + const int dblReach = kReach; + const int dblRegularCount = + Min(dblReach / kDoubleSize, ptrReach / (kDoubleSize + kPointerSize)); + const int ptrRegularCount = + ((ptrReach - (dblRegularCount * (kDoubleSize + kPointerSize))) / + kPointerSize) + + dblRegularCount; + ConstantPoolBuilder builder(ptrReachBits, dblReachBits); + ConstantPoolEntry::Access access; + int pos = 0; + intptr_t ptrValue = 0; + double dblValue = 0.0; + bool sharing_ok = true; + int ptrCount = 0; + int dblCount = 0; + + CHECK(builder.IsEmpty()); + while (builder.NextAccess(kDblType) == kRegAccess) { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + dblCount++; + CHECK_EQ(access, kRegAccess); + + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + ptrCount++; + CHECK_EQ(access, kRegAccess); } - CHECK_EQ(count, i); -} + CHECK(!builder.IsEmpty()); + CHECK_EQ(dblCount, dblRegularCount); + while (ptrCount < ptrRegularCount) { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + CHECK_EQ(access, kOvflAccess); -TEST(ConstantPoolIteratorSmall) { - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - - ConstantPoolArray::NumberOfEntries small(1, 5, 2, 0); - Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + ptrCount++; + CHECK_EQ(access, kRegAccess); + } + CHECK_EQ(builder.NextAccess(kPtrType), kOvflAccess); - int expected_int64_indexs[] = { 0 }; - CheckIterator(array, ConstantPoolArray::INT64, expected_int64_indexs, 1); - int expected_code_indexs[] = { 1, 2, 3, 4, 5 }; - CheckIterator(array, ConstantPoolArray::CODE_PTR, expected_code_indexs, 5); - int expected_heap_indexs[] = { 6, 7 }; - CheckIterator(array, ConstantPoolArray::HEAP_PTR, expected_heap_indexs, 2); - int expected_int32_indexs[1]; - CheckIterator(array, ConstantPoolArray::INT32, expected_int32_indexs, 0); + access = builder.AddEntry(pos++, ptrValue, sharing_ok); + CHECK_EQ(access, kOvflAccess); + access = builder.AddEntry(pos, dblValue); + CHECK_EQ(access, kOvflAccess); } -TEST(ConstantPoolIteratorExtended) { - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - - ConstantPoolArray::NumberOfEntries small(1, 0, 0, 4); - ConstantPoolArray::NumberOfEntries extended(5, 0, 3, 0); - Handle<ConstantPoolArray> array = - factory->NewExtendedConstantPoolArray(small, extended); - - int expected_int64_indexs[] = { 0, 5, 6, 7, 8, 9 }; - CheckIterator(array, ConstantPoolArray::INT64, expected_int64_indexs, 6); - int expected_code_indexs[1]; - CheckIterator(array, ConstantPoolArray::CODE_PTR, expected_code_indexs, 0); - int expected_heap_indexs[] = { 10, 11, 12 }; - CheckIterator(array, ConstantPoolArray::HEAP_PTR, expected_heap_indexs, 3); - int expected_int32_indexs[] = { 1, 2, 3, 4 }; - CheckIterator(array, ConstantPoolArray::INT32, expected_int32_indexs, 4); -} +TEST(ConstantPoolSharing) { + ConstantPoolBuilder builder(kReachBits, kReachBits); + const int kRegularCount = (((kReach / (kDoubleSize + kPointerSize)) * 2) + + ((kPointerSize < kDoubleSize) ? 1 : 0)); + ConstantPoolEntry::Access access; + CHECK(builder.IsEmpty()); -TEST(ConstantPoolPreciseGC) { - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - - ConstantPoolArray::NumberOfEntries small(1, 0, 0, 1); - Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); - - // Check that the store buffer knows which entries are pointers and which are - // not. To do this, make non-pointer entries which look like new space - // pointers but are actually invalid and ensure the GC doesn't try to move - // them. - Handle<HeapObject> object = factory->NewHeapNumber(4.0); - Object* raw_ptr = *object; - // If interpreted as a pointer, this should be right inside the heap number - // which will cause a crash when trying to lookup the 'map' pointer. - intptr_t invalid_ptr = reinterpret_cast<intptr_t>(raw_ptr) + kInt32Size; - int32_t invalid_ptr_int32 = static_cast<int32_t>(invalid_ptr); - int64_t invalid_ptr_int64 = static_cast<int64_t>(invalid_ptr); - array->set(0, invalid_ptr_int64); - array->set(1, invalid_ptr_int32); - - // Ensure we perform a scan on scavenge for the constant pool's page. - MemoryChunk::FromAddress(array->address())->set_scan_on_scavenge(true); - heap->CollectGarbage(NEW_SPACE); - - // Check the object was moved by GC. - CHECK_NE(*object, raw_ptr); - - // Check the non-pointer entries weren't changed. - CHECK_EQ(invalid_ptr_int64, array->get_int64_entry(0)); - CHECK_EQ(invalid_ptr_int32, array->get_int32_entry(1)); + ConstantPoolEntry::Type type = kPtrType; + int pos = 0; + intptr_t ptrValue = 0; + double dblValue = 0.0; + bool sharing_ok = true; + while (builder.NextAccess(type) == kRegAccess) { + if (type == kPtrType) { + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + type = kDblType; + } else { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + type = kPtrType; + } + CHECK_EQ(access, kRegAccess); + } + CHECK(!builder.IsEmpty()); + CHECK_EQ(pos, kRegularCount); + + type = kPtrType; + ptrValue = 0; + dblValue = 0.0; + while (pos < kRegularCount * 2) { + if (type == kPtrType) { + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + type = kDblType; + } else { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + type = kPtrType; + } + CHECK_EQ(access, kRegAccess); + } + + access = builder.AddEntry(pos++, ptrValue, sharing_ok); + CHECK_EQ(access, kOvflAccess); + access = builder.AddEntry(pos, dblValue); + CHECK_EQ(access, kOvflAccess); } -TEST(ConstantPoolCompacting) { - if (i::FLAG_never_compact) return; - i::FLAG_always_compact = true; - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(context->GetIsolate()); - - ConstantPoolArray::NumberOfEntries small(0, 0, 1, 0); - ConstantPoolArray::NumberOfEntries extended(0, 0, 1, 0); - Handle<ConstantPoolArray> array = - factory->NewExtendedConstantPoolArray(small, extended); - - // Start a second old-space page so that the heap pointer added to the - // constant pool array ends up on the an evacuation candidate page. - Page* first_page = heap->old_space()->anchor()->next_page(); - { - HandleScope scope(isolate); - int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; - Handle<HeapObject> temp = - factory->NewFixedDoubleArray(dummy_array_size / kDoubleSize, TENURED); - CHECK(heap->InOldSpace(temp->address())); - Handle<HeapObject> heap_ptr = - factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); - CHECK(heap->InOldSpace(heap_ptr->address())); - CHECK(!first_page->Contains(heap_ptr->address())); - array->set(0, *heap_ptr); - array->set(1, *heap_ptr); - } +TEST(ConstantPoolNoSharing) { + ConstantPoolBuilder builder(kReachBits, kReachBits); + const int kRegularCount = (((kReach / (kDoubleSize + kPointerSize)) * 2) + + ((kPointerSize < kDoubleSize) ? 1 : 0)); + ConstantPoolEntry::Access access; - // Check heap pointers are correctly updated on GC. - Object* old_ptr = array->get_heap_ptr_entry(0); - Handle<Object> object(old_ptr, isolate); - CHECK_EQ(old_ptr, *object); - CHECK_EQ(old_ptr, array->get_heap_ptr_entry(1)); + CHECK(builder.IsEmpty()); - // Force compacting garbage collection. - CHECK(FLAG_always_compact); - heap->CollectAllGarbage(); + ConstantPoolEntry::Type type = kPtrType; + int pos = 0; + intptr_t ptrValue = 0; + double dblValue = 0.0; + bool sharing_ok = false; + while (builder.NextAccess(type) == kRegAccess) { + if (type == kPtrType) { + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + type = kDblType; + } else { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + type = kPtrType; + } + CHECK_EQ(access, kRegAccess); + } + CHECK(!builder.IsEmpty()); + CHECK_EQ(pos, kRegularCount); + + type = kPtrType; + ptrValue = 0; + dblValue = 0.0; + sharing_ok = true; + while (pos < kRegularCount * 2) { + if (type == kPtrType) { + access = builder.AddEntry(pos++, ptrValue++, sharing_ok); + type = kDblType; + CHECK_EQ(access, kOvflAccess); + } else { + access = builder.AddEntry(pos++, dblValue); + dblValue += 0.5; + type = kPtrType; + CHECK_EQ(access, kRegAccess); + } + } - CHECK_NE(old_ptr, *object); - CHECK_EQ(*object, array->get_heap_ptr_entry(0)); - CHECK_EQ(*object, array->get_heap_ptr_entry(1)); + access = builder.AddEntry(pos++, ptrValue, sharing_ok); + CHECK_EQ(access, kOvflAccess); + access = builder.AddEntry(pos, dblValue); + CHECK_EQ(access, kOvflAccess); } diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 2f6cf6e9a2..a6ffdca179 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -115,8 +115,9 @@ class DebugLocalContext { v8::Utils::OpenHandle(*context_->Global()))); Handle<v8::internal::String> debug_string = factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug")); - v8::internal::Runtime::DefineObjectProperty(global, debug_string, - handle(debug_context->global_proxy(), isolate), DONT_ENUM).Check(); + v8::internal::JSObject::SetOwnPropertyIgnoreAttributes( + global, debug_string, handle(debug_context->global_proxy()), DONT_ENUM) + .Check(); } private: @@ -211,7 +212,7 @@ static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id, } buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::Handle<v8::String> str = v8::String::NewFromUtf8(isolate, buffer.start()); v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run(); @@ -240,7 +241,7 @@ static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate, } buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::Handle<v8::String> str = v8::String::NewFromUtf8(isolate, buffer.start()); v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run(); @@ -425,7 +426,8 @@ void CheckDebuggerUnloaded(bool check_functions) { } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 // Check that the debugger has been fully unloaded. @@ -443,6 +445,7 @@ void CheckDebugBreakFunction(DebugLocalContext* env, const char* source, const char* name, int position, v8::internal::RelocInfo::Mode mode, Code* debug_break) { + EnableDebugger(); i::Debug* debug = CcTest::i_isolate()->debug(); // Create function and set the break point. @@ -486,6 +489,8 @@ void CheckDebugBreakFunction(DebugLocalContext* env, i::RelocInfo rinfo = location.rinfo(); CHECK(!rinfo.IsPatchedReturnSequence()); } + + DisableDebugger(); } @@ -964,92 +969,6 @@ static void MessageCallbackCount(v8::Handle<v8::Message> message, // --- T h e A c t u a l T e s t s - -// Test that the debug break function is the expected one for different kinds -// of break locations. -TEST(DebugStub) { - using ::v8::internal::Builtins; - using ::v8::internal::Isolate; - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - CheckDebugBreakFunction(&env, - "function f1(){}", "f1", - 0, - v8::internal::RelocInfo::JS_RETURN, - NULL); - CheckDebugBreakFunction(&env, - "function f2(){x=1;}", "f2", - 0, - v8::internal::RelocInfo::CODE_TARGET, - CcTest::i_isolate()->builtins()->builtin( - Builtins::kStoreIC_DebugBreak)); - CheckDebugBreakFunction(&env, - "function f3(){var a=x;}", "f3", - 0, - v8::internal::RelocInfo::CODE_TARGET, - CcTest::i_isolate()->builtins()->builtin( - Builtins::kLoadIC_DebugBreak)); - -// TODO(1240753): Make the test architecture independent or split -// parts of the debugger into architecture dependent files. This -// part currently disabled as it is not portable between IA32/ARM. -// Currently on ICs for keyed store/load on ARM. -#if !defined (__arm__) && !defined(__thumb__) - CheckDebugBreakFunction( - &env, - "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}", - "f4", - 0, - v8::internal::RelocInfo::CODE_TARGET, - CcTest::i_isolate()->builtins()->builtin( - Builtins::kKeyedStoreIC_DebugBreak)); - CheckDebugBreakFunction( - &env, - "function f5(){var index='propertyName'; var a={}; return a[index];}", - "f5", - 0, - v8::internal::RelocInfo::CODE_TARGET, - CcTest::i_isolate()->builtins()->builtin( - Builtins::kKeyedLoadIC_DebugBreak)); -#endif - - CheckDebugBreakFunction( - &env, - "function f6(a){return a==null;}", - "f6", - 0, - v8::internal::RelocInfo::CODE_TARGET, - CcTest::i_isolate()->builtins()->builtin( - Builtins::kCompareNilIC_DebugBreak)); - - // Check the debug break code stubs for call ICs with different number of - // parameters. - // TODO(verwaest): XXX update test. - // Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0); - // Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1); - // Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4); - - // CheckDebugBreakFunction(&env, - // "function f4_0(){x();}", "f4_0", - // 0, - // v8::internal::RelocInfo::CODE_TARGET, - // *debug_break_0); - - // CheckDebugBreakFunction(&env, - // "function f4_1(){x(1);}", "f4_1", - // 0, - // v8::internal::RelocInfo::CODE_TARGET, - // *debug_break_1); - - // CheckDebugBreakFunction(&env, - // "function f4_4(){x(1,2,3,4);}", "f4_4", - // 0, - // v8::internal::RelocInfo::CODE_TARGET, - // *debug_break_4); -} - - // Test that the debug info in the VM is in sync with the functions being // debugged. TEST(DebugInfo) { @@ -1064,6 +983,7 @@ TEST(DebugInfo) { CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length()); CHECK(!HasDebugInfo(foo)); CHECK(!HasDebugInfo(bar)); + EnableDebugger(); // One function (foo) is debugged. int bp1 = SetBreakPoint(foo, 0); CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length()); @@ -1081,6 +1001,7 @@ TEST(DebugInfo) { CHECK(HasDebugInfo(bar)); // No functions are debugged. ClearBreakPoint(bp2); + DisableDebugger(); CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length()); CHECK(!HasDebugInfo(foo)); CHECK(!HasDebugInfo(bar)); @@ -2288,11 +2209,12 @@ TEST(RemoveBreakPointInBreak) { v8::Local<v8::Function> foo = CompileFunction(&env, "function foo(){a=1;}", "foo"); - debug_event_remove_break_point = SetBreakPoint(foo, 0); // Register the debug event listener pasing the function v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo); + debug_event_remove_break_point = SetBreakPoint(foo, 0); + break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); @@ -2348,7 +2270,7 @@ TEST(DebuggerStatementBreakpoint) { v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo"))); - // The debugger statement triggers breakpint hit + // The debugger statement triggers breakpoint hit foo->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); @@ -2779,11 +2701,11 @@ TEST(DebugStepLinear) { // Run foo to allow it to get optimized. CompileRun("a=0; b=0; c=0; foo();"); - SetBreakPoint(foo, 3); - // Register a debug event listener which steps and counts. v8::Debug::SetDebugEventListener(DebugEventStep); + SetBreakPoint(foo, 3); + step_action = StepIn; break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); @@ -3272,6 +3194,13 @@ TEST(DebugStepDoWhile) { v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo"); SetBreakPoint(foo, 8); // "var a = 0;" + // Looping 0 times. + step_action = StepIn; + break_point_hit_count = 0; + v8::Handle<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)}; + foo->Call(env->Global(), argc, argv_0); + CHECK_EQ(4, break_point_hit_count); + // Looping 10 times. step_action = StepIn; break_point_hit_count = 0; @@ -3314,19 +3243,26 @@ TEST(DebugStepFor) { SetBreakPoint(foo, 8); // "a = 1;" + // Looping 0 times. + step_action = StepIn; + break_point_hit_count = 0; + v8::Handle<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)}; + foo->Call(env->Global(), argc, argv_0); + CHECK_EQ(4, break_point_hit_count); + // Looping 10 times. step_action = StepIn; break_point_hit_count = 0; v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) }; foo->Call(env->Global(), argc, argv_10); - CHECK_EQ(45, break_point_hit_count); + CHECK_EQ(34, break_point_hit_count); // Looping 100 times. step_action = StepIn; break_point_hit_count = 0; v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) }; foo->Call(env->Global(), argc, argv_100); - CHECK_EQ(405, break_point_hit_count); + CHECK_EQ(304, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); @@ -3541,14 +3477,14 @@ TEST(DebugConditional) { step_action = StepIn; break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); - CHECK_EQ(5, break_point_hit_count); + CHECK_EQ(4, break_point_hit_count); step_action = StepIn; break_point_hit_count = 0; const int argc = 1; v8::Handle<v8::Value> argv_true[argc] = { v8::True(isolate) }; foo->Call(env->Global(), argc, argv_true); - CHECK_EQ(5, break_point_hit_count); + CHECK_EQ(4, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); @@ -3823,6 +3759,48 @@ TEST(DebugStepFunctionCall) { } +// Test that step in works with Function.call.apply. +TEST(DebugStepFunctionCallApply) { + DebugLocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + // Create a function for testing stepping. + v8::Local<v8::Function> foo = + CompileFunction(&env, + "function bar() { }" + "function foo(){ debugger;" + " Function.call.apply(bar);" + " Function.call.apply(Function.call, " + "[Function.call, bar]);" + "}", + "foo"); + + // Register a debug event listener which steps and counts. + v8::Debug::SetDebugEventListener(DebugEventStep); + step_action = StepIn; + + break_point_hit_count = 0; + foo->Call(env->Global(), 0, NULL); + CHECK_EQ(5, break_point_hit_count); + + v8::Debug::SetDebugEventListener(NULL); + CheckDebuggerUnloaded(); + + // Register a debug event listener which just counts. + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); + + break_point_hit_count = 0; + foo->Call(env->Global(), 0, NULL); + + // Without stepping only the debugger statement is hit. + CHECK_EQ(1, break_point_hit_count); + + v8::Debug::SetDebugEventListener(NULL); + CheckDebuggerUnloaded(); +} + + // Tests that breakpoint will be hit if it's set in script. TEST(PauseInScript) { DebugLocalContext env; @@ -3856,6 +3834,13 @@ TEST(PauseInScript) { } +static void DebugEventCounterCheck(int caught, int uncaught, int message) { + CHECK_EQ(caught, exception_hit_count); + CHECK_EQ(uncaught, uncaught_exception_hit_count); + CHECK_EQ(message, message_callback_count); +} + + // Test break on exceptions. For each exception break combination the number // of debug event exception callbacks and message callbacks are collected. The // number of debug event exception callbacks are used to check that the @@ -3875,6 +3860,15 @@ TEST(BreakOnException) { "caught"); v8::Local<v8::Function> notCaught = CompileFunction(&env, "function notCaught(){throws();}", "notCaught"); + v8::Local<v8::Function> notCaughtFinally = CompileFunction( + &env, "function notCaughtFinally(){try{throws();}finally{}}", + "notCaughtFinally"); + // In this edge case, even though this finally does not propagate the + // exception, the debugger considers this uncaught, since we want to break + // at the first throw for the general case where finally implicitly rethrows. + v8::Local<v8::Function> edgeCaseFinally = CompileFunction( + &env, "function caughtFinally(){L:try{throws();}finally{break L;}}", + "caughtFinally"); v8::V8::AddMessageListener(MessageCallbackCount); v8::Debug::SetDebugEventListener(DebugEventCounter); @@ -3883,117 +3877,117 @@ TEST(BreakOnException) { DebugEventCounterClear(); MessageCallbackCountClear(); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(0, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(0, 0, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); // No break on exception DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnException(false, false); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(0, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(0, 0, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); // Break on uncaught exception DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnException(false, true); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(0, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(1, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(2, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 3, 2); // Break on exception and uncaught exception DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnException(true, true); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(1, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(2, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(2, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(4, 3, 2); // Break on exception DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnException(true, false); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(1, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(2, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(2, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(4, 3, 2); // No break on exception using JavaScript DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(0, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(0, 0, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(0, 0, 2); // Break on uncaught exception using JavaScript DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(0, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(0, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(1, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(2, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 3, 2); // Break on exception and uncaught exception using JavaScript DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(0, message_callback_count); - CHECK_EQ(0, uncaught_exception_hit_count); + DebugEventCounterCheck(1, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(2, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(2, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(4, 3, 2); // Break on exception using JavaScript DebugEventCounterClear(); MessageCallbackCountClear(); ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false); caught->Call(env->Global(), 0, NULL); - CHECK_EQ(1, exception_hit_count); - CHECK_EQ(0, uncaught_exception_hit_count); - CHECK_EQ(0, message_callback_count); + DebugEventCounterCheck(1, 0, 0); notCaught->Call(env->Global(), 0, NULL); - CHECK_EQ(2, exception_hit_count); - CHECK_EQ(1, uncaught_exception_hit_count); - CHECK_EQ(1, message_callback_count); + DebugEventCounterCheck(2, 1, 1); + notCaughtFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(3, 2, 2); + edgeCaseFinally->Call(env->Global(), 0, NULL); + DebugEventCounterCheck(4, 3, 2); v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); @@ -4001,6 +3995,35 @@ TEST(BreakOnException) { } +static void try_finally_original_message(v8::Handle<v8::Message> message, + v8::Handle<v8::Value> data) { + CHECK_EQ(2, message->GetLineNumber()); + CHECK_EQ(2, message->GetStartColumn()); + message_callback_count++; +} + + +TEST(TryFinallyOriginalMessage) { + // Test that the debugger plays nicely with the pending message. + message_callback_count = 0; + DebugEventCounterClear(); + v8::V8::AddMessageListener(try_finally_original_message); + v8::Debug::SetDebugEventListener(DebugEventCounter); + ChangeBreakOnException(true, true); + DebugLocalContext env; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + CompileRun( + "try {\n" + " throw 1;\n" + "} finally {\n" + "}\n"); + DebugEventCounterCheck(1, 1, 1); + v8::Debug::SetDebugEventListener(NULL); + v8::V8::RemoveMessageListeners(try_finally_original_message); +} + + TEST(EvalJSInDebugEventListenerOnNativeReThrownException) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -4023,7 +4046,7 @@ TEST(EvalJSInDebugEventListenerOnNativeReThrownException) { // ReThrow native error { - v8::TryCatch tryCatch; + v8::TryCatch tryCatch(env->GetIsolate()); env->GetIsolate()->ThrowException(v8::Exception::TypeError( v8::String::NewFromUtf8(env->GetIsolate(), "Type error"))); CHECK(tryCatch.HasCaught()); @@ -5532,11 +5555,6 @@ TEST(RecursiveBreakpointsGlobal) { } -static void DummyDebugEventListener( - const v8::Debug::EventDetails& event_details) { -} - - TEST(SetDebugEventListenerOnUninitializedVM) { v8::Debug::SetDebugEventListener(DummyDebugEventListener); } @@ -5602,7 +5620,7 @@ static void CheckDataParameter( CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString()); for (int i = 0; i < 3; i++) { - v8::TryCatch catcher; + v8::TryCatch catcher(args.GetIsolate()); CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty()); CHECK(catcher.HasCaught()); CHECK(catcher.Exception()->IsString()); @@ -5910,7 +5928,7 @@ TEST(DebugGetLoadedScripts) { v8::String::NewExternal(env->GetIsolate(), &source_ext_str); v8::Handle<v8::Script> evil_script(v8::Script::Compile(source)); // "use" evil_script to make the compiler happy. - (void) evil_script; + USE(evil_script); Handle<i::ExternalTwoByteString> i_source( i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source))); // This situation can happen if source was an external string disposed @@ -5919,12 +5937,23 @@ TEST(DebugGetLoadedScripts) { bool allow_natives_syntax = i::FLAG_allow_natives_syntax; i::FLAG_allow_natives_syntax = true; - CompileRun( - "var scripts = %DebugGetLoadedScripts();" - "var count = scripts.length;" - "for (var i = 0; i < count; ++i) {" - " scripts[i].line_ends;" - "}"); + EnableDebugger(); + v8::MaybeLocal<v8::Value> result = + CompileRun(env.context(), + "var scripts = %DebugGetLoadedScripts();" + "var count = scripts.length;" + "for (var i = 0; i < count; ++i) {" + " var lines = scripts[i].lineCount();" + " if (lines < 1) throw 'lineCount';" + " var last = -1;" + " for (var j = 0; j < lines; ++j) {" + " var end = scripts[i].lineEnd(j);" + " if (last >= end) throw 'lineEnd';" + " last = end;" + " }" + "}"); + CHECK(!result.IsEmpty()); + DisableDebugger(); // Must not crash while accessing line_ends. i::FLAG_allow_natives_syntax = allow_natives_syntax; @@ -6492,6 +6521,8 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { const char* script = "function f() {};"; const char* resource_name = "test_resource"; + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); + // Set a couple of provisional breakpoint on lines out of the script lines // range. int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, @@ -6500,7 +6531,6 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5); after_compile_message_count = 0; - v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::ScriptOrigin origin( v8::String::NewFromUtf8(env->GetIsolate(), resource_name), @@ -6925,6 +6955,13 @@ TEST(DebugContextIsPreservedBetweenAccesses) { } +TEST(NoDebugContextWhenDebuggerDisabled) { + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> context = v8::Debug::GetDebugContext(); + CHECK(context.IsEmpty()); +} + + static v8::Handle<v8::Value> expected_callback_data; static void DebugEventContextChecker(const v8::Debug::EventDetails& details) { CHECK(details.GetEventContext() == expected_context); @@ -7260,7 +7297,7 @@ static void DebugEventStepNext( static void RunScriptInANewCFrame(const char* source) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); CompileRun(source); CHECK(try_catch.HasCaught()); } @@ -7440,7 +7477,7 @@ TEST(DebugBreakOffThreadTerminate) { v8::Debug::SetDebugEventListener(DebugBreakTriggerTerminate); TerminationThread terminator(isolate); terminator.Start(); - v8::TryCatch try_catch; + v8::TryCatch try_catch(env->GetIsolate()); v8::Debug::DebugBreak(isolate); CompileRun("while (true);"); CHECK(try_catch.HasTerminated()); @@ -7456,7 +7493,7 @@ static void DebugEventExpectNoException( static void TryCatchWrappedThrowCallback( const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CompileRun("throw 'rejection';"); CHECK(try_catch.HasCaught()); } diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index f3dc777102..347ca9a6bc 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -130,6 +130,10 @@ void DeclarationContext::InitializeIfNeeded() { context_.Reset(isolate, context); context->Enter(); is_initialized_ = true; + // Reset counts. Bootstrapping might have called into the interceptor. + get_count_ = 0; + set_count_ = 0; + query_count_ = 0; PostInitializeContext(context); } @@ -143,7 +147,7 @@ void DeclarationContext::Check(const char* source, // to avoid that. CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE); HandleScope scope(CcTest::isolate()); - TryCatch catcher; + TryCatch catcher(CcTest::isolate()); catcher.SetVerbose(true); Local<Script> script = Script::Compile(String::NewFromUtf8(CcTest::isolate(), source)); @@ -567,7 +571,7 @@ class SimpleContext { Expectations expectations, v8::Handle<Value> value = Local<Value>()) { HandleScope scope(context_->GetIsolate()); - TryCatch catcher; + TryCatch catcher(context_->GetIsolate()); catcher.SetVerbose(true); Local<Script> script = Script::Compile(String::NewFromUtf8(context_->GetIsolate(), source)); diff --git a/deps/v8/test/cctest/test-deoptimization.cc b/deps/v8/test/cctest/test-deoptimization.cc index 674291524d..1d512e0a75 100644 --- a/deps/v8/test/cctest/test-deoptimization.cc +++ b/deps/v8/test/cctest/test-deoptimization.cc @@ -112,8 +112,6 @@ static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj, TEST(DeoptimizeSimple) { - i::FLAG_turbo_deoptimization = true; - LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -152,8 +150,6 @@ TEST(DeoptimizeSimple) { TEST(DeoptimizeSimpleWithArguments) { - i::FLAG_turbo_deoptimization = true; - LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -193,8 +189,6 @@ TEST(DeoptimizeSimpleWithArguments) { TEST(DeoptimizeSimpleNested) { - i::FLAG_turbo_deoptimization = true; - LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -220,7 +214,6 @@ TEST(DeoptimizeSimpleNested) { TEST(DeoptimizeRecursive) { - i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -248,7 +241,6 @@ TEST(DeoptimizeRecursive) { TEST(DeoptimizeMultiple) { - i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -277,7 +269,6 @@ TEST(DeoptimizeMultiple) { TEST(DeoptimizeConstructor) { - i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -316,7 +307,6 @@ TEST(DeoptimizeConstructor) { TEST(DeoptimizeConstructorMultiple) { - i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -346,7 +336,6 @@ TEST(DeoptimizeConstructorMultiple) { UNINITIALIZED_TEST(DeoptimizeBinaryOperationADDString) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; AllowNativesSyntaxNoInlining options; v8::Isolate::CreateParams create_params; @@ -451,7 +440,6 @@ static void TestDeoptimizeBinaryOpHelper(LocalContext* env, UNINITIALIZED_TEST(DeoptimizeBinaryOperationADD) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -474,7 +462,6 @@ UNINITIALIZED_TEST(DeoptimizeBinaryOperationADD) { UNINITIALIZED_TEST(DeoptimizeBinaryOperationSUB) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -497,7 +484,6 @@ UNINITIALIZED_TEST(DeoptimizeBinaryOperationSUB) { UNINITIALIZED_TEST(DeoptimizeBinaryOperationMUL) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -520,7 +506,6 @@ UNINITIALIZED_TEST(DeoptimizeBinaryOperationMUL) { UNINITIALIZED_TEST(DeoptimizeBinaryOperationDIV) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -543,7 +528,6 @@ UNINITIALIZED_TEST(DeoptimizeBinaryOperationDIV) { UNINITIALIZED_TEST(DeoptimizeBinaryOperationMOD) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -566,7 +550,6 @@ UNINITIALIZED_TEST(DeoptimizeBinaryOperationMOD) { UNINITIALIZED_TEST(DeoptimizeCompare) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -623,7 +606,6 @@ UNINITIALIZED_TEST(DeoptimizeCompare) { UNINITIALIZED_TEST(DeoptimizeLoadICStoreIC) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); @@ -716,7 +698,6 @@ UNINITIALIZED_TEST(DeoptimizeLoadICStoreIC) { UNINITIALIZED_TEST(DeoptimizeLoadICStoreICNested) { - i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); diff --git a/deps/v8/test/cctest/test-disasm-arm64.cc b/deps/v8/test/cctest/test-disasm-arm64.cc index 208f1f5afb..b3b50acf9d 100644 --- a/deps/v8/test/cctest/test-disasm-arm64.cc +++ b/deps/v8/test/cctest/test-disasm-arm64.cc @@ -83,10 +83,11 @@ using namespace v8::internal; abort(); \ } -#define CLEANUP() \ - delete disasm; \ - delete decoder; \ - delete assm +#define CLEANUP() \ + delete disasm; \ + delete decoder; \ + delete assm; \ + free(buf) static bool vm_initialized = false; diff --git a/deps/v8/test/cctest/test-disasm-mips.cc b/deps/v8/test/cctest/test-disasm-mips.cc index b66554e55e..c04cd23bf5 100644 --- a/deps/v8/test/cctest/test-disasm-mips.cc +++ b/deps/v8/test/cctest/test-disasm-mips.cc @@ -92,6 +92,45 @@ if (failure) { \ } +#define COMPARE_PC_REL_COMPACT(asm_, compare_string, offset) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, progcounter + 4 + (offset << 2)); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + +#define COMPARE_PC_REL(asm_, compare_string, offset) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, progcounter + (offset << 2)); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + +#define COMPARE_PC_JUMP(asm_, compare_string, target) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + int instr_index = target >> 2; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, reinterpret_cast<byte *>( \ + ((uint32_t)(progcounter + 1) & ~0xfffffff) | \ + (instr_index << 2))); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + TEST(Type0) { SET_UP(); @@ -199,39 +238,241 @@ TEST(Type0) { COMPARE(modu(v0, v1, a0), "006410db modu v0, v1, a0"); - COMPARE(bovc(a0, a0, static_cast<int16_t>(0)), - "20840000 bovc a0, a0, 0"); - COMPARE(bovc(a1, a0, static_cast<int16_t>(0)), - "20a40000 bovc a1, a0, 0"); - COMPARE(bovc(a1, a0, 32767), - "20a47fff bovc a1, a0, 32767"); - COMPARE(bovc(a1, a0, -32768), - "20a48000 bovc a1, a0, -32768"); - - COMPARE(bnvc(a0, a0, static_cast<int16_t>(0)), - "60840000 bnvc a0, a0, 0"); - COMPARE(bnvc(a1, a0, static_cast<int16_t>(0)), - "60a40000 bnvc a1, a0, 0"); - COMPARE(bnvc(a1, a0, 32767), - "60a47fff bnvc a1, a0, 32767"); - COMPARE(bnvc(a1, a0, -32768), - "60a48000 bnvc a1, a0, -32768"); - - COMPARE(beqzc(a0, 0), - "d8800000 beqzc a0, 0x0"); - COMPARE(beqzc(a0, 0xfffff), // 0x0fffff == 1048575. - "d88fffff beqzc a0, 0xfffff"); - COMPARE(beqzc(a0, 0x100000), // 0x100000 == -1048576. - "d8900000 beqzc a0, 0x100000"); - - COMPARE(bnezc(a0, 0), - "f8800000 bnezc a0, 0x0"); - COMPARE(bnezc(a0, 0xfffff), // 0x0fffff == 1048575. - "f88fffff bnezc a0, 0xfffff"); - COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576. - "f8900000 bnezc a0, 0x100000"); + COMPARE_PC_REL_COMPACT(bovc(a0, a0, static_cast<int16_t>(0)), + "20840000 bovc a0, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, static_cast<int16_t>(0)), + "20a40000 bovc a1, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, 32767), + "20a47fff bovc a1, a0, 32767", 32767); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, -32768), + "20a48000 bovc a1, a0, -32768", -32768); + + COMPARE_PC_REL_COMPACT(bnvc(a0, a0, static_cast<int16_t>(0)), + "60840000 bnvc a0, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, static_cast<int16_t>(0)), + "60a40000 bnvc a1, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, 32767), + "60a47fff bnvc a1, a0, 32767", 32767); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, -32768), + "60a48000 bnvc a1, a0, -32768", -32768); + + COMPARE_PC_REL_COMPACT(beqzc(a0, -1048576), + "d8900000 beqzc a0, -1048576", -1048576); + COMPARE_PC_REL_COMPACT(beqzc(a0, -1), "d89fffff beqzc a0, -1", -1); + COMPARE_PC_REL_COMPACT(beqzc(a0, 0), "d8800000 beqzc a0, 0", 0); + COMPARE_PC_REL_COMPACT(beqzc(a0, 1), "d8800001 beqzc a0, 1", 1); + COMPARE_PC_REL_COMPACT(beqzc(a0, 1048575), + "d88fffff beqzc a0, 1048575", 1048575); + + COMPARE_PC_REL_COMPACT(bnezc(a0, 0), "f8800000 bnezc a0, 0x0", 0); + COMPARE_PC_REL_COMPACT(bnezc(a0, 0xfffff), // 0x0fffff == 1048575. + "f88fffff bnezc a0, 0xfffff", 1048575); + COMPARE_PC_REL_COMPACT(bnezc(a0, 0x100000), // 0x100000 == -1048576. + "f8900000 bnezc a0, 0x100000", -1048576); + + COMPARE_PC_REL_COMPACT(bc(-33554432), "ca000000 bc -33554432", + -33554432); + COMPARE_PC_REL_COMPACT(bc(-1), "cbffffff bc -1", -1); + COMPARE_PC_REL_COMPACT(bc(0), "c8000000 bc 0", 0); + COMPARE_PC_REL_COMPACT(bc(1), "c8000001 bc 1", 1); + COMPARE_PC_REL_COMPACT(bc(33554431), "c9ffffff bc 33554431", + 33554431); + + COMPARE_PC_REL_COMPACT(balc(-33554432), "ea000000 balc -33554432", + -33554432); + COMPARE_PC_REL_COMPACT(balc(-1), "ebffffff balc -1", -1); + COMPARE_PC_REL_COMPACT(balc(0), "e8000000 balc 0", 0); + COMPARE_PC_REL_COMPACT(balc(1), "e8000001 balc 1", 1); + COMPARE_PC_REL_COMPACT(balc(33554431), "e9ffffff balc 33554431", + 33554431); + + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, -32768), + "18858000 bgeuc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, -1), + "1885ffff bgeuc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 1), + "18850001 bgeuc a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 32767), + "18857fff bgeuc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgezalc(a0, -32768), + "18848000 bgezalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgezalc(a0, -1), "1884ffff bgezalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bgezalc(a0, 1), "18840001 bgezalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgezalc(a0, 32767), + "18847fff bgezalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(blezalc(a0, -32768), + "18048000 blezalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(blezalc(a0, -1), "1804ffff blezalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(blezalc(a0, 1), "18040001 blezalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(blezalc(a0, 32767), + "18047fff blezalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, -32768), + "1c858000 bltuc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, -1), + "1c85ffff bltuc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, 1), "1c850001 bltuc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, 32767), + "1c857fff bltuc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltzalc(a0, -32768), + "1c848000 bltzalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltzalc(a0, -1), "1c84ffff bltzalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bltzalc(a0, 1), "1c840001 bltzalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltzalc(a0, 32767), + "1c847fff bltzalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgtzalc(a0, -32768), + "1c048000 bgtzalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, -1), "1c04ffff bgtzalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, 1), "1c040001 bgtzalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, 32767), + "1c047fff bgtzalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgezc(a0, -32768), + "58848000 bgezc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgezc(a0, -1), "5884ffff bgezc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgezc(a0, 1), "58840001 bgezc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgezc(a0, 32767), + "58847fff bgezc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgec(a0, a1, -32768), + "58858000 bgec a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, -1), + "5885ffff bgec a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, 1), "58850001 bgec a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, 32767), + "58857fff bgec a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(blezc(a0, -32768), + "58048000 blezc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(blezc(a0, -1), "5804ffff blezc a0, -1", -1); + COMPARE_PC_REL_COMPACT(blezc(a0, 1), "58040001 blezc a0, 1", 1); + COMPARE_PC_REL_COMPACT(blezc(a0, 32767), + "58047fff blezc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltzc(a0, -32768), + "5c848000 bltzc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltzc(a0, -1), "5c84ffff bltzc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bltzc(a0, 1), "5c840001 bltzc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltzc(a0, 32767), + "5c847fff bltzc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltc(a0, a1, -32768), + "5c858000 bltc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, -1), + "5c85ffff bltc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, 1), "5c850001 bltc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, 32767), + "5c857fff bltc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgtzc(a0, -32768), + "5c048000 bgtzc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgtzc(a0, -1), "5c04ffff bgtzc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgtzc(a0, 1), "5c040001 bgtzc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtzc(a0, 32767), + "5c047fff bgtzc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bc1eqz(-32768, f1), + "45218000 bc1eqz f1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bc1eqz(-1, f1), "4521ffff bc1eqz f1, -1", + -1); + COMPARE_PC_REL_COMPACT(bc1eqz(1, f1), "45210001 bc1eqz f1, 1", 1); + COMPARE_PC_REL_COMPACT(bc1eqz(32767, f1), + "45217fff bc1eqz f1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bc1nez(-32768, f1), + "45a18000 bc1nez f1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bc1nez(-1, f1), "45a1ffff bc1nez f1, -1", + -1); + COMPARE_PC_REL_COMPACT(bc1nez(1, f1), "45a10001 bc1nez f1, 1", 1); + COMPARE_PC_REL_COMPACT(bc1nez(32767, f1), + "45a17fff bc1nez f1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bovc(a1, a0, -1), "20a4ffff bovc a1, a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bovc(a0, a0, 1), "20840001 bovc a0, a0, 1", + 1); + + COMPARE_PC_REL_COMPACT(beqc(a0, a1, -32768), + "20858000 beqc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, -1), "2085ffff beqc a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, 1), "20850001 beqc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, 32767), + "20857fff beqc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bnec(a0, a1, -32768), + "60858000 bnec a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, -1), "6085ffff bnec a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, 1), "60850001 bnec a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, 32767), + "60857fff bnec a0, a1, 32767", 32767); } + COMPARE_PC_REL_COMPACT(bne(a0, a1, -32768), + "14858000 bne a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bne(a0, a1, -1), "1485ffff bne a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(bne(a0, a1, 1), "14850001 bne a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(bne(a0, a1, 32767), + "14857fff bne a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(beq(a0, a1, -32768), + "10858000 beq a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(beq(a0, a1, -1), "1085ffff beq a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(beq(a0, a1, 1), "10850001 beq a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(beq(a0, a1, 32767), + "10857fff beq a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltz(a0, -32768), "04808000 bltz a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bltz(a0, -1), "0480ffff bltz a0, -1", -1); + COMPARE_PC_REL_COMPACT(bltz(a0, 1), "04800001 bltz a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltz(a0, 32767), "04807fff bltz a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(bgez(a0, -32768), "04818000 bgez a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bgez(a0, -1), "0481ffff bgez a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgez(a0, 1), "04810001 bgez a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgez(a0, 32767), "04817fff bgez a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(blez(a0, -32768), "18808000 blez a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(blez(a0, -1), "1880ffff blez a0, -1", -1); + COMPARE_PC_REL_COMPACT(blez(a0, 1), "18800001 blez a0, 1", 1); + COMPARE_PC_REL_COMPACT(blez(a0, 32767), "18807fff blez a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(bgtz(a0, -32768), "1c808000 bgtz a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bgtz(a0, -1), "1c80ffff bgtz a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgtz(a0, 1), "1c800001 bgtz a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtz(a0, 32767), "1c807fff bgtz a0, 32767", + 32767); + + COMPARE_PC_JUMP(j(0x4), "08000001 j 0x4", 0x4); + COMPARE_PC_JUMP(j(0xffffffc), "0bffffff j 0xffffffc", 0xffffffc); + + COMPARE_PC_JUMP(jal(0x4), "0c000001 jal 0x4", 0x4); + COMPARE_PC_JUMP(jal(0xffffffc), "0fffffff jal 0xffffffc", + 0xffffffc); + COMPARE(addiu(a0, a1, 0x0), "24a40000 addiu a0, a1, 0"); COMPARE(addiu(s0, s1, 32767), @@ -506,7 +747,7 @@ TEST(Type0) { } } - if (IsMipsArchVariant(kMips32r2)) { + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { COMPARE(ins_(a0, a1, 31, 1), "7ca4ffc4 ins a0, a1, 31, 1"); COMPARE(ins_(s6, s7, 30, 2), @@ -520,26 +761,280 @@ TEST(Type0) { COMPARE(ext_(v0, v1, 0, 32), "7c62f800 ext v0, v1, 0, 32"); } + COMPARE(add_s(f4, f6, f8), "46083100 add.s f4, f6, f8"); + COMPARE(add_d(f12, f14, f16), "46307300 add.d f12, f14, f16"); + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(bitswap(a0, a1), "7c052020 bitswap a0, a1"); + COMPARE(bitswap(t8, s0), "7c10c020 bitswap t8, s0"); + } + + COMPARE(abs_s(f6, f8), "46004185 abs.s f6, f8"); + COMPARE(abs_d(f10, f12), "46206285 abs.d f10, f12"); + + COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6"); + COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6"); + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0"); + COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1"); + COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2"); + COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0"); + COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1"); + COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767"); + COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768"); + COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0"); + COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1"); + COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767"); + COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768"); + COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(lwpc(t1, 0), "ed280000 lwpc t1, 0"); + COMPARE(lwpc(t1, 4), "ed280004 lwpc t1, 4"); + COMPARE(lwpc(t1, -4), "ed2ffffc lwpc t1, -4"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(jic(t0, -32768), "d8088000 jic t0, -32768"); + COMPARE(jic(t0, -1), "d808ffff jic t0, -1"); + COMPARE(jic(t0, 0), "d8080000 jic t0, 0"); + COMPARE(jic(t0, 4), "d8080004 jic t0, 4"); + COMPARE(jic(t0, 32767), "d8087fff jic t0, 32767"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143"); + COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1"); + COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0"); + COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1"); + COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144"); + } + + if (IsMipsArchVariant(kMips32r6)) { + COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000"); + COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff"); + COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0"); + COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1"); + COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff"); + } VERIFY_RUN(); } -// Tests only seleqz, selnez, seleqz.fmt and selnez.fmt TEST(Type1) { + SET_UP(); if (IsMipsArchVariant(kMips32r6)) { - SET_UP(); COMPARE(seleqz(a0, a1, a2), "00a62035 seleqz a0, a1, a2"); COMPARE(selnez(a0, a1, a2), "00a62037 selnez a0, a1, a2"); - COMPARE(seleqz(D, f3, f4, f5), "462520d4 seleqz.d f3, f4, f5"); - COMPARE(selnez(D, f3, f4, f5), "462520d7 selnez.d f3, f4, f5"); + COMPARE(seleqz_d(f3, f4, f5), "462520d4 seleqz.d f3, f4, f5"); + COMPARE(selnez_d(f3, f4, f5), "462520d7 selnez.d f3, f4, f5"); + COMPARE(seleqz_s(f3, f4, f5), "460520d4 seleqz.s f3, f4, f5"); + COMPARE(selnez_s(f3, f4, f5), "460520d7 selnez.s f3, f4, f5"); COMPARE(min_d(f3, f4, f5), "462520dc min.d f3, f4, f5"); COMPARE(max_d(f3, f4, f5), "462520de max.d f3, f4, f5"); + + COMPARE(sel_s(f3, f4, f5), "460520d0 sel.s f3, f4, f5"); + COMPARE(sel_d(f3, f4, f5), "462520d0 sel.d f3, f4, f5"); + COMPARE(rint_d(f8, f6), "4620321a rint.d f8, f6"); + COMPARE(rint_s(f8, f6), "4600321a rint.s f8, f6"); + + COMPARE(min_s(f3, f4, f5), "460520dc min.s f3, f4, f5"); + COMPARE(max_s(f3, f4, f5), "460520de max.s f3, f4, f5"); + + COMPARE(mina_d(f3, f4, f5), "462520dd mina.d f3, f4, f5"); + COMPARE(mina_s(f3, f4, f5), "460520dd mina.s f3, f4, f5"); + + COMPARE(maxa_d(f3, f4, f5), "462520df maxa.d f3, f4, f5"); + COMPARE(maxa_s(f3, f4, f5), "460520df maxa.s f3, f4, f5"); + } + + COMPARE(trunc_w_d(f8, f6), "4620320d trunc.w.d f8, f6"); + COMPARE(trunc_w_s(f8, f6), "4600320d trunc.w.s f8, f6"); + + COMPARE(round_w_s(f8, f6), "4600320c round.w.s f8, f6"); + COMPARE(round_w_d(f8, f6), "4620320c round.w.d f8, f6"); + + COMPARE(round_l_s(f8, f6), "46003208 round.l.s f8, f6"); + COMPARE(round_l_d(f8, f6), "46203208 round.l.d f8, f6"); + + COMPARE(floor_w_s(f8, f6), "4600320f floor.w.s f8, f6"); + COMPARE(floor_w_d(f8, f6), "4620320f floor.w.d f8, f6"); + + COMPARE(floor_l_s(f8, f6), "4600320b floor.l.s f8, f6"); + COMPARE(floor_l_d(f8, f6), "4620320b floor.l.d f8, f6"); + + COMPARE(ceil_w_s(f8, f6), "4600320e ceil.w.s f8, f6"); + COMPARE(ceil_w_d(f8, f6), "4620320e ceil.w.d f8, f6"); + + COMPARE(ceil_l_s(f8, f6), "4600320a ceil.l.s f8, f6"); + COMPARE(ceil_l_d(f8, f6), "4620320a ceil.l.d f8, f6"); + + COMPARE(sub_s(f10, f8, f6), "46064281 sub.s f10, f8, f6"); + COMPARE(sub_d(f10, f8, f6), "46264281 sub.d f10, f8, f6"); + + COMPARE(sqrt_s(f8, f6), "46003204 sqrt.s f8, f6"); + COMPARE(sqrt_d(f8, f6), "46203204 sqrt.d f8, f6"); + + COMPARE(neg_s(f8, f6), "46003207 neg.s f8, f6"); + COMPARE(neg_d(f8, f6), "46203207 neg.d f8, f6"); + + COMPARE(mul_s(f8, f6, f4), "46043202 mul.s f8, f6, f4"); + COMPARE(mul_d(f8, f6, f4), "46243202 mul.d f8, f6, f4"); + + if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) { + COMPARE(rsqrt_s(f8, f6), "46003216 rsqrt.s f8, f6"); + COMPARE(rsqrt_d(f8, f6), "46203216 rsqrt.d f8, f6"); + + COMPARE(recip_s(f8, f6), "46003215 recip.s f8, f6"); + COMPARE(recip_d(f8, f6), "46203215 recip.d f8, f6"); + } + + COMPARE(mov_s(f6, f4), "46002186 mov.s f6, f4"); + COMPARE(mov_d(f6, f4), "46202186 mov.d f6, f4"); + + if (IsMipsArchVariant(kMips32r2)) { + COMPARE(trunc_l_d(f8, f6), "46203209 trunc.l.d f8, f6"); + COMPARE(trunc_l_s(f8, f6), "46003209 trunc.l.s f8, f6"); + + COMPARE(movz_s(f6, f4, t0), "46082192 movz.s f6, f4, t0"); + COMPARE(movz_d(f6, f4, t0), "46282192 movz.d f6, f4, t0"); + + COMPARE(movt_s(f6, f4, 4), "46112191 movt.s f6, f4, cc(1)"); + COMPARE(movt_d(f6, f4, 4), "46312191 movt.d f6, f4, cc(1)"); + + COMPARE(movf_s(f6, f4, 4), "46102191 movf.s f6, f4, cc(1)"); + COMPARE(movf_d(f6, f4, 4), "46302191 movf.d f6, f4, cc(1)"); + + COMPARE(movn_s(f6, f4, t0), "46082193 movn.s f6, f4, t0"); + COMPARE(movn_d(f6, f4, t0), "46282193 movn.d f6, f4, t0"); + } + VERIFY_RUN(); +} + + +TEST(Type2) { + if (IsMipsArchVariant(kMips32r6)) { + SET_UP(); + + COMPARE(class_s(f3, f4), "460020db class.s f3, f4"); + COMPARE(class_d(f2, f3), "4620189b class.d f2, f3"); + + VERIFY_RUN(); + } +} + + +TEST(C_FMT_DISASM) { + if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2)) { + SET_UP(); + + COMPARE(c_s(F, f8, f10, 0), "460a4030 c.f.s f8, f10, cc(0)"); + COMPARE(c_d(F, f8, f10, 0), "462a4030 c.f.d f8, f10, cc(0)"); + + COMPARE(c_s(UN, f8, f10, 2), "460a4231 c.un.s f8, f10, cc(2)"); + COMPARE(c_d(UN, f8, f10, 2), "462a4231 c.un.d f8, f10, cc(2)"); + + COMPARE(c_s(EQ, f8, f10, 4), "460a4432 c.eq.s f8, f10, cc(4)"); + COMPARE(c_d(EQ, f8, f10, 4), "462a4432 c.eq.d f8, f10, cc(4)"); + + COMPARE(c_s(UEQ, f8, f10, 6), "460a4633 c.ueq.s f8, f10, cc(6)"); + COMPARE(c_d(UEQ, f8, f10, 6), "462a4633 c.ueq.d f8, f10, cc(6)"); + + COMPARE(c_s(OLT, f8, f10, 0), "460a4034 c.olt.s f8, f10, cc(0)"); + COMPARE(c_d(OLT, f8, f10, 0), "462a4034 c.olt.d f8, f10, cc(0)"); + + COMPARE(c_s(ULT, f8, f10, 2), "460a4235 c.ult.s f8, f10, cc(2)"); + COMPARE(c_d(ULT, f8, f10, 2), "462a4235 c.ult.d f8, f10, cc(2)"); + + COMPARE(c_s(OLE, f8, f10, 4), "460a4436 c.ole.s f8, f10, cc(4)"); + COMPARE(c_d(OLE, f8, f10, 4), "462a4436 c.ole.d f8, f10, cc(4)"); + + COMPARE(c_s(ULE, f8, f10, 6), "460a4637 c.ule.s f8, f10, cc(6)"); + COMPARE(c_d(ULE, f8, f10, 6), "462a4637 c.ule.d f8, f10, cc(6)"); VERIFY_RUN(); } } + + +TEST(COND_FMT_DISASM) { + if (IsMipsArchVariant(kMips32r6)) { + SET_UP(); + + COMPARE(cmp_s(F, f6, f8, f10), "468a4180 cmp.af.s f6, f8, f10"); + COMPARE(cmp_d(F, f6, f8, f10), "46aa4180 cmp.af.d f6, f8, f10"); + + COMPARE(cmp_s(UN, f6, f8, f10), "468a4181 cmp.un.s f6, f8, f10"); + COMPARE(cmp_d(UN, f6, f8, f10), "46aa4181 cmp.un.d f6, f8, f10"); + + COMPARE(cmp_s(EQ, f6, f8, f10), "468a4182 cmp.eq.s f6, f8, f10"); + COMPARE(cmp_d(EQ, f6, f8, f10), "46aa4182 cmp.eq.d f6, f8, f10"); + + COMPARE(cmp_s(UEQ, f6, f8, f10), "468a4183 cmp.ueq.s f6, f8, f10"); + COMPARE(cmp_d(UEQ, f6, f8, f10), "46aa4183 cmp.ueq.d f6, f8, f10"); + + COMPARE(cmp_s(LT, f6, f8, f10), "468a4184 cmp.lt.s f6, f8, f10"); + COMPARE(cmp_d(LT, f6, f8, f10), "46aa4184 cmp.lt.d f6, f8, f10"); + + COMPARE(cmp_s(ULT, f6, f8, f10), "468a4185 cmp.ult.s f6, f8, f10"); + COMPARE(cmp_d(ULT, f6, f8, f10), "46aa4185 cmp.ult.d f6, f8, f10"); + + COMPARE(cmp_s(LE, f6, f8, f10), "468a4186 cmp.le.s f6, f8, f10"); + COMPARE(cmp_d(LE, f6, f8, f10), "46aa4186 cmp.le.d f6, f8, f10"); + + COMPARE(cmp_s(ULE, f6, f8, f10), "468a4187 cmp.ule.s f6, f8, f10"); + COMPARE(cmp_d(ULE, f6, f8, f10), "46aa4187 cmp.ule.d f6, f8, f10"); + + COMPARE(cmp_s(ORD, f6, f8, f10), "468a4191 cmp.or.s f6, f8, f10"); + COMPARE(cmp_d(ORD, f6, f8, f10), "46aa4191 cmp.or.d f6, f8, f10"); + + COMPARE(cmp_s(UNE, f6, f8, f10), "468a4192 cmp.une.s f6, f8, f10"); + COMPARE(cmp_d(UNE, f6, f8, f10), "46aa4192 cmp.une.d f6, f8, f10"); + + COMPARE(cmp_s(NE, f6, f8, f10), "468a4193 cmp.ne.s f6, f8, f10"); + COMPARE(cmp_d(NE, f6, f8, f10), "46aa4193 cmp.ne.d f6, f8, f10"); + + VERIFY_RUN(); + } +} + + +TEST(CVT_DISSASM) { + SET_UP(); + COMPARE(cvt_d_s(f22, f24), "4600c5a1 cvt.d.s f22, f24"); + COMPARE(cvt_d_w(f22, f24), "4680c5a1 cvt.d.w f22, f24"); + if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) { + COMPARE(cvt_d_l(f22, f24), "46a0c5a1 cvt.d.l f22, f24"); + } + + if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) { + COMPARE(cvt_l_s(f22, f24), "4600c5a5 cvt.l.s f22, f24"); + COMPARE(cvt_l_d(f22, f24), "4620c5a5 cvt.l.d f22, f24"); + } + + COMPARE(cvt_s_d(f22, f24), "4620c5a0 cvt.s.d f22, f24"); + COMPARE(cvt_s_w(f22, f24), "4680c5a0 cvt.s.w f22, f24"); + if (IsMipsArchVariant(kMips32r6) || IsMipsArchVariant(kMips32r2)) { + COMPARE(cvt_s_l(f22, f24), "46a0c5a0 cvt.s.l f22, f24"); + } + + COMPARE(cvt_s_d(f22, f24), "4620c5a0 cvt.s.d f22, f24"); + COMPARE(cvt_s_w(f22, f24), "4680c5a0 cvt.s.w f22, f24"); + + VERIFY_RUN(); +} diff --git a/deps/v8/test/cctest/test-disasm-mips64.cc b/deps/v8/test/cctest/test-disasm-mips64.cc index 492265b2e7..225a1e7f0b 100644 --- a/deps/v8/test/cctest/test-disasm-mips64.cc +++ b/deps/v8/test/cctest/test-disasm-mips64.cc @@ -92,6 +92,45 @@ if (failure) { \ } +#define COMPARE_PC_REL_COMPACT(asm_, compare_string, offset) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, progcounter + 4 + (offset << 2)); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + +#define COMPARE_PC_REL(asm_, compare_string, offset) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, progcounter + (offset << 2)); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + +#define COMPARE_PC_JUMP(asm_, compare_string, target) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + char str_with_address[100]; \ + int instr_index = target >> 2; \ + snprintf(str_with_address, sizeof(str_with_address), "%s -> %p", \ + compare_string, reinterpret_cast<byte *>( \ + ((uint64_t)(progcounter + 1) & ~0xfffffff) | \ + (instr_index << 2))); \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, str_with_address)) failure = true; \ + } + + TEST(Type0) { SET_UP(); @@ -279,38 +318,6 @@ TEST(Type0) { "0064109f ddivu v0, v1, a0"); COMPARE(dmodu(v0, v1, a0), "006410df dmodu v0, v1, a0"); - - COMPARE(bovc(a0, a0, static_cast<int16_t>(0)), - "20840000 bovc a0, a0, 0"); - COMPARE(bovc(a1, a0, static_cast<int16_t>(0)), - "20a40000 bovc a1, a0, 0"); - COMPARE(bovc(a1, a0, 32767), - "20a47fff bovc a1, a0, 32767"); - COMPARE(bovc(a1, a0, -32768), - "20a48000 bovc a1, a0, -32768"); - - COMPARE(bnvc(a0, a0, static_cast<int16_t>(0)), - "60840000 bnvc a0, a0, 0"); - COMPARE(bnvc(a1, a0, static_cast<int16_t>(0)), - "60a40000 bnvc a1, a0, 0"); - COMPARE(bnvc(a1, a0, 32767), - "60a47fff bnvc a1, a0, 32767"); - COMPARE(bnvc(a1, a0, -32768), - "60a48000 bnvc a1, a0, -32768"); - - COMPARE(beqzc(a0, 0), - "d8800000 beqzc a0, 0x0"); - COMPARE(beqzc(a0, 0xfffff), // 0x0fffff == 1048575. - "d88fffff beqzc a0, 0xfffff"); - COMPARE(beqzc(a0, 0x100000), // 0x100000 == -1048576. - "d8900000 beqzc a0, 0x100000"); - - COMPARE(bnezc(a0, 0), - "f8800000 bnezc a0, 0x0"); - COMPARE(bnezc(a0, 0xfffff), // 0x0fffff == 1048575. - "f88fffff bnezc a0, 0xfffff"); - COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576. - "f8900000 bnezc a0, 0x100000"); } COMPARE(addiu(a0, a1, 0x0), @@ -669,23 +676,551 @@ TEST(Type0) { COMPARE(ext_(v0, v1, 0, 32), "7c62f800 ext v0, v1, 0, 32"); + COMPARE(add_s(f4, f6, f8), "46083100 add.s f4, f6, f8"); + COMPARE(add_d(f12, f14, f16), "46307300 add.d f12, f14, f16"); + + if (kArchVariant == kMips64r6) { + COMPARE(bitswap(a0, a1), "7c052020 bitswap a0, a1"); + COMPARE(bitswap(t8, s0), "7c10c020 bitswap t8, s0"); + COMPARE(dbitswap(a0, a1), "7c052024 dbitswap a0, a1"); + COMPARE(dbitswap(t8, s0), "7c10c024 dbitswap t8, s0"); + } + + COMPARE(abs_s(f6, f8), "46004185 abs.s f6, f8"); + COMPARE(abs_d(f10, f12), "46206285 abs.d f10, f12"); + + COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6"); + COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6"); + + if (kArchVariant == kMips64r6) { + COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0"); + COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1"); + COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2"); + COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(dalign(v0, a0, a1, 0), "7c851224 dalign v0, a0, a1, 0"); + COMPARE(dalign(v0, a0, a1, 1), "7c851264 dalign v0, a0, a1, 1"); + COMPARE(dalign(v0, a0, a1, 2), "7c8512a4 dalign v0, a0, a1, 2"); + COMPARE(dalign(v0, a0, a1, 3), "7c8512e4 dalign v0, a0, a1, 3"); + COMPARE(dalign(v0, a0, a1, 4), "7c851324 dalign v0, a0, a1, 4"); + COMPARE(dalign(v0, a0, a1, 5), "7c851364 dalign v0, a0, a1, 5"); + COMPARE(dalign(v0, a0, a1, 6), "7c8513a4 dalign v0, a0, a1, 6"); + COMPARE(dalign(v0, a0, a1, 7), "7c8513e4 dalign v0, a0, a1, 7"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0"); + COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1"); + COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767"); + COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768"); + COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0"); + COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1"); + COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767"); + COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768"); + COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(lwpc(a5, 0), "ed280000 lwpc a5, 0"); + COMPARE(lwpc(a5, 4), "ed280004 lwpc a5, 4"); + COMPARE(lwpc(a5, -4), "ed2ffffc lwpc a5, -4"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(lwupc(a0, -262144), "ec940000 lwupc a0, -262144"); + COMPARE(lwupc(a0, -1), "ec97ffff lwupc a0, -1"); + COMPARE(lwupc(a0, 0), "ec900000 lwupc a0, 0"); + COMPARE(lwupc(a0, 1), "ec900001 lwupc a0, 1"); + COMPARE(lwupc(a0, 262143), "ec93ffff lwupc a0, 262143"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(jic(t0, 16), "d80c0010 jic t0, 16"); + COMPARE(jic(t0, 4), "d80c0004 jic t0, 4"); + COMPARE(jic(t0, -32), "d80cffe0 jic t0, -32"); + } + + if (kArchVariant == kMips64r6) { + COMPARE_PC_REL_COMPACT(beqzc(a0, 16), "d8800010 beqzc a0, 0x10", + 16); + COMPARE_PC_REL_COMPACT(beqzc(a0, 4), "d8800004 beqzc a0, 0x4", 4); + COMPARE_PC_REL_COMPACT(beqzc(a0, -32), + "d89fffe0 beqzc a0, 0x1fffe0", -32); + } + + if (kArchVariant == kMips64r6) { + COMPARE(ldpc(v0, 256), "ec580100 ldpc v0, 256"); + COMPARE(ldpc(a0, -1), "ec9bffff ldpc a0, -1"); + COMPARE(ldpc(a1, 0), "ecb80000 ldpc a1, 0"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143"); + COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1"); + COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0"); + COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1"); + COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144"); + } + + if (kArchVariant == kMips64r6) { + COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000"); + COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff"); + COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0"); + COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1"); + COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff"); + } + VERIFY_RUN(); } TEST(Type1) { + SET_UP(); if (kArchVariant == kMips64r6) { - SET_UP(); COMPARE(seleqz(a0, a1, a2), "00a62035 seleqz a0, a1, a2"); COMPARE(selnez(a0, a1, a2), "00a62037 selnez a0, a1, a2"); COMPARE(seleqz(D, f3, f4, f5), "462520d4 seleqz.d f3, f4, f5"); COMPARE(selnez(D, f3, f4, f5), "462520d7 selnez.d f3, f4, f5"); + COMPARE(seleqz(S, f3, f4, f5), "460520d4 seleqz.s f3, f4, f5"); + COMPARE(selnez(S, f3, f4, f5), "460520d7 selnez.s f3, f4, f5"); COMPARE(min_d(f3, f4, f5), "462520dc min.d f3, f4, f5"); COMPARE(max_d(f3, f4, f5), "462520de max.d f3, f4, f5"); + + COMPARE(sel(S, f3, f4, f5), "460520d0 sel.s f3, f4, f5"); + COMPARE(sel(D, f3, f4, f5), "462520d0 sel.d f3, f4, f5"); + COMPARE(rint_d(f8, f6), "4620321a rint.d f8, f6"); + + COMPARE(min_s(f3, f4, f5), "460520dc min.s f3, f4, f5"); + COMPARE(max_s(f3, f4, f5), "460520de max.s f3, f4, f5"); + + COMPARE(rint(S, f8, f6), "4600321a rint.s f8, f6"); + + COMPARE(mina_d(f3, f4, f5), "462520dd mina.d f3, f4, f5"); + COMPARE(mina_s(f3, f4, f5), "460520dd mina.s f3, f4, f5"); + + COMPARE(maxa_d(f3, f4, f5), "462520df maxa.d f3, f4, f5"); + COMPARE(maxa_s(f3, f4, f5), "460520df maxa.s f3, f4, f5"); + } + COMPARE(trunc_w_d(f8, f6), "4620320d trunc.w.d f8, f6"); + COMPARE(trunc_w_s(f8, f6), "4600320d trunc.w.s f8, f6"); + + COMPARE(round_w_s(f8, f6), "4600320c round.w.s f8, f6"); + COMPARE(round_w_d(f8, f6), "4620320c round.w.d f8, f6"); + + COMPARE(round_l_s(f8, f6), "46003208 round.l.s f8, f6"); + COMPARE(round_l_d(f8, f6), "46203208 round.l.d f8, f6"); + + COMPARE(floor_w_s(f8, f6), "4600320f floor.w.s f8, f6"); + COMPARE(floor_w_d(f8, f6), "4620320f floor.w.d f8, f6"); + + COMPARE(floor_l_s(f8, f6), "4600320b floor.l.s f8, f6"); + COMPARE(floor_l_d(f8, f6), "4620320b floor.l.d f8, f6"); + + COMPARE(ceil_w_s(f8, f6), "4600320e ceil.w.s f8, f6"); + COMPARE(ceil_w_d(f8, f6), "4620320e ceil.w.d f8, f6"); + + COMPARE(ceil_l_s(f8, f6), "4600320a ceil.l.s f8, f6"); + COMPARE(ceil_l_d(f8, f6), "4620320a ceil.l.d f8, f6"); + + COMPARE(sub_s(f10, f8, f6), "46064281 sub.s f10, f8, f6"); + COMPARE(sub_d(f10, f8, f6), "46264281 sub.d f10, f8, f6"); + + COMPARE(sqrt_s(f8, f6), "46003204 sqrt.s f8, f6"); + COMPARE(sqrt_d(f8, f6), "46203204 sqrt.d f8, f6"); + + COMPARE(neg_s(f8, f6), "46003207 neg.s f8, f6"); + COMPARE(neg_d(f8, f6), "46203207 neg.d f8, f6"); + + COMPARE(mul_s(f8, f6, f4), "46043202 mul.s f8, f6, f4"); + COMPARE(mul_d(f8, f6, f4), "46243202 mul.d f8, f6, f4"); + + COMPARE(rsqrt_s(f8, f6), "46003216 rsqrt.s f8, f6"); + COMPARE(rsqrt_d(f8, f6), "46203216 rsqrt.d f8, f6"); + + COMPARE(recip_s(f8, f6), "46003215 recip.s f8, f6"); + COMPARE(recip_d(f8, f6), "46203215 recip.d f8, f6"); + + COMPARE(mov_s(f6, f4), "46002186 mov.s f6, f4"); + COMPARE(mov_d(f6, f4), "46202186 mov.d f6, f4"); + if (kArchVariant == kMips64r2) { + COMPARE(trunc_l_d(f8, f6), "46203209 trunc.l.d f8, f6"); + COMPARE(trunc_l_s(f8, f6), "46003209 trunc.l.s f8, f6"); + + COMPARE(movz_s(f6, f4, t0), "460c2192 movz.s f6, f4, t0"); + COMPARE(movz_d(f6, f4, t0), "462c2192 movz.d f6, f4, t0"); + + COMPARE(movt_s(f6, f4, 4), "46112191 movt.s f6, f4, cc(1)"); + COMPARE(movt_d(f6, f4, 4), "46312191 movt.d f6, f4, cc(1)"); + + COMPARE(movf_s(f6, f4, 4), "46102191 movf.s f6, f4, cc(1)"); + COMPARE(movf_d(f6, f4, 4), "46302191 movf.d f6, f4, cc(1)"); + + COMPARE(movn_s(f6, f4, t0), "460c2193 movn.s f6, f4, t0"); + COMPARE(movn_d(f6, f4, t0), "462c2193 movn.d f6, f4, t0"); + } + VERIFY_RUN(); +} + + +TEST(Type2) { + if (kArchVariant == kMips64r6) { + SET_UP(); + + COMPARE(class_s(f3, f4), "460020db class.s f3, f4"); + COMPARE(class_d(f2, f3), "4620189b class.d f2, f3"); + VERIFY_RUN(); } } + + +TEST(Type3) { + SET_UP(); + + if (kArchVariant == kMips64r6) { + COMPARE_PC_REL_COMPACT(bovc(a0, a0, static_cast<int16_t>(0)), + "20840000 bovc a0, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, static_cast<int16_t>(0)), + "20a40000 bovc a1, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, 32767), + "20a47fff bovc a1, a0, 32767", 32767); + COMPARE_PC_REL_COMPACT(bovc(a1, a0, -32768), + "20a48000 bovc a1, a0, -32768", -32768); + + COMPARE_PC_REL_COMPACT(bnvc(a0, a0, static_cast<int16_t>(0)), + "60840000 bnvc a0, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, static_cast<int16_t>(0)), + "60a40000 bnvc a1, a0, 0", 0); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, 32767), + "60a47fff bnvc a1, a0, 32767", 32767); + COMPARE_PC_REL_COMPACT(bnvc(a1, a0, -32768), + "60a48000 bnvc a1, a0, -32768", -32768); + + COMPARE_PC_REL_COMPACT(beqzc(a0, 0), "d8800000 beqzc a0, 0x0", 0); + COMPARE_PC_REL_COMPACT(beqzc(a0, 0xfffff), // 0x0fffff == 1048575. + "d88fffff beqzc a0, 0xfffff", 1048575); + COMPARE_PC_REL_COMPACT(beqzc(a0, 0x100000), // 0x100000 == -1048576. + "d8900000 beqzc a0, 0x100000", -1048576); + + COMPARE_PC_REL_COMPACT(bnezc(a0, 0), "f8800000 bnezc a0, 0x0", 0); + COMPARE_PC_REL_COMPACT(bnezc(a0, 0xfffff), // 0x0fffff == 1048575. + "f88fffff bnezc a0, 0xfffff", 1048575); + COMPARE_PC_REL_COMPACT(bnezc(a0, 0x100000), // 0x100000 == -1048576. + "f8900000 bnezc a0, 0x100000", -1048576); + + COMPARE_PC_REL_COMPACT(bc(-33554432), "ca000000 bc -33554432", + -33554432); + COMPARE_PC_REL_COMPACT(bc(-1), "cbffffff bc -1", -1); + COMPARE_PC_REL_COMPACT(bc(0), "c8000000 bc 0", 0); + COMPARE_PC_REL_COMPACT(bc(1), "c8000001 bc 1", 1); + COMPARE_PC_REL_COMPACT(bc(33554431), "c9ffffff bc 33554431", + 33554431); + + COMPARE_PC_REL_COMPACT(balc(-33554432), "ea000000 balc -33554432", + -33554432); + COMPARE_PC_REL_COMPACT(balc(-1), "ebffffff balc -1", -1); + COMPARE_PC_REL_COMPACT(balc(0), "e8000000 balc 0", 0); + COMPARE_PC_REL_COMPACT(balc(1), "e8000001 balc 1", 1); + COMPARE_PC_REL_COMPACT(balc(33554431), "e9ffffff balc 33554431", + 33554431); + + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, -32768), + "18858000 bgeuc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, -1), + "1885ffff bgeuc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 1), + "18850001 bgeuc a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(bgeuc(a0, a1, 32767), + "18857fff bgeuc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgezalc(a0, -32768), + "18848000 bgezalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgezalc(a0, -1), "1884ffff bgezalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bgezalc(a0, 1), "18840001 bgezalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgezalc(a0, 32767), + "18847fff bgezalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(blezalc(a0, -32768), + "18048000 blezalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(blezalc(a0, -1), "1804ffff blezalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(blezalc(a0, 1), "18040001 blezalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(blezalc(a0, 32767), + "18047fff blezalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, -32768), + "1c858000 bltuc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, -1), + "1c85ffff bltuc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, 1), "1c850001 bltuc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bltuc(a0, a1, 32767), + "1c857fff bltuc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltzalc(a0, -32768), + "1c848000 bltzalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltzalc(a0, -1), "1c84ffff bltzalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bltzalc(a0, 1), "1c840001 bltzalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltzalc(a0, 32767), + "1c847fff bltzalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgtzalc(a0, -32768), + "1c048000 bgtzalc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, -1), "1c04ffff bgtzalc a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, 1), "1c040001 bgtzalc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtzalc(a0, 32767), + "1c047fff bgtzalc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgezc(a0, -32768), + "58848000 bgezc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgezc(a0, -1), "5884ffff bgezc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgezc(a0, 1), "58840001 bgezc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgezc(a0, 32767), + "58847fff bgezc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgec(a0, a1, -32768), + "58858000 bgec a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, -1), + "5885ffff bgec a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, 1), "58850001 bgec a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bgec(a0, a1, 32767), + "58857fff bgec a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(blezc(a0, -32768), + "58048000 blezc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(blezc(a0, -1), "5804ffff blezc a0, -1", -1); + COMPARE_PC_REL_COMPACT(blezc(a0, 1), "58040001 blezc a0, 1", 1); + COMPARE_PC_REL_COMPACT(blezc(a0, 32767), + "58047fff blezc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltzc(a0, -32768), + "5c848000 bltzc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltzc(a0, -1), "5c84ffff bltzc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bltzc(a0, 1), "5c840001 bltzc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltzc(a0, 32767), + "5c847fff bltzc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltc(a0, a1, -32768), + "5c858000 bltc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, -1), + "5c85ffff bltc a0, a1, -1", -1); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, 1), "5c850001 bltc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bltc(a0, a1, 32767), + "5c857fff bltc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bgtzc(a0, -32768), + "5c048000 bgtzc a0, -32768", -32768); + COMPARE_PC_REL_COMPACT(bgtzc(a0, -1), "5c04ffff bgtzc a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgtzc(a0, 1), "5c040001 bgtzc a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtzc(a0, 32767), + "5c047fff bgtzc a0, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bc1eqz(-32768, f1), + "45218000 bc1eqz f1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bc1eqz(-1, f1), "4521ffff bc1eqz f1, -1", + -1); + COMPARE_PC_REL_COMPACT(bc1eqz(1, f1), "45210001 bc1eqz f1, 1", 1); + COMPARE_PC_REL_COMPACT(bc1eqz(32767, f1), + "45217fff bc1eqz f1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bc1nez(-32768, f1), + "45a18000 bc1nez f1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bc1nez(-1, f1), "45a1ffff bc1nez f1, -1", + -1); + COMPARE_PC_REL_COMPACT(bc1nez(1, f1), "45a10001 bc1nez f1, 1", 1); + COMPARE_PC_REL_COMPACT(bc1nez(32767, f1), + "45a17fff bc1nez f1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bovc(a1, a0, -1), "20a4ffff bovc a1, a0, -1", + -1); + COMPARE_PC_REL_COMPACT(bovc(a0, a0, 1), "20840001 bovc a0, a0, 1", + 1); + + COMPARE_PC_REL_COMPACT(beqc(a0, a1, -32768), + "20858000 beqc a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, -1), "2085ffff beqc a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, 1), "20850001 beqc a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(beqc(a0, a1, 32767), + "20857fff beqc a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bnec(a0, a1, -32768), + "60858000 bnec a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, -1), "6085ffff bnec a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, 1), "60850001 bnec a0, a1, 1", + 1); + COMPARE_PC_REL_COMPACT(bnec(a0, a1, 32767), + "60857fff bnec a0, a1, 32767", 32767); + } + + COMPARE_PC_REL_COMPACT(bne(a0, a1, -32768), + "14858000 bne a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(bne(a0, a1, -1), "1485ffff bne a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(bne(a0, a1, 1), "14850001 bne a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(bne(a0, a1, 32767), + "14857fff bne a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(beq(a0, a1, -32768), + "10858000 beq a0, a1, -32768", -32768); + COMPARE_PC_REL_COMPACT(beq(a0, a1, -1), "1085ffff beq a0, a1, -1", + -1); + COMPARE_PC_REL_COMPACT(beq(a0, a1, 1), "10850001 beq a0, a1, 1", 1); + COMPARE_PC_REL_COMPACT(beq(a0, a1, 32767), + "10857fff beq a0, a1, 32767", 32767); + + COMPARE_PC_REL_COMPACT(bltz(a0, -32768), "04808000 bltz a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bltz(a0, -1), "0480ffff bltz a0, -1", -1); + COMPARE_PC_REL_COMPACT(bltz(a0, 1), "04800001 bltz a0, 1", 1); + COMPARE_PC_REL_COMPACT(bltz(a0, 32767), "04807fff bltz a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(bgez(a0, -32768), "04818000 bgez a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bgez(a0, -1), "0481ffff bgez a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgez(a0, 1), "04810001 bgez a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgez(a0, 32767), "04817fff bgez a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(blez(a0, -32768), "18808000 blez a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(blez(a0, -1), "1880ffff blez a0, -1", -1); + COMPARE_PC_REL_COMPACT(blez(a0, 1), "18800001 blez a0, 1", 1); + COMPARE_PC_REL_COMPACT(blez(a0, 32767), "18807fff blez a0, 32767", + 32767); + + COMPARE_PC_REL_COMPACT(bgtz(a0, -32768), "1c808000 bgtz a0, -32768", + -32768); + COMPARE_PC_REL_COMPACT(bgtz(a0, -1), "1c80ffff bgtz a0, -1", -1); + COMPARE_PC_REL_COMPACT(bgtz(a0, 1), "1c800001 bgtz a0, 1", 1); + COMPARE_PC_REL_COMPACT(bgtz(a0, 32767), "1c807fff bgtz a0, 32767", + 32767); + + COMPARE_PC_JUMP(j(0x4), "08000001 j 0x4", 0x4); + COMPARE_PC_JUMP(j(0xffffffc), "0bffffff j 0xffffffc", 0xffffffc); + + COMPARE_PC_JUMP(jal(0x4), "0c000001 jal 0x4", 0x4); + COMPARE_PC_JUMP(jal(0xffffffc), "0fffffff jal 0xffffffc", + 0xffffffc); + + VERIFY_RUN(); +} + + +TEST(C_FMT_DISASM) { + if (kArchVariant == kMips64r2) { + SET_UP(); + + COMPARE(c_s(F, f8, f10, 0), "460a4030 c.f.s f8, f10, cc(0)"); + COMPARE(c_d(F, f8, f10, 0), "462a4030 c.f.d f8, f10, cc(0)"); + + COMPARE(c_s(UN, f8, f10, 2), "460a4231 c.un.s f8, f10, cc(2)"); + COMPARE(c_d(UN, f8, f10, 2), "462a4231 c.un.d f8, f10, cc(2)"); + + COMPARE(c_s(EQ, f8, f10, 4), "460a4432 c.eq.s f8, f10, cc(4)"); + COMPARE(c_d(EQ, f8, f10, 4), "462a4432 c.eq.d f8, f10, cc(4)"); + + COMPARE(c_s(UEQ, f8, f10, 6), "460a4633 c.ueq.s f8, f10, cc(6)"); + COMPARE(c_d(UEQ, f8, f10, 6), "462a4633 c.ueq.d f8, f10, cc(6)"); + + COMPARE(c_s(OLT, f8, f10, 0), "460a4034 c.olt.s f8, f10, cc(0)"); + COMPARE(c_d(OLT, f8, f10, 0), "462a4034 c.olt.d f8, f10, cc(0)"); + + COMPARE(c_s(ULT, f8, f10, 2), "460a4235 c.ult.s f8, f10, cc(2)"); + COMPARE(c_d(ULT, f8, f10, 2), "462a4235 c.ult.d f8, f10, cc(2)"); + + COMPARE(c_s(OLE, f8, f10, 4), "460a4436 c.ole.s f8, f10, cc(4)"); + COMPARE(c_d(OLE, f8, f10, 4), "462a4436 c.ole.d f8, f10, cc(4)"); + + COMPARE(c_s(ULE, f8, f10, 6), "460a4637 c.ule.s f8, f10, cc(6)"); + COMPARE(c_d(ULE, f8, f10, 6), "462a4637 c.ule.d f8, f10, cc(6)"); + + VERIFY_RUN(); + } +} + + +TEST(COND_FMT_DISASM) { + if (kArchVariant == kMips64r6) { + SET_UP(); + + COMPARE(cmp_s(F, f6, f8, f10), "468a4180 cmp.af.s f6, f8, f10"); + COMPARE(cmp_d(F, f6, f8, f10), "46aa4180 cmp.af.d f6, f8, f10"); + + COMPARE(cmp_s(UN, f6, f8, f10), "468a4181 cmp.un.s f6, f8, f10"); + COMPARE(cmp_d(UN, f6, f8, f10), "46aa4181 cmp.un.d f6, f8, f10"); + + COMPARE(cmp_s(EQ, f6, f8, f10), "468a4182 cmp.eq.s f6, f8, f10"); + COMPARE(cmp_d(EQ, f6, f8, f10), "46aa4182 cmp.eq.d f6, f8, f10"); + + COMPARE(cmp_s(UEQ, f6, f8, f10), "468a4183 cmp.ueq.s f6, f8, f10"); + COMPARE(cmp_d(UEQ, f6, f8, f10), "46aa4183 cmp.ueq.d f6, f8, f10"); + + COMPARE(cmp_s(LT, f6, f8, f10), "468a4184 cmp.lt.s f6, f8, f10"); + COMPARE(cmp_d(LT, f6, f8, f10), "46aa4184 cmp.lt.d f6, f8, f10"); + + COMPARE(cmp_s(ULT, f6, f8, f10), "468a4185 cmp.ult.s f6, f8, f10"); + COMPARE(cmp_d(ULT, f6, f8, f10), "46aa4185 cmp.ult.d f6, f8, f10"); + + COMPARE(cmp_s(LE, f6, f8, f10), "468a4186 cmp.le.s f6, f8, f10"); + COMPARE(cmp_d(LE, f6, f8, f10), "46aa4186 cmp.le.d f6, f8, f10"); + + COMPARE(cmp_s(ULE, f6, f8, f10), "468a4187 cmp.ule.s f6, f8, f10"); + COMPARE(cmp_d(ULE, f6, f8, f10), "46aa4187 cmp.ule.d f6, f8, f10"); + + COMPARE(cmp_s(ORD, f6, f8, f10), "468a4191 cmp.or.s f6, f8, f10"); + COMPARE(cmp_d(ORD, f6, f8, f10), "46aa4191 cmp.or.d f6, f8, f10"); + + COMPARE(cmp_s(UNE, f6, f8, f10), "468a4192 cmp.une.s f6, f8, f10"); + COMPARE(cmp_d(UNE, f6, f8, f10), "46aa4192 cmp.une.d f6, f8, f10"); + + COMPARE(cmp_s(NE, f6, f8, f10), "468a4193 cmp.ne.s f6, f8, f10"); + COMPARE(cmp_d(NE, f6, f8, f10), "46aa4193 cmp.ne.d f6, f8, f10"); + + VERIFY_RUN(); + } +} + + +TEST(CVT_DISSASM) { + SET_UP(); + COMPARE(cvt_d_s(f22, f24), "4600c5a1 cvt.d.s f22, f24"); + COMPARE(cvt_d_w(f22, f24), "4680c5a1 cvt.d.w f22, f24"); + if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) { + COMPARE(cvt_d_l(f22, f24), "46a0c5a1 cvt.d.l f22, f24"); + } + + if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) { + COMPARE(cvt_l_s(f22, f24), "4600c5a5 cvt.l.s f22, f24"); + COMPARE(cvt_l_d(f22, f24), "4620c5a5 cvt.l.d f22, f24"); + } + + COMPARE(cvt_s_d(f22, f24), "4620c5a0 cvt.s.d f22, f24"); + COMPARE(cvt_s_w(f22, f24), "4680c5a0 cvt.s.w f22, f24"); + if (kArchVariant == kMips64r6 || kArchVariant == kMips64r2) { + COMPARE(cvt_s_l(f22, f24), "46a0c5a0 cvt.s.l f22, f24"); + } + + COMPARE(cvt_s_d(f22, f24), "4620c5a0 cvt.s.d f22, f24"); + COMPARE(cvt_s_w(f22, f24), "4680c5a0 cvt.s.w f22, f24"); + + VERIFY_RUN(); +} diff --git a/deps/v8/test/cctest/test-extra.js b/deps/v8/test/cctest/test-extra.js new file mode 100644 index 0000000000..829ddee01a --- /dev/null +++ b/deps/v8/test/cctest/test-extra.js @@ -0,0 +1,14 @@ +// Copyright 2015 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. + +(function (global, exports) { + 'use strict'; + exports.testExtraShouldReturnFive = function () { + return 5; + }; + + exports.testExtraShouldCallToRuntime = function() { + return exports.runtime(3); + }; +}) diff --git a/deps/v8/test/cctest/test-feedback-vector.cc b/deps/v8/test/cctest/test-feedback-vector.cc index e94de7b552..cf8a730fb7 100644 --- a/deps/v8/test/cctest/test-feedback-vector.cc +++ b/deps/v8/test/cctest/test-feedback-vector.cc @@ -46,19 +46,13 @@ TEST(VectorStructure) { CHECK_EQ(1, vector->ICSlots()); ZoneFeedbackVectorSpec spec(zone, 3, 5); - if (FLAG_vector_ics) { - for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC); - } + for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC); vector = factory->NewTypeFeedbackVector(&spec); CHECK_EQ(3, vector->Slots()); CHECK_EQ(5, vector->ICSlots()); int metadata_length = vector->ic_metadata_length(); - if (!FLAG_vector_ics) { - CHECK_EQ(0, metadata_length); - } else { - CHECK(metadata_length > 0); - } + CHECK(metadata_length > 0); int index = vector->GetIndex(FeedbackVectorSlot(0)); @@ -79,11 +73,6 @@ TEST(VectorStructure) { TEST(VectorICMetadata) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); - if (!FLAG_vector_ics) { - // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so - // there is no need for metadata to describe the slots. - return; - } Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); Zone* zone = isolate->runtime_zone(); @@ -259,7 +248,7 @@ TEST(VectorCallICStates) { TEST(VectorLoadICStates) { - if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; + if (i::FLAG_always_opt) return; CcTest::InitializeVM(); LocalContext context; v8::HandleScope scope(context->GetIsolate()); @@ -313,7 +302,7 @@ TEST(VectorLoadICStates) { TEST(VectorLoadICSlotSharing) { - if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; + if (i::FLAG_always_opt) return; CcTest::InitializeVM(); LocalContext context; v8::HandleScope scope(context->GetIsolate()); @@ -322,7 +311,7 @@ TEST(VectorLoadICSlotSharing) { // Function f has 3 LoadICs, one for each o, but the ICs share the same // feedback vector IC slot. CompileRun( - "var o = 10;" + "o = 10;" "function f() {" " var x = o + 10;" " return o + x + o;" @@ -341,7 +330,7 @@ TEST(VectorLoadICSlotSharing) { TEST(VectorLoadICOnSmi) { - if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; + if (i::FLAG_always_opt) return; CcTest::InitializeVM(); LocalContext context; v8::HandleScope scope(context->GetIsolate()); diff --git a/deps/v8/test/cctest/test-fuzz-arm64.cc b/deps/v8/test/cctest/test-fuzz-arm64.cc index ada609fe78..8f6651a6a9 100644 --- a/deps/v8/test/cctest/test-fuzz-arm64.cc +++ b/deps/v8/test/cctest/test-fuzz-arm64.cc @@ -43,7 +43,7 @@ TEST(FUZZ_decoder) { Instruction buffer[kInstructionSize]; for (int i = 0; i < instruction_count; i++) { - uint32_t instr = mrand48(); + uint32_t instr = static_cast<uint32_t>(mrand48()); buffer->SetInstructionBits(instr); decoder.Decode(buffer); } @@ -64,7 +64,7 @@ TEST(FUZZ_disasm) { decoder.AppendVisitor(&disasm); for (int i = 0; i < instruction_count; i++) { - uint32_t instr = mrand48(); + uint32_t instr = static_cast<uint32_t>(mrand48()); buffer->SetInstructionBits(instr); decoder.Decode(buffer); } diff --git a/deps/v8/test/cctest/test-global-object.cc b/deps/v8/test/cctest/test-global-object.cc index b0ed29daf1..9cc755e4e1 100644 --- a/deps/v8/test/cctest/test-global-object.cc +++ b/deps/v8/test/cctest/test-global-object.cc @@ -29,15 +29,13 @@ #include "test/cctest/cctest.h" -using namespace v8; - // This test fails if properties on the prototype of the global object appear // as declared globals. TEST(StrictUndeclaredGlobalVariable) { - HandleScope scope(CcTest::isolate()); + v8::HandleScope scope(CcTest::isolate()); v8::Local<v8::String> var_name = v8_str("x"); LocalContext context; - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); v8::Local<v8::Script> script = v8_compile("\"use strict\"; x = 42;"); v8::Handle<v8::Object> proto = v8::Object::New(CcTest::isolate()); v8::Handle<v8::Object> global = diff --git a/deps/v8/test/cctest/test-hashing.cc b/deps/v8/test/cctest/test-hashing.cc index c8ae4f30e5..9e5de2e05a 100644 --- a/deps/v8/test/cctest/test-hashing.cc +++ b/deps/v8/test/cctest/test-hashing.cc @@ -131,7 +131,7 @@ void check(uint32_t key) { #endif uint32_t runtime_hash = ComputeIntegerHash(key, isolate->heap()->HashSeed()); - CHECK(runtime_hash == codegen_hash); + CHECK_EQ(runtime_hash, codegen_hash); } diff --git a/deps/v8/test/cctest/test-hashmap.cc b/deps/v8/test/cctest/test-hashmap.cc index fb56225fb4..b45d6c7183 100644 --- a/deps/v8/test/cctest/test-hashmap.cc +++ b/deps/v8/test/cctest/test-hashmap.cc @@ -171,7 +171,7 @@ void TestSet(IntKeyHash hash, int size) { } -TEST(Set) { +TEST(HashSet) { TestSet(Hash, 100); TestSet(CollisionHash, 50); } diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index f0a6ad5d26..d85310225a 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -59,6 +59,7 @@ TEST(HeapMaps) { Heap* heap = CcTest::heap(); CheckMap(heap->meta_map(), MAP_TYPE, Map::kSize); CheckMap(heap->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize); + CheckMap(heap->float32x4_map(), FLOAT32X4_TYPE, Float32x4::kSize); CheckMap(heap->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel); CheckMap(heap->string_map(), STRING_TYPE, kVariableSizeSentinel); } @@ -213,6 +214,60 @@ TEST(HeapObjects) { } +template <typename T, typename LANE_TYPE, int LANES> +static void CheckSimdLanes(T* value) { + // Get the original values, and check that all lanes can be set to new values + // without disturbing the other lanes. + LANE_TYPE lane_values[LANES]; + for (int i = 0; i < LANES; i++) { + lane_values[i] = value->get_lane(i); + } + for (int i = 0; i < LANES; i++) { + lane_values[i] += 1; + value->set_lane(i, lane_values[i]); + for (int j = 0; j < LANES; j++) { + CHECK_EQ(lane_values[j], value->get_lane(j)); + } + } +} + + +TEST(SimdObjects) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + + HandleScope sc(isolate); + + Handle<Object> value = factory->NewFloat32x4(1, 2, 3, 4); + CHECK(value->IsFloat32x4()); + CHECK(value->BooleanValue()); // SIMD values map to true. + + Float32x4* float32x4 = *Handle<Float32x4>::cast(value); + CheckSimdLanes<Float32x4, float, 4>(float32x4); + + // Check ToString for SIMD values. + // TODO(bbudge): Switch to Check* style function to test ToString(). + value = factory->NewFloat32x4(1, 2, 3, 4); + float32x4 = *Handle<Float32x4>::cast(value); + std::ostringstream os; + float32x4->Float32x4Print(os); + CHECK_EQ("1, 2, 3, 4", os.str()); + + // Check unusual lane values. + float32x4->set_lane(0, 0); + CHECK_EQ(0, float32x4->get_lane(0)); + float32x4->set_lane(1, -0.0); + CHECK_EQ(-0.0, float32x4->get_lane(1)); + float quiet_NaN = std::numeric_limits<float>::quiet_NaN(); + float signaling_NaN = std::numeric_limits<float>::signaling_NaN(); + float32x4->set_lane(2, quiet_NaN); + CHECK(std::isnan(float32x4->get_lane(2))); + float32x4->set_lane(3, signaling_NaN); + CHECK(std::isnan(float32x4->get_lane(3))); +} + + TEST(Tagging) { CcTest::InitializeVM(); int request = 24; @@ -730,29 +785,27 @@ TEST(JSArray) { JSArray::Initialize(array, 0); // Set array length to 0. - JSArray::SetElementsLength(array, handle(Smi::FromInt(0), isolate)).Check(); + JSArray::SetLength(array, 0); CHECK_EQ(Smi::FromInt(0), array->length()); // Must be in fast mode. CHECK(array->HasFastSmiOrObjectElements()); // array[length] = name. - JSReceiver::SetElement(array, 0, name, NONE, SLOPPY).Check(); + JSReceiver::SetElement(array, 0, name, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(1), array->length()); element = i::Object::GetElement(isolate, array, 0).ToHandleChecked(); CHECK_EQ(*element, *name); // Set array length with larger than smi value. - Handle<Object> length = - factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1); - JSArray::SetElementsLength(array, length).Check(); + JSArray::SetLength(array, static_cast<uint32_t>(Smi::kMaxValue) + 1); uint32_t int_length = 0; - CHECK(length->ToArrayIndex(&int_length)); - CHECK_EQ(*length, array->length()); + CHECK(array->length()->ToArrayIndex(&int_length)); + CHECK_EQ(static_cast<uint32_t>(Smi::kMaxValue) + 1, int_length); CHECK(array->HasDictionaryElements()); // Must be in slow mode. // array[length] = name. - JSReceiver::SetElement(array, int_length, name, NONE, SLOPPY).Check(); + JSReceiver::SetElement(array, int_length, name, SLOPPY).Check(); uint32_t new_int_length = 0; CHECK(array->length()->ToArrayIndex(&new_int_length)); CHECK_EQ(static_cast<double>(int_length), new_int_length - 1); @@ -783,8 +836,8 @@ TEST(JSObjectCopy) { JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); - JSReceiver::SetElement(obj, 0, first, NONE, SLOPPY).Check(); - JSReceiver::SetElement(obj, 1, second, NONE, SLOPPY).Check(); + JSReceiver::SetElement(obj, 0, first, SLOPPY).Check(); + JSReceiver::SetElement(obj, 1, second, SLOPPY).Check(); // Make the clone. Handle<Object> value1, value2; @@ -809,8 +862,8 @@ TEST(JSObjectCopy) { JSReceiver::SetProperty(clone, first, two, SLOPPY).Check(); JSReceiver::SetProperty(clone, second, one, SLOPPY).Check(); - JSReceiver::SetElement(clone, 0, second, NONE, SLOPPY).Check(); - JSReceiver::SetElement(clone, 1, first, NONE, SLOPPY).Check(); + JSReceiver::SetElement(clone, 0, second, SLOPPY).Check(); + JSReceiver::SetElement(clone, 1, first, SLOPPY).Check(); value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked(); value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked(); @@ -896,9 +949,8 @@ TEST(Iteration) { // Allocate a JS array to OLD_SPACE and NEW_SPACE objs[next_objs_index++] = factory->NewJSArray(10); - objs[next_objs_index++] = factory->NewJSArray(10, - FAST_HOLEY_ELEMENTS, - TENURED); + objs[next_objs_index++] = + factory->NewJSArray(10, FAST_HOLEY_ELEMENTS, Strength::WEAK, TENURED); // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE objs[next_objs_index++] = factory->NewStringFromStaticChars("abcdefghij"); @@ -1142,7 +1194,7 @@ TEST(TestCodeFlushingPreAged) { TEST(TestCodeFlushingIncremental) { // If we do not flush code this test is invalid. - if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + if (!FLAG_flush_code) return; i::FLAG_allow_natives_syntax = true; i::FLAG_optimize_for_size = false; CcTest::InitializeVM(); @@ -1211,7 +1263,7 @@ TEST(TestCodeFlushingIncremental) { TEST(TestCodeFlushingIncrementalScavenge) { // If we do not flush code this test is invalid. - if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + if (!FLAG_flush_code) return; i::FLAG_allow_natives_syntax = true; i::FLAG_optimize_for_size = false; CcTest::InitializeVM(); @@ -1280,7 +1332,7 @@ TEST(TestCodeFlushingIncrementalScavenge) { TEST(TestCodeFlushingIncrementalAbort) { // If we do not flush code this test is invalid. - if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + if (!FLAG_flush_code) return; i::FLAG_allow_natives_syntax = true; i::FLAG_optimize_for_size = false; CcTest::InitializeVM(); @@ -1328,8 +1380,10 @@ TEST(TestCodeFlushingIncrementalAbort) { // disabled. int position = 0; Handle<Object> breakpoint_object(Smi::FromInt(0), isolate); + EnableDebugger(); isolate->debug()->SetBreakPoint(function, breakpoint_object, &position); isolate->debug()->ClearAllBreakPoints(); + DisableDebugger(); // Force optimization now that code flushing is disabled. { v8::HandleScope scope(CcTest::isolate()); @@ -1346,8 +1400,7 @@ TEST(TestCodeFlushingIncrementalAbort) { TEST(CompilationCacheCachingBehavior) { // If we do not flush code, or have the compilation cache turned off, this // test is invalid. - if (!FLAG_flush_code || !FLAG_flush_code_incrementally || - !FLAG_compilation_cache) { + if (!FLAG_flush_code || !FLAG_compilation_cache) { return; } CcTest::InitializeVM(); @@ -1377,7 +1430,8 @@ TEST(CompilationCacheCachingBehavior) { // On first compilation, only a hash is inserted in the code cache. We can't // find that value. MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript( - source, Handle<Object>(), 0, 0, false, true, native_context, + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, language_mode); CHECK(info.is_null()); @@ -1388,16 +1442,20 @@ TEST(CompilationCacheCachingBehavior) { // On second compilation, the hash is replaced by a real cache entry mapping // the source to the shared function info containing the code. - info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, false, - true, native_context, language_mode); + info = compilation_cache->LookupScript( + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, + language_mode); CHECK(!info.is_null()); heap->CollectAllGarbage(); // On second compilation, the hash is replaced by a real cache entry mapping // the source to the shared function info containing the code. - info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, false, - true, native_context, language_mode); + info = compilation_cache->LookupScript( + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, + language_mode); CHECK(!info.is_null()); while (!info.ToHandleChecked()->code()->IsOld()) { @@ -1406,8 +1464,10 @@ TEST(CompilationCacheCachingBehavior) { heap->CollectAllGarbage(); // Ensure code aging cleared the entry from the cache. - info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, false, - true, native_context, language_mode); + info = compilation_cache->LookupScript( + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, + language_mode); CHECK(info.is_null()); { @@ -1417,8 +1477,10 @@ TEST(CompilationCacheCachingBehavior) { // On first compilation, only a hash is inserted in the code cache. We can't // find that value. - info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, false, - true, native_context, language_mode); + info = compilation_cache->LookupScript( + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, + language_mode); CHECK(info.is_null()); for (int i = 0; i < CompilationCacheTable::kHashGenerations; i++) { @@ -1432,8 +1494,10 @@ TEST(CompilationCacheCachingBehavior) { // If we aged the cache before caching the script, ensure that we didn't cache // on next compilation. - info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, false, - true, native_context, language_mode); + info = compilation_cache->LookupScript( + source, Handle<Object>(), 0, 0, + v8::ScriptOriginOptions(false, true, false), native_context, + language_mode); CHECK(info.is_null()); } @@ -1682,13 +1746,13 @@ TEST(TestSizeOfRegExpCode) { // Adjust source below and this check to match // RegExpImple::kRegExpTooLargeToOptimize. - DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 10 * KB); + DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 20 * KB); // Compile a regexp that is much larger if we are using regexp optimizations. CompileRun( "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';" "var half_size_reg_exp;" - "while (reg_exp_source.length < 10 * 1024) {" + "while (reg_exp_source.length < 20 * 1024) {" " half_size_reg_exp = reg_exp_source;" " reg_exp_source = reg_exp_source + reg_exp_source;" "}" @@ -1719,7 +1783,11 @@ TEST(TestSizeOfRegExpCode) { int size_of_regexp_code = size_with_regexp - initial_size; - CHECK_LE(size_of_regexp_code, 1 * MB); + // On some platforms the debug-code flag causes huge amounts of regexp code + // to be emitted, breaking this test. + if (!FLAG_debug_code) { + CHECK_LE(size_of_regexp_code, 1 * MB); + } // Small regexp is half the size, but compiles to more than twice the code // due to the optimization steps. @@ -1773,6 +1841,271 @@ TEST(TestSizeOfObjects) { } +TEST(TestAlignmentCalculations) { + // Maximum fill amounts are consistent. + int maximum_double_misalignment = kDoubleSize - kPointerSize; + int maximum_simd128_misalignment = kSimd128Size - kPointerSize; + int max_word_fill = Heap::GetMaximumFillToAlign(kWordAligned); + CHECK_EQ(0, max_word_fill); + int max_double_fill = Heap::GetMaximumFillToAlign(kDoubleAligned); + CHECK_EQ(maximum_double_misalignment, max_double_fill); + int max_double_unaligned_fill = Heap::GetMaximumFillToAlign(kDoubleUnaligned); + CHECK_EQ(maximum_double_misalignment, max_double_unaligned_fill); + int max_simd128_unaligned_fill = + Heap::GetMaximumFillToAlign(kSimd128Unaligned); + CHECK_EQ(maximum_simd128_misalignment, max_simd128_unaligned_fill); + + Address base = reinterpret_cast<Address>(NULL); + int fill = 0; + + // Word alignment never requires fill. + fill = Heap::GetFillToAlign(base, kWordAligned); + CHECK_EQ(0, fill); + fill = Heap::GetFillToAlign(base + kPointerSize, kWordAligned); + CHECK_EQ(0, fill); + + // No fill is required when address is double aligned. + fill = Heap::GetFillToAlign(base, kDoubleAligned); + CHECK_EQ(0, fill); + // Fill is required if address is not double aligned. + fill = Heap::GetFillToAlign(base + kPointerSize, kDoubleAligned); + CHECK_EQ(maximum_double_misalignment, fill); + // kDoubleUnaligned has the opposite fill amounts. + fill = Heap::GetFillToAlign(base, kDoubleUnaligned); + CHECK_EQ(maximum_double_misalignment, fill); + fill = Heap::GetFillToAlign(base + kPointerSize, kDoubleUnaligned); + CHECK_EQ(0, fill); + + // 128 bit SIMD types have 2 or 4 possible alignments, depending on platform. + fill = Heap::GetFillToAlign(base, kSimd128Unaligned); + CHECK_EQ((3 * kPointerSize) & kSimd128AlignmentMask, fill); + fill = Heap::GetFillToAlign(base + kPointerSize, kSimd128Unaligned); + CHECK_EQ((2 * kPointerSize) & kSimd128AlignmentMask, fill); + fill = Heap::GetFillToAlign(base + 2 * kPointerSize, kSimd128Unaligned); + CHECK_EQ(kPointerSize, fill); + fill = Heap::GetFillToAlign(base + 3 * kPointerSize, kSimd128Unaligned); + CHECK_EQ(0, fill); +} + + +static HeapObject* NewSpaceAllocateAligned(int size, + AllocationAlignment alignment) { + Heap* heap = CcTest::heap(); + AllocationResult allocation = + heap->new_space()->AllocateRawAligned(size, alignment); + HeapObject* obj = NULL; + allocation.To(&obj); + heap->CreateFillerObjectAt(obj->address(), size); + return obj; +} + + +// Get new space allocation into the desired alignment. +static Address AlignNewSpace(AllocationAlignment alignment, int offset) { + Address* top_addr = CcTest::heap()->new_space()->allocation_top_address(); + int fill = Heap::GetFillToAlign(*top_addr, alignment); + if (fill) { + NewSpaceAllocateAligned(fill + offset, kWordAligned); + } + return *top_addr; +} + + +TEST(TestAlignedAllocation) { + // Double misalignment is 4 on 32-bit platforms, 0 on 64-bit ones. + const intptr_t double_misalignment = kDoubleSize - kPointerSize; + Address* top_addr = CcTest::heap()->new_space()->allocation_top_address(); + Address start; + HeapObject* obj; + HeapObject* filler; + if (double_misalignment) { + // Allocate a pointer sized object that must be double aligned at an + // aligned address. + start = AlignNewSpace(kDoubleAligned, 0); + obj = NewSpaceAllocateAligned(kPointerSize, kDoubleAligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment)); + // There is no filler. + CHECK_EQ(kPointerSize, *top_addr - start); + + // Allocate a second pointer sized object that must be double aligned at an + // unaligned address. + start = AlignNewSpace(kDoubleAligned, kPointerSize); + obj = NewSpaceAllocateAligned(kPointerSize, kDoubleAligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment)); + // There is a filler object before the object. + filler = HeapObject::FromAddress(start); + CHECK(obj != filler && filler->IsFiller() && + filler->Size() == kPointerSize); + CHECK_EQ(kPointerSize + double_misalignment, *top_addr - start); + + // Similarly for kDoubleUnaligned. + start = AlignNewSpace(kDoubleUnaligned, 0); + obj = NewSpaceAllocateAligned(kPointerSize, kDoubleUnaligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize)); + CHECK_EQ(kPointerSize, *top_addr - start); + start = AlignNewSpace(kDoubleUnaligned, kPointerSize); + obj = NewSpaceAllocateAligned(kPointerSize, kDoubleUnaligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize)); + // There is a filler object before the object. + filler = HeapObject::FromAddress(start); + CHECK(obj != filler && filler->IsFiller() && + filler->Size() == kPointerSize); + CHECK_EQ(kPointerSize + double_misalignment, *top_addr - start); + } + + // Now test SIMD alignment. There are 2 or 4 possible alignments, depending + // on platform. + start = AlignNewSpace(kSimd128Unaligned, 0); + obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is no filler. + CHECK_EQ(kPointerSize, *top_addr - start); + start = AlignNewSpace(kSimd128Unaligned, kPointerSize); + obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is a filler object before the object. + filler = HeapObject::FromAddress(start); + CHECK(obj != filler && filler->IsFiller() && + filler->Size() == kSimd128Size - kPointerSize); + CHECK_EQ(kPointerSize + kSimd128Size - kPointerSize, *top_addr - start); + + if (double_misalignment) { + // Test the 2 other alignments possible on 32 bit platforms. + start = AlignNewSpace(kSimd128Unaligned, 2 * kPointerSize); + obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is a filler object before the object. + filler = HeapObject::FromAddress(start); + CHECK(obj != filler && filler->IsFiller() && + filler->Size() == 2 * kPointerSize); + CHECK_EQ(kPointerSize + 2 * kPointerSize, *top_addr - start); + start = AlignNewSpace(kSimd128Unaligned, 3 * kPointerSize); + obj = NewSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is a filler object before the object. + filler = HeapObject::FromAddress(start); + CHECK(obj != filler && filler->IsFiller() && + filler->Size() == kPointerSize); + CHECK_EQ(kPointerSize + kPointerSize, *top_addr - start); + } +} + + +static HeapObject* OldSpaceAllocateAligned(int size, + AllocationAlignment alignment) { + Heap* heap = CcTest::heap(); + AllocationResult allocation = + heap->old_space()->AllocateRawAligned(size, alignment); + HeapObject* obj = NULL; + allocation.To(&obj); + heap->CreateFillerObjectAt(obj->address(), size); + return obj; +} + + +// Get old space allocation into the desired alignment. +static Address AlignOldSpace(AllocationAlignment alignment, int offset) { + Address* top_addr = CcTest::heap()->old_space()->allocation_top_address(); + int fill = Heap::GetFillToAlign(*top_addr, alignment); + int allocation = fill + offset; + if (allocation) { + OldSpaceAllocateAligned(allocation, kWordAligned); + } + Address top = *top_addr; + // Now force the remaining allocation onto the free list. + CcTest::heap()->old_space()->EmptyAllocationInfo(); + return top; +} + + +// Test the case where allocation must be done from the free list, so filler +// may precede or follow the object. +TEST(TestAlignedOverAllocation) { + // Double misalignment is 4 on 32-bit platforms, 0 on 64-bit ones. + const intptr_t double_misalignment = kDoubleSize - kPointerSize; + Address start; + HeapObject* obj; + HeapObject* filler1; + HeapObject* filler2; + if (double_misalignment) { + start = AlignOldSpace(kDoubleAligned, 0); + obj = OldSpaceAllocateAligned(kPointerSize, kDoubleAligned); + // The object is aligned, and a filler object is created after. + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment)); + filler1 = HeapObject::FromAddress(start + kPointerSize); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kPointerSize); + // Try the opposite alignment case. + start = AlignOldSpace(kDoubleAligned, kPointerSize); + obj = OldSpaceAllocateAligned(kPointerSize, kDoubleAligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment)); + filler1 = HeapObject::FromAddress(start); + CHECK(obj != filler1); + CHECK(filler1->IsFiller()); + CHECK(filler1->Size() == kPointerSize); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kPointerSize); + + // Similarly for kDoubleUnaligned. + start = AlignOldSpace(kDoubleUnaligned, 0); + obj = OldSpaceAllocateAligned(kPointerSize, kDoubleUnaligned); + // The object is aligned, and a filler object is created after. + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize)); + filler1 = HeapObject::FromAddress(start + kPointerSize); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kPointerSize); + // Try the opposite alignment case. + start = AlignOldSpace(kDoubleUnaligned, kPointerSize); + obj = OldSpaceAllocateAligned(kPointerSize, kDoubleUnaligned); + CHECK(IsAddressAligned(obj->address(), kDoubleAlignment, kPointerSize)); + filler1 = HeapObject::FromAddress(start); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kPointerSize); + } + + // Now test SIMD alignment. There are 2 or 4 possible alignments, depending + // on platform. + start = AlignOldSpace(kSimd128Unaligned, 0); + obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is a filler object after the object. + filler1 = HeapObject::FromAddress(start + kPointerSize); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kSimd128Size - kPointerSize); + start = AlignOldSpace(kSimd128Unaligned, kPointerSize); + obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There is a filler object before the object. + filler1 = HeapObject::FromAddress(start); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kSimd128Size - kPointerSize); + + if (double_misalignment) { + // Test the 2 other alignments possible on 32 bit platforms. + start = AlignOldSpace(kSimd128Unaligned, 2 * kPointerSize); + obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There are filler objects before and after the object. + filler1 = HeapObject::FromAddress(start); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == 2 * kPointerSize); + filler2 = HeapObject::FromAddress(start + 3 * kPointerSize); + CHECK(obj != filler2 && filler2->IsFiller() && + filler2->Size() == kPointerSize); + start = AlignOldSpace(kSimd128Unaligned, 3 * kPointerSize); + obj = OldSpaceAllocateAligned(kPointerSize, kSimd128Unaligned); + CHECK(IsAddressAligned(obj->address(), kSimd128Alignment, kPointerSize)); + // There are filler objects before and after the object. + filler1 = HeapObject::FromAddress(start); + CHECK(obj != filler1 && filler1->IsFiller() && + filler1->Size() == kPointerSize); + filler2 = HeapObject::FromAddress(start + 2 * kPointerSize); + CHECK(obj != filler2 && filler2->IsFiller() && + filler2->Size() == 2 * kPointerSize); + } +} + + TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { CcTest::InitializeVM(); HeapIterator iterator(CcTest::heap()); @@ -2118,7 +2451,7 @@ TEST(InstanceOfStubWriteBarrier) { IncrementalMarking* marking = CcTest::heap()->incremental_marking(); marking->Abort(); - marking->Start(); + marking->Start(Heap::kNoGCFlags); Handle<JSFunction> f = v8::Utils::OpenHandle( @@ -2191,7 +2524,8 @@ TEST(PrototypeTransitionClearing) { TransitionArray::GetPrototypeTransitions(baseObject->map()); for (int i = initialTransitions; i < initialTransitions + transitions; i++) { int j = TransitionArray::kProtoTransitionHeaderSize + i; - CHECK(trans->get(j)->IsMap()); + CHECK(trans->get(j)->IsWeakCell()); + CHECK(WeakCell::cast(trans->get(j))->value()->IsMap()); } // Make sure next prototype is placed on an old-space evacuation candidate. @@ -2200,7 +2534,8 @@ TEST(PrototypeTransitionClearing) { { AlwaysAllocateScope always_allocate(isolate); SimulateFullSpace(space); - prototype = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); + prototype = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, + Strength::WEAK, TENURED); } // Add a prototype on an evacuation candidate and verify that transition @@ -2244,7 +2579,7 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { IncrementalMarking* marking = CcTest::heap()->incremental_marking(); marking->Abort(); - marking->Start(); + marking->Start(Heap::kNoGCFlags); // The following calls will increment CcTest::heap()->global_ic_age(). CcTest::isolate()->ContextDisposedNotification(); SimulateIncrementalMarking(CcTest::heap()); @@ -2302,7 +2637,7 @@ TEST(IdleNotificationFinishMarking) { SimulateFullSpace(CcTest::heap()->old_space()); IncrementalMarking* marking = CcTest::heap()->incremental_marking(); marking->Abort(); - marking->Start(); + marking->Start(Heap::kNoGCFlags); CHECK_EQ(CcTest::heap()->gc_count(), 0); @@ -3071,7 +3406,6 @@ TEST(TransitionArraySimpleToFull) { TEST(Regress2143a) { - i::FLAG_collect_maps = true; i::FLAG_incremental_marking = true; CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); @@ -3111,7 +3445,6 @@ TEST(Regress2143a) { TEST(Regress2143b) { - i::FLAG_collect_maps = true; i::FLAG_incremental_marking = true; i::FLAG_allow_natives_syntax = true; CcTest::InitializeVM(); @@ -3203,6 +3536,31 @@ TEST(ReleaseOverReservedPages) { CHECK_EQ(1, old_space->CountTotalPages()); } +static int forced_gc_counter = 0; + +void MockUseCounterCallback(v8::Isolate* isolate, + v8::Isolate::UseCounterFeature feature) { + isolate->GetCallingContext(); + if (feature == v8::Isolate::kForcedGC) { + forced_gc_counter++; + } +} + + +TEST(CountForcedGC) { + i::FLAG_expose_gc = true; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + v8::HandleScope scope(CcTest::isolate()); + + isolate->SetUseCounterCallback(MockUseCounterCallback); + + forced_gc_counter = 0; + const char* source = "gc();"; + CompileRun(source); + CHECK_GT(forced_gc_counter, 0); +} + TEST(Regress2237) { i::FLAG_stress_compaction = false; @@ -3255,41 +3613,6 @@ TEST(PrintSharedFunctionInfo) { #endif // OBJECT_PRINT -TEST(Regress2211) { - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - - v8::Handle<v8::String> value = v8_str("val string"); - Smi* hash = Smi::FromInt(321); - Factory* factory = CcTest::i_isolate()->factory(); - - for (int i = 0; i < 2; i++) { - // Store identity hash first and common hidden property second. - v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate()); - Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj); - CHECK(internal_obj->HasFastProperties()); - - // In the first iteration, set hidden value first and identity hash second. - // In the second iteration, reverse the order. - if (i == 0) obj->SetHiddenValue(v8_str("key string"), value); - JSObject::SetIdentityHash(internal_obj, handle(hash, CcTest::i_isolate())); - if (i == 1) obj->SetHiddenValue(v8_str("key string"), value); - - // Check values. - CHECK_EQ(hash, - internal_obj->GetHiddenProperty(factory->identity_hash_string())); - CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string")))); - - // Check size. - FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0); - ObjectHashTable* hashtable = ObjectHashTable::cast( - internal_obj->RawFastPropertyAt(index)); - // HashTable header (5) and 4 initial entries (8). - CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize); - } -} - - TEST(IncrementalMarkingPreservesMonomorphicCallIC) { if (i::FLAG_always_opt) return; CcTest::InitializeVM(); @@ -3447,23 +3770,15 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) { CcTest::global()->Get(v8_str("f")))); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, MONOMORPHIC); - CHECK(ic_before->ic_state() == DEFAULT); - } else { - CHECK(ic_before->ic_state() == MONOMORPHIC); - } + CheckVectorIC(f, 0, MONOMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, MONOMORPHIC); - CHECK(ic_after->ic_state() == DEFAULT); - } else { - CHECK(ic_after->ic_state() == MONOMORPHIC); - } + CheckVectorIC(f, 0, MONOMORPHIC); + CHECK(ic_after->ic_state() == DEFAULT); } @@ -3487,12 +3802,8 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, MONOMORPHIC); - CHECK(ic_before->ic_state() == DEFAULT); - } else { - CHECK(ic_before->ic_state() == MONOMORPHIC); - } + CheckVectorIC(f, 0, MONOMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); // Fire context dispose notification. CcTest::isolate()->ContextDisposedNotification(); @@ -3500,12 +3811,8 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { CcTest::heap()->CollectAllGarbage(); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorICCleared(f, 0); - CHECK(ic_after->ic_state() == DEFAULT); - } else { - CHECK(IC::IsCleared(ic_after)); - } + CheckVectorICCleared(f, 0); + CHECK(ic_after->ic_state() == DEFAULT); } @@ -3536,24 +3843,16 @@ TEST(IncrementalMarkingPreservesPolymorphicIC) { *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, POLYMORPHIC); - CHECK(ic_before->ic_state() == DEFAULT); - } else { - CHECK(ic_before->ic_state() == POLYMORPHIC); - } + CheckVectorIC(f, 0, POLYMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); // Fire context dispose notification. SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, POLYMORPHIC); - CHECK(ic_after->ic_state() == DEFAULT); - } else { - CHECK(ic_after->ic_state() == POLYMORPHIC); - } + CheckVectorIC(f, 0, POLYMORPHIC); + CHECK(ic_after->ic_state() == DEFAULT); } @@ -3584,25 +3883,16 @@ TEST(IncrementalMarkingClearsPolymorphicIC) { *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorIC(f, 0, POLYMORPHIC); - CHECK(ic_before->ic_state() == DEFAULT); - } else { - CHECK(ic_before->ic_state() == POLYMORPHIC); - } + CheckVectorIC(f, 0, POLYMORPHIC); + CHECK(ic_before->ic_state() == DEFAULT); // Fire context dispose notification. CcTest::isolate()->ContextDisposedNotification(); SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(); - Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); - if (FLAG_vector_ics) { - CheckVectorICCleared(f, 0); - CHECK(ic_before->ic_state() == DEFAULT); - } else { - CHECK(IC::IsCleared(ic_after)); - } + CheckVectorICCleared(f, 0); + CHECK(ic_before->ic_state() == DEFAULT); } @@ -3718,7 +4008,6 @@ UNINITIALIZED_TEST(ReleaseStackTraceData) { TEST(Regress159140) { i::FLAG_allow_natives_syntax = true; - i::FLAG_flush_code_incrementally = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -3780,7 +4069,6 @@ TEST(Regress159140) { TEST(Regress165495) { i::FLAG_allow_natives_syntax = true; - i::FLAG_flush_code_incrementally = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -3828,7 +4116,6 @@ TEST(Regress165495) { TEST(Regress169209) { i::FLAG_stress_compaction = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_flush_code_incrementally = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -3944,9 +4231,8 @@ TEST(Regress169928) { JSArray::kSize + AllocationMemento::kSize + kPointerSize); - Handle<JSArray> array = factory->NewJSArrayWithElements(array_data, - FAST_SMI_ELEMENTS, - NOT_TENURED); + Handle<JSArray> array = + factory->NewJSArrayWithElements(array_data, FAST_SMI_ELEMENTS); CHECK_EQ(Smi::FromInt(2), array->length()); CHECK(array->HasFastSmiOrObjectElements()); @@ -3954,8 +4240,9 @@ TEST(Regress169928) { // We need filler the size of AllocationMemento object, plus an extra // fill pointer value. HeapObject* obj = NULL; - AllocationResult allocation = CcTest::heap()->new_space()->AllocateRaw( - AllocationMemento::kSize + kPointerSize); + AllocationResult allocation = + CcTest::heap()->new_space()->AllocateRawUnaligned( + AllocationMemento::kSize + kPointerSize); CHECK(allocation.To(&obj)); Address addr_obj = obj->address(); CcTest::heap()->CreateFillerObjectAt( @@ -3977,7 +4264,6 @@ TEST(Regress168801) { i::FLAG_always_compact = true; i::FLAG_cache_optimized_code = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_flush_code_incrementally = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -4034,7 +4320,6 @@ TEST(Regress173458) { i::FLAG_always_compact = true; i::FLAG_cache_optimized_code = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_flush_code_incrementally = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -4119,7 +4404,7 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) { "};" "f(10 * 1024 * 1024);"); IncrementalMarking* marking = CcTest::heap()->incremental_marking(); - if (marking->IsStopped()) marking->Start(); + if (marking->IsStopped()) marking->Start(Heap::kNoGCFlags); // This big step should be sufficient to mark the whole array. marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); DCHECK(marking->IsComplete() || @@ -4390,7 +4675,6 @@ static int GetCodeChainLength(Code* code) { TEST(NextCodeLinkIsWeak) { i::FLAG_always_opt = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_turbo_deoptimization = true; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); v8::internal::Heap* heap = CcTest::heap(); @@ -4705,9 +4989,8 @@ Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) { void CheckIC(Code* code, Code::Kind kind, SharedFunctionInfo* shared, int ic_slot, InlineCacheState state) { - if (FLAG_vector_ics && - (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC || - kind == Code::CALL_IC)) { + if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC || + kind == Code::CALL_IC) { TypeFeedbackVector* vector = shared->feedback_vector(); FeedbackVectorICSlot slot(ic_slot); if (kind == Code::LOAD_IC) { @@ -4849,7 +5132,7 @@ TEST(WeakCellsWithIncrementalMarking) { Handle<WeakCell> weak_cell = factory->NewWeakCell(value); CHECK(weak_cell->value()->IsFixedArray()); IncrementalMarking* marking = heap->incremental_marking(); - if (marking->IsStopped()) marking->Start(); + if (marking->IsStopped()) marking->Start(Heap::kNoGCFlags); marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD); heap->CollectGarbage(NEW_SPACE); CHECK(weak_cell->value()->IsFixedArray()); @@ -5117,7 +5400,7 @@ TEST(Regress388880) { // that would cause crash. IncrementalMarking* marking = CcTest::heap()->incremental_marking(); marking->Abort(); - marking->Start(); + marking->Start(Heap::kNoGCFlags); CHECK(marking->IsMarking()); // Now everything is set up for crashing in JSObject::MigrateFastToFast() @@ -5143,7 +5426,7 @@ TEST(Regress3631) { "}" "weak_map"); if (marking->IsStopped()) { - marking->Start(); + marking->Start(Heap::kNoGCFlags); } // Incrementally mark the backing store. Handle<JSObject> obj = @@ -5319,7 +5602,7 @@ static void TestRightTrimFixedTypedArray(i::ExternalArrayType type, Heap* heap = isolate->heap(); Handle<FixedTypedArrayBase> array = - factory->NewFixedTypedArray(initial_length, type); + factory->NewFixedTypedArray(initial_length, type, true); int old_size = array->size(); heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, elements_to_trim); @@ -5369,7 +5652,7 @@ TEST(WeakFixedArray) { Handle<HeapNumber> number = CcTest::i_isolate()->factory()->NewHeapNumber(1); Handle<WeakFixedArray> array = WeakFixedArray::Add(Handle<Object>(), number); array->Remove(number); - array->Compact(); + array->Compact<WeakFixedArray::NullCallback>(); WeakFixedArray::Add(array, number); } @@ -5379,7 +5662,7 @@ TEST(PreprocessStackTrace) { FLAG_gc_interval = -1; CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); CompileRun("throw new Error();"); CHECK(try_catch.HasCaught()); Isolate* isolate = CcTest::i_isolate(); @@ -5405,3 +5688,370 @@ TEST(PreprocessStackTrace) { CHECK(!element->IsCode()); } } + + +static bool utils_has_been_collected = false; + +static void UtilsHasBeenCollected( + const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { + utils_has_been_collected = true; + data.GetParameter()->Reset(); +} + + +TEST(BootstrappingExports) { + FLAG_expose_natives_as = "natives"; + CcTest::InitializeVM(); + v8::Isolate* isolate = CcTest::isolate(); + + if (Snapshot::HaveASnapshotToStartFrom(CcTest::i_isolate())) return; + + utils_has_been_collected = false; + + v8::Persistent<v8::Object> utils; + + { + v8::HandleScope scope(isolate); + v8::Handle<v8::Object> natives = + CcTest::global()->Get(v8_str("natives"))->ToObject(isolate); + utils.Reset(isolate, natives->Get(v8_str("utils"))->ToObject(isolate)); + natives->Delete(v8_str("utils")); + } + + utils.SetWeak(&utils, UtilsHasBeenCollected, + v8::WeakCallbackType::kParameter); + + CcTest::heap()->CollectAllAvailableGarbage("fire weak callbacks"); + + CHECK(utils_has_been_collected); +} + + +TEST(Regress1878) { + FLAG_allow_natives_syntax = true; + CcTest::InitializeVM(); + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Local<v8::Function> constructor = + v8::Utils::ToLocal(CcTest::i_isolate()->internal_array_function()); + CcTest::global()->Set(v8_str("InternalArray"), constructor); + + v8::TryCatch try_catch(isolate); + + CompileRun( + "var a = Array();" + "for (var i = 0; i < 1000; i++) {" + " var ai = new InternalArray(10000);" + " if (%HaveSameMap(ai, a)) throw Error();" + " if (!%HasFastObjectElements(ai)) throw Error();" + "}" + "for (var i = 0; i < 1000; i++) {" + " var ai = new InternalArray(10000);" + " if (%HaveSameMap(ai, a)) throw Error();" + " if (!%HasFastObjectElements(ai)) throw Error();" + "}"); + + CHECK(!try_catch.HasCaught()); +} + + +void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) { + CHECK(bytes >= FixedArray::kHeaderSize); + CHECK(bytes % kPointerSize == 0); + Factory* factory = isolate->factory(); + HandleScope scope(isolate); + AlwaysAllocateScope always_allocate(isolate); + int elements = + static_cast<int>((bytes - FixedArray::kHeaderSize) / kPointerSize); + Handle<FixedArray> array = factory->NewFixedArray( + elements, space == NEW_SPACE ? NOT_TENURED : TENURED); + CHECK((space == NEW_SPACE) == isolate->heap()->InNewSpace(*array)); + CHECK_EQ(bytes, static_cast<size_t>(array->Size())); +} + + +TEST(NewSpaceAllocationCounter) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + size_t counter1 = heap->NewSpaceAllocationCounter(); + heap->CollectGarbage(NEW_SPACE); + const size_t kSize = 1024; + AllocateInSpace(isolate, kSize, NEW_SPACE); + size_t counter2 = heap->NewSpaceAllocationCounter(); + CHECK_EQ(kSize, counter2 - counter1); + heap->CollectGarbage(NEW_SPACE); + size_t counter3 = heap->NewSpaceAllocationCounter(); + CHECK_EQ(0U, counter3 - counter2); + // Test counter overflow. + size_t max_counter = -1; + heap->set_new_space_allocation_counter(max_counter - 10 * kSize); + size_t start = heap->NewSpaceAllocationCounter(); + for (int i = 0; i < 20; i++) { + AllocateInSpace(isolate, kSize, NEW_SPACE); + size_t counter = heap->NewSpaceAllocationCounter(); + CHECK_EQ(kSize, counter - start); + start = counter; + } +} + + +TEST(OldSpaceAllocationCounter) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + size_t counter1 = heap->OldGenerationAllocationCounter(); + heap->CollectGarbage(NEW_SPACE); + heap->CollectGarbage(NEW_SPACE); + const size_t kSize = 1024; + AllocateInSpace(isolate, kSize, OLD_SPACE); + size_t counter2 = heap->OldGenerationAllocationCounter(); + // TODO(ulan): replace all CHECK_LE with CHECK_EQ after v8:4148 is fixed. + CHECK_LE(kSize, counter2 - counter1); + heap->CollectGarbage(NEW_SPACE); + size_t counter3 = heap->OldGenerationAllocationCounter(); + CHECK_EQ(0u, counter3 - counter2); + AllocateInSpace(isolate, kSize, OLD_SPACE); + heap->CollectGarbage(OLD_SPACE); + size_t counter4 = heap->OldGenerationAllocationCounter(); + CHECK_LE(kSize, counter4 - counter3); + // Test counter overflow. + size_t max_counter = -1; + heap->set_old_generation_allocation_counter(max_counter - 10 * kSize); + size_t start = heap->OldGenerationAllocationCounter(); + for (int i = 0; i < 20; i++) { + AllocateInSpace(isolate, kSize, OLD_SPACE); + size_t counter = heap->OldGenerationAllocationCounter(); + CHECK_LE(kSize, counter - start); + start = counter; + } +} + + +TEST(NewSpaceAllocationThroughput) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + GCTracer* tracer = heap->tracer(); + int time1 = 100; + size_t counter1 = 1000; + tracer->SampleAllocation(time1, counter1, 0); + int time2 = 200; + size_t counter2 = 2000; + tracer->SampleAllocation(time2, counter2, 0); + size_t throughput = + tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(); + CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput); + int time3 = 1000; + size_t counter3 = 30000; + tracer->SampleAllocation(time3, counter3, 0); + throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(); + CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput); +} + + +TEST(NewSpaceAllocationThroughput2) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + GCTracer* tracer = heap->tracer(); + int time1 = 100; + size_t counter1 = 1000; + tracer->SampleAllocation(time1, counter1, 0); + int time2 = 200; + size_t counter2 = 2000; + tracer->SampleAllocation(time2, counter2, 0); + size_t throughput = + tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput); + int time3 = 1000; + size_t counter3 = 30000; + tracer->SampleAllocation(time3, counter3, 0); + throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput); +} + + +static void CheckLeak(const v8::FunctionCallbackInfo<v8::Value>& args) { + Isolate* isolate = CcTest::i_isolate(); + Object* message = + *reinterpret_cast<Object**>(isolate->pending_message_obj_address()); + CHECK(message->IsTheHole()); +} + + +TEST(MessageObjectLeak) { + CcTest::InitializeVM(); + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); + global->Set(v8::String::NewFromUtf8(isolate, "check"), + v8::FunctionTemplate::New(isolate, CheckLeak)); + v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); + v8::Context::Scope cscope(context); + + const char* test = + "try {" + " throw 'message 1';" + "} catch (e) {" + "}" + "check();" + "L: try {" + " throw 'message 2';" + "} finally {" + " break L;" + "}" + "check();"; + CompileRun(test); + + const char* flag = "--turbo-filter=*"; + FlagList::SetFlagsFromString(flag, StrLength(flag)); + FLAG_always_opt = true; + FLAG_turbo_try_catch = true; + FLAG_turbo_try_finally = true; + + CompileRun(test); +} + + +static void CheckEqualSharedFunctionInfos( + const v8::FunctionCallbackInfo<v8::Value>& args) { + Handle<Object> obj1 = v8::Utils::OpenHandle(*args[0]); + Handle<Object> obj2 = v8::Utils::OpenHandle(*args[1]); + Handle<JSFunction> fun1 = Handle<JSFunction>::cast(obj1); + Handle<JSFunction> fun2 = Handle<JSFunction>::cast(obj2); + CHECK(fun1->shared() == fun2->shared()); +} + + +static void RemoveCodeAndGC(const v8::FunctionCallbackInfo<v8::Value>& args) { + Isolate* isolate = CcTest::i_isolate(); + Handle<Object> obj = v8::Utils::OpenHandle(*args[0]); + Handle<JSFunction> fun = Handle<JSFunction>::cast(obj); + fun->ReplaceCode(*isolate->builtins()->CompileLazy()); + fun->shared()->ReplaceCode(*isolate->builtins()->CompileLazy()); + isolate->heap()->CollectAllAvailableGarbage("remove code and gc"); +} + + +TEST(CanonicalSharedFunctionInfo) { + CcTest::InitializeVM(); + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); + global->Set(isolate, "check", v8::FunctionTemplate::New( + isolate, CheckEqualSharedFunctionInfos)); + global->Set(isolate, "remove", + v8::FunctionTemplate::New(isolate, RemoveCodeAndGC)); + v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); + v8::Context::Scope cscope(context); + CompileRun( + "function f() { return function g() {}; }" + "var g1 = f();" + "remove(f);" + "var g2 = f();" + "check(g1, g2);"); + + CompileRun( + "function f() { return (function() { return function g() {}; })(); }" + "var g1 = f();" + "remove(f);" + "var g2 = f();" + "check(g1, g2);"); +} + + +TEST(OldGenerationAllocationThroughput) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + GCTracer* tracer = heap->tracer(); + int time1 = 100; + size_t counter1 = 1000; + tracer->SampleAllocation(time1, 0, counter1); + int time2 = 200; + size_t counter2 = 2000; + tracer->SampleAllocation(time2, 0, counter2); + size_t throughput = + tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput); + int time3 = 1000; + size_t counter3 = 30000; + tracer->SampleAllocation(time3, 0, counter3); + throughput = + tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput); +} + + +TEST(AllocationThroughput) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + GCTracer* tracer = heap->tracer(); + int time1 = 100; + size_t counter1 = 1000; + tracer->SampleAllocation(time1, counter1, counter1); + int time2 = 200; + size_t counter2 = 2000; + tracer->SampleAllocation(time2, counter2, counter2); + size_t throughput = tracer->AllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ(2 * (counter2 - counter1) / (time2 - time1), throughput); + int time3 = 1000; + size_t counter3 = 30000; + tracer->SampleAllocation(time3, counter3, counter3); + throughput = tracer->AllocationThroughputInBytesPerMillisecond(100); + CHECK_EQ(2 * (counter3 - counter1) / (time3 - time1), throughput); +} + + +TEST(SlotsBufferObjectSlotsRemoval) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + + SlotsBuffer* buffer = new SlotsBuffer(NULL); + void* fake_object[1]; + + Handle<FixedArray> array = factory->NewFixedArray(2, TENURED); + CHECK(heap->old_space()->Contains(*array)); + array->set(0, reinterpret_cast<Object*>(fake_object), SKIP_WRITE_BARRIER); + + // Firstly, let's test the regular slots buffer entry. + buffer->Add(HeapObject::RawField(*array, FixedArray::kHeaderSize)); + DCHECK(reinterpret_cast<void*>(buffer->Get(0)) == + HeapObject::RawField(*array, FixedArray::kHeaderSize)); + SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer, + array->address(), + array->address() + array->Size()); + DCHECK(reinterpret_cast<void*>(buffer->Get(0)) == + HeapObject::RawField(heap->empty_fixed_array(), + FixedArrayBase::kLengthOffset)); + + // Secondly, let's test the typed slots buffer entry. + SlotsBuffer::AddTo(NULL, &buffer, SlotsBuffer::EMBEDDED_OBJECT_SLOT, + array->address() + FixedArray::kHeaderSize, + SlotsBuffer::FAIL_ON_OVERFLOW); + DCHECK(reinterpret_cast<void*>(buffer->Get(1)) == + reinterpret_cast<Object**>(SlotsBuffer::EMBEDDED_OBJECT_SLOT)); + DCHECK(reinterpret_cast<void*>(buffer->Get(2)) == + HeapObject::RawField(*array, FixedArray::kHeaderSize)); + SlotsBuffer::RemoveObjectSlots(CcTest::i_isolate()->heap(), buffer, + array->address(), + array->address() + array->Size()); + DCHECK(reinterpret_cast<void*>(buffer->Get(1)) == + HeapObject::RawField(heap->empty_fixed_array(), + FixedArrayBase::kLengthOffset)); + DCHECK(reinterpret_cast<void*>(buffer->Get(2)) == + HeapObject::RawField(heap->empty_fixed_array(), + FixedArrayBase::kLengthOffset)); + delete buffer; +} diff --git a/deps/v8/test/cctest/test-hydrogen-types.cc b/deps/v8/test/cctest/test-hydrogen-types.cc index 0ac53bde09..93fdf7b32d 100644 --- a/deps/v8/test/cctest/test-hydrogen-types.cc +++ b/deps/v8/test/cctest/test-hydrogen-types.cc @@ -8,7 +8,6 @@ using namespace v8::internal; - static const HType kTypes[] = { #define DECLARE_TYPE(Name, mask) HType::Name(), HTYPE_LIST(DECLARE_TYPE) diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 90245b7882..0938a9ede2 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -482,7 +482,7 @@ TEST(EquivalenceOfLoggingAndTraversal) { i::Vector<const char> source = TestSources::GetScriptsSource(); v8::Handle<v8::String> source_str = v8::String::NewFromUtf8( isolate, source.start(), v8::String::kNormalString, source.length()); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); v8::Handle<v8::Script> script = CompileWithOrigin(source_str, ""); if (script.IsEmpty()) { v8::String::Utf8Value exception(try_catch.Exception()); diff --git a/deps/v8/test/cctest/test-microtask-delivery.cc b/deps/v8/test/cctest/test-microtask-delivery.cc index 601290cf3a..5befdfba9f 100644 --- a/deps/v8/test/cctest/test-microtask-delivery.cc +++ b/deps/v8/test/cctest/test-microtask-delivery.cc @@ -29,7 +29,6 @@ #include "test/cctest/cctest.h" -using namespace v8; namespace i = v8::internal; namespace { @@ -38,7 +37,7 @@ class HarmonyIsolate { HarmonyIsolate() { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - isolate_ = Isolate::New(create_params); + isolate_ = v8::Isolate::New(create_params); isolate_->Enter(); } @@ -47,17 +46,17 @@ class HarmonyIsolate { isolate_->Dispose(); } - Isolate* GetIsolate() const { return isolate_; } + v8::Isolate* GetIsolate() const { return isolate_; } private: - Isolate* isolate_; + v8::Isolate* isolate_; }; } TEST(MicrotaskDeliverySimple) { HarmonyIsolate isolate; - HandleScope scope(isolate.GetIsolate()); + v8::HandleScope scope(isolate.GetIsolate()); LocalContext context(isolate.GetIsolate()); CompileRun( "var ordering = [];" @@ -95,16 +94,16 @@ TEST(MicrotaskDeliverySimple) { TEST(MicrotaskPerIsolateState) { HarmonyIsolate isolate; - HandleScope scope(isolate.GetIsolate()); + v8::HandleScope scope(isolate.GetIsolate()); LocalContext context1(isolate.GetIsolate()); isolate.GetIsolate()->SetAutorunMicrotasks(false); CompileRun( "var obj = { calls: 0 };"); - Handle<Value> obj = CompileRun("obj"); + v8::Handle<v8::Value> obj = CompileRun("obj"); { LocalContext context2(isolate.GetIsolate()); - context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"), - obj); + context2->Global()->Set( + v8::String::NewFromUtf8(isolate.GetIsolate(), "obj"), obj); CompileRun( "var resolver = {};" "new Promise(function(resolve) {" @@ -118,8 +117,8 @@ TEST(MicrotaskPerIsolateState) { } { LocalContext context3(isolate.GetIsolate()); - context3->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"), - obj); + context3->Global()->Set( + v8::String::NewFromUtf8(isolate.GetIsolate(), "obj"), obj); CompileRun( "var foo = { id: 1 };" "Object.observe(foo, function() {" @@ -129,8 +128,8 @@ TEST(MicrotaskPerIsolateState) { } { LocalContext context4(isolate.GetIsolate()); - context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"), - obj); + context4->Global()->Set( + v8::String::NewFromUtf8(isolate.GetIsolate(), "obj"), obj); isolate.GetIsolate()->RunMicrotasks(); CHECK_EQ(2, CompileRun("obj.calls")->Int32Value()); } diff --git a/deps/v8/test/cctest/test-migrations.cc b/deps/v8/test/cctest/test-migrations.cc index 14bdcea3c6..0cefd54ceb 100644 --- a/deps/v8/test/cctest/test-migrations.cc +++ b/deps/v8/test/cctest/test-migrations.cc @@ -503,8 +503,7 @@ TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) { CHECK(obj->map()->instance_descriptors()->GetValue(0)->IsAccessorPair()); Handle<Object> value(Smi::FromInt(42), isolate); - JSObject::SetOwnPropertyIgnoreAttributes( - obj, foo_str, value, NONE, JSObject::DONT_FORCE_FIELD).ToHandleChecked(); + JSObject::SetOwnPropertyIgnoreAttributes(obj, foo_str, value, NONE).Check(); // Check that the property contains |value|. CHECK_EQ(1, obj->map()->NumberOfOwnDescriptors()); diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc index 58a5955685..cbb79b16da 100644 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -73,7 +73,6 @@ TEST(ScanKeywords) { i::Scanner scanner(&unicode_cache); // The scanner should parse Harmony keywords for this test. scanner.SetHarmonyModules(true); - scanner.SetHarmonyClasses(true); scanner.Initialize(&stream); CHECK_EQ(key_token.token, scanner.Next()); CHECK_EQ(i::Token::EOS, scanner.Next()); @@ -277,7 +276,7 @@ TEST(PreparseFunctionDataIsUsed) { for (unsigned i = 0; i < arraysize(good_code); i++) { v8::ScriptCompiler::Source good_source(v8_str(good_code[i])); v8::ScriptCompiler::Compile(isolate, &good_source, - v8::ScriptCompiler::kProduceDataToCache); + v8::ScriptCompiler::kProduceParserCache); const v8::ScriptCompiler::CachedData* cached_data = good_source.GetCachedData(); @@ -291,7 +290,9 @@ TEST(PreparseFunctionDataIsUsed) { v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData( cached_data->data, cached_data->length)); v8::Local<v8::Value> result = - v8::ScriptCompiler::Compile(isolate, &bad_source)->Run(); + v8::ScriptCompiler::Compile(isolate, &bad_source, + v8::ScriptCompiler::kConsumeParserCache) + ->Run(); CHECK(result->IsInt32()); CHECK_EQ(25, result->Int32Value()); } @@ -976,10 +977,10 @@ TEST(ScopeUsesArgumentsSuperThis) { SUPER_PROPERTY = 1 << 1, THIS = 1 << 2, INNER_ARGUMENTS = 1 << 3, - INNER_SUPER_PROPERTY = 1 << 4, - INNER_THIS = 1 << 5 + EVAL = 1 << 4 }; + // clang-format off static const struct { const char* body; int expected; @@ -992,8 +993,8 @@ TEST(ScopeUsesArgumentsSuperThis) { {"return this + arguments[0]", ARGUMENTS | THIS}, {"return this + arguments[0] + super.x", ARGUMENTS | SUPER_PROPERTY | THIS}, - {"return x => this + x", INNER_THIS}, - {"return x => super.f() + x", INNER_SUPER_PROPERTY}, + {"return x => this + x", THIS}, + {"return x => super.f() + x", SUPER_PROPERTY}, {"this.foo = 42;", THIS}, {"this.foo();", THIS}, {"if (foo()) { this.f() }", THIS}, @@ -1006,9 +1007,7 @@ TEST(ScopeUsesArgumentsSuperThis) { {"while (true) { while (true) { while (true) return this } }", THIS}, {"while (true) { while (true) { while (true) return super.f() } }", SUPER_PROPERTY}, - {"if (1) { return () => { while (true) new this() } }", INNER_THIS}, - // Note that propagation of the inner_uses_this() value does not - // cross boundaries of normal functions onto parent scopes. + {"if (1) { return () => { while (true) new this() } }", THIS}, {"return function (x) { return this + x }", NONE}, {"return { m(x) { return super.m() + x } }", NONE}, {"var x = function () { this.foo = 42 };", NONE}, @@ -1019,17 +1018,22 @@ TEST(ScopeUsesArgumentsSuperThis) { {"return { m(x) { return () => super.m() } }", NONE}, // Flags must be correctly set when using block scoping. {"\"use strict\"; while (true) { let x; this, arguments; }", - INNER_ARGUMENTS | INNER_THIS}, + INNER_ARGUMENTS | THIS}, {"\"use strict\"; while (true) { let x; this, super.f(), arguments; }", - INNER_ARGUMENTS | INNER_SUPER_PROPERTY | INNER_THIS}, - {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS}, - {"\"use strict\"; if (foo()) { let x; super.f() }", - INNER_SUPER_PROPERTY}, + INNER_ARGUMENTS | SUPER_PROPERTY | THIS}, + {"\"use strict\"; if (foo()) { let x; this.f() }", THIS}, + {"\"use strict\"; if (foo()) { let x; super.f() }", SUPER_PROPERTY}, {"\"use strict\"; if (1) {" " let x; return { m() { return this + super.m() + arguments } }" "}", NONE}, + {"eval(42)", EVAL}, + {"if (1) { eval(42) }", EVAL}, + {"eval('super.x')", EVAL}, + {"eval('this.x')", EVAL}, + {"eval('arguments')", EVAL}, }; + // clang-format on i::Isolate* isolate = CcTest::i_isolate(); i::Factory* factory = isolate->factory(); @@ -1045,7 +1049,6 @@ TEST(ScopeUsesArgumentsSuperThis) { for (unsigned i = 0; i < arraysize(source_data); ++i) { // Super property is only allowed in constructor and method. if (((source_data[i].expected & SUPER_PROPERTY) || - (source_data[i].expected & INNER_SUPER_PROPERTY) || (source_data[i].expected == NONE)) && j != 2) { continue; } @@ -1063,8 +1066,6 @@ TEST(ScopeUsesArgumentsSuperThis) { i::ParseInfo info(&zone, script); i::Parser parser(&info); parser.set_allow_harmony_arrow_functions(true); - parser.set_allow_harmony_classes(true); - parser.set_allow_harmony_object_literals(true); parser.set_allow_harmony_sloppy(true); info.set_global(); CHECK(parser.Parse(&info)); @@ -1086,18 +1087,71 @@ TEST(ScopeUsesArgumentsSuperThis) { scope->uses_arguments()); CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0, scope->uses_super_property()); - CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this()); + if ((source_data[i].expected & THIS) != 0) { + // Currently the is_used() flag is conservative; all variables in a + // script scope are marked as used. + CHECK(scope->LookupThis()->is_used()); + } CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0, scope->inner_uses_arguments()); - CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0, - scope->inner_uses_super_property()); - CHECK_EQ((source_data[i].expected & INNER_THIS) != 0, - scope->inner_uses_this()); + CHECK_EQ((source_data[i].expected & EVAL) != 0, scope->calls_eval()); } } } +static void CheckParsesToNumber(const char* source, bool with_dot) { + v8::V8::Initialize(); + HandleAndZoneScope handles; + + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + + std::string full_source = "function f() { return "; + full_source += source; + full_source += "; }"; + + i::Handle<i::String> source_code = + factory->NewStringFromUtf8(i::CStrVector(full_source.c_str())) + .ToHandleChecked(); + + i::Handle<i::Script> script = factory->NewScript(source_code); + + i::ParseInfo info(handles.main_zone(), script); + i::Parser parser(&info); + parser.set_allow_harmony_arrow_functions(true); + parser.set_allow_harmony_sloppy(true); + info.set_global(); + info.set_lazy(false); + info.set_allow_lazy_parsing(false); + info.set_toplevel(true); + + i::CompilationInfo compilation_info(&info); + CHECK(i::Compiler::ParseAndAnalyze(&info)); + + CHECK(info.scope()->declarations()->length() == 1); + i::FunctionLiteral* fun = + info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(); + CHECK(fun->body()->length() == 1); + CHECK(fun->body()->at(0)->IsReturnStatement()); + i::ReturnStatement* ret = fun->body()->at(0)->AsReturnStatement(); + CHECK(ret->expression()->IsLiteral()); + i::Literal* lit = ret->expression()->AsLiteral(); + const i::AstValue* val = lit->raw_value(); + CHECK(with_dot == val->ContainsDot()); +} + + +TEST(ParseNumbers) { + CheckParsesToNumber("1.34", true); + CheckParsesToNumber("134", false); + CheckParsesToNumber("134e44", false); + CheckParsesToNumber("134.e44", true); + CheckParsesToNumber("134.44e44", true); + CheckParsesToNumber(".44", true); +} + + TEST(ScopePositions) { // Test the parser for correctly setting the start and end positions // of a scope. We check the scope positions of exactly one scope @@ -1348,40 +1402,24 @@ const char* ReadString(unsigned* start) { i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) { i::Isolate* isolate = CcTest::i_isolate(); - i::Factory* factory = isolate->factory(); - const char* message = - ReadString(&data[i::PreparseDataConstants::kMessageTextPos]); - i::Handle<i::String> format = v8::Utils::OpenHandle( - *v8::String::NewFromUtf8(CcTest::isolate(), message)); + int message = data[i::PreparseDataConstants::kMessageTemplatePos]; int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos]; - const char* arg = NULL; - i::Handle<i::JSArray> args_array; + i::Handle<i::Object> arg_object; if (arg_count == 1) { // Position after text found by skipping past length field and // length field content words. - int pos = i::PreparseDataConstants::kMessageTextPos + 1 + - data[i::PreparseDataConstants::kMessageTextPos]; - arg = ReadString(&data[pos]); - args_array = factory->NewJSArray(1); - i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)), - NONE, i::SLOPPY).Check(); + const char* arg = + ReadString(&data[i::PreparseDataConstants::kMessageArgPos]); + arg_object = + v8::Utils::OpenHandle(*v8::String::NewFromUtf8(CcTest::isolate(), arg)); + i::DeleteArray(arg); } else { CHECK_EQ(0, arg_count); - args_array = factory->NewJSArray(0); + arg_object = isolate->factory()->undefined_value(); } - i::Handle<i::JSObject> builtins(isolate->js_builtins_object()); - i::Handle<i::Object> format_fun = - i::Object::GetProperty(isolate, builtins, "$formatMessage") - .ToHandleChecked(); - i::Handle<i::Object> arg_handles[] = { format, args_array }; - i::Handle<i::Object> result = i::Execution::Call( - isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked(); - CHECK(result->IsString()); - i::DeleteArray(message); - i::DeleteArray(arg); data.Dispose(); - return i::Handle<i::String>::cast(result); + return i::MessageTemplate::FormatMessage(isolate, message, arg_object); } @@ -1390,15 +1428,16 @@ enum ParserFlag { kAllowNatives, kAllowHarmonyModules, kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonyRestParameters, kAllowHarmonySloppy, kAllowHarmonyUnicode, kAllowHarmonyComputedPropertyNames, kAllowHarmonySpreadCalls, kAllowHarmonyDestructuring, - kAllowStrongMode + kAllowHarmonySpreadArrays, + kAllowHarmonyNewTarget, + kAllowStrongMode, + kNoLegacyConst }; @@ -1414,11 +1453,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser, parser->set_allow_lazy(flags.Contains(kAllowLazy)); parser->set_allow_natives(flags.Contains(kAllowNatives)); parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules)); - parser->set_allow_harmony_object_literals( - flags.Contains(kAllowHarmonyObjectLiterals)); parser->set_allow_harmony_arrow_functions( flags.Contains(kAllowHarmonyArrowFunctions)); - parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses)); parser->set_allow_harmony_rest_params( flags.Contains(kAllowHarmonyRestParameters)); parser->set_allow_harmony_spreadcalls( @@ -1429,7 +1465,11 @@ void SetParserFlags(i::ParserBase<Traits>* parser, flags.Contains(kAllowHarmonyComputedPropertyNames)); parser->set_allow_harmony_destructuring( flags.Contains(kAllowHarmonyDestructuring)); + parser->set_allow_harmony_spread_arrays( + flags.Contains(kAllowHarmonySpreadArrays)); + parser->set_allow_harmony_new_target(flags.Contains(kAllowHarmonyNewTarget)); parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode)); + parser->set_allow_legacy_const(!flags.Contains(kNoLegacyConst)); } @@ -1702,7 +1742,7 @@ TEST(StrictOctal) { v8::HandleScope scope(CcTest::isolate()); v8::Context::Scope context_scope( v8::Context::New(CcTest::isolate())); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); const char* script = "\"use strict\"; \n" "a = function() { \n" @@ -1982,8 +2022,7 @@ TEST(NoErrorsFutureStrictReservedWords) { RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); - static const ParserFlag classes_flags[] = {kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses}; + static const ParserFlag classes_flags[] = {kAllowHarmonyArrowFunctions}; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, classes_flags, arraysize(classes_flags)); } @@ -2996,10 +3035,7 @@ TEST(NoErrorsDeclsInCase) { nullptr }; - static const ParserFlag always_flags[] = {kAllowHarmonyClasses}; - - RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, statement_data, kSuccess); } @@ -3579,6 +3615,10 @@ TEST(ErrorsArrowFunctions) { "(foo ? bar : baz) => {}", "(a, foo ? bar : baz) => {}", "(foo ? bar : baz, a) => {}", + "(a.b, c) => {}", + "(c, a.b) => {}", + "(a['b'], c) => {}", + "(c, a['b']) => {}", NULL }; @@ -3727,8 +3767,6 @@ TEST(SuperNoErrors) { static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, @@ -3759,11 +3797,7 @@ TEST(SuperErrors) { NULL }; - static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, - kAllowHarmonySloppy - }; + static const ParserFlag always_flags[] = {kAllowHarmonySloppy}; RunParserSyncTest(context_data, expression_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } @@ -3779,12 +3813,8 @@ TEST(SuperCall) { NULL }; - static const ParserFlag always_flags[] = { - kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, - kAllowHarmonySloppy - }; + static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions, + kAllowHarmonySloppy}; RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); @@ -3834,12 +3864,8 @@ TEST(SuperNewNoErrors) { NULL }; - static const ParserFlag always_flags[] = { - kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, - kAllowHarmonySloppy - }; + static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions, + kAllowHarmonySloppy}; RunParserSyncTest(context_data, expression_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -3872,12 +3898,8 @@ TEST(SuperNewErrors) { NULL }; - static const ParserFlag always_flags[] = { - kAllowHarmonyArrowFunctions, - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, - kAllowHarmonySloppy - }; + static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions, + kAllowHarmonySloppy}; RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } @@ -3918,8 +3940,6 @@ TEST(SuperErrorsNonMethods) { }; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, statement_data, kError, NULL, 0, @@ -3943,9 +3963,7 @@ TEST(NoErrorsMethodDefinition) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, object_literal_body_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, object_literal_body_data, kSuccess); } @@ -4019,9 +4037,7 @@ TEST(MethodDefinitionNames) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, name_data, kSuccess); } @@ -4040,9 +4056,7 @@ TEST(MethodDefinitionStrictFormalParamereters) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, params_data, kError, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, params_data, kError); } @@ -4061,15 +4075,11 @@ TEST(MethodDefinitionEvalArguments) { "arguments", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - // Fail in strict mode - RunParserSyncTest(strict_context_data, data, kError, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(strict_context_data, data, kError); // OK in sloppy mode - RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(sloppy_context_data, data, kSuccess); } @@ -4088,12 +4098,9 @@ TEST(MethodDefinitionDuplicateEvalArguments) { "arguments, a, arguments", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - // In strict mode, the error is using "eval" or "arguments" as parameter names // In sloppy mode, the error is that eval / arguments are duplicated - RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError); } @@ -4127,9 +4134,7 @@ TEST(MethodDefinitionDuplicateProperty) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, params_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, params_data, kSuccess); } @@ -4151,8 +4156,7 @@ TEST(ClassExpressionNoErrors) { "class name extends class base {} {}", NULL}; - static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonySloppy}; + static const ParserFlag always_flags[] = {kAllowHarmonySloppy}; RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -4171,9 +4175,7 @@ TEST(ClassDeclarationNoErrors) { "class name extends class base {} {}", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyClasses}; - RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, statement_data, kSuccess); } @@ -4215,8 +4217,6 @@ TEST(ClassBodyNoErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, @@ -4274,8 +4274,6 @@ TEST(ClassPropertyNameNoErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, @@ -4306,8 +4304,6 @@ TEST(ClassExpressionErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_data, kError, NULL, 0, @@ -4344,7 +4340,6 @@ TEST(ClassDeclarationErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_data, kError, NULL, 0, @@ -4374,8 +4369,6 @@ TEST(ClassNameErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_name, kError, NULL, 0, @@ -4408,8 +4401,6 @@ TEST(ClassGetterParamNameErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_name, kError, NULL, 0, @@ -4437,8 +4428,6 @@ TEST(ClassStaticPrototypeErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, @@ -4465,8 +4454,6 @@ TEST(ClassSpecialConstructorErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, @@ -4488,8 +4475,6 @@ TEST(ClassConstructorNoErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, @@ -4507,8 +4492,6 @@ TEST(ClassMultipleConstructorErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, @@ -4530,8 +4513,6 @@ TEST(ClassMultiplePropertyNamesNoErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0, @@ -4551,8 +4532,6 @@ TEST(ClassesAreStrictErrors) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy }; RunParserSyncTest(context_data, class_body_data, kError, NULL, 0, @@ -4605,9 +4584,7 @@ TEST(ObjectLiteralPropertyShorthandKeywordsError) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, name_data, kError, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, name_data, kError); } @@ -4628,14 +4605,11 @@ TEST(ObjectLiteralPropertyShorthandStrictKeywords) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, name_data, kSuccess); const char* context_strict_data[][2] = {{"'use strict'; ({", "});"}, {NULL, NULL}}; - RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_strict_data, name_data, kError); } @@ -4657,9 +4631,7 @@ TEST(ObjectLiteralPropertyShorthandError) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, name_data, kError, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, name_data, kError); } @@ -4672,9 +4644,7 @@ TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals}; - RunParserSyncTest(context_data, name_data, kError, NULL, 0, - always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, name_data, kError); } @@ -5136,6 +5106,24 @@ TEST(ParseRestParametersErrors) { } +TEST(RestParameterInSetterMethodError) { + const char* context_data[][2] = { + {"'use strict';({ set prop(", ") {} }).prop = 1;"}, + {"'use strict';(class { static set prop(", ") {} }).prop = 1;"}, + {"'use strict';(new (class { set prop(", ") {} })).prop = 1;"}, + {"({ set prop(", ") {} }).prop = 1;"}, + {"(class { static set prop(", ") {} }).prop = 1;"}, + {"(new (class { set prop(", ") {} })).prop = 1;"}, + {nullptr, nullptr}}; + const char* data[] = {"...a", "...arguments", "...eval", nullptr}; + + static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters, + kAllowHarmonySloppy}; + RunParserSyncTest(context_data, data, kError, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + TEST(RestParametersEvalArguments) { const char* strict_context_data[][2] = {{"'use strict';(function(", @@ -5253,18 +5241,15 @@ TEST(LexicalScopingSloppyMode) { "(class C {})", "(class C extends D {})", NULL}; - static const ParserFlag always_true_flags[] = {kAllowHarmonyClasses}; static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy}; - RunParserSyncTest(context_data, bad_data, kError, NULL, 0, - always_true_flags, arraysize(always_true_flags), + RunParserSyncTest(context_data, bad_data, kError, NULL, 0, NULL, 0, always_false_flags, arraysize(always_false_flags)); const char* good_data[] = { "let = 1;", "for(let = 1;;){}", NULL}; - RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0, - always_true_flags, arraysize(always_true_flags), + RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0, NULL, 0, always_false_flags, arraysize(always_false_flags)); } @@ -5286,9 +5271,7 @@ TEST(ComputedPropertyName) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyComputedPropertyNames, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy, }; RunParserSyncTest(context_data, error_data, kError, NULL, 0, @@ -5317,9 +5300,7 @@ TEST(ComputedPropertyNameShorthandError) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyComputedPropertyNames, - kAllowHarmonyObjectLiterals, kAllowHarmonySloppy, }; RunParserSyncTest(context_data, error_data, kError, NULL, 0, @@ -5387,7 +5368,6 @@ TEST(BasicImportExportParsing) { i::Zone zone; i::ParseInfo info(&zone, script); i::Parser parser(&info); - parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); info.set_module(); if (!parser.Parse(&info)) { @@ -5414,7 +5394,6 @@ TEST(BasicImportExportParsing) { i::Zone zone; i::ParseInfo info(&zone, script); i::Parser parser(&info); - parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); info.set_global(); CHECK(!parser.Parse(&info)); @@ -5504,7 +5483,6 @@ TEST(ImportExportParsingErrors) { i::Zone zone; i::ParseInfo info(&zone, script); i::Parser parser(&info); - parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); info.set_module(); CHECK(!parser.Parse(&info)); @@ -5617,7 +5595,6 @@ TEST(DuplicateProtoNoError) { static const ParserFlag always_flags[] = { kAllowHarmonyComputedPropertyNames, - kAllowHarmonyObjectLiterals, }; RunParserSyncTest(context_data, error_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); @@ -5645,8 +5622,7 @@ TEST(DeclarationsError) { "class C {}", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyClasses, - kAllowStrongMode}; + static const ParserFlag always_flags[] = {kAllowStrongMode}; RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } @@ -5730,8 +5706,7 @@ TEST(PropertyNameEvalArguments) { NULL}; - static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowStrongMode}; + static const ParserFlag always_flags[] = {kAllowStrongMode}; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -5915,10 +5890,8 @@ TEST(StrongConstructorThis) { "class C { constructor() { label: 0; this.a = 0; this.b = 6; } }", NULL}; - static const ParserFlag always_flags[] = { - kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, - kAllowHarmonyArrowFunctions - }; + static const ParserFlag always_flags[] = {kAllowStrongMode, + kAllowHarmonyArrowFunctions}; RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0, @@ -5971,10 +5944,8 @@ TEST(StrongConstructorSuper) { "class C extends Object { constructor() { 3; super(3); this.x = 0; } }", NULL}; - static const ParserFlag always_flags[] = { - kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, - kAllowHarmonyArrowFunctions - }; + static const ParserFlag always_flags[] = {kAllowStrongMode, + kAllowHarmonyArrowFunctions}; RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0, @@ -6019,9 +5990,7 @@ TEST(StrongConstructorReturns) { "class C extends Array { constructor() { super(); this.a = 9; return } }", NULL}; - static const ParserFlag always_flags[] = { - kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals - }; + static const ParserFlag always_flags[] = {kAllowStrongMode}; RunParserSyncTest(sloppy_context_data, error_data, kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_context_data, error_data, kSuccess, NULL, 0, @@ -6219,7 +6188,7 @@ TEST(StrongModeFreeVariablesDeclaredByPreviousScript) { v8::V8::Initialize(); v8::HandleScope scope(CcTest::isolate()); v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); // Introduce a bunch of variables, in all language modes. const char* script1 = @@ -6278,7 +6247,7 @@ TEST(StrongModeFreeVariablesDeclaredByLanguage) { v8::V8::Initialize(); v8::HandleScope scope(CcTest::isolate()); v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); const char* script1 = "\"use strong\"; \n" @@ -6294,7 +6263,7 @@ TEST(StrongModeFreeVariablesDeclaredInGlobalPrototype) { v8::V8::Initialize(); v8::HandleScope scope(CcTest::isolate()); v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); const char* script1 = "this.__proto__.my_var = 0;\n"; CompileRun(v8_str(script1)); @@ -6313,7 +6282,7 @@ TEST(StrongModeFreeVariablesNotDeclared) { v8::V8::Initialize(); v8::HandleScope scope(CcTest::isolate()); v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); - v8::TryCatch try_catch; + v8::TryCatch try_catch(CcTest::isolate()); // Test that referencing unintroduced variables in sloppy mode is ok. const char* script1 = @@ -6330,7 +6299,7 @@ TEST(StrongModeFreeVariablesNotDeclared) { "if (false) { \n" " not_there2; \n" "} \n"; - v8::TryCatch try_catch2; + v8::TryCatch try_catch2(CcTest::isolate()); v8::Script::Compile(v8_str(script2)); CHECK(try_catch2.HasCaught()); v8::String::Utf8Value exception(try_catch2.Exception()); @@ -6351,7 +6320,7 @@ TEST(StrongModeFreeVariablesNotDeclared) { " not_there3; \n" " } \n" "})(); \n"; - v8::TryCatch try_catch2; + v8::TryCatch try_catch2(CcTest::isolate()); v8::Script::Compile(v8_str(script3)); CHECK(try_catch2.HasCaught()); v8::String::Utf8Value exception(try_catch2.Exception()); @@ -6366,30 +6335,59 @@ TEST(StrongModeFreeVariablesNotDeclared) { TEST(DestructuringPositiveTests) { i::FLAG_harmony_destructuring = true; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_computed_property_names = true; const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, {"var ", " = {};"}, {"'use strict'; const ", " = {};"}, + {"function f(", ") {}"}, + {"function f(argument1, ", ") {}"}, + {"var f = (", ") => {};"}, + {"var f = (argument1,", ") => {};"}, {NULL, NULL}}; // clang-format off const char* data[] = { "a", "{ x : y }", + "{ x : y = 1 }", "[a]", + "[a = 1]", "[a,b,c]", + "[a, b = 42, c]", "{ x : x, y : y }", + "{ x : x = 1, y : y }", + "{ x : x, y : y = 42 }", "[]", "{}", "[{x:x, y:y}, [a,b,c]]", + "[{x:x = 1, y:y = 2}, [a = 3, b = 4, c = 5]]", + "{x}", + "{x, y}", + "{x = 42, y = 15}", "[a,,b]", "{42 : x}", + "{42 : x = 42}", "{42e-2 : x}", + "{42e-2 : x = 42}", + "{x : y, x : z}", "{'hi' : x}", + "{'hi' : x = 42}", "{var: x}", + "{var: x = 42}", + "{[x] : z}", + "{[1+1] : z}", + "{[foo()] : z}", + "{}", + "[...rest]", + "[a,b,...rest]", + "[a,,...rest]", NULL}; // clang-format on - static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; + static const ParserFlag always_flags[] = {kAllowHarmonyComputedPropertyNames, + kAllowHarmonyArrowFunctions, + kAllowHarmonyDestructuring}; RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -6397,12 +6395,21 @@ TEST(DestructuringPositiveTests) { TEST(DestructuringNegativeTests) { i::FLAG_harmony_destructuring = true; - static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_computed_property_names = true; + static const ParserFlag always_flags[] = {kAllowHarmonyComputedPropertyNames, + kAllowHarmonyArrowFunctions, + kAllowHarmonyDestructuring}; { // All modes. const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, {"var ", " = {};"}, {"'use strict'; const ", " = {};"}, + {"function f(", ") {}"}, + {"function f(argument1, ", ") {}"}, + {"var f = (", ") => {};"}, + {"var f = ", " => {};"}, + {"var f = (argument1,", ") => {};"}, {NULL, NULL}}; // clang-format off @@ -6435,7 +6442,6 @@ TEST(DestructuringNegativeTests) { "a >>> a", "function a() {}", "a`bcd`", - "x => x", "this", "null", "true", @@ -6443,25 +6449,61 @@ TEST(DestructuringNegativeTests) { "1", "'abc'", "class {}", - "() => x", "{+2 : x}", "{-2 : x}", "var", "[var]", "{x : {y : var}}", + "{x : x = a+}", + "{x : x = (a+)}", + "{x : x += a}", + "{m() {} = 0}", + "{[1+1]}", + "[...rest, x]", + "[a,b,...rest, x]", + "[a,,...rest, x]", + "[...rest,]", + "[a,b,...rest,]", + "[a,,...rest,]", + "[...rest,...rest1]", + "[a,b,...rest,...rest1]", + "[a,,..rest,...rest1]", NULL}; // clang-format on RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); } - { // Strict mode. + { // All modes. const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, + {"var ", " = {};"}, {"'use strict'; const ", " = {};"}, + {"function f(", ") {}"}, + {"function f(argument1, ", ") {}"}, + {"var f = (", ") => {};"}, + {"var f = (argument1,", ") => {};"}, {NULL, NULL}}; // clang-format off const char* data[] = { + "x => x", + "() => x", + NULL}; + // clang-format on + RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + } + + { // Strict mode. + const char* context_data[][2] = { + {"'use strict'; let ", " = {};"}, + {"'use strict'; const ", " = {};"}, + {"'use strict'; function f(", ") {}"}, + {"'use strict'; function f(argument1, ", ") {}"}, + {NULL, NULL}}; + + // clang-format off + const char* data[] = { "[eval]", "{ a : arguments }", "[public]", @@ -6490,3 +6532,261 @@ TEST(DestructuringNegativeTests) { arraysize(always_flags)); } } + + +TEST(DestructuringDisallowPatternsInForVarIn) { + i::FLAG_harmony_destructuring = true; + static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; + const char* context_data[][2] = { + {"", ""}, {"function f() {", "}"}, {NULL, NULL}}; + // clang-format off + const char* error_data[] = { + "for (let x = {} in null);", + "for (let x = {} of null);", + NULL}; + // clang-format on + RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + + // clang-format off + const char* success_data[] = { + "for (var x = {} in null);", + NULL}; + // clang-format on + RunParserSyncTest(context_data, success_data, kSuccess, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(DestructuringDuplicateParams) { + i::FLAG_harmony_destructuring = true; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_computed_property_names = true; + static const ParserFlag always_flags[] = {kAllowHarmonyComputedPropertyNames, + kAllowHarmonyArrowFunctions, + kAllowHarmonyDestructuring}; + const char* context_data[][2] = {{"'use strict';", ""}, + {"function outer() { 'use strict';", "}"}, + {nullptr, nullptr}}; + + + // clang-format off + const char* error_data[] = { + "function f(x,x){}", + "function f(x, {x : x}){}", + "function f(x, {x}){}", + "function f({x,x}) {}", + "function f([x,x]) {}", + "function f(x, [y,{z:x}]) {}", + "function f([x,{y:x}]) {}", + // non-simple parameter list causes duplicates to be errors in sloppy mode. + "function f(x, x, {a}) {}", + nullptr}; + // clang-format on + RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(DestructuringDuplicateParamsSloppy) { + i::FLAG_harmony_destructuring = true; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_computed_property_names = true; + static const ParserFlag always_flags[] = {kAllowHarmonyComputedPropertyNames, + kAllowHarmonyArrowFunctions, + kAllowHarmonyDestructuring}; + const char* context_data[][2] = { + {"", ""}, {"function outer() {", "}"}, {nullptr, nullptr}}; + + + // clang-format off + const char* error_data[] = { + // non-simple parameter list causes duplicates to be errors in sloppy mode. + "function f(x, {x : x}){}", + "function f(x, {x}){}", + "function f({x,x}) {}", + "function f(x, x, {a}) {}", + nullptr}; + // clang-format on + RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(DestructuringDisallowPatternsInSingleParamArrows) { + i::FLAG_harmony_destructuring = true; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_computed_property_names = true; + static const ParserFlag always_flags[] = {kAllowHarmonyComputedPropertyNames, + kAllowHarmonyArrowFunctions, + kAllowHarmonyDestructuring}; + const char* context_data[][2] = {{"'use strict';", ""}, + {"function outer() { 'use strict';", "}"}, + {"", ""}, + {"function outer() { ", "}"}, + {nullptr, nullptr}}; + + // clang-format off + const char* error_data[] = { + "var f = {x} => {};", + "var f = {x,y} => {};", + nullptr}; + // clang-format on + RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(DestructuringDisallowPatternsInRestParams) { + i::FLAG_harmony_destructuring = true; + i::FLAG_harmony_arrow_functions = true; + i::FLAG_harmony_rest_parameters = true; + i::FLAG_harmony_computed_property_names = true; + static const ParserFlag always_flags[] = { + kAllowHarmonyComputedPropertyNames, kAllowHarmonyArrowFunctions, + kAllowHarmonyRestParameters, kAllowHarmonyDestructuring}; + const char* context_data[][2] = {{"'use strict';", ""}, + {"function outer() { 'use strict';", "}"}, + {"", ""}, + {"function outer() { ", "}"}, + {nullptr, nullptr}}; + + // clang-format off + const char* error_data[] = { + "function(...{}) {}", + "function(...{x}) {}", + "function(...[x]) {}", + "(...{}) => {}", + "(...{x}) => {}", + "(...[x]) => {}", + nullptr}; + // clang-format on + RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(SpreadArray) { + i::FLAG_harmony_spread_arrays = true; + + const char* context_data[][2] = { + {"'use strict';", ""}, {"", ""}, {NULL, NULL}}; + + // clang-format off + const char* data[] = { + "[...a]", + "[a, ...b]", + "[...a,]", + "[...a, ,]", + "[, ...a]", + "[...a, ...b]", + "[...a, , ...b]", + "[...[...a]]", + "[, ...a]", + "[, , ...a]", + NULL}; + // clang-format on + static const ParserFlag always_flags[] = {kAllowHarmonySpreadArrays}; + RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(SpreadArrayError) { + i::FLAG_harmony_spread_arrays = true; + + const char* context_data[][2] = { + {"'use strict';", ""}, {"", ""}, {NULL, NULL}}; + + // clang-format off + const char* data[] = { + "[...]", + "[a, ...]", + "[..., ]", + "[..., ...]", + "[ (...a)]", + NULL}; + // clang-format on + static const ParserFlag always_flags[] = {kAllowHarmonySpreadArrays}; + RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(NewTarget) { + // clang-format off + const char* good_context_data[][2] = { + {"function f() {", "}"}, + {"'use strict'; function f() {", "}"}, + {"var f = function() {", "}"}, + {"'use strict'; var f = function() {", "}"}, + {"({m: function() {", "}})"}, + {"'use strict'; ({m: function() {", "}})"}, + {"({m() {", "}})"}, + {"'use strict'; ({m() {", "}})"}, + {"({get x() {", "}})"}, + {"'use strict'; ({get x() {", "}})"}, + {"({set x(_) {", "}})"}, + {"'use strict'; ({set x(_) {", "}})"}, + {"class C {m() {", "}}"}, + {"class C {get x() {", "}}"}, + {"class C {set x(_) {", "}}"}, + {NULL} + }; + + const char* bad_context_data[][2] = { + {"", ""}, + {"'use strict';", ""}, + {NULL} + }; + + const char* data[] = { + "new.target", + "{ new.target }", + "() => { new.target }", + "() => new.target", + "if (1) { new.target }", + "if (1) {} else { new.target }", + "while (0) { new.target }", + "do { new.target } while (0)", + NULL + }; + + static const ParserFlag always_flags[] = { + kAllowHarmonyArrowFunctions, + kAllowHarmonyNewTarget, + kAllowHarmonySloppy, + }; + // clang-format on + + RunParserSyncTest(good_context_data, data, kSuccess, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(bad_context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(LegacyConst) { + // clang-format off + const char* context_data[][2] = { + {"", ""}, + {"{", "}"}, + {NULL, NULL} + }; + + const char* data[] = { + "const x", + "const x = 1", + "for (const x = 1; x < 1; x++) {}", + "for (const x in {}) {}", + "for (const x of []) {}", + NULL + }; + // clang-format on + + static const ParserFlag always_flags[] = {kNoLegacyConst}; + + RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess); +} diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 0a2c7a5625..221761487c 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -681,14 +681,13 @@ TEST(BailoutReason) { CHECK_EQ(0, iprofiler->GetProfilesCount()); v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), - "function TryCatch() {\n" - " try {\n" - " startProfiling();\n" - " } catch (e) { };\n" + "function Debugger() {\n" + " debugger;\n" + " startProfiling();\n" "}\n" "function TryFinally() {\n" " try {\n" - " TryCatch();\n" + " Debugger();\n" " } finally { };\n" "}\n" "TryFinally();\n" @@ -703,8 +702,8 @@ TEST(BailoutReason) { // The tree should look like this: // (root) // "" - // kTryFinally - // kTryCatch + // kTryFinallyStatement + // kDebuggerStatement current = PickChild(current, ""); CHECK(const_cast<v8::CpuProfileNode*>(current)); @@ -712,7 +711,7 @@ TEST(BailoutReason) { CHECK(const_cast<v8::CpuProfileNode*>(current)); CHECK(!strcmp("TryFinallyStatement", current->GetBailoutReason())); - current = PickChild(current, "TryCatch"); + current = PickChild(current, "Debugger"); CHECK(const_cast<v8::CpuProfileNode*>(current)); - CHECK(!strcmp("TryCatchStatement", current->GetBailoutReason())); + CHECK(!strcmp("DebuggerStatement", current->GetBailoutReason())); } diff --git a/deps/v8/test/cctest/test-reloc-info.cc b/deps/v8/test/cctest/test-reloc-info.cc index a238c3a7d8..829fd24f4d 100644 --- a/deps/v8/test/cctest/test-reloc-info.cc +++ b/deps/v8/test/cctest/test-reloc-info.cc @@ -66,8 +66,8 @@ TEST(Positions) { writer.Finish(); relocation_info_size = static_cast<int>(buffer_end - writer.pos()); - CodeDesc desc = { buffer.get(), buffer_size, code_size, - relocation_info_size, NULL }; + CodeDesc desc = {buffer.get(), buffer_size, code_size, relocation_info_size, + 0, NULL}; // Read only (non-statement) positions. { @@ -120,4 +120,5 @@ TEST(Positions) { } } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 938178efb9..0bae94e219 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -493,7 +493,7 @@ UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { &outdated_contexts).ToHandleChecked(); CHECK(root->IsContext()); CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy); - CHECK_EQ(1, outdated_contexts->length()); + CHECK_EQ(2, outdated_contexts->length()); } Handle<Object> root2; @@ -628,13 +628,13 @@ UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, root = deserializer.DeserializePartial(isolate, global_proxy, &outdated_contexts).ToHandleChecked(); - CHECK_EQ(2, outdated_contexts->length()); + CHECK_EQ(3, outdated_contexts->length()); CHECK(root->IsContext()); Handle<Context> context = Handle<Context>::cast(root); CHECK(context->global_proxy() == *global_proxy); Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); Handle<JSObject> global_object(context->global_object(), isolate); - Handle<Object> property = JSObject::GetDataProperty(global_object, o); + Handle<Object> property = JSReceiver::GetDataProperty(global_object, o); CHECK(property.is_identical_to(global_proxy)); v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context); @@ -859,7 +859,7 @@ static Handle<SharedFunctionInfo> CompileScript( Isolate* isolate, Handle<String> source, Handle<String> name, ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) { return Compiler::CompileScript( - source, name, 0, 0, false, false, Handle<Object>(), + source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, cached_data, options, NOT_NATIVES_CODE, false); } @@ -938,7 +938,7 @@ TEST(CodeCachePromotedToCompilationCache) { isolate, src, src, &cache, v8::ScriptCompiler::kConsumeCodeCache); CHECK(isolate->compilation_cache() - ->LookupScript(src, src, 0, 0, false, false, + ->LookupScript(src, src, 0, 0, v8::ScriptOriginOptions(), isolate->native_context(), SLOPPY) .ToHandleChecked() .is_identical_to(copy)); @@ -1098,11 +1098,11 @@ TEST(SerializeToplevelLargeStrings) { Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length()); - Handle<Object> property = JSObject::GetDataProperty( + Handle<Object> property = JSReceiver::GetDataProperty( isolate->global_object(), f->NewStringFromAsciiChecked("s")); CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); - property = JSObject::GetDataProperty(isolate->global_object(), - f->NewStringFromAsciiChecked("t")); + property = JSReceiver::GetDataProperty(isolate->global_object(), + f->NewStringFromAsciiChecked("t")); CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE)); // Make sure we do not serialize too much, e.g. include the source string. CHECK_LT(cache->length(), 13000000); @@ -1595,7 +1595,6 @@ TEST(SerializeInternalReference) { return; #endif // Disable experimental natives that are loaded after deserialization. - FLAG_turbo_deoptimization = false; FLAG_context_specialization = false; FLAG_always_opt = true; const char* flag = "--turbo-filter=foo"; @@ -1659,6 +1658,31 @@ TEST(SerializeInternalReference) { } +TEST(Regress503552) { + // Test that the code serializer can deal with weak cells that form a linked + // list during incremental marking. + + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + + HandleScope scope(isolate); + Handle<String> source = isolate->factory()->NewStringFromAsciiChecked( + "function f() {} function g() {}"); + ScriptData* script_data = NULL; + Handle<SharedFunctionInfo> shared = Compiler::CompileScript( + source, Handle<String>(), 0, 0, v8::ScriptOriginOptions(), + Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, + &script_data, v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE, + false); + delete script_data; + + SimulateIncrementalMarking(isolate->heap()); + + script_data = CodeSerializer::Serialize(isolate, shared, source); + delete script_data; +} + + TEST(SerializationMemoryStats) { FLAG_profile_deserialization = true; FLAG_always_opt = false; diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc index 9d22327831..3f5e437223 100644 --- a/deps/v8/test/cctest/test-spaces.cc +++ b/deps/v8/test/cctest/test-spaces.cc @@ -145,7 +145,8 @@ class TestCodeRangeScope { DISALLOW_COPY_AND_ASSIGN(TestCodeRangeScope); }; -} } // namespace v8::internal +} // namespace internal +} // namespace v8 static void VerifyMemoryChunk(Isolate* isolate, @@ -358,8 +359,9 @@ TEST(NewSpace) { CHECK(new_space.HasBeenSetUp()); while (new_space.Available() >= Page::kMaxRegularHeapObjectSize) { - Object* obj = new_space.AllocateRaw( - Page::kMaxRegularHeapObjectSize).ToObjectChecked(); + Object* obj = + new_space.AllocateRawUnaligned(Page::kMaxRegularHeapObjectSize) + .ToObjectChecked(); CHECK(new_space.Contains(HeapObject::cast(obj))); } @@ -384,7 +386,7 @@ TEST(OldSpace) { CHECK(s->SetUp()); while (s->Available() > 0) { - s->AllocateRaw(Page::kMaxRegularHeapObjectSize).ToObjectChecked(); + s->AllocateRawUnaligned(Page::kMaxRegularHeapObjectSize).ToObjectChecked(); } s->TearDown(); @@ -437,6 +439,9 @@ TEST(SizeOfFirstPageIsLargeEnough) { if (!isolate->snapshot_available()) return; if (Snapshot::EmbedsScript(isolate)) return; + // If this test fails due to enabling experimental natives that are not part + // of the snapshot, we may need to adjust CalculateFirstPageSizes. + // Freshly initialized VM gets by with one page per space. for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) { // Debug code can be very large, so skip CODE_SPACE if we are generating it. @@ -485,7 +490,8 @@ UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) { // Try to allocate out of the new space. A new page should be added and // the // allocation should succeed. - v8::internal::AllocationResult allocation = new_space->AllocateRaw(80); + v8::internal::AllocationResult allocation = + new_space->AllocateRawUnaligned(80); CHECK(!allocation.IsRetry()); CHECK(new_space->CommittedMemory() == 2 * Page::kPageSize); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 1713e91662..d8d7c96871 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -1222,7 +1222,7 @@ UNINITIALIZED_TEST(OneByteArrayJoin) { // summing the lengths of the strings (as Smis) overflows and wraps. LocalContext context(isolate); v8::HandleScope scope(isolate); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(CompileRun( "var two_14 = Math.pow(2, 14);" "var two_17 = Math.pow(2, 17);" diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc index 250e9a344a..c0cc1cb8d1 100644 --- a/deps/v8/test/cctest/test-thread-termination.cc +++ b/deps/v8/test/cctest/test-thread-termination.cc @@ -61,7 +61,7 @@ void Loop(const v8::FunctionCallbackInfo<v8::Value>& args) { void DoLoop(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(), "function f() {" @@ -86,7 +86,7 @@ void DoLoop(const v8::FunctionCallbackInfo<v8::Value>& args) { void DoLoopNoCall(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(), "var term = true;" @@ -217,7 +217,7 @@ void TerminateOrReturnObject(const v8::FunctionCallbackInfo<v8::Value>& args) { void LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); v8::Script::Compile( v8::String::NewFromUtf8(args.GetIsolate(), @@ -275,7 +275,7 @@ v8::Persistent<v8::String> reenter_script_1; v8::Persistent<v8::String> reenter_script_2; void ReenterAfterTermination(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); v8::Isolate* isolate = args.GetIsolate(); CHECK(!v8::V8::IsExecutionTerminating(isolate)); v8::Local<v8::String> script = @@ -328,7 +328,7 @@ TEST(TerminateAndReenterFromThreadItself) { void DoLoopCancelTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::TryCatch try_catch; + v8::TryCatch try_catch(args.GetIsolate()); CHECK(!v8::V8::IsExecutionTerminating()); v8::Script::Compile(v8::String::NewFromUtf8(args.GetIsolate(), "var term = true;" @@ -426,7 +426,7 @@ TEST(PostponeTerminateException) { v8::Context::New(CcTest::isolate(), NULL, global); v8::Context::Scope context_scope(context); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); static const char* terminate_and_loop = "terminate(); for (var i = 0; i < 10000; i++);"; @@ -504,7 +504,7 @@ TEST(TerminationInInnerTryCall) { v8::Context::New(CcTest::isolate(), NULL, global_template); v8::Context::Scope context_scope(context); { - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CompileRun("inner_try_call_terminate()"); CHECK(try_catch.HasTerminated()); } @@ -522,7 +522,7 @@ TEST(TerminateAndTryCall) { v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global); v8::Context::Scope context_scope(context); CHECK(!v8::V8::IsExecutionTerminating(isolate)); - v8::TryCatch try_catch; + v8::TryCatch try_catch(isolate); CHECK(!v8::V8::IsExecutionTerminating(isolate)); // Terminate execution has been triggered inside TryCall, but re-requested // to trigger later. diff --git a/deps/v8/test/cctest/test-threads.cc b/deps/v8/test/cctest/test-threads.cc index e192bc1559..5f2cdae2a2 100644 --- a/deps/v8/test/cctest/test-threads.cc +++ b/deps/v8/test/cctest/test-threads.cc @@ -32,12 +32,7 @@ #include "src/isolate.h" -enum Turn { - FILL_CACHE, - CLEAN_CACHE, - SECOND_TIME_FILL_CACHE, - DONE -}; +enum Turn { FILL_CACHE, CLEAN_CACHE, SECOND_TIME_FILL_CACHE, CACHE_DONE }; static Turn turn = FILL_CACHE; @@ -76,7 +71,7 @@ class ThreadA : public v8::base::Thread { // Rerun the script. CHECK(script->Run()->IsTrue()); - turn = DONE; + turn = CACHE_DONE; } }; @@ -116,7 +111,7 @@ TEST(JSFunctionResultCachesInTwoThreads) { threadA.Join(); threadB.Join(); - CHECK_EQ(DONE, turn); + CHECK_EQ(CACHE_DONE, turn); } class ThreadIdValidationThread : public v8::base::Thread { diff --git a/deps/v8/test/cctest/test-typedarrays.cc b/deps/v8/test/cctest/test-typedarrays.cc index d371673b9e..394f6194fd 100644 --- a/deps/v8/test/cctest/test-typedarrays.cc +++ b/deps/v8/test/cctest/test-typedarrays.cc @@ -48,7 +48,7 @@ TEST(CopyContentsArray) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); CompileRun("var a = new Uint8Array([0, 1, 2, 3]);"); - TestArrayBufferViewContents(env, true); + TestArrayBufferViewContents(env, false); } diff --git a/deps/v8/test/cctest/test-types.cc b/deps/v8/test/cctest/test-types.cc index 295cef6d36..fe07093077 100644 --- a/deps/v8/test/cctest/test-types.cc +++ b/deps/v8/test/cctest/test-types.cc @@ -1020,15 +1020,10 @@ struct Tests : Rep { CheckSub(T.Proxy, T.Receiver); CheckSub(T.OtherObject, T.Object); CheckSub(T.Undetectable, T.Object); - CheckSub(T.DetectableObject, T.Object); - CheckSub(T.GlobalObject, T.DetectableObject); - CheckSub(T.OtherObject, T.DetectableObject); - CheckSub(T.GlobalObject, T.Object); - CheckSub(T.GlobalObject, T.Receiver); + CheckSub(T.OtherObject, T.Object); CheckUnordered(T.Object, T.Proxy); - CheckUnordered(T.GlobalObject, T.OtherObject); - CheckUnordered(T.DetectableObject, T.Undetectable); + CheckUnordered(T.OtherObject, T.Undetectable); // Subtyping between concrete structural types @@ -1350,7 +1345,6 @@ struct Tests : Rep { CheckDisjoint(T.InternalizedString, T.Symbol); CheckOverlap(T.Object, T.Receiver); CheckOverlap(T.OtherObject, T.Object); - CheckOverlap(T.GlobalObject, T.Object); CheckOverlap(T.Proxy, T.Receiver); CheckDisjoint(T.Object, T.Proxy); @@ -1505,6 +1499,7 @@ struct Tests : Rep { void Union3() { // Monotonicity: T1->Is(T2) or T1->Is(T3) implies T1->Is(Union(T2, T3)) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + HandleScope scope(isolate); for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) { TypeHandle type1 = *it1; @@ -1757,6 +1752,7 @@ struct Tests : Rep { // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3)) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + HandleScope scope(isolate); for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { TypeHandle type1 = *it1; @@ -1963,66 +1959,6 @@ struct Tests : Rep { } } } - - void GlobalObjectType() { - i::Handle<i::Context> context1 = v8::Utils::OpenHandle( - *v8::Context::New(reinterpret_cast<v8::Isolate*>(isolate))); - Handle<i::GlobalObject> global_object1(context1->global_object()); - TypeHandle GlobalObjectConstant1 = - Type::Constant(global_object1, Rep::ToRegion(&zone, isolate)); - - i::Handle<i::Context> context2 = v8::Utils::OpenHandle( - *v8::Context::New(reinterpret_cast<v8::Isolate*>(isolate))); - Handle<i::GlobalObject> global_object2(context2->global_object()); - TypeHandle GlobalObjectConstant2 = - Type::Constant(global_object2, Rep::ToRegion(&zone, isolate)); - - CheckSub(GlobalObjectConstant1, T.DetectableObject); - CheckSub(GlobalObjectConstant2, T.DetectableObject); - CheckSub(GlobalObjectConstant1, T.GlobalObject); - CheckSub(GlobalObjectConstant2, T.GlobalObject); - CheckSub(GlobalObjectConstant1, T.Object); - CheckSub(GlobalObjectConstant2, T.Object); - - CheckUnordered(T.GlobalObject, T.OtherObject); - CheckUnordered(GlobalObjectConstant1, T.OtherObject); - CheckUnordered(GlobalObjectConstant2, T.OtherObject); - CheckUnordered(GlobalObjectConstant1, GlobalObjectConstant2); - - CheckDisjoint(T.GlobalObject, T.ObjectClass); - CheckDisjoint(GlobalObjectConstant1, T.ObjectClass); - CheckDisjoint(GlobalObjectConstant2, T.ArrayClass); - - CheckUnordered(T.Union(T.ObjectClass, T.ArrayClass), T.GlobalObject); - CheckUnordered(T.Union(T.ObjectClass, T.ArrayClass), GlobalObjectConstant1); - CheckUnordered(T.Union(T.ObjectClass, T.ArrayClass), GlobalObjectConstant2); - - CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayClass), T.GlobalObject); - CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayClass), - GlobalObjectConstant1); - CheckUnordered(T.Union(T.ObjectConstant1, T.ArrayClass), - GlobalObjectConstant2); - - CheckUnordered(T.Union(T.ObjectClass, T.String), T.GlobalObject); - - CheckSub(T.Union(T.ObjectConstant1, T.ArrayClass), - T.Union(T.GlobalObject, T.Object)); - - CheckDisjoint(T.Union(GlobalObjectConstant1, T.ArrayClass), - GlobalObjectConstant2); - - CheckEqual(T.Union(T.Union(T.Number, GlobalObjectConstant1), - T.Union(T.SignedSmall, T.GlobalObject)), - T.Union(T.Number, T.GlobalObject)); - - CheckEqual(T.Semantic(T.Intersect(T.ObjectClass, T.GlobalObject)), T.None); - - CHECK(!T.Intersect(T.ArrayClass, GlobalObjectConstant2)->IsInhabited()); - - CheckEqual(T.Intersect(T.Union(T.Number, T.OtherObject), - T.Union(T.Signed32, T.GlobalObject)), - T.Signed32); - } }; typedef Tests<Type, Type*, Zone, ZoneRep> ZoneTests; @@ -2197,9 +2133,3 @@ TEST(HTypeFromType_zone) { ZoneTests().HTypeFromType(); } TEST(HTypeFromType_heap) { HeapTests().HTypeFromType(); } - - -TEST(GlobalObjectType_zone) { ZoneTests().GlobalObjectType(); } - - -TEST(GlobalObjectType_heap) { HeapTests().GlobalObjectType(); } diff --git a/deps/v8/test/cctest/test-unboxed-doubles.cc b/deps/v8/test/cctest/test-unboxed-doubles.cc index 89f58a62e4..4746e47322 100644 --- a/deps/v8/test/cctest/test-unboxed-doubles.cc +++ b/deps/v8/test/cctest/test-unboxed-doubles.cc @@ -1035,7 +1035,7 @@ TEST(DoScavenge) { CcTest::heap()->CollectGarbage(i::NEW_SPACE); // Create temp object in the new space. - Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED); + Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS); CHECK(isolate->heap()->new_space()->Contains(*temp)); // Construct a double value that looks like a pointer to the new space object @@ -1088,7 +1088,8 @@ TEST(DoScavengeWithIncrementalWriteBarrier) { AlwaysAllocateScope always_allocate(isolate); // Make sure |obj_value| is placed on an old-space evacuation candidate. SimulateFullSpace(old_space); - obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); + obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, + Strength::WEAK, TENURED); ec_page = Page::FromAddress(obj_value->address()); } @@ -1373,7 +1374,7 @@ TEST(StoreBufferScanOnScavenge) { CHECK(isolate->heap()->old_space()->Contains(*obj)); // Create temp object in the new space. - Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED); + Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS); CHECK(isolate->heap()->new_space()->Contains(*temp)); // Construct a double value that looks like a pointer to the new space object @@ -1572,7 +1573,8 @@ static void TestIncrementalWriteBarrier(Handle<Map> map, Handle<Map> new_map, // Make sure |obj_value| is placed on an old-space evacuation candidate. SimulateFullSpace(old_space); - obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); + obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, + Strength::WEAK, TENURED); ec_page = Page::FromAddress(obj_value->address()); CHECK_NE(ec_page, Page::FromAddress(obj->address())); } diff --git a/deps/v8/test/cctest/test-utils-arm64.h b/deps/v8/test/cctest/test-utils-arm64.h index d00ad5e78c..a091bf3932 100644 --- a/deps/v8/test/cctest/test-utils-arm64.h +++ b/deps/v8/test/cctest/test-utils-arm64.h @@ -96,13 +96,13 @@ class RegisterDump { return dump_.sp_; } - inline int64_t wspreg() const { + inline int32_t wspreg() const { DCHECK(SPRegAliasesMatch()); - return dump_.wsp_; + return static_cast<int32_t>(dump_.wsp_); } // Flags accessors. - inline uint64_t flags_nzcv() const { + inline uint32_t flags_nzcv() const { DCHECK(IsComplete()); DCHECK((dump_.flags_ & ~Flags_mask) == 0); return dump_.flags_ & Flags_mask; diff --git a/deps/v8/test/cctest/test-version.cc b/deps/v8/test/cctest/test-version.cc index 7de4467d6b..50fca16871 100644 --- a/deps/v8/test/cctest/test-version.cc +++ b/deps/v8/test/cctest/test-version.cc @@ -46,7 +46,8 @@ void SetVersion(int major, int minor, int build, int patch, Version::soname_ = soname; } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 static void CheckVersion(int major, int minor, int build, diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 64d2876887..31b812e287 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -34,7 +34,6 @@ using namespace v8::internal; - static Isolate* GetIsolateFrom(LocalContext* context) { return reinterpret_cast<Isolate*>((*context)->GetIsolate()); } @@ -89,8 +88,10 @@ TEST(Weakness) { Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); Handle<JSObject> object = factory->NewJSObjectFromMap(map); Handle<Smi> smi(Smi::FromInt(23), isolate); - Runtime::WeakCollectionSet(weakmap, key, object); - Runtime::WeakCollectionSet(weakmap, object, smi); + int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); + Runtime::WeakCollectionSet(weakmap, key, object, hash); + int32_t object_hash = Object::GetOrCreateHash(isolate, object)->value(); + Runtime::WeakCollectionSet(weakmap, object, smi, object_hash); } CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements()); @@ -145,7 +146,8 @@ TEST(Shrinking) { for (int i = 0; i < 32; i++) { Handle<JSObject> object = factory->NewJSObjectFromMap(map); Handle<Smi> smi(Smi::FromInt(i), isolate); - Runtime::WeakCollectionSet(weakmap, object, smi); + int32_t object_hash = Object::GetOrCreateHash(isolate, object)->value(); + Runtime::WeakCollectionSet(weakmap, object, smi, object_hash); } } @@ -193,7 +195,8 @@ TEST(Regress2060a) { Handle<JSObject> object = factory->NewJSObject(function, TENURED); CHECK(!heap->InNewSpace(object->address())); CHECK(!first_page->Contains(object->address())); - Runtime::WeakCollectionSet(weakmap, key, object); + int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); + Runtime::WeakCollectionSet(weakmap, key, object, hash); } } @@ -235,7 +238,8 @@ TEST(Regress2060b) { Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate); for (int i = 0; i < 32; i++) { Handle<Smi> smi(Smi::FromInt(i), isolate); - Runtime::WeakCollectionSet(weakmap, keys[i], smi); + int32_t hash = Object::GetOrCreateHash(isolate, keys[i])->value(); + Runtime::WeakCollectionSet(weakmap, keys[i], smi, hash); } // Force compacting garbage collection. The subsequent collections are used diff --git a/deps/v8/test/cctest/test-weaksets.cc b/deps/v8/test/cctest/test-weaksets.cc index dbb7311e83..3595af288f 100644 --- a/deps/v8/test/cctest/test-weaksets.cc +++ b/deps/v8/test/cctest/test-weaksets.cc @@ -34,7 +34,6 @@ using namespace v8::internal; - static Isolate* GetIsolateFrom(LocalContext* context) { return reinterpret_cast<Isolate*>((*context)->GetIsolate()); } @@ -90,7 +89,8 @@ TEST(WeakSet_Weakness) { { HandleScope scope(isolate); Handle<Smi> smi(Smi::FromInt(23), isolate); - Runtime::WeakCollectionSet(weakset, key, smi); + int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); + Runtime::WeakCollectionSet(weakset, key, smi, hash); } CHECK_EQ(1, ObjectHashTable::cast(weakset->table())->NumberOfElements()); @@ -145,7 +145,8 @@ TEST(WeakSet_Shrinking) { for (int i = 0; i < 32; i++) { Handle<JSObject> object = factory->NewJSObjectFromMap(map); Handle<Smi> smi(Smi::FromInt(i), isolate); - Runtime::WeakCollectionSet(weakset, object, smi); + int32_t hash = Object::GetOrCreateHash(isolate, object)->value(); + Runtime::WeakCollectionSet(weakset, object, smi, hash); } } @@ -193,7 +194,8 @@ TEST(WeakSet_Regress2060a) { Handle<JSObject> object = factory->NewJSObject(function, TENURED); CHECK(!heap->InNewSpace(object->address())); CHECK(!first_page->Contains(object->address())); - Runtime::WeakCollectionSet(weakset, key, object); + int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); + Runtime::WeakCollectionSet(weakset, key, object, hash); } } @@ -235,7 +237,8 @@ TEST(WeakSet_Regress2060b) { Handle<JSWeakSet> weakset = AllocateJSWeakSet(isolate); for (int i = 0; i < 32; i++) { Handle<Smi> smi(Smi::FromInt(i), isolate); - Runtime::WeakCollectionSet(weakset, keys[i], smi); + int32_t hash = Object::GetOrCreateHash(isolate, keys[i])->value(); + Runtime::WeakCollectionSet(weakset, keys[i], smi, hash); } // Force compacting garbage collection. The subsequent collections are used diff --git a/deps/v8/test/cctest/trace-extension.cc b/deps/v8/test/cctest/trace-extension.cc index a95532f931..e7f097f86f 100644 --- a/deps/v8/test/cctest/trace-extension.cc +++ b/deps/v8/test/cctest/trace-extension.cc @@ -151,4 +151,5 @@ void TraceExtension::JSEntrySPLevel2( } -} } // namespace v8::internal +} // namespace internal +} // namespace v8 |