diff options
author | Refael Ackermann <refack@gmail.com> | 2014-09-29 13:20:04 +0400 |
---|---|---|
committer | Fedor Indutny <fedor@indutny.com> | 2014-10-08 15:35:57 +0400 |
commit | 939278ac059b44439d41aab12bf552c8ae3c52d0 (patch) | |
tree | 86c586915a96d308b1b04de679a8ae293caf3e41 /deps/v8/test/cctest | |
parent | 4412a71d76a0fa002f627ec21d2337e089da6764 (diff) | |
download | node-new-939278ac059b44439d41aab12bf552c8ae3c52d0.tar.gz |
deps: update v8 to 3.28.73
Reviewed-By: Fedor Indutny <fedor@indutny.com>
PR-URL: https://github.com/joyent/node/pull/8476
Diffstat (limited to 'deps/v8/test/cctest')
178 files changed, 34641 insertions, 7160 deletions
diff --git a/deps/v8/test/cctest/DEPS b/deps/v8/test/cctest/DEPS new file mode 100644 index 0000000000..3e73aa244f --- /dev/null +++ b/deps/v8/test/cctest/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+src", +] diff --git a/deps/v8/test/cctest/cctest.cc b/deps/v8/test/cctest/cctest.cc index b1cf5abb4e..2bb08b0ec9 100644 --- a/deps/v8/test/cctest/cctest.cc +++ b/deps/v8/test/cctest/cctest.cc @@ -25,13 +25,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <v8.h> -#include "cctest.h" +#include "include/v8.h" +#include "test/cctest/cctest.h" -#include "print-extension.h" -#include "profiler-extension.h" -#include "trace-extension.h" -#include "debug.h" +#include "include/libplatform/libplatform.h" +#include "src/debug.h" +#include "test/cctest/print-extension.h" +#include "test/cctest/profiler-extension.h" +#include "test/cctest/trace-extension.h" enum InitializationState {kUnset, kUnintialized, kInitialized}; static InitializationState initialization_state_ = kUnset; @@ -138,7 +139,8 @@ static void SuggestTestHarness(int tests) { int main(int argc, char* argv[]) { v8::V8::InitializeICU(); - i::Isolate::SetCrashIfDefaultIsolateInitialized(); + v8::Platform* platform = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(platform); v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true); @@ -157,6 +159,10 @@ int main(int argc, char* argv[]) { for (int i = 1; i < argc; i++) { char* arg = argv[i]; if (strcmp(arg, "--list") == 0) { + // TODO(svenpanne) Serializer::enabled() and Serializer::code_address_map_ + // are fundamentally broken, so we can't unconditionally initialize and + // dispose V8. + v8::V8::Initialize(); PrintTestList(CcTest::last()); print_run_count = false; @@ -200,7 +206,10 @@ int main(int argc, char* argv[]) { if (print_run_count && tests_run != 1) printf("Ran %i tests.\n", tests_run); CcTest::TearDown(); - if (!disable_automatic_dispose_) v8::V8::Dispose(); + // TODO(svenpanne) See comment above. + // if (!disable_automatic_dispose_) v8::V8::Dispose(); + v8::V8::ShutdownPlatform(); + delete platform; return 0; } diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 745b4c51d8..42946f5bfe 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -37,12 +37,53 @@ 'type': 'executable', 'dependencies': [ 'resources', + '../../tools/gyp/v8.gyp:v8_libplatform', ], 'include_dirs': [ - '../../src', + '../..', ], 'sources': [ ### gcmole(all) ### '<(generated_file)', + 'compiler/codegen-tester.cc', + 'compiler/codegen-tester.h', + 'compiler/function-tester.h', + 'compiler/graph-builder-tester.cc', + 'compiler/graph-builder-tester.h', + 'compiler/graph-tester.h', + 'compiler/simplified-graph-builder.cc', + 'compiler/simplified-graph-builder.h', + 'compiler/test-branch-combine.cc', + 'compiler/test-changes-lowering.cc', + 'compiler/test-codegen-deopt.cc', + 'compiler/test-gap-resolver.cc', + 'compiler/test-graph-reducer.cc', + 'compiler/test-instruction-selector.cc', + 'compiler/test-instruction.cc', + 'compiler/test-js-context-specialization.cc', + 'compiler/test-js-constant-cache.cc', + 'compiler/test-js-typed-lowering.cc', + 'compiler/test-linkage.cc', + 'compiler/test-machine-operator-reducer.cc', + 'compiler/test-node-algorithm.cc', + 'compiler/test-node-cache.cc', + 'compiler/test-node.cc', + 'compiler/test-operator.cc', + 'compiler/test-phi-reducer.cc', + 'compiler/test-pipeline.cc', + 'compiler/test-representation-change.cc', + 'compiler/test-run-deopt.cc', + 'compiler/test-run-intrinsics.cc', + 'compiler/test-run-jsbranches.cc', + 'compiler/test-run-jscalls.cc', + 'compiler/test-run-jsexceptions.cc', + 'compiler/test-run-jsops.cc', + 'compiler/test-run-machops.cc', + 'compiler/test-run-variables.cc', + 'compiler/test-schedule.cc', + 'compiler/test-scheduler.cc', + 'compiler/test-simplified-lowering.cc', + 'compiler/test-structured-ifbuilder-fuzzer.cc', + 'compiler/test-structured-machine-assembler.cc', 'cctest.cc', 'gay-fixed.cc', 'gay-precision.cc', @@ -56,12 +97,11 @@ 'test-atomicops.cc', 'test-bignum.cc', 'test-bignum-dtoa.cc', + 'test-checks.cc', 'test-circular-queue.cc', 'test-compiler.cc', - 'test-condition-variable.cc', 'test-constantpool.cc', 'test-conversions.cc', - 'test-cpu.cc', 'test-cpu-profiler.cc', 'test-dataflow.cc', 'test-date.cc', @@ -77,12 +117,15 @@ 'test-fixed-dtoa.cc', 'test-flags.cc', 'test-func-name-inference.cc', + 'test-gc-tracer.cc', 'test-global-handles.cc', 'test-global-object.cc', 'test-hashing.cc', 'test-hashmap.cc', 'test-heap.cc', 'test-heap-profiler.cc', + 'test-hydrogen-types.cc', + 'test-libplatform-default-platform.cc', 'test-libplatform-task-queue.cc', 'test-libplatform-worker-thread.cc', 'test-list.cc', @@ -92,12 +135,11 @@ 'test-microtask-delivery.cc', 'test-mark-compact.cc', 'test-mementos.cc', - 'test-mutex.cc', 'test-object-observe.cc', 'test-ordered-hash-table.cc', + 'test-ostreams.cc', 'test-parsing.cc', 'test-platform.cc', - 'test-platform-tls.cc', 'test-profile-generator.cc', 'test-random-number-generator.cc', 'test-regexp.cc', @@ -105,17 +147,16 @@ 'test-representation.cc', 'test-semaphore.cc', 'test-serialize.cc', - 'test-socket.cc', 'test-spaces.cc', 'test-strings.cc', 'test-symbols.cc', 'test-strtod.cc', 'test-thread-termination.cc', 'test-threads.cc', - 'test-time.cc', 'test-types.cc', 'test-unbound-queue.cc', 'test-unique.cc', + 'test-unscopables-hidden-prototype.cc', 'test-utils.cc', 'test-version.cc', 'test-weakmaps.cc', @@ -126,10 +167,10 @@ 'conditions': [ ['v8_target_arch=="ia32"', { 'sources': [ ### gcmole(arch:ia32) ### + 'compiler/test-instruction-selector-ia32.cc', 'test-assembler-ia32.cc', 'test-code-stubs.cc', 'test-code-stubs-ia32.cc', - 'test-cpu-ia32.cc', 'test-disasm-ia32.cc', 'test-macro-assembler-ia32.cc', 'test-log-stack-tracer.cc' @@ -140,7 +181,6 @@ 'test-assembler-x64.cc', 'test-code-stubs.cc', 'test-code-stubs-x64.cc', - 'test-cpu-x64.cc', 'test-disasm-x64.cc', 'test-macro-assembler-x64.cc', 'test-log-stack-tracer.cc' @@ -148,6 +188,7 @@ }], ['v8_target_arch=="arm"', { 'sources': [ ### gcmole(arch:arm) ### + 'compiler/test-instruction-selector-arm.cc', 'test-assembler-arm.cc', 'test-code-stubs.cc', 'test-code-stubs-arm.cc', @@ -176,14 +217,28 @@ 'test-macro-assembler-mips.cc' ], }], - [ 'OS=="linux" or OS=="qnx"', { + ['v8_target_arch=="mips64el"', { 'sources': [ - 'test-platform-linux.cc', + 'test-assembler-mips64.cc', + 'test-code-stubs.cc', + 'test-code-stubs-mips64.cc', + 'test-disasm-mips64.cc', + 'test-macro-assembler-mips64.cc' ], }], - [ 'OS=="mac"', { + ['v8_target_arch=="x87"', { + 'sources': [ ### gcmole(arch:x87) ### + 'test-assembler-x87.cc', + 'test-code-stubs.cc', + 'test-code-stubs-x87.cc', + 'test-disasm-x87.cc', + 'test-macro-assembler-x87.cc', + 'test-log-stack-tracer.cc' + ], + }], + [ 'OS=="linux" or OS=="qnx"', { 'sources': [ - 'test-platform-macos.cc', + 'test-platform-linux.cc', ], }], [ 'OS=="win"', { @@ -206,7 +261,7 @@ }, { 'dependencies': [ - '../../tools/gyp/v8.gyp:v8_nosnapshot.<(v8_target_arch)', + '../../tools/gyp/v8.gyp:v8_nosnapshot', ], }], ], diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index 36e1b96ebf..2ab973c52d 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -28,7 +28,9 @@ #ifndef CCTEST_H_ #define CCTEST_H_ -#include "v8.h" +#include "src/v8.h" + +#include "src/isolate-inl.h" #ifndef TEST #define TEST(Name) \ @@ -83,7 +85,6 @@ typedef v8::internal::EnumSet<CcTestExtensionIds> CcTestExtensionFlags; // Use this to expose protected methods in i::Heap. class TestHeap : public i::Heap { public: - using i::Heap::AllocateArgumentsObject; using i::Heap::AllocateByteArray; using i::Heap::AllocateFixedArray; using i::Heap::AllocateHeapNumber; @@ -113,6 +114,11 @@ class CcTest { return isolate_; } + static i::Isolate* InitIsolateOnce() { + if (!initialize_called_) InitializeVM(); + return i_isolate(); + } + static i::Isolate* i_isolate() { return reinterpret_cast<i::Isolate*>(isolate()); } @@ -125,6 +131,10 @@ class CcTest { return reinterpret_cast<TestHeap*>(i_isolate()->heap()); } + static v8::base::RandomNumberGenerator* random_number_generator() { + return InitIsolateOnce()->random_number_generator(); + } + static v8::Local<v8::Object> global() { return isolate()->GetCurrentContext()->Global(); } @@ -177,7 +187,7 @@ class CcTest { // thread fuzzing test. In the thread fuzzing test it will // pseudorandomly select a successor thread and switch execution // to that thread, suspending the current test. -class ApiTestFuzzer: public v8::internal::Thread { +class ApiTestFuzzer: public v8::base::Thread { public: void CallTest(); @@ -199,11 +209,10 @@ class ApiTestFuzzer: public v8::internal::Thread { private: explicit ApiTestFuzzer(int num) - : Thread("ApiTestFuzzer"), + : Thread(Options("ApiTestFuzzer")), test_number_(num), gate_(0), - active_(true) { - } + active_(true) {} ~ApiTestFuzzer() {} static bool fuzzing_; @@ -212,11 +221,11 @@ class ApiTestFuzzer: public v8::internal::Thread { static int active_tests_; static bool NextThread(); int test_number_; - v8::internal::Semaphore gate_; + v8::base::Semaphore gate_; bool active_; void ContextSwitch(); static int GetNextTestNumber(); - static v8::internal::Semaphore all_tests_done_; + static v8::base::Semaphore all_tests_done_; }; @@ -311,6 +320,15 @@ class LocalContext { v8::Isolate* isolate_; }; + +static inline uint16_t* AsciiToTwoByteString(const char* source) { + int array_length = i::StrLength(source) + 1; + uint16_t* converted = i::NewArray<uint16_t>(array_length); + for (int i = 0; i < array_length; i++) converted[i] = source[i]; + return converted; +} + + static inline v8::Local<v8::Value> v8_num(double x) { return v8::Number::New(v8::Isolate::GetCurrent(), x); } @@ -363,14 +381,20 @@ static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) { } -static inline v8::Local<v8::Value> PreCompileCompileRun(const char* source) { +static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) { // Compile once just to get the preparse data, then compile the second time // using the data. v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::ScriptCompiler::Source script_source(v8_str(source)); v8::ScriptCompiler::Compile(isolate, &script_source, - v8::ScriptCompiler::kProduceDataToCache); - return v8::ScriptCompiler::Compile(isolate, &script_source)->Run(); + v8::ScriptCompiler::kProduceParserCache); + + // Check whether we received cached data, and if so use it. + v8::ScriptCompiler::CompileOptions options = + script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache + : v8::ScriptCompiler::kNoCompileOptions; + + return v8::ScriptCompiler::Compile(isolate, &script_source, options)->Run(); } @@ -403,10 +427,49 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin( } -// Pick a slightly different port to allow tests to be run in parallel. -static inline int FlagDependentPortOffset() { - return ::v8::internal::FLAG_crankshaft == false ? 100 : - ::v8::internal::FLAG_always_opt ? 200 : 0; + +static inline void ExpectString(const char* code, const char* expected) { + v8::Local<v8::Value> result = CompileRun(code); + CHECK(result->IsString()); + v8::String::Utf8Value utf8(result); + CHECK_EQ(expected, *utf8); +} + + +static inline void ExpectInt32(const char* code, int expected) { + v8::Local<v8::Value> result = CompileRun(code); + CHECK(result->IsInt32()); + CHECK_EQ(expected, result->Int32Value()); +} + + +static inline void ExpectBoolean(const char* code, bool expected) { + v8::Local<v8::Value> result = CompileRun(code); + CHECK(result->IsBoolean()); + CHECK_EQ(expected, result->BooleanValue()); +} + + +static inline void ExpectTrue(const char* code) { + ExpectBoolean(code, true); +} + + +static inline void ExpectFalse(const char* code) { + ExpectBoolean(code, false); +} + + +static inline void ExpectObject(const char* code, + v8::Local<v8::Value> expected) { + v8::Local<v8::Value> result = CompileRun(code); + CHECK(result->SameValue(expected)); +} + + +static inline void ExpectUndefined(const char* code) { + v8::Local<v8::Value> result = CompileRun(code); + CHECK(result->IsUndefined()); } @@ -431,6 +494,26 @@ static inline void SimulateFullSpace(v8::internal::PagedSpace* space) { } +// Helper function that simulates many incremental marking steps until +// marking is completed. +static inline void SimulateIncrementalMarking(i::Heap* heap) { + i::MarkCompactCollector* collector = heap->mark_compact_collector(); + i::IncrementalMarking* marking = heap->incremental_marking(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); + } + CHECK(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + marking->Start(); + } + CHECK(marking->IsMarking()); + while (!marking->IsComplete()) { + marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD); + } + CHECK(marking->IsComplete()); +} + + // 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. @@ -453,4 +536,30 @@ class HeapObjectsTracker { }; +class InitializedHandleScope { + public: + InitializedHandleScope() + : main_isolate_(CcTest::InitIsolateOnce()), + handle_scope_(main_isolate_) {} + + // Prefixing the below with main_ reduces a lot of naming clashes. + i::Isolate* main_isolate() { return main_isolate_; } + + private: + i::Isolate* main_isolate_; + i::HandleScope handle_scope_; +}; + + +class HandleAndZoneScope : public InitializedHandleScope { + public: + HandleAndZoneScope() : main_zone_(main_isolate()) {} + + // Prefixing the below with main_ reduces a lot of naming clashes. + i::Zone* main_zone() { return &main_zone_; } + + private: + i::Zone main_zone_; +}; + #endif // ifndef CCTEST_H_ diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index fb73f7a6da..60baaca081 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -31,6 +31,7 @@ 'test-api/Bug*': [FAIL], ############################################################################## + # BUG(382): Weird test. Can't guarantee that it never times out. 'test-api/ApplyInterruption': [PASS, TIMEOUT], @@ -67,14 +68,102 @@ # This tests only the type system, so there is no point in running several # variants. + 'test-hydrogen-types/*': [PASS, NO_VARIANTS], 'test-types/*': [PASS, NO_VARIANTS], - # BUG(2999). - 'test-cpu-profiler/CollectCpuProfile': [PASS, FLAKY], - # BUG(3287). - 'test-cpu-profiler/SampleWhenFrameIsNotSetup': [PASS, FLAKY], - # BUG(3308). - 'test-cpu-profiler/JsNativeJsRuntimeJsSample': [PASS, FLAKY], + # The cpu profiler tests are notoriously flaky. + # BUG(2999). (test/cpu-profiler/CollectCpuProfile) + # BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup) + 'test-cpu-profiler/*': [PASS, FLAKY], + + ############################################################################## + # TurboFan compiler failures. + + # TODO(mstarzinger): These need investigation and are not categorized yet. + 'test-cpu-profiler/*': [SKIP], + 'test-heap/NextCodeLinkIsWeak': [PASS, NO_VARIANTS], + + # TODO(mstarzinger/verwaest): This access check API is borked. + 'test-api/TurnOnAccessCheck': [PASS, NO_VARIANTS], + 'test-api/TurnOnAccessCheckAndRecompile': [PASS, NO_VARIANTS], + + # TODO(mstarzinger): Sometimes the try-catch blacklist fails. + 'test-debug/DebugEvaluateWithoutStack': [PASS, NO_VARIANTS], + 'test-debug/MessageQueues': [PASS, NO_VARIANTS], + 'test-debug/NestedBreakEventContextData': [PASS, NO_VARIANTS], + 'test-debug/SendClientDataToHandler': [PASS, NO_VARIANTS], + + # TODO(dcarney): C calls are broken all over the place. + 'test-run-machops/RunCall*': [SKIP], + 'test-run-machops/RunLoadImmIndex': [SKIP], + 'test-run-machops/RunSpillLotsOfThingsWithCall': [SKIP], + + # Some tests are just too slow to run for now. + 'test-api/Threading*': [PASS, NO_VARIANTS], + 'test-api/RequestInterruptTestWithMathAbs': [PASS, NO_VARIANTS], + 'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [PASS, NO_VARIANTS], + 'test-heap-profiler/ManyLocalsInSharedContext': [PASS, NO_VARIANTS], + 'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS], + 'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS], + + # Support for lazy deoptimization is missing. + 'test-deoptimization/DeoptimizeCompare': [PASS, NO_VARIANTS], + + # Support for breakpoints requires using LoadICs and StoreICs. + 'test-debug/BreakPointICStore': [PASS, NO_VARIANTS], + 'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS], + 'test-debug/BreakPointICCall': [PASS, NO_VARIANTS], + 'test-debug/BreakPointICCallWithGC': [PASS, NO_VARIANTS], + 'test-debug/BreakPointConstructCallWithGC': [PASS, NO_VARIANTS], + 'test-debug/BreakPointReturn': [PASS, NO_VARIANTS], + 'test-debug/BreakPointThroughJavaScript': [PASS, NO_VARIANTS], + 'test-debug/ScriptBreakPointByNameThroughJavaScript': [PASS, NO_VARIANTS], + 'test-debug/ScriptBreakPointByIdThroughJavaScript': [PASS, NO_VARIANTS], + 'test-debug/DebugStepLinear': [PASS, NO_VARIANTS], + 'test-debug/DebugStepKeyedLoadLoop': [PASS, NO_VARIANTS], + 'test-debug/DebugStepKeyedStoreLoop': [PASS, NO_VARIANTS], + 'test-debug/DebugStepNamedLoadLoop': [PASS, NO_VARIANTS], + 'test-debug/DebugStepNamedStoreLoop': [PASS, NO_VARIANTS], + 'test-debug/DebugStepLinearMixedICs': [PASS, NO_VARIANTS], + 'test-debug/DebugStepDeclarations': [PASS, NO_VARIANTS], + 'test-debug/DebugStepLocals': [PASS, NO_VARIANTS], + 'test-debug/DebugStepIf': [PASS, NO_VARIANTS], + 'test-debug/DebugStepSwitch': [PASS, NO_VARIANTS], + 'test-debug/DebugStepWhile': [PASS, NO_VARIANTS], + 'test-debug/DebugStepDoWhile': [PASS, NO_VARIANTS], + 'test-debug/DebugStepFor': [PASS, NO_VARIANTS], + 'test-debug/DebugStepForContinue': [PASS, NO_VARIANTS], + 'test-debug/DebugStepForBreak': [PASS, NO_VARIANTS], + 'test-debug/DebugStepForIn': [PASS, NO_VARIANTS], + 'test-debug/DebugStepWith': [PASS, NO_VARIANTS], + 'test-debug/DebugConditional': [PASS, NO_VARIANTS], + 'test-debug/StepInOutSimple': [PASS, NO_VARIANTS], + 'test-debug/StepInOutTree': [PASS, NO_VARIANTS], + 'test-debug/StepInOutBranch': [PASS, NO_VARIANTS], + 'test-debug/DebugBreak': [PASS, NO_VARIANTS], + 'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS], + 'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS], + 'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS], + 'test-debug/DisableBreak': [PASS, NO_VARIANTS], + 'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS], + 'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS], + 'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS], + + # Support for %GetFrameDetails is missing and requires checkpoints. + 'test-api/Regress385349': [PASS, NO_VARIANTS], + 'test-debug/DebuggerStatement': [PASS, NO_VARIANTS], + 'test-debug/DebuggerStatementBreakpoint': [PASS, NO_VARIANTS], + 'test-debug/DebugEvaluateWithCodeGenerationDisallowed': [PASS, NO_VARIANTS], + 'test-debug/DebugStepNatives': [PASS, NO_VARIANTS], + 'test-debug/DebugStepFunctionCall': [PASS, NO_VARIANTS], + 'test-debug/DebugStepFunctionApply': [PASS, NO_VARIANTS], + 'test-debug/ScriptNameAndData': [PASS, NO_VARIANTS], + 'test-debug/ContextData': [PASS, NO_VARIANTS], + 'test-debug/DebugBreakInMessageHandler': [PASS, NO_VARIANTS], + 'test-debug/CallFunctionInDebugger': [PASS, NO_VARIANTS], + 'test-debug/CallingContextIsNotDebugContext': [PASS, NO_VARIANTS], + 'test-debug/DebugEventContext': [PASS, NO_VARIANTS], + 'test-debug/DebugBreakInline': [PASS, NO_VARIANTS], ############################################################################ # Slow tests. @@ -90,6 +179,10 @@ 'test-api/Bug618': [PASS], + # BUG(v8:3385). + 'test-serialize/DeserializeFromSecondSerialization': [PASS, FAIL], + 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [PASS, FAIL], + # BUG(v8:2999). 'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL], @@ -101,6 +194,12 @@ # BUG(v8:3247). 'test-mark-compact/NoPromotion': [SKIP], + + # BUG(v8:3446). + 'test-mark-compact/Promotion': [PASS, FAIL], + + # BUG(v8:3434). + ' test-api/LoadICFastApi_DirectCall_GCMoveStubWithProfiler': [SKIP] }], # 'arch == arm64' ['arch == arm64 and simulator_run == True', { @@ -132,7 +231,7 @@ ############################################################################## ['no_snap == True', { # BUG(3215) - 'test-lockers/MultithreadedParallelIsolates': [PASS, FAIL], + 'test-lockers/MultithreadedParallelIsolates': [PASS, FAIL, TIMEOUT], }], # 'no_snap == True' ############################################################################## @@ -148,16 +247,19 @@ # BUG(2999). 'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL], - 'test-cpu-profiler/JsNativeJsSample': [PASS, FLAKY], - - # BUG(3055). - 'test-cpu-profiler/JsNative1JsNative2JsSample': [PASS, ['mode == release', FAIL], ['mode == debug', FLAKY]], # BUG(3005). 'test-alloc/CodeRange': [PASS, FAIL], # BUG(3215). Crashes on windows. 'test-lockers/MultithreadedParallelIsolates': [SKIP], + + # BUG(3331). Fails on windows. + 'test-heap/NoWeakHashTableLeakWithIncrementalMarking': [SKIP], + + # BUG(v8:3433). Crashes on windows. + 'test-cpu-profiler/FunctionApplySample': [SKIP], + }], # 'system == windows' ############################################################################## @@ -187,6 +289,10 @@ 'test-api/Threading2': [PASS, SLOW], 'test-api/Threading3': [PASS, SLOW], 'test-api/Threading4': [PASS, SLOW], + + # Crashes due to OOM in simulator. + 'test-types/Distributivity1': [PASS, FLAKY], + 'test-types/Distributivity2': [PASS, FLAKY], }], # 'arch == arm' ############################################################################## @@ -203,6 +309,39 @@ }], # 'arch == mipsel or arch == mips' ############################################################################## +['arch == mips64el', { + + # BUG(2657): Test sometimes times out on MIPS simulator. + 'test-thread-termination/TerminateMultipleV8ThreadsDefaultIsolate': [PASS, TIMEOUT], + + # BUG(v8:3154). + 'test-heap/ReleaseOverReservedPages': [PASS, FAIL], + + # BUG(1075): Unresolved crashes on MIPS also. + 'test-serialize/Deserialize': [SKIP], + 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP], + 'test-serialize/DeserializeAndRunScript2': [SKIP], + 'test-serialize/DeserializeFromSecondSerialization': [SKIP], +}], # 'arch == mips64el' + +############################################################################## +['arch == x87', { + + # TODO (weiliang): Enable below tests after fixing the double register + # allocation limit in X87 port. + 'test-serialize/Serialize': [PASS, ['mode == debug', SKIP]], + 'test-serialize/Deserialize': [PASS, ['mode == debug', SKIP]], + 'test-serialize/SerializeTwice': [PASS, ['mode == debug', SKIP]], + 'test-serialize/ContextSerialization': [PASS, ['mode == debug', SKIP]], + 'test-serialize/ContextDeserialization': [PASS, ['mode == debug', SKIP]], + 'test-serialize/PartialDeserialization': [PASS, ['mode == debug', SKIP]], + 'test-serialize/PartialSerialization': [PASS, ['mode == debug', SKIP]], + 'test-serialize/DeserializeAndRunScript2': [PASS, ['mode == debug', SKIP]], + 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [PASS, ['mode == debug', SKIP]], + 'test-serialize/DeserializeFromSecondSerialization': [PASS, ['mode == debug', SKIP]], +}], # 'arch == x87' + +############################################################################## ['arch == android_arm or arch == android_ia32', { # Tests crash as there is no /tmp directory in Android. diff --git a/deps/v8/test/cctest/compiler/call-tester.h b/deps/v8/test/cctest/compiler/call-tester.h new file mode 100644 index 0000000000..40189ab405 --- /dev/null +++ b/deps/v8/test/cctest/compiler/call-tester.h @@ -0,0 +1,384 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_CALL_TESTER_H_ +#define V8_CCTEST_COMPILER_CALL_TESTER_H_ + +#include "src/v8.h" + +#include "src/simulator.h" + +#if V8_TARGET_ARCH_IA32 +#if __GNUC__ +#define V8_CDECL __attribute__((cdecl)) +#else +#define V8_CDECL __cdecl +#endif +#else +#define V8_CDECL +#endif + +namespace v8 { +namespace internal { +namespace compiler { + +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 kMachineTagged; + } +}; + +template <> +struct ReturnValueTraits<int32_t*> { + static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); } + static MachineType Representation() { + return MachineOperatorBuilder::pointer_rep(); + } +}; + +template <> +struct ReturnValueTraits<void> { + static void Cast(uintptr_t r) {} + static MachineType Representation() { + return MachineOperatorBuilder::pointer_rep(); + } +}; + +template <> +struct ReturnValueTraits<bool> { + static bool Cast(uintptr_t r) { return static_cast<bool>(r); } + static MachineType Representation() { + return MachineOperatorBuilder::pointer_rep(); + } +}; + +template <> +struct ReturnValueTraits<int32_t> { + static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); } + static MachineType Representation() { return kMachineWord32; } +}; + +template <> +struct ReturnValueTraits<uint32_t> { + static uint32_t Cast(uintptr_t r) { return static_cast<uint32_t>(r); } + static MachineType Representation() { return kMachineWord32; } +}; + +template <> +struct ReturnValueTraits<int64_t> { + static int64_t Cast(uintptr_t r) { return static_cast<int64_t>(r); } + static MachineType Representation() { return kMachineWord64; } +}; + +template <> +struct ReturnValueTraits<uint64_t> { + static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); } + static MachineType Representation() { return kMachineWord64; } +}; + +template <> +struct ReturnValueTraits<int16_t> { + static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); } + static MachineType Representation() { + return MachineOperatorBuilder::pointer_rep(); + } +}; + +template <> +struct ReturnValueTraits<int8_t> { + static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); } + static MachineType Representation() { + return MachineOperatorBuilder::pointer_rep(); + } +}; + +template <> +struct ReturnValueTraits<double> { + static double Cast(uintptr_t r) { + UNREACHABLE(); + return 0.0; + } + static MachineType Representation() { return kMachineFloat64; } +}; + + +template <typename R> +struct ParameterTraits { + static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); } +}; + +template <> +struct ParameterTraits<int*> { + static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); } +}; + +template <typename T> +struct ParameterTraits<T*> { + static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); } +}; + +class CallHelper { + public: + explicit CallHelper(Isolate* isolate) : isolate_(isolate) { USE(isolate_); } + virtual ~CallHelper() {} + + static MachineCallDescriptorBuilder* ToCallDescriptorBuilder( + Zone* zone, MachineType return_type, MachineType p0 = kMachineLast, + MachineType p1 = kMachineLast, MachineType p2 = kMachineLast, + MachineType p3 = kMachineLast, MachineType p4 = kMachineLast) { + const int kSize = 5; + MachineType* params = zone->NewArray<MachineType>(kSize); + params[0] = p0; + params[1] = p1; + params[2] = p2; + params[3] = p3; + params[4] = p4; + int parameter_count = 0; + for (int i = 0; i < kSize; ++i) { + if (params[i] == kMachineLast) { + break; + } + parameter_count++; + } + return new (zone) + MachineCallDescriptorBuilder(return_type, parameter_count, params); + } + + protected: + virtual void VerifyParameters(int parameter_count, + MachineType* parameters) = 0; + virtual byte* Generate() = 0; + + private: +#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64 + uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) { + Simulator* simulator = Simulator::current(isolate_); + return static_cast<uintptr_t>(simulator->CallInt64(f, args)); + } + + template <typename R, typename F> + R DoCall(F* f) { + Simulator::CallArgument args[] = {Simulator::CallArgument::End()}; + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + } + template <typename R, typename F, typename P1> + R DoCall(F* f, P1 p1) { + Simulator::CallArgument args[] = {Simulator::CallArgument(p1), + Simulator::CallArgument::End()}; + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + } + template <typename R, typename F, typename P1, typename P2> + R DoCall(F* f, P1 p1, P2 p2) { + Simulator::CallArgument args[] = {Simulator::CallArgument(p1), + Simulator::CallArgument(p2), + Simulator::CallArgument::End()}; + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + } + template <typename R, typename F, typename P1, typename P2, typename P3> + R DoCall(F* f, P1 p1, P2 p2, P3 p3) { + Simulator::CallArgument args[] = { + Simulator::CallArgument(p1), Simulator::CallArgument(p2), + Simulator::CallArgument(p3), Simulator::CallArgument::End()}; + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + } + template <typename R, typename F, typename P1, typename P2, typename P3, + typename P4> + R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { + Simulator::CallArgument args[] = { + Simulator::CallArgument(p1), Simulator::CallArgument(p2), + Simulator::CallArgument(p3), Simulator::CallArgument(p4), + Simulator::CallArgument::End()}; + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args)); + } +#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM + uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0, + int32_t p3 = 0, int32_t p4 = 0) { + Simulator* simulator = Simulator::current(isolate_); + return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4)); + } + template <typename R, typename F> + R DoCall(F* f) { + return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f))); + } + template <typename R, typename F, typename P1> + R DoCall(F* f, P1 p1) { + return ReturnValueTraits<R>::Cast( + CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1))); + } + template <typename R, typename F, typename P1, typename P2> + R DoCall(F* f, P1 p1, P2 p2) { + return ReturnValueTraits<R>::Cast( + CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1), + ParameterTraits<P2>::Cast(p2))); + } + template <typename R, typename F, typename P1, typename P2, typename P3> + R DoCall(F* f, P1 p1, P2 p2, P3 p3) { + return ReturnValueTraits<R>::Cast(CallSimulator( + FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1), + ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3))); + } + template <typename R, typename F, typename P1, typename P2, typename P3, + typename P4> + R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { + return ReturnValueTraits<R>::Cast(CallSimulator( + FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1), + ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3), + ParameterTraits<P4>::Cast(p4))); + } +#else + template <typename R, typename F> + R DoCall(F* f) { + return f(); + } + template <typename R, typename F, typename P1> + R DoCall(F* f, P1 p1) { + return f(p1); + } + template <typename R, typename F, typename P1, typename P2> + R DoCall(F* f, P1 p1, P2 p2) { + return f(p1, p2); + } + template <typename R, typename F, typename P1, typename P2, typename P3> + R DoCall(F* f, P1 p1, P2 p2, P3 p3) { + return f(p1, p2, p3); + } + template <typename R, typename F, typename P1, typename P2, typename P3, + typename P4> + R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { + return f(p1, p2, p3, p4); + } +#endif + +#ifndef DEBUG + void VerifyParameters0() {} + + template <typename P1> + void VerifyParameters1() {} + + template <typename P1, typename P2> + void VerifyParameters2() {} + + template <typename P1, typename P2, typename P3> + void VerifyParameters3() {} + + template <typename P1, typename P2, typename P3, typename P4> + void VerifyParameters4() {} +#else + void VerifyParameters0() { VerifyParameters(0, NULL); } + + template <typename P1> + void VerifyParameters1() { + MachineType parameters[] = {ReturnValueTraits<P1>::Representation()}; + VerifyParameters(ARRAY_SIZE(parameters), parameters); + } + + template <typename P1, typename P2> + void VerifyParameters2() { + MachineType parameters[] = {ReturnValueTraits<P1>::Representation(), + ReturnValueTraits<P2>::Representation()}; + VerifyParameters(ARRAY_SIZE(parameters), parameters); + } + + template <typename P1, typename P2, typename P3> + void VerifyParameters3() { + MachineType parameters[] = {ReturnValueTraits<P1>::Representation(), + ReturnValueTraits<P2>::Representation(), + ReturnValueTraits<P3>::Representation()}; + VerifyParameters(ARRAY_SIZE(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(ARRAY_SIZE(parameters), parameters); + } +#endif + + // TODO(dcarney): replace Call() in CallHelper2 with these. + template <typename R> + R Call0() { + typedef R V8_CDECL FType(); + VerifyParameters0(); + return DoCall<R>(FUNCTION_CAST<FType*>(Generate())); + } + + template <typename R, typename P1> + R Call1(P1 p1) { + typedef R V8_CDECL FType(P1); + VerifyParameters1<P1>(); + return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1); + } + + template <typename R, typename P1, typename P2> + R Call2(P1 p1, P2 p2) { + typedef R V8_CDECL FType(P1, P2); + VerifyParameters2<P1, P2>(); + return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2); + } + + template <typename R, typename P1, typename P2, typename P3> + R Call3(P1 p1, P2 p2, P3 p3) { + typedef R V8_CDECL FType(P1, P2, P3); + VerifyParameters3<P1, P2, P3>(); + return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3); + } + + template <typename R, typename P1, typename P2, typename P3, typename P4> + R Call4(P1 p1, P2 p2, P3 p3, P4 p4) { + typedef R V8_CDECL FType(P1, P2, P3, P4); + VerifyParameters4<P1, P2, P3, P4>(); + return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4); + } + + template <typename R, typename C> + friend class CallHelper2; + Isolate* isolate_; +}; + + +// TODO(dcarney): replace CallHelper with CallHelper2 and rename. +template <typename R, typename C> +class CallHelper2 { + public: + R Call() { return helper()->template Call0<R>(); } + + template <typename P1> + R Call(P1 p1) { + return helper()->template Call1<R>(p1); + } + + template <typename P1, typename P2> + R Call(P1 p1, P2 p2) { + return helper()->template Call2<R>(p1, p2); + } + + template <typename P1, typename P2, typename P3> + R Call(P1 p1, P2 p2, P3 p3) { + return helper()->template Call3<R>(p1, p2, p3); + } + + template <typename P1, typename P2, typename P3, typename P4> + R Call(P1 p1, P2 p2, P3 p3, P4 p4) { + return helper()->template Call4<R>(p1, p2, p3, p4); + } + + private: + CallHelper* helper() { return static_cast<C*>(this); } +}; + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_CALL_TESTER_H_ diff --git a/deps/v8/test/cctest/compiler/codegen-tester.cc b/deps/v8/test/cctest/compiler/codegen-tester.cc new file mode 100644 index 0000000000..24b2c6e9f0 --- /dev/null +++ b/deps/v8/test/cctest/compiler/codegen-tester.cc @@ -0,0 +1,578 @@ +// 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 "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(CompareWrapper) { + // Who tests the testers? + // If CompareWrapper is broken, then test expectations will be broken. + RawMachineAssemblerTester<int32_t> m; + CompareWrapper wWord32Equal(IrOpcode::kWord32Equal); + CompareWrapper wInt32LessThan(IrOpcode::kInt32LessThan); + CompareWrapper wInt32LessThanOrEqual(IrOpcode::kInt32LessThanOrEqual); + CompareWrapper wUint32LessThan(IrOpcode::kUint32LessThan); + CompareWrapper wUint32LessThanOrEqual(IrOpcode::kUint32LessThanOrEqual); + + { + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t a = *pl; + int32_t b = *pr; + CHECK_EQ(a == b, wWord32Equal.Int32Compare(a, b)); + CHECK_EQ(a < b, wInt32LessThan.Int32Compare(a, b)); + CHECK_EQ(a <= b, wInt32LessThanOrEqual.Int32Compare(a, b)); + } + } + } + + { + FOR_UINT32_INPUTS(pl) { + FOR_UINT32_INPUTS(pr) { + uint32_t a = *pl; + uint32_t b = *pr; + CHECK_EQ(a == b, wWord32Equal.Int32Compare(a, b)); + CHECK_EQ(a < b, wUint32LessThan.Int32Compare(a, b)); + CHECK_EQ(a <= b, wUint32LessThanOrEqual.Int32Compare(a, b)); + } + } + } + + CHECK_EQ(true, wWord32Equal.Int32Compare(0, 0)); + CHECK_EQ(true, wWord32Equal.Int32Compare(257, 257)); + CHECK_EQ(true, wWord32Equal.Int32Compare(65539, 65539)); + CHECK_EQ(true, wWord32Equal.Int32Compare(-1, -1)); + CHECK_EQ(true, wWord32Equal.Int32Compare(0xffffffff, 0xffffffff)); + + CHECK_EQ(false, wWord32Equal.Int32Compare(0, 1)); + CHECK_EQ(false, wWord32Equal.Int32Compare(257, 256)); + CHECK_EQ(false, wWord32Equal.Int32Compare(65539, 65537)); + CHECK_EQ(false, wWord32Equal.Int32Compare(-1, -2)); + CHECK_EQ(false, wWord32Equal.Int32Compare(0xffffffff, 0xfffffffe)); + + CHECK_EQ(false, wInt32LessThan.Int32Compare(0, 0)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(357, 357)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(75539, 75539)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(-1, -1)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(0xffffffff, 0xffffffff)); + + CHECK_EQ(true, wInt32LessThan.Int32Compare(0, 1)); + CHECK_EQ(true, wInt32LessThan.Int32Compare(456, 457)); + CHECK_EQ(true, wInt32LessThan.Int32Compare(85537, 85539)); + CHECK_EQ(true, wInt32LessThan.Int32Compare(-2, -1)); + CHECK_EQ(true, wInt32LessThan.Int32Compare(0xfffffffe, 0xffffffff)); + + CHECK_EQ(false, wInt32LessThan.Int32Compare(1, 0)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(457, 456)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(85539, 85537)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(-1, -2)); + CHECK_EQ(false, wInt32LessThan.Int32Compare(0xffffffff, 0xfffffffe)); + + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0, 0)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(357, 357)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(75539, 75539)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(-1, -1)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0xffffffff, 0xffffffff)); + + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0, 1)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(456, 457)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(85537, 85539)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(-2, -1)); + CHECK_EQ(true, wInt32LessThanOrEqual.Int32Compare(0xfffffffe, 0xffffffff)); + + CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(1, 0)); + CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(457, 456)); + CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(85539, 85537)); + CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(-1, -2)); + CHECK_EQ(false, wInt32LessThanOrEqual.Int32Compare(0xffffffff, 0xfffffffe)); + + // Unsigned comparisons. + CHECK_EQ(false, wUint32LessThan.Int32Compare(0, 0)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(357, 357)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(75539, 75539)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(-1, -1)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0xffffffff)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(-2999, 0)); + + CHECK_EQ(true, wUint32LessThan.Int32Compare(0, 1)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(456, 457)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(85537, 85539)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(-11, -10)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(0xfffffffe, 0xffffffff)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(0, 0xffffffff)); + CHECK_EQ(true, wUint32LessThan.Int32Compare(0, -2996)); + + CHECK_EQ(false, wUint32LessThan.Int32Compare(1, 0)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(457, 456)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(85539, 85537)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(-10, -21)); + CHECK_EQ(false, wUint32LessThan.Int32Compare(0xffffffff, 0xfffffffe)); + + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, 0)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(357, 357)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(75539, 75539)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-1, -1)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0xffffffff, 0xffffffff)); + + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, 1)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(456, 457)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(85537, 85539)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-300, -299)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(-300, -300)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0xfffffffe, 0xffffffff)); + CHECK_EQ(true, wUint32LessThanOrEqual.Int32Compare(0, -2995)); + + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(1, 0)); + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(457, 456)); + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(85539, 85537)); + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(-130, -170)); + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(0xffffffff, 0xfffffffe)); + CHECK_EQ(false, wUint32LessThanOrEqual.Int32Compare(-2997, 0)); + + CompareWrapper wFloat64Equal(IrOpcode::kFloat64Equal); + CompareWrapper wFloat64LessThan(IrOpcode::kFloat64LessThan); + CompareWrapper wFloat64LessThanOrEqual(IrOpcode::kFloat64LessThanOrEqual); + + // Check NaN handling. + double nan = v8::base::OS::nan_value(); + double inf = V8_INFINITY; + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, 0.0)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, 1.0)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, -inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, nan)); + + CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, nan)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, nan)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, nan)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, nan)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(nan, nan)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, 0.0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, 1.0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, -inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, nan)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(0.0, nan)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(1.0, nan)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, nan)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, nan)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(nan, nan)); + + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, 0.0)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, 1.0)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, inf)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, -inf)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, nan)); + + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(0.0, nan)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1.0, nan)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, nan)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(-inf, nan)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(nan, nan)); + + // Check inf handling. + CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, 0.0)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, 1.0)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(inf, inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, -inf)); + + CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, inf)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(inf, inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, inf)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, 0.0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, 1.0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, -inf)); + + CHECK_EQ(true, wFloat64LessThan.Float64Compare(0.0, inf)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(1.0, inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, inf)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, inf)); + + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, 0.0)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, 1.0)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(inf, inf)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, -inf)); + + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0.0, inf)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(1.0, inf)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(inf, inf)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, inf)); + + // Check -inf handling. + CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, 0.0)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, 1.0)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(-inf, inf)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(-inf, -inf)); + + CHECK_EQ(false, wFloat64Equal.Float64Compare(0.0, -inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(1.0, -inf)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(inf, -inf)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(-inf, -inf)); + + CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, 0.0)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, 1.0)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(-inf, inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, -inf)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(0.0, -inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(1.0, -inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(inf, -inf)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(-inf, -inf)); + + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, 0.0)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, 1.0)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, inf)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, -inf)); + + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(0.0, -inf)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1.0, -inf)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(inf, -inf)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-inf, -inf)); + + // Check basic values. + CHECK_EQ(true, wFloat64Equal.Float64Compare(0, 0)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(257.1, 257.1)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(65539.1, 65539.1)); + CHECK_EQ(true, wFloat64Equal.Float64Compare(-1.1, -1.1)); + + CHECK_EQ(false, wFloat64Equal.Float64Compare(0, 1)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(257.2, 256.2)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(65539.2, 65537.2)); + CHECK_EQ(false, wFloat64Equal.Float64Compare(-1.2, -2.2)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(0, 0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(357.3, 357.3)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(75539.3, 75539.3)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(-1.3, -1.3)); + + CHECK_EQ(true, wFloat64LessThan.Float64Compare(0, 1)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(456.4, 457.4)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(85537.4, 85539.4)); + CHECK_EQ(true, wFloat64LessThan.Float64Compare(-2.4, -1.4)); + + CHECK_EQ(false, wFloat64LessThan.Float64Compare(1, 0)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(457.5, 456.5)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(85539.5, 85537.5)); + CHECK_EQ(false, wFloat64LessThan.Float64Compare(-1.5, -2.5)); + + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0, 0)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(357.6, 357.6)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(75539.6, 75539.6)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-1.6, -1.6)); + + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(0, 1)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(456.7, 457.7)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(85537.7, 85539.7)); + CHECK_EQ(true, wFloat64LessThanOrEqual.Float64Compare(-2.7, -1.7)); + + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(1, 0)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(457.8, 456.8)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(85539.8, 85537.8)); + CHECK_EQ(false, wFloat64LessThanOrEqual.Float64Compare(-1.8, -2.8)); +} + + +void Int32BinopInputShapeTester::TestAllInputShapes() { + std::vector<int32_t> inputs = ValueHelper::int32_vector(); + int num_int_inputs = static_cast<int>(inputs.size()); + if (num_int_inputs > 16) num_int_inputs = 16; // limit to 16 inputs + + for (int i = -2; i < num_int_inputs; i++) { // for all left shapes + for (int j = -2; j < num_int_inputs; j++) { // for all right shapes + if (i >= 0 && j >= 0) break; // No constant/constant combos + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + Node* n0; + Node* n1; + + // left = Parameter | Load | Constant + if (i == -2) { + n0 = p0; + } else if (i == -1) { + n0 = m.LoadFromPointer(&input_a, kMachineWord32); + } else { + n0 = m.Int32Constant(inputs[i]); + } + + // right = Parameter | Load | Constant + if (j == -2) { + n1 = p1; + } else if (j == -1) { + n1 = m.LoadFromPointer(&input_b, kMachineWord32); + } else { + n1 = m.Int32Constant(inputs[j]); + } + + gen->gen(&m, n0, n1); + + if (false) printf("Int32BinopInputShapeTester i=%d, j=%d\n", i, j); + if (i >= 0) { + input_a = inputs[i]; + RunRight(&m); + } else if (j >= 0) { + input_b = inputs[j]; + RunLeft(&m); + } else { + Run(&m); + } + } + } +} + + +void Int32BinopInputShapeTester::Run(RawMachineAssemblerTester<int32_t>* m) { + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + input_a = *pl; + input_b = *pr; + int32_t expect = gen->expected(input_a, input_b); + if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect); + CHECK_EQ(expect, m->Call(input_a, input_b)); + } + } +} + + +void Int32BinopInputShapeTester::RunLeft( + RawMachineAssemblerTester<int32_t>* m) { + FOR_UINT32_INPUTS(i) { + input_a = *i; + int32_t expect = gen->expected(input_a, input_b); + if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect); + CHECK_EQ(expect, m->Call(input_a, input_b)); + } +} + + +void Int32BinopInputShapeTester::RunRight( + RawMachineAssemblerTester<int32_t>* m) { + FOR_UINT32_INPUTS(i) { + input_b = *i; + int32_t expect = gen->expected(input_a, input_b); + if (false) printf(" cmp(a=%d, b=%d) ?== %d\n", input_a, input_b, expect); + CHECK_EQ(expect, m->Call(input_a, input_b)); + } +} + + +TEST(ParametersEqual) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* p1 = m.Parameter(1); + CHECK_NE(NULL, p1); + Node* p0 = m.Parameter(0); + CHECK_NE(NULL, p0); + CHECK_EQ(p0, m.Parameter(0)); + CHECK_EQ(p1, m.Parameter(1)); +} + + +#if V8_TURBOFAN_TARGET + +void RunSmiConstant(int32_t v) { +// TODO(dcarney): on x64 Smis are generated with the SmiConstantRegister +#if !V8_TARGET_ARCH_X64 + if (Smi::IsValid(v)) { + RawMachineAssemblerTester<Object*> m; + m.Return(m.NumberConstant(v)); + CHECK_EQ(Smi::FromInt(v), m.Call()); + } +#endif +} + + +void RunNumberConstant(double v) { + RawMachineAssemblerTester<Object*> m; +#if V8_TARGET_ARCH_X64 + // TODO(dcarney): on x64 Smis are generated with the SmiConstantRegister + Handle<Object> number = m.isolate()->factory()->NewNumber(v); + if (number->IsSmi()) return; +#endif + m.Return(m.NumberConstant(v)); + Object* result = m.Call(); + m.CheckNumber(v, result); +} + + +TEST(RunEmpty) { + RawMachineAssemblerTester<int32_t> m; + m.Return(m.Int32Constant(0)); + CHECK_EQ(0, m.Call()); +} + + +TEST(RunInt32Constants) { + FOR_INT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + m.Return(m.Int32Constant(*i)); + CHECK_EQ(*i, m.Call()); + } +} + + +TEST(RunSmiConstants) { + for (int32_t i = 1; i < Smi::kMaxValue && i != 0; i = i << 1) { + RunSmiConstant(i); + RunSmiConstant(3 * i); + RunSmiConstant(5 * i); + RunSmiConstant(-i); + RunSmiConstant(i | 1); + RunSmiConstant(i | 3); + } + RunSmiConstant(Smi::kMaxValue); + RunSmiConstant(Smi::kMaxValue - 1); + RunSmiConstant(Smi::kMinValue); + RunSmiConstant(Smi::kMinValue + 1); + + FOR_INT32_INPUTS(i) { RunSmiConstant(*i); } +} + + +TEST(RunNumberConstants) { + { + FOR_FLOAT64_INPUTS(i) { RunNumberConstant(*i); } + } + { + FOR_INT32_INPUTS(i) { RunNumberConstant(*i); } + } + + for (int32_t i = 1; i < Smi::kMaxValue && i != 0; i = i << 1) { + RunNumberConstant(i); + RunNumberConstant(-i); + RunNumberConstant(i | 1); + RunNumberConstant(i | 3); + } + RunNumberConstant(Smi::kMaxValue); + RunNumberConstant(Smi::kMaxValue - 1); + RunNumberConstant(Smi::kMinValue); + RunNumberConstant(Smi::kMinValue + 1); +} + + +TEST(RunEmptyString) { + RawMachineAssemblerTester<Object*> m; + m.Return(m.StringConstant("empty")); + m.CheckString("empty", m.Call()); +} + + +TEST(RunHeapConstant) { + RawMachineAssemblerTester<Object*> m; + m.Return(m.StringConstant("empty")); + m.CheckString("empty", m.Call()); +} + + +TEST(RunHeapNumberConstant) { + RawMachineAssemblerTester<Object*> m; + Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5); + m.Return(m.HeapConstant(number)); + Object* result = m.Call(); + CHECK_EQ(result, *number); +} + + +TEST(RunParam1) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Parameter(0)); + + FOR_INT32_INPUTS(i) { + int32_t result = m.Call(*i); + CHECK_EQ(*i, result); + } +} + + +TEST(RunParam2_1) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + m.Return(p0); + USE(p1); + + FOR_INT32_INPUTS(i) { + int32_t result = m.Call(*i, -9999); + CHECK_EQ(*i, result); + } +} + + +TEST(RunParam2_2) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + m.Return(p1); + USE(p0); + + FOR_INT32_INPUTS(i) { + int32_t result = m.Call(-7777, *i); + CHECK_EQ(*i, result); + } +} + + +TEST(RunParam3) { + for (int i = 0; i < 3; i++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + Node* nodes[] = {m.Parameter(0), m.Parameter(1), m.Parameter(2)}; + m.Return(nodes[i]); + + int p[] = {-99, -77, -88}; + FOR_INT32_INPUTS(j) { + p[i] = *j; + int32_t result = m.Call(p[0], p[1], p[2]); + CHECK_EQ(*j, result); + } + } +} + + +TEST(RunBinopTester) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(bt.param0); + + FOR_INT32_INPUTS(i) { CHECK_EQ(*i, bt.call(*i, 777)); } + } + + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(bt.param1); + + FOR_INT32_INPUTS(i) { CHECK_EQ(*i, bt.call(666, *i)); } + } + + { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + bt.AddReturn(bt.param0); + + FOR_FLOAT64_INPUTS(i) { CHECK_EQ(*i, bt.call(*i, 9.0)); } + } + + { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + bt.AddReturn(bt.param1); + + FOR_FLOAT64_INPUTS(i) { CHECK_EQ(*i, bt.call(-11.25, *i)); } + } +} + +#endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/codegen-tester.h b/deps/v8/test/cctest/compiler/codegen-tester.h new file mode 100644 index 0000000000..300381b493 --- /dev/null +++ b/deps/v8/test/cctest/compiler/codegen-tester.h @@ -0,0 +1,353 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_CODEGEN_TESTER_H_ +#define V8_CCTEST_COMPILER_CODEGEN_TESTER_H_ + +#include "src/v8.h" + +#include "src/compiler/pipeline.h" +#include "src/compiler/raw-machine-assembler.h" +#include "src/compiler/structured-machine-assembler.h" +#include "src/simulator.h" +#include "test/cctest/compiler/call-tester.h" + +namespace v8 { +namespace internal { +namespace compiler { + +template <typename MachineAssembler> +class MachineAssemblerTester : public HandleAndZoneScope, + public CallHelper, + public MachineAssembler { + public: + MachineAssemblerTester(MachineType return_type, MachineType p0, + MachineType p1, MachineType p2, MachineType p3, + MachineType p4) + : HandleAndZoneScope(), + CallHelper(main_isolate()), + MachineAssembler(new (main_zone()) Graph(main_zone()), + ToCallDescriptorBuilder(main_zone(), return_type, p0, + p1, p2, p3, p4), + MachineOperatorBuilder::pointer_rep()) {} + + 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)); + } + + void CheckNumber(double expected, Object* number) { + CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number)); + } + + void CheckString(const char* expected, Object* string) { + CHECK( + this->isolate()->factory()->InternalizeUtf8String(expected)->SameValue( + string)); + } + + void GenerateCode() { Generate(); } + + protected: + virtual void VerifyParameters(int parameter_count, + MachineType* parameter_types) { + CHECK_EQ(this->parameter_count(), parameter_count); + const MachineType* expected_types = this->parameter_types(); + for (int i = 0; i < parameter_count; i++) { + CHECK_EQ(expected_types[i], parameter_types[i]); + } + } + + virtual byte* Generate() { + if (code_.is_null()) { + Schedule* schedule = this->Export(); + CallDescriptor* call_descriptor = this->call_descriptor(); + Graph* graph = this->graph(); + CompilationInfo info(graph->zone()->isolate(), graph->zone()); + Linkage linkage(&info, call_descriptor); + Pipeline pipeline(&info); + code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph, schedule); + } + return this->code_.ToHandleChecked()->entry(); + } + + private: + MaybeHandle<Code> code_; +}; + + +template <typename ReturnType> +class RawMachineAssemblerTester + : public MachineAssemblerTester<RawMachineAssembler>, + public CallHelper2<ReturnType, RawMachineAssemblerTester<ReturnType> > { + public: + RawMachineAssemblerTester(MachineType p0 = kMachineLast, + MachineType p1 = kMachineLast, + MachineType p2 = kMachineLast, + MachineType p3 = kMachineLast, + MachineType p4 = kMachineLast) + : MachineAssemblerTester<RawMachineAssembler>( + ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, + p4) {} + + 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)); + } + } + } +}; + + +template <typename ReturnType> +class StructuredMachineAssemblerTester + : public MachineAssemblerTester<StructuredMachineAssembler>, + public CallHelper2<ReturnType, + StructuredMachineAssemblerTester<ReturnType> > { + public: + StructuredMachineAssemblerTester(MachineType p0 = kMachineLast, + MachineType p1 = kMachineLast, + MachineType p2 = kMachineLast, + MachineType p3 = kMachineLast, + MachineType p4 = kMachineLast) + : MachineAssemblerTester<StructuredMachineAssembler>( + ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, + p4) {} +}; + + +static const bool USE_RESULT_BUFFER = true; +static const bool USE_RETURN_REGISTER = false; +static const int32_t CHECK_VALUE = 0x99BEEDCE; + + +// TODO(titzer): use the C-style calling convention, or any register-based +// calling convention for binop tests. +template <typename CType, MachineType rep, bool use_result_buffer> +class BinopTester { + public: + explicit BinopTester(RawMachineAssemblerTester<int32_t>* tester) + : T(tester), + param0(T->LoadFromPointer(&p0, rep)), + param1(T->LoadFromPointer(&p1, rep)), + p0(static_cast<CType>(0)), + p1(static_cast<CType>(0)), + result(static_cast<CType>(0)) {} + + RawMachineAssemblerTester<int32_t>* T; + Node* param0; + Node* param1; + + CType call(CType a0, CType a1) { + p0 = a0; + p1 = a1; + if (use_result_buffer) { + CHECK_EQ(CHECK_VALUE, T->Call()); + return result; + } else { + return T->Call(); + } + } + + void AddReturn(Node* val) { + if (use_result_buffer) { + T->Store(rep, T->PointerConstant(&result), T->Int32Constant(0), val); + T->Return(T->Int32Constant(CHECK_VALUE)); + } else { + T->Return(val); + } + } + + 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)); + } + } + } + + protected: + CType p0; + CType p1; + CType result; +}; + + +// A helper class for testing code sequences that take two int parameters and +// return an int value. +class Int32BinopTester + : public BinopTester<int32_t, kMachineWord32, USE_RETURN_REGISTER> { + public: + explicit Int32BinopTester(RawMachineAssemblerTester<int32_t>* tester) + : BinopTester<int32_t, kMachineWord32, USE_RETURN_REGISTER>(tester) {} + + int32_t call(uint32_t a0, uint32_t a1) { + p0 = static_cast<int32_t>(a0); + p1 = static_cast<int32_t>(a1); + return T->Call(); + } +}; + + +// A helper class for testing code sequences that take two double parameters and +// return a double value. +// TODO(titzer): figure out how to return doubles correctly on ia32. +class Float64BinopTester + : public BinopTester<double, kMachineFloat64, USE_RESULT_BUFFER> { + public: + explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester) + : BinopTester<double, kMachineFloat64, USE_RESULT_BUFFER>(tester) {} +}; + + +// A helper class for testing code sequences that take two pointer parameters +// and return a pointer value. +// TODO(titzer): pick word size of pointers based on V8_TARGET. +template <typename Type> +class PointerBinopTester + : public BinopTester<Type*, kMachineWord32, USE_RETURN_REGISTER> { + public: + explicit PointerBinopTester(RawMachineAssemblerTester<int32_t>* tester) + : BinopTester<Type*, kMachineWord32, USE_RETURN_REGISTER>(tester) {} +}; + + +// A helper class for testing code sequences that take two tagged parameters and +// return a tagged value. +template <typename Type> +class TaggedBinopTester + : public BinopTester<Type*, kMachineTagged, USE_RETURN_REGISTER> { + public: + explicit TaggedBinopTester(RawMachineAssemblerTester<int32_t>* tester) + : BinopTester<Type*, kMachineTagged, USE_RETURN_REGISTER>(tester) {} +}; + +// A helper class for testing compares. Wraps a machine opcode and provides +// evaluation routines and the operators. +class CompareWrapper { + public: + explicit CompareWrapper(IrOpcode::Value op) : opcode(op) {} + + Node* MakeNode(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) { + return m->NewNode(op(m->machine()), a, b); + } + + Operator* op(MachineOperatorBuilder* machine) { + switch (opcode) { + case IrOpcode::kWord32Equal: + return machine->Word32Equal(); + case IrOpcode::kInt32LessThan: + return machine->Int32LessThan(); + case IrOpcode::kInt32LessThanOrEqual: + return machine->Int32LessThanOrEqual(); + case IrOpcode::kUint32LessThan: + return machine->Uint32LessThan(); + case IrOpcode::kUint32LessThanOrEqual: + return machine->Uint32LessThanOrEqual(); + case IrOpcode::kFloat64Equal: + return machine->Float64Equal(); + case IrOpcode::kFloat64LessThan: + return machine->Float64LessThan(); + case IrOpcode::kFloat64LessThanOrEqual: + return machine->Float64LessThanOrEqual(); + default: + UNREACHABLE(); + } + return NULL; + } + + bool Int32Compare(int32_t a, int32_t b) { + switch (opcode) { + case IrOpcode::kWord32Equal: + return a == b; + case IrOpcode::kInt32LessThan: + return a < b; + case IrOpcode::kInt32LessThanOrEqual: + return a <= b; + case IrOpcode::kUint32LessThan: + return static_cast<uint32_t>(a) < static_cast<uint32_t>(b); + case IrOpcode::kUint32LessThanOrEqual: + return static_cast<uint32_t>(a) <= static_cast<uint32_t>(b); + default: + UNREACHABLE(); + } + return false; + } + + bool Float64Compare(double a, double b) { + switch (opcode) { + case IrOpcode::kFloat64Equal: + return a == b; + case IrOpcode::kFloat64LessThan: + return a < b; + case IrOpcode::kFloat64LessThanOrEqual: + return a <= b; + default: + UNREACHABLE(); + } + return false; + } + + IrOpcode::Value opcode; +}; + + +// A small closure class to generate code for a function of two inputs that +// produces a single output so that it can be used in many different contexts. +// The {expected()} method should compute the expected output for a given +// pair of inputs. +template <typename T> +class BinopGen { + public: + virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) = 0; + virtual T expected(T a, T b) = 0; + virtual ~BinopGen() {} +}; + +// A helper class to generate various combination of input shape combinations +// and run the generated code to ensure it produces the correct results. +class Int32BinopInputShapeTester { + public: + explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g) : gen(g) {} + + void TestAllInputShapes(); + + private: + BinopGen<int32_t>* gen; + int32_t input_a; + int32_t input_b; + + void Run(RawMachineAssemblerTester<int32_t>* m); + void RunLeft(RawMachineAssemblerTester<int32_t>* m); + void RunRight(RawMachineAssemblerTester<int32_t>* m); +}; +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_CODEGEN_TESTER_H_ diff --git a/deps/v8/test/cctest/compiler/function-tester.h b/deps/v8/test/cctest/compiler/function-tester.h new file mode 100644 index 0000000000..2ed2fe9988 --- /dev/null +++ b/deps/v8/test/cctest/compiler/function-tester.h @@ -0,0 +1,194 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ +#define V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/compiler.h" +#include "src/compiler/pipeline.h" +#include "src/execution.h" +#include "src/full-codegen.h" +#include "src/handles.h" +#include "src/objects-inl.h" +#include "src/parser.h" +#include "src/rewriter.h" +#include "src/scopes.h" + +#define USE_CRANKSHAFT 0 + +namespace v8 { +namespace internal { +namespace compiler { + +class FunctionTester : public InitializedHandleScope { + public: + explicit FunctionTester(const char* source) + : isolate(main_isolate()), + function((FLAG_allow_natives_syntax = true, NewFunction(source))) { + Compile(function); + } + + Isolate* isolate; + Handle<JSFunction> function; + + Handle<JSFunction> Compile(Handle<JSFunction> function) { +#if V8_TURBOFAN_TARGET + CompilationInfoWithZone info(function); + + CHECK(Parser::Parse(&info)); + StrictMode strict_mode = info.function()->strict_mode(); + info.SetStrictMode(strict_mode); + info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); + CHECK(Rewriter::Rewrite(&info)); + CHECK(Scope::Analyze(&info)); + CHECK_NE(NULL, info.scope()); + + EnsureDeoptimizationSupport(&info); + + Pipeline pipeline(&info); + Handle<Code> code = pipeline.GenerateCode(); + + CHECK(!code.is_null()); + function->ReplaceCode(*code); +#elif USE_CRANKSHAFT + Handle<Code> unoptimized = Handle<Code>(function->code()); + Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, + Compiler::NOT_CONCURRENT); + CHECK(!code.is_null()); +#if ENABLE_DISASSEMBLER + if (FLAG_print_opt_code) { + CodeTracer::Scope tracing_scope(isolate->GetCodeTracer()); + code->Disassemble("test code", tracing_scope.file()); + } +#endif + function->ReplaceCode(*code); +#endif + return function; + } + + static void EnsureDeoptimizationSupport(CompilationInfo* info) { + bool should_recompile = !info->shared_info()->has_deoptimization_support(); + if (should_recompile) { + CompilationInfoWithZone unoptimized(info->shared_info()); + // Note that we use the same AST that we will use for generating the + // optimized code. + unoptimized.SetFunction(info->function()); + unoptimized.PrepareForCompilation(info->scope()); + unoptimized.SetContext(info->context()); + if (should_recompile) unoptimized.EnableDeoptimizationSupport(); + bool succeeded = FullCodeGenerator::MakeCode(&unoptimized); + CHECK(succeeded); + Handle<SharedFunctionInfo> shared = info->shared_info(); + shared->EnableDeoptimizationSupport(*unoptimized.code()); + } + } + + MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) { + Handle<Object> args[] = {a, b}; + return Execution::Call(isolate, function, undefined(), 2, args, false); + } + + void CheckThrows(Handle<Object> a, Handle<Object> b) { + TryCatch try_catch; + MaybeHandle<Object> no_result = Call(a, b); + CHECK(isolate->has_pending_exception()); + CHECK(try_catch.HasCaught()); + CHECK(no_result.is_null()); + // TODO(mstarzinger): Temporary workaround for issue chromium:362388. + isolate->OptionalRescheduleException(true); + } + + v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a, + Handle<Object> b) { + TryCatch try_catch; + MaybeHandle<Object> no_result = Call(a, b); + CHECK(isolate->has_pending_exception()); + CHECK(try_catch.HasCaught()); + CHECK(no_result.is_null()); + // TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack, + // it's the only way to make Message() not to assert because an external + // exception has been caught by the try_catch. + isolate->OptionalRescheduleException(true); + return try_catch.Message(); + } + + void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) { + Handle<Object> result = Call(a, b).ToHandleChecked(); + CHECK(expected->SameValue(*result)); + } + + void CheckCall(Handle<Object> expected, Handle<Object> a) { + CheckCall(expected, a, undefined()); + } + + void CheckCall(Handle<Object> expected) { + CheckCall(expected, undefined(), undefined()); + } + + void CheckCall(double expected, double a, double b) { + CheckCall(Val(expected), Val(a), Val(b)); + } + + void CheckTrue(Handle<Object> a, Handle<Object> b) { + CheckCall(true_value(), a, b); + } + + void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); } + + void CheckTrue(double a, double b) { + CheckCall(true_value(), Val(a), Val(b)); + } + + void CheckFalse(Handle<Object> a, Handle<Object> b) { + CheckCall(false_value(), a, b); + } + + void CheckFalse(Handle<Object> a) { + CheckCall(false_value(), a, undefined()); + } + + void CheckFalse(double a, double b) { + CheckCall(false_value(), Val(a), Val(b)); + } + + Handle<JSFunction> NewFunction(const char* source) { + return v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast(CompileRun(source))); + } + + Handle<JSObject> NewObject(const char* source) { + return v8::Utils::OpenHandle( + *v8::Handle<v8::Object>::Cast(CompileRun(source))); + } + + Handle<String> Val(const char* string) { + return isolate->factory()->InternalizeUtf8String(string); + } + + Handle<Object> Val(double value) { + return isolate->factory()->NewNumber(value); + } + + Handle<Object> infinity() { return isolate->factory()->infinity_value(); } + + Handle<Object> minus_infinity() { return Val(-V8_INFINITY); } + + Handle<Object> nan() { return isolate->factory()->nan_value(); } + + Handle<Object> undefined() { return isolate->factory()->undefined_value(); } + + Handle<Object> null() { return isolate->factory()->null_value(); } + + Handle<Object> true_value() { return isolate->factory()->true_value(); } + + Handle<Object> false_value() { return isolate->factory()->false_value(); } +}; +} +} +} // namespace v8::internal::compiler + +#endif // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_ diff --git a/deps/v8/test/cctest/compiler/graph-builder-tester.cc b/deps/v8/test/cctest/compiler/graph-builder-tester.cc new file mode 100644 index 0000000000..fb6e4a28ce --- /dev/null +++ b/deps/v8/test/cctest/compiler/graph-builder-tester.cc @@ -0,0 +1,65 @@ +// 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 "test/cctest/compiler/graph-builder-tester.h" +#include "src/compiler/pipeline.h" + +namespace v8 { +namespace internal { +namespace compiler { + +MachineCallHelper::MachineCallHelper(Zone* zone, + MachineCallDescriptorBuilder* builder) + : CallHelper(zone->isolate()), + call_descriptor_builder_(builder), + parameters_(NULL), + graph_(NULL) {} + + +void MachineCallHelper::InitParameters(GraphBuilder* builder, + CommonOperatorBuilder* common) { + DCHECK_EQ(NULL, parameters_); + graph_ = builder->graph(); + if (parameter_count() == 0) return; + parameters_ = graph_->zone()->NewArray<Node*>(parameter_count()); + for (int i = 0; i < parameter_count(); ++i) { + parameters_[i] = builder->NewNode(common->Parameter(i), graph_->start()); + } +} + + +byte* MachineCallHelper::Generate() { + DCHECK(parameter_count() == 0 || parameters_ != NULL); + if (!Pipeline::SupportedBackend()) return NULL; + if (code_.is_null()) { + Zone* zone = graph_->zone(); + CompilationInfo info(zone->isolate(), zone); + Linkage linkage(&info, call_descriptor_builder_->BuildCallDescriptor(zone)); + Pipeline pipeline(&info); + code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph_); + } + return code_.ToHandleChecked()->entry(); +} + + +void MachineCallHelper::VerifyParameters(int parameter_count, + MachineType* parameter_types) { + CHECK_EQ(this->parameter_count(), parameter_count); + const MachineType* expected_types = + call_descriptor_builder_->parameter_types(); + for (int i = 0; i < parameter_count; i++) { + CHECK_EQ(expected_types[i], parameter_types[i]); + } +} + + +Node* MachineCallHelper::Parameter(int offset) { + DCHECK_NE(NULL, parameters_); + DCHECK(0 <= offset && offset < parameter_count()); + return parameters_[offset]; +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/compiler/graph-builder-tester.h b/deps/v8/test/cctest/compiler/graph-builder-tester.h new file mode 100644 index 0000000000..64d9b8a73d --- /dev/null +++ b/deps/v8/test/cctest/compiler/graph-builder-tester.h @@ -0,0 +1,114 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ +#define V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/compiler/common-operator.h" +#include "src/compiler/graph-builder.h" +#include "src/compiler/machine-node-factory.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/simplified-node-factory.h" +#include "src/compiler/simplified-operator.h" +#include "test/cctest/compiler/call-tester.h" +#include "test/cctest/compiler/simplified-graph-builder.h" + +namespace v8 { +namespace internal { +namespace compiler { + +// A class that just passes node creation on to the Graph. +class DirectGraphBuilder : public GraphBuilder { + public: + explicit DirectGraphBuilder(Graph* graph) : GraphBuilder(graph) {} + virtual ~DirectGraphBuilder() {} + + protected: + virtual Node* MakeNode(Operator* op, int value_input_count, + Node** value_inputs) { + return graph()->NewNode(op, value_input_count, value_inputs); + } +}; + + +class MachineCallHelper : public CallHelper { + public: + MachineCallHelper(Zone* zone, MachineCallDescriptorBuilder* builder); + + Node* Parameter(int offset); + + void GenerateCode() { Generate(); } + + protected: + virtual byte* Generate(); + virtual void VerifyParameters(int parameter_count, MachineType* parameters); + void InitParameters(GraphBuilder* builder, CommonOperatorBuilder* common); + + protected: + int parameter_count() const { + return call_descriptor_builder_->parameter_count(); + } + + private: + MachineCallDescriptorBuilder* call_descriptor_builder_; + Node** parameters_; + // TODO(dcarney): shouldn't need graph stored. + Graph* graph_; + MaybeHandle<Code> code_; +}; + + +class GraphAndBuilders { + public: + explicit GraphAndBuilders(Zone* zone) + : main_graph_(new (zone) Graph(zone)), + main_common_(zone), + main_machine_(zone), + main_simplified_(zone) {} + + protected: + // Prefixed with main_ to avoid naiming conflicts. + Graph* main_graph_; + CommonOperatorBuilder main_common_; + MachineOperatorBuilder main_machine_; + SimplifiedOperatorBuilder main_simplified_; +}; + + +template <typename ReturnType> +class GraphBuilderTester + : public HandleAndZoneScope, + private GraphAndBuilders, + public MachineCallHelper, + public SimplifiedGraphBuilder, + public CallHelper2<ReturnType, GraphBuilderTester<ReturnType> > { + public: + explicit GraphBuilderTester(MachineType p0 = kMachineLast, + MachineType p1 = kMachineLast, + MachineType p2 = kMachineLast, + MachineType p3 = kMachineLast, + MachineType p4 = kMachineLast) + : GraphAndBuilders(main_zone()), + MachineCallHelper( + main_zone(), + ToCallDescriptorBuilder( + main_zone(), ReturnValueTraits<ReturnType>::Representation(), + p0, p1, p2, p3, p4)), + SimplifiedGraphBuilder(main_graph_, &main_common_, &main_machine_, + &main_simplified_) { + Begin(parameter_count()); + InitParameters(this, &main_common_); + } + virtual ~GraphBuilderTester() {} + + Factory* factory() const { return isolate()->factory(); } +}; +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_ diff --git a/deps/v8/test/cctest/compiler/graph-tester.h b/deps/v8/test/cctest/compiler/graph-tester.h new file mode 100644 index 0000000000..e56924540b --- /dev/null +++ b/deps/v8/test/cctest/compiler/graph-tester.h @@ -0,0 +1,42 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_GRAPH_TESTER_H_ +#define V8_CCTEST_COMPILER_GRAPH_TESTER_H_ + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/compiler/common-operator.h" +#include "src/compiler/graph.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class GraphTester : public HandleAndZoneScope, public Graph { + public: + GraphTester() : Graph(main_zone()) {} +}; + + +class GraphWithStartNodeTester : public GraphTester { + public: + explicit GraphWithStartNodeTester(int num_parameters = 0) + : builder_(main_zone()), + start_node_(NewNode(builder_.Start(num_parameters))) { + SetStart(start_node_); + } + + Node* start_node() { return start_node_; } + + private: + CommonOperatorBuilder builder_; + Node* start_node_; +}; +} +} +} // namespace v8::internal::compiler + +#endif // V8_CCTEST_COMPILER_GRAPH_TESTER_H_ diff --git a/deps/v8/test/cctest/compiler/instruction-selector-tester.h b/deps/v8/test/cctest/compiler/instruction-selector-tester.h new file mode 100644 index 0000000000..60adaec823 --- /dev/null +++ b/deps/v8/test/cctest/compiler/instruction-selector-tester.h @@ -0,0 +1,127 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_ +#define V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_ + +#include <deque> +#include <set> + +#include "src/compiler/instruction-selector.h" +#include "src/compiler/raw-machine-assembler.h" +#include "src/ostreams.h" +#include "test/cctest/cctest.h" + +namespace v8 { +namespace internal { +namespace compiler { + +typedef std::set<int> VirtualRegisterSet; + +enum InstructionSelectorTesterMode { kTargetMode, kInternalMode }; + +class InstructionSelectorTester : public HandleAndZoneScope, + public RawMachineAssembler { + public: + enum Mode { kTargetMode, kInternalMode }; + + static const int kParameterCount = 3; + static MachineType* BuildParameterArray(Zone* zone) { + MachineType* array = zone->NewArray<MachineType>(kParameterCount); + for (int i = 0; i < kParameterCount; ++i) { + array[i] = kMachineWord32; + } + return array; + } + + InstructionSelectorTester() + : RawMachineAssembler( + new (main_zone()) Graph(main_zone()), new (main_zone()) + MachineCallDescriptorBuilder(kMachineWord32, kParameterCount, + BuildParameterArray(main_zone())), + MachineOperatorBuilder::pointer_rep()) {} + + void SelectInstructions(CpuFeature feature) { + SelectInstructions(InstructionSelector::Features(feature)); + } + + void SelectInstructions(CpuFeature feature1, CpuFeature feature2) { + SelectInstructions(InstructionSelector::Features(feature1, feature2)); + } + + void SelectInstructions(Mode mode = kTargetMode) { + SelectInstructions(InstructionSelector::Features(), mode); + } + + void SelectInstructions(InstructionSelector::Features features, + Mode mode = kTargetMode) { + OFStream out(stdout); + Schedule* schedule = Export(); + CHECK_NE(0, graph()->NodeCount()); + CompilationInfo info(main_isolate(), main_zone()); + Linkage linkage(&info, call_descriptor()); + InstructionSequence sequence(&linkage, graph(), schedule); + SourcePositionTable source_positions(graph()); + InstructionSelector selector(&sequence, &source_positions, features); + selector.SelectInstructions(); + out << "--- Code sequence after instruction selection --- " << endl + << sequence; + for (InstructionSequence::const_iterator i = sequence.begin(); + i != sequence.end(); ++i) { + Instruction* instr = *i; + if (instr->opcode() < 0) continue; + if (mode == kTargetMode) { + switch (ArchOpcodeField::decode(instr->opcode())) { +#define CASE(Name) \ + case k##Name: \ + break; + TARGET_ARCH_OPCODE_LIST(CASE) +#undef CASE + default: + continue; + } + } + code.push_back(instr); + } + for (int vreg = 0; vreg < sequence.VirtualRegisterCount(); ++vreg) { + if (sequence.IsDouble(vreg)) { + CHECK(!sequence.IsReference(vreg)); + doubles.insert(vreg); + } + if (sequence.IsReference(vreg)) { + CHECK(!sequence.IsDouble(vreg)); + references.insert(vreg); + } + } + immediates.assign(sequence.immediates().begin(), + sequence.immediates().end()); + } + + int32_t ToInt32(const InstructionOperand* operand) const { + size_t i = operand->index(); + CHECK(i < immediates.size()); + CHECK_EQ(InstructionOperand::IMMEDIATE, operand->kind()); + return immediates[i].ToInt32(); + } + + std::deque<Instruction*> code; + VirtualRegisterSet doubles; + VirtualRegisterSet references; + std::deque<Constant> immediates; +}; + + +static inline void CheckSameVreg(InstructionOperand* exp, + InstructionOperand* val) { + CHECK_EQ(InstructionOperand::UNALLOCATED, exp->kind()); + CHECK_EQ(InstructionOperand::UNALLOCATED, val->kind()); + CHECK_EQ(UnallocatedOperand::cast(exp)->virtual_register(), + UnallocatedOperand::cast(val)->virtual_register()); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_INSTRUCTION_SELECTOR_TEST_H_ diff --git a/deps/v8/test/cctest/compiler/simplified-graph-builder.cc b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc new file mode 100644 index 0000000000..c688399eae --- /dev/null +++ b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc @@ -0,0 +1,78 @@ +// 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 "test/cctest/compiler/simplified-graph-builder.h" + +namespace v8 { +namespace internal { +namespace compiler { + +SimplifiedGraphBuilder::SimplifiedGraphBuilder( + Graph* graph, CommonOperatorBuilder* common, + MachineOperatorBuilder* machine, SimplifiedOperatorBuilder* simplified) + : StructuredGraphBuilder(graph, common), + machine_(machine), + simplified_(simplified) {} + + +void SimplifiedGraphBuilder::Begin(int num_parameters) { + DCHECK(graph()->start() == NULL); + Node* start = graph()->NewNode(common()->Start(num_parameters)); + graph()->SetStart(start); + set_environment(new (zone()) Environment(this, start)); +} + + +void SimplifiedGraphBuilder::Return(Node* value) { + Node* control = NewNode(common()->Return(), value); + UpdateControlDependencyToLeaveFunction(control); +} + + +void SimplifiedGraphBuilder::End() { + environment()->UpdateControlDependency(exit_control()); + graph()->SetEnd(NewNode(common()->End())); +} + + +SimplifiedGraphBuilder::Environment::Environment( + SimplifiedGraphBuilder* builder, Node* control_dependency) + : StructuredGraphBuilder::Environment(builder, control_dependency) {} + + +Node* SimplifiedGraphBuilder::Environment::Top() { + DCHECK(!values()->empty()); + return values()->back(); +} + + +void SimplifiedGraphBuilder::Environment::Push(Node* node) { + values()->push_back(node); +} + + +Node* SimplifiedGraphBuilder::Environment::Pop() { + DCHECK(!values()->empty()); + Node* back = values()->back(); + values()->pop_back(); + return back; +} + + +void SimplifiedGraphBuilder::Environment::Poke(size_t depth, Node* node) { + DCHECK(depth < values()->size()); + size_t index = values()->size() - depth - 1; + values()->at(index) = node; +} + + +Node* SimplifiedGraphBuilder::Environment::Peek(size_t depth) { + DCHECK(depth < values()->size()); + size_t index = values()->size() - depth - 1; + return values()->at(index); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/compiler/simplified-graph-builder.h b/deps/v8/test/cctest/compiler/simplified-graph-builder.h new file mode 100644 index 0000000000..fa9161e171 --- /dev/null +++ b/deps/v8/test/cctest/compiler/simplified-graph-builder.h @@ -0,0 +1,73 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_ +#define V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_ + +#include "src/compiler/common-operator.h" +#include "src/compiler/graph-builder.h" +#include "src/compiler/machine-node-factory.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/simplified-node-factory.h" +#include "src/compiler/simplified-operator.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/call-tester.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class SimplifiedGraphBuilder + : public StructuredGraphBuilder, + public MachineNodeFactory<SimplifiedGraphBuilder>, + public SimplifiedNodeFactory<SimplifiedGraphBuilder> { + public: + SimplifiedGraphBuilder(Graph* graph, CommonOperatorBuilder* common, + MachineOperatorBuilder* machine, + SimplifiedOperatorBuilder* simplified); + virtual ~SimplifiedGraphBuilder() {} + + class Environment : public StructuredGraphBuilder::Environment { + public: + Environment(SimplifiedGraphBuilder* builder, Node* control_dependency); + + // TODO(dcarney): encode somehow and merge into StructuredGraphBuilder. + // SSA renaming operations. + Node* Top(); + void Push(Node* node); + Node* Pop(); + void Poke(size_t depth, Node* node); + Node* Peek(size_t depth); + }; + + Isolate* isolate() const { return zone()->isolate(); } + Zone* zone() const { return StructuredGraphBuilder::zone(); } + CommonOperatorBuilder* common() const { + return StructuredGraphBuilder::common(); + } + MachineOperatorBuilder* machine() const { return machine_; } + SimplifiedOperatorBuilder* simplified() const { return simplified_; } + Environment* environment() { + return reinterpret_cast<Environment*>( + StructuredGraphBuilder::environment()); + } + + // Initialize graph and builder. + void Begin(int num_parameters); + + void Return(Node* value); + + // Close the graph. + void End(); + + private: + MachineOperatorBuilder* machine_; + SimplifiedOperatorBuilder* simplified_; +}; + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_SIMPLIFIED_GRAPH_BUILDER_H_ diff --git a/deps/v8/test/cctest/compiler/test-branch-combine.cc b/deps/v8/test/cctest/compiler/test-branch-combine.cc new file mode 100644 index 0000000000..61dffdca87 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-branch-combine.cc @@ -0,0 +1,462 @@ +// 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 "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/value-helper.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal; +using namespace v8::internal::compiler; + +typedef RawMachineAssembler::Label MLabel; + +static IrOpcode::Value int32cmp_opcodes[] = { + IrOpcode::kWord32Equal, IrOpcode::kInt32LessThan, + IrOpcode::kInt32LessThanOrEqual, IrOpcode::kUint32LessThan, + IrOpcode::kUint32LessThanOrEqual}; + + +TEST(BranchCombineWord32EqualZero_1) { + // Test combining a branch with x == 0 + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = -1033; + int32_t ne_constant = 825118; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + int32_t a = *i; + int32_t expect = a == 0 ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineWord32EqualZero_chain) { + // Test combining a branch with a chain of x == 0 == 0 == 0 ... + int32_t eq_constant = -1133; + int32_t ne_constant = 815118; + + for (int k = 0; k < 6; k++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* p0 = m.Parameter(0); + MLabel blocka, blockb; + Node* cond = p0; + for (int j = 0; j < k; j++) { + cond = m.Word32Equal(cond, m.Int32Constant(0)); + } + m.Branch(cond, &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + int32_t a = *i; + int32_t expect = (k & 1) == 1 ? (a == 0 ? eq_constant : ne_constant) + : (a == 0 ? ne_constant : eq_constant); + CHECK_EQ(expect, m.Call(a)); + } + } +} + + +TEST(BranchCombineInt32LessThanZero_1) { + // Test combining a branch with x < 0 + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = -1433; + int32_t ne_constant = 845118; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Int32LessThan(p0, m.Int32Constant(0)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + int32_t a = *i; + int32_t expect = a < 0 ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineUint32LessThan100_1) { + // Test combining a branch with x < 100 + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = 1471; + int32_t ne_constant = 88845718; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Uint32LessThan(p0, m.Int32Constant(100)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_UINT32_INPUTS(i) { + uint32_t a = *i; + int32_t expect = a < 100 ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineUint32LessThanOrEqual100_1) { + // Test combining a branch with x <= 100 + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = 1479; + int32_t ne_constant = 77845719; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Uint32LessThanOrEqual(p0, m.Int32Constant(100)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_UINT32_INPUTS(i) { + uint32_t a = *i; + int32_t expect = a <= 100 ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineZeroLessThanInt32_1) { + // Test combining a branch with 0 < x + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = -2033; + int32_t ne_constant = 225118; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Int32LessThan(m.Int32Constant(0), p0), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + int32_t a = *i; + int32_t expect = 0 < a ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineInt32GreaterThanZero_1) { + // Test combining a branch with x > 0 + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t eq_constant = -1073; + int32_t ne_constant = 825178; + Node* p0 = m.Parameter(0); + + MLabel blocka, blockb; + m.Branch(m.Int32GreaterThan(p0, m.Int32Constant(0)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + int32_t a = *i; + int32_t expect = a > 0 ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a)); + } +} + + +TEST(BranchCombineWord32EqualP) { + // Test combining a branch with an Word32Equal. + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + int32_t eq_constant = -1035; + int32_t ne_constant = 825018; + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + + MLabel blocka, blockb; + m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t a = *i; + int32_t b = *j; + int32_t expect = a == b ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a, b)); + } + } +} + + +TEST(BranchCombineWord32EqualI) { + int32_t eq_constant = -1135; + int32_t ne_constant = 925718; + + for (int left = 0; left < 2; left++) { + FOR_INT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t a = *i; + + Node* p0 = m.Int32Constant(a); + Node* p1 = m.Parameter(0); + + MLabel blocka, blockb; + if (left == 1) m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb); + if (left == 0) m.Branch(m.Word32Equal(p1, p0), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(j) { + int32_t b = *j; + int32_t expect = a == b ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(b)); + } + } + } +} + + +TEST(BranchCombineInt32CmpP) { + int32_t eq_constant = -1235; + int32_t ne_constant = 725018; + + for (int op = 0; op < 2; op++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + + MLabel blocka, blockb; + if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb); + if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t a = *i; + int32_t b = *j; + int32_t expect = 0; + if (op == 0) expect = a < b ? eq_constant : ne_constant; + if (op == 1) expect = a <= b ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(a, b)); + } + } + } +} + + +TEST(BranchCombineInt32CmpI) { + int32_t eq_constant = -1175; + int32_t ne_constant = 927711; + + for (int op = 0; op < 2; op++) { + FOR_INT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int32_t a = *i; + Node* p0 = m.Int32Constant(a); + Node* p1 = m.Parameter(0); + + MLabel blocka, blockb; + if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb); + if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + FOR_INT32_INPUTS(j) { + int32_t b = *j; + int32_t expect = 0; + if (op == 0) expect = a < b ? eq_constant : ne_constant; + if (op == 1) expect = a <= b ? eq_constant : ne_constant; + CHECK_EQ(expect, m.Call(b)); + } + } + } +} + + +// Now come the sophisticated tests for many input shape combinations. + +// Materializes a boolean (1 or 0) from a comparison. +class CmpMaterializeBoolGen : public BinopGen<int32_t> { + public: + CompareWrapper w; + bool invert; + + CmpMaterializeBoolGen(IrOpcode::Value opcode, bool i) + : w(opcode), invert(i) {} + + virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) { + Node* cond = w.MakeNode(m, a, b); + if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0)); + m->Return(cond); + } + virtual int32_t expected(int32_t a, int32_t b) { + if (invert) return !w.Int32Compare(a, b) ? 1 : 0; + return w.Int32Compare(a, b) ? 1 : 0; + } +}; + + +// Generates a branch and return one of two values from a comparison. +class CmpBranchGen : public BinopGen<int32_t> { + public: + CompareWrapper w; + bool invert; + bool true_first; + int32_t eq_constant; + int32_t ne_constant; + + CmpBranchGen(IrOpcode::Value opcode, bool i, bool t, int32_t eq, int32_t ne) + : w(opcode), invert(i), true_first(t), eq_constant(eq), ne_constant(ne) {} + + virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) { + MLabel blocka, blockb; + Node* cond = w.MakeNode(m, a, b); + if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0)); + m->Branch(cond, &blocka, &blockb); + if (true_first) { + m->Bind(&blocka); + m->Return(m->Int32Constant(eq_constant)); + m->Bind(&blockb); + m->Return(m->Int32Constant(ne_constant)); + } else { + m->Bind(&blockb); + m->Return(m->Int32Constant(ne_constant)); + m->Bind(&blocka); + m->Return(m->Int32Constant(eq_constant)); + } + } + virtual int32_t expected(int32_t a, int32_t b) { + if (invert) return !w.Int32Compare(a, b) ? eq_constant : ne_constant; + return w.Int32Compare(a, b) ? eq_constant : ne_constant; + } +}; + + +TEST(BranchCombineInt32CmpAllInputShapes_materialized) { + for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { + CmpMaterializeBoolGen gen(int32cmp_opcodes[i], false); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineInt32CmpAllInputShapes_inverted_materialized) { + for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { + CmpMaterializeBoolGen gen(int32cmp_opcodes[i], true); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineInt32CmpAllInputShapes_branch_true) { + for (int i = 0; i < static_cast<int>(ARRAY_SIZE(int32cmp_opcodes)); i++) { + CmpBranchGen gen(int32cmp_opcodes[i], false, false, 995 + i, -1011 - i); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineInt32CmpAllInputShapes_branch_false) { + for (int i = 0; i < static_cast<int>(ARRAY_SIZE(int32cmp_opcodes)); i++) { + CmpBranchGen gen(int32cmp_opcodes[i], false, true, 795 + i, -2011 - i); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_true) { + for (int i = 0; i < static_cast<int>(ARRAY_SIZE(int32cmp_opcodes)); i++) { + CmpBranchGen gen(int32cmp_opcodes[i], true, false, 695 + i, -3011 - i); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_false) { + for (int i = 0; i < static_cast<int>(ARRAY_SIZE(int32cmp_opcodes)); i++) { + CmpBranchGen gen(int32cmp_opcodes[i], true, true, 595 + i, -4011 - i); + Int32BinopInputShapeTester tester(&gen); + tester.TestAllInputShapes(); + } +} + + +TEST(BranchCombineFloat64Compares) { + double inf = V8_INFINITY; + double nan = v8::base::OS::nan_value(); + double inputs[] = {0.0, 1.0, -1.0, -inf, inf, nan}; + + int32_t eq_constant = -1733; + int32_t ne_constant = 915118; + + double input_a = 0.0; + double input_b = 0.0; + + CompareWrapper cmps[] = {CompareWrapper(IrOpcode::kFloat64Equal), + CompareWrapper(IrOpcode::kFloat64LessThan), + CompareWrapper(IrOpcode::kFloat64LessThanOrEqual)}; + + for (size_t c = 0; c < ARRAY_SIZE(cmps); c++) { + CompareWrapper cmp = cmps[c]; + for (int invert = 0; invert < 2; invert++) { + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + + MLabel blocka, blockb; + Node* cond = cmp.MakeNode(&m, a, b); + if (invert) cond = m.Word32Equal(cond, m.Int32Constant(0)); + m.Branch(cond, &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(eq_constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(ne_constant)); + + for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) { + for (size_t j = 0; j < ARRAY_SIZE(inputs); j += 2) { + input_a = inputs[i]; + input_b = inputs[i]; + int32_t expected = + invert ? (cmp.Float64Compare(input_a, input_b) ? ne_constant + : eq_constant) + : (cmp.Float64Compare(input_a, input_b) ? eq_constant + : ne_constant); + CHECK_EQ(expected, m.Call()); + } + } + } + } +} +#endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-changes-lowering.cc b/deps/v8/test/cctest/compiler/test-changes-lowering.cc new file mode 100644 index 0000000000..148f4b34f5 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-changes-lowering.cc @@ -0,0 +1,397 @@ +// 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 <limits> + +#include "src/compiler/control-builders.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/node-properties-inl.h" +#include "src/compiler/pipeline.h" +#include "src/compiler/simplified-lowering.h" +#include "src/compiler/simplified-node-factory.h" +#include "src/compiler/typer.h" +#include "src/compiler/verifier.h" +#include "src/execution.h" +#include "src/parser.h" +#include "src/rewriter.h" +#include "src/scopes.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/graph-builder-tester.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +template <typename ReturnType> +class ChangesLoweringTester : public GraphBuilderTester<ReturnType> { + public: + explicit ChangesLoweringTester(MachineType p0 = kMachineLast) + : GraphBuilderTester<ReturnType>(p0), + typer(this->zone()), + source_positions(this->graph()), + jsgraph(this->graph(), this->common(), &typer), + lowering(&jsgraph, &source_positions), + function(Handle<JSFunction>::null()) {} + + Typer typer; + SourcePositionTable source_positions; + JSGraph jsgraph; + SimplifiedLowering lowering; + Handle<JSFunction> function; + + Node* start() { return this->graph()->start(); } + + template <typename T> + T* CallWithPotentialGC() { + // TODO(titzer): we need to wrap the code in a JSFunction and call it via + // Execution::Call() so that the GC knows about the frame, can walk it, + // relocate the code object if necessary, etc. + // This is pretty ugly and at the least should be moved up to helpers. + if (function.is_null()) { + function = + v8::Utils::OpenHandle(*v8::Handle<v8::Function>::Cast(CompileRun( + "(function() { 'use strict'; return 2.7123; })"))); + CompilationInfoWithZone info(function); + CHECK(Parser::Parse(&info)); + StrictMode strict_mode = info.function()->strict_mode(); + info.SetStrictMode(strict_mode); + info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); + CHECK(Rewriter::Rewrite(&info)); + CHECK(Scope::Analyze(&info)); + CHECK_NE(NULL, info.scope()); + Pipeline pipeline(&info); + Linkage linkage(&info); + Handle<Code> code = + pipeline.GenerateCodeForMachineGraph(&linkage, this->graph()); + CHECK(!code.is_null()); + function->ReplaceCode(*code); + } + Handle<Object>* args = NULL; + MaybeHandle<Object> result = + Execution::Call(this->isolate(), function, factory()->undefined_value(), + 0, args, false); + return T::cast(*result.ToHandleChecked()); + } + + void StoreFloat64(Node* node, double* ptr) { + Node* ptr_node = this->PointerConstant(ptr); + this->Store(kMachineFloat64, ptr_node, node); + } + + Node* LoadInt32(int32_t* ptr) { + Node* ptr_node = this->PointerConstant(ptr); + return this->Load(kMachineWord32, ptr_node); + } + + Node* LoadUint32(uint32_t* ptr) { + Node* ptr_node = this->PointerConstant(ptr); + return this->Load(kMachineWord32, ptr_node); + } + + Node* LoadFloat64(double* ptr) { + Node* ptr_node = this->PointerConstant(ptr); + return this->Load(kMachineFloat64, ptr_node); + } + + void CheckNumber(double expected, Object* number) { + CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number)); + } + + void BuildAndLower(Operator* op) { + // We build a graph by hand here, because the raw machine assembler + // does not add the correct control and effect nodes. + Node* p0 = this->Parameter(0); + 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); + this->graph()->SetEnd(end); + this->lowering.LowerChange(change, this->start(), this->start()); + Verifier::Run(this->graph()); + } + + void BuildStoreAndLower(Operator* op, Operator* store_op, void* location) { + // We build a graph by hand here, because the raw machine assembler + // does not add the correct control and effect nodes. + Node* p0 = this->Parameter(0); + Node* change = this->graph()->NewNode(op, p0); + Node* store = this->graph()->NewNode( + store_op, this->PointerConstant(location), this->Int32Constant(0), + 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); + this->graph()->SetEnd(end); + this->lowering.LowerChange(change, this->start(), this->start()); + Verifier::Run(this->graph()); + } + + void BuildLoadAndLower(Operator* op, Operator* load_op, void* location) { + // We build a graph by hand here, because the raw machine assembler + // does not add the correct control and effect nodes. + Node* load = + this->graph()->NewNode(load_op, this->PointerConstant(location), + this->Int32Constant(0), this->start()); + 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); + this->graph()->SetEnd(end); + this->lowering.LowerChange(change, this->start(), this->start()); + Verifier::Run(this->graph()); + } + + Factory* factory() { return this->isolate()->factory(); } + Heap* heap() { return this->isolate()->heap(); } +}; + + +TEST(RunChangeTaggedToInt32) { + // Build and lower a graph by hand. + ChangesLoweringTester<int32_t> t(kMachineTagged); + t.BuildAndLower(t.simplified()->ChangeTaggedToInt32()); + + if (Pipeline::SupportedTarget()) { + FOR_INT32_INPUTS(i) { + int32_t input = *i; + + if (Smi::IsValid(input)) { + int32_t result = t.Call(Smi::FromInt(input)); + CHECK_EQ(input, result); + } + + { + Handle<Object> number = t.factory()->NewNumber(input); + int32_t result = t.Call(*number); + CHECK_EQ(input, result); + } + + { + Handle<HeapNumber> number = t.factory()->NewHeapNumber(input); + int32_t result = t.Call(*number); + CHECK_EQ(input, result); + } + } + } +} + + +TEST(RunChangeTaggedToUint32) { + // Build and lower a graph by hand. + ChangesLoweringTester<uint32_t> t(kMachineTagged); + t.BuildAndLower(t.simplified()->ChangeTaggedToUint32()); + + if (Pipeline::SupportedTarget()) { + FOR_UINT32_INPUTS(i) { + uint32_t input = *i; + + if (Smi::IsValid(input)) { + uint32_t result = t.Call(Smi::FromInt(input)); + CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result)); + } + + { + Handle<Object> number = t.factory()->NewNumber(input); + uint32_t result = t.Call(*number); + CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result)); + } + + { + Handle<HeapNumber> number = t.factory()->NewHeapNumber(input); + uint32_t result = t.Call(*number); + CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result)); + } + } + } +} + + +TEST(RunChangeTaggedToFloat64) { + ChangesLoweringTester<int32_t> t(kMachineTagged); + double result; + + t.BuildStoreAndLower(t.simplified()->ChangeTaggedToFloat64(), + t.machine()->Store(kMachineFloat64, kNoWriteBarrier), + &result); + + if (Pipeline::SupportedTarget()) { + FOR_INT32_INPUTS(i) { + int32_t input = *i; + + if (Smi::IsValid(input)) { + t.Call(Smi::FromInt(input)); + CHECK_EQ(input, static_cast<int32_t>(result)); + } + + { + Handle<Object> number = t.factory()->NewNumber(input); + t.Call(*number); + CHECK_EQ(input, static_cast<int32_t>(result)); + } + + { + Handle<HeapNumber> number = t.factory()->NewHeapNumber(input); + t.Call(*number); + CHECK_EQ(input, static_cast<int32_t>(result)); + } + } + } + + if (Pipeline::SupportedTarget()) { + FOR_FLOAT64_INPUTS(i) { + double input = *i; + { + Handle<Object> number = t.factory()->NewNumber(input); + t.Call(*number); + CHECK_EQ(input, result); + } + + { + Handle<HeapNumber> number = t.factory()->NewHeapNumber(input); + t.Call(*number); + CHECK_EQ(input, result); + } + } + } +} + + +TEST(RunChangeBoolToBit) { + ChangesLoweringTester<int32_t> t(kMachineTagged); + t.BuildAndLower(t.simplified()->ChangeBoolToBit()); + + if (Pipeline::SupportedTarget()) { + Object* true_obj = t.heap()->true_value(); + int32_t result = t.Call(true_obj); + CHECK_EQ(1, result); + } + + if (Pipeline::SupportedTarget()) { + Object* false_obj = t.heap()->false_value(); + int32_t result = t.Call(false_obj); + CHECK_EQ(0, result); + } +} + + +TEST(RunChangeBitToBool) { + ChangesLoweringTester<Object*> t(kMachineWord32); + t.BuildAndLower(t.simplified()->ChangeBitToBool()); + + if (Pipeline::SupportedTarget()) { + Object* result = t.Call(1); + Object* true_obj = t.heap()->true_value(); + CHECK_EQ(true_obj, result); + } + + if (Pipeline::SupportedTarget()) { + Object* result = t.Call(0); + Object* false_obj = t.heap()->false_value(); + CHECK_EQ(false_obj, result); + } +} + + +bool TODO_INT32_TO_TAGGED_WILL_WORK(int32_t v) { + // TODO(titzer): enable all UI32 -> Tagged checking when inline allocation + // works. + return Smi::IsValid(v); +} + + +bool TODO_UINT32_TO_TAGGED_WILL_WORK(uint32_t v) { + // TODO(titzer): enable all UI32 -> Tagged checking when inline allocation + // works. + return v <= static_cast<uint32_t>(Smi::kMaxValue); +} + + +TEST(RunChangeInt32ToTagged) { + ChangesLoweringTester<Object*> t; + int32_t input; + t.BuildLoadAndLower(t.simplified()->ChangeInt32ToTagged(), + t.machine()->Load(kMachineWord32), &input); + + if (Pipeline::SupportedTarget()) { + FOR_INT32_INPUTS(i) { + input = *i; + Object* result = t.CallWithPotentialGC<Object>(); + if (TODO_INT32_TO_TAGGED_WILL_WORK(input)) { + t.CheckNumber(static_cast<double>(input), result); + } + } + } + + if (Pipeline::SupportedTarget()) { + FOR_INT32_INPUTS(i) { + input = *i; + SimulateFullSpace(CcTest::heap()->new_space()); + Object* result = t.CallWithPotentialGC<Object>(); + if (TODO_INT32_TO_TAGGED_WILL_WORK(input)) { + t.CheckNumber(static_cast<double>(input), result); + } + } + } +} + + +TEST(RunChangeUint32ToTagged) { + ChangesLoweringTester<Object*> t; + uint32_t input; + t.BuildLoadAndLower(t.simplified()->ChangeUint32ToTagged(), + t.machine()->Load(kMachineWord32), &input); + + if (Pipeline::SupportedTarget()) { + FOR_UINT32_INPUTS(i) { + input = *i; + Object* result = t.CallWithPotentialGC<Object>(); + double expected = static_cast<double>(input); + if (TODO_UINT32_TO_TAGGED_WILL_WORK(input)) { + t.CheckNumber(expected, result); + } + } + } + + if (Pipeline::SupportedTarget()) { + FOR_UINT32_INPUTS(i) { + input = *i; + SimulateFullSpace(CcTest::heap()->new_space()); + Object* result = t.CallWithPotentialGC<Object>(); + double expected = static_cast<double>(static_cast<uint32_t>(input)); + if (TODO_UINT32_TO_TAGGED_WILL_WORK(input)) { + t.CheckNumber(expected, result); + } + } + } +} + + +// TODO(titzer): lowering of Float64->Tagged needs inline allocation. +#define TODO_FLOAT64_TO_TAGGED false + +TEST(RunChangeFloat64ToTagged) { + ChangesLoweringTester<Object*> t; + double input; + t.BuildLoadAndLower(t.simplified()->ChangeFloat64ToTagged(), + t.machine()->Load(kMachineFloat64), &input); + + // TODO(titzer): need inline allocation to change float to tagged. + if (TODO_FLOAT64_TO_TAGGED && Pipeline::SupportedTarget()) { + FOR_FLOAT64_INPUTS(i) { + input = *i; + Object* result = t.CallWithPotentialGC<Object>(); + t.CheckNumber(input, result); + } + } + + if (TODO_FLOAT64_TO_TAGGED && Pipeline::SupportedTarget()) { + FOR_FLOAT64_INPUTS(i) { + input = *i; + SimulateFullSpace(CcTest::heap()->new_space()); + Object* result = t.CallWithPotentialGC<Object>(); + t.CheckNumber(input, result); + } + } +} diff --git a/deps/v8/test/cctest/compiler/test-codegen-deopt.cc b/deps/v8/test/cctest/compiler/test-codegen-deopt.cc new file mode 100644 index 0000000000..b953ee53cc --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-codegen-deopt.cc @@ -0,0 +1,344 @@ +// 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/full-codegen.h" +#include "src/parser.h" +#include "src/rewriter.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; + +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)), + info(function, scope->main_zone()), + bailout_id(-1) { + CHECK(Parser::Parse(&info)); + StrictMode strict_mode = info.function()->strict_mode(); + info.SetStrictMode(strict_mode); + info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); + CHECK(Rewriter::Rewrite(&info)); + CHECK(Scope::Analyze(&info)); + CHECK_NE(NULL, info.scope()); + + FunctionTester::EnsureDeoptimizationSupport(&info); + + DCHECK(info.shared_info()->has_deoptimization_support()); + + graph = new (scope_->main_zone()) Graph(scope_->main_zone()); + } + + virtual ~DeoptCodegenTester() { delete code; } + + void GenerateCodeFromSchedule(Schedule* schedule) { + OFStream os(stdout); + os << *schedule; + + // Initialize the codegen and generate code. + Linkage* linkage = new (scope_->main_zone()) Linkage(&info); + code = new v8::internal::compiler::InstructionSequence(linkage, graph, + schedule); + SourcePositionTable source_positions(graph); + InstructionSelector selector(code, &source_positions); + selector.SelectInstructions(); + + os << "----- Instruction sequence before register allocation -----\n" + << *code; + + RegisterAllocator allocator(code); + CHECK(allocator.Allocate()); + + os << "----- Instruction sequence after register allocation -----\n" + << *code; + + compiler::CodeGenerator generator(code); + result_code = generator.GenerateCode(); + +#ifdef DEBUG + result_code->Print(); +#endif + } + + Zone* zone() { return scope_->main_zone(); } + + HandleAndZoneScope* scope_; + Handle<JSFunction> function; + CompilationInfo info; + BailoutId bailout_id; + Handle<Code> result_code; + v8::internal::compiler::InstructionSequence* code; + Graph* graph; +}; + + +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) { + Isolate* isolate = info.isolate(); + CommonOperatorBuilder common(zone()); + + // Manually construct a schedule for the function below: + // function foo() { + // deopt(); + // } + + MachineType parameter_reps[] = {kMachineTagged}; + MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 1, + parameter_reps); + + RawMachineAssembler m(graph, &descriptor_builder); + + Handle<Object> undef_object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> undef_constant = + PrintableUnique<Object>::CreateUninitialized(zone(), undef_object); + Node* undef_node = m.NewNode(common.HeapConstant(undef_constant)); + + Handle<JSFunction> deopt_function = + NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt"); + PrintableUnique<Object> deopt_fun_constant = + PrintableUnique<Object>::CreateUninitialized(zone(), deopt_function); + Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant)); + + MLabel deopt, cont; + Node* call = m.CallJS0(deopt_fun_node, undef_node, &cont, &deopt); + + m.Bind(&cont); + m.NewNode(common.Continuation(), call); + m.Return(undef_node); + + m.Bind(&deopt); + m.NewNode(common.LazyDeoptimization(), call); + + bailout_id = GetCallBailoutId(); + Node* parameters = m.NewNode(common.StateValues(1), undef_node); + Node* locals = m.NewNode(common.StateValues(0)); + Node* stack = m.NewNode(common.StateValues(0)); + + Node* state_node = + m.NewNode(common.FrameState(bailout_id), parameters, locals, stack); + m.Deoptimize(state_node); + + // Schedule the graph: + Schedule* schedule = m.Export(); + + cont_block = cont.block(); + deopt_block = deopt.block(); + + 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); + } + + BasicBlock* cont_block; + BasicBlock* deopt_block; +}; + + +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()); + + Label* cont_label = t.code->GetLabel(t.cont_block); + Label* deopt_label = t.code->GetLabel(t.deopt_block); + + // Check the patch table. It should patch the continuation address to the + // deoptimization block address. + CHECK_EQ(1, data->ReturnAddressPatchCount()); + CHECK_EQ(cont_label->pos(), data->ReturnAddressPc(0)->value()); + CHECK_EQ(deopt_label->pos(), data->PatchedAddressPc(0)->value()); + + // Check that we deoptimize to the right AST id. + CHECK_EQ(1, data->DeoptCount()); + 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) { + Isolate* isolate = info.isolate(); + CommonOperatorBuilder common(zone()); + + // Manually construct a schedule for the function below: + // function foo() { + // %DeoptimizeFunction(foo); + // } + + MachineType parameter_reps[] = {kMachineTagged}; + MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 2, + parameter_reps); + + RawMachineAssembler m(graph, &descriptor_builder); + + Handle<Object> undef_object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> undef_constant = + PrintableUnique<Object>::CreateUninitialized(zone(), undef_object); + Node* undef_node = m.NewNode(common.HeapConstant(undef_constant)); + + PrintableUnique<Object> this_fun_constant = + PrintableUnique<Object>::CreateUninitialized(zone(), function); + Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant)); + + MLabel deopt, cont; + Node* call = m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, + &cont, &deopt); + + m.Bind(&cont); + m.NewNode(common.Continuation(), call); + m.Return(undef_node); + + m.Bind(&deopt); + m.NewNode(common.LazyDeoptimization(), call); + + bailout_id = GetCallBailoutId(); + Node* parameters = m.NewNode(common.StateValues(1), undef_node); + Node* locals = m.NewNode(common.StateValues(0)); + Node* stack = m.NewNode(common.StateValues(0)); + + Node* state_node = + m.NewNode(common.FrameState(bailout_id), parameters, locals, stack); + m.Deoptimize(state_node); + + // Schedule the graph: + Schedule* schedule = m.Export(); + + cont_block = cont.block(); + deopt_block = deopt.block(); + + 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); + } + + BasicBlock* cont_block; + BasicBlock* deopt_block; +}; + + +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-gap-resolver.cc b/deps/v8/test/cctest/compiler/test-gap-resolver.cc new file mode 100644 index 0000000000..00c220945d --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-gap-resolver.cc @@ -0,0 +1,173 @@ +// 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/compiler/gap-resolver.h" + +#include "src/base/utils/random-number-generator.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +// The state of our move interpreter is the mapping of operands to values. Note +// that the actual values don't really matter, all we care about is equality. +class InterpreterState { + public: + typedef std::vector<MoveOperands> Moves; + + void ExecuteInParallel(Moves moves) { + InterpreterState copy(*this); + for (Moves::iterator it = moves.begin(); it != moves.end(); ++it) { + if (!it->IsRedundant()) write(it->destination(), copy.read(it->source())); + } + } + + bool operator==(const InterpreterState& other) const { + return values_ == other.values_; + } + + bool operator!=(const InterpreterState& other) const { + return values_ != other.values_; + } + + private: + // Internally, the state is a normalized permutation of (kind,index) pairs. + typedef std::pair<InstructionOperand::Kind, int> Key; + typedef Key Value; + typedef std::map<Key, Value> OperandMap; + + Value read(const InstructionOperand* op) const { + OperandMap::const_iterator it = values_.find(KeyFor(op)); + return (it == values_.end()) ? ValueFor(op) : it->second; + } + + void write(const InstructionOperand* op, Value v) { + if (v == ValueFor(op)) { + values_.erase(KeyFor(op)); + } else { + values_[KeyFor(op)] = v; + } + } + + static Key KeyFor(const InstructionOperand* op) { + return Key(op->kind(), op->index()); + } + + static Value ValueFor(const InstructionOperand* op) { + return Value(op->kind(), op->index()); + } + + friend OStream& operator<<(OStream& os, const InterpreterState& is) { + for (OperandMap::const_iterator it = is.values_.begin(); + it != is.values_.end(); ++it) { + if (it != is.values_.begin()) os << " "; + InstructionOperand source(it->first.first, it->first.second); + InstructionOperand destination(it->second.first, it->second.second); + os << MoveOperands(&source, &destination); + } + return os; + } + + OperandMap values_; +}; + + +// An abstract interpreter for moves, swaps and parallel moves. +class MoveInterpreter : public GapResolver::Assembler { + public: + virtual void AssembleMove(InstructionOperand* source, + InstructionOperand* destination) V8_OVERRIDE { + InterpreterState::Moves moves; + moves.push_back(MoveOperands(source, destination)); + state_.ExecuteInParallel(moves); + } + + virtual void AssembleSwap(InstructionOperand* source, + InstructionOperand* destination) V8_OVERRIDE { + InterpreterState::Moves moves; + moves.push_back(MoveOperands(source, destination)); + moves.push_back(MoveOperands(destination, source)); + state_.ExecuteInParallel(moves); + } + + void AssembleParallelMove(const ParallelMove* pm) { + InterpreterState::Moves moves(pm->move_operands()->begin(), + pm->move_operands()->end()); + state_.ExecuteInParallel(moves); + } + + InterpreterState state() const { return state_; } + + private: + InterpreterState state_; +}; + + +class ParallelMoveCreator : public HandleAndZoneScope { + public: + ParallelMoveCreator() : rng_(CcTest::random_number_generator()) {} + + ParallelMove* Create(int size) { + ParallelMove* parallel_move = new (main_zone()) ParallelMove(main_zone()); + std::set<InstructionOperand*, InstructionOperandComparator> seen; + for (int i = 0; i < size; ++i) { + MoveOperands mo(CreateRandomOperand(), CreateRandomOperand()); + if (!mo.IsRedundant() && seen.find(mo.destination()) == seen.end()) { + parallel_move->AddMove(mo.source(), mo.destination(), main_zone()); + seen.insert(mo.destination()); + } + } + return parallel_move; + } + + private: + struct InstructionOperandComparator { + bool operator()(const InstructionOperand* x, + const InstructionOperand* y) const { + return (x->kind() < y->kind()) || + (x->kind() == y->kind() && x->index() < y->index()); + } + }; + + InstructionOperand* CreateRandomOperand() { + int index = rng_->NextInt(6); + switch (rng_->NextInt(5)) { + case 0: + return ConstantOperand::Create(index, main_zone()); + case 1: + return StackSlotOperand::Create(index, main_zone()); + case 2: + return DoubleStackSlotOperand::Create(index, main_zone()); + case 3: + return RegisterOperand::Create(index, main_zone()); + case 4: + return DoubleRegisterOperand::Create(index, main_zone()); + } + UNREACHABLE(); + return NULL; + } + + private: + v8::base::RandomNumberGenerator* rng_; +}; + + +TEST(FuzzResolver) { + ParallelMoveCreator pmc; + for (int size = 0; size < 20; ++size) { + for (int repeat = 0; repeat < 50; ++repeat) { + ParallelMove* pm = pmc.Create(size); + + // Note: The gap resolver modifies the ParallelMove, so interpret first. + MoveInterpreter mi1; + mi1.AssembleParallelMove(pm); + + MoveInterpreter mi2; + GapResolver resolver(&mi2); + resolver.Resolve(pm); + + CHECK(mi1.state() == mi2.state()); + } + } +} diff --git a/deps/v8/test/cctest/compiler/test-graph-reducer.cc b/deps/v8/test/cctest/compiler/test-graph-reducer.cc new file mode 100644 index 0000000000..189b3db18e --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-graph-reducer.cc @@ -0,0 +1,661 @@ +// 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 "graph-tester.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/graph-reducer.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +const uint8_t OPCODE_A0 = 10; +const uint8_t OPCODE_A1 = 11; +const uint8_t OPCODE_A2 = 12; +const uint8_t OPCODE_B0 = 20; +const uint8_t OPCODE_B1 = 21; +const uint8_t OPCODE_B2 = 22; +const uint8_t OPCODE_C0 = 30; +const uint8_t OPCODE_C1 = 31; +const uint8_t OPCODE_C2 = 32; + +static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0"); +static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1"); +static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2"); +static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0"); +static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1"); +static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2"); +static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0"); +static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1"); +static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2"); + + +// Replaces all "A" operators with "B" operators without creating new nodes. +class InPlaceABReducer : public Reducer { + public: + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_A0: + CHECK_EQ(0, node->InputCount()); + node->set_op(&OPB0); + return Replace(node); + case OPCODE_A1: + CHECK_EQ(1, node->InputCount()); + node->set_op(&OPB1); + return Replace(node); + case OPCODE_A2: + CHECK_EQ(2, node->InputCount()); + node->set_op(&OPB2); + return Replace(node); + } + return NoChange(); + } +}; + + +// Replaces all "A" operators with "B" operators by allocating new nodes. +class NewABReducer : public Reducer { + public: + explicit NewABReducer(Graph* graph) : graph_(graph) {} + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_A0: + CHECK_EQ(0, node->InputCount()); + return Replace(graph_->NewNode(&OPB0)); + case OPCODE_A1: + CHECK_EQ(1, node->InputCount()); + return Replace(graph_->NewNode(&OPB1, node->InputAt(0))); + case OPCODE_A2: + CHECK_EQ(2, node->InputCount()); + return Replace( + graph_->NewNode(&OPB2, node->InputAt(0), node->InputAt(1))); + } + return NoChange(); + } + Graph* graph_; +}; + + +// Replaces all "B" operators with "C" operators without creating new nodes. +class InPlaceBCReducer : public Reducer { + public: + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_B0: + CHECK_EQ(0, node->InputCount()); + node->set_op(&OPC0); + return Replace(node); + case OPCODE_B1: + CHECK_EQ(1, node->InputCount()); + node->set_op(&OPC1); + return Replace(node); + case OPCODE_B2: + CHECK_EQ(2, node->InputCount()); + node->set_op(&OPC2); + return Replace(node); + } + return NoChange(); + } +}; + + +// Wraps all "OPA0" nodes in "OPB1" operators by allocating new nodes. +class A0Wrapper V8_FINAL : public Reducer { + public: + explicit A0Wrapper(Graph* graph) : graph_(graph) {} + virtual Reduction Reduce(Node* node) V8_OVERRIDE { + switch (node->op()->opcode()) { + case OPCODE_A0: + CHECK_EQ(0, node->InputCount()); + return Replace(graph_->NewNode(&OPB1, node)); + } + return NoChange(); + } + Graph* graph_; +}; + + +// Wraps all "OPB0" nodes in two "OPC1" operators by allocating new nodes. +class B0Wrapper V8_FINAL : public Reducer { + public: + explicit B0Wrapper(Graph* graph) : graph_(graph) {} + virtual Reduction Reduce(Node* node) V8_OVERRIDE { + switch (node->op()->opcode()) { + case OPCODE_B0: + CHECK_EQ(0, node->InputCount()); + return Replace(graph_->NewNode(&OPC1, graph_->NewNode(&OPC1, node))); + } + return NoChange(); + } + Graph* graph_; +}; + + +// Replaces all "OPA1" nodes with the first input. +class A1Forwarder : public Reducer { + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_A1: + CHECK_EQ(1, node->InputCount()); + return Replace(node->InputAt(0)); + } + return NoChange(); + } +}; + + +// Replaces all "OPB1" nodes with the first input. +class B1Forwarder : public Reducer { + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_B1: + CHECK_EQ(1, node->InputCount()); + return Replace(node->InputAt(0)); + } + return NoChange(); + } +}; + + +// Swaps the inputs to "OP2A" and "OP2B" nodes based on ids. +class AB2Sorter : public Reducer { + virtual Reduction Reduce(Node* node) { + switch (node->op()->opcode()) { + case OPCODE_A2: + case OPCODE_B2: + CHECK_EQ(2, node->InputCount()); + Node* x = node->InputAt(0); + Node* y = node->InputAt(1); + if (x->id() > y->id()) { + node->ReplaceInput(0, y); + node->ReplaceInput(1, x); + return Replace(node); + } + } + return NoChange(); + } +}; + + +// Simply records the nodes visited. +class ReducerRecorder : public Reducer { + public: + explicit ReducerRecorder(Zone* zone) + : set(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {} + virtual Reduction Reduce(Node* node) { + set.insert(node); + return NoChange(); + } + void CheckContains(Node* node) { + CHECK_EQ(1, static_cast<int>(set.count(node))); + } + NodeSet set; +}; + + +TEST(ReduceGraphFromEnd1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = graph.NewNode(&OPA1, n1); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + ReducerRecorder recorder(graph.zone()); + reducer.AddReducer(&recorder); + reducer.ReduceGraph(); + recorder.CheckContains(n1); + recorder.CheckContains(end); +} + + +TEST(ReduceGraphFromEnd2) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = graph.NewNode(&OPA2, n2, n3); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + ReducerRecorder recorder(graph.zone()); + reducer.AddReducer(&recorder); + reducer.ReduceGraph(); + recorder.CheckContains(n1); + recorder.CheckContains(n2); + recorder.CheckContains(n3); + recorder.CheckContains(end); +} + + +TEST(ReduceInPlace1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = graph.NewNode(&OPA1, n1); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + InPlaceABReducer r; + reducer.AddReducer(&r); + + // Tests A* => B* with in-place updates. + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPB0, n1->op()); + CHECK_EQ(&OPB1, end->op()); + CHECK_EQ(n1, end->InputAt(0)); + } +} + + +TEST(ReduceInPlace2) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = graph.NewNode(&OPA2, n2, n3); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + InPlaceABReducer r; + reducer.AddReducer(&r); + + // Tests A* => B* with in-place updates. + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPB0, n1->op()); + CHECK_EQ(&OPB1, n2->op()); + CHECK_EQ(n1, n2->InputAt(0)); + CHECK_EQ(&OPB1, n3->op()); + CHECK_EQ(n1, n3->InputAt(0)); + CHECK_EQ(&OPB2, end->op()); + CHECK_EQ(n2, end->InputAt(0)); + CHECK_EQ(n3, end->InputAt(1)); + } +} + + +TEST(ReduceNew1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = graph.NewNode(&OPA2, n2, n3); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + NewABReducer r(&graph); + reducer.AddReducer(&r); + + // Tests A* => B* while creating new nodes. + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + if (i == 0) { + CHECK_NE(before, graph.NodeCount()); + } else { + CHECK_EQ(before, graph.NodeCount()); + } + Node* nend = graph.end(); + CHECK_NE(end, nend); // end() should be updated too. + + Node* nn2 = nend->InputAt(0); + Node* nn3 = nend->InputAt(1); + Node* nn1 = nn2->InputAt(0); + + CHECK_EQ(nn1, nn3->InputAt(0)); + + CHECK_EQ(&OPB0, nn1->op()); + CHECK_EQ(&OPB1, nn2->op()); + CHECK_EQ(&OPB1, nn3->op()); + CHECK_EQ(&OPB2, nend->op()); + } +} + + +TEST(Wrapping1) { + GraphTester graph; + + Node* end = graph.NewNode(&OPA0); + graph.SetEnd(end); + CHECK_EQ(1, graph.NodeCount()); + + GraphReducer reducer(&graph); + A0Wrapper r(&graph); + reducer.AddReducer(&r); + + reducer.ReduceGraph(); + CHECK_EQ(2, graph.NodeCount()); + + Node* nend = graph.end(); + CHECK_NE(end, nend); + CHECK_EQ(&OPB1, nend->op()); + CHECK_EQ(1, nend->InputCount()); + CHECK_EQ(end, nend->InputAt(0)); +} + + +TEST(Wrapping2) { + GraphTester graph; + + Node* end = graph.NewNode(&OPB0); + graph.SetEnd(end); + CHECK_EQ(1, graph.NodeCount()); + + GraphReducer reducer(&graph); + B0Wrapper r(&graph); + reducer.AddReducer(&r); + + reducer.ReduceGraph(); + CHECK_EQ(3, graph.NodeCount()); + + Node* nend = graph.end(); + CHECK_NE(end, nend); + CHECK_EQ(&OPC1, nend->op()); + CHECK_EQ(1, nend->InputCount()); + + Node* n1 = nend->InputAt(0); + CHECK_NE(end, n1); + CHECK_EQ(&OPC1, n1->op()); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(end, n1->InputAt(0)); +} + + +TEST(Forwarding1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = graph.NewNode(&OPA1, n1); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + A1Forwarder r; + reducer.AddReducer(&r); + + // Tests A1(x) => x + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPA0, n1->op()); + CHECK_EQ(n1, graph.end()); + } +} + + +TEST(Forwarding2) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = graph.NewNode(&OPA2, n2, n3); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + A1Forwarder r; + reducer.AddReducer(&r); + + // Tests reducing A2(A1(x), A1(y)) => A2(x, y). + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPA0, n1->op()); + CHECK_EQ(n1, end->InputAt(0)); + CHECK_EQ(n1, end->InputAt(1)); + CHECK_EQ(&OPA2, end->op()); + CHECK_EQ(0, n2->UseCount()); + CHECK_EQ(0, n3->UseCount()); + } +} + + +TEST(Forwarding3) { + // Tests reducing a chain of A1(A1(A1(A1(x)))) => x. + for (int i = 0; i < 8; i++) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = n1; + for (int j = 0; j < i; j++) { + end = graph.NewNode(&OPA1, end); + } + graph.SetEnd(end); + + GraphReducer reducer(&graph); + A1Forwarder r; + reducer.AddReducer(&r); + + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPA0, n1->op()); + CHECK_EQ(n1, graph.end()); + } + } +} + + +TEST(ReduceForward1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = graph.NewNode(&OPA2, n2, n3); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + InPlaceABReducer r; + B1Forwarder f; + reducer.AddReducer(&r); + reducer.AddReducer(&f); + + // Tests first reducing A => B, then B1(x) => x. + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPB0, n1->op()); + CHECK_EQ(&OPB1, n2->op()); + CHECK_EQ(n1, end->InputAt(0)); + CHECK_EQ(&OPB1, n3->op()); + CHECK_EQ(n1, end->InputAt(0)); + CHECK_EQ(&OPB2, end->op()); + CHECK_EQ(0, n2->UseCount()); + CHECK_EQ(0, n3->UseCount()); + } +} + + +TEST(Sorter1) { + HandleAndZoneScope scope; + AB2Sorter r; + for (int i = 0; i < 6; i++) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* n2 = graph.NewNode(&OPA1, n1); + Node* n3 = graph.NewNode(&OPA1, n1); + Node* end = NULL; // Initialize to please the compiler. + + if (i == 0) end = graph.NewNode(&OPA2, n2, n3); + if (i == 1) end = graph.NewNode(&OPA2, n3, n2); + if (i == 2) end = graph.NewNode(&OPA2, n2, n1); + if (i == 3) end = graph.NewNode(&OPA2, n1, n2); + if (i == 4) end = graph.NewNode(&OPA2, n3, n1); + if (i == 5) end = graph.NewNode(&OPA2, n1, n3); + + graph.SetEnd(end); + + GraphReducer reducer(&graph); + reducer.AddReducer(&r); + + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPA0, n1->op()); + CHECK_EQ(&OPA1, n2->op()); + CHECK_EQ(&OPA1, n3->op()); + CHECK_EQ(&OPA2, end->op()); + CHECK_EQ(end, graph.end()); + CHECK(end->InputAt(0)->id() <= end->InputAt(1)->id()); + } +} + + +// Generate a node graph with the given permutations. +void GenDAG(Graph* graph, int* p3, int* p2, int* p1) { + Node* level4 = graph->NewNode(&OPA0); + Node* level3[] = {graph->NewNode(&OPA1, level4), + graph->NewNode(&OPA1, level4)}; + + Node* level2[] = {graph->NewNode(&OPA1, level3[p3[0]]), + graph->NewNode(&OPA1, level3[p3[1]]), + graph->NewNode(&OPA1, level3[p3[0]]), + graph->NewNode(&OPA1, level3[p3[1]])}; + + Node* level1[] = {graph->NewNode(&OPA2, level2[p2[0]], level2[p2[1]]), + graph->NewNode(&OPA2, level2[p2[2]], level2[p2[3]])}; + + Node* end = graph->NewNode(&OPA2, level1[p1[0]], level1[p1[1]]); + graph->SetEnd(end); +} + + +TEST(SortForwardReduce) { + GraphTester graph; + + // Tests combined reductions on a series of DAGs. + for (int j = 0; j < 2; j++) { + int p3[] = {j, 1 - j}; + for (int m = 0; m < 2; m++) { + int p1[] = {m, 1 - m}; + for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3 + int p2[] = {-1, -1, -1, -1}; + int n = k; + for (int d = 4; d >= 1; d--) { // Construct permutation. + int p = n % d; + for (int z = 0; z < 4; z++) { + if (p2[z] == -1) { + if (p == 0) p2[z] = d - 1; + p--; + } + } + n = n / d; + } + + GenDAG(&graph, p3, p2, p1); + + GraphReducer reducer(&graph); + AB2Sorter r1; + A1Forwarder r2; + InPlaceABReducer r3; + reducer.AddReducer(&r1); + reducer.AddReducer(&r2); + reducer.AddReducer(&r3); + + reducer.ReduceGraph(); + + Node* end = graph.end(); + CHECK_EQ(&OPB2, end->op()); + Node* n1 = end->InputAt(0); + Node* n2 = end->InputAt(1); + CHECK_NE(n1, n2); + CHECK(n1->id() < n2->id()); + CHECK_EQ(&OPB2, n1->op()); + CHECK_EQ(&OPB2, n2->op()); + Node* n4 = n1->InputAt(0); + CHECK_EQ(&OPB0, n4->op()); + CHECK_EQ(n4, n1->InputAt(1)); + CHECK_EQ(n4, n2->InputAt(0)); + CHECK_EQ(n4, n2->InputAt(1)); + } + } + } +} + + +TEST(Order) { + // Test that the order of reducers doesn't matter, as they should be + // rerun for changed nodes. + for (int i = 0; i < 2; i++) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = graph.NewNode(&OPA1, n1); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + InPlaceABReducer abr; + InPlaceBCReducer bcr; + if (i == 0) { + reducer.AddReducer(&abr); + reducer.AddReducer(&bcr); + } else { + reducer.AddReducer(&bcr); + reducer.AddReducer(&abr); + } + + // Tests A* => C* with in-place updates. + for (int i = 0; i < 3; i++) { + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPC0, n1->op()); + CHECK_EQ(&OPC1, end->op()); + CHECK_EQ(n1, end->InputAt(0)); + } + } +} + + +// Tests that a reducer is only applied once. +class OneTimeReducer : public Reducer { + public: + OneTimeReducer(Reducer* reducer, Zone* zone) + : reducer_(reducer), + nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {} + virtual Reduction Reduce(Node* node) { + CHECK_EQ(0, static_cast<int>(nodes_.count(node))); + nodes_.insert(node); + return reducer_->Reduce(node); + } + Reducer* reducer_; + NodeSet nodes_; +}; + + +TEST(OneTimeReduce1) { + GraphTester graph; + + Node* n1 = graph.NewNode(&OPA0); + Node* end = graph.NewNode(&OPA1, n1); + graph.SetEnd(end); + + GraphReducer reducer(&graph); + InPlaceABReducer r; + OneTimeReducer once(&r, graph.zone()); + reducer.AddReducer(&once); + + // Tests A* => B* with in-place updates. Should only be applied once. + int before = graph.NodeCount(); + reducer.ReduceGraph(); + CHECK_EQ(before, graph.NodeCount()); + CHECK_EQ(&OPB0, n1->op()); + CHECK_EQ(&OPB1, end->op()); + CHECK_EQ(n1, end->InputAt(0)); +} diff --git a/deps/v8/test/cctest/compiler/test-instruction-selector-arm.cc b/deps/v8/test/cctest/compiler/test-instruction-selector-arm.cc new file mode 100644 index 0000000000..f62e09f978 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-instruction-selector-arm.cc @@ -0,0 +1,1863 @@ +// 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 <list> + +#include "test/cctest/compiler/instruction-selector-tester.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +namespace { + +typedef RawMachineAssembler::Label MLabel; + +struct DPI { + Operator* op; + ArchOpcode arch_opcode; + ArchOpcode reverse_arch_opcode; + ArchOpcode test_arch_opcode; +}; + + +// ARM data processing instructions. +class DPIs V8_FINAL : public std::list<DPI>, private HandleAndZoneScope { + public: + DPIs() { + MachineOperatorBuilder machine(main_zone()); + DPI and_ = {machine.Word32And(), kArmAnd, kArmAnd, kArmTst}; + push_back(and_); + DPI or_ = {machine.Word32Or(), kArmOrr, kArmOrr, kArmOrr}; + push_back(or_); + DPI xor_ = {machine.Word32Xor(), kArmEor, kArmEor, kArmTeq}; + push_back(xor_); + DPI add = {machine.Int32Add(), kArmAdd, kArmAdd, kArmCmn}; + push_back(add); + DPI sub = {machine.Int32Sub(), kArmSub, kArmRsb, kArmCmp}; + push_back(sub); + } +}; + + +struct ODPI { + Operator* op; + ArchOpcode arch_opcode; + ArchOpcode reverse_arch_opcode; +}; + + +// ARM data processing instructions with overflow. +class ODPIs V8_FINAL : public std::list<ODPI>, private HandleAndZoneScope { + public: + ODPIs() { + MachineOperatorBuilder machine(main_zone()); + ODPI add = {machine.Int32AddWithOverflow(), kArmAdd, kArmAdd}; + push_back(add); + ODPI sub = {machine.Int32SubWithOverflow(), kArmSub, kArmRsb}; + push_back(sub); + } +}; + + +// ARM immediates. +class Immediates V8_FINAL : public std::list<int32_t> { + public: + Immediates() { + for (uint32_t imm8 = 0; imm8 < 256; ++imm8) { + for (uint32_t rot4 = 0; rot4 < 32; rot4 += 2) { + int32_t imm = (imm8 >> rot4) | (imm8 << (32 - rot4)); + CHECK(Assembler::ImmediateFitsAddrMode1Instruction(imm)); + push_back(imm); + } + } + } +}; + + +struct Shift { + Operator* op; + int32_t i_low; // lowest possible immediate + int32_t i_high; // highest possible immediate + AddressingMode i_mode; // Operand2_R_<shift>_I + AddressingMode r_mode; // Operand2_R_<shift>_R +}; + + +// ARM shifts. +class Shifts V8_FINAL : public std::list<Shift>, private HandleAndZoneScope { + public: + Shifts() { + MachineOperatorBuilder machine(main_zone()); + Shift sar = {machine.Word32Sar(), 1, 32, kMode_Operand2_R_ASR_I, + kMode_Operand2_R_ASR_R}; + Shift shl = {machine.Word32Shl(), 0, 31, kMode_Operand2_R_LSL_I, + kMode_Operand2_R_LSL_R}; + Shift shr = {machine.Word32Shr(), 1, 32, kMode_Operand2_R_LSR_I, + kMode_Operand2_R_LSR_R}; + push_back(sar); + push_back(shl); + push_back(shr); + } +}; + +} // namespace + + +TEST(InstructionSelectorDPIP) { + DPIs dpis; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + InstructionSelectorTester m; + m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } +} + + +TEST(InstructionSelectorDPIImm) { + DPIs dpis; + Immediates immediates; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + for (Immediates::const_iterator j = immediates.begin(); + j != immediates.end(); ++j) { + int32_t imm = *j; + { + InstructionSelectorTester m; + m.Return(m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + } + } + } +} + + +TEST(InstructionSelectorDPIAndShiftP) { + DPIs dpis; + Shifts shifts; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { + Shift shift = *j; + { + InstructionSelectorTester m; + m.Return( + m.NewNode(dpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.NewNode(dpi.op, + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + } + } +} + + +TEST(InstructionSelectorDPIAndRotateRightP) { + DPIs dpis; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + { + InstructionSelectorTester m; + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = m.Word32Or( + m.Word32Shr(value, shift), + m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); + m.Return(m.NewNode(dpi.op, m.Parameter(0), ror)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), + m.Word32Shr(value, shift)); + m.Return(m.NewNode(dpi.op, m.Parameter(0), ror)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = m.Word32Or( + m.Word32Shr(value, shift), + m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); + m.Return(m.NewNode(dpi.op, ror, m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), + m.Word32Shr(value, shift)); + m.Return(m.NewNode(dpi.op, ror, m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + } + } +} + + +TEST(InstructionSelectorDPIAndShiftImm) { + DPIs dpis; + Shifts shifts; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { + Shift shift = *j; + for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { + { + InstructionSelectorTester m; + m.Return(m.NewNode( + dpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.NewNode( + dpi.op, m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm)), + m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + } + } + } + } +} + + +TEST(InstructionSelectorODPIP) { + ODPIs odpis; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + { + InstructionSelectorTester m; + m.Return( + m.Projection(1, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return( + m.Projection(0, m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + } +} + + +TEST(InstructionSelectorODPIImm) { + ODPIs odpis; + Immediates immediates; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + for (Immediates::const_iterator j = immediates.begin(); + j != immediates.end(); ++j) { + int32_t imm = *j; + { + InstructionSelectorTester m; + m.Return(m.Projection( + 1, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 1, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 0, m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 0, m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + } + } +} + + +TEST(InstructionSelectorODPIAndShiftP) { + ODPIs odpis; + Shifts shifts; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { + Shift shift = *j; + { + InstructionSelectorTester m; + m.Return(m.Projection( + 1, m.NewNode(odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 1, m.NewNode(odpi.op, + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Parameter(2)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 0, m.NewNode(odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 0, m.NewNode(odpi.op, + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Parameter(2)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = + m.NewNode(odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode( + odpi.op, m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Parameter(2)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + } + } +} + + +TEST(InstructionSelectorODPIAndShiftImm) { + ODPIs odpis; + Shifts shifts; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + for (Shifts::const_iterator j = shifts.begin(); j != shifts.end(); ++j) { + Shift shift = *j; + for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { + { + InstructionSelectorTester m; + m.Return(m.Projection(1, m.NewNode(odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), + m.Int32Constant(imm))))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 1, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), + m.Int32Constant(imm)), + m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection(0, m.NewNode(odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), + m.Int32Constant(imm))))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + m.Return(m.Projection( + 0, m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), + m.Int32Constant(imm)), + m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_none, m.code[0]->flags_mode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_LE(1, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode( + odpi.op, m.Parameter(0), + m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm))); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + { + InstructionSelectorTester m; + Node* node = m.NewNode(odpi.op, m.NewNode(shift.op, m.Parameter(0), + m.Int32Constant(imm)), + m.Parameter(1)); + m.Return(m.Word32Equal(m.Projection(0, node), m.Projection(1, node))); + m.SelectInstructions(); + CHECK_LE(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(2))); + CHECK_EQ(2, m.code[0]->OutputCount()); + } + } + } + } +} + + +TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1P) { + { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Parameter(0), + m.Word32Xor(m.Int32Constant(-1), m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Parameter(0), + m.Word32Xor(m.Parameter(1), m.Int32Constant(-1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)), + m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)), + m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } +} + + +TEST(InstructionSelectorWord32AndAndWord32XorWithMinus1AndShiftP) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + { + InstructionSelectorTester m; + m.Return(m.Word32And( + m.Parameter(0), + m.Word32Xor(m.Int32Constant(-1), + m.NewNode(shift.op, m.Parameter(1), m.Parameter(2))))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And( + m.Parameter(0), + m.Word32Xor(m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)), + m.Int32Constant(-1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And( + m.Word32Xor(m.Int32Constant(-1), + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1))), + m.Parameter(2))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32And( + m.Word32Xor(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Int32Constant(-1)), + m.Parameter(2))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBic, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + } +} + + +TEST(InstructionSelectorWord32XorWithMinus1P) { + { + InstructionSelectorTester m; + m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + } +} + + +TEST(InstructionSelectorWord32XorWithMinus1AndShiftP) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + { + InstructionSelectorTester m; + m.Return( + m.Word32Xor(m.Int32Constant(-1), + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Xor(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), + m.Int32Constant(-1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMvn, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + } + } +} + + +TEST(InstructionSelectorShiftP) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + InstructionSelectorTester m; + m.Return(m.NewNode(shift.op, m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + } +} + + +TEST(InstructionSelectorShiftImm) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { + InstructionSelectorTester m; + m.Return(m.NewNode(shift.op, m.Parameter(0), m.Int32Constant(imm))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + } +} + + +TEST(InstructionSelectorRotateRightP) { + { + InstructionSelectorTester m; + Node* value = m.Parameter(0); + Node* shift = m.Parameter(1); + m.Return( + m.Word32Or(m.Word32Shr(value, shift), + m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + } + { + InstructionSelectorTester m; + Node* value = m.Parameter(0); + Node* shift = m.Parameter(1); + m.Return( + m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), + m.Word32Shr(value, shift))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + } +} + + +TEST(InstructionSelectorRotateRightImm) { + FOR_INPUTS(uint32_t, ror, i) { + uint32_t shift = *i; + { + InstructionSelectorTester m; + Node* value = m.Parameter(0); + m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), + m.Word32Shl(value, m.Int32Constant(32 - shift)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1))); + } + { + InstructionSelectorTester m; + Node* value = m.Parameter(0); + m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), + m.Word32Shr(value, m.Int32Constant(shift)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMov, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(1))); + } + } +} + + +TEST(InstructionSelectorInt32MulP) { + InstructionSelectorTester m; + m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMul, m.code[0]->arch_opcode()); +} + + +TEST(InstructionSelectorInt32MulImm) { + // x * (2^k + 1) -> (x >> k) + x + for (int k = 1; k < 31; ++k) { + InstructionSelectorTester m; + m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmAdd, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); + } + // (2^k + 1) * x -> (x >> k) + x + for (int k = 1; k < 31; ++k) { + InstructionSelectorTester m; + m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmAdd, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); + } + // x * (2^k - 1) -> (x >> k) - x + for (int k = 3; k < 31; ++k) { + InstructionSelectorTester m; + m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmRsb, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); + } + // (2^k - 1) * x -> (x >> k) - x + for (int k = 3; k < 31; ++k) { + InstructionSelectorTester m; + m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmRsb, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_LSL_I, m.code[0]->addressing_mode()); + } +} + + +TEST(InstructionSelectorWord32AndImm_ARMv7) { + for (uint32_t width = 1; width <= 32; ++width) { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Parameter(0), + m.Int32Constant(0xffffffffu >> (32 - width)))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(0, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + for (uint32_t lsb = 0; lsb <= 31; ++lsb) { + for (uint32_t width = 1; width < 32 - lsb; ++width) { + uint32_t msk = ~((0xffffffffu >> (32 - width)) << lsb); + InstructionSelectorTester m; + m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(msk))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmBfc, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK(UnallocatedOperand::cast(m.code[0]->Output()) + ->HasSameAsInputPolicy()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + } +} + + +TEST(InstructionSelectorWord32AndAndWord32ShrImm_ARMv7) { + for (uint32_t lsb = 0; lsb <= 31; ++lsb) { + for (uint32_t width = 1; width <= 32 - lsb; ++width) { + { + InstructionSelectorTester m; + m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), + m.Int32Constant(0xffffffffu >> (32 - width)))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + { + InstructionSelectorTester m; + m.Return( + m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), + m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + } + } +} + + +TEST(InstructionSelectorWord32ShrAndWord32AndImm_ARMv7) { + for (uint32_t lsb = 0; lsb <= 31; ++lsb) { + for (uint32_t width = 1; width <= 32 - lsb; ++width) { + uint32_t max = 1 << lsb; + if (max > static_cast<uint32_t>(kMaxInt)) max -= 1; + uint32_t jnk = CcTest::random_number_generator()->NextInt(max); + uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk; + { + InstructionSelectorTester m; + m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)), + m.Int32Constant(lsb))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)), + m.Int32Constant(lsb))); + m.SelectInstructions(ARMv7); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUbfx, m.code[0]->arch_opcode()); + CHECK_EQ(3, m.code[0]->InputCount()); + CHECK_EQ(lsb, m.ToInt32(m.code[0]->InputAt(1))); + CHECK_EQ(width, m.ToInt32(m.code[0]->InputAt(2))); + } + } + } +} + + +TEST(InstructionSelectorInt32SubAndInt32MulP) { + InstructionSelectorTester m; + m.Return( + m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + m.SelectInstructions(); + CHECK_EQ(2, m.code.size()); + CHECK_EQ(kArmMul, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(kArmSub, m.code[1]->arch_opcode()); + CHECK_EQ(2, m.code[1]->InputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(1)); +} + + +TEST(InstructionSelectorInt32SubAndInt32MulP_MLS) { + InstructionSelectorTester m; + m.Return( + m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + m.SelectInstructions(MLS); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmMls, m.code[0]->arch_opcode()); +} + + +TEST(InstructionSelectorInt32DivP) { + InstructionSelectorTester m; + m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(4, m.code.size()); + CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); + CHECK_EQ(2, m.code[2]->InputCount()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); + CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode()); + CHECK_EQ(1, m.code[3]->InputCount()); + CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); +} + + +TEST(InstructionSelectorInt32DivP_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(SUDIV); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); +} + + +TEST(InstructionSelectorInt32UDivP) { + InstructionSelectorTester m; + m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(4, m.code.size()); + CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); + CHECK_EQ(2, m.code[2]->InputCount()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); + CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode()); + CHECK_EQ(1, m.code[3]->InputCount()); + CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); +} + + +TEST(InstructionSelectorInt32UDivP_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(SUDIV); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); +} + + +TEST(InstructionSelectorInt32ModP) { + InstructionSelectorTester m; + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(6, m.code.size()); + CHECK_EQ(kArmVcvtF64S32, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(kArmVcvtF64S32, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); + CHECK_EQ(2, m.code[2]->InputCount()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); + CHECK_EQ(kArmVcvtS32F64, m.code[3]->arch_opcode()); + CHECK_EQ(1, m.code[3]->InputCount()); + CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); + CHECK_EQ(kArmMul, m.code[4]->arch_opcode()); + CHECK_EQ(1, m.code[4]->OutputCount()); + CHECK_EQ(2, m.code[4]->InputCount()); + CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0)); + CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1)); + CHECK_EQ(kArmSub, m.code[5]->arch_opcode()); + CHECK_EQ(1, m.code[5]->OutputCount()); + CHECK_EQ(2, m.code[5]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0)); + CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1)); +} + + +TEST(InstructionSelectorInt32ModP_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(SUDIV); + CHECK_EQ(3, m.code.size()); + CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(kArmMul, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(2, m.code[1]->InputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); + CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); + CHECK_EQ(kArmSub, m.code[2]->arch_opcode()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CHECK_EQ(2, m.code[2]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); +} + + +TEST(InstructionSelectorInt32ModP_MLS_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(MLS, SUDIV); + CHECK_EQ(2, m.code.size()); + CHECK_EQ(kArmSdiv, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(kArmMls, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(3, m.code[1]->InputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); + CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); + CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2)); +} + + +TEST(InstructionSelectorInt32UModP) { + InstructionSelectorTester m; + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(6, m.code.size()); + CHECK_EQ(kArmVcvtF64U32, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(kArmVcvtF64U32, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(kArmVdivF64, m.code[2]->arch_opcode()); + CHECK_EQ(2, m.code[2]->InputCount()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); + CHECK_EQ(kArmVcvtU32F64, m.code[3]->arch_opcode()); + CHECK_EQ(1, m.code[3]->InputCount()); + CheckSameVreg(m.code[2]->Output(), m.code[3]->InputAt(0)); + CHECK_EQ(kArmMul, m.code[4]->arch_opcode()); + CHECK_EQ(1, m.code[4]->OutputCount()); + CHECK_EQ(2, m.code[4]->InputCount()); + CheckSameVreg(m.code[3]->Output(), m.code[4]->InputAt(0)); + CheckSameVreg(m.code[1]->InputAt(0), m.code[4]->InputAt(1)); + CHECK_EQ(kArmSub, m.code[5]->arch_opcode()); + CHECK_EQ(1, m.code[5]->OutputCount()); + CHECK_EQ(2, m.code[5]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[5]->InputAt(0)); + CheckSameVreg(m.code[4]->Output(), m.code[5]->InputAt(1)); +} + + +TEST(InstructionSelectorInt32UModP_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(SUDIV); + CHECK_EQ(3, m.code.size()); + CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(kArmMul, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(2, m.code[1]->InputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); + CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); + CHECK_EQ(kArmSub, m.code[2]->arch_opcode()); + CHECK_EQ(1, m.code[2]->OutputCount()); + CHECK_EQ(2, m.code[2]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[2]->InputAt(0)); + CheckSameVreg(m.code[1]->Output(), m.code[2]->InputAt(1)); +} + + +TEST(InstructionSelectorInt32UModP_MLS_SUDIV) { + InstructionSelectorTester m; + m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(MLS, SUDIV); + CHECK_EQ(2, m.code.size()); + CHECK_EQ(kArmUdiv, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(kArmMls, m.code[1]->arch_opcode()); + CHECK_EQ(1, m.code[1]->OutputCount()); + CHECK_EQ(3, m.code[1]->InputCount()); + CheckSameVreg(m.code[0]->Output(), m.code[1]->InputAt(0)); + CheckSameVreg(m.code[0]->InputAt(1), m.code[1]->InputAt(1)); + CheckSameVreg(m.code[0]->InputAt(0), m.code[1]->InputAt(2)); +} + + +TEST(InstructionSelectorWord32EqualP) { + InstructionSelectorTester m; + m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); +} + + +TEST(InstructionSelectorWord32EqualImm) { + Immediates immediates; + for (Immediates::const_iterator i = immediates.begin(); i != immediates.end(); + ++i) { + int32_t imm = *i; + { + InstructionSelectorTester m; + m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + if (imm == 0) { + CHECK_EQ(kArmTst, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1)); + } else { + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + } + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + if (imm == 0) { + CHECK_EQ(kArmTst, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CheckSameVreg(m.code[0]->InputAt(0), m.code[0]->InputAt(1)); + } else { + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + } + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorWord32EqualAndDPIP) { + DPIs dpis; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + { + InstructionSelectorTester m; + m.Return(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), + m.Int32Constant(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return( + m.Word32Equal(m.Int32Constant(0), + m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorWord32EqualAndDPIImm) { + DPIs dpis; + Immediates immediates; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + for (Immediates::const_iterator j = immediates.begin(); + j != immediates.end(); ++j) { + int32_t imm = *j; + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)), + m.Int32Constant(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)), + m.Int32Constant(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.Int32Constant(0), + m.NewNode(dpi.op, m.Parameter(0), m.Int32Constant(imm)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.Int32Constant(0), + m.NewNode(dpi.op, m.Int32Constant(imm), m.Parameter(0)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } + } +} + + +TEST(InstructionSelectorWord32EqualAndShiftP) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + m.Return(m.Word32Equal( + m.NewNode(shift.op, m.Parameter(0), m.Parameter(1)), m.Parameter(2))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_set, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorBranchWithWord32EqualAndShiftP) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), + m.Parameter(2))), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.NewNode(shift.op, m.Parameter(1), m.Parameter(2)), + m.Parameter(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.r_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorBranchWithWord32EqualAndShiftImm) { + Shifts shifts; + for (Shifts::const_iterator i = shifts.begin(); i != shifts.end(); ++i) { + Shift shift = *i; + for (int32_t imm = shift.i_low; imm <= shift.i_high; ++imm) { + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Parameter(0), m.NewNode(shift.op, m.Parameter(1), + m.Int32Constant(imm))), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch(m.Word32Equal( + m.NewNode(shift.op, m.Parameter(1), m.Int32Constant(imm)), + m.Parameter(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(shift.i_mode, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } + } +} + + +TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightP) { + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shr(value, shift), + m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); + m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), + m.Word32Shr(value, shift)); + m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shr(value, shift), + m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift))); + m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* shift = m.Parameter(2); + Node* ror = + m.Word32Or(m.Word32Shl(value, m.Int32Sub(m.Int32Constant(32), shift)), + m.Word32Shr(value, shift)); + m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } +} + + +TEST(InstructionSelectorBranchWithWord32EqualAndRotateRightImm) { + FOR_INPUTS(uint32_t, ror, i) { + uint32_t shift = *i; + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), + m.Word32Shl(value, m.Int32Constant(32 - shift))); + m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + CHECK_LE(3, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), + m.Word32Shr(value, m.Int32Constant(shift))); + m.Branch(m.Word32Equal(input, ror), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + CHECK_LE(3, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* ror = m.Word32Or(m.Word32Shr(value, m.Int32Constant(shift)), + m.Word32Shl(value, m.Int32Constant(32 - shift))); + m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + CHECK_LE(3, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* input = m.Parameter(0); + Node* value = m.Parameter(1); + Node* ror = m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - shift)), + m.Word32Shr(value, m.Int32Constant(shift))); + m.Branch(m.Word32Equal(ror, input), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kArmCmp, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R_ROR_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + CHECK_LE(3, m.code[0]->InputCount()); + CHECK_EQ(shift, m.ToInt32(m.code[0]->InputAt(2))); + } + } +} + + +TEST(InstructionSelectorBranchWithDPIP) { + DPIs dpis; + for (DPIs::const_iterator i = dpis.begin(); i != dpis.end(); ++i) { + DPI dpi = *i; + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), &blocka, + &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kNotEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Int32Constant(0), + m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1))), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.NewNode(dpi.op, m.Parameter(0), m.Parameter(1)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(dpi.test_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kEqual, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorBranchWithODPIP) { + ODPIs odpis; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); + m.Branch(m.Projection(1, node), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); + m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Parameter(1)); + m.Branch(m.Word32Equal(m.Int32Constant(0), m.Projection(1, node)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_R, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); + } + } +} + + +TEST(InstructionSelectorBranchWithODPIImm) { + ODPIs odpis; + Immediates immediates; + for (ODPIs::const_iterator i = odpis.begin(); i != odpis.end(); ++i) { + ODPI odpi = *i; + for (Immediates::const_iterator j = immediates.begin(); + j != immediates.end(); ++j) { + int32_t imm = *j; + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); + m.Branch(m.Projection(1, node), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_LE(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); + m.Branch(m.Projection(1, node), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kOverflow, m.code[0]->flags_condition()); + CHECK_LE(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Parameter(0), m.Int32Constant(imm)); + m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); + CHECK_LE(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + { + InstructionSelectorTester m; + MLabel blocka, blockb; + Node* node = m.NewNode(odpi.op, m.Int32Constant(imm), m.Parameter(0)); + m.Branch(m.Word32Equal(m.Projection(1, node), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0)); + m.Bind(&blockb); + m.Return(m.Projection(0, node)); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(odpi.reverse_arch_opcode, m.code[0]->arch_opcode()); + CHECK_EQ(kMode_Operand2_I, m.code[0]->addressing_mode()); + CHECK_EQ(kFlags_branch, m.code[0]->flags_mode()); + CHECK_EQ(kNotOverflow, m.code[0]->flags_condition()); + CHECK_LE(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + } + } +} diff --git a/deps/v8/test/cctest/compiler/test-instruction-selector-ia32.cc b/deps/v8/test/cctest/compiler/test-instruction-selector-ia32.cc new file mode 100644 index 0000000000..b6509584e0 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-instruction-selector-ia32.cc @@ -0,0 +1,66 @@ +// 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 "test/cctest/compiler/instruction-selector-tester.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(InstructionSelectorInt32AddP) { + InstructionSelectorTester m; + m.Return(m.Int32Add(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); +} + + +TEST(InstructionSelectorInt32AddImm) { + FOR_INT32_INPUTS(i) { + int32_t imm = *i; + { + InstructionSelectorTester m; + m.Return(m.Int32Add(m.Parameter(0), m.Int32Constant(imm))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + { + InstructionSelectorTester m; + m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kIA32Add, m.code[0]->arch_opcode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } + } +} + + +TEST(InstructionSelectorInt32SubP) { + InstructionSelectorTester m; + m.Return(m.Int32Sub(m.Parameter(0), m.Parameter(1))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode()); + CHECK_EQ(1, m.code[0]->OutputCount()); +} + + +TEST(InstructionSelectorInt32SubImm) { + FOR_INT32_INPUTS(i) { + int32_t imm = *i; + InstructionSelectorTester m; + m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm))); + m.SelectInstructions(); + CHECK_EQ(1, m.code.size()); + CHECK_EQ(kIA32Sub, m.code[0]->arch_opcode()); + CHECK_EQ(2, m.code[0]->InputCount()); + CHECK_EQ(imm, m.ToInt32(m.code[0]->InputAt(1))); + } +} diff --git a/deps/v8/test/cctest/compiler/test-instruction-selector.cc b/deps/v8/test/cctest/compiler/test-instruction-selector.cc new file mode 100644 index 0000000000..e59406426e --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-instruction-selector.cc @@ -0,0 +1,22 @@ +// 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 "test/cctest/compiler/instruction-selector-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +#if V8_TURBOFAN_TARGET + +TEST(InstructionSelectionReturnZero) { + InstructionSelectorTester m; + m.Return(m.Int32Constant(0)); + m.SelectInstructions(InstructionSelectorTester::kInternalMode); + CHECK_EQ(2, static_cast<int>(m.code.size())); + CHECK_EQ(kArchNop, m.code[0]->opcode()); + CHECK_EQ(kArchRet, m.code[1]->opcode()); + CHECK_EQ(1, static_cast<int>(m.code[1]->InputCount())); +} + +#endif // !V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-instruction.cc b/deps/v8/test/cctest/compiler/test-instruction.cc new file mode 100644 index 0000000000..bc9f4c7723 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-instruction.cc @@ -0,0 +1,350 @@ +// 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.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" +#include "src/compiler/operator.h" +#include "src/compiler/schedule.h" +#include "src/compiler/scheduler.h" +#include "src/lithium.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +typedef v8::internal::compiler::Instruction TestInstr; +typedef v8::internal::compiler::InstructionSequence TestInstrSeq; + +// A testing helper for the register code abstraction. +class InstructionTester : public HandleAndZoneScope { + public: // We're all friends here. + InstructionTester() + : isolate(main_isolate()), + graph(zone()), + schedule(zone()), + info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()), + linkage(&info), + common(zone()), + machine(zone(), kMachineWord32), + code(NULL) {} + + ~InstructionTester() { delete code; } + + Isolate* isolate; + Graph graph; + Schedule schedule; + CompilationInfoWithZone info; + Linkage linkage; + CommonOperatorBuilder common; + MachineOperatorBuilder machine; + TestInstrSeq* code; + + Zone* zone() { return main_zone(); } + + void allocCode() { + if (schedule.rpo_order()->size() == 0) { + // Compute the RPO order. + Scheduler::ComputeSpecialRPO(&schedule); + DCHECK(schedule.rpo_order()->size() > 0); + } + code = new TestInstrSeq(&linkage, &graph, &schedule); + } + + Node* Int32Constant(int32_t val) { + Node* node = graph.NewNode(common.Int32Constant(val)); + schedule.AddNode(schedule.entry(), node); + return node; + } + + Node* Float64Constant(double val) { + Node* node = graph.NewNode(common.Float64Constant(val)); + schedule.AddNode(schedule.entry(), node); + return node; + } + + Node* Parameter(int32_t which) { + Node* node = graph.NewNode(common.Parameter(which)); + schedule.AddNode(schedule.entry(), node); + return node; + } + + Node* NewNode(BasicBlock* block) { + Node* node = graph.NewNode(common.Int32Constant(111)); + schedule.AddNode(block, node); + return node; + } + + int NewInstr(BasicBlock* block) { + InstructionCode opcode = static_cast<InstructionCode>(110); + TestInstr* instr = TestInstr::New(zone(), opcode); + return code->AddInstruction(instr, block); + } + + UnallocatedOperand* NewUnallocated(int vreg) { + UnallocatedOperand* unallocated = + new (zone()) UnallocatedOperand(UnallocatedOperand::ANY); + unallocated->set_virtual_register(vreg); + return unallocated; + } +}; + + +TEST(InstructionBasic) { + InstructionTester R; + + for (int i = 0; i < 10; i++) { + R.Int32Constant(i); // Add some nodes to the graph. + } + + BasicBlock* last = R.schedule.entry(); + for (int i = 0; i < 5; i++) { + BasicBlock* block = R.schedule.NewBasicBlock(); + R.schedule.AddGoto(last, block); + last = block; + } + + R.allocCode(); + + CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount()); + + BasicBlockVector* blocks = R.schedule.rpo_order(); + CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount()); + + int index = 0; + for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end(); + i++, index++) { + BasicBlock* block = *i; + CHECK_EQ(block, R.code->BlockAt(index)); + CHECK_EQ(-1, R.code->GetLoopEnd(block)); + } +} + + +TEST(InstructionGetBasicBlock) { + InstructionTester R; + + BasicBlock* b0 = R.schedule.entry(); + BasicBlock* b1 = R.schedule.NewBasicBlock(); + BasicBlock* b2 = R.schedule.NewBasicBlock(); + BasicBlock* b3 = R.schedule.exit(); + + R.schedule.AddGoto(b0, b1); + R.schedule.AddGoto(b1, b2); + R.schedule.AddGoto(b2, b3); + + R.allocCode(); + + R.code->StartBlock(b0); + int i0 = R.NewInstr(b0); + int i1 = R.NewInstr(b0); + R.code->EndBlock(b0); + R.code->StartBlock(b1); + int i2 = R.NewInstr(b1); + int i3 = R.NewInstr(b1); + int i4 = R.NewInstr(b1); + int i5 = R.NewInstr(b1); + R.code->EndBlock(b1); + R.code->StartBlock(b2); + int i6 = R.NewInstr(b2); + int i7 = R.NewInstr(b2); + int i8 = R.NewInstr(b2); + R.code->EndBlock(b2); + R.code->StartBlock(b3); + R.code->EndBlock(b3); + + CHECK_EQ(b0, R.code->GetBasicBlock(i0)); + CHECK_EQ(b0, R.code->GetBasicBlock(i1)); + + CHECK_EQ(b1, R.code->GetBasicBlock(i2)); + CHECK_EQ(b1, R.code->GetBasicBlock(i3)); + CHECK_EQ(b1, R.code->GetBasicBlock(i4)); + CHECK_EQ(b1, R.code->GetBasicBlock(i5)); + + CHECK_EQ(b2, R.code->GetBasicBlock(i6)); + CHECK_EQ(b2, R.code->GetBasicBlock(i7)); + CHECK_EQ(b2, R.code->GetBasicBlock(i8)); + + CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index())); + CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index())); + + CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index())); + CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index())); + + CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index())); + CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index())); + + CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index())); + CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index())); +} + + +TEST(InstructionIsGapAt) { + InstructionTester R; + + BasicBlock* b0 = R.schedule.entry(); + R.schedule.AddReturn(b0, R.Int32Constant(1)); + + R.allocCode(); + TestInstr* i0 = TestInstr::New(R.zone(), 100); + TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); + R.code->StartBlock(b0); + R.code->AddInstruction(i0, b0); + R.code->AddInstruction(g, b0); + R.code->EndBlock(b0); + + CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); + + CHECK_EQ(true, R.code->IsGapAt(0)); // Label + CHECK_EQ(true, R.code->IsGapAt(1)); // Gap + CHECK_EQ(false, R.code->IsGapAt(2)); // i0 + CHECK_EQ(true, R.code->IsGapAt(3)); // Gap + CHECK_EQ(true, R.code->IsGapAt(4)); // Gap + CHECK_EQ(false, R.code->IsGapAt(5)); // g +} + + +TEST(InstructionIsGapAt2) { + InstructionTester R; + + BasicBlock* b0 = R.schedule.entry(); + BasicBlock* b1 = R.schedule.exit(); + R.schedule.AddGoto(b0, b1); + R.schedule.AddReturn(b1, R.Int32Constant(1)); + + R.allocCode(); + TestInstr* i0 = TestInstr::New(R.zone(), 100); + TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); + R.code->StartBlock(b0); + R.code->AddInstruction(i0, b0); + R.code->AddInstruction(g, b0); + R.code->EndBlock(b0); + + TestInstr* i1 = TestInstr::New(R.zone(), 102); + TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl(); + R.code->StartBlock(b1); + R.code->AddInstruction(i1, b1); + R.code->AddInstruction(g1, b1); + R.code->EndBlock(b1); + + CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); + + CHECK_EQ(true, R.code->IsGapAt(0)); // Label + CHECK_EQ(true, R.code->IsGapAt(1)); // Gap + CHECK_EQ(false, R.code->IsGapAt(2)); // i0 + CHECK_EQ(true, R.code->IsGapAt(3)); // Gap + CHECK_EQ(true, R.code->IsGapAt(4)); // Gap + CHECK_EQ(false, R.code->IsGapAt(5)); // g + + CHECK_EQ(true, R.code->InstructionAt(6)->IsBlockStart()); + + CHECK_EQ(true, R.code->IsGapAt(6)); // Label + CHECK_EQ(true, R.code->IsGapAt(7)); // Gap + CHECK_EQ(false, R.code->IsGapAt(8)); // i1 + CHECK_EQ(true, R.code->IsGapAt(9)); // Gap + CHECK_EQ(true, R.code->IsGapAt(10)); // Gap + CHECK_EQ(false, R.code->IsGapAt(11)); // g1 +} + + +TEST(InstructionAddGapMove) { + InstructionTester R; + + BasicBlock* b0 = R.schedule.entry(); + R.schedule.AddReturn(b0, R.Int32Constant(1)); + + R.allocCode(); + TestInstr* i0 = TestInstr::New(R.zone(), 100); + TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); + R.code->StartBlock(b0); + R.code->AddInstruction(i0, b0); + R.code->AddInstruction(g, b0); + R.code->EndBlock(b0); + + CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart()); + + CHECK_EQ(true, R.code->IsGapAt(0)); // Label + CHECK_EQ(true, R.code->IsGapAt(1)); // Gap + CHECK_EQ(false, R.code->IsGapAt(2)); // i0 + CHECK_EQ(true, R.code->IsGapAt(3)); // Gap + CHECK_EQ(true, R.code->IsGapAt(4)); // Gap + CHECK_EQ(false, R.code->IsGapAt(5)); // g + + int indexes[] = {0, 1, 3, 4, -1}; + for (int i = 0; indexes[i] >= 0; i++) { + int index = indexes[i]; + + UnallocatedOperand* op1 = R.NewUnallocated(index + 6); + UnallocatedOperand* op2 = R.NewUnallocated(index + 12); + + R.code->AddGapMove(index, op1, op2); + GapInstruction* gap = R.code->GapAt(index); + ParallelMove* move = gap->GetParallelMove(GapInstruction::START); + CHECK_NE(NULL, move); + const ZoneList<MoveOperands>* move_operands = move->move_operands(); + CHECK_EQ(1, move_operands->length()); + MoveOperands* cur = &move_operands->at(0); + CHECK_EQ(op1, cur->source()); + CHECK_EQ(op2, cur->destination()); + } +} + + +TEST(InstructionOperands) { + Zone zone(CcTest::InitIsolateOnce()); + + { + TestInstr* i = TestInstr::New(&zone, 101); + CHECK_EQ(0, static_cast<int>(i->OutputCount())); + CHECK_EQ(0, static_cast<int>(i->InputCount())); + CHECK_EQ(0, static_cast<int>(i->TempCount())); + } + + InstructionOperand* outputs[] = { + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; + + InstructionOperand* inputs[] = { + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; + + InstructionOperand* temps[] = { + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER), + new (&zone) UnallocatedOperand(UnallocatedOperand::MUST_HAVE_REGISTER)}; + + for (size_t i = 0; i < ARRAY_SIZE(outputs); i++) { + for (size_t j = 0; j < ARRAY_SIZE(inputs); j++) { + for (size_t k = 0; k < ARRAY_SIZE(temps); k++) { + TestInstr* m = + TestInstr::New(&zone, 101, i, outputs, j, inputs, k, temps); + CHECK(i == m->OutputCount()); + CHECK(j == m->InputCount()); + CHECK(k == m->TempCount()); + + for (size_t z = 0; z < i; z++) { + CHECK_EQ(outputs[z], m->OutputAt(z)); + } + + for (size_t z = 0; z < j; z++) { + CHECK_EQ(inputs[z], m->InputAt(z)); + } + + for (size_t z = 0; z < k; z++) { + CHECK_EQ(temps[z], m->TempAt(z)); + } + } + } + } +} diff --git a/deps/v8/test/cctest/compiler/test-js-constant-cache.cc b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc new file mode 100644 index 0000000000..42a606d23c --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-js-constant-cache.cc @@ -0,0 +1,284 @@ +// 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 "src/compiler/js-graph.h" +#include "src/compiler/node-properties-inl.h" +#include "src/compiler/typer.h" +#include "src/types.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +class JSCacheTesterHelper { + protected: + explicit JSCacheTesterHelper(Zone* zone) + : main_graph_(zone), main_common_(zone), main_typer_(zone) {} + Graph main_graph_; + CommonOperatorBuilder main_common_; + Typer main_typer_; +}; + + +class JSConstantCacheTester : public HandleAndZoneScope, + public JSCacheTesterHelper, + public JSGraph { + public: + JSConstantCacheTester() + : JSCacheTesterHelper(main_zone()), + JSGraph(&main_graph_, &main_common_, &main_typer_) {} + + Type* upper(Node* node) { return NodeProperties::GetBounds(node).upper; } + + Handle<Object> handle(Node* node) { + CHECK_EQ(IrOpcode::kHeapConstant, node->opcode()); + return ValueOf<Handle<Object> >(node->op()); + } + + Factory* factory() { return main_isolate()->factory(); } +}; + + +TEST(ZeroConstant1) { + JSConstantCacheTester T; + + Node* zero = T.ZeroConstant(); + + CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode()); + CHECK_EQ(zero, T.Constant(0)); + CHECK_NE(zero, T.Constant(-0.0)); + CHECK_NE(zero, T.Constant(1.0)); + CHECK_NE(zero, T.Constant(v8::base::OS::nan_value())); + CHECK_NE(zero, T.Float64Constant(0)); + CHECK_NE(zero, T.Int32Constant(0)); + + Type* t = T.upper(zero); + + CHECK(t->Is(Type::Number())); + CHECK(t->Is(Type::Integral32())); + CHECK(t->Is(Type::Signed32())); + CHECK(t->Is(Type::Unsigned32())); + CHECK(t->Is(Type::SignedSmall())); + CHECK(t->Is(Type::UnsignedSmall())); +} + + +TEST(MinusZeroConstant) { + JSConstantCacheTester T; + + Node* minus_zero = T.Constant(-0.0); + Node* zero = T.ZeroConstant(); + + CHECK_EQ(IrOpcode::kNumberConstant, minus_zero->opcode()); + CHECK_EQ(minus_zero, T.Constant(-0.0)); + CHECK_NE(zero, minus_zero); + + Type* t = T.upper(minus_zero); + + CHECK(t->Is(Type::Number())); + CHECK(t->Is(Type::MinusZero())); + CHECK(!t->Is(Type::Integral32())); + CHECK(!t->Is(Type::Signed32())); + CHECK(!t->Is(Type::Unsigned32())); + CHECK(!t->Is(Type::SignedSmall())); + CHECK(!t->Is(Type::UnsignedSmall())); + + double zero_value = ValueOf<double>(zero->op()); + double minus_zero_value = ValueOf<double>(minus_zero->op()); + + CHECK_EQ(0.0, zero_value); + CHECK_NE(-0.0, zero_value); + CHECK_EQ(-0.0, minus_zero_value); + CHECK_NE(0.0, minus_zero_value); +} + + +TEST(ZeroConstant2) { + JSConstantCacheTester T; + + Node* zero = T.Constant(0); + + CHECK_EQ(IrOpcode::kNumberConstant, zero->opcode()); + CHECK_EQ(zero, T.ZeroConstant()); + CHECK_NE(zero, T.Constant(-0.0)); + CHECK_NE(zero, T.Constant(1.0)); + CHECK_NE(zero, T.Constant(v8::base::OS::nan_value())); + CHECK_NE(zero, T.Float64Constant(0)); + CHECK_NE(zero, T.Int32Constant(0)); + + Type* t = T.upper(zero); + + CHECK(t->Is(Type::Number())); + CHECK(t->Is(Type::Integral32())); + CHECK(t->Is(Type::Signed32())); + CHECK(t->Is(Type::Unsigned32())); + CHECK(t->Is(Type::SignedSmall())); + CHECK(t->Is(Type::UnsignedSmall())); +} + + +TEST(OneConstant1) { + JSConstantCacheTester T; + + Node* one = T.OneConstant(); + + CHECK_EQ(IrOpcode::kNumberConstant, one->opcode()); + CHECK_EQ(one, T.Constant(1)); + CHECK_EQ(one, T.Constant(1.0)); + CHECK_NE(one, T.Constant(1.01)); + CHECK_NE(one, T.Constant(-1.01)); + CHECK_NE(one, T.Constant(v8::base::OS::nan_value())); + CHECK_NE(one, T.Float64Constant(1.0)); + CHECK_NE(one, T.Int32Constant(1)); + + Type* t = T.upper(one); + + CHECK(t->Is(Type::Number())); + CHECK(t->Is(Type::Integral32())); + CHECK(t->Is(Type::Signed32())); + CHECK(t->Is(Type::Unsigned32())); + CHECK(t->Is(Type::SignedSmall())); + CHECK(t->Is(Type::UnsignedSmall())); +} + + +TEST(OneConstant2) { + JSConstantCacheTester T; + + Node* one = T.Constant(1); + + CHECK_EQ(IrOpcode::kNumberConstant, one->opcode()); + CHECK_EQ(one, T.OneConstant()); + CHECK_EQ(one, T.Constant(1.0)); + CHECK_NE(one, T.Constant(1.01)); + CHECK_NE(one, T.Constant(-1.01)); + CHECK_NE(one, T.Constant(v8::base::OS::nan_value())); + CHECK_NE(one, T.Float64Constant(1.0)); + CHECK_NE(one, T.Int32Constant(1)); + + Type* t = T.upper(one); + + CHECK(t->Is(Type::Number())); + CHECK(t->Is(Type::Integral32())); + CHECK(t->Is(Type::Signed32())); + CHECK(t->Is(Type::Unsigned32())); + CHECK(t->Is(Type::SignedSmall())); + CHECK(t->Is(Type::UnsignedSmall())); +} + + +TEST(Canonicalizations) { + JSConstantCacheTester T; + + CHECK_EQ(T.ZeroConstant(), T.ZeroConstant()); + CHECK_EQ(T.UndefinedConstant(), T.UndefinedConstant()); + CHECK_EQ(T.TheHoleConstant(), T.TheHoleConstant()); + CHECK_EQ(T.TrueConstant(), T.TrueConstant()); + CHECK_EQ(T.FalseConstant(), T.FalseConstant()); + CHECK_EQ(T.NullConstant(), T.NullConstant()); + CHECK_EQ(T.ZeroConstant(), T.ZeroConstant()); + CHECK_EQ(T.OneConstant(), T.OneConstant()); + CHECK_EQ(T.NaNConstant(), T.NaNConstant()); +} + + +TEST(NoAliasing) { + JSConstantCacheTester T; + + Node* nodes[] = {T.UndefinedConstant(), T.TheHoleConstant(), T.TrueConstant(), + T.FalseConstant(), T.NullConstant(), T.ZeroConstant(), + T.OneConstant(), T.NaNConstant(), T.Constant(21), + T.Constant(22.2)}; + + for (size_t i = 0; i < ARRAY_SIZE(nodes); i++) { + for (size_t j = 0; j < ARRAY_SIZE(nodes); j++) { + if (i != j) CHECK_NE(nodes[i], nodes[j]); + } + } +} + + +TEST(CanonicalizingNumbers) { + JSConstantCacheTester T; + + FOR_FLOAT64_INPUTS(i) { + Node* node = T.Constant(*i); + for (int j = 0; j < 5; j++) { + CHECK_EQ(node, T.Constant(*i)); + } + } +} + + +TEST(NumberTypes) { + JSConstantCacheTester T; + + FOR_FLOAT64_INPUTS(i) { + double value = *i; + Node* node = T.Constant(value); + CHECK(T.upper(node)->Equals(Type::Of(value, T.main_zone()))); + } +} + + +TEST(HeapNumbers) { + JSConstantCacheTester T; + + FOR_FLOAT64_INPUTS(i) { + double value = *i; + Handle<Object> num = T.factory()->NewNumber(value); + Handle<HeapNumber> heap = T.factory()->NewHeapNumber(value); + Node* node1 = T.Constant(value); + Node* node2 = T.Constant(num); + Node* node3 = T.Constant(heap); + CHECK_EQ(node1, node2); + CHECK_EQ(node1, node3); + } +} + + +TEST(OddballHandle) { + JSConstantCacheTester T; + + CHECK_EQ(T.UndefinedConstant(), T.Constant(T.factory()->undefined_value())); + CHECK_EQ(T.TheHoleConstant(), T.Constant(T.factory()->the_hole_value())); + CHECK_EQ(T.TrueConstant(), T.Constant(T.factory()->true_value())); + CHECK_EQ(T.FalseConstant(), T.Constant(T.factory()->false_value())); + CHECK_EQ(T.NullConstant(), T.Constant(T.factory()->null_value())); + CHECK_EQ(T.NaNConstant(), T.Constant(T.factory()->nan_value())); +} + + +TEST(OddballValues) { + JSConstantCacheTester T; + + CHECK_EQ(*T.factory()->undefined_value(), *T.handle(T.UndefinedConstant())); + CHECK_EQ(*T.factory()->the_hole_value(), *T.handle(T.TheHoleConstant())); + CHECK_EQ(*T.factory()->true_value(), *T.handle(T.TrueConstant())); + CHECK_EQ(*T.factory()->false_value(), *T.handle(T.FalseConstant())); + CHECK_EQ(*T.factory()->null_value(), *T.handle(T.NullConstant())); +} + + +TEST(OddballTypes) { + JSConstantCacheTester T; + + CHECK(T.upper(T.UndefinedConstant())->Is(Type::Undefined())); + // TODO(dcarney): figure this out. + // CHECK(T.upper(T.TheHoleConstant())->Is(Type::Internal())); + CHECK(T.upper(T.TrueConstant())->Is(Type::Boolean())); + CHECK(T.upper(T.FalseConstant())->Is(Type::Boolean())); + CHECK(T.upper(T.NullConstant())->Is(Type::Null())); + CHECK(T.upper(T.ZeroConstant())->Is(Type::Number())); + CHECK(T.upper(T.OneConstant())->Is(Type::Number())); + CHECK(T.upper(T.NaNConstant())->Is(Type::NaN())); +} + + +TEST(ExternalReferences) { + // TODO(titzer): test canonicalization of external references. +} diff --git a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc new file mode 100644 index 0000000000..740d9f3d49 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc @@ -0,0 +1,309 @@ +// 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/compiler/js-context-specialization.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/node-matchers.h" +#include "src/compiler/node-properties-inl.h" +#include "src/compiler/simplified-node-factory.h" +#include "src/compiler/source-position.h" +#include "src/compiler/typer.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/function-tester.h" +#include "test/cctest/compiler/graph-builder-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +class ContextSpecializationTester + : public HandleAndZoneScope, + public DirectGraphBuilder, + public SimplifiedNodeFactory<ContextSpecializationTester> { + public: + ContextSpecializationTester() + : DirectGraphBuilder(new (main_zone()) Graph(main_zone())), + common_(main_zone()), + javascript_(main_zone()), + simplified_(main_zone()), + typer_(main_zone()), + jsgraph_(graph(), common(), &typer_), + info_(main_isolate(), main_zone()) {} + + Factory* factory() { return main_isolate()->factory(); } + CommonOperatorBuilder* common() { return &common_; } + JSOperatorBuilder* javascript() { return &javascript_; } + SimplifiedOperatorBuilder* simplified() { return &simplified_; } + JSGraph* jsgraph() { return &jsgraph_; } + CompilationInfo* info() { return &info_; } + + private: + CommonOperatorBuilder common_; + JSOperatorBuilder javascript_; + SimplifiedOperatorBuilder simplified_; + Typer typer_; + JSGraph jsgraph_; + CompilationInfo info_; +}; + + +TEST(ReduceJSLoadContext) { + ContextSpecializationTester t; + + Node* start = t.NewNode(t.common()->Start(0)); + t.graph()->SetStart(start); + + // Make a context and initialize it a bit for this test. + Handle<Context> native = t.factory()->NewNativeContext(); + Handle<Context> subcontext1 = t.factory()->NewNativeContext(); + Handle<Context> subcontext2 = t.factory()->NewNativeContext(); + subcontext2->set_previous(*subcontext1); + subcontext1->set_previous(*native); + Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!"); + const int slot = Context::GLOBAL_OBJECT_INDEX; + native->set(slot, *expected); + + Node* const_context = t.jsgraph()->Constant(native); + Node* deep_const_context = t.jsgraph()->Constant(subcontext2); + Node* param_context = t.NewNode(t.common()->Parameter(0), start); + JSContextSpecializer spec(t.info(), t.jsgraph(), const_context); + + { + // Mutable slot, constant context, depth = 0 => do nothing. + Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false), + const_context, const_context, start); + Reduction r = spec.ReduceJSLoadContext(load); + CHECK(!r.Changed()); + } + + { + // Mutable slot, non-constant context, depth = 0 => do nothing. + Node* load = t.NewNode(t.javascript()->LoadContext(0, 0, false), + param_context, param_context, start); + Reduction r = spec.ReduceJSLoadContext(load); + CHECK(!r.Changed()); + } + + { + // Mutable slot, constant context, depth > 0 => fold-in parent context. + Node* load = t.NewNode( + t.javascript()->LoadContext(2, Context::GLOBAL_EVAL_FUN_INDEX, false), + deep_const_context, deep_const_context, start); + Reduction r = spec.ReduceJSLoadContext(load); + CHECK(r.Changed()); + Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); + CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); + ValueMatcher<Handle<Context> > match(new_context_input); + CHECK_EQ(*native, *match.Value()); + ContextAccess access = static_cast<Operator1<ContextAccess>*>( + r.replacement()->op())->parameter(); + CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index()); + CHECK_EQ(0, access.depth()); + CHECK_EQ(false, access.immutable()); + } + + { + // Immutable slot, constant context, depth = 0 => specialize. + Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true), + const_context, const_context, start); + Reduction r = spec.ReduceJSLoadContext(load); + CHECK(r.Changed()); + CHECK(r.replacement() != load); + + ValueMatcher<Handle<Object> > match(r.replacement()); + CHECK(match.HasValue()); + CHECK_EQ(*expected, *match.Value()); + } + + // TODO(titzer): test with other kinds of contexts, e.g. a function context. + // TODO(sigurds): test that loads below create context are not optimized +} + + +TEST(ReduceJSStoreContext) { + ContextSpecializationTester t; + + Node* start = t.NewNode(t.common()->Start(0)); + t.graph()->SetStart(start); + + // Make a context and initialize it a bit for this test. + Handle<Context> native = t.factory()->NewNativeContext(); + Handle<Context> subcontext1 = t.factory()->NewNativeContext(); + Handle<Context> subcontext2 = t.factory()->NewNativeContext(); + subcontext2->set_previous(*subcontext1); + subcontext1->set_previous(*native); + Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!"); + const int slot = Context::GLOBAL_OBJECT_INDEX; + native->set(slot, *expected); + + Node* const_context = t.jsgraph()->Constant(native); + Node* deep_const_context = t.jsgraph()->Constant(subcontext2); + Node* param_context = t.NewNode(t.common()->Parameter(0), start); + JSContextSpecializer spec(t.info(), t.jsgraph(), const_context); + + { + // Mutable slot, constant context, depth = 0 => do nothing. + Node* load = t.NewNode(t.javascript()->StoreContext(0, 0), const_context, + const_context, start); + Reduction r = spec.ReduceJSStoreContext(load); + CHECK(!r.Changed()); + } + + { + // Mutable slot, non-constant context, depth = 0 => do nothing. + Node* load = t.NewNode(t.javascript()->StoreContext(0, 0), param_context, + param_context, start); + Reduction r = spec.ReduceJSStoreContext(load); + CHECK(!r.Changed()); + } + + { + // Immutable slot, constant context, depth = 0 => do nothing. + Node* load = t.NewNode(t.javascript()->StoreContext(0, slot), const_context, + const_context, start); + Reduction r = spec.ReduceJSStoreContext(load); + CHECK(!r.Changed()); + } + + { + // Mutable slot, constant context, depth > 0 => fold-in parent context. + Node* load = t.NewNode( + t.javascript()->StoreContext(2, Context::GLOBAL_EVAL_FUN_INDEX), + deep_const_context, deep_const_context, start); + Reduction r = spec.ReduceJSStoreContext(load); + CHECK(r.Changed()); + Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0); + CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode()); + ValueMatcher<Handle<Context> > match(new_context_input); + CHECK_EQ(*native, *match.Value()); + ContextAccess access = static_cast<Operator1<ContextAccess>*>( + r.replacement()->op())->parameter(); + CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index()); + CHECK_EQ(0, access.depth()); + CHECK_EQ(false, access.immutable()); + } +} + + +// TODO(titzer): factor out common code with effects checking in typed lowering. +static void CheckEffectInput(Node* effect, Node* use) { + CHECK_EQ(effect, NodeProperties::GetEffectInput(use)); +} + + +TEST(SpecializeToContext) { + ContextSpecializationTester t; + + Node* start = t.NewNode(t.common()->Start(0)); + t.graph()->SetStart(start); + + // Make a context and initialize it a bit for this test. + Handle<Context> native = t.factory()->NewNativeContext(); + Handle<Object> expected = t.factory()->InternalizeUtf8String("gboy!"); + const int slot = Context::GLOBAL_OBJECT_INDEX; + native->set(slot, *expected); + t.info()->SetContext(native); + + Node* const_context = t.jsgraph()->Constant(native); + Node* param_context = t.NewNode(t.common()->Parameter(0), start); + JSContextSpecializer spec(t.info(), t.jsgraph(), const_context); + + { + // Check that SpecializeToContext() replaces values and forwards effects + // correctly, and folds values from constant and non-constant contexts + Node* effect_in = start; + Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true), + const_context, const_context, effect_in); + + + Node* value_use = t.ChangeTaggedToInt32(load); + Node* other_load = t.NewNode(t.javascript()->LoadContext(0, slot, true), + param_context, param_context, load); + Node* effect_use = other_load; + Node* other_use = t.ChangeTaggedToInt32(other_load); + + Node* add = t.NewNode(t.javascript()->Add(), value_use, other_use, + param_context, other_load, start); + + Node* ret = t.NewNode(t.common()->Return(), add, effect_use, start); + Node* end = t.NewNode(t.common()->End(), ret); + USE(end); + t.graph()->SetEnd(end); + + // Double check the above graph is what we expect, or the test is broken. + CheckEffectInput(effect_in, load); + CheckEffectInput(load, effect_use); + + // Perform the substitution on the entire graph. + spec.SpecializeToContext(); + + // Effects should have been forwarded (not replaced with a value). + CheckEffectInput(effect_in, effect_use); + + // Use of {other_load} should not have been replaced. + CHECK_EQ(other_load, other_use->InputAt(0)); + + Node* replacement = value_use->InputAt(0); + ValueMatcher<Handle<Object> > match(replacement); + CHECK(match.HasValue()); + CHECK_EQ(*expected, *match.Value()); + } + // TODO(titzer): clean up above test and test more complicated effects. +} + + +TEST(SpecializeJSFunction_ToConstant1) { + FunctionTester T( + "(function() { var x = 1; function inc(a)" + " { return a + x; } return inc; })()"); + + T.CheckCall(1.0, 0.0, 0.0); + T.CheckCall(2.0, 1.0, 0.0); + T.CheckCall(2.1, 1.1, 0.0); +} + + +TEST(SpecializeJSFunction_ToConstant2) { + FunctionTester T( + "(function() { var x = 1.5; var y = 2.25; var z = 3.75;" + " function f(a) { return a - x + y - z; } return f; })()"); + + T.CheckCall(-3.0, 0.0, 0.0); + T.CheckCall(-2.0, 1.0, 0.0); + T.CheckCall(-1.9, 1.1, 0.0); +} + + +TEST(SpecializeJSFunction_ToConstant3) { + FunctionTester T( + "(function() { var x = -11.5; function inc()" + " { return (function(a) { return a + x; }); }" + " return inc(); })()"); + + T.CheckCall(-11.5, 0.0, 0.0); + T.CheckCall(-10.5, 1.0, 0.0); + T.CheckCall(-10.4, 1.1, 0.0); +} + + +TEST(SpecializeJSFunction_ToConstant_uninit) { + { + FunctionTester T( + "(function() { if (false) { var x = 1; } function inc(a)" + " { return x; } return inc; })()"); // x is undefined! + + CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsUndefined()); + CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsUndefined()); + CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsUndefined()); + } + + { + FunctionTester T( + "(function() { if (false) { var x = 1; } function inc(a)" + " { return a + x; } return inc; })()"); // x is undefined! + + CHECK(T.Call(T.Val(0.0), T.Val(0.0)).ToHandleChecked()->IsNaN()); + CHECK(T.Call(T.Val(2.0), T.Val(0.0)).ToHandleChecked()->IsNaN()); + CHECK(T.Call(T.Val(-2.1), T.Val(0.0)).ToHandleChecked()->IsNaN()); + } +} diff --git a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc new file mode 100644 index 0000000000..b6aa6d9582 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc @@ -0,0 +1,1342 @@ +// 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/graph-inl.h" +#include "src/compiler/js-typed-lowering.h" +#include "src/compiler/node-properties-inl.h" +#include "src/compiler/opcodes.h" +#include "src/compiler/typer.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +class JSTypedLoweringTester : public HandleAndZoneScope { + public: + explicit JSTypedLoweringTester(int num_parameters = 0) + : isolate(main_isolate()), + binop(NULL), + unop(NULL), + javascript(main_zone()), + machine(main_zone()), + simplified(main_zone()), + common(main_zone()), + graph(main_zone()), + typer(main_zone()), + source_positions(&graph), + context_node(NULL) { + typer.DecorateGraph(&graph); + Node* s = graph.NewNode(common.Start(num_parameters)); + graph.SetStart(s); + } + + Isolate* isolate; + Operator* binop; + Operator* unop; + JSOperatorBuilder javascript; + MachineOperatorBuilder machine; + SimplifiedOperatorBuilder simplified; + CommonOperatorBuilder common; + Graph graph; + Typer typer; + SourcePositionTable source_positions; + Node* context_node; + + Node* Parameter(Type* t, int32_t index = 0) { + Node* n = graph.NewNode(common.Parameter(index), graph.start()); + NodeProperties::SetBounds(n, Bounds(Type::None(), t)); + return n; + } + + Node* reduce(Node* node) { + JSGraph jsgraph(&graph, &common, &typer); + JSTypedLowering reducer(&jsgraph, &source_positions); + Reduction reduction = reducer.Reduce(node); + if (reduction.Changed()) return reduction.replacement(); + return node; + } + + Node* start() { return graph.start(); } + + Node* context() { + if (context_node == NULL) { + context_node = graph.NewNode(common.Parameter(-1), graph.start()); + } + return context_node; + } + + Node* control() { return start(); } + + void CheckPureBinop(IrOpcode::Value expected, Node* node) { + CHECK_EQ(expected, node->opcode()); + CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. + } + + void CheckPureBinop(Operator* expected, Node* node) { + CHECK_EQ(expected->opcode(), node->op()->opcode()); + CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. + } + + Node* ReduceUnop(Operator* op, Type* input_type) { + return reduce(Unop(op, Parameter(input_type))); + } + + Node* ReduceBinop(Operator* op, Type* left_type, Type* right_type) { + return reduce(Binop(op, Parameter(left_type, 0), Parameter(right_type, 1))); + } + + Node* Binop(Operator* op, Node* left, Node* right) { + // JS binops also require context, effect, and control + return graph.NewNode(op, left, right, context(), start(), control()); + } + + Node* Unop(Operator* op, Node* input) { + // JS unops also require context, effect, and control + return graph.NewNode(op, input, context(), start(), control()); + } + + Node* UseForEffect(Node* node) { + // TODO(titzer): use EffectPhi after fixing EffectCount + return graph.NewNode(javascript.ToNumber(), node, context(), node, + control()); + } + + void CheckEffectInput(Node* effect, Node* use) { + CHECK_EQ(effect, NodeProperties::GetEffectInput(use)); + } + + void CheckInt32Constant(int32_t expected, Node* result) { + CHECK_EQ(IrOpcode::kInt32Constant, result->opcode()); + CHECK_EQ(expected, ValueOf<int32_t>(result->op())); + } + + void CheckNumberConstant(double expected, Node* result) { + CHECK_EQ(IrOpcode::kNumberConstant, result->opcode()); + CHECK_EQ(expected, ValueOf<double>(result->op())); + } + + void CheckNaN(Node* result) { + CHECK_EQ(IrOpcode::kNumberConstant, result->opcode()); + double value = ValueOf<double>(result->op()); + CHECK(std::isnan(value)); + } + + void CheckTrue(Node* result) { + CheckHandle(isolate->factory()->true_value(), result); + } + + void CheckFalse(Node* result) { + CheckHandle(isolate->factory()->false_value(), result); + } + + void CheckHandle(Handle<Object> expected, Node* result) { + CHECK_EQ(IrOpcode::kHeapConstant, result->opcode()); + Handle<Object> value = ValueOf<Handle<Object> >(result->op()); + CHECK_EQ(*expected, *value); + } +}; + +static Type* kStringTypes[] = {Type::InternalizedString(), Type::OtherString(), + Type::String()}; + + +static Type* kInt32Types[] = { + Type::UnsignedSmall(), Type::OtherSignedSmall(), Type::OtherUnsigned31(), + Type::OtherUnsigned32(), Type::OtherSigned32(), Type::SignedSmall(), + Type::Signed32(), Type::Unsigned32(), Type::Integral32()}; + + +static Type* kNumberTypes[] = { + Type::UnsignedSmall(), Type::OtherSignedSmall(), Type::OtherUnsigned31(), + Type::OtherUnsigned32(), Type::OtherSigned32(), Type::SignedSmall(), + Type::Signed32(), Type::Unsigned32(), Type::Integral32(), + Type::MinusZero(), Type::NaN(), Type::OtherNumber(), + Type::Number()}; + + +static Type* kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), + Type::Number(), Type::String(), Type::Object()}; + + +static Type* I32Type(bool is_signed) { + return is_signed ? Type::Signed32() : Type::Unsigned32(); +} + + +static IrOpcode::Value NumberToI32(bool is_signed) { + return is_signed ? IrOpcode::kNumberToInt32 : IrOpcode::kNumberToUint32; +} + + +TEST(StringBinops) { + JSTypedLoweringTester R; + + for (size_t i = 0; i < ARRAY_SIZE(kStringTypes); ++i) { + Node* p0 = R.Parameter(kStringTypes[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(kStringTypes); ++j) { + Node* p1 = R.Parameter(kStringTypes[j], 1); + + Node* add = R.Binop(R.javascript.Add(), p0, p1); + Node* r = R.reduce(add); + + R.CheckPureBinop(IrOpcode::kStringAdd, r); + CHECK_EQ(p0, r->InputAt(0)); + CHECK_EQ(p1, r->InputAt(1)); + } + } +} + + +TEST(AddNumber1) { + JSTypedLoweringTester R; + for (size_t i = 0; i < ARRAY_SIZE(kNumberTypes); ++i) { + Node* p0 = R.Parameter(kNumberTypes[i], 0); + Node* p1 = R.Parameter(kNumberTypes[i], 1); + Node* add = R.Binop(R.javascript.Add(), p0, p1); + Node* r = R.reduce(add); + + R.CheckPureBinop(IrOpcode::kNumberAdd, r); + CHECK_EQ(p0, r->InputAt(0)); + CHECK_EQ(p1, r->InputAt(1)); + } +} + + +TEST(NumberBinops) { + JSTypedLoweringTester R; + Operator* ops[] = { + R.javascript.Add(), R.simplified.NumberAdd(), + R.javascript.Subtract(), R.simplified.NumberSubtract(), + R.javascript.Multiply(), R.simplified.NumberMultiply(), + R.javascript.Divide(), R.simplified.NumberDivide(), + R.javascript.Modulus(), R.simplified.NumberModulus(), + }; + + for (size_t i = 0; i < ARRAY_SIZE(kNumberTypes); ++i) { + Node* p0 = R.Parameter(kNumberTypes[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(kNumberTypes); ++j) { + Node* p1 = R.Parameter(kNumberTypes[j], 1); + + for (size_t k = 0; k < ARRAY_SIZE(ops); k += 2) { + Node* add = R.Binop(ops[k], p0, p1); + Node* r = R.reduce(add); + + R.CheckPureBinop(ops[k + 1], r); + CHECK_EQ(p0, r->InputAt(0)); + CHECK_EQ(p1, r->InputAt(1)); + } + } + } +} + + +static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) { + Type* old_type = NodeProperties::GetBounds(old_input).upper; + Type* expected_type = I32Type(is_signed); + if (old_type->Is(expected_type)) { + CHECK_EQ(old_input, new_input); + } else if (new_input->opcode() == IrOpcode::kNumberConstant) { + CHECK(NodeProperties::GetBounds(new_input).upper->Is(expected_type)); + double v = ValueOf<double>(new_input->op()); + double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v)); + CHECK_EQ(e, v); + } else { + CHECK_EQ(NumberToI32(is_signed), new_input->opcode()); + } +} + + +// A helper class for testing lowering of bitwise shift operators. +class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { + public: + static const int kNumberOps = 6; + Operator* ops[kNumberOps]; + bool signedness[kNumberOps]; + + JSBitwiseShiftTypedLoweringTester() { + int i = 0; + set(i++, javascript.ShiftLeft(), true); + set(i++, machine.Word32Shl(), false); + set(i++, javascript.ShiftRight(), true); + set(i++, machine.Word32Sar(), false); + set(i++, javascript.ShiftRightLogical(), false); + set(i++, machine.Word32Shr(), false); + } + + private: + void set(int idx, Operator* op, bool s) { + ops[idx] = op; + signedness[idx] = s; + } +}; + + +TEST(Int32BitwiseShifts) { + JSBitwiseShiftTypedLoweringTester R; + + Type* types[] = { + Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(), + Type::Unsigned32(), Type::Signed32(), Type::MinusZero(), + Type::NaN(), Type::OtherNumber(), Type::Undefined(), + Type::Null(), Type::Boolean(), Type::Number(), + Type::String(), Type::Object()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { + Node* p0 = R.Parameter(types[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(types); ++j) { + Node* p1 = R.Parameter(types[j], 1); + + for (int k = 0; k < R.kNumberOps; k += 2) { + Node* add = R.Binop(R.ops[k], p0, p1); + Node* r = R.reduce(add); + + R.CheckPureBinop(R.ops[k + 1], r); + Node* r0 = r->InputAt(0); + Node* r1 = r->InputAt(1); + + CheckToI32(p0, r0, R.signedness[k]); + + R.CheckPureBinop(IrOpcode::kWord32And, r1); + CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]); + R.CheckInt32Constant(0x1F, r1->InputAt(1)); + } + } + } +} + + +// A helper class for testing lowering of bitwise operators. +class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { + public: + static const int kNumberOps = 6; + Operator* ops[kNumberOps]; + bool signedness[kNumberOps]; + + JSBitwiseTypedLoweringTester() { + int i = 0; + set(i++, javascript.BitwiseOr(), true); + set(i++, machine.Word32Or(), true); + set(i++, javascript.BitwiseXor(), true); + set(i++, machine.Word32Xor(), true); + set(i++, javascript.BitwiseAnd(), true); + set(i++, machine.Word32And(), true); + } + + private: + void set(int idx, Operator* op, bool s) { + ops[idx] = op; + signedness[idx] = s; + } +}; + + +TEST(Int32BitwiseBinops) { + JSBitwiseTypedLoweringTester R; + + Type* types[] = { + Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(), + Type::Unsigned32(), Type::Signed32(), Type::MinusZero(), + Type::NaN(), Type::OtherNumber(), Type::Undefined(), + Type::Null(), Type::Boolean(), Type::Number(), + Type::String(), Type::Object()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); ++i) { + Node* p0 = R.Parameter(types[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(types); ++j) { + Node* p1 = R.Parameter(types[j], 1); + + for (int k = 0; k < R.kNumberOps; k += 2) { + Node* add = R.Binop(R.ops[k], p0, p1); + Node* r = R.reduce(add); + + R.CheckPureBinop(R.ops[k + 1], r); + + CheckToI32(p0, r->InputAt(0), R.signedness[k]); + CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]); + } + } + } +} + + +TEST(JSToNumber1) { + JSTypedLoweringTester R; + Operator* ton = R.javascript.ToNumber(); + + for (size_t i = 0; i < ARRAY_SIZE(kNumberTypes); i++) { // ToNumber(number) + Node* r = R.ReduceUnop(ton, kNumberTypes[i]); + CHECK_EQ(IrOpcode::kParameter, r->opcode()); + } + + { // ToNumber(undefined) + Node* r = R.ReduceUnop(ton, Type::Undefined()); + R.CheckNaN(r); + } + + { // ToNumber(null) + Node* r = R.ReduceUnop(ton, Type::Null()); + R.CheckNumberConstant(0.0, r); + } +} + + +TEST(JSToNumber_replacement) { + JSTypedLoweringTester R; + + Type* types[] = {Type::Null(), Type::Undefined(), Type::Number()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + Node* n = R.Parameter(types[i]); + Node* c = R.graph.NewNode(R.javascript.ToNumber(), n, R.context(), + R.start(), R.start()); + Node* effect_use = R.UseForEffect(c); + Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c); + + R.CheckEffectInput(c, effect_use); + Node* r = R.reduce(c); + + if (types[i]->Is(Type::Number())) { + CHECK_EQ(n, r); + } else { + CHECK_EQ(IrOpcode::kNumberConstant, r->opcode()); + } + + CHECK_EQ(n, add->InputAt(0)); + CHECK_EQ(r, add->InputAt(1)); + R.CheckEffectInput(R.start(), effect_use); + } +} + + +TEST(JSToNumberOfConstant) { + JSTypedLoweringTester R; + + Operator* ops[] = {R.common.NumberConstant(0), R.common.NumberConstant(-1), + R.common.NumberConstant(0.1), R.common.Int32Constant(1177), + R.common.Float64Constant(0.99)}; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + Node* n = R.graph.NewNode(ops[i]); + Node* convert = R.Unop(R.javascript.ToNumber(), n); + Node* r = R.reduce(convert); + // Note that either outcome below is correct. It only depends on whether + // the types of constants are eagerly computed or only computed by the + // typing pass. + if (NodeProperties::GetBounds(n).upper->Is(Type::Number())) { + // If number constants are eagerly typed, then reduction should + // remove the ToNumber. + CHECK_EQ(n, r); + } else { + // Otherwise, type-based lowering should only look at the type, and + // *not* try to constant fold. + CHECK_EQ(convert, r); + } + } +} + + +TEST(JSToNumberOfNumberOrOtherPrimitive) { + JSTypedLoweringTester R; + Type* others[] = {Type::Undefined(), Type::Null(), Type::Boolean(), + Type::String()}; + + for (size_t i = 0; i < ARRAY_SIZE(others); i++) { + Type* t = Type::Union(Type::Number(), others[i], R.main_zone()); + Node* r = R.ReduceUnop(R.javascript.ToNumber(), t); + CHECK_EQ(IrOpcode::kJSToNumber, r->opcode()); + } +} + + +TEST(JSToBoolean) { + JSTypedLoweringTester R; + Operator* op = R.javascript.ToBoolean(); + + { // ToBoolean(undefined) + Node* r = R.ReduceUnop(op, Type::Undefined()); + R.CheckFalse(r); + } + + { // ToBoolean(null) + Node* r = R.ReduceUnop(op, Type::Null()); + R.CheckFalse(r); + } + + { // ToBoolean(boolean) + Node* r = R.ReduceUnop(op, Type::Boolean()); + CHECK_EQ(IrOpcode::kParameter, r->opcode()); + } + + { // ToBoolean(number) + Node* r = R.ReduceUnop(op, Type::Number()); + CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); + Node* i = r->InputAt(0); + CHECK_EQ(IrOpcode::kNumberEqual, i->opcode()); + // ToBoolean(number) => BooleanNot(NumberEqual(x, #0)) + } + + { // ToBoolean(string) + Node* r = R.ReduceUnop(op, Type::String()); + // TODO(titzer): test will break with better js-typed-lowering + CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode()); + } + + { // ToBoolean(object) + Node* r = R.ReduceUnop(op, Type::DetectableObject()); + R.CheckTrue(r); + } + + { // ToBoolean(undetectable) + Node* r = R.ReduceUnop(op, Type::Undetectable()); + R.CheckFalse(r); + } + + { // ToBoolean(object) + Node* r = R.ReduceUnop(op, Type::Object()); + CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode()); + } +} + + +TEST(JSToBoolean_replacement) { + JSTypedLoweringTester R; + + Type* types[] = {Type::Null(), Type::Undefined(), Type::Boolean(), + Type::DetectableObject(), Type::Undetectable()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + Node* n = R.Parameter(types[i]); + Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context(), + R.start(), R.start()); + Node* effect_use = R.UseForEffect(c); + Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c); + + R.CheckEffectInput(c, effect_use); + Node* r = R.reduce(c); + + if (types[i]->Is(Type::Boolean())) { + CHECK_EQ(n, r); + } else { + CHECK_EQ(IrOpcode::kHeapConstant, r->opcode()); + } + + CHECK_EQ(n, add->InputAt(0)); + CHECK_EQ(r, add->InputAt(1)); + R.CheckEffectInput(R.start(), effect_use); + } +} + + +TEST(JSToString1) { + JSTypedLoweringTester R; + + for (size_t i = 0; i < ARRAY_SIZE(kStringTypes); i++) { + Node* r = R.ReduceUnop(R.javascript.ToString(), kStringTypes[i]); + CHECK_EQ(IrOpcode::kParameter, r->opcode()); + } + + Operator* op = R.javascript.ToString(); + + { // ToString(undefined) => "undefined" + Node* r = R.ReduceUnop(op, Type::Undefined()); + R.CheckHandle(R.isolate->factory()->undefined_string(), r); + } + + { // ToString(null) => "null" + Node* r = R.ReduceUnop(op, Type::Null()); + R.CheckHandle(R.isolate->factory()->null_string(), r); + } + + { // ToString(boolean) + Node* r = R.ReduceUnop(op, Type::Boolean()); + // TODO(titzer): could be a branch + CHECK_EQ(IrOpcode::kJSToString, r->opcode()); + } + + { // ToString(number) + Node* r = R.ReduceUnop(op, Type::Number()); + // TODO(titzer): could remove effects + CHECK_EQ(IrOpcode::kJSToString, r->opcode()); + } + + { // ToString(string) + Node* r = R.ReduceUnop(op, Type::String()); + CHECK_EQ(IrOpcode::kParameter, r->opcode()); // No-op + } + + { // ToString(object) + Node* r = R.ReduceUnop(op, Type::Object()); + CHECK_EQ(IrOpcode::kJSToString, r->opcode()); // No reduction. + } +} + + +TEST(JSToString_replacement) { + JSTypedLoweringTester R; + + Type* types[] = {Type::Null(), Type::Undefined(), Type::String()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + Node* n = R.Parameter(types[i]); + Node* c = R.graph.NewNode(R.javascript.ToString(), n, R.context(), + R.start(), R.start()); + Node* effect_use = R.UseForEffect(c); + Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c); + + R.CheckEffectInput(c, effect_use); + Node* r = R.reduce(c); + + if (types[i]->Is(Type::String())) { + CHECK_EQ(n, r); + } else { + CHECK_EQ(IrOpcode::kHeapConstant, r->opcode()); + } + + CHECK_EQ(n, add->InputAt(0)); + CHECK_EQ(r, add->InputAt(1)); + R.CheckEffectInput(R.start(), effect_use); + } +} + + +TEST(StringComparison) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.LessThan(), R.simplified.StringLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.StringLessThanOrEqual(), + R.javascript.GreaterThan(), R.simplified.StringLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.StringLessThanOrEqual()}; + + for (size_t i = 0; i < ARRAY_SIZE(kStringTypes); i++) { + Node* p0 = R.Parameter(kStringTypes[i], 0); + for (size_t j = 0; j < ARRAY_SIZE(kStringTypes); j++) { + Node* p1 = R.Parameter(kStringTypes[j], 1); + + for (size_t k = 0; k < ARRAY_SIZE(ops); k += 2) { + Node* cmp = R.Binop(ops[k], p0, p1); + Node* r = R.reduce(cmp); + + R.CheckPureBinop(ops[k + 1], r); + if (k >= 4) { + // GreaterThan and GreaterThanOrEqual commute the inputs + // and use the LessThan and LessThanOrEqual operators. + CHECK_EQ(p1, r->InputAt(0)); + CHECK_EQ(p0, r->InputAt(1)); + } else { + CHECK_EQ(p0, r->InputAt(0)); + CHECK_EQ(p1, r->InputAt(1)); + } + } + } + } +} + + +static void CheckIsConvertedToNumber(Node* val, Node* converted) { + if (NodeProperties::GetBounds(val).upper->Is(Type::Number())) { + CHECK_EQ(val, converted); + } else { + if (converted->opcode() == IrOpcode::kNumberConstant) return; + CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode()); + CHECK_EQ(val, converted->InputAt(0)); + } +} + + +TEST(NumberComparison) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.LessThan(), R.simplified.NumberLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + R.javascript.GreaterThan(), R.simplified.NumberLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()}; + + for (size_t i = 0; i < ARRAY_SIZE(kJSTypes); i++) { + Type* t0 = kJSTypes[i]; + if (t0->Is(Type::String())) continue; // skip Type::String + Node* p0 = R.Parameter(t0, 0); + + for (size_t j = 0; j < ARRAY_SIZE(kJSTypes); j++) { + Type* t1 = kJSTypes[j]; + if (t1->Is(Type::String())) continue; // skip Type::String + Node* p1 = R.Parameter(t1, 1); + + for (size_t k = 0; k < ARRAY_SIZE(ops); k += 2) { + Node* cmp = R.Binop(ops[k], p0, p1); + Node* r = R.reduce(cmp); + + R.CheckPureBinop(ops[k + 1], r); + if (k >= 4) { + // GreaterThan and GreaterThanOrEqual commute the inputs + // and use the LessThan and LessThanOrEqual operators. + CheckIsConvertedToNumber(p1, r->InputAt(0)); + CheckIsConvertedToNumber(p0, r->InputAt(1)); + } else { + CheckIsConvertedToNumber(p0, r->InputAt(0)); + CheckIsConvertedToNumber(p1, r->InputAt(1)); + } + } + } + } +} + + +TEST(MixedComparison1) { + JSTypedLoweringTester R; + + Type* types[] = {Type::Number(), Type::String(), + Type::Union(Type::Number(), Type::String(), R.main_zone())}; + + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + Node* p0 = R.Parameter(types[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(types); j++) { + Node* p1 = R.Parameter(types[j], 1); + { + Node* cmp = R.Binop(R.javascript.LessThan(), 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); + } + } else { + CHECK_EQ(cmp, r); // No reduction of mixed types. + } + } + } + } +} + + +TEST(ObjectComparison) { + JSTypedLoweringTester R; + + Node* p0 = R.Parameter(Type::Object(), 0); + Node* p1 = R.Parameter(Type::Object(), 1); + + Node* cmp = R.Binop(R.javascript.LessThan(), p0, p1); + Node* effect_use = R.UseForEffect(cmp); + + R.CheckEffectInput(R.start(), cmp); + R.CheckEffectInput(cmp, effect_use); + + Node* r = R.reduce(cmp); + + R.CheckPureBinop(R.simplified.NumberLessThan(), r); + + Node* i0 = r->InputAt(0); + Node* i1 = r->InputAt(1); + + CHECK_NE(p0, i0); + CHECK_NE(p1, i1); + CHECK_EQ(IrOpcode::kJSToNumber, i0->opcode()); + CHECK_EQ(IrOpcode::kJSToNumber, i1->opcode()); + + // Check effect chain is correct. + R.CheckEffectInput(R.start(), i0); + R.CheckEffectInput(i0, i1); + R.CheckEffectInput(i1, effect_use); +} + + +TEST(UnaryNot) { + JSTypedLoweringTester R; + Operator* opnot = R.javascript.UnaryNot(); + + for (size_t i = 0; i < ARRAY_SIZE(kJSTypes); i++) { + Node* r = R.ReduceUnop(opnot, kJSTypes[i]); + // TODO(titzer): test will break if/when js-typed-lowering constant folds. + CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); + } +} + + +TEST(RemoveToNumberEffects) { + JSTypedLoweringTester R; + + Node* effect_use = NULL; + for (int i = 0; i < 10; i++) { + Node* p0 = R.Parameter(Type::Number()); + Node* ton = R.Unop(R.javascript.ToNumber(), p0); + effect_use = NULL; + + switch (i) { + case 0: + effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(), + ton, R.start()); + break; + case 1: + effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(), + ton, R.start()); + break; + case 2: + effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); + case 3: + effect_use = R.graph.NewNode(R.javascript.Add(), ton, ton, R.context(), + ton, R.start()); + break; + case 4: + effect_use = R.graph.NewNode(R.javascript.Add(), p0, p0, R.context(), + ton, R.start()); + break; + case 5: + effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); + break; + case 6: + effect_use = R.graph.NewNode(R.common.Return(), ton, ton, R.start()); + } + + R.CheckEffectInput(R.start(), ton); + if (effect_use != NULL) R.CheckEffectInput(ton, effect_use); + + Node* r = R.reduce(ton); + CHECK_EQ(p0, r); + CHECK_NE(R.start(), r); + + if (effect_use != NULL) { + R.CheckEffectInput(R.start(), effect_use); + // Check that value uses of ToNumber() do not go to start(). + for (int i = 0; i < effect_use->op()->InputCount(); i++) { + CHECK_NE(R.start(), effect_use->InputAt(i)); + } + } + } + + CHECK_EQ(NULL, effect_use); // should have done all cases above. +} + + +// Helper class for testing the reduction of a single binop. +class BinopEffectsTester { + public: + explicit BinopEffectsTester(Operator* op, Type* t0, Type* t1) + : R(), + p0(R.Parameter(t0, 0)), + p1(R.Parameter(t1, 1)), + binop(R.Binop(op, p0, p1)), + effect_use(R.graph.NewNode(R.common.EffectPhi(1), binop, R.start())) { + // Effects should be ordered start -> binop -> effect_use + R.CheckEffectInput(R.start(), binop); + R.CheckEffectInput(binop, effect_use); + result = R.reduce(binop); + } + + JSTypedLoweringTester R; + Node* p0; + Node* p1; + Node* binop; + Node* effect_use; + Node* result; + + void CheckEffectsRemoved() { R.CheckEffectInput(R.start(), effect_use); } + + void CheckEffectOrdering(Node* n0) { + R.CheckEffectInput(R.start(), n0); + R.CheckEffectInput(n0, effect_use); + } + + void CheckEffectOrdering(Node* n0, Node* n1) { + R.CheckEffectInput(R.start(), n0); + R.CheckEffectInput(n0, n1); + R.CheckEffectInput(n1, effect_use); + } + + Node* CheckConvertedInput(IrOpcode::Value opcode, int which, bool effects) { + return CheckConverted(opcode, result->InputAt(which), effects); + } + + Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) { + CHECK_EQ(opcode, node->opcode()); + if (effects) { + CHECK_LT(0, OperatorProperties::GetEffectInputCount(node->op())); + } else { + CHECK_EQ(0, OperatorProperties::GetEffectInputCount(node->op())); + } + return node; + } + + Node* CheckNoOp(int which) { + CHECK_EQ(which == 0 ? p0 : p1, result->InputAt(which)); + return result->InputAt(which); + } +}; + + +// Helper function for strict and non-strict equality reductions. +void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l, + Node* r, IrOpcode::Value expected) { + for (int j = 0; j < 2; j++) { + Node* p0 = j == 0 ? l : r; + Node* p1 = j == 1 ? l : r; + + { + Node* eq = strict ? R->graph.NewNode(R->javascript.StrictEqual(), p0, p1) + : R->Binop(R->javascript.Equal(), p0, p1); + Node* r = R->reduce(eq); + R->CheckPureBinop(expected, r); + } + + { + Node* ne = strict + ? R->graph.NewNode(R->javascript.StrictNotEqual(), p0, p1) + : R->Binop(R->javascript.NotEqual(), p0, p1); + Node* n = R->reduce(ne); + CHECK_EQ(IrOpcode::kBooleanNot, n->opcode()); + Node* r = n->InputAt(0); + R->CheckPureBinop(expected, r); + } + } +} + + +TEST(EqualityForNumbers) { + JSTypedLoweringTester R; + + Type* simple_number_types[] = {Type::UnsignedSmall(), Type::SignedSmall(), + Type::Signed32(), Type::Unsigned32(), + Type::Number()}; + + + for (size_t i = 0; i < ARRAY_SIZE(simple_number_types); ++i) { + Node* p0 = R.Parameter(simple_number_types[i], 0); + + for (size_t j = 0; j < ARRAY_SIZE(simple_number_types); ++j) { + Node* p1 = R.Parameter(simple_number_types[j], 1); + + CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kNumberEqual); + CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kNumberEqual); + } + } +} + + +TEST(StrictEqualityForRefEqualTypes) { + JSTypedLoweringTester R; + + Type* types[] = {Type::Undefined(), Type::Null(), Type::Boolean(), + Type::Object(), Type::Receiver()}; + + Node* p0 = R.Parameter(Type::Any()); + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + Node* p1 = R.Parameter(types[i]); + CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual); + } + // TODO(titzer): Equal(RefEqualTypes) +} + + +TEST(StringEquality) { + JSTypedLoweringTester R; + Node* p0 = R.Parameter(Type::String()); + Node* p1 = R.Parameter(Type::String()); + + CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kStringEqual); + CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual); +} + + +TEST(RemovePureNumberBinopEffects) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.Equal(), R.simplified.NumberEqual(), + R.javascript.Add(), R.simplified.NumberAdd(), + R.javascript.Subtract(), R.simplified.NumberSubtract(), + R.javascript.Multiply(), R.simplified.NumberMultiply(), + R.javascript.Divide(), R.simplified.NumberDivide(), + R.javascript.Modulus(), R.simplified.NumberModulus(), + R.javascript.LessThan(), R.simplified.NumberLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + }; + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Number(), Type::Number()); + CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + B.CheckNoOp(0); + B.CheckNoOp(1); + + B.CheckEffectsRemoved(); + } +} + + +TEST(OrderNumberBinopEffects1) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.Subtract(), R.simplified.NumberSubtract(), + R.javascript.Multiply(), R.simplified.NumberMultiply(), + R.javascript.Divide(), R.simplified.NumberDivide(), + R.javascript.Modulus(), R.simplified.NumberModulus(), + }; + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Object(), Type::String()); + CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); + + Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); + Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); + + CHECK_EQ(B.p0, i0->InputAt(0)); + CHECK_EQ(B.p1, i1->InputAt(0)); + + // Effects should be ordered start -> i0 -> i1 -> effect_use + B.CheckEffectOrdering(i0, i1); + } +} + + +TEST(OrderNumberBinopEffects2) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.Add(), R.simplified.NumberAdd(), + R.javascript.Subtract(), R.simplified.NumberSubtract(), + R.javascript.Multiply(), R.simplified.NumberMultiply(), + R.javascript.Divide(), R.simplified.NumberDivide(), + R.javascript.Modulus(), R.simplified.NumberModulus(), + }; + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Number(), Type::Object()); + + Node* i0 = B.CheckNoOp(0); + Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); + + CHECK_EQ(B.p0, i0); + CHECK_EQ(B.p1, i1->InputAt(0)); + + // Effects should be ordered start -> i1 -> effect_use + B.CheckEffectOrdering(i1); + } + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Object(), Type::Number()); + + Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); + Node* i1 = B.CheckNoOp(1); + + CHECK_EQ(B.p0, i0->InputAt(0)); + CHECK_EQ(B.p1, i1); + + // Effects should be ordered start -> i0 -> effect_use + B.CheckEffectOrdering(i0); + } +} + + +TEST(OrderCompareEffects) { + JSTypedLoweringTester R; + + Operator* ops[] = { + R.javascript.GreaterThan(), R.simplified.NumberLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + }; + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Object(), Type::String()); + CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); + + Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); + Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); + + // Inputs should be commuted. + CHECK_EQ(B.p1, i0->InputAt(0)); + CHECK_EQ(B.p0, i1->InputAt(0)); + + // But effects should be ordered start -> i1 -> i0 -> effect_use + B.CheckEffectOrdering(i1, i0); + } + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Number(), Type::Object()); + + Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); + Node* i1 = B.result->InputAt(1); + + CHECK_EQ(B.p1, i0->InputAt(0)); // Should be commuted. + CHECK_EQ(B.p0, i1); + + // Effects should be ordered start -> i1 -> effect_use + B.CheckEffectOrdering(i0); + } + + for (size_t j = 0; j < ARRAY_SIZE(ops); j += 2) { + BinopEffectsTester B(ops[j], Type::Object(), Type::Number()); + + Node* i0 = B.result->InputAt(0); + Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); + + CHECK_EQ(B.p1, i0); // Should be commuted. + CHECK_EQ(B.p0, i1->InputAt(0)); + + // Effects should be ordered start -> i0 -> effect_use + B.CheckEffectOrdering(i1); + } +} + + +TEST(Int32BinopEffects) { + JSBitwiseTypedLoweringTester R; + + for (int j = 0; j < R.kNumberOps; j += 2) { + bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; + BinopEffectsTester B(R.ops[j], I32Type(signed_left), I32Type(signed_right)); + CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + B.CheckNoOp(0); + B.CheckNoOp(1); + + B.CheckEffectsRemoved(); + } + + for (int j = 0; j < R.kNumberOps; j += 2) { + bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; + BinopEffectsTester B(R.ops[j], Type::Number(), Type::Number()); + CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + B.CheckConvertedInput(NumberToI32(signed_left), 0, false); + B.CheckConvertedInput(NumberToI32(signed_right), 1, false); + + B.CheckEffectsRemoved(); + } + + for (int j = 0; j < R.kNumberOps; j += 2) { + bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; + BinopEffectsTester B(R.ops[j], Type::Number(), Type::Object()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false); + Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false); + + CHECK_EQ(B.p0, i0->InputAt(0)); + Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true); + + CHECK_EQ(B.p1, ii1->InputAt(0)); + + B.CheckEffectOrdering(ii1); + } + + for (int j = 0; j < R.kNumberOps; j += 2) { + bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; + BinopEffectsTester B(R.ops[j], Type::Object(), Type::Number()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false); + Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false); + + Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true); + CHECK_EQ(B.p1, i1->InputAt(0)); + + CHECK_EQ(B.p0, ii0->InputAt(0)); + + B.CheckEffectOrdering(ii0); + } + + for (int j = 0; j < R.kNumberOps; j += 2) { + bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; + BinopEffectsTester B(R.ops[j], Type::Object(), Type::Object()); + + B.R.CheckPureBinop(B.result->opcode(), B.result); + + Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false); + Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false); + + Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true); + Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true); + + CHECK_EQ(B.p0, ii0->InputAt(0)); + CHECK_EQ(B.p1, ii1->InputAt(0)); + + B.CheckEffectOrdering(ii0, ii1); + } +} + + +TEST(UnaryNotEffects) { + JSTypedLoweringTester R; + Operator* opnot = R.javascript.UnaryNot(); + + for (size_t i = 0; i < ARRAY_SIZE(kJSTypes); i++) { + Node* p0 = R.Parameter(kJSTypes[i], 0); + Node* orig = R.Unop(opnot, p0); + Node* effect_use = R.UseForEffect(orig); + Node* value_use = R.graph.NewNode(R.common.Return(), orig); + Node* r = R.reduce(orig); + // TODO(titzer): test will break if/when js-typed-lowering constant folds. + CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); + + CHECK_EQ(r, value_use->InputAt(0)); + + if (r->InputAt(0) == orig && orig->opcode() == IrOpcode::kJSToBoolean) { + // The original node was turned into a ToBoolean, which has an effect. + R.CheckEffectInput(R.start(), orig); + R.CheckEffectInput(orig, effect_use); + } else { + // effect should have been removed from this node. + R.CheckEffectInput(R.start(), effect_use); + } + } +} + + +TEST(Int32AddNarrowing) { + { + JSBitwiseTypedLoweringTester R; + + for (int o = 0; o < R.kNumberOps; o += 2) { + for (size_t i = 0; i < ARRAY_SIZE(kInt32Types); i++) { + Node* n0 = R.Parameter(kInt32Types[i]); + for (size_t j = 0; j < ARRAY_SIZE(kInt32Types); j++) { + Node* n1 = R.Parameter(kInt32Types[j]); + Node* one = R.graph.NewNode(R.common.NumberConstant(1)); + + for (int l = 0; l < 2; l++) { + Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1); + Node* or_node = + R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node); + Node* r = R.reduce(or_node); + + CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode()); + CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode()); + bool is_signed = l ? R.signedness[o] : R.signedness[o + 1]; + + Type* add_type = NodeProperties::GetBounds(add_node).upper; + CHECK(add_type->Is(I32Type(is_signed))); + } + } + } + } + } + { + JSBitwiseShiftTypedLoweringTester R; + + for (int o = 0; o < R.kNumberOps; o += 2) { + for (size_t i = 0; i < ARRAY_SIZE(kInt32Types); i++) { + Node* n0 = R.Parameter(kInt32Types[i]); + for (size_t j = 0; j < ARRAY_SIZE(kInt32Types); j++) { + Node* n1 = R.Parameter(kInt32Types[j]); + Node* one = R.graph.NewNode(R.common.NumberConstant(1)); + + for (int l = 0; l < 2; l++) { + Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1); + Node* or_node = + R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node); + Node* r = R.reduce(or_node); + + CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode()); + CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode()); + bool is_signed = l ? R.signedness[o] : R.signedness[o + 1]; + + Type* add_type = NodeProperties::GetBounds(add_node).upper; + CHECK(add_type->Is(I32Type(is_signed))); + } + } + } + } + } +} + + +TEST(Int32AddNarrowingNotOwned) { + JSBitwiseTypedLoweringTester R; + + for (int o = 0; o < R.kNumberOps; o += 2) { + Node* n0 = R.Parameter(I32Type(R.signedness[o])); + Node* n1 = R.Parameter(I32Type(R.signedness[o + 1])); + Node* one = R.graph.NewNode(R.common.NumberConstant(1)); + + Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1); + Node* or_node = R.Binop(R.ops[o], add_node, one); + Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one); + Node* r = R.reduce(or_node); + CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode()); + // Should not be reduced to Int32Add because of the other number add. + CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode()); + // Conversion to int32 should be done. + CheckToI32(add_node, r->InputAt(0), R.signedness[o]); + CheckToI32(one, r->InputAt(1), R.signedness[o + 1]); + // The other use should also not be touched. + CHECK_EQ(add_node, other_use->InputAt(0)); + CHECK_EQ(one, other_use->InputAt(1)); + } +} + + +TEST(Int32Comparisons) { + JSTypedLoweringTester R; + + struct Entry { + Operator* js_op; + Operator* uint_op; + Operator* int_op; + Operator* num_op; + bool commute; + }; + + Entry ops[] = { + {R.javascript.LessThan(), R.machine.Uint32LessThan(), + R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false}, + {R.javascript.LessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), + R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + false}, + {R.javascript.GreaterThan(), R.machine.Uint32LessThan(), + R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true}, + {R.javascript.GreaterThanOrEqual(), R.machine.Uint32LessThanOrEqual(), + R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + true}}; + + for (size_t o = 0; o < ARRAY_SIZE(ops); o++) { + for (size_t i = 0; i < ARRAY_SIZE(kNumberTypes); i++) { + Type* t0 = kNumberTypes[i]; + Node* p0 = R.Parameter(t0, 0); + + for (size_t j = 0; j < ARRAY_SIZE(kNumberTypes); j++) { + Type* t1 = kNumberTypes[j]; + Node* p1 = R.Parameter(t1, 1); + + Node* cmp = R.Binop(ops[o].js_op, p0, p1); + Node* r = R.reduce(cmp); + + Operator* expected; + if (t0->Is(Type::Unsigned32()) && t1->Is(Type::Unsigned32())) { + expected = ops[o].uint_op; + } else if (t0->Is(Type::Signed32()) && t1->Is(Type::Signed32())) { + expected = ops[o].int_op; + } else { + expected = ops[o].num_op; + } + R.CheckPureBinop(expected, r); + if (ops[o].commute) { + CHECK_EQ(p1, r->InputAt(0)); + CHECK_EQ(p0, r->InputAt(1)); + } else { + CHECK_EQ(p0, r->InputAt(0)); + CHECK_EQ(p1, r->InputAt(1)); + } + } + } + } +} diff --git a/deps/v8/test/cctest/compiler/test-linkage.cc b/deps/v8/test/cctest/compiler/test-linkage.cc new file mode 100644 index 0000000000..6d9453f7c4 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-linkage.cc @@ -0,0 +1,113 @@ +// 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 "src/compiler.h" +#include "src/zone.h" + +#include "src/compiler/common-operator.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/graph.h" +#include "src/compiler/linkage.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" +#include "src/compiler/operator.h" +#include "src/compiler/pipeline.h" +#include "src/compiler/schedule.h" +#include "test/cctest/cctest.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal; +using namespace v8::internal::compiler; + +static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, + 0, 0, "dummy"); + +// So we can get a real JS function. +static Handle<JSFunction> Compile(const char* source) { + Isolate* isolate = CcTest::i_isolate(); + Handle<String> source_code = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( + source_code, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, NULL, + v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE); + return isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared_function, isolate->native_context()); +} + + +TEST(TestLinkageCreate) { + InitializedHandleScope handles; + Handle<JSFunction> function = Compile("a + b"); + CompilationInfoWithZone info(function); + Linkage linkage(&info); +} + + +TEST(TestLinkageJSFunctionIncoming) { + InitializedHandleScope handles; + + const char* sources[] = {"(function() { })", "(function(a) { })", + "(function(a,b) { })", "(function(a,b,c) { })"}; + + for (int i = 0; i < 3; i++) { + i::HandleScope handles(CcTest::i_isolate()); + Handle<JSFunction> function = v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast(CompileRun(sources[i]))); + CompilationInfoWithZone info(function); + Linkage linkage(&info); + + CallDescriptor* descriptor = linkage.GetIncomingDescriptor(); + CHECK_NE(NULL, descriptor); + + CHECK_EQ(1 + i, descriptor->ParameterCount()); + CHECK_EQ(1, descriptor->ReturnCount()); + CHECK_EQ(Operator::kNoProperties, descriptor->properties()); + CHECK_EQ(true, descriptor->IsJSFunctionCall()); + } +} + + +TEST(TestLinkageCodeStubIncoming) { + Isolate* isolate = CcTest::InitIsolateOnce(); + CompilationInfoWithZone info(static_cast<HydrogenCodeStub*>(NULL), isolate); + Linkage linkage(&info); + // TODO(titzer): test linkage creation with a bonafide code stub. + // this just checks current behavior. + CHECK_EQ(NULL, linkage.GetIncomingDescriptor()); +} + + +TEST(TestLinkageJSCall) { + HandleAndZoneScope handles; + Handle<JSFunction> function = Compile("a + c"); + CompilationInfoWithZone info(function); + Linkage linkage(&info); + + for (int i = 0; i < 32; i++) { + CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i); + CHECK_NE(NULL, descriptor); + CHECK_EQ(i, descriptor->ParameterCount()); + CHECK_EQ(1, descriptor->ReturnCount()); + CHECK_EQ(Operator::kNoProperties, descriptor->properties()); + CHECK_EQ(true, descriptor->IsJSFunctionCall()); + } +} + + +TEST(TestLinkageRuntimeCall) { + // TODO(titzer): test linkage creation for outgoing runtime calls. +} + + +TEST(TestLinkageStubCall) { + // TODO(titzer): test linkage creation for outgoing stub calls. +} + + +#endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc new file mode 100644 index 0000000000..c79a96a094 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc @@ -0,0 +1,779 @@ +// 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 "test/cctest/cctest.h" + +#include "src/base/utils/random-number-generator.h" +#include "src/compiler/graph-inl.h" +#include "src/compiler/machine-operator-reducer.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +template <typename T> +Operator* NewConstantOperator(CommonOperatorBuilder* common, volatile T value); + +template <> +Operator* NewConstantOperator<int32_t>(CommonOperatorBuilder* common, + volatile int32_t value) { + return common->Int32Constant(value); +} + +template <> +Operator* NewConstantOperator<double>(CommonOperatorBuilder* common, + volatile double value) { + return common->Float64Constant(value); +} + + +class ReducerTester : public HandleAndZoneScope { + public: + explicit ReducerTester(int num_parameters = 0) + : isolate(main_isolate()), + binop(NULL), + unop(NULL), + machine(main_zone()), + common(main_zone()), + graph(main_zone()), + maxuint32(Constant<int32_t>(kMaxUInt32)) { + Node* s = graph.NewNode(common.Start(num_parameters)); + graph.SetStart(s); + } + + Isolate* isolate; + Operator* binop; + Operator* unop; + MachineOperatorBuilder machine; + CommonOperatorBuilder common; + Graph graph; + Node* maxuint32; + + template <typename T> + Node* Constant(volatile T value) { + return graph.NewNode(NewConstantOperator<T>(&common, value)); + } + + // Check that the reduction of this binop applied to constants {a} and {b} + // yields the {expect} value. + template <typename T> + void CheckFoldBinop(volatile T expect, volatile T a, volatile T b) { + CheckFoldBinop<T>(expect, Constant<T>(a), Constant<T>(b)); + } + + // Check that the reduction of this binop applied to {a} and {b} yields + // the {expect} value. + template <typename T> + void CheckFoldBinop(volatile T expect, Node* a, Node* b) { + CHECK_NE(NULL, binop); + Node* n = graph.NewNode(binop, a, b); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(reduction.Changed()); + CHECK_NE(n, reduction.replacement()); + CHECK_EQ(expect, ValueOf<T>(reduction.replacement()->op())); + } + + // Check that the reduction of this binop applied to {a} and {b} yields + // the {expect} node. + void CheckBinop(Node* expect, Node* a, Node* b) { + CHECK_NE(NULL, binop); + Node* n = graph.NewNode(binop, a, b); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(reduction.Changed()); + CHECK_EQ(expect, reduction.replacement()); + } + + // Check that the reduction of this binop applied to {left} and {right} yields + // this binop applied to {left_expect} and {right_expect}. + void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left, + Node* right) { + CHECK_NE(NULL, binop); + Node* n = graph.NewNode(binop, left, right); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(reduction.Changed()); + CHECK_EQ(binop, reduction.replacement()->op()); + CHECK_EQ(left_expect, reduction.replacement()->InputAt(0)); + CHECK_EQ(right_expect, reduction.replacement()->InputAt(1)); + } + + // Check that the reduction of this binop applied to {left} and {right} yields + // the {op_expect} applied to {left_expect} and {right_expect}. + template <typename T> + void CheckFoldBinop(volatile T left_expect, Operator* op_expect, + Node* right_expect, Node* left, Node* right) { + CHECK_NE(NULL, binop); + Node* n = graph.NewNode(binop, left, right); + MachineOperatorReducer reducer(&graph); + Reduction r = reducer.Reduce(n); + CHECK(r.Changed()); + CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode()); + CHECK_EQ(left_expect, ValueOf<T>(r.replacement()->InputAt(0)->op())); + CHECK_EQ(right_expect, r.replacement()->InputAt(1)); + } + + // Check that the reduction of this binop applied to {left} and {right} yields + // the {op_expect} applied to {left_expect} and {right_expect}. + template <typename T> + void CheckFoldBinop(Node* left_expect, Operator* op_expect, + volatile T right_expect, Node* left, Node* right) { + CHECK_NE(NULL, binop); + Node* n = graph.NewNode(binop, left, right); + MachineOperatorReducer reducer(&graph); + Reduction r = reducer.Reduce(n); + CHECK(r.Changed()); + CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode()); + CHECK_EQ(left_expect, r.replacement()->InputAt(0)); + CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op())); + } + + // Check that if the given constant appears on the left, the reducer will + // swap it to be on the right. + template <typename T> + void CheckPutConstantOnRight(volatile T constant) { + // TODO(titzer): CHECK(binop->HasProperty(Operator::kCommutative)); + Node* p = Parameter(); + Node* k = Constant<T>(constant); + { + Node* n = graph.NewNode(binop, k, p); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(!reduction.Changed() || reduction.replacement() == n); + CHECK_EQ(p, n->InputAt(0)); + CHECK_EQ(k, n->InputAt(1)); + } + { + Node* n = graph.NewNode(binop, p, k); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(!reduction.Changed()); + CHECK_EQ(p, n->InputAt(0)); + CHECK_EQ(k, n->InputAt(1)); + } + } + + // Check that if the given constant appears on the left, the reducer will + // *NOT* swap it to be on the right. + template <typename T> + void CheckDontPutConstantOnRight(volatile T constant) { + CHECK(!binop->HasProperty(Operator::kCommutative)); + Node* p = Parameter(); + Node* k = Constant<T>(constant); + Node* n = graph.NewNode(binop, k, p); + MachineOperatorReducer reducer(&graph); + Reduction reduction = reducer.Reduce(n); + CHECK(!reduction.Changed()); + CHECK_EQ(k, n->InputAt(0)); + CHECK_EQ(p, n->InputAt(1)); + } + + Node* Parameter(int32_t index = 0) { + return graph.NewNode(common.Parameter(index), graph.start()); + } +}; + + +TEST(ReduceWord32And) { + ReducerTester R; + R.binop = R.machine.Word32And(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x & y, x, y); + } + } + + R.CheckPutConstantOnRight(33); + R.CheckPutConstantOnRight(44000); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + Node* minus_1 = R.Constant<int32_t>(-1); + + R.CheckBinop(zero, x, zero); // x & 0 => 0 + R.CheckBinop(zero, zero, x); // 0 & x => 0 + R.CheckBinop(x, x, minus_1); // x & -1 => 0 + R.CheckBinop(x, minus_1, x); // -1 & x => 0 + R.CheckBinop(x, x, x); // x & x => x +} + + +TEST(ReduceWord32Or) { + ReducerTester R; + R.binop = R.machine.Word32Or(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x | y, x, y); + } + } + + R.CheckPutConstantOnRight(36); + R.CheckPutConstantOnRight(44001); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + Node* minus_1 = R.Constant<int32_t>(-1); + + R.CheckBinop(x, x, zero); // x & 0 => x + R.CheckBinop(x, zero, x); // 0 & x => x + R.CheckBinop(minus_1, x, minus_1); // x & -1 => -1 + R.CheckBinop(minus_1, minus_1, x); // -1 & x => -1 + R.CheckBinop(x, x, x); // x & x => x +} + + +TEST(ReduceWord32Xor) { + ReducerTester R; + R.binop = R.machine.Word32Xor(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x ^ y, x, y); + } + } + + R.CheckPutConstantOnRight(39); + R.CheckPutConstantOnRight(4403); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x ^ 0 => x + R.CheckBinop(x, zero, x); // 0 ^ x => x + R.CheckFoldBinop<int32_t>(0, x, x); // x ^ x => 0 +} + + +TEST(ReduceWord32Shl) { + ReducerTester R; + R.binop = R.machine.Word32Shl(); + + // TODO(titzer): out of range shifts + FOR_INT32_INPUTS(i) { + for (int y = 0; y < 32; y++) { + int32_t x = *i; + R.CheckFoldBinop<int32_t>(x << y, x, y); + } + } + + R.CheckDontPutConstantOnRight(44); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x << 0 => x +} + + +TEST(ReduceWord32Shr) { + ReducerTester R; + R.binop = R.machine.Word32Shr(); + + // TODO(titzer): test out of range shifts + FOR_UINT32_INPUTS(i) { + for (uint32_t y = 0; y < 32; y++) { + uint32_t x = *i; + R.CheckFoldBinop<int32_t>(x >> y, x, y); + } + } + + R.CheckDontPutConstantOnRight(44); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x >>> 0 => x +} + + +TEST(ReduceWord32Sar) { + ReducerTester R; + R.binop = R.machine.Word32Sar(); + + // TODO(titzer): test out of range shifts + FOR_INT32_INPUTS(i) { + for (int32_t y = 0; y < 32; y++) { + int32_t x = *i; + R.CheckFoldBinop<int32_t>(x >> y, x, y); + } + } + + R.CheckDontPutConstantOnRight(44); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x >> 0 => x +} + + +TEST(ReduceWord32Equal) { + ReducerTester R; + R.binop = R.machine.Word32Equal(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x == y ? 1 : 0, x, y); + } + } + + R.CheckPutConstantOnRight(48); + R.CheckPutConstantOnRight(-48); + + Node* x = R.Parameter(0); + Node* y = R.Parameter(1); + Node* zero = R.Constant<int32_t>(0); + Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y); + + R.CheckFoldBinop<int32_t>(1, x, x); // x == x => 1 + R.CheckFoldBinop(x, y, sub, zero); // x - y == 0 => x == y + R.CheckFoldBinop(x, y, zero, sub); // 0 == x - y => x == y +} + + +TEST(ReduceInt32Add) { + ReducerTester R; + R.binop = R.machine.Int32Add(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x + y, x, y); // TODO(titzer): signed overflow + } + } + + R.CheckPutConstantOnRight(41); + R.CheckPutConstantOnRight(4407); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x + 0 => x + R.CheckBinop(x, zero, x); // 0 + x => x +} + + +TEST(ReduceInt32Sub) { + ReducerTester R; + R.binop = R.machine.Int32Sub(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x - y, x, y); + } + } + + R.CheckDontPutConstantOnRight(412); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + + R.CheckBinop(x, x, zero); // x - 0 => x +} + + +TEST(ReduceInt32Mul) { + ReducerTester R; + R.binop = R.machine.Int32Mul(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x * y, x, y); // TODO(titzer): signed overflow + } + } + + R.CheckPutConstantOnRight(4111); + R.CheckPutConstantOnRight(-4407); + + Node* x = R.Parameter(); + Node* zero = R.Constant<int32_t>(0); + Node* one = R.Constant<int32_t>(1); + Node* minus_one = R.Constant<int32_t>(-1); + + R.CheckBinop(zero, x, zero); // x * 0 => 0 + R.CheckBinop(zero, zero, x); // 0 * x => 0 + R.CheckBinop(x, x, one); // x * 1 => x + R.CheckBinop(x, one, x); // 1 * x => x + R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, minus_one, + x); // -1 * x => 0 - x + R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x, + minus_one); // x * -1 => 0 - x + + for (int32_t n = 1; n < 31; ++n) { + Node* multiplier = R.Constant<int32_t>(1 << n); + R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, x, + multiplier); // x * 2^n => x << n + R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shl(), n, multiplier, + x); // 2^n * x => x << n + } +} + + +TEST(ReduceInt32Div) { + ReducerTester R; + R.binop = R.machine.Int32Div(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + if (y == 0) continue; // TODO(titzer): test / 0 + int32_t r = y == -1 ? -x : x / y; // INT_MIN / -1 may explode in C + R.CheckFoldBinop<int32_t>(r, x, y); + } + } + + R.CheckDontPutConstantOnRight(41111); + R.CheckDontPutConstantOnRight(-44071); + + Node* x = R.Parameter(); + Node* one = R.Constant<int32_t>(1); + Node* minus_one = R.Constant<int32_t>(-1); + + R.CheckBinop(x, x, one); // x / 1 => x + // TODO(titzer): // 0 / x => 0 if x != 0 + // TODO(titzer): // x / 2^n => x >> n and round + R.CheckFoldBinop<int32_t>(0, R.machine.Int32Sub(), x, x, + minus_one); // x / -1 => 0 - x +} + + +TEST(ReduceInt32UDiv) { + ReducerTester R; + R.binop = R.machine.Int32UDiv(); + + FOR_UINT32_INPUTS(pl) { + FOR_UINT32_INPUTS(pr) { + uint32_t x = *pl, y = *pr; + if (y == 0) continue; // TODO(titzer): test / 0 + R.CheckFoldBinop<int32_t>(x / y, x, y); + } + } + + R.CheckDontPutConstantOnRight(41311); + R.CheckDontPutConstantOnRight(-44371); + + Node* x = R.Parameter(); + Node* one = R.Constant<int32_t>(1); + + R.CheckBinop(x, x, one); // x / 1 => x + // TODO(titzer): // 0 / x => 0 if x != 0 + + for (uint32_t n = 1; n < 32; ++n) { + Node* divisor = R.Constant<int32_t>(1u << n); + R.CheckFoldBinop<int32_t>(x, R.machine.Word32Shr(), n, x, + divisor); // x / 2^n => x >> n + } +} + + +TEST(ReduceInt32Mod) { + ReducerTester R; + R.binop = R.machine.Int32Mod(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + if (y == 0) continue; // TODO(titzer): test % 0 + int32_t r = y == -1 ? 0 : x % y; // INT_MIN % -1 may explode in C + R.CheckFoldBinop<int32_t>(r, x, y); + } + } + + R.CheckDontPutConstantOnRight(413); + R.CheckDontPutConstantOnRight(-4401); + + Node* x = R.Parameter(); + Node* one = R.Constant<int32_t>(1); + + R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0 + // TODO(titzer): // x % 2^n => x & 2^n-1 and round +} + + +TEST(ReduceInt32UMod) { + ReducerTester R; + R.binop = R.machine.Int32UMod(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + uint32_t x = *pl, y = *pr; + if (y == 0) continue; // TODO(titzer): test x % 0 + R.CheckFoldBinop<int32_t>(x % y, x, y); + } + } + + R.CheckDontPutConstantOnRight(417); + R.CheckDontPutConstantOnRight(-4371); + + Node* x = R.Parameter(); + Node* one = R.Constant<int32_t>(1); + + R.CheckFoldBinop<int32_t>(0, x, one); // x % 1 => 0 + + for (uint32_t n = 1; n < 32; ++n) { + Node* divisor = R.Constant<int32_t>(1u << n); + R.CheckFoldBinop<int32_t>(x, R.machine.Word32And(), (1u << n) - 1, x, + divisor); // x % 2^n => x & 2^n-1 + } +} + + +TEST(ReduceInt32LessThan) { + ReducerTester R; + R.binop = R.machine.Int32LessThan(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y); + } + } + + R.CheckDontPutConstantOnRight(41399); + R.CheckDontPutConstantOnRight(-440197); + + Node* x = R.Parameter(0); + Node* y = R.Parameter(1); + Node* zero = R.Constant<int32_t>(0); + Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y); + + R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0 + R.CheckFoldBinop(x, y, sub, zero); // x - y < 0 => x < y + R.CheckFoldBinop(y, x, zero, sub); // 0 < x - y => y < x +} + + +TEST(ReduceInt32LessThanOrEqual) { + ReducerTester R; + R.binop = R.machine.Int32LessThanOrEqual(); + + FOR_INT32_INPUTS(pl) { + FOR_INT32_INPUTS(pr) { + int32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y); + } + } + + FOR_INT32_INPUTS(i) { R.CheckDontPutConstantOnRight<int32_t>(*i); } + + Node* x = R.Parameter(0); + Node* y = R.Parameter(1); + Node* zero = R.Constant<int32_t>(0); + Node* sub = R.graph.NewNode(R.machine.Int32Sub(), x, y); + + R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1 + R.CheckFoldBinop(x, y, sub, zero); // x - y <= 0 => x <= y + R.CheckFoldBinop(y, x, zero, sub); // 0 <= x - y => y <= x +} + + +TEST(ReduceUint32LessThan) { + ReducerTester R; + R.binop = R.machine.Uint32LessThan(); + + FOR_UINT32_INPUTS(pl) { + FOR_UINT32_INPUTS(pr) { + uint32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x < y ? 1 : 0, x, y); + } + } + + R.CheckDontPutConstantOnRight(41399); + R.CheckDontPutConstantOnRight(-440197); + + Node* x = R.Parameter(); + Node* max = R.maxuint32; + Node* zero = R.Constant<int32_t>(0); + + R.CheckFoldBinop<int32_t>(0, max, x); // M < x => 0 + R.CheckFoldBinop<int32_t>(0, x, zero); // x < 0 => 0 + R.CheckFoldBinop<int32_t>(0, x, x); // x < x => 0 +} + + +TEST(ReduceUint32LessThanOrEqual) { + ReducerTester R; + R.binop = R.machine.Uint32LessThanOrEqual(); + + FOR_UINT32_INPUTS(pl) { + FOR_UINT32_INPUTS(pr) { + uint32_t x = *pl, y = *pr; + R.CheckFoldBinop<int32_t>(x <= y ? 1 : 0, x, y); + } + } + + R.CheckDontPutConstantOnRight(41399); + R.CheckDontPutConstantOnRight(-440197); + + Node* x = R.Parameter(); + Node* max = R.maxuint32; + Node* zero = R.Constant<int32_t>(0); + + R.CheckFoldBinop<int32_t>(1, x, max); // x <= M => 1 + R.CheckFoldBinop<int32_t>(1, zero, x); // 0 <= x => 1 + R.CheckFoldBinop<int32_t>(1, x, x); // x <= x => 1 +} + + +TEST(ReduceLoadStore) { + ReducerTester R; + + Node* base = R.Constant<int32_t>(11); + Node* index = R.Constant<int32_t>(4); + Node* load = R.graph.NewNode(R.machine.Load(kMachineWord32), base, index); + + { + MachineOperatorReducer reducer(&R.graph); + Reduction reduction = reducer.Reduce(load); + CHECK(!reduction.Changed()); // loads should not be reduced. + } + + { + Node* store = R.graph.NewNode( + R.machine.Store(kMachineWord32, kNoWriteBarrier), base, index, load); + MachineOperatorReducer reducer(&R.graph); + Reduction reduction = reducer.Reduce(store); + CHECK(!reduction.Changed()); // stores should not be reduced. + } +} + + +static void CheckNans(ReducerTester* R) { + Node* x = R->Parameter(); + std::vector<double> nans = ValueHelper::nan_vector(); + for (std::vector<double>::const_iterator pl = nans.begin(); pl != nans.end(); + ++pl) { + for (std::vector<double>::const_iterator pr = nans.begin(); + pr != nans.end(); ++pr) { + Node* nan1 = R->Constant<double>(*pl); + Node* nan2 = R->Constant<double>(*pr); + R->CheckBinop(nan1, x, nan1); // x % NaN => NaN + R->CheckBinop(nan1, nan1, x); // NaN % x => NaN + R->CheckBinop(nan1, nan2, nan1); // NaN % NaN => NaN + } + } +} + + +TEST(ReduceFloat64Add) { + ReducerTester R; + R.binop = R.machine.Float64Add(); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double x = *pl, y = *pr; + R.CheckFoldBinop<double>(x + y, x, y); + } + } + + FOR_FLOAT64_INPUTS(i) { R.CheckPutConstantOnRight(*i); } + // TODO(titzer): CheckNans(&R); +} + + +TEST(ReduceFloat64Sub) { + ReducerTester R; + R.binop = R.machine.Float64Sub(); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double x = *pl, y = *pr; + R.CheckFoldBinop<double>(x - y, x, y); + } + } + // TODO(titzer): CheckNans(&R); +} + + +TEST(ReduceFloat64Mul) { + ReducerTester R; + R.binop = R.machine.Float64Mul(); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double x = *pl, y = *pr; + R.CheckFoldBinop<double>(x * y, x, y); + } + } + + double inf = V8_INFINITY; + R.CheckPutConstantOnRight(-inf); + R.CheckPutConstantOnRight(-0.1); + R.CheckPutConstantOnRight(0.1); + R.CheckPutConstantOnRight(inf); + + Node* x = R.Parameter(); + Node* one = R.Constant<double>(1.0); + + R.CheckBinop(x, x, one); // x * 1.0 => x + R.CheckBinop(x, one, x); // 1.0 * x => x + + CheckNans(&R); +} + + +TEST(ReduceFloat64Div) { + ReducerTester R; + R.binop = R.machine.Float64Div(); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double x = *pl, y = *pr; + R.CheckFoldBinop<double>(x / y, x, y); + } + } + + Node* x = R.Parameter(); + Node* one = R.Constant<double>(1.0); + + R.CheckBinop(x, x, one); // x / 1.0 => x + + CheckNans(&R); +} + + +TEST(ReduceFloat64Mod) { + ReducerTester R; + R.binop = R.machine.Float64Mod(); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double x = *pl, y = *pr; + R.CheckFoldBinop<double>(modulo(x, y), x, y); + } + } + + CheckNans(&R); +} + + +// TODO(titzer): test MachineOperatorReducer for Word64And +// TODO(titzer): test MachineOperatorReducer for Word64Or +// TODO(titzer): test MachineOperatorReducer for Word64Xor +// TODO(titzer): test MachineOperatorReducer for Word64Shl +// TODO(titzer): test MachineOperatorReducer for Word64Shr +// TODO(titzer): test MachineOperatorReducer for Word64Sar +// TODO(titzer): test MachineOperatorReducer for Word64Equal +// TODO(titzer): test MachineOperatorReducer for Word64Not +// TODO(titzer): test MachineOperatorReducer for Int64Add +// TODO(titzer): test MachineOperatorReducer for Int64Sub +// TODO(titzer): test MachineOperatorReducer for Int64Mul +// TODO(titzer): test MachineOperatorReducer for Int64UMul +// TODO(titzer): test MachineOperatorReducer for Int64Div +// TODO(titzer): test MachineOperatorReducer for Int64UDiv +// TODO(titzer): test MachineOperatorReducer for Int64Mod +// TODO(titzer): test MachineOperatorReducer for Int64UMod +// TODO(titzer): test MachineOperatorReducer for Int64Neg +// TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64 +// TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32 +// TODO(titzer): test MachineOperatorReducer for Float64Compare diff --git a/deps/v8/test/cctest/compiler/test-node-algorithm.cc b/deps/v8/test/cctest/compiler/test-node-algorithm.cc new file mode 100644 index 0000000000..10f98a66a7 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-node-algorithm.cc @@ -0,0 +1,330 @@ +// Copyright 2013 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 <vector> + +#include "src/v8.h" + +#include "graph-tester.h" +#include "src/compiler/common-operator.h" +#include "src/compiler/generic-node.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/graph.h" +#include "src/compiler/graph-inl.h" +#include "src/compiler/graph-visualizer.h" +#include "src/compiler/operator.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, + 0, 0, "dummy"); + +class PreNodeVisitor : public NullNodeVisitor { + public: + GenericGraphVisit::Control Pre(Node* node) { + printf("NODE ID: %d\n", node->id()); + nodes_.push_back(node); + return GenericGraphVisit::CONTINUE; + } + std::vector<Node*> nodes_; +}; + + +class PostNodeVisitor : public NullNodeVisitor { + public: + GenericGraphVisit::Control Post(Node* node) { + printf("NODE ID: %d\n", node->id()); + nodes_.push_back(node); + return GenericGraphVisit::CONTINUE; + } + std::vector<Node*> nodes_; +}; + + +TEST(TestUseNodeVisitEmpty) { + GraphWithStartNodeTester graph; + + PreNodeVisitor node_visitor; + graph.VisitNodeUsesFromStart(&node_visitor); + + CHECK_EQ(1, static_cast<int>(node_visitor.nodes_.size())); +} + + +TEST(TestUseNodePreOrderVisitSimple) { + GraphWithStartNodeTester graph; + Node* n2 = graph.NewNode(&dummy_operator, graph.start()); + Node* n3 = graph.NewNode(&dummy_operator, n2); + Node* n4 = graph.NewNode(&dummy_operator, n2, n3); + Node* n5 = graph.NewNode(&dummy_operator, n4, n2); + graph.SetEnd(n5); + + PreNodeVisitor node_visitor; + graph.VisitNodeUsesFromStart(&node_visitor); + + CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size())); + CHECK(graph.start()->id() == node_visitor.nodes_[0]->id()); + CHECK(n2->id() == node_visitor.nodes_[1]->id()); + CHECK(n3->id() == node_visitor.nodes_[2]->id()); + CHECK(n4->id() == node_visitor.nodes_[3]->id()); + CHECK(n5->id() == node_visitor.nodes_[4]->id()); +} + + +TEST(TestInputNodePreOrderVisitSimple) { + GraphWithStartNodeTester graph; + Node* n2 = graph.NewNode(&dummy_operator, graph.start()); + Node* n3 = graph.NewNode(&dummy_operator, n2); + Node* n4 = graph.NewNode(&dummy_operator, n2, n3); + Node* n5 = graph.NewNode(&dummy_operator, n4, n2); + graph.SetEnd(n5); + + PreNodeVisitor node_visitor; + graph.VisitNodeInputsFromEnd(&node_visitor); + CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size())); + CHECK(n5->id() == node_visitor.nodes_[0]->id()); + CHECK(n4->id() == node_visitor.nodes_[1]->id()); + CHECK(n2->id() == node_visitor.nodes_[2]->id()); + CHECK(graph.start()->id() == node_visitor.nodes_[3]->id()); + CHECK(n3->id() == node_visitor.nodes_[4]->id()); +} + + +TEST(TestUseNodePostOrderVisitSimple) { + GraphWithStartNodeTester graph; + Node* n2 = graph.NewNode(&dummy_operator, graph.start()); + Node* n3 = graph.NewNode(&dummy_operator, graph.start()); + Node* n4 = graph.NewNode(&dummy_operator, n2); + Node* n5 = graph.NewNode(&dummy_operator, n2); + Node* n6 = graph.NewNode(&dummy_operator, n2); + Node* n7 = graph.NewNode(&dummy_operator, n3); + Node* end_dependencies[4] = {n4, n5, n6, n7}; + Node* n8 = graph.NewNode(&dummy_operator, 4, end_dependencies); + graph.SetEnd(n8); + + PostNodeVisitor node_visitor; + graph.VisitNodeUsesFromStart(&node_visitor); + + CHECK_EQ(8, static_cast<int>(node_visitor.nodes_.size())); + CHECK(graph.end()->id() == node_visitor.nodes_[0]->id()); + CHECK(n4->id() == node_visitor.nodes_[1]->id()); + CHECK(n5->id() == node_visitor.nodes_[2]->id()); + CHECK(n6->id() == node_visitor.nodes_[3]->id()); + CHECK(n2->id() == node_visitor.nodes_[4]->id()); + CHECK(n7->id() == node_visitor.nodes_[5]->id()); + CHECK(n3->id() == node_visitor.nodes_[6]->id()); + CHECK(graph.start()->id() == node_visitor.nodes_[7]->id()); +} + + +TEST(TestUseNodePostOrderVisitLong) { + GraphWithStartNodeTester graph; + Node* n2 = graph.NewNode(&dummy_operator, graph.start()); + Node* n3 = graph.NewNode(&dummy_operator, graph.start()); + Node* n4 = graph.NewNode(&dummy_operator, n2); + Node* n5 = graph.NewNode(&dummy_operator, n2); + Node* n6 = graph.NewNode(&dummy_operator, n3); + Node* n7 = graph.NewNode(&dummy_operator, n3); + Node* n8 = graph.NewNode(&dummy_operator, n5); + Node* n9 = graph.NewNode(&dummy_operator, n5); + Node* n10 = graph.NewNode(&dummy_operator, n9); + Node* n11 = graph.NewNode(&dummy_operator, n9); + Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7}; + Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies); + graph.SetEnd(n12); + + PostNodeVisitor node_visitor; + graph.VisitNodeUsesFromStart(&node_visitor); + + CHECK_EQ(12, static_cast<int>(node_visitor.nodes_.size())); + CHECK(graph.end()->id() == node_visitor.nodes_[0]->id()); + CHECK(n4->id() == node_visitor.nodes_[1]->id()); + CHECK(n8->id() == node_visitor.nodes_[2]->id()); + CHECK(n10->id() == node_visitor.nodes_[3]->id()); + CHECK(n11->id() == node_visitor.nodes_[4]->id()); + CHECK(n9->id() == node_visitor.nodes_[5]->id()); + CHECK(n5->id() == node_visitor.nodes_[6]->id()); + CHECK(n2->id() == node_visitor.nodes_[7]->id()); + CHECK(n6->id() == node_visitor.nodes_[8]->id()); + CHECK(n7->id() == node_visitor.nodes_[9]->id()); + CHECK(n3->id() == node_visitor.nodes_[10]->id()); + CHECK(graph.start()->id() == node_visitor.nodes_[11]->id()); +} + + +TEST(TestUseNodePreOrderVisitCycle) { + GraphWithStartNodeTester graph; + Node* n0 = graph.start_node(); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n1); + n0->AppendInput(graph.main_zone(), n2); + graph.SetStart(n0); + graph.SetEnd(n2); + + PreNodeVisitor node_visitor; + graph.VisitNodeUsesFromStart(&node_visitor); + + CHECK_EQ(3, static_cast<int>(node_visitor.nodes_.size())); + CHECK(n0->id() == node_visitor.nodes_[0]->id()); + CHECK(n1->id() == node_visitor.nodes_[1]->id()); + CHECK(n2->id() == node_visitor.nodes_[2]->id()); +} + + +struct ReenterNodeVisitor : NullNodeVisitor { + GenericGraphVisit::Control Pre(Node* node) { + printf("[%d] PRE NODE: %d\n", static_cast<int>(nodes_.size()), node->id()); + nodes_.push_back(node->id()); + int size = static_cast<int>(nodes_.size()); + switch (node->id()) { + case 0: + return size < 6 ? GenericGraphVisit::REENTER : GenericGraphVisit::SKIP; + case 1: + return size < 4 ? GenericGraphVisit::DEFER + : GenericGraphVisit::CONTINUE; + default: + return GenericGraphVisit::REENTER; + } + } + + GenericGraphVisit::Control Post(Node* node) { + printf("[%d] POST NODE: %d\n", static_cast<int>(nodes_.size()), node->id()); + nodes_.push_back(-node->id()); + return node->id() == 4 ? GenericGraphVisit::REENTER + : GenericGraphVisit::CONTINUE; + } + + void PreEdge(Node* from, int index, Node* to) { + printf("[%d] PRE EDGE: %d-%d\n", static_cast<int>(edges_.size()), + from->id(), to->id()); + edges_.push_back(std::make_pair(from->id(), to->id())); + } + + void PostEdge(Node* from, int index, Node* to) { + printf("[%d] POST EDGE: %d-%d\n", static_cast<int>(edges_.size()), + from->id(), to->id()); + edges_.push_back(std::make_pair(-from->id(), -to->id())); + } + + std::vector<int> nodes_; + std::vector<std::pair<int, int> > edges_; +}; + + +TEST(TestUseNodeReenterVisit) { + GraphWithStartNodeTester graph; + Node* n0 = graph.start_node(); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator, n2); + Node* n4 = graph.NewNode(&dummy_operator, n0); + Node* n5 = graph.NewNode(&dummy_operator, n4); + n0->AppendInput(graph.main_zone(), n3); + graph.SetStart(n0); + graph.SetEnd(n5); + + ReenterNodeVisitor visitor; + graph.VisitNodeUsesFromStart(&visitor); + + CHECK_EQ(22, static_cast<int>(visitor.nodes_.size())); + CHECK_EQ(24, static_cast<int>(visitor.edges_.size())); + + CHECK(n0->id() == visitor.nodes_[0]); + CHECK(n0->id() == visitor.edges_[0].first); + CHECK(n1->id() == visitor.edges_[0].second); + CHECK(n1->id() == visitor.nodes_[1]); + // N1 is deferred. + CHECK(-n1->id() == visitor.edges_[1].second); + CHECK(-n0->id() == visitor.edges_[1].first); + CHECK(n0->id() == visitor.edges_[2].first); + CHECK(n2->id() == visitor.edges_[2].second); + CHECK(n2->id() == visitor.nodes_[2]); + CHECK(n2->id() == visitor.edges_[3].first); + CHECK(n3->id() == visitor.edges_[3].second); + CHECK(n3->id() == visitor.nodes_[3]); + // Circle back to N0, which we may reenter for now. + CHECK(n3->id() == visitor.edges_[4].first); + CHECK(n0->id() == visitor.edges_[4].second); + CHECK(n0->id() == visitor.nodes_[4]); + CHECK(n0->id() == visitor.edges_[5].first); + CHECK(n1->id() == visitor.edges_[5].second); + CHECK(n1->id() == visitor.nodes_[5]); + // This time N1 is no longer deferred. + CHECK(-n1->id() == visitor.nodes_[6]); + CHECK(-n1->id() == visitor.edges_[6].second); + CHECK(-n0->id() == visitor.edges_[6].first); + CHECK(n0->id() == visitor.edges_[7].first); + CHECK(n2->id() == visitor.edges_[7].second); + CHECK(n2->id() == visitor.nodes_[7]); + CHECK(n2->id() == visitor.edges_[8].first); + CHECK(n3->id() == visitor.edges_[8].second); + CHECK(n3->id() == visitor.nodes_[8]); + CHECK(n3->id() == visitor.edges_[9].first); + CHECK(n0->id() == visitor.edges_[9].second); + CHECK(n0->id() == visitor.nodes_[9]); + // This time we break at N0 and skip it. + CHECK(-n0->id() == visitor.edges_[10].second); + CHECK(-n3->id() == visitor.edges_[10].first); + CHECK(-n3->id() == visitor.nodes_[10]); + CHECK(-n3->id() == visitor.edges_[11].second); + CHECK(-n2->id() == visitor.edges_[11].first); + CHECK(-n2->id() == visitor.nodes_[11]); + CHECK(-n2->id() == visitor.edges_[12].second); + CHECK(-n0->id() == visitor.edges_[12].first); + CHECK(n0->id() == visitor.edges_[13].first); + CHECK(n4->id() == visitor.edges_[13].second); + CHECK(n4->id() == visitor.nodes_[12]); + CHECK(n4->id() == visitor.edges_[14].first); + CHECK(n5->id() == visitor.edges_[14].second); + CHECK(n5->id() == visitor.nodes_[13]); + CHECK(-n5->id() == visitor.nodes_[14]); + CHECK(-n5->id() == visitor.edges_[15].second); + CHECK(-n4->id() == visitor.edges_[15].first); + CHECK(-n4->id() == visitor.nodes_[15]); + CHECK(-n4->id() == visitor.edges_[16].second); + CHECK(-n0->id() == visitor.edges_[16].first); + CHECK(-n0->id() == visitor.nodes_[16]); + CHECK(-n0->id() == visitor.edges_[17].second); + CHECK(-n3->id() == visitor.edges_[17].first); + CHECK(-n3->id() == visitor.nodes_[17]); + CHECK(-n3->id() == visitor.edges_[18].second); + CHECK(-n2->id() == visitor.edges_[18].first); + CHECK(-n2->id() == visitor.nodes_[18]); + CHECK(-n2->id() == visitor.edges_[19].second); + CHECK(-n0->id() == visitor.edges_[19].first); + // N4 may be reentered. + CHECK(n0->id() == visitor.edges_[20].first); + CHECK(n4->id() == visitor.edges_[20].second); + CHECK(n4->id() == visitor.nodes_[19]); + CHECK(n4->id() == visitor.edges_[21].first); + CHECK(n5->id() == visitor.edges_[21].second); + CHECK(-n5->id() == visitor.edges_[22].second); + CHECK(-n4->id() == visitor.edges_[22].first); + CHECK(-n4->id() == visitor.nodes_[20]); + CHECK(-n4->id() == visitor.edges_[23].second); + CHECK(-n0->id() == visitor.edges_[23].first); + CHECK(-n0->id() == visitor.nodes_[21]); +} + + +TEST(TestPrintNodeGraphToNodeGraphviz) { + GraphWithStartNodeTester graph; + Node* n2 = graph.NewNode(&dummy_operator, graph.start()); + Node* n3 = graph.NewNode(&dummy_operator, graph.start()); + Node* n4 = graph.NewNode(&dummy_operator, n2); + Node* n5 = graph.NewNode(&dummy_operator, n2); + Node* n6 = graph.NewNode(&dummy_operator, n3); + Node* n7 = graph.NewNode(&dummy_operator, n3); + Node* n8 = graph.NewNode(&dummy_operator, n5); + Node* n9 = graph.NewNode(&dummy_operator, n5); + Node* n10 = graph.NewNode(&dummy_operator, n9); + Node* n11 = graph.NewNode(&dummy_operator, n9); + Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7}; + Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies); + graph.SetEnd(n12); + + OFStream os(stdout); + os << AsDOT(graph); +} diff --git a/deps/v8/test/cctest/compiler/test-node-cache.cc b/deps/v8/test/cctest/compiler/test-node-cache.cc new file mode 100644 index 0000000000..23909a5f5a --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-node-cache.cc @@ -0,0 +1,160 @@ +// 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 "graph-tester.h" +#include "src/compiler/common-operator.h" +#include "src/compiler/node-cache.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(Int32Constant_back_to_back) { + GraphTester graph; + Int32NodeCache cache; + + for (int i = -2000000000; i < 2000000000; i += 3315177) { + Node** pos = cache.Find(graph.zone(), i); + CHECK_NE(NULL, pos); + for (int j = 0; j < 3; j++) { + Node** npos = cache.Find(graph.zone(), i); + CHECK_EQ(pos, npos); + } + } +} + + +TEST(Int32Constant_five) { + GraphTester graph; + Int32NodeCache cache; + CommonOperatorBuilder common(graph.zone()); + + int32_t constants[] = {static_cast<int32_t>(0x80000000), -77, 0, 1, -1}; + + Node* nodes[ARRAY_SIZE(constants)]; + + for (size_t i = 0; i < ARRAY_SIZE(constants); i++) { + int32_t k = constants[i]; + Node* node = graph.NewNode(common.Int32Constant(k)); + *cache.Find(graph.zone(), k) = nodes[i] = node; + } + + for (size_t i = 0; i < ARRAY_SIZE(constants); i++) { + int32_t k = constants[i]; + CHECK_EQ(nodes[i], *cache.Find(graph.zone(), k)); + } +} + + +TEST(Int32Constant_hits) { + GraphTester graph; + Int32NodeCache cache; + const int32_t kSize = 1500; + Node** nodes = graph.zone()->NewArray<Node*>(kSize); + CommonOperatorBuilder common(graph.zone()); + + for (int i = 0; i < kSize; i++) { + int32_t v = i * -55; + nodes[i] = graph.NewNode(common.Int32Constant(v)); + *cache.Find(graph.zone(), v) = nodes[i]; + } + + int hits = 0; + for (int i = 0; i < kSize; i++) { + int32_t v = i * -55; + Node** pos = cache.Find(graph.zone(), v); + if (*pos != NULL) { + CHECK_EQ(nodes[i], *pos); + hits++; + } + } + CHECK_LT(4, hits); +} + + +TEST(Int64Constant_back_to_back) { + GraphTester graph; + Int64NodeCache cache; + + for (int64_t i = -2000000000; i < 2000000000; i += 3315177) { + Node** pos = cache.Find(graph.zone(), i); + CHECK_NE(NULL, pos); + for (int j = 0; j < 3; j++) { + Node** npos = cache.Find(graph.zone(), i); + CHECK_EQ(pos, npos); + } + } +} + + +TEST(Int64Constant_hits) { + GraphTester graph; + Int64NodeCache cache; + const int32_t kSize = 1500; + Node** nodes = graph.zone()->NewArray<Node*>(kSize); + CommonOperatorBuilder common(graph.zone()); + + for (int i = 0; i < kSize; i++) { + int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001); + nodes[i] = graph.NewNode(common.Int32Constant(i)); + *cache.Find(graph.zone(), v) = nodes[i]; + } + + int hits = 0; + for (int i = 0; i < kSize; i++) { + int64_t v = static_cast<int64_t>(i) * static_cast<int64_t>(5003001); + Node** pos = cache.Find(graph.zone(), v); + if (*pos != NULL) { + CHECK_EQ(nodes[i], *pos); + hits++; + } + } + CHECK_LT(4, hits); +} + + +TEST(PtrConstant_back_to_back) { + GraphTester graph; + PtrNodeCache cache; + int32_t buffer[50]; + + for (int32_t* p = buffer; + (p - buffer) < static_cast<ptrdiff_t>(ARRAY_SIZE(buffer)); p++) { + Node** pos = cache.Find(graph.zone(), p); + CHECK_NE(NULL, pos); + for (int j = 0; j < 3; j++) { + Node** npos = cache.Find(graph.zone(), p); + CHECK_EQ(pos, npos); + } + } +} + + +TEST(PtrConstant_hits) { + GraphTester graph; + PtrNodeCache cache; + const int32_t kSize = 50; + int32_t buffer[kSize]; + Node* nodes[kSize]; + CommonOperatorBuilder common(graph.zone()); + + for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) { + int k = static_cast<int>(i); + int32_t* p = &buffer[i]; + nodes[i] = graph.NewNode(common.Int32Constant(k)); + *cache.Find(graph.zone(), p) = nodes[i]; + } + + int hits = 0; + for (size_t i = 0; i < ARRAY_SIZE(buffer); i++) { + int32_t* p = &buffer[i]; + Node** pos = cache.Find(graph.zone(), p); + if (*pos != NULL) { + CHECK_EQ(nodes[i], *pos); + hits++; + } + } + CHECK_LT(4, hits); +} diff --git a/deps/v8/test/cctest/compiler/test-node.cc b/deps/v8/test/cctest/compiler/test-node.cc new file mode 100644 index 0000000000..6fe8573a2f --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-node.cc @@ -0,0 +1,815 @@ +// Copyright 2013 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 <functional> + +#include "src/v8.h" + +#include "graph-tester.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/node.h" +#include "src/compiler/operator.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, + 0, 0, "dummy"); + +TEST(NodeAllocation) { + GraphTester graph; + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + CHECK(n2->id() != n1->id()); +} + + +TEST(NodeWithOpcode) { + GraphTester graph; + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + CHECK(n1->op() == &dummy_operator); + CHECK(n2->op() == &dummy_operator); +} + + +TEST(NodeInputs1) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + CHECK_EQ(1, n2->InputCount()); + CHECK(n0 == n2->InputAt(0)); +} + + +TEST(NodeInputs2) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + CHECK_EQ(2, n2->InputCount()); + CHECK(n0 == n2->InputAt(0)); + CHECK(n1 == n2->InputAt(1)); +} + + +TEST(NodeInputs3) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1, n1); + CHECK_EQ(3, n2->InputCount()); + CHECK(n0 == n2->InputAt(0)); + CHECK(n1 == n2->InputAt(1)); + CHECK(n1 == n2->InputAt(2)); +} + + +TEST(NodeInputIteratorEmpty) { + GraphTester graph; + Node* n1 = graph.NewNode(&dummy_operator); + Node::Inputs::iterator i(n1->inputs().begin()); + int input_count = 0; + for (; i != n1->inputs().end(); ++i) { + input_count++; + } + CHECK_EQ(0, input_count); +} + + +TEST(NodeInputIteratorOne) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node::Inputs::iterator i(n1->inputs().begin()); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(n0, *i); + ++i; + CHECK(n1->inputs().end() == i); +} + + +TEST(NodeUseIteratorEmpty) { + GraphTester graph; + Node* n1 = graph.NewNode(&dummy_operator); + Node::Uses::iterator i(n1->uses().begin()); + int use_count = 0; + for (; i != n1->uses().end(); ++i) { + Node::Edge edge(i.edge()); + USE(edge); + use_count++; + } + CHECK_EQ(0, use_count); +} + + +TEST(NodeUseIteratorOne) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node::Uses::iterator i(n0->uses().begin()); + CHECK_EQ(n1, *i); + ++i; + CHECK(n0->uses().end() == i); +} + + +TEST(NodeUseIteratorReplaceNoUses) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n3 = graph.NewNode(&dummy_operator); + n0->ReplaceUses(n3); + CHECK(n0->uses().begin() == n0->uses().end()); +} + + +TEST(NodeUseIteratorReplaceUses) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator); + Node::Uses::iterator i1(n0->uses().begin()); + CHECK_EQ(n1, *i1); + ++i1; + CHECK_EQ(n2, *i1); + n0->ReplaceUses(n3); + Node::Uses::iterator i2(n3->uses().begin()); + CHECK_EQ(n1, *i2); + ++i2; + CHECK_EQ(n2, *i2); + Node::Inputs::iterator i3(n1->inputs().begin()); + CHECK_EQ(n3, *i3); + ++i3; + CHECK(n1->inputs().end() == i3); + Node::Inputs::iterator i4(n2->inputs().begin()); + CHECK_EQ(n3, *i4); + ++i4; + CHECK(n2->inputs().end() == i4); +} + + +TEST(NodeUseIteratorReplaceUsesSelf) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator); + + n1->ReplaceInput(0, n1); // Create self-reference. + + Node::Uses::iterator i1(n1->uses().begin()); + CHECK_EQ(n1, *i1); + + n1->ReplaceUses(n3); + + CHECK(n1->uses().begin() == n1->uses().end()); + + Node::Uses::iterator i2(n3->uses().begin()); + CHECK_EQ(n1, *i2); + ++i2; + CHECK(n1->uses().end() == i2); +} + + +TEST(ReplaceInput) { + GraphTester graph; + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); + Node::Inputs::iterator i1(n3->inputs().begin()); + CHECK(n0 == *i1); + CHECK_EQ(n0, n3->InputAt(0)); + ++i1; + CHECK_EQ(n1, *i1); + CHECK_EQ(n1, n3->InputAt(1)); + ++i1; + CHECK_EQ(n2, *i1); + CHECK_EQ(n2, n3->InputAt(2)); + ++i1; + CHECK(i1 == n3->inputs().end()); + + Node::Uses::iterator i2(n1->uses().begin()); + CHECK_EQ(n3, *i2); + ++i2; + CHECK(i2 == n1->uses().end()); + + Node* n4 = graph.NewNode(&dummy_operator); + Node::Uses::iterator i3(n4->uses().begin()); + CHECK(i3 == n4->uses().end()); + + n3->ReplaceInput(1, n4); + + Node::Uses::iterator i4(n1->uses().begin()); + CHECK(i4 == n1->uses().end()); + + Node::Uses::iterator i5(n4->uses().begin()); + CHECK_EQ(n3, *i5); + ++i5; + CHECK(i5 == n4->uses().end()); + + Node::Inputs::iterator i6(n3->inputs().begin()); + CHECK(n0 == *i6); + CHECK_EQ(n0, n3->InputAt(0)); + ++i6; + CHECK_EQ(n4, *i6); + CHECK_EQ(n4, n3->InputAt(1)); + ++i6; + CHECK_EQ(n2, *i6); + CHECK_EQ(n2, n3->InputAt(2)); + ++i6; + CHECK(i6 == n3->inputs().end()); +} + + +TEST(OwnedBy) { + GraphTester graph; + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + + CHECK(!n0->OwnedBy(n1)); + CHECK(!n1->OwnedBy(n0)); + + Node* n2 = graph.NewNode(&dummy_operator, n0); + CHECK(n0->OwnedBy(n2)); + CHECK(!n2->OwnedBy(n0)); + + Node* n3 = graph.NewNode(&dummy_operator, n0); + CHECK(!n0->OwnedBy(n2)); + CHECK(!n0->OwnedBy(n3)); + CHECK(!n2->OwnedBy(n0)); + CHECK(!n3->OwnedBy(n0)); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + CHECK(n0->OwnedBy(n1)); + CHECK(!n1->OwnedBy(n0)); + Node* n2 = graph.NewNode(&dummy_operator, n0); + CHECK(!n0->OwnedBy(n1)); + CHECK(!n0->OwnedBy(n2)); + CHECK(!n1->OwnedBy(n0)); + CHECK(!n1->OwnedBy(n2)); + CHECK(!n2->OwnedBy(n0)); + CHECK(!n2->OwnedBy(n1)); + + Node* n3 = graph.NewNode(&dummy_operator); + n2->ReplaceInput(0, n3); + + CHECK(n0->OwnedBy(n1)); + CHECK(!n1->OwnedBy(n0)); + CHECK(!n1->OwnedBy(n0)); + CHECK(!n1->OwnedBy(n2)); + CHECK(!n2->OwnedBy(n0)); + CHECK(!n2->OwnedBy(n1)); + CHECK(n3->OwnedBy(n2)); + CHECK(!n2->OwnedBy(n3)); + } +} + + +TEST(Uses) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + CHECK_EQ(1, n0->UseCount()); + printf("A: %d vs %d\n", n0->UseAt(0)->id(), n1->id()); + CHECK(n0->UseAt(0) == n1); + Node* n2 = graph.NewNode(&dummy_operator, n0); + CHECK_EQ(2, n0->UseCount()); + printf("B: %d vs %d\n", n0->UseAt(1)->id(), n2->id()); + CHECK(n0->UseAt(1) == n2); + Node* n3 = graph.NewNode(&dummy_operator, n0); + CHECK_EQ(3, n0->UseCount()); + CHECK(n0->UseAt(2) == n3); +} + + +TEST(Inputs) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); + CHECK_EQ(3, n3->InputCount()); + CHECK(n3->InputAt(0) == n0); + CHECK(n3->InputAt(1) == n1); + CHECK(n3->InputAt(2) == n2); + Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2); + n3->AppendInput(graph.zone(), n4); + CHECK_EQ(4, n3->InputCount()); + CHECK(n3->InputAt(0) == n0); + CHECK(n3->InputAt(1) == n1); + CHECK(n3->InputAt(2) == n2); + CHECK(n3->InputAt(3) == n4); + Node* n5 = graph.NewNode(&dummy_operator, n4); + n3->AppendInput(graph.zone(), n4); + CHECK_EQ(5, n3->InputCount()); + CHECK(n3->InputAt(0) == n0); + CHECK(n3->InputAt(1) == n1); + CHECK(n3->InputAt(2) == n2); + CHECK(n3->InputAt(3) == n4); + CHECK(n3->InputAt(4) == n4); + + // Make sure uses have been hooked op correctly. + Node::Uses uses(n4->uses()); + Node::Uses::iterator current = uses.begin(); + CHECK(current != uses.end()); + CHECK(*current == n3); + ++current; + CHECK(current != uses.end()); + CHECK(*current == n5); + ++current; + CHECK(current != uses.end()); + CHECK(*current == n3); + ++current; + CHECK(current == uses.end()); +} + + +TEST(AppendInputsAndIterator) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + + Node::Inputs inputs(n2->inputs()); + Node::Inputs::iterator current = inputs.begin(); + CHECK(current != inputs.end()); + CHECK(*current == n0); + ++current; + CHECK(current != inputs.end()); + CHECK(*current == n1); + ++current; + CHECK(current == inputs.end()); + + Node* n3 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n3); + inputs = n2->inputs(); + current = inputs.begin(); + CHECK(current != inputs.end()); + CHECK(*current == n0); + CHECK_EQ(0, current.index()); + ++current; + CHECK(current != inputs.end()); + CHECK(*current == n1); + CHECK_EQ(1, current.index()); + ++current; + CHECK(current != inputs.end()); + CHECK(*current == n3); + CHECK_EQ(2, current.index()); + ++current; + CHECK(current == inputs.end()); +} + + +TEST(NullInputsSimple) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + CHECK_EQ(2, n2->InputCount()); + + CHECK(n0 == n2->InputAt(0)); + CHECK(n1 == n2->InputAt(1)); + CHECK_EQ(2, n0->UseCount()); + n2->ReplaceInput(0, NULL); + CHECK(NULL == n2->InputAt(0)); + CHECK(n1 == n2->InputAt(1)); + CHECK_EQ(1, n0->UseCount()); +} + + +TEST(NullInputsAppended) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator, n0); + n3->AppendInput(graph.zone(), n1); + n3->AppendInput(graph.zone(), n2); + CHECK_EQ(3, n3->InputCount()); + + CHECK(n0 == n3->InputAt(0)); + CHECK(n1 == n3->InputAt(1)); + CHECK(n2 == n3->InputAt(2)); + CHECK_EQ(1, n1->UseCount()); + n3->ReplaceInput(1, NULL); + CHECK(n0 == n3->InputAt(0)); + CHECK(NULL == n3->InputAt(1)); + CHECK(n2 == n3->InputAt(2)); + CHECK_EQ(0, n1->UseCount()); +} + + +TEST(ReplaceUsesFromAppendedInputs) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n1); + n2->AppendInput(graph.zone(), n0); + CHECK_EQ(0, n3->UseCount()); + CHECK_EQ(3, n0->UseCount()); + n0->ReplaceUses(n3); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(3, n3->UseCount()); + + Node::Uses uses(n3->uses()); + Node::Uses::iterator current = uses.begin(); + CHECK(current != uses.end()); + CHECK(*current == n1); + ++current; + CHECK(current != uses.end()); + CHECK(*current == n2); + ++current; + CHECK(current != uses.end()); + CHECK(*current == n2); + ++current; + CHECK(current == uses.end()); +} + + +template <bool result> +struct FixedPredicate { + bool operator()(const Node* node) const { return result; } +}; + + +TEST(ReplaceUsesIfWithFixedPredicate) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0); + Node* n3 = graph.NewNode(&dummy_operator); + + CHECK_EQ(0, n2->UseCount()); + n2->ReplaceUsesIf(FixedPredicate<true>(), n1); + CHECK_EQ(0, n2->UseCount()); + n2->ReplaceUsesIf(FixedPredicate<false>(), n1); + CHECK_EQ(0, n2->UseCount()); + + CHECK_EQ(0, n3->UseCount()); + n3->ReplaceUsesIf(FixedPredicate<true>(), n1); + CHECK_EQ(0, n3->UseCount()); + n3->ReplaceUsesIf(FixedPredicate<false>(), n1); + CHECK_EQ(0, n3->UseCount()); + + CHECK_EQ(2, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + n0->ReplaceUsesIf(FixedPredicate<false>(), n1); + CHECK_EQ(2, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + n0->ReplaceUsesIf(FixedPredicate<true>(), n1); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(2, n1->UseCount()); + + n1->AppendInput(graph.zone(), n1); + CHECK_EQ(3, n1->UseCount()); + n1->AppendInput(graph.zone(), n3); + CHECK_EQ(1, n3->UseCount()); + n3->ReplaceUsesIf(FixedPredicate<true>(), n1); + CHECK_EQ(4, n1->UseCount()); + CHECK_EQ(0, n3->UseCount()); + n1->ReplaceUsesIf(FixedPredicate<false>(), n3); + CHECK_EQ(4, n1->UseCount()); + CHECK_EQ(0, n3->UseCount()); +} + + +TEST(ReplaceUsesIfWithEqualTo) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + + CHECK_EQ(0, n2->UseCount()); + n2->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n1), n0); + CHECK_EQ(0, n2->UseCount()); + + CHECK_EQ(2, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + n1->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n0), n0); + CHECK_EQ(2, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + n0->ReplaceUsesIf(std::bind2nd(std::equal_to<Node*>(), n2), n1); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(2, n1->UseCount()); +} + + +TEST(ReplaceInputMultipleUses) { + GraphTester graph; + + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->ReplaceInput(0, n1); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + + Node* n3 = graph.NewNode(&dummy_operator, n0); + n3->ReplaceInput(0, n1); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(2, n1->UseCount()); +} + + +TEST(TrimInputCountInline) { + GraphTester graph; + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + n1->TrimInputCount(1); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(n0, n1->InputAt(0)); + CHECK_EQ(1, n0->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + n1->TrimInputCount(0); + CHECK_EQ(0, n1->InputCount()); + CHECK_EQ(0, n0->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + n2->TrimInputCount(2); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n0); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0, n0); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } +} + + +TEST(TrimInputCountOutOfLine1) { + GraphTester graph; + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + n1->AppendInput(graph.zone(), n0); + n1->TrimInputCount(1); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(n0, n1->InputAt(0)); + CHECK_EQ(1, n0->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + n1->AppendInput(graph.zone(), n0); + CHECK_EQ(1, n1->InputCount()); + n1->TrimInputCount(0); + CHECK_EQ(0, n1->InputCount()); + CHECK_EQ(0, n0->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(2); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(n0, n2->InputAt(0)); + CHECK_EQ(n1, n2->InputAt(1)); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(n0, n2->InputAt(0)); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n0); + n2->AppendInput(graph.zone(), n0); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(2, n0->UseCount()); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n0); + n2->AppendInput(graph.zone(), n0); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(2, n0->UseCount()); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } +} + + +TEST(TrimInputCountOutOfLine2) { + GraphTester graph; + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(2); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(n0, n2->InputAt(0)); + CHECK_EQ(n1, n2->InputAt(1)); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(n0, n2->InputAt(0)); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n1); + CHECK_EQ(2, n2->InputCount()); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n0); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(2, n0->UseCount()); + n2->TrimInputCount(1); + CHECK_EQ(1, n2->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n0); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(2, n0->UseCount()); + n2->TrimInputCount(0); + CHECK_EQ(0, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n2->UseCount()); + } +} + + +TEST(RemoveAllInputs) { + GraphTester graph; + + for (int i = 0; i < 2; i++) { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + Node* n2; + if (i == 0) { + n2 = graph.NewNode(&dummy_operator, n0, n1); + } else { + n2 = graph.NewNode(&dummy_operator, n0); + n2->AppendInput(graph.zone(), n1); // with out-of-line input. + } + + n0->RemoveAllInputs(); + CHECK_EQ(0, n0->InputCount()); + + CHECK_EQ(2, n0->UseCount()); + n1->RemoveAllInputs(); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(1, n0->UseCount()); + CHECK_EQ(NULL, n1->InputAt(0)); + + CHECK_EQ(1, n1->UseCount()); + n2->RemoveAllInputs(); + CHECK_EQ(2, n2->InputCount()); + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(NULL, n2->InputAt(0)); + CHECK_EQ(NULL, n2->InputAt(1)); + } + + { + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator, n0); + n1->ReplaceInput(0, n1); // self-reference. + + CHECK_EQ(0, n0->UseCount()); + CHECK_EQ(1, n1->UseCount()); + n1->RemoveAllInputs(); + CHECK_EQ(1, n1->InputCount()); + CHECK_EQ(0, n1->UseCount()); + CHECK_EQ(NULL, n1->InputAt(0)); + } +} diff --git a/deps/v8/test/cctest/compiler/test-operator.cc b/deps/v8/test/cctest/compiler/test-operator.cc new file mode 100644 index 0000000000..0bf8cb755b --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-operator.cc @@ -0,0 +1,244 @@ +// Copyright 2013 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 "src/compiler/operator.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +#define NaN (v8::base::OS::nan_value()) +#define Infinity (std::numeric_limits<double>::infinity()) + +TEST(TestOperatorMnemonic) { + SimpleOperator op1(10, 0, 0, 0, "ThisOne"); + CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne")); + + SimpleOperator op2(11, 0, 0, 0, "ThatOne"); + CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne")); + + Operator1<int> op3(12, 0, 0, 1, "Mnemonic1", 12333); + CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1")); + + Operator1<double> op4(13, 0, 0, 1, "TheOther", 99.9); + CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther")); +} + + +TEST(TestSimpleOperatorHash) { + SimpleOperator op1(17, 0, 0, 0, "Another"); + CHECK_EQ(17, op1.HashCode()); + + SimpleOperator op2(18, 0, 0, 0, "Falsch"); + CHECK_EQ(18, op2.HashCode()); +} + + +TEST(TestSimpleOperatorEquals) { + SimpleOperator op1a(19, 0, 0, 0, "Another1"); + SimpleOperator op1b(19, 2, 2, 2, "Another2"); + + CHECK(op1a.Equals(&op1a)); + CHECK(op1a.Equals(&op1b)); + CHECK(op1b.Equals(&op1a)); + CHECK(op1b.Equals(&op1b)); + + SimpleOperator op2a(20, 0, 0, 0, "Falsch1"); + SimpleOperator op2b(20, 1, 1, 1, "Falsch2"); + + CHECK(op2a.Equals(&op2a)); + CHECK(op2a.Equals(&op2b)); + CHECK(op2b.Equals(&op2a)); + CHECK(op2b.Equals(&op2b)); + + CHECK(!op1a.Equals(&op2a)); + CHECK(!op1a.Equals(&op2b)); + CHECK(!op1b.Equals(&op2a)); + CHECK(!op1b.Equals(&op2b)); + + CHECK(!op2a.Equals(&op1a)); + CHECK(!op2a.Equals(&op1b)); + CHECK(!op2b.Equals(&op1a)); + CHECK(!op2b.Equals(&op1b)); +} + + +static SmartArrayPointer<const char> OperatorToString(Operator* op) { + OStringStream os; + os << *op; + return SmartArrayPointer<const char>(StrDup(os.c_str())); +} + + +TEST(TestSimpleOperatorPrint) { + SimpleOperator op1a(19, 0, 0, 0, "Another1"); + SimpleOperator op1b(19, 2, 2, 2, "Another2"); + + CHECK_EQ("Another1", OperatorToString(&op1a).get()); + CHECK_EQ("Another2", OperatorToString(&op1b).get()); + + SimpleOperator op2a(20, 0, 0, 0, "Flog1"); + SimpleOperator op2b(20, 1, 1, 1, "Flog2"); + + CHECK_EQ("Flog1", OperatorToString(&op2a).get()); + CHECK_EQ("Flog2", OperatorToString(&op2b).get()); +} + + +TEST(TestOperator1intHash) { + Operator1<int> op1a(23, 0, 0, 0, "Wolfie", 11); + Operator1<int> op1b(23, 2, 2, 2, "Doggie", 11); + + CHECK_EQ(op1a.HashCode(), op1b.HashCode()); + + Operator1<int> op2a(24, 0, 0, 0, "Arfie", 3); + Operator1<int> op2b(24, 0, 0, 0, "Arfie", 4); + + CHECK_NE(op1a.HashCode(), op2a.HashCode()); + CHECK_NE(op2a.HashCode(), op2b.HashCode()); +} + + +TEST(TestOperator1intEquals) { + Operator1<int> op1a(23, 0, 0, 0, "Scratchy", 11); + Operator1<int> op1b(23, 2, 2, 2, "Scratchy", 11); + + CHECK(op1a.Equals(&op1a)); + CHECK(op1a.Equals(&op1b)); + CHECK(op1b.Equals(&op1a)); + CHECK(op1b.Equals(&op1b)); + + Operator1<int> op2a(24, 0, 0, 0, "Im", 3); + Operator1<int> op2b(24, 0, 0, 0, "Im", 4); + + CHECK(op2a.Equals(&op2a)); + CHECK(!op2a.Equals(&op2b)); + CHECK(!op2b.Equals(&op2a)); + CHECK(op2b.Equals(&op2b)); + + CHECK(!op1a.Equals(&op2a)); + CHECK(!op1a.Equals(&op2b)); + CHECK(!op1b.Equals(&op2a)); + CHECK(!op1b.Equals(&op2b)); + + CHECK(!op2a.Equals(&op1a)); + CHECK(!op2a.Equals(&op1b)); + CHECK(!op2b.Equals(&op1a)); + CHECK(!op2b.Equals(&op1b)); + + SimpleOperator op3(25, 0, 0, 0, "Weepy"); + + CHECK(!op1a.Equals(&op3)); + CHECK(!op1b.Equals(&op3)); + CHECK(!op2a.Equals(&op3)); + CHECK(!op2b.Equals(&op3)); + + CHECK(!op3.Equals(&op1a)); + CHECK(!op3.Equals(&op1b)); + CHECK(!op3.Equals(&op2a)); + CHECK(!op3.Equals(&op2b)); +} + + +TEST(TestOperator1intPrint) { + Operator1<int> op1(12, 0, 0, 1, "Op1Test", 0); + CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get()); + + Operator1<int> op2(12, 0, 0, 1, "Op1Test", 66666666); + CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get()); + + Operator1<int> op3(12, 0, 0, 1, "FooBar", 2347); + CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get()); + + Operator1<int> op4(12, 0, 0, 1, "BarFoo", -879); + CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get()); +} + + +TEST(TestOperator1doubleHash) { + Operator1<double> op1a(23, 0, 0, 0, "Wolfie", 11.77); + Operator1<double> op1b(23, 2, 2, 2, "Doggie", 11.77); + + CHECK_EQ(op1a.HashCode(), op1b.HashCode()); + + Operator1<double> op2a(24, 0, 0, 0, "Arfie", -6.7); + Operator1<double> op2b(24, 0, 0, 0, "Arfie", -6.8); + + CHECK_NE(op1a.HashCode(), op2a.HashCode()); + CHECK_NE(op2a.HashCode(), op2b.HashCode()); +} + + +TEST(TestOperator1doubleEquals) { + Operator1<double> op1a(23, 0, 0, 0, "Scratchy", 11.77); + Operator1<double> op1b(23, 2, 2, 2, "Scratchy", 11.77); + + CHECK(op1a.Equals(&op1a)); + CHECK(op1a.Equals(&op1b)); + CHECK(op1b.Equals(&op1a)); + CHECK(op1b.Equals(&op1b)); + + Operator1<double> op2a(24, 0, 0, 0, "Im", 3.1); + Operator1<double> op2b(24, 0, 0, 0, "Im", 3.2); + + CHECK(op2a.Equals(&op2a)); + CHECK(!op2a.Equals(&op2b)); + CHECK(!op2b.Equals(&op2a)); + CHECK(op2b.Equals(&op2b)); + + CHECK(!op1a.Equals(&op2a)); + CHECK(!op1a.Equals(&op2b)); + CHECK(!op1b.Equals(&op2a)); + CHECK(!op1b.Equals(&op2b)); + + CHECK(!op2a.Equals(&op1a)); + CHECK(!op2a.Equals(&op1b)); + CHECK(!op2b.Equals(&op1a)); + CHECK(!op2b.Equals(&op1b)); + + SimpleOperator op3(25, 0, 0, 0, "Weepy"); + + CHECK(!op1a.Equals(&op3)); + CHECK(!op1b.Equals(&op3)); + CHECK(!op2a.Equals(&op3)); + CHECK(!op2b.Equals(&op3)); + + CHECK(!op3.Equals(&op1a)); + CHECK(!op3.Equals(&op1b)); + CHECK(!op3.Equals(&op2a)); + CHECK(!op3.Equals(&op2b)); + + Operator1<double> op4a(24, 0, 0, 0, "Bashful", NaN); + Operator1<double> op4b(24, 0, 0, 0, "Bashful", NaN); + + CHECK(op4a.Equals(&op4a)); + CHECK(op4a.Equals(&op4b)); + CHECK(op4b.Equals(&op4a)); + CHECK(op4b.Equals(&op4b)); + + CHECK(!op3.Equals(&op4a)); + CHECK(!op3.Equals(&op4b)); + CHECK(!op3.Equals(&op4a)); + CHECK(!op3.Equals(&op4b)); +} + + +TEST(TestOperator1doublePrint) { + Operator1<double> op1(12, 0, 0, 1, "Op1Test", 0); + CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get()); + + Operator1<double> op2(12, 0, 0, 1, "Op1Test", 7.3); + CHECK_EQ("Op1Test[7.3]", OperatorToString(&op2).get()); + + Operator1<double> op3(12, 0, 0, 1, "FooBar", 2e+123); + CHECK_EQ("FooBar[2e+123]", OperatorToString(&op3).get()); + + Operator1<double> op4(12, 0, 0, 1, "BarFoo", Infinity); + CHECK_EQ("BarFoo[inf]", OperatorToString(&op4).get()); + + Operator1<double> op5(12, 0, 0, 1, "BarFoo", NaN); + CHECK_EQ("BarFoo[nan]", OperatorToString(&op5).get()); +} diff --git a/deps/v8/test/cctest/compiler/test-phi-reducer.cc b/deps/v8/test/cctest/compiler/test-phi-reducer.cc new file mode 100644 index 0000000000..00e250d8a2 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-phi-reducer.cc @@ -0,0 +1,225 @@ +// 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/common-operator.h" +#include "src/compiler/graph-inl.h" +#include "src/compiler/phi-reducer.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +class PhiReducerTester : HandleAndZoneScope { + public: + explicit PhiReducerTester(int num_parameters = 0) + : isolate(main_isolate()), + common(main_zone()), + graph(main_zone()), + self(graph.NewNode(common.Start(num_parameters))), + dead(graph.NewNode(common.Dead())) { + graph.SetStart(self); + } + + Isolate* isolate; + CommonOperatorBuilder common; + Graph graph; + Node* self; + Node* dead; + + void CheckReduce(Node* expect, Node* phi) { + PhiReducer reducer; + Reduction reduction = reducer.Reduce(phi); + if (expect == phi) { + CHECK(!reduction.Changed()); + } else { + CHECK(reduction.Changed()); + CHECK_EQ(expect, reduction.replacement()); + } + } + + Node* Int32Constant(int32_t val) { + return graph.NewNode(common.Int32Constant(val)); + } + + Node* Float64Constant(double val) { + return graph.NewNode(common.Float64Constant(val)); + } + + Node* Parameter(int32_t index = 0) { + return graph.NewNode(common.Parameter(index), graph.start()); + } + + Node* Phi(Node* a) { + return SetSelfReferences(graph.NewNode(common.Phi(1), a)); + } + + Node* Phi(Node* a, Node* b) { + return SetSelfReferences(graph.NewNode(common.Phi(2), a, b)); + } + + Node* Phi(Node* a, Node* b, Node* c) { + return SetSelfReferences(graph.NewNode(common.Phi(3), a, b, c)); + } + + Node* Phi(Node* a, Node* b, Node* c, Node* d) { + return SetSelfReferences(graph.NewNode(common.Phi(4), a, b, c, d)); + } + + Node* PhiWithControl(Node* a, Node* control) { + return SetSelfReferences(graph.NewNode(common.Phi(1), a, control)); + } + + Node* PhiWithControl(Node* a, Node* b, Node* control) { + return SetSelfReferences(graph.NewNode(common.Phi(2), a, b, control)); + } + + Node* SetSelfReferences(Node* node) { + Node::Inputs inputs = node->inputs(); + for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); + ++iter) { + Node* input = *iter; + if (input == self) node->ReplaceInput(iter.index(), node); + } + return node; + } +}; + + +TEST(PhiReduce1) { + PhiReducerTester R; + Node* zero = R.Int32Constant(0); + Node* one = R.Int32Constant(1); + Node* oneish = R.Float64Constant(1.1); + Node* param = R.Parameter(); + + Node* singles[] = {zero, one, oneish, param}; + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + R.CheckReduce(singles[i], R.Phi(singles[i])); + } +} + + +TEST(PhiReduce2) { + PhiReducerTester R; + Node* zero = R.Int32Constant(0); + Node* one = R.Int32Constant(1); + Node* oneish = R.Float64Constant(1.1); + Node* param = R.Parameter(); + + Node* singles[] = {zero, one, oneish, param}; + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(a, a)); + } + + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(R.self, a)); + R.CheckReduce(a, R.Phi(a, R.self)); + } + + for (size_t i = 1; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i], *b = singles[0]; + Node* phi1 = R.Phi(b, a); + R.CheckReduce(phi1, phi1); + + Node* phi2 = R.Phi(a, b); + R.CheckReduce(phi2, phi2); + } +} + + +TEST(PhiReduce3) { + PhiReducerTester R; + Node* zero = R.Int32Constant(0); + Node* one = R.Int32Constant(1); + Node* oneish = R.Float64Constant(1.1); + Node* param = R.Parameter(); + + Node* singles[] = {zero, one, oneish, param}; + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(a, a, a)); + } + + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(R.self, a, a)); + R.CheckReduce(a, R.Phi(a, R.self, a)); + R.CheckReduce(a, R.Phi(a, a, R.self)); + } + + for (size_t i = 1; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i], *b = singles[0]; + Node* phi1 = R.Phi(b, a, a); + R.CheckReduce(phi1, phi1); + + Node* phi2 = R.Phi(a, b, a); + R.CheckReduce(phi2, phi2); + + Node* phi3 = R.Phi(a, a, b); + R.CheckReduce(phi3, phi3); + } +} + + +TEST(PhiReduce4) { + PhiReducerTester R; + Node* zero = R.Int32Constant(0); + Node* one = R.Int32Constant(1); + Node* oneish = R.Float64Constant(1.1); + Node* param = R.Parameter(); + + Node* singles[] = {zero, one, oneish, param}; + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(a, a, a, a)); + } + + for (size_t i = 0; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i]; + R.CheckReduce(a, R.Phi(R.self, a, a, a)); + R.CheckReduce(a, R.Phi(a, R.self, a, a)); + R.CheckReduce(a, R.Phi(a, a, R.self, a)); + R.CheckReduce(a, R.Phi(a, a, a, R.self)); + + R.CheckReduce(a, R.Phi(R.self, R.self, a, a)); + R.CheckReduce(a, R.Phi(a, R.self, R.self, a)); + R.CheckReduce(a, R.Phi(a, a, R.self, R.self)); + R.CheckReduce(a, R.Phi(R.self, a, a, R.self)); + } + + for (size_t i = 1; i < ARRAY_SIZE(singles); i++) { + Node* a = singles[i], *b = singles[0]; + Node* phi1 = R.Phi(b, a, a, a); + R.CheckReduce(phi1, phi1); + + Node* phi2 = R.Phi(a, b, a, a); + R.CheckReduce(phi2, phi2); + + Node* phi3 = R.Phi(a, a, b, a); + R.CheckReduce(phi3, phi3); + + Node* phi4 = R.Phi(a, a, a, b); + R.CheckReduce(phi4, phi4); + } +} + + +TEST(PhiReduceShouldIgnoreControlNodes) { + PhiReducerTester R; + Node* zero = R.Int32Constant(0); + Node* one = R.Int32Constant(1); + Node* oneish = R.Float64Constant(1.1); + Node* param = R.Parameter(); + + Node* singles[] = {zero, one, oneish, param}; + for (size_t i = 0; i < ARRAY_SIZE(singles); ++i) { + R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.dead)); + R.CheckReduce(singles[i], R.PhiWithControl(R.self, singles[i], R.dead)); + R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.self, R.dead)); + } +} diff --git a/deps/v8/test/cctest/compiler/test-pipeline.cc b/deps/v8/test/cctest/compiler/test-pipeline.cc new file mode 100644 index 0000000000..7efedeeea2 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-pipeline.cc @@ -0,0 +1,40 @@ +// Copyright 2013 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.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) { + InitializedHandleScope handles; + const char* source = "(function(a,b) { return a + b; })"; + Handle<JSFunction> function = v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast(CompileRun(source))); + CompilationInfoWithZone info(function); + + CHECK(Parser::Parse(&info)); + StrictMode strict_mode = info.function()->strict_mode(); + info.SetStrictMode(strict_mode); + CHECK(Rewriter::Rewrite(&info)); + CHECK(Scope::Analyze(&info)); + CHECK_NE(NULL, info.scope()); + + Pipeline pipeline(&info); +#if V8_TURBOFAN_TARGET + Handle<Code> code = pipeline.GenerateCode(); + CHECK(Pipeline::SupportedTarget()); + CHECK(!code.is_null()); +#else + USE(pipeline); +#endif +} diff --git a/deps/v8/test/cctest/compiler/test-representation-change.cc b/deps/v8/test/cctest/compiler/test-representation-change.cc new file mode 100644 index 0000000000..092a5f7d90 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-representation-change.cc @@ -0,0 +1,276 @@ +// 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 <limits> + +#include "src/v8.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/graph-builder-tester.h" + +#include "src/compiler/node-matchers.h" +#include "src/compiler/representation-change.h" +#include "src/compiler/typer.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +namespace v8 { // for friendiness. +namespace internal { +namespace compiler { + +class RepresentationChangerTester : public HandleAndZoneScope, + public GraphAndBuilders { + public: + explicit RepresentationChangerTester(int num_parameters = 0) + : GraphAndBuilders(main_zone()), + typer_(main_zone()), + jsgraph_(main_graph_, &main_common_, &typer_), + changer_(&jsgraph_, &main_simplified_, &main_machine_, main_isolate()) { + Node* s = graph()->NewNode(common()->Start(num_parameters)); + graph()->SetStart(s); + } + + Typer typer_; + JSGraph jsgraph_; + RepresentationChanger changer_; + + Isolate* isolate() { return main_isolate(); } + Graph* graph() { return main_graph_; } + CommonOperatorBuilder* common() { return &main_common_; } + JSGraph* jsgraph() { return &jsgraph_; } + RepresentationChanger* changer() { return &changer_; } + + // TODO(titzer): use ValueChecker / ValueUtil + void CheckInt32Constant(Node* n, int32_t expected) { + ValueMatcher<int32_t> m(n); + CHECK(m.HasValue()); + CHECK_EQ(expected, m.Value()); + } + + void CheckHeapConstant(Node* n, Object* expected) { + ValueMatcher<Handle<Object> > m(n); + CHECK(m.HasValue()); + CHECK_EQ(expected, *m.Value()); + } + + void CheckNumberConstant(Node* n, double expected) { + ValueMatcher<double> m(n); + CHECK_EQ(IrOpcode::kNumberConstant, n->opcode()); + CHECK(m.HasValue()); + CHECK_EQ(expected, m.Value()); + } + + Node* Parameter(int index = 0) { + return graph()->NewNode(common()->Parameter(index), graph()->start()); + } + + void CheckTypeError(RepTypeUnion from, RepTypeUnion to) { + changer()->testing_type_errors_ = true; + changer()->type_error_ = false; + Node* n = Parameter(0); + Node* c = changer()->GetRepresentationFor(n, from, to); + CHECK_EQ(n, c); + CHECK(changer()->type_error_); + } + + void CheckNop(RepTypeUnion from, RepTypeUnion to) { + Node* n = Parameter(0); + Node* c = changer()->GetRepresentationFor(n, from, to); + CHECK_EQ(n, c); + } +}; +} +} +} // namespace v8::internal::compiler + + +static const RepType all_reps[] = {rBit, rWord32, rWord64, rFloat64, rTagged}; + + +// TODO(titzer): lift this to ValueHelper +static const double double_inputs[] = { + 0.0, -0.0, 1.0, -1.0, 0.1, 1.4, -1.7, + 2, 5, 6, 982983, 888, -999.8, 3.1e7, + -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY}; + + +static const int32_t int32_inputs[] = { + 0, 1, -1, + 2, 5, 6, + 982983, 888, -999, + 65535, static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)}; + + +static const uint32_t uint32_inputs[] = { + 0, 1, static_cast<uint32_t>(-1), 2, 5, 6, + 982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000}; + + +TEST(BoolToBit_constant) { + RepresentationChangerTester r; + + Node* true_node = r.jsgraph()->TrueConstant(); + Node* true_bit = r.changer()->GetRepresentationFor(true_node, rTagged, rBit); + r.CheckInt32Constant(true_bit, 1); + + Node* false_node = r.jsgraph()->FalseConstant(); + Node* false_bit = + r.changer()->GetRepresentationFor(false_node, rTagged, rBit); + r.CheckInt32Constant(false_bit, 0); +} + + +TEST(BitToBool_constant) { + RepresentationChangerTester r; + + for (int i = -5; i < 5; i++) { + Node* node = r.jsgraph()->Int32Constant(i); + Node* val = r.changer()->GetRepresentationFor(node, rBit, rTagged); + r.CheckHeapConstant(val, i == 0 ? r.isolate()->heap()->false_value() + : r.isolate()->heap()->true_value()); + } +} + + +TEST(ToTagged_constant) { + RepresentationChangerTester r; + + for (size_t i = 0; i < ARRAY_SIZE(double_inputs); i++) { + Node* n = r.jsgraph()->Float64Constant(double_inputs[i]); + Node* c = r.changer()->GetRepresentationFor(n, rFloat64, rTagged); + r.CheckNumberConstant(c, double_inputs[i]); + } + + for (size_t i = 0; i < ARRAY_SIZE(int32_inputs); i++) { + Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]); + Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tInt32, rTagged); + r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i])); + } + + for (size_t i = 0; i < ARRAY_SIZE(uint32_inputs); i++) { + Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]); + Node* c = r.changer()->GetRepresentationFor(n, rWord32 | tUint32, rTagged); + r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i])); + } +} + + +static void CheckChange(IrOpcode::Value expected, RepTypeUnion from, + RepTypeUnion to) { + RepresentationChangerTester r; + + Node* n = r.Parameter(); + Node* c = r.changer()->GetRepresentationFor(n, from, to); + + CHECK_NE(c, n); + CHECK_EQ(expected, c->opcode()); + CHECK_EQ(n, c->InputAt(0)); +} + + +TEST(SingleChanges) { + CheckChange(IrOpcode::kChangeBoolToBit, rTagged, rBit); + CheckChange(IrOpcode::kChangeBitToBool, rBit, rTagged); + + CheckChange(IrOpcode::kChangeInt32ToTagged, rWord32 | tInt32, rTagged); + CheckChange(IrOpcode::kChangeUint32ToTagged, rWord32 | tUint32, rTagged); + CheckChange(IrOpcode::kChangeFloat64ToTagged, rFloat64, rTagged); + + CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged | tInt32, rWord32); + CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged | tUint32, rWord32); + CheckChange(IrOpcode::kChangeTaggedToFloat64, rTagged, rFloat64); + + // Int32,Uint32 <-> Float64 are actually machine conversions. + CheckChange(IrOpcode::kChangeInt32ToFloat64, rWord32 | tInt32, rFloat64); + CheckChange(IrOpcode::kChangeUint32ToFloat64, rWord32 | tUint32, rFloat64); + CheckChange(IrOpcode::kChangeFloat64ToInt32, rFloat64 | tInt32, rWord32); + CheckChange(IrOpcode::kChangeFloat64ToUint32, rFloat64 | tUint32, rWord32); +} + + +TEST(SignednessInWord32) { + RepresentationChangerTester r; + + // TODO(titzer): assume that uses of a word32 without a sign mean tInt32. + CheckChange(IrOpcode::kChangeTaggedToInt32, rTagged, rWord32 | tInt32); + CheckChange(IrOpcode::kChangeTaggedToUint32, rTagged, rWord32 | tUint32); + CheckChange(IrOpcode::kChangeInt32ToFloat64, rWord32, rFloat64); + CheckChange(IrOpcode::kChangeFloat64ToInt32, rFloat64, rWord32); +} + + +TEST(Nops) { + RepresentationChangerTester r; + + // X -> X is always a nop for any single representation X. + for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) { + r.CheckNop(all_reps[i], all_reps[i]); + } + + // 32-bit or 64-bit words can be used as branch conditions (rBit). + r.CheckNop(rWord32, rBit); + r.CheckNop(rWord32, rBit | tBool); + r.CheckNop(rWord64, rBit); + r.CheckNop(rWord64, rBit | tBool); + + // rBit (result of comparison) is implicitly a wordish thing. + r.CheckNop(rBit, rWord32); + r.CheckNop(rBit | tBool, rWord32); + r.CheckNop(rBit, rWord64); + r.CheckNop(rBit | tBool, rWord64); +} + + +TEST(TypeErrors) { + RepresentationChangerTester r; + + // Floats cannot be implicitly converted to/from comparison conditions. + r.CheckTypeError(rFloat64, rBit); + r.CheckTypeError(rFloat64, rBit | tBool); + r.CheckTypeError(rBit, rFloat64); + r.CheckTypeError(rBit | tBool, rFloat64); + + // Word64 is internal and shouldn't be implicitly converted. + r.CheckTypeError(rWord64, rTagged | tBool); + r.CheckTypeError(rWord64, rTagged); + r.CheckTypeError(rWord64, rTagged | tBool); + r.CheckTypeError(rTagged, rWord64); + r.CheckTypeError(rTagged | tBool, rWord64); + + // Word64 / Word32 shouldn't be implicitly converted. + r.CheckTypeError(rWord64, rWord32); + r.CheckTypeError(rWord32, rWord64); + r.CheckTypeError(rWord64, rWord32 | tInt32); + r.CheckTypeError(rWord32 | tInt32, rWord64); + r.CheckTypeError(rWord64, rWord32 | tUint32); + r.CheckTypeError(rWord32 | tUint32, rWord64); + + for (size_t i = 0; i < ARRAY_SIZE(all_reps); i++) { + for (size_t j = 0; j < ARRAY_SIZE(all_reps); j++) { + if (i == j) continue; + // Only a single from representation is allowed. + r.CheckTypeError(all_reps[i] | all_reps[j], rTagged); + } + } +} + + +TEST(CompleteMatrix) { + // TODO(titzer): test all variants in the matrix. + // rB + // tBrB + // tBrT + // rW32 + // tIrW32 + // tUrW32 + // rW64 + // tIrW64 + // tUrW64 + // rF64 + // tIrF64 + // tUrF64 + // tArF64 + // rT + // tArT +} diff --git a/deps/v8/test/cctest/compiler/test-run-deopt.cc b/deps/v8/test/cctest/compiler/test-run-deopt.cc new file mode 100644 index 0000000000..af173d6be6 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-deopt.cc @@ -0,0 +1,58 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +#if V8_TURBOFAN_TARGET + +TEST(TurboSimpleDeopt) { + 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; })"); + + T.CheckCall(T.Val(2), T.Val(1)); +} + + +TEST(TurboSimpleDeoptInExpr) { + 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; })"); + + T.CheckCall(T.Val(6), T.Val(3)); +} + +#endif + +TEST(TurboTrivialDeopt) { + FLAG_allow_natives_syntax = true; + FLAG_turbo_deoptimization = true; + + FunctionTester T( + "(function foo() {" + "%DeoptimizeFunction(foo);" + "return 1; })"); + + T.CheckCall(T.Val(1)); +} diff --git a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc new file mode 100644 index 0000000000..a1b5676186 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc @@ -0,0 +1,211 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + + +TEST(IsSmi) { + FunctionTester T("(function(a) { return %_IsSmi(a); })"); + + 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(IsNonNegativeSmi) { + FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })"); + + T.CheckTrue(T.Val(1)); + T.CheckFalse(T.Val(1.1)); + T.CheckFalse(T.Val(-0.0)); + T.CheckFalse(T.Val(-2)); + T.CheckFalse(T.Val(-2.3)); + T.CheckFalse(T.undefined()); +} + + +TEST(IsMinusZero) { + FunctionTester T("(function(a) { return %_IsMinusZero(a); })"); + + T.CheckFalse(T.Val(1)); + T.CheckFalse(T.Val(1.1)); + T.CheckTrue(T.Val(-0.0)); + T.CheckFalse(T.Val(-2)); + T.CheckFalse(T.Val(-2.3)); + T.CheckFalse(T.undefined()); +} + + +TEST(IsArray) { + FunctionTester T("(function(a) { return %_IsArray(a); })"); + + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckTrue(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(IsObject) { + FunctionTester T("(function(a) { return %_IsObject(a); })"); + + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckTrue(T.NewObject("([1])")); + T.CheckTrue(T.NewObject("({})")); + T.CheckTrue(T.NewObject("(/x/)")); + T.CheckFalse(T.undefined()); + T.CheckTrue(T.null()); + T.CheckFalse(T.Val("x")); + T.CheckFalse(T.Val(1)); +} + + +TEST(IsFunction) { + FunctionTester T("(function(a) { return %_IsFunction(a); })"); + + T.CheckTrue(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(IsRegExp) { + FunctionTester T("(function(a) { return %_IsRegExp(a); })"); + + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckFalse(T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})")); + T.CheckTrue(T.NewObject("(/x/)")); + T.CheckFalse(T.undefined()); + T.CheckFalse(T.null()); + T.CheckFalse(T.Val("x")); + T.CheckFalse(T.Val(1)); +} + + +TEST(ClassOf) { + FunctionTester T("(function(a) { return %_ClassOf(a); })"); + + T.CheckCall(T.Val("Function"), T.NewObject("(function() {})")); + T.CheckCall(T.Val("Array"), T.NewObject("([1])")); + T.CheckCall(T.Val("Object"), T.NewObject("({})")); + T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)")); + T.CheckCall(T.null(), T.undefined()); + T.CheckCall(T.null(), T.null()); + T.CheckCall(T.null(), T.Val("x")); + T.CheckCall(T.null(), T.Val(1)); +} + + +TEST(ObjectEquals) { + FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })"); + CompileRun("var o = {}"); + + T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)")); + T.CheckTrue(T.Val("internal"), T.Val("internal")); + T.CheckTrue(T.true_value(), T.true_value()); + T.CheckFalse(T.true_value(), T.false_value()); + T.CheckFalse(T.NewObject("({})"), T.NewObject("({})")); + T.CheckFalse(T.Val("a"), T.Val("b")); +} + + +TEST(ValueOf) { + FunctionTester T("(function(a) { return %_ValueOf(a); })"); + + T.CheckCall(T.Val("a"), T.Val("a")); + T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))")); + T.CheckCall(T.Val(123), T.Val(123)); + T.CheckCall(T.Val(456), T.NewObject("(new Number(456))")); +} + + +TEST(SetValueOf) { + FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })"); + + T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a")); + T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123)); + T.CheckCall(T.Val("x"), T.undefined(), T.Val("x")); +} + + +TEST(StringCharFromCode) { + FunctionTester T("(function(a) { return %_StringCharFromCode(a); })"); + + T.CheckCall(T.Val("a"), T.Val(97)); + T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A)); + T.CheckCall(T.Val(""), T.undefined()); +} + + +TEST(StringCharAt) { + FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })"); + + T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3)); + T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2)); + T.CheckCall(T.Val(""), T.Val("not a fan!"), T.Val(23)); +} + + +TEST(StringCharCodeAt) { + FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })"); + + T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3)); + T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2)); + T.CheckCall(T.nan(), T.Val("not a fan!"), T.Val(23)); +} + + +TEST(StringAdd) { + FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })"); + + T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb")); + T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val("")); + T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb")); +} + + +TEST(StringSubString) { + FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })"); + + T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0)); + T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2)); + T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(0.0)); +} + + +TEST(StringCompare) { + FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })"); + + T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb")); + T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb")); + T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb")); +} + + +TEST(CallFunction) { + FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })"); + CompileRun("function f(a,b,c) { return a + b + c + this.d; }"); + + T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f")); + T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f")); +} diff --git a/deps/v8/test/cctest/compiler/test-run-jsbranches.cc b/deps/v8/test/cctest/compiler/test-run-jsbranches.cc new file mode 100644 index 0000000000..2eb4fa6d0f --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-jsbranches.cc @@ -0,0 +1,262 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(Conditional) { + FunctionTester T("(function(a) { return a ? 23 : 42; })"); + + T.CheckCall(T.Val(23), T.true_value(), T.undefined()); + T.CheckCall(T.Val(42), T.false_value(), T.undefined()); + T.CheckCall(T.Val(42), T.undefined(), T.undefined()); + T.CheckCall(T.Val(42), T.Val(0.0), T.undefined()); + T.CheckCall(T.Val(23), T.Val(999), T.undefined()); + T.CheckCall(T.Val(23), T.Val("x"), T.undefined()); +} + + +TEST(LogicalAnd) { + FunctionTester T("(function(a,b) { return a && b; })"); + + T.CheckCall(T.true_value(), T.true_value(), T.true_value()); + T.CheckCall(T.false_value(), T.false_value(), T.true_value()); + T.CheckCall(T.false_value(), T.true_value(), T.false_value()); + T.CheckCall(T.false_value(), T.false_value(), T.false_value()); + + T.CheckCall(T.Val(999), T.Val(777), T.Val(999)); + T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(999)); + T.CheckCall(T.Val("b"), T.Val("a"), T.Val("b")); +} + + +TEST(LogicalOr) { + FunctionTester T("(function(a,b) { return a || b; })"); + + T.CheckCall(T.true_value(), T.true_value(), T.true_value()); + T.CheckCall(T.true_value(), T.false_value(), T.true_value()); + T.CheckCall(T.true_value(), T.true_value(), T.false_value()); + T.CheckCall(T.false_value(), T.false_value(), T.false_value()); + + T.CheckCall(T.Val(777), T.Val(777), T.Val(999)); + T.CheckCall(T.Val(999), T.Val(0.0), T.Val(999)); + T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b")); +} + + +TEST(LogicalEffect) { + FunctionTester T("(function(a,b) { a && (b = a); return b; })"); + + T.CheckCall(T.true_value(), T.true_value(), T.true_value()); + T.CheckCall(T.true_value(), T.false_value(), T.true_value()); + T.CheckCall(T.true_value(), T.true_value(), T.false_value()); + T.CheckCall(T.false_value(), T.false_value(), T.false_value()); + + T.CheckCall(T.Val(777), T.Val(777), T.Val(999)); + T.CheckCall(T.Val(999), T.Val(0.0), T.Val(999)); + T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b")); +} + + +TEST(IfStatement) { + FunctionTester T("(function(a) { if (a) { return 1; } else { return 2; } })"); + + T.CheckCall(T.Val(1), T.true_value(), T.undefined()); + T.CheckCall(T.Val(2), T.false_value(), T.undefined()); + T.CheckCall(T.Val(2), T.undefined(), T.undefined()); + T.CheckCall(T.Val(2), T.Val(0.0), T.undefined()); + T.CheckCall(T.Val(1), T.Val(999), T.undefined()); + T.CheckCall(T.Val(1), T.Val("x"), T.undefined()); +} + + +TEST(DoWhileStatement) { + FunctionTester T("(function(a,b) { do { a+=23; } while(a < b) return a; })"); + + T.CheckCall(T.Val(24), T.Val(1), T.Val(1)); + T.CheckCall(T.Val(24), T.Val(1), T.Val(23)); + T.CheckCall(T.Val(47), T.Val(1), T.Val(25)); + T.CheckCall(T.Val("str23"), T.Val("str"), T.Val("str")); +} + + +TEST(WhileStatement) { + FunctionTester T("(function(a,b) { while(a < b) { a+=23; } return a; })"); + + T.CheckCall(T.Val(1), T.Val(1), T.Val(1)); + T.CheckCall(T.Val(24), T.Val(1), T.Val(23)); + T.CheckCall(T.Val(47), T.Val(1), T.Val(25)); + T.CheckCall(T.Val("str"), T.Val("str"), T.Val("str")); +} + + +TEST(ForStatement) { + FunctionTester T("(function(a,b) { for (; a < b; a+=23) {} return a; })"); + + T.CheckCall(T.Val(1), T.Val(1), T.Val(1)); + T.CheckCall(T.Val(24), T.Val(1), T.Val(23)); + T.CheckCall(T.Val(47), T.Val(1), T.Val(25)); + T.CheckCall(T.Val("str"), T.Val("str"), T.Val("str")); +} + + +static void TestForIn(const char* code) { + FunctionTester T(code); + T.CheckCall(T.undefined(), T.undefined()); + T.CheckCall(T.undefined(), T.null()); + T.CheckCall(T.undefined(), T.NewObject("({})")); + T.CheckCall(T.undefined(), T.Val(1)); + T.CheckCall(T.Val("2"), T.Val("str")); + T.CheckCall(T.Val("a"), T.NewObject("({'a' : 1})")); + T.CheckCall(T.Val("2"), T.NewObject("([1, 2, 3])")); + T.CheckCall(T.Val("a"), T.NewObject("({'a' : 1, 'b' : 1})"), T.Val("b")); + T.CheckCall(T.Val("1"), T.NewObject("([1, 2, 3])"), T.Val("2")); +} + + +TEST(ForInStatement) { + // Variable assignment. + TestForIn( + "(function(a, b) {" + "var last;" + "for (var x in a) {" + " if (b) { delete a[b]; b = undefined; }" + " last = x;" + "}" + "return last;})"); + // Indexed assignment. + TestForIn( + "(function(a, b) {" + "var array = [0, 1, undefined];" + "for (array[2] in a) {" + " if (b) { delete a[b]; b = undefined; }" + "}" + "return array[2];})"); + // Named assignment. + TestForIn( + "(function(a, b) {" + "var obj = {'a' : undefined};" + "for (obj.a in a) {" + " if (b) { delete a[b]; b = undefined; }" + "}" + "return obj.a;})"); +} + + +TEST(SwitchStatement) { + const char* src = + "(function(a,b) {" + " var r = '-';" + " switch (a) {" + " case 'x' : r += 'X-';" + " case b + 'b': r += 'B-';" + " default : r += 'D-';" + " case 'y' : r += 'Y-';" + " }" + " return r;" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val("-X-B-D-Y-"), T.Val("x"), T.Val("B")); + T.CheckCall(T.Val("-B-D-Y-"), T.Val("Bb"), T.Val("B")); + T.CheckCall(T.Val("-D-Y-"), T.Val("z"), T.Val("B")); + T.CheckCall(T.Val("-Y-"), T.Val("y"), T.Val("B")); + + CompileRun("var c = 0; var o = { toString:function(){return c++} };"); + T.CheckCall(T.Val("-D-Y-"), T.Val("1b"), T.NewObject("o")); + T.CheckCall(T.Val("-B-D-Y-"), T.Val("1b"), T.NewObject("o")); + T.CheckCall(T.Val("-D-Y-"), T.Val("1b"), T.NewObject("o")); +} + + +TEST(BlockBreakStatement) { + FunctionTester T("(function(a,b) { L:{ if (a) break L; b=1; } return b; })"); + + T.CheckCall(T.Val(7), T.true_value(), T.Val(7)); + T.CheckCall(T.Val(1), T.false_value(), T.Val(7)); +} + + +TEST(BlockReturnStatement) { + FunctionTester T("(function(a,b) { L:{ if (a) b=1; return b; } })"); + + T.CheckCall(T.Val(1), T.true_value(), T.Val(7)); + T.CheckCall(T.Val(7), T.false_value(), T.Val(7)); +} + + +TEST(NestedIfConditional) { + FunctionTester T("(function(a,b) { if (a) { b = (b?b:7) + 1; } return b; })"); + + T.CheckCall(T.Val(4), T.false_value(), T.Val(4)); + T.CheckCall(T.Val(6), T.true_value(), T.Val(5)); + T.CheckCall(T.Val(8), T.true_value(), T.undefined()); +} + + +TEST(NestedIfLogical) { + const char* src = + "(function(a,b) {" + " if (a || b) { return 1; } else { return 2; }" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(1), T.true_value(), T.true_value()); + T.CheckCall(T.Val(1), T.false_value(), T.true_value()); + T.CheckCall(T.Val(1), T.true_value(), T.false_value()); + T.CheckCall(T.Val(2), T.false_value(), T.false_value()); + T.CheckCall(T.Val(1), T.Val(1.0), T.Val(1.0)); + T.CheckCall(T.Val(1), T.Val(0.0), T.Val(1.0)); + T.CheckCall(T.Val(1), T.Val(1.0), T.Val(0.0)); + T.CheckCall(T.Val(2), T.Val(0.0), T.Val(0.0)); +} + + +TEST(NestedIfElseFor) { + const char* src = + "(function(a,b) {" + " if (!a) { return b - 3; } else { for (; a < b; a++); }" + " return a;" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(1), T.false_value(), T.Val(4)); + T.CheckCall(T.Val(2), T.true_value(), T.Val(2)); + T.CheckCall(T.Val(3), T.Val(3), T.Val(1)); +} + + +TEST(NestedWhileWhile) { + const char* src = + "(function(a) {" + " var i = a; while (false) while(false) return i;" + " return i;" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(2.0), T.Val(2.0), T.Val(-1.0)); + T.CheckCall(T.Val(65.0), T.Val(65.0), T.Val(-1.0)); +} + + +TEST(NestedForIf) { + FunctionTester T("(function(a,b) { for (; a > 1; a--) if (b) return 1; })"); + + T.CheckCall(T.Val(1), T.Val(3), T.true_value()); + T.CheckCall(T.undefined(), T.Val(2), T.false_value()); + T.CheckCall(T.undefined(), T.Val(1), T.null()); +} + + +TEST(NestedForConditional) { + FunctionTester T("(function(a,b) { for (; a > 1; a--) return b ? 1 : 2; })"); + + T.CheckCall(T.Val(1), T.Val(3), T.true_value()); + T.CheckCall(T.Val(2), T.Val(2), T.false_value()); + T.CheckCall(T.undefined(), T.Val(1), T.null()); +} diff --git a/deps/v8/test/cctest/compiler/test-run-jscalls.cc b/deps/v8/test/cctest/compiler/test-run-jscalls.cc new file mode 100644 index 0000000000..2ad7e50467 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-jscalls.cc @@ -0,0 +1,235 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(SimpleCall) { + FunctionTester T("(function(foo,a) { return foo(a); })"); + Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })"); + + T.CheckCall(T.Val(3), foo, T.Val(3)); + T.CheckCall(T.Val(3.1), foo, T.Val(3.1)); + T.CheckCall(foo, foo, foo); + T.CheckCall(T.Val("Abba"), foo, T.Val("Abba")); +} + + +TEST(SimpleCall2) { + FunctionTester T("(function(foo,a) { return foo(a); })"); + Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })"); + T.Compile(foo); + + T.CheckCall(T.Val(3), foo, T.Val(3)); + T.CheckCall(T.Val(3.1), foo, T.Val(3.1)); + T.CheckCall(foo, foo, foo); + T.CheckCall(T.Val("Abba"), foo, T.Val("Abba")); +} + + +TEST(ConstCall) { + FunctionTester T("(function(foo,a) { return foo(a,3); })"); + Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })"); + T.Compile(foo); + + T.CheckCall(T.Val(6), foo, T.Val(3)); + T.CheckCall(T.Val(6.1), foo, T.Val(3.1)); + T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo); + T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba")); +} + + +TEST(ConstCall2) { + FunctionTester T("(function(foo,a) { return foo(a,\"3\"); })"); + Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })"); + T.Compile(foo); + + T.CheckCall(T.Val("33"), foo, T.Val(3)); + T.CheckCall(T.Val("3.13"), foo, T.Val(3.1)); + T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo); + T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba")); +} + + +TEST(PropertyNamedCall) { + FunctionTester T("(function(a,b) { return a.foo(b,23); })"); + CompileRun("function foo(y,z) { return this.x + y + z; }"); + + T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5)); + T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y")); + T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3)); +} + + +TEST(PropertyKeyedCall) { + FunctionTester T("(function(a,b) { var f = 'foo'; return a[f](b,23); })"); + CompileRun("function foo(y,z) { return this.x + y + z; }"); + + T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5)); + T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y")); + T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3)); +} + + +TEST(GlobalCall) { + FunctionTester T("(function(a,b) { return foo(a,b); })"); + CompileRun("function foo(a,b) { return a + b + this.c; }"); + CompileRun("var c = 23;"); + + T.CheckCall(T.Val(32), T.Val(4), T.Val(5)); + T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y")); + T.CheckCall(T.nan(), T.undefined(), T.Val(3)); +} + + +TEST(LookupCall) { + FunctionTester T("(function(a,b) { with (a) { return foo(a,b); } })"); + + CompileRun("function f1(a,b) { return a.val + b; }"); + T.CheckCall(T.Val(5), T.NewObject("({ foo:f1, val:2 })"), T.Val(3)); + T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f1, val:'x' })"), T.Val("y")); + + CompileRun("function f2(a,b) { return this.val + b; }"); + T.CheckCall(T.Val(9), T.NewObject("({ foo:f2, val:4 })"), T.Val(5)); + T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f2, val:'x' })"), T.Val("y")); +} + + +TEST(MismatchCallTooFew) { + FunctionTester T("(function(a,b) { return foo(a,b); })"); + CompileRun("function foo(a,b,c) { return a + b + c; }"); + + T.CheckCall(T.nan(), T.Val(23), T.Val(42)); + T.CheckCall(T.nan(), T.Val(4.2), T.Val(2.3)); + T.CheckCall(T.Val("abundefined"), T.Val("a"), T.Val("b")); +} + + +TEST(MismatchCallTooMany) { + FunctionTester T("(function(a,b) { return foo(a,b); })"); + CompileRun("function foo(a) { return a; }"); + + T.CheckCall(T.Val(23), T.Val(23), T.Val(42)); + T.CheckCall(T.Val(4.2), T.Val(4.2), T.Val(2.3)); + T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b")); +} + + +TEST(ConstructorCall) { + FunctionTester T("(function(a,b) { return new foo(a,b).value; })"); + CompileRun("function foo(a,b) { return { value: a + b + this.c }; }"); + CompileRun("foo.prototype.c = 23;"); + + T.CheckCall(T.Val(32), T.Val(4), T.Val(5)); + T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y")); + T.CheckCall(T.nan(), T.undefined(), T.Val(3)); +} + + +// TODO(titzer): factor these out into test-runtime-calls.cc +TEST(RuntimeCallCPP1) { + FLAG_allow_natives_syntax = true; + FunctionTester T("(function(a) { return %ToBool(a); })"); + + T.CheckCall(T.true_value(), T.Val(23), T.undefined()); + T.CheckCall(T.true_value(), T.Val(4.2), T.undefined()); + T.CheckCall(T.true_value(), T.Val("str"), T.undefined()); + T.CheckCall(T.true_value(), T.true_value(), T.undefined()); + T.CheckCall(T.false_value(), T.false_value(), T.undefined()); + T.CheckCall(T.false_value(), T.undefined(), T.undefined()); + T.CheckCall(T.false_value(), T.Val(0.0), T.undefined()); +} + + +TEST(RuntimeCallCPP2) { + FLAG_allow_natives_syntax = true; + FunctionTester T("(function(a,b) { return %NumberAdd(a, b); })"); + + T.CheckCall(T.Val(65), T.Val(42), T.Val(23)); + T.CheckCall(T.Val(19), T.Val(42), T.Val(-23)); + T.CheckCall(T.Val(6.5), T.Val(4.2), T.Val(2.3)); +} + + +TEST(RuntimeCallJS) { + FLAG_allow_natives_syntax = true; + FunctionTester T("(function(a) { return %ToString(a); })"); + + T.CheckCall(T.Val("23"), T.Val(23), T.undefined()); + T.CheckCall(T.Val("4.2"), T.Val(4.2), T.undefined()); + T.CheckCall(T.Val("str"), T.Val("str"), T.undefined()); + T.CheckCall(T.Val("true"), T.true_value(), T.undefined()); + T.CheckCall(T.Val("false"), T.false_value(), T.undefined()); + T.CheckCall(T.Val("undefined"), T.undefined(), T.undefined()); +} + + +TEST(RuntimeCallInline) { + FLAG_allow_natives_syntax = true; + FunctionTester T("(function(a) { return %_IsObject(a); })"); + + T.CheckCall(T.false_value(), T.Val(23), T.undefined()); + T.CheckCall(T.false_value(), T.Val(4.2), T.undefined()); + T.CheckCall(T.false_value(), T.Val("str"), T.undefined()); + T.CheckCall(T.false_value(), T.true_value(), T.undefined()); + T.CheckCall(T.false_value(), T.false_value(), T.undefined()); + T.CheckCall(T.false_value(), T.undefined(), T.undefined()); + T.CheckCall(T.true_value(), T.NewObject("({})"), T.undefined()); + T.CheckCall(T.true_value(), T.NewObject("([])"), T.undefined()); +} + + +TEST(RuntimeCallBooleanize) { + // TODO(turbofan): %Booleanize will disappear, don't hesitate to remove this + // test case, two-argument case is covered by the above test already. + FLAG_allow_natives_syntax = true; + FunctionTester T("(function(a,b) { return %Booleanize(a, b); })"); + + T.CheckCall(T.true_value(), T.Val(-1), T.Val(Token::LT)); + T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::EQ)); + T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::GT)); + + T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::LT)); + T.CheckCall(T.true_value(), T.Val(0.0), T.Val(Token::EQ)); + T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::GT)); + + T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::LT)); + T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::EQ)); + T.CheckCall(T.true_value(), T.Val(1), T.Val(Token::GT)); +} + + +TEST(EvalCall) { + FunctionTester T("(function(a,b) { return eval(a); })"); + Handle<JSObject> g(T.function->context()->global_object()->global_proxy()); + + T.CheckCall(T.Val(23), T.Val("17 + 6"), T.undefined()); + T.CheckCall(T.Val("'Y'; a"), T.Val("'Y'; a"), T.Val("b-val")); + T.CheckCall(T.Val("b-val"), T.Val("'Y'; b"), T.Val("b-val")); + T.CheckCall(g, T.Val("this"), T.undefined()); + T.CheckCall(g, T.Val("'use strict'; this"), T.undefined()); + + CompileRun("eval = function(x) { return x; }"); + T.CheckCall(T.Val("17 + 6"), T.Val("17 + 6"), T.undefined()); + + CompileRun("eval = function(x) { return this; }"); + T.CheckCall(g, T.Val("17 + 6"), T.undefined()); + + CompileRun("eval = function(x) { 'use strict'; return this; }"); + T.CheckCall(T.undefined(), T.Val("17 + 6"), T.undefined()); +} + + +TEST(ReceiverPatching) { + // TODO(turbofan): Note that this test only checks that the function prologue + // patches an undefined receiver to the global receiver. If this starts to + // fail once we fix the calling protocol, just remove this test. + FunctionTester T("(function(a) { return this; })"); + Handle<JSObject> g(T.function->context()->global_object()->global_proxy()); + T.CheckCall(g, T.undefined()); +} diff --git a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc new file mode 100644 index 0000000000..0712ab6205 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc @@ -0,0 +1,45 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(Throw) { + FunctionTester T("(function(a,b) { if (a) { throw b; } else { return b; }})"); + + T.CheckThrows(T.true_value(), T.NewObject("new Error")); + T.CheckCall(T.Val(23), T.false_value(), T.Val(23)); +} + + +TEST(ThrowSourcePosition) { + static const char* src = + "(function(a, b) { \n" + " if (a == 1) throw 1; \n" + " if (a == 2) {throw 2} \n" + " if (a == 3) {0;throw 3}\n" + " throw 4; \n" + "}) "; + FunctionTester T(src); + v8::Handle<v8::Message> message; + + message = T.CheckThrowsReturnMessage(T.Val(1), T.undefined()); + CHECK(!message.IsEmpty()); + CHECK_EQ(2, message->GetLineNumber()); + CHECK_EQ(40, message->GetStartPosition()); + + message = T.CheckThrowsReturnMessage(T.Val(2), T.undefined()); + CHECK(!message.IsEmpty()); + CHECK_EQ(3, message->GetLineNumber()); + CHECK_EQ(67, message->GetStartPosition()); + + message = T.CheckThrowsReturnMessage(T.Val(3), T.undefined()); + CHECK(!message.IsEmpty()); + CHECK_EQ(4, message->GetLineNumber()); + CHECK_EQ(95, message->GetStartPosition()); +} diff --git a/deps/v8/test/cctest/compiler/test-run-jsops.cc b/deps/v8/test/cctest/compiler/test-run-jsops.cc new file mode 100644 index 0000000000..eb39760ff7 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-jsops.cc @@ -0,0 +1,524 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +TEST(BinopAdd) { + FunctionTester T("(function(a,b) { return a + b; })"); + + T.CheckCall(3, 1, 2); + T.CheckCall(-11, -2, -9); + T.CheckCall(-11, -1.5, -9.5); + T.CheckCall(T.Val("AB"), T.Val("A"), T.Val("B")); + T.CheckCall(T.Val("A11"), T.Val("A"), T.Val(11)); + T.CheckCall(T.Val("12B"), T.Val(12), T.Val("B")); + T.CheckCall(T.Val("38"), T.Val("3"), T.Val("8")); + T.CheckCall(T.Val("31"), T.Val("3"), T.NewObject("([1])")); + T.CheckCall(T.Val("3[object Object]"), T.Val("3"), T.NewObject("({})")); +} + + +TEST(BinopSubtract) { + FunctionTester T("(function(a,b) { return a - b; })"); + + T.CheckCall(3, 4, 1); + T.CheckCall(3.0, 4.5, 1.5); + T.CheckCall(T.Val(-9), T.Val("0"), T.Val(9)); + T.CheckCall(T.Val(-9), T.Val(0.0), T.Val("9")); + T.CheckCall(T.Val(1), T.Val("3"), T.Val("2")); + T.CheckCall(T.nan(), T.Val("3"), T.Val("B")); + T.CheckCall(T.Val(2), T.Val("3"), T.NewObject("([1])")); + T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})")); +} + + +TEST(BinopMultiply) { + FunctionTester T("(function(a,b) { return a * b; })"); + + T.CheckCall(6, 3, 2); + T.CheckCall(4.5, 2.0, 2.25); + T.CheckCall(T.Val(6), T.Val("3"), T.Val(2)); + T.CheckCall(T.Val(4.5), T.Val(2.0), T.Val("2.25")); + T.CheckCall(T.Val(6), T.Val("3"), T.Val("2")); + T.CheckCall(T.nan(), T.Val("3"), T.Val("B")); + T.CheckCall(T.Val(3), T.Val("3"), T.NewObject("([1])")); + T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})")); +} + + +TEST(BinopDivide) { + FunctionTester T("(function(a,b) { return a / b; })"); + + T.CheckCall(2, 8, 4); + T.CheckCall(2.1, 8.4, 4); + T.CheckCall(V8_INFINITY, 8, 0); + T.CheckCall(-V8_INFINITY, -8, 0); + T.CheckCall(T.infinity(), T.Val(8), T.Val("0")); + T.CheckCall(T.minus_infinity(), T.Val("-8"), T.Val(0.0)); + T.CheckCall(T.Val(1.5), T.Val("3"), T.Val("2")); + T.CheckCall(T.nan(), T.Val("3"), T.Val("B")); + T.CheckCall(T.Val(1.5), T.Val("3"), T.NewObject("([2])")); + T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})")); +} + + +TEST(BinopModulus) { + FunctionTester T("(function(a,b) { return a % b; })"); + + T.CheckCall(3, 8, 5); + T.CheckCall(T.Val(3), T.Val("8"), T.Val(5)); + T.CheckCall(T.Val(3), T.Val(8), T.Val("5")); + T.CheckCall(T.Val(1), T.Val("3"), T.Val("2")); + T.CheckCall(T.nan(), T.Val("3"), T.Val("B")); + T.CheckCall(T.Val(1), T.Val("3"), T.NewObject("([2])")); + T.CheckCall(T.nan(), T.Val("3"), T.NewObject("({})")); +} + + +TEST(BinopShiftLeft) { + FunctionTester T("(function(a,b) { return a << b; })"); + + T.CheckCall(4, 2, 1); + T.CheckCall(T.Val(4), T.Val("2"), T.Val(1)); + T.CheckCall(T.Val(4), T.Val(2), T.Val("1")); +} + + +TEST(BinopShiftRight) { + FunctionTester T("(function(a,b) { return a >> b; })"); + + T.CheckCall(4, 8, 1); + T.CheckCall(-4, -8, 1); + T.CheckCall(T.Val(4), T.Val("8"), T.Val(1)); + T.CheckCall(T.Val(4), T.Val(8), T.Val("1")); +} + + +TEST(BinopShiftRightLogical) { + FunctionTester T("(function(a,b) { return a >>> b; })"); + + T.CheckCall(4, 8, 1); + T.CheckCall(0x7ffffffc, -8, 1); + T.CheckCall(T.Val(4), T.Val("8"), T.Val(1)); + T.CheckCall(T.Val(4), T.Val(8), T.Val("1")); +} + + +TEST(BinopAnd) { + FunctionTester T("(function(a,b) { return a & b; })"); + + T.CheckCall(7, 7, 15); + T.CheckCall(7, 15, 7); + T.CheckCall(T.Val(7), T.Val("15"), T.Val(7)); + T.CheckCall(T.Val(7), T.Val(15), T.Val("7")); +} + + +TEST(BinopOr) { + FunctionTester T("(function(a,b) { return a | b; })"); + + T.CheckCall(6, 4, 2); + T.CheckCall(6, 2, 4); + T.CheckCall(T.Val(6), T.Val("2"), T.Val(4)); + T.CheckCall(T.Val(6), T.Val(2), T.Val("4")); +} + + +TEST(BinopXor) { + FunctionTester T("(function(a,b) { return a ^ b; })"); + + T.CheckCall(7, 15, 8); + T.CheckCall(7, 8, 15); + T.CheckCall(T.Val(7), T.Val("8"), T.Val(15)); + T.CheckCall(T.Val(7), T.Val(8), T.Val("15")); +} + + +TEST(BinopStrictEqual) { + FunctionTester T("(function(a,b) { return a === b; })"); + + T.CheckTrue(7, 7); + T.CheckFalse(7, 8); + T.CheckTrue(7.1, 7.1); + T.CheckFalse(7.1, 8.1); + + T.CheckTrue(T.Val("7.1"), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("7.1")); + T.CheckFalse(T.Val(7), T.undefined()); + T.CheckFalse(T.undefined(), T.Val(7)); + + CompileRun("var o = { desc : 'I am a singleton' }"); + T.CheckFalse(T.NewObject("([1])"), T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})"), T.NewObject("({})")); + T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)")); +} + + +TEST(BinopEqual) { + FunctionTester T("(function(a,b) { return a == b; })"); + + T.CheckTrue(7, 7); + T.CheckFalse(7, 8); + T.CheckTrue(7.1, 7.1); + T.CheckFalse(7.1, 8.1); + + T.CheckTrue(T.Val("7.1"), T.Val("7.1")); + T.CheckTrue(T.Val(7.1), T.Val("7.1")); + + CompileRun("var o = { desc : 'I am a singleton' }"); + T.CheckFalse(T.NewObject("([1])"), T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})"), T.NewObject("({})")); + T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)")); +} + + +TEST(BinopNotEqual) { + FunctionTester T("(function(a,b) { return a != b; })"); + + T.CheckFalse(7, 7); + T.CheckTrue(7, 8); + T.CheckFalse(7.1, 7.1); + T.CheckTrue(7.1, 8.1); + + T.CheckFalse(T.Val("7.1"), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("7.1")); + + CompileRun("var o = { desc : 'I am a singleton' }"); + T.CheckTrue(T.NewObject("([1])"), T.NewObject("([1])")); + T.CheckTrue(T.NewObject("({})"), T.NewObject("({})")); + T.CheckFalse(T.NewObject("(o)"), T.NewObject("(o)")); +} + + +TEST(BinopLessThan) { + FunctionTester T("(function(a,b) { return a < b; })"); + + T.CheckTrue(7, 8); + T.CheckFalse(8, 7); + T.CheckTrue(-8.1, -8); + T.CheckFalse(-8, -8.1); + T.CheckFalse(0.111, 0.111); + + T.CheckFalse(T.Val("7.1"), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("6.1")); + T.CheckFalse(T.Val(7.1), T.Val("7.1")); + T.CheckTrue(T.Val(7.1), T.Val("8.1")); +} + + +TEST(BinopLessThanEqual) { + FunctionTester T("(function(a,b) { return a <= b; })"); + + T.CheckTrue(7, 8); + T.CheckFalse(8, 7); + T.CheckTrue(-8.1, -8); + T.CheckFalse(-8, -8.1); + T.CheckTrue(0.111, 0.111); + + T.CheckTrue(T.Val("7.1"), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("6.1")); + T.CheckTrue(T.Val(7.1), T.Val("7.1")); + T.CheckTrue(T.Val(7.1), T.Val("8.1")); +} + + +TEST(BinopGreaterThan) { + FunctionTester T("(function(a,b) { return a > b; })"); + + T.CheckFalse(7, 8); + T.CheckTrue(8, 7); + T.CheckFalse(-8.1, -8); + T.CheckTrue(-8, -8.1); + T.CheckFalse(0.111, 0.111); + + T.CheckFalse(T.Val("7.1"), T.Val("7.1")); + T.CheckTrue(T.Val(7.1), T.Val("6.1")); + T.CheckFalse(T.Val(7.1), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("8.1")); +} + + +TEST(BinopGreaterThanOrEqual) { + FunctionTester T("(function(a,b) { return a >= b; })"); + + T.CheckFalse(7, 8); + T.CheckTrue(8, 7); + T.CheckFalse(-8.1, -8); + T.CheckTrue(-8, -8.1); + T.CheckTrue(0.111, 0.111); + + T.CheckTrue(T.Val("7.1"), T.Val("7.1")); + T.CheckTrue(T.Val(7.1), T.Val("6.1")); + T.CheckTrue(T.Val(7.1), T.Val("7.1")); + T.CheckFalse(T.Val(7.1), T.Val("8.1")); +} + + +TEST(BinopIn) { + FunctionTester T("(function(a,b) { return a in b; })"); + + T.CheckTrue(T.Val("x"), T.NewObject("({x:23})")); + T.CheckFalse(T.Val("y"), T.NewObject("({x:42})")); + T.CheckFalse(T.Val(123), T.NewObject("({x:65})")); + T.CheckTrue(T.Val(1), T.NewObject("([1,2,3])")); +} + + +TEST(BinopInstanceOf) { + FunctionTester T("(function(a,b) { return a instanceof b; })"); + + T.CheckTrue(T.NewObject("(new Number(23))"), T.NewObject("Number")); + T.CheckFalse(T.NewObject("(new Number(23))"), T.NewObject("String")); + T.CheckFalse(T.NewObject("(new String('a'))"), T.NewObject("Number")); + T.CheckTrue(T.NewObject("(new String('b'))"), T.NewObject("String")); + T.CheckFalse(T.Val(1), T.NewObject("Number")); + T.CheckFalse(T.Val("abc"), T.NewObject("String")); + + CompileRun("var bound = (function() {}).bind(undefined)"); + T.CheckTrue(T.NewObject("(new bound())"), T.NewObject("bound")); + T.CheckTrue(T.NewObject("(new bound())"), T.NewObject("Object")); + T.CheckFalse(T.NewObject("(new bound())"), T.NewObject("Number")); +} + + +TEST(UnopNot) { + FunctionTester T("(function(a) { return !a; })"); + + T.CheckCall(T.true_value(), T.false_value(), T.undefined()); + T.CheckCall(T.false_value(), T.true_value(), T.undefined()); + T.CheckCall(T.true_value(), T.Val(0.0), T.undefined()); + T.CheckCall(T.false_value(), T.Val(123), T.undefined()); + T.CheckCall(T.false_value(), T.Val("x"), T.undefined()); + T.CheckCall(T.true_value(), T.undefined(), T.undefined()); + T.CheckCall(T.true_value(), T.nan(), T.undefined()); +} + + +TEST(UnopCountPost) { + FunctionTester T("(function(a) { return a++; })"); + + T.CheckCall(T.Val(0.0), T.Val(0.0), T.undefined()); + T.CheckCall(T.Val(2.3), T.Val(2.3), T.undefined()); + T.CheckCall(T.Val(123), T.Val(123), T.undefined()); + T.CheckCall(T.Val(7), T.Val("7"), T.undefined()); + T.CheckCall(T.nan(), T.Val("x"), T.undefined()); + T.CheckCall(T.nan(), T.undefined(), T.undefined()); + T.CheckCall(T.Val(1.0), T.true_value(), T.undefined()); + T.CheckCall(T.Val(0.0), T.false_value(), T.undefined()); + T.CheckCall(T.nan(), T.nan(), T.undefined()); +} + + +TEST(UnopCountPre) { + FunctionTester T("(function(a) { return ++a; })"); + + T.CheckCall(T.Val(1.0), T.Val(0.0), T.undefined()); + T.CheckCall(T.Val(3.3), T.Val(2.3), T.undefined()); + T.CheckCall(T.Val(124), T.Val(123), T.undefined()); + T.CheckCall(T.Val(8), T.Val("7"), T.undefined()); + T.CheckCall(T.nan(), T.Val("x"), T.undefined()); + T.CheckCall(T.nan(), T.undefined(), T.undefined()); + T.CheckCall(T.Val(2.0), T.true_value(), T.undefined()); + T.CheckCall(T.Val(1.0), T.false_value(), T.undefined()); + T.CheckCall(T.nan(), T.nan(), T.undefined()); +} + + +TEST(PropertyNamedLoad) { + FunctionTester T("(function(a,b) { return a.x; })"); + + T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.undefined()); + T.CheckCall(T.undefined(), T.NewObject("({y:23})"), T.undefined()); +} + + +TEST(PropertyKeyedLoad) { + FunctionTester T("(function(a,b) { return a[b]; })"); + + T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.Val("x")); + T.CheckCall(T.Val(42), T.NewObject("([23,42,65])"), T.Val(1)); + T.CheckCall(T.undefined(), T.NewObject("({x:23})"), T.Val("y")); + T.CheckCall(T.undefined(), T.NewObject("([23,42,65])"), T.Val(4)); +} + + +TEST(PropertyNamedStore) { + FunctionTester T("(function(a) { a.x = 7; return a.x; })"); + + T.CheckCall(T.Val(7), T.NewObject("({})"), T.undefined()); + T.CheckCall(T.Val(7), T.NewObject("({x:23})"), T.undefined()); +} + + +TEST(PropertyKeyedStore) { + FunctionTester T("(function(a,b) { a[b] = 7; return a.x; })"); + + T.CheckCall(T.Val(7), T.NewObject("({})"), T.Val("x")); + T.CheckCall(T.Val(7), T.NewObject("({x:23})"), T.Val("x")); + T.CheckCall(T.Val(9), T.NewObject("({x:9})"), T.Val("y")); +} + + +TEST(PropertyNamedDelete) { + FunctionTester T("(function(a) { return delete a.x; })"); + + CompileRun("var o = Object.create({}, { x: { value:23 } });"); + T.CheckTrue(T.NewObject("({x:42})"), T.undefined()); + T.CheckTrue(T.NewObject("({})"), T.undefined()); + T.CheckFalse(T.NewObject("(o)"), T.undefined()); +} + + +TEST(PropertyKeyedDelete) { + FunctionTester T("(function(a, b) { return delete a[b]; })"); + + CompileRun("function getX() { return 'x'; }"); + CompileRun("var o = Object.create({}, { x: { value:23 } });"); + T.CheckTrue(T.NewObject("({x:42})"), T.Val("x")); + T.CheckFalse(T.NewObject("(o)"), T.Val("x")); + T.CheckFalse(T.NewObject("(o)"), T.NewObject("({toString:getX})")); +} + + +TEST(GlobalLoad) { + FunctionTester T("(function() { return g; })"); + + T.CheckThrows(T.undefined(), T.undefined()); + CompileRun("var g = 23;"); + T.CheckCall(T.Val(23)); +} + + +TEST(GlobalStoreSloppy) { + FunctionTester T("(function(a,b) { g = a + b; return g; })"); + + T.CheckCall(T.Val(33), T.Val(22), T.Val(11)); + CompileRun("delete g"); + CompileRun("const g = 23"); + T.CheckCall(T.Val(23), T.Val(55), T.Val(44)); +} + + +TEST(GlobalStoreStrict) { + FunctionTester T("(function(a,b) { 'use strict'; g = a + b; return g; })"); + + T.CheckThrows(T.Val(22), T.Val(11)); + CompileRun("var g = 'a global variable';"); + T.CheckCall(T.Val(33), T.Val(22), T.Val(11)); +} + + +TEST(ContextLoad) { + FunctionTester T("(function(a,b) { (function(){a}); return a + b; })"); + + T.CheckCall(T.Val(65), T.Val(23), T.Val(42)); + T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b")); +} + + +TEST(ContextStore) { + FunctionTester T("(function(a,b) { (function(){x}); var x = a; return x; })"); + + T.CheckCall(T.Val(23), T.Val(23), T.undefined()); + T.CheckCall(T.Val("a"), T.Val("a"), T.undefined()); +} + + +TEST(LookupLoad) { + FunctionTester T("(function(a,b) { with(a) { return x + b; } })"); + + T.CheckCall(T.Val(24), T.NewObject("({x:23})"), T.Val(1)); + T.CheckCall(T.Val(32), T.NewObject("({x:23, b:9})"), T.Val(2)); + T.CheckCall(T.Val(45), T.NewObject("({__proto__:{x:42}})"), T.Val(3)); + T.CheckCall(T.Val(69), T.NewObject("({get x() { return 65; }})"), T.Val(4)); +} + + +TEST(LookupStore) { + FunctionTester T("(function(a,b) { var x; with(a) { x = b; } return x; })"); + + T.CheckCall(T.undefined(), T.NewObject("({x:23})"), T.Val(1)); + T.CheckCall(T.Val(2), T.NewObject("({y:23})"), T.Val(2)); + T.CheckCall(T.Val(23), T.NewObject("({b:23})"), T.Val(3)); + T.CheckCall(T.undefined(), T.NewObject("({__proto__:{x:42}})"), T.Val(4)); +} + + +TEST(BlockLoadStore) { + FLAG_harmony_scoping = true; + FunctionTester T("(function(a) { 'use strict'; { let x = a+a; return x; }})"); + + T.CheckCall(T.Val(46), T.Val(23)); + T.CheckCall(T.Val("aa"), T.Val("a")); +} + + +TEST(BlockLoadStoreNested) { + FLAG_harmony_scoping = true; + const char* src = + "(function(a,b) {" + "'use strict';" + "{ let x = a, y = a;" + " { let y = b;" + " return x + y;" + " }" + "}})"; + FunctionTester T(src); + + T.CheckCall(T.Val(65), T.Val(23), T.Val(42)); + T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b")); +} + + +TEST(ObjectLiteralComputed) { + FunctionTester T("(function(a,b) { o = { x:a+b }; return o.x; })"); + + T.CheckCall(T.Val(65), T.Val(23), T.Val(42)); + T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b")); +} + + +TEST(ObjectLiteralNonString) { + FunctionTester T("(function(a,b) { o = { 7:a+b }; return o[7]; })"); + + T.CheckCall(T.Val(65), T.Val(23), T.Val(42)); + T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b")); +} + + +TEST(ObjectLiteralPrototype) { + FunctionTester T("(function(a) { o = { __proto__:a }; return o.x; })"); + + T.CheckCall(T.Val(23), T.NewObject("({x:23})"), T.undefined()); + T.CheckCall(T.undefined(), T.NewObject("({y:42})"), T.undefined()); +} + + +TEST(ObjectLiteralGetter) { + FunctionTester T("(function(a) { o = { get x() {return a} }; return o.x; })"); + + T.CheckCall(T.Val(23), T.Val(23), T.undefined()); + T.CheckCall(T.Val("x"), T.Val("x"), T.undefined()); +} + + +TEST(ArrayLiteral) { + FunctionTester T("(function(a,b) { o = [1, a + b, 3]; return o[1]; })"); + + T.CheckCall(T.Val(65), T.Val(23), T.Val(42)); + T.CheckCall(T.Val("ab"), T.Val("a"), T.Val("b")); +} + + +TEST(RegExpLiteral) { + FunctionTester T("(function(a) { o = /b/; return o.test(a); })"); + + T.CheckTrue(T.Val("abc")); + T.CheckFalse(T.Val("xyz")); +} diff --git a/deps/v8/test/cctest/compiler/test-run-machops.cc b/deps/v8/test/cctest/compiler/test-run-machops.cc new file mode 100644 index 0000000000..6786f38741 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-machops.cc @@ -0,0 +1,4077 @@ +// 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 <functional> +#include <limits> + +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/value-helper.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal; +using namespace v8::internal::compiler; + +typedef RawMachineAssembler::Label MLabel; + +TEST(RunInt32Add) { + RawMachineAssemblerTester<int32_t> m; + Node* add = m.Int32Add(m.Int32Constant(0), m.Int32Constant(1)); + m.Return(add); + CHECK_EQ(1, m.Call()); +} + + +static Node* Int32Input(RawMachineAssemblerTester<int32_t>* m, int index) { + switch (index) { + case 0: + return m->Parameter(0); + case 1: + return m->Parameter(1); + case 2: + return m->Int32Constant(0); + case 3: + return m->Int32Constant(1); + case 4: + return m->Int32Constant(-1); + case 5: + return m->Int32Constant(0xff); + case 6: + return m->Int32Constant(0x01234567); + case 7: + return m->Load(kMachineWord32, m->PointerConstant(NULL)); + default: + return NULL; + } +} + + +TEST(CodeGenInt32Binop) { + RawMachineAssemblerTester<void> m; + + Operator* ops[] = { + m.machine()->Word32And(), m.machine()->Word32Or(), + m.machine()->Word32Xor(), m.machine()->Word32Shl(), + m.machine()->Word32Shr(), m.machine()->Word32Sar(), + m.machine()->Word32Equal(), m.machine()->Int32Add(), + m.machine()->Int32Sub(), m.machine()->Int32Mul(), + m.machine()->Int32Div(), m.machine()->Int32UDiv(), + m.machine()->Int32Mod(), m.machine()->Int32UMod(), + m.machine()->Int32LessThan(), m.machine()->Int32LessThanOrEqual(), + m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(), + NULL}; + + for (int i = 0; ops[i] != NULL; i++) { + for (int j = 0; j < 8; j++) { + for (int k = 0; k < 8; k++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* a = Int32Input(&m, j); + Node* b = Int32Input(&m, k); + m.Return(m.NewNode(ops[i], a, b)); + m.GenerateCode(); + } + } + } +} + + +TEST(RunGoto) { + RawMachineAssemblerTester<int32_t> m; + int constant = 99999; + + MLabel next; + m.Goto(&next); + m.Bind(&next); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunGotoMultiple) { + RawMachineAssemblerTester<int32_t> m; + int constant = 9999977; + + MLabel labels[10]; + for (size_t i = 0; i < ARRAY_SIZE(labels); i++) { + m.Goto(&labels[i]); + m.Bind(&labels[i]); + } + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunBranch) { + RawMachineAssemblerTester<int32_t> m; + int constant = 999777; + + MLabel blocka, blockb; + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(0 - constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunRedundantBranch1) { + RawMachineAssemblerTester<int32_t> m; + int constant = 944777; + + MLabel blocka; + m.Branch(m.Int32Constant(0), &blocka, &blocka); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunRedundantBranch2) { + RawMachineAssemblerTester<int32_t> m; + int constant = 955777; + + MLabel blocka, blockb; + m.Branch(m.Int32Constant(0), &blocka, &blocka); + m.Bind(&blockb); + m.Goto(&blocka); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunRedundantBranch3) { + RawMachineAssemblerTester<int32_t> m; + int constant = 966777; + + MLabel blocka, blockb, blockc; + m.Branch(m.Int32Constant(0), &blocka, &blockc); + m.Bind(&blocka); + m.Branch(m.Int32Constant(0), &blockb, &blockb); + m.Bind(&blockc); + m.Goto(&blockb); + m.Bind(&blockb); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunDiamond2) { + RawMachineAssemblerTester<int32_t> m; + + int constant = 995666; + + MLabel blocka, blockb, end; + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&end); + m.Bind(&blockb); + m.Goto(&end); + m.Bind(&end); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunLoop) { + RawMachineAssemblerTester<int32_t> m; + int constant = 999555; + + MLabel header, body, exit; + m.Goto(&header); + m.Bind(&header); + m.Branch(m.Int32Constant(0), &body, &exit); + m.Bind(&body); + m.Goto(&header); + m.Bind(&exit); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call()); +} + + +template <typename R> +static void BuildDiamondPhi(RawMachineAssemblerTester<R>* m, Node* cond_node, + Node* true_node, Node* false_node) { + MLabel blocka, blockb; + MLabel* end = m->Exit(); + m->Branch(cond_node, &blocka, &blockb); + m->Bind(&blocka); + m->Goto(end); + m->Bind(&blockb); + m->Goto(end); + + m->Bind(end); + Node* phi = m->Phi(true_node, false_node); + m->Return(phi); +} + + +TEST(RunDiamondPhiConst) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + int false_val = 0xFF666; + int true_val = 0x00DDD; + Node* true_node = m.Int32Constant(true_val); + Node* false_node = m.Int32Constant(false_val); + BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node); + CHECK_EQ(false_val, m.Call(0)); + CHECK_EQ(true_val, m.Call(1)); +} + + +TEST(RunDiamondPhiNumber) { + RawMachineAssemblerTester<Object*> m(kMachineWord32); + double false_val = -11.1; + double true_val = 200.1; + Node* true_node = m.NumberConstant(true_val); + Node* false_node = m.NumberConstant(false_val); + BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node); + m.CheckNumber(false_val, m.Call(0)); + m.CheckNumber(true_val, m.Call(1)); +} + + +TEST(RunDiamondPhiString) { + RawMachineAssemblerTester<Object*> m(kMachineWord32); + const char* false_val = "false"; + const char* true_val = "true"; + Node* true_node = m.StringConstant(true_val); + Node* false_node = m.StringConstant(false_val); + BuildDiamondPhi(&m, m.Parameter(0), true_node, false_node); + m.CheckString(false_val, m.Call(0)); + m.CheckString(true_val, m.Call(1)); +} + + +TEST(RunDiamondPhiParam) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + BuildDiamondPhi(&m, m.Parameter(0), m.Parameter(1), m.Parameter(2)); + int32_t c1 = 0x260cb75a; + int32_t c2 = 0xcd3e9c8b; + int result = m.Call(0, c1, c2); + CHECK_EQ(c2, result); + result = m.Call(1, c1, c2); + CHECK_EQ(c1, result); +} + + +TEST(RunLoopPhiConst) { + RawMachineAssemblerTester<int32_t> m; + int true_val = 0x44000; + int false_val = 0x00888; + + Node* cond_node = m.Int32Constant(0); + Node* true_node = m.Int32Constant(true_val); + Node* false_node = m.Int32Constant(false_val); + + // x = false_val; while(false) { x = true_val; } return x; + MLabel body, header; + MLabel* end = m.Exit(); + + m.Goto(&header); + m.Bind(&header); + Node* phi = m.Phi(false_node, true_node); + m.Branch(cond_node, &body, end); + m.Bind(&body); + m.Goto(&header); + m.Bind(end); + m.Return(phi); + + CHECK_EQ(false_val, m.Call()); +} + + +TEST(RunLoopPhiParam) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + + MLabel blocka, blockb; + MLabel* end = m.Exit(); + + m.Goto(&blocka); + + m.Bind(&blocka); + Node* phi = m.Phi(m.Parameter(1), m.Parameter(2)); + Node* cond = m.Phi(m.Parameter(0), m.Int32Constant(0)); + m.Branch(cond, &blockb, end); + + m.Bind(&blockb); + m.Goto(&blocka); + + m.Bind(end); + m.Return(phi); + + int32_t c1 = 0xa81903b4; + int32_t c2 = 0x5a1207da; + int result = m.Call(0, c1, c2); + CHECK_EQ(c1, result); + result = m.Call(1, c1, c2); + CHECK_EQ(c2, result); +} + + +TEST(RunLoopPhiInduction) { + RawMachineAssemblerTester<int32_t> m; + + int false_val = 0x10777; + + // x = false_val; while(false) { x++; } return x; + MLabel header, body; + MLabel* end = m.Exit(); + Node* false_node = m.Int32Constant(false_val); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(false_node, false_node); + 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.Return(phi); + + CHECK_EQ(false_val, m.Call()); +} + + +TEST(RunLoopIncrement) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + // x = 0; while(x ^ param) { x++; } return x; + MLabel header, body; + MLabel* end = m.Exit(); + Node* zero = m.Int32Constant(0); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(zero, zero); + 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); + bt.AddReturn(phi); + + CHECK_EQ(11, bt.call(11, 0)); + CHECK_EQ(110, bt.call(110, 0)); + CHECK_EQ(176, bt.call(176, 0)); +} + + +TEST(RunLoopIncrement2) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + // x = 0; while(x < param) { x++; } return x; + MLabel header, body; + MLabel* end = m.Exit(); + Node* zero = m.Int32Constant(0); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(zero, zero); + 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); + bt.AddReturn(phi); + + CHECK_EQ(11, bt.call(11, 0)); + CHECK_EQ(110, bt.call(110, 0)); + CHECK_EQ(176, bt.call(176, 0)); + CHECK_EQ(0, bt.call(-200, 0)); +} + + +TEST(RunLoopIncrement3) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + // x = 0; while(x < param) { x++; } return x; + MLabel header, body; + MLabel* end = m.Exit(); + Node* zero = m.Int32Constant(0); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(zero, zero); + 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); + bt.AddReturn(phi); + + CHECK_EQ(11, bt.call(11, 0)); + CHECK_EQ(110, bt.call(110, 0)); + CHECK_EQ(176, bt.call(176, 0)); + CHECK_EQ(200, bt.call(200, 0)); +} + + +TEST(RunLoopDecrement) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + // x = param; while(x) { x--; } return x; + MLabel header, body; + MLabel* end = m.Exit(); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(bt.param0, m.Int32Constant(0)); + m.Branch(phi, &body, end); + + m.Bind(&body); + phi->ReplaceInput(1, m.Int32Sub(phi, m.Int32Constant(1))); + m.Goto(&header); + + m.Bind(end); + bt.AddReturn(phi); + + CHECK_EQ(0, bt.call(11, 0)); + CHECK_EQ(0, bt.call(110, 0)); + CHECK_EQ(0, bt.call(197, 0)); +} + + +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(); + Node* minus_3 = m.Float64Constant(-3.0); + Node* ten = m.Float64Constant(10.0); + + m.Goto(&header); + + m.Bind(&header); + Node* phi = m.Phi(minus_3, ten); + 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.Return(m.ChangeFloat64ToInt32(phi)); + + CHECK_EQ(10, m.Call()); +} + + +TEST(RunLoadInt32) { + RawMachineAssemblerTester<int32_t> m; + + int32_t p1 = 0; // loads directly from this location. + m.Return(m.LoadFromPointer(&p1, kMachineWord32)); + + FOR_INT32_INPUTS(i) { + p1 = *i; + CHECK_EQ(p1, m.Call()); + } +} + + +TEST(RunLoadInt32Offset) { + int32_t p1 = 0; // loads directly from this location. + + int32_t offsets[] = {-2000000, -100, -101, 1, 3, + 7, 120, 2000, 2000000000, 0xff}; + + for (size_t i = 0; i < ARRAY_SIZE(offsets); i++) { + RawMachineAssemblerTester<int32_t> m; + int32_t offset = offsets[i]; + byte* pointer = reinterpret_cast<byte*>(&p1) - offset; + // generate load [#base + #index] + m.Return(m.LoadFromPointer(pointer, kMachineWord32, offset)); + + FOR_INT32_INPUTS(j) { + p1 = *j; + CHECK_EQ(p1, m.Call()); + } + } +} + + +TEST(RunLoadStoreFloat64Offset) { + double p1 = 0; // loads directly from this location. + double p2 = 0; // and stores directly into this location. + + FOR_INT32_INPUTS(i) { + int32_t magic = 0x2342aabb + *i * 3; + RawMachineAssemblerTester<int32_t> m; + int32_t offset = *i; + byte* from = reinterpret_cast<byte*>(&p1) - offset; + byte* to = reinterpret_cast<byte*>(&p2) - offset; + // generate load [#base + #index] + Node* load = m.Load(kMachineFloat64, m.PointerConstant(from), + m.Int32Constant(offset)); + m.Store(kMachineFloat64, m.PointerConstant(to), m.Int32Constant(offset), + load); + m.Return(m.Int32Constant(magic)); + + FOR_FLOAT64_INPUTS(j) { + p1 = *j; + p2 = *j - 5; + CHECK_EQ(magic, m.Call()); + CHECK_EQ(p1, p2); + } + } +} + + +TEST(RunInt32AddP) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + bt.AddReturn(m.Int32Add(bt.param0, bt.param1)); + + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + // Use uint32_t because signed overflow is UB in C. + int expected = static_cast<int32_t>(*i + *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } +} + + +TEST(RunInt32AddAndWord32SarP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Parameter(0), + m.Word32Sar(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i + (*j >> shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Word32Sar(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i >> shift) + *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32AddAndWord32ShlP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Parameter(0), + m.Word32Shl(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i + (*j << shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Word32Shl(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i << shift) + *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32AddAndWord32ShrP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Parameter(0), + m.Word32Shr(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i + (*j >> shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Add(m.Word32Shr(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i >> shift) + *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32AddInBranch) { + static const int32_t constant = 987654321; + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32NotEqual(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Int32Add(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), + m.Parameter(2))), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = ((*i + right) == 0) ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunInt32AddInComparison) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Add(bt.param0, bt.param1), m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Constant(0), m.Int32Add(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Int32Add(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i + *j) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Int32Add(m.Parameter(0), m.Int32Constant(*i)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*j + *i) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal( + m.Int32Add(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), m.Parameter(2))), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = (*i + right) == 0; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunInt32SubP) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + + m.Return(m.Int32Sub(bt.param0, bt.param1)); + + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + // Use uint32_t because signed overflow is UB in C. + int expected = static_cast<int32_t>(*i - *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } +} + + +TEST(RunInt32SubImm) { + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0))); + FOR_UINT32_INPUTS(j) { + // Use uint32_t because signed overflow is UB in C. + int32_t expected = static_cast<int32_t>(*i - *j); + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i))); + FOR_UINT32_INPUTS(j) { + // Use uint32_t because signed overflow is UB in C. + int32_t expected = static_cast<int32_t>(*j - *i); + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunInt32SubAndWord32SarP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), + m.Word32Sar(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i - (*j >> shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Word32Sar(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i >> shift) - *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32SubAndWord32ShlP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), + m.Word32Shl(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i - (*j << shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Word32Shl(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i << shift) - *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32SubAndWord32ShrP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Parameter(0), + m.Word32Shr(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = *i - (*j >> shift); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Int32Sub(m.Word32Shr(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + // Use uint32_t because signed overflow is UB in C. + int32_t expected = (*i >> shift) - *k; + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunInt32SubInBranch) { + static const int constant = 987654321; + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32NotEqual(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Int32Sub(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), + m.Parameter(2))), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = ((*i - right) == 0) ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunInt32SubInComparison) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Sub(bt.param0, bt.param1), m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Constant(0), m.Int32Sub(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Int32Sub(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i - *j) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Int32Sub(m.Parameter(0), m.Int32Constant(*i)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*j - *i) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal( + m.Int32Sub(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), m.Parameter(2))), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = (*i - right) == 0; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunInt32MulP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Mul(bt.param0, bt.param1)); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int expected = static_cast<int32_t>(*i * *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Mul(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int expected = static_cast<int32_t>(*i * *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunInt32MulImm) { + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Int32Mul(m.Int32Constant(*i), m.Parameter(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = static_cast<int32_t>(*i * *j); + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant(*i))); + FOR_UINT32_INPUTS(j) { + int32_t expected = static_cast<int32_t>(*j * *i); + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunInt32MulAndInt32AddP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + int32_t p0 = *i; + int32_t p1 = *j; + int32_t p2 = *k; + int expected = p0 + static_cast<int32_t>(p1 * p2); + CHECK_EQ(expected, m.Call(p0, p1, p2)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Add(m.Int32Mul(m.Parameter(0), m.Parameter(1)), m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + int32_t p0 = *i; + int32_t p1 = *j; + int32_t p2 = *k; + int expected = static_cast<int32_t>(p0 * p1) + p2; + CHECK_EQ(expected, m.Call(p0, p1, p2)); + } + } + } + } + { + FOR_INT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Int32Add(m.Int32Constant(*i), m.Int32Mul(bt.param0, bt.param1))); + FOR_INT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + int32_t p0 = *j; + int32_t p1 = *k; + int expected = *i + static_cast<int32_t>(p0 * p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunInt32MulAndInt32SubP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return( + m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + uint32_t p0 = *i; + int32_t p1 = *j; + int32_t p2 = *k; + // Use uint32_t because signed overflow is UB in C. + int expected = p0 - static_cast<uint32_t>(p1 * p2); + CHECK_EQ(expected, m.Call(p0, p1, p2)); + } + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Int32Sub(m.Int32Constant(*i), m.Int32Mul(bt.param0, bt.param1))); + FOR_INT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + int32_t p0 = *j; + int32_t p1 = *k; + // Use uint32_t because signed overflow is UB in C. + int expected = *i - static_cast<uint32_t>(p0 * p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunInt32DivP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Div(bt.param0, bt.param1)); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int p0 = *i; + int p1 = *j; + if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) { + int expected = static_cast<int32_t>(p0 / p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Add(bt.param0, m.Int32Div(bt.param0, bt.param1))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int p0 = *i; + int p1 = *j; + if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) { + int expected = static_cast<int32_t>(p0 + (p0 / p1)); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunInt32UDivP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32UDiv(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t p0 = *i; + uint32_t p1 = *j; + if (p1 != 0) { + uint32_t expected = static_cast<uint32_t>(p0 / p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Add(bt.param0, m.Int32UDiv(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t p0 = *i; + uint32_t p1 = *j; + if (p1 != 0) { + uint32_t expected = static_cast<uint32_t>(p0 + (p0 / p1)); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunInt32ModP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Mod(bt.param0, bt.param1)); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int p0 = *i; + int p1 = *j; + if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) { + int expected = static_cast<int32_t>(p0 % p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Add(bt.param0, m.Int32Mod(bt.param0, bt.param1))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int p0 = *i; + int p1 = *j; + if (p1 != 0 && (static_cast<uint32_t>(p0) != 0x80000000 || p1 != -1)) { + int expected = static_cast<int32_t>(p0 + (p0 % p1)); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunInt32UModP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32UMod(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t p0 = *i; + uint32_t p1 = *j; + if (p1 != 0) { + uint32_t expected = static_cast<uint32_t>(p0 % p1); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Int32Add(bt.param0, m.Int32UMod(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t p0 = *i; + uint32_t p1 = *j; + if (p1 != 0) { + uint32_t expected = static_cast<uint32_t>(p0 + (p0 % p1)); + CHECK_EQ(expected, bt.call(p0, p1)); + } + } + } + } +} + + +TEST(RunWord32AndP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32And(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i & *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32And(bt.param0, m.Word32Not(bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i & ~(*j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32And(m.Word32Not(bt.param0), bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = ~(*i) & *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunWord32AndAndWord32ShlP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Shl(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i << (*j & 0x1f); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Shl(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i << (0x1f & *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunWord32AndAndWord32ShrP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Shr(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i >> (*j & 0x1f); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Shr(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i >> (0x1f & *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunWord32AndAndWord32SarP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Sar(bt.param0, m.Word32And(bt.param1, m.Int32Constant(0x1f)))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i >> (*j & 0x1f); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Sar(bt.param0, m.Word32And(m.Int32Constant(0x1f), bt.param1))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i >> (0x1f & *j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunWord32AndImm) { + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32And(m.Int32Constant(*i), m.Parameter(0))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i & *j; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32And(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i & ~(*j); + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunWord32AndInBranch) { + static const int constant = 987654321; + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32And(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Word32And(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32And(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), + m.Parameter(2))), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = ((*i & right) == 0) ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunWord32AndInComparison) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Word32And(bt.param0, bt.param1), m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Constant(0), m.Word32And(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Word32And(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i & *j) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Word32And(m.Parameter(0), m.Int32Constant(*i)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*j & *i) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunWord32OrP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Or(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i | *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Or(bt.param0, m.Word32Not(bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i | ~(*j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Or(m.Word32Not(bt.param0), bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = ~(*i) | *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } +} + + +TEST(RunWord32OrImm) { + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Or(m.Int32Constant(*i), m.Parameter(0))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i | *j; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Or(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i | ~(*j); + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunWord32OrInBranch) { + static const int constant = 987654321; + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32NotEqual(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32Or(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), + m.Parameter(2))), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = ((*i | right) == 0) ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunWord32OrInComparison) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Word32Or(bt.param0, bt.param1), m.Int32Constant(0))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn( + m.Word32Equal(m.Int32Constant(0), m.Word32Or(bt.param0, bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) == 0; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Word32Or(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i | *j) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Equal(m.Word32Or(m.Parameter(0), m.Int32Constant(*i)), + m.Int32Constant(0))); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*j | *i) == 0; + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunWord32XorP) { + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i ^ *j; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Xor(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i ^ *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Xor(bt.param0, m.Word32Not(bt.param1))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i ^ ~(*j); + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Xor(m.Word32Not(bt.param0), bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t expected = ~(*i) ^ *j; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Xor(m.Int32Constant(*i), m.Word32Not(m.Parameter(0)))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *i ^ ~(*j); + CHECK_EQ(expected, m.Call(*j)); + } + } + } +} + + +TEST(RunWord32XorInBranch) { + static const int constant = 987654321; + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32Equal(m.Word32Xor(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Word32Xor(bt.param0, bt.param1), m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + bt.AddReturn(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i ^ *j) == 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + FOR_UINT32_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + MLabel blocka, blockb; + m.Branch( + m.Word32NotEqual(m.Word32Xor(m.Int32Constant(*i), m.Parameter(0)), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(j) { + int32_t expected = (*i ^ *j) != 0 ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<void> m; + Operator* shops[] = {m.machine()->Word32Sar(), m.machine()->Word32Shl(), + m.machine()->Word32Shr()}; + for (size_t n = 0; n < ARRAY_SIZE(shops); n++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + MLabel blocka, blockb; + m.Branch(m.Word32Equal(m.Word32Xor(m.Parameter(0), + m.NewNode(shops[n], m.Parameter(1), + m.Parameter(2))), + m.Int32Constant(0)), + &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(constant)); + m.Bind(&blockb); + m.Return(m.Int32Constant(0 - constant)); + FOR_UINT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t right; + switch (shops[n]->opcode()) { + default: + UNREACHABLE(); + case IrOpcode::kWord32Sar: + right = *j >> shift; + break; + case IrOpcode::kWord32Shl: + right = *j << shift; + break; + case IrOpcode::kWord32Shr: + right = static_cast<uint32_t>(*j) >> shift; + break; + } + int32_t expected = ((*i ^ right) == 0) ? constant : 0 - constant; + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + } +} + + +TEST(RunWord32ShlP) { + { + FOR_UINT32_INPUTS(i) { + uint32_t shift = *i & 0x1F; + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Shl(m.Parameter(0), m.Int32Constant(shift))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *j << shift; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Shl(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t shift = *j & 0x1F; + uint32_t expected = *i << shift; + CHECK_EQ(expected, bt.call(*i, shift)); + } + } + } +} + + +TEST(RunWord32ShrP) { + { + FOR_UINT32_INPUTS(i) { + uint32_t shift = *i & 0x1F; + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Shr(m.Parameter(0), m.Int32Constant(shift))); + FOR_UINT32_INPUTS(j) { + uint32_t expected = *j >> shift; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Shr(bt.param0, bt.param1)); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + uint32_t shift = *j & 0x1F; + uint32_t expected = *i >> shift; + CHECK_EQ(expected, bt.call(*i, shift)); + } + } + CHECK_EQ(0x00010000, bt.call(0x80000000, 15)); + } +} + + +TEST(RunWord32SarP) { + { + FOR_INT32_INPUTS(i) { + int32_t shift = *i & 0x1F; + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Sar(m.Parameter(0), m.Int32Constant(shift))); + FOR_INT32_INPUTS(j) { + int32_t expected = *j >> shift; + CHECK_EQ(expected, m.Call(*j)); + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Sar(bt.param0, bt.param1)); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t shift = *j & 0x1F; + int32_t expected = *i >> shift; + CHECK_EQ(expected, bt.call(*i, shift)); + } + } + CHECK_EQ(0xFFFF0000, bt.call(0x80000000, 15)); + } +} + + +TEST(RunWord32NotP) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Word32Not(m.Parameter(0))); + FOR_UINT32_INPUTS(i) { + int expected = ~(*i); + CHECK_EQ(expected, m.Call(*i)); + } +} + + +TEST(RunInt32NegP) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + m.Return(m.Int32Neg(m.Parameter(0))); + FOR_INT32_INPUTS(i) { + int expected = -*i; + CHECK_EQ(expected, m.Call(*i)); + } +} + + +TEST(RunWord32EqualAndWord32SarP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), + m.Word32Sar(m.Parameter(1), m.Parameter(2)))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t expected = (*i == (*j >> shift)); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Word32Sar(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_INT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_INT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + int32_t expected = ((*i >> shift) == *k); + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunWord32EqualAndWord32ShlP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), + m.Word32Shl(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t expected = (*i == (*j << shift)); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Word32Shl(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + int32_t expected = ((*i << shift) == *k); + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunWord32EqualAndWord32ShrP) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Parameter(0), + m.Word32Shr(m.Parameter(1), m.Parameter(2)))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *k & 0x1F; + int32_t expected = (*i == (*j >> shift)); + CHECK_EQ(expected, m.Call(*i, *j, shift)); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32, + kMachineWord32); + m.Return(m.Word32Equal(m.Word32Shr(m.Parameter(0), m.Parameter(1)), + m.Parameter(2))); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + FOR_UINT32_INPUTS(k) { + uint32_t shift = *j & 0x1F; + int32_t expected = ((*i >> shift) == *k); + CHECK_EQ(expected, m.Call(*i, shift, *k)); + } + } + } + } +} + + +TEST(RunDeadNodes) { + for (int i = 0; true; i++) { + RawMachineAssemblerTester<int32_t> m(i == 5 ? kMachineWord32 + : kMachineLast); + int constant = 0x55 + i; + switch (i) { + case 0: + m.Int32Constant(44); + break; + case 1: + m.StringConstant("unused"); + break; + case 2: + m.NumberConstant(11.1); + break; + case 3: + m.PointerConstant(&constant); + break; + case 4: + m.LoadFromPointer(&constant, kMachineWord32); + break; + case 5: + m.Parameter(0); + break; + default: + return; + } + m.Return(m.Int32Constant(constant)); + if (i != 5) { + CHECK_EQ(constant, m.Call()); + } else { + CHECK_EQ(constant, m.Call(0)); + } + } +} + + +TEST(RunDeadInt32Binops) { + RawMachineAssemblerTester<int32_t> m; + + Operator* ops[] = { + m.machine()->Word32And(), m.machine()->Word32Or(), + m.machine()->Word32Xor(), m.machine()->Word32Shl(), + m.machine()->Word32Shr(), m.machine()->Word32Sar(), + m.machine()->Word32Equal(), m.machine()->Int32Add(), + m.machine()->Int32Sub(), m.machine()->Int32Mul(), + m.machine()->Int32Div(), m.machine()->Int32UDiv(), + m.machine()->Int32Mod(), m.machine()->Int32UMod(), + m.machine()->Int32LessThan(), m.machine()->Int32LessThanOrEqual(), + m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(), + NULL}; + + for (int i = 0; ops[i] != NULL; i++) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + int constant = 0x55555 + i; + m.NewNode(ops[i], m.Parameter(0), m.Parameter(1)); + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call(1, 1)); + } +} + + +template <typename Type, typename CType> +static void RunLoadImmIndex(MachineType rep) { + const int kNumElems = 3; + CType buffer[kNumElems]; + + // initialize the buffer with raw data. + byte* raw = reinterpret_cast<byte*>(buffer); + for (size_t i = 0; i < sizeof(buffer); i++) { + raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA); + } + + // Test with various large and small offsets. + for (int offset = -1; offset <= 200000; offset *= -5) { + for (int i = 0; i < kNumElems; i++) { + RawMachineAssemblerTester<Type> m; + Node* base = m.PointerConstant(buffer - offset); + Node* index = m.Int32Constant((offset + i) * sizeof(buffer[0])); + m.Return(m.Load(rep, base, index)); + + Type expected = buffer[i]; + Type actual = static_cast<CType>(m.Call()); + CHECK_EQ(expected, actual); + printf("XXX\n"); + } + } +} + + +TEST(RunLoadImmIndex) { + RunLoadImmIndex<int8_t, uint8_t>(kMachineWord8); + RunLoadImmIndex<int16_t, uint16_t>(kMachineWord16); + RunLoadImmIndex<int32_t, uint32_t>(kMachineWord32); + RunLoadImmIndex<int32_t*, int32_t*>(kMachineTagged); + + // TODO(titzer): test kMachineFloat64 loads + // TODO(titzer): test various indexing modes. +} + + +template <typename CType> +static void RunLoadStore(MachineType rep) { + const int kNumElems = 4; + CType buffer[kNumElems]; + + for (int32_t x = 0; x < kNumElems; x++) { + int32_t y = kNumElems - x - 1; + // initialize the buffer with raw data. + byte* raw = reinterpret_cast<byte*>(buffer); + for (size_t i = 0; i < sizeof(buffer); i++) { + raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA); + } + + RawMachineAssemblerTester<int32_t> m; + int32_t OK = 0x29000 + x; + Node* base = m.PointerConstant(buffer); + Node* index0 = m.Int32Constant(x * sizeof(buffer[0])); + Node* load = m.Load(rep, base, index0); + Node* index1 = m.Int32Constant(y * sizeof(buffer[0])); + m.Store(rep, base, index1, load); + m.Return(m.Int32Constant(OK)); + + CHECK_NE(buffer[x], buffer[y]); + CHECK_EQ(OK, m.Call()); + CHECK_EQ(buffer[x], buffer[y]); + } +} + + +TEST(RunLoadStore) { + RunLoadStore<int8_t>(kMachineWord8); + RunLoadStore<int16_t>(kMachineWord16); + RunLoadStore<int32_t>(kMachineWord32); + RunLoadStore<void*>(kMachineTagged); + RunLoadStore<double>(kMachineFloat64); +} + + +TEST(RunFloat64Binop) { + RawMachineAssemblerTester<int32_t> m; + double result; + + Operator* ops[] = {m.machine()->Float64Add(), m.machine()->Float64Sub(), + m.machine()->Float64Mul(), m.machine()->Float64Div(), + m.machine()->Float64Mod(), NULL}; + + double inf = V8_INFINITY; + Operator* inputs[] = { + m.common()->Float64Constant(0), m.common()->Float64Constant(1), + m.common()->Float64Constant(1), m.common()->Float64Constant(0), + m.common()->Float64Constant(0), m.common()->Float64Constant(-1), + m.common()->Float64Constant(-1), m.common()->Float64Constant(0), + m.common()->Float64Constant(0.22), m.common()->Float64Constant(-1.22), + m.common()->Float64Constant(-1.22), m.common()->Float64Constant(0.22), + m.common()->Float64Constant(inf), m.common()->Float64Constant(0.22), + m.common()->Float64Constant(inf), m.common()->Float64Constant(-inf), + NULL}; + + for (int i = 0; ops[i] != NULL; i++) { + for (int j = 0; inputs[j] != NULL; j += 2) { + RawMachineAssemblerTester<int32_t> m; + Node* a = m.NewNode(inputs[j]); + Node* b = m.NewNode(inputs[j + 1]); + Node* binop = m.NewNode(ops[i], a, b); + Node* base = m.PointerConstant(&result); + Node* zero = m.Int32Constant(0); + m.Store(kMachineFloat64, base, zero, binop); + m.Return(m.Int32Constant(i + j)); + CHECK_EQ(i + j, m.Call()); + } + } +} + + +TEST(RunDeadFloat64Binops) { + RawMachineAssemblerTester<int32_t> m; + + Operator* ops[] = {m.machine()->Float64Add(), m.machine()->Float64Sub(), + m.machine()->Float64Mul(), m.machine()->Float64Div(), + m.machine()->Float64Mod(), NULL}; + + for (int i = 0; ops[i] != NULL; i++) { + RawMachineAssemblerTester<int32_t> m; + int constant = 0x53355 + i; + m.NewNode(ops[i], m.Float64Constant(0.1), m.Float64Constant(1.11)); + m.Return(m.Int32Constant(constant)); + CHECK_EQ(constant, m.Call()); + } +} + + +TEST(RunFloat64AddP) { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + + bt.AddReturn(m.Float64Add(bt.param0, bt.param1)); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double expected = *pl + *pr; + CHECK_EQ(expected, bt.call(*pl, *pr)); + } + } +} + + +TEST(RunFloat64SubP) { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + + bt.AddReturn(m.Float64Sub(bt.param0, bt.param1)); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double expected = *pl - *pr; + CHECK_EQ(expected, bt.call(*pl, *pr)); + } + } +} + + +TEST(RunFloat64SubImm1) { + double input = 0.0; + double output = 0.0; + + FOR_FLOAT64_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); + Node* t1 = m.Float64Sub(m.Float64Constant(*i), t0); + m.StoreToPointer(&output, kMachineFloat64, t1); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(j) { + input = *j; + double expected = *i - input; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } +} + + +TEST(RunFloat64SubImm2) { + double input = 0.0; + double output = 0.0; + + FOR_FLOAT64_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); + Node* t1 = m.Float64Sub(t0, m.Float64Constant(*i)); + m.StoreToPointer(&output, kMachineFloat64, t1); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(j) { + input = *j; + double expected = input - *i; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } +} + + +TEST(RunFloat64MulP) { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + + bt.AddReturn(m.Float64Mul(bt.param0, bt.param1)); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double expected = *pl * *pr; + CHECK_EQ(expected, bt.call(*pl, *pr)); + } + } +} + + +TEST(RunFloat64MulAndFloat64AddP) { + double input_a = 0.0; + double input_b = 0.0; + double input_c = 0.0; + double output = 0.0; + + { + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); + m.StoreToPointer(&output, kMachineFloat64, + m.Float64Add(m.Float64Mul(a, b), c)); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_FLOAT64_INPUTS(j) { + FOR_FLOAT64_INPUTS(k) { + input_a = *i; + input_b = *j; + input_c = *k; + volatile double temp = input_a * input_b; + volatile double expected = temp + input_c; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } + } + } + { + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); + m.StoreToPointer(&output, kMachineFloat64, + m.Float64Add(a, m.Float64Mul(b, c))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_FLOAT64_INPUTS(j) { + FOR_FLOAT64_INPUTS(k) { + input_a = *i; + input_b = *j; + input_c = *k; + volatile double temp = input_b * input_c; + volatile double expected = input_a + temp; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } + } + } +} + + +TEST(RunFloat64MulAndFloat64SubP) { + double input_a = 0.0; + double input_b = 0.0; + double input_c = 0.0; + double output = 0.0; + + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + Node* c = m.LoadFromPointer(&input_c, kMachineFloat64); + m.StoreToPointer(&output, kMachineFloat64, + m.Float64Sub(a, m.Float64Mul(b, c))); + m.Return(m.Int32Constant(0)); + + FOR_FLOAT64_INPUTS(i) { + FOR_FLOAT64_INPUTS(j) { + FOR_FLOAT64_INPUTS(k) { + input_a = *i; + input_b = *j; + input_c = *k; + volatile double temp = input_b * input_c; + volatile double expected = input_a - temp; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } + } +} + + +TEST(RunFloat64MulImm) { + double input = 0.0; + double output = 0.0; + + { + FOR_FLOAT64_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); + Node* t1 = m.Float64Mul(m.Float64Constant(*i), t0); + m.StoreToPointer(&output, kMachineFloat64, t1); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(j) { + input = *j; + double expected = *i * input; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } + } + { + FOR_FLOAT64_INPUTS(i) { + RawMachineAssemblerTester<int32_t> m; + Node* t0 = m.LoadFromPointer(&input, kMachineFloat64); + Node* t1 = m.Float64Mul(t0, m.Float64Constant(*i)); + m.StoreToPointer(&output, kMachineFloat64, t1); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(j) { + input = *j; + double expected = input * *i; + CHECK_EQ(0, m.Call()); + CHECK_EQ(expected, output); + } + } + } +} + + +TEST(RunFloat64DivP) { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + + bt.AddReturn(m.Float64Div(bt.param0, bt.param1)); + + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + double expected = *pl / *pr; + CHECK_EQ(expected, bt.call(*pl, *pr)); + } + } +} + + +TEST(RunFloat64ModP) { + RawMachineAssemblerTester<int32_t> m; + Float64BinopTester bt(&m); + + bt.AddReturn(m.Float64Mod(bt.param0, bt.param1)); + + FOR_FLOAT64_INPUTS(i) { + FOR_FLOAT64_INPUTS(j) { + double expected = modulo(*i, *j); + double found = bt.call(*i, *j); + CHECK_EQ(expected, found); + } + } +} + + +TEST(RunChangeInt32ToFloat64_A) { + RawMachineAssemblerTester<int32_t> m; + int32_t magic = 0x986234; + double result = 0; + + Node* convert = m.ChangeInt32ToFloat64(m.Int32Constant(magic)); + m.Store(kMachineFloat64, m.PointerConstant(&result), m.Int32Constant(0), + convert); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK_EQ(static_cast<double>(magic), result); +} + + +TEST(RunChangeInt32ToFloat64_B) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + double output = 0; + + Node* convert = m.ChangeInt32ToFloat64(m.Parameter(0)); + m.Store(kMachineFloat64, m.PointerConstant(&output), m.Int32Constant(0), + convert); + m.Return(m.Parameter(0)); + + FOR_INT32_INPUTS(i) { + int32_t expect = *i; + CHECK_EQ(expect, m.Call(expect)); + CHECK_EQ(static_cast<double>(expect), output); + } +} + + +TEST(RunChangeUint32ToFloat64_B) { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + double output = 0; + + Node* convert = m.ChangeUint32ToFloat64(m.Parameter(0)); + m.Store(kMachineFloat64, m.PointerConstant(&output), m.Int32Constant(0), + convert); + m.Return(m.Parameter(0)); + + FOR_UINT32_INPUTS(i) { + uint32_t expect = *i; + CHECK_EQ(expect, m.Call(expect)); + CHECK_EQ(static_cast<double>(expect), output); + } +} + + +TEST(RunChangeFloat64ToInt32_A) { + RawMachineAssemblerTester<int32_t> m; + int32_t magic = 0x786234; + double input = 11.1; + int32_t result = 0; + + m.Store(kMachineWord32, m.PointerConstant(&result), m.Int32Constant(0), + m.ChangeFloat64ToInt32(m.Float64Constant(input))); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK_EQ(static_cast<int32_t>(input), result); +} + + +TEST(RunChangeFloat64ToInt32_B) { + RawMachineAssemblerTester<int32_t> m; + double input = 0; + int32_t output = 0; + + Node* load = + m.Load(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(0)); + Node* convert = m.ChangeFloat64ToInt32(load); + m.Store(kMachineWord32, m.PointerConstant(&output), m.Int32Constant(0), + convert); + m.Return(convert); + + { + FOR_INT32_INPUTS(i) { + input = *i; + int32_t expect = *i; + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + } + + // Check various powers of 2. + for (int32_t n = 1; n < 31; ++n) { + { + input = 1 << n; + int32_t expect = static_cast<int32_t>(input); + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + + { + input = 3 << n; + int32_t expect = static_cast<int32_t>(input); + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + } + // Note we don't check fractional inputs, because these Convert operators + // really should be Change operators. +} + + +TEST(RunChangeFloat64ToUint32_B) { + RawMachineAssemblerTester<int32_t> m; + double input = 0; + int32_t output = 0; + + Node* load = + m.Load(kMachineFloat64, m.PointerConstant(&input), m.Int32Constant(0)); + Node* convert = m.ChangeFloat64ToUint32(load); + m.Store(kMachineWord32, m.PointerConstant(&output), m.Int32Constant(0), + convert); + m.Return(convert); + + { + FOR_UINT32_INPUTS(i) { + input = *i; + // TODO(titzer): add a CheckEqualsHelper overload for uint32_t. + int32_t expect = static_cast<int32_t>(*i); + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + } + + // Check various powers of 2. + for (int32_t n = 1; n < 31; ++n) { + { + input = 1u << n; + int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input)); + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + + { + input = 3u << n; + int32_t expect = static_cast<int32_t>(static_cast<uint32_t>(input)); + CHECK_EQ(expect, m.Call()); + CHECK_EQ(expect, output); + } + } + // Note we don't check fractional inputs, because these Convert operators + // really should be Change operators. +} + + +TEST(RunChangeFloat64ToInt32_spilled) { + RawMachineAssemblerTester<int32_t> m; + const int kNumInputs = 32; + int32_t magic = 0x786234; + double input[kNumInputs]; + int32_t result[kNumInputs]; + Node* input_node[kNumInputs]; + + for (int i = 0; i < kNumInputs; i++) { + input_node[i] = m.Load(kMachineFloat64, m.PointerConstant(&input), + m.Int32Constant(i * 8)); + } + + for (int i = 0; i < kNumInputs; i++) { + m.Store(kMachineWord32, m.PointerConstant(&result), m.Int32Constant(i * 4), + m.ChangeFloat64ToInt32(input_node[i])); + } + + m.Return(m.Int32Constant(magic)); + + for (int i = 0; i < kNumInputs; i++) { + input[i] = 100.9 + i; + } + + CHECK_EQ(magic, m.Call()); + + for (int i = 0; i < kNumInputs; i++) { + CHECK_EQ(result[i], 100 + i); + } +} + + +TEST(RunDeadChangeFloat64ToInt32) { + RawMachineAssemblerTester<int32_t> m; + const int magic = 0x88abcda4; + m.ChangeFloat64ToInt32(m.Float64Constant(999.78)); + m.Return(m.Int32Constant(magic)); + CHECK_EQ(magic, m.Call()); +} + + +TEST(RunDeadChangeInt32ToFloat64) { + RawMachineAssemblerTester<int32_t> m; + const int magic = 0x8834abcd; + m.ChangeInt32ToFloat64(m.Int32Constant(magic - 6888)); + m.Return(m.Int32Constant(magic)); + CHECK_EQ(magic, m.Call()); +} + + +TEST(RunLoopPhiInduction2) { + RawMachineAssemblerTester<int32_t> m; + + int false_val = 0x10777; + + // x = false_val; while(false) { x++; } return x; + MLabel header, body, end; + Node* false_node = m.Int32Constant(false_val); + m.Goto(&header); + m.Bind(&header); + Node* phi = m.Phi(false_node, false_node); + 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.Return(phi); + + CHECK_EQ(false_val, m.Call()); +} + + +TEST(RunDoubleDiamond) { + RawMachineAssemblerTester<int32_t> m; + + const int magic = 99645; + double buffer = 0.1; + double constant = 99.99; + + MLabel blocka, blockb, end; + Node* k1 = m.Float64Constant(constant); + Node* k2 = m.Float64Constant(0 - constant); + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&end); + m.Bind(&blockb); + m.Goto(&end); + m.Bind(&end); + Node* phi = m.Phi(k2, k1); + m.Store(kMachineFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK_EQ(constant, buffer); +} + + +TEST(RunRefDiamond) { + RawMachineAssemblerTester<int32_t> m; + + const int magic = 99644; + Handle<String> rexpected = + CcTest::i_isolate()->factory()->InternalizeUtf8String("A"); + String* buffer; + + MLabel blocka, blockb, end; + Node* k1 = m.StringConstant("A"); + Node* k2 = m.StringConstant("B"); + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&end); + m.Bind(&blockb); + m.Goto(&end); + m.Bind(&end); + Node* phi = m.Phi(k2, k1); + m.Store(kMachineTagged, m.PointerConstant(&buffer), m.Int32Constant(0), phi); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK(rexpected->SameValue(buffer)); +} + + +TEST(RunDoubleRefDiamond) { + RawMachineAssemblerTester<int32_t> m; + + const int magic = 99648; + double dbuffer = 0.1; + double dconstant = 99.99; + Handle<String> rexpected = + CcTest::i_isolate()->factory()->InternalizeUtf8String("AX"); + String* rbuffer; + + MLabel blocka, blockb, end; + Node* d1 = m.Float64Constant(dconstant); + Node* d2 = m.Float64Constant(0 - dconstant); + Node* r1 = m.StringConstant("AX"); + Node* r2 = m.StringConstant("BX"); + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&end); + m.Bind(&blockb); + m.Goto(&end); + m.Bind(&end); + Node* dphi = m.Phi(d2, d1); + Node* rphi = m.Phi(r2, r1); + m.Store(kMachineFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), + dphi); + m.Store(kMachineTagged, m.PointerConstant(&rbuffer), m.Int32Constant(0), + rphi); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK_EQ(dconstant, dbuffer); + CHECK(rexpected->SameValue(rbuffer)); +} + + +TEST(RunDoubleRefDoubleDiamond) { + RawMachineAssemblerTester<int32_t> m; + + const int magic = 99649; + double dbuffer = 0.1; + double dconstant = 99.997; + Handle<String> rexpected = + CcTest::i_isolate()->factory()->InternalizeUtf8String("AD"); + String* rbuffer; + + MLabel blocka, blockb, mid, blockd, blocke, end; + Node* d1 = m.Float64Constant(dconstant); + Node* d2 = m.Float64Constant(0 - dconstant); + Node* r1 = m.StringConstant("AD"); + Node* r2 = m.StringConstant("BD"); + m.Branch(m.Int32Constant(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&mid); + m.Bind(&blockb); + m.Goto(&mid); + m.Bind(&mid); + Node* dphi1 = m.Phi(d2, d1); + Node* rphi1 = m.Phi(r2, r1); + m.Branch(m.Int32Constant(0), &blockd, &blocke); + + m.Bind(&blockd); + m.Goto(&end); + m.Bind(&blocke); + m.Goto(&end); + m.Bind(&end); + Node* dphi2 = m.Phi(d1, dphi1); + Node* rphi2 = m.Phi(r1, rphi1); + + m.Store(kMachineFloat64, m.PointerConstant(&dbuffer), m.Int32Constant(0), + dphi2); + m.Store(kMachineTagged, m.PointerConstant(&rbuffer), m.Int32Constant(0), + rphi2); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); + CHECK_EQ(dconstant, dbuffer); + CHECK(rexpected->SameValue(rbuffer)); +} + + +TEST(RunDoubleLoopPhi) { + RawMachineAssemblerTester<int32_t> m; + MLabel header, body, end; + + int magic = 99773; + double buffer = 0.99; + double dconstant = 777.1; + + Node* zero = m.Int32Constant(0); + Node* dk = m.Float64Constant(dconstant); + + m.Goto(&header); + m.Bind(&header); + Node* phi = m.Phi(dk, dk); + phi->ReplaceInput(1, phi); + m.Branch(zero, &body, &end); + m.Bind(&body); + m.Goto(&header); + m.Bind(&end); + m.Store(kMachineFloat64, m.PointerConstant(&buffer), m.Int32Constant(0), phi); + m.Return(m.Int32Constant(magic)); + + CHECK_EQ(magic, m.Call()); +} + + +TEST(RunCountToTenAccRaw) { + RawMachineAssemblerTester<int32_t> m; + + Node* zero = m.Int32Constant(0); + Node* ten = m.Int32Constant(10); + Node* one = m.Int32Constant(1); + + MLabel header, body, body_cont, end; + + m.Goto(&header); + + m.Bind(&header); + Node* i = m.Phi(zero, zero); + Node* j = m.Phi(zero, zero); + m.Goto(&body); + + m.Bind(&body); + Node* next_i = m.Int32Add(i, one); + Node* next_j = m.Int32Add(j, one); + m.Branch(m.Word32Equal(next_i, ten), &end, &body_cont); + + m.Bind(&body_cont); + i->ReplaceInput(1, next_i); + j->ReplaceInput(1, next_j); + m.Goto(&header); + + m.Bind(&end); + m.Return(ten); + + CHECK_EQ(10, m.Call()); +} + + +TEST(RunCountToTenAccRaw2) { + RawMachineAssemblerTester<int32_t> m; + + Node* zero = m.Int32Constant(0); + Node* ten = m.Int32Constant(10); + Node* one = m.Int32Constant(1); + + MLabel header, body, body_cont, end; + + m.Goto(&header); + + m.Bind(&header); + Node* i = m.Phi(zero, zero); + Node* j = m.Phi(zero, zero); + Node* k = m.Phi(zero, zero); + m.Goto(&body); + + m.Bind(&body); + Node* next_i = m.Int32Add(i, one); + Node* next_j = m.Int32Add(j, one); + Node* next_k = m.Int32Add(j, one); + m.Branch(m.Word32Equal(next_i, ten), &end, &body_cont); + + m.Bind(&body_cont); + i->ReplaceInput(1, next_i); + j->ReplaceInput(1, next_j); + k->ReplaceInput(1, next_k); + m.Goto(&header); + + m.Bind(&end); + m.Return(ten); + + CHECK_EQ(10, m.Call()); +} + + +TEST(RunAddTree) { + RawMachineAssemblerTester<int32_t> m; + int32_t inputs[] = {11, 12, 13, 14, 15, 16, 17, 18}; + + Node* base = m.PointerConstant(inputs); + Node* n0 = m.Load(kMachineWord32, base, m.Int32Constant(0 * sizeof(int32_t))); + Node* n1 = m.Load(kMachineWord32, base, m.Int32Constant(1 * sizeof(int32_t))); + Node* n2 = m.Load(kMachineWord32, base, m.Int32Constant(2 * sizeof(int32_t))); + Node* n3 = m.Load(kMachineWord32, base, m.Int32Constant(3 * sizeof(int32_t))); + Node* n4 = m.Load(kMachineWord32, base, m.Int32Constant(4 * sizeof(int32_t))); + Node* n5 = m.Load(kMachineWord32, base, m.Int32Constant(5 * sizeof(int32_t))); + Node* n6 = m.Load(kMachineWord32, base, m.Int32Constant(6 * sizeof(int32_t))); + Node* n7 = m.Load(kMachineWord32, base, m.Int32Constant(7 * sizeof(int32_t))); + + Node* i1 = m.Int32Add(n0, n1); + Node* i2 = m.Int32Add(n2, n3); + Node* i3 = m.Int32Add(n4, n5); + Node* i4 = m.Int32Add(n6, n7); + + Node* i5 = m.Int32Add(i1, i2); + Node* i6 = m.Int32Add(i3, i4); + + Node* i7 = m.Int32Add(i5, i6); + + m.Return(i7); + + CHECK_EQ(116, m.Call()); +} + + +#if MACHINE_ASSEMBLER_SUPPORTS_CALL_C + +static int Seven() { return 7; } +static int UnaryMinus(int a) { return -a; } +static int APlusTwoB(int a, int b) { return a + 2 * b; } + + +TEST(RunCallSeven) { + for (int i = 0; i < 2; i++) { + bool call_direct = i == 0; + void* function_address = + reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&Seven)); + + RawMachineAssemblerTester<int32_t> m; + Node** args = NULL; + MachineType* arg_types = NULL; + Node* function = + call_direct ? m.PointerConstant(function_address) + : m.LoadFromPointer(&function_address, + MachineOperatorBuilder::pointer_rep()); + m.Return(m.CallC(function, kMachineWord32, arg_types, args, 0)); + + CHECK_EQ(7, m.Call()); + } +} + + +TEST(RunCallUnaryMinus) { + for (int i = 0; i < 2; i++) { + bool call_direct = i == 0; + void* function_address = + reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&UnaryMinus)); + + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* args[] = {m.Parameter(0)}; + MachineType arg_types[] = {kMachineWord32}; + Node* function = + call_direct ? m.PointerConstant(function_address) + : m.LoadFromPointer(&function_address, + MachineOperatorBuilder::pointer_rep()); + m.Return(m.CallC(function, kMachineWord32, arg_types, args, 1)); + + FOR_INT32_INPUTS(i) { + int a = *i; + CHECK_EQ(-a, m.Call(a)); + } + } +} + + +TEST(RunCallAPlusTwoB) { + for (int i = 0; i < 2; i++) { + bool call_direct = i == 0; + void* function_address = + reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&APlusTwoB)); + + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + Node* args[] = {m.Parameter(0), m.Parameter(1)}; + MachineType arg_types[] = {kMachineWord32, kMachineWord32}; + Node* function = + call_direct ? m.PointerConstant(function_address) + : m.LoadFromPointer(&function_address, + MachineOperatorBuilder::pointer_rep()); + m.Return(m.CallC(function, kMachineWord32, arg_types, args, 2)); + + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int a = *i; + int b = *j; + int result = m.Call(a, b); + CHECK_EQ(a + 2 * b, result); + } + } + } +} + +#endif // MACHINE_ASSEMBLER_SUPPORTS_CALL_C + + +static const int kFloat64CompareHelperTestCases = 15; +static const int kFloat64CompareHelperNodeType = 4; + +static int Float64CompareHelper(RawMachineAssemblerTester<int32_t>* m, + int test_case, int node_type, double x, + double y) { + static double buffer[2]; + buffer[0] = x; + buffer[1] = y; + CHECK(0 <= test_case && test_case < kFloat64CompareHelperTestCases); + CHECK(0 <= node_type && node_type < kFloat64CompareHelperNodeType); + CHECK(x < y); + bool load_a = node_type / 2 == 1; + bool load_b = node_type % 2 == 1; + Node* a = load_a ? m->Load(kMachineFloat64, m->PointerConstant(&buffer[0])) + : m->Float64Constant(x); + Node* b = load_b ? m->Load(kMachineFloat64, m->PointerConstant(&buffer[1])) + : m->Float64Constant(y); + Node* cmp = NULL; + bool expected = false; + switch (test_case) { + // Equal tests. + case 0: + cmp = m->Float64Equal(a, b); + expected = false; + break; + case 1: + cmp = m->Float64Equal(a, a); + expected = true; + break; + // LessThan tests. + case 2: + cmp = m->Float64LessThan(a, b); + expected = true; + break; + case 3: + cmp = m->Float64LessThan(b, a); + expected = false; + break; + case 4: + cmp = m->Float64LessThan(a, a); + expected = false; + break; + // LessThanOrEqual tests. + case 5: + cmp = m->Float64LessThanOrEqual(a, b); + expected = true; + break; + case 6: + cmp = m->Float64LessThanOrEqual(b, a); + expected = false; + break; + case 7: + cmp = m->Float64LessThanOrEqual(a, a); + expected = true; + break; + // NotEqual tests. + case 8: + cmp = m->Float64NotEqual(a, b); + expected = true; + break; + case 9: + cmp = m->Float64NotEqual(b, a); + expected = true; + break; + case 10: + cmp = m->Float64NotEqual(a, a); + expected = false; + break; + // GreaterThan tests. + case 11: + cmp = m->Float64GreaterThan(a, a); + expected = false; + break; + case 12: + cmp = m->Float64GreaterThan(a, b); + expected = false; + break; + // GreaterThanOrEqual tests. + case 13: + cmp = m->Float64GreaterThanOrEqual(a, a); + expected = true; + break; + case 14: + cmp = m->Float64GreaterThanOrEqual(b, a); + expected = true; + break; + default: + UNREACHABLE(); + } + m->Return(cmp); + return expected; +} + + +TEST(RunFloat64Compare) { + double inf = V8_INFINITY; + // All pairs (a1, a2) are of the form a1 < a2. + double inputs[] = {0.0, 1.0, -1.0, 0.22, -1.22, 0.22, + -inf, 0.22, 0.22, inf, -inf, inf}; + + for (int test = 0; test < kFloat64CompareHelperTestCases; test++) { + for (int node_type = 0; node_type < kFloat64CompareHelperNodeType; + node_type++) { + for (size_t input = 0; input < ARRAY_SIZE(inputs); input += 2) { + RawMachineAssemblerTester<int32_t> m; + int expected = Float64CompareHelper(&m, test, node_type, inputs[input], + inputs[input + 1]); + CHECK_EQ(expected, m.Call()); + } + } + } +} + + +TEST(RunFloat64UnorderedCompare) { + RawMachineAssemblerTester<int32_t> m; + + Operator* operators[] = {m.machine()->Float64Equal(), + m.machine()->Float64LessThan(), + m.machine()->Float64LessThanOrEqual()}; + + double nan = v8::base::OS::nan_value(); + + FOR_FLOAT64_INPUTS(i) { + for (size_t o = 0; o < ARRAY_SIZE(operators); ++o) { + for (int j = 0; j < 2; j++) { + RawMachineAssemblerTester<int32_t> m; + Node* a = m.Float64Constant(*i); + Node* b = m.Float64Constant(nan); + if (j == 1) std::swap(a, b); + m.Return(m.NewNode(operators[o], a, b)); + CHECK_EQ(0, m.Call()); + } + } + } +} + + +TEST(RunFloat64Equal) { + double input_a = 0.0; + double input_b = 0.0; + + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + m.Return(m.Float64Equal(a, b)); + + CompareWrapper cmp(IrOpcode::kFloat64Equal); + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + input_a = *pl; + input_b = *pr; + int32_t expected = cmp.Float64Compare(input_a, input_b) ? 1 : 0; + CHECK_EQ(expected, m.Call()); + } + } +} + + +TEST(RunFloat64LessThan) { + double input_a = 0.0; + double input_b = 0.0; + + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); + Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); + m.Return(m.Float64LessThan(a, b)); + + CompareWrapper cmp(IrOpcode::kFloat64LessThan); + FOR_FLOAT64_INPUTS(pl) { + FOR_FLOAT64_INPUTS(pr) { + input_a = *pl; + input_b = *pr; + int32_t expected = cmp.Float64Compare(input_a, input_b) ? 1 : 0; + CHECK_EQ(expected, m.Call()); + } + } +} + + +template <typename IntType, MachineType kRepresentation> +static void LoadStoreTruncation() { + IntType input; + + RawMachineAssemblerTester<int32_t> m; + Node* a = m.LoadFromPointer(&input, kRepresentation); + Node* ap1 = m.Int32Add(a, m.Int32Constant(1)); + m.StoreToPointer(&input, kRepresentation, ap1); + m.Return(ap1); + + const IntType max = std::numeric_limits<IntType>::max(); + const IntType min = std::numeric_limits<IntType>::min(); + + // Test upper bound. + input = max; + CHECK_EQ(max + 1, m.Call()); + CHECK_EQ(min, input); + + // Test lower bound. + input = min; + CHECK_EQ(max + 2, m.Call()); + CHECK_EQ(min + 1, input); + + // Test all one byte values that are not one byte bounds. + for (int i = -127; i < 127; i++) { + input = i; + int expected = i >= 0 ? i + 1 : max + (i - min) + 2; + CHECK_EQ(expected, m.Call()); + CHECK_EQ(i + 1, input); + } +} + + +TEST(RunLoadStoreTruncation) { + LoadStoreTruncation<int8_t, kMachineWord8>(); + LoadStoreTruncation<int16_t, kMachineWord16>(); +} + + +static void IntPtrCompare(intptr_t left, intptr_t right) { + for (int test = 0; test < 7; test++) { + RawMachineAssemblerTester<bool> m(MachineOperatorBuilder::pointer_rep(), + MachineOperatorBuilder::pointer_rep()); + Node* p0 = m.Parameter(0); + Node* p1 = m.Parameter(1); + Node* res = NULL; + bool expected = false; + switch (test) { + case 0: + res = m.IntPtrLessThan(p0, p1); + expected = true; + break; + case 1: + res = m.IntPtrLessThanOrEqual(p0, p1); + expected = true; + break; + case 2: + res = m.IntPtrEqual(p0, p1); + expected = false; + break; + case 3: + res = m.IntPtrGreaterThanOrEqual(p0, p1); + expected = false; + break; + case 4: + res = m.IntPtrGreaterThan(p0, p1); + expected = false; + break; + case 5: + res = m.IntPtrEqual(p0, p0); + expected = true; + break; + case 6: + res = m.IntPtrNotEqual(p0, p1); + expected = true; + break; + default: + UNREACHABLE(); + break; + } + m.Return(res); + CHECK_EQ(expected, m.Call(reinterpret_cast<int32_t*>(left), + reinterpret_cast<int32_t*>(right))); + } +} + + +TEST(RunIntPtrCompare) { + intptr_t min = std::numeric_limits<intptr_t>::min(); + intptr_t max = std::numeric_limits<intptr_t>::max(); + // An ascending chain of intptr_t + intptr_t inputs[] = {min, min / 2, -1, 0, 1, max / 2, max}; + for (size_t i = 0; i < ARRAY_SIZE(inputs) - 1; i++) { + IntPtrCompare(inputs[i], inputs[i + 1]); + } +} + + +TEST(RunTestIntPtrArithmetic) { + static const int kInputSize = 10; + int32_t inputs[kInputSize]; + int32_t outputs[kInputSize]; + for (int i = 0; i < kInputSize; i++) { + inputs[i] = i; + outputs[i] = -1; + } + 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]))); + for (int i = 0; i < kInputSize; i++) { + m.Store(kMachineWord32, output, m.Load(kMachineWord32, input)); + input = m.IntPtrAdd(input, elem_size); + output = m.IntPtrSub(output, elem_size); + } + m.Return(input); + CHECK_EQ(&inputs[kInputSize], m.Call()); + for (int i = 0; i < kInputSize; i++) { + CHECK_EQ(i, inputs[i]); + CHECK_EQ(kInputSize - i - 1, outputs[i]); + } +} + + +static inline uint32_t rotr32(uint32_t i, uint32_t j) { + return (i >> j) | (i << (32 - j)); +} + + +TEST(RunTestInt32RotateRightP) { + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Or( + m.Word32Shr(bt.param0, bt.param1), + m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)))); + bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32); + } + { + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + bt.AddReturn(m.Word32Or( + m.Word32Shl(bt.param0, m.Int32Sub(m.Int32Constant(32), bt.param1)), + m.Word32Shr(bt.param0, bt.param1))); + bt.Run(ValueHelper::uint32_vector(), ValueHelper::ror_vector(), rotr32); + } +} + + +TEST(RunTestInt32RotateRightImm) { + FOR_INPUTS(uint32_t, ror, i) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* value = m.Parameter(0); + m.Return(m.Word32Or(m.Word32Shr(value, m.Int32Constant(*i)), + m.Word32Shl(value, m.Int32Constant(32 - *i)))); + m.Run(ValueHelper::uint32_vector(), + std::bind2nd(std::ptr_fun(&rotr32), *i)); + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* value = m.Parameter(0); + m.Return(m.Word32Or(m.Word32Shl(value, m.Int32Constant(32 - *i)), + m.Word32Shr(value, m.Int32Constant(*i)))); + m.Run(ValueHelper::uint32_vector(), + std::bind2nd(std::ptr_fun(&rotr32), *i)); + } + } +} + + +TEST(RunSpillLotsOfThings) { + static const int kInputSize = 1000; + RawMachineAssemblerTester<void> m; + Node* accs[kInputSize]; + int32_t outputs[kInputSize]; + Node* one = m.Int32Constant(1); + Node* acc = one; + for (int i = 0; i < kInputSize; i++) { + acc = m.Int32Add(acc, one); + accs[i] = acc; + } + for (int i = 0; i < kInputSize; i++) { + m.StoreToPointer(&outputs[i], kMachineWord32, accs[i]); + } + m.Return(one); + m.Call(); + for (int i = 0; i < kInputSize; i++) { + CHECK_EQ(outputs[i], i + 2); + } +} + + +TEST(RunSpillConstantsAndParameters) { + static const int kInputSize = 1000; + static const int32_t kBase = 987; + RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + int32_t outputs[kInputSize]; + Node* csts[kInputSize]; + Node* accs[kInputSize]; + Node* acc = m.Int32Constant(0); + for (int i = 0; i < kInputSize; i++) { + csts[i] = m.Int32Constant(static_cast<int32_t>(kBase + i)); + } + for (int i = 0; i < kInputSize; i++) { + acc = m.Int32Add(acc, csts[i]); + accs[i] = acc; + } + for (int i = 0; i < kInputSize; i++) { + m.StoreToPointer(&outputs[i], kMachineWord32, accs[i]); + } + m.Return(m.Int32Add(acc, m.Int32Add(m.Parameter(0), m.Parameter(1)))); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t expected = *i + *j; + for (int k = 0; k < kInputSize; k++) { + expected += kBase + k; + } + CHECK_EQ(expected, m.Call(*i, *j)); + expected = 0; + for (int k = 0; k < kInputSize; k++) { + expected += kBase + k; + CHECK_EQ(expected, outputs[k]); + } + } + } +} + + +TEST(RunNewSpaceConstantsInPhi) { + RawMachineAssemblerTester<Object*> m(kMachineWord32); + + Isolate* isolate = CcTest::i_isolate(); + Handle<HeapNumber> true_val = isolate->factory()->NewHeapNumber(11.2); + Handle<HeapNumber> false_val = isolate->factory()->NewHeapNumber(11.3); + Node* true_node = m.HeapConstant(true_val); + Node* false_node = m.HeapConstant(false_val); + + MLabel blocka, blockb, end; + m.Branch(m.Parameter(0), &blocka, &blockb); + m.Bind(&blocka); + m.Goto(&end); + m.Bind(&blockb); + m.Goto(&end); + + m.Bind(&end); + Node* phi = m.Phi(true_node, false_node); + m.Return(phi); + + CHECK_EQ(*false_val, m.Call(0)); + CHECK_EQ(*true_val, m.Call(1)); +} + + +#if MACHINE_ASSEMBLER_SUPPORTS_CALL_C + +TEST(RunSpillLotsOfThingsWithCall) { + static const int kInputSize = 1000; + RawMachineAssemblerTester<void> m; + Node* accs[kInputSize]; + int32_t outputs[kInputSize]; + Node* one = m.Int32Constant(1); + Node* acc = one; + for (int i = 0; i < kInputSize; i++) { + acc = m.Int32Add(acc, one); + accs[i] = acc; + } + // If the spill slot computation is wrong, it might load from the c frame + { + void* func = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(&Seven)); + Node** args = NULL; + MachineType* arg_types = NULL; + m.CallC(m.PointerConstant(func), kMachineWord32, arg_types, args, 0); + } + for (int i = 0; i < kInputSize; i++) { + m.StoreToPointer(&outputs[i], kMachineWord32, accs[i]); + } + m.Return(one); + m.Call(); + for (int i = 0; i < kInputSize; i++) { + CHECK_EQ(outputs[i], i + 2); + } +} + +#endif // MACHINE_ASSEMBLER_SUPPORTS_CALL_C + + +static bool sadd_overflow(int32_t x, int32_t y, int32_t* val) { + int32_t v = + static_cast<int32_t>(static_cast<uint32_t>(x) + static_cast<uint32_t>(y)); + *val = v; + return (((v ^ x) & (v ^ y)) >> 31) & 1; +} + + +static bool ssub_overflow(int32_t x, int32_t y, int32_t* val) { + int32_t v = + static_cast<int32_t>(static_cast<uint32_t>(x) - static_cast<uint32_t>(y)); + *val = v; + return (((v ^ x) & (v ^ ~y)) >> 31) & 1; +} + + +TEST(RunInt32AddWithOverflowP) { + int32_t actual_val = -1; + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + Node* add = m.Int32AddWithOverflow(bt.param0, bt.param1); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + bt.AddReturn(ovf); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t expected_val; + int expected_ovf = sadd_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, bt.call(*i, *j)); + CHECK_EQ(expected_val, actual_val); + } + } +} + + +TEST(RunInt32AddWithOverflowImm) { + int32_t actual_val = -1, expected_val = 0; + FOR_INT32_INPUTS(i) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* add = m.Int32AddWithOverflow(m.Int32Constant(*i), m.Parameter(0)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + FOR_INT32_INPUTS(j) { + int expected_ovf = sadd_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, m.Call(*j)); + CHECK_EQ(expected_val, actual_val); + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* add = m.Int32AddWithOverflow(m.Parameter(0), m.Int32Constant(*i)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + FOR_INT32_INPUTS(j) { + int expected_ovf = sadd_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, m.Call(*j)); + CHECK_EQ(expected_val, actual_val); + } + } + FOR_INT32_INPUTS(j) { + RawMachineAssemblerTester<int32_t> m; + Node* add = + m.Int32AddWithOverflow(m.Int32Constant(*i), m.Int32Constant(*j)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + int expected_ovf = sadd_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, m.Call()); + CHECK_EQ(expected_val, actual_val); + } + } +} + + +TEST(RunInt32AddWithOverflowInBranchP) { + int constant = 911777; + MLabel blocka, blockb; + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + Node* add = m.Int32AddWithOverflow(bt.param0, bt.param1); + Node* ovf = m.Projection(1, add); + m.Branch(ovf, &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + Node* val = m.Projection(0, add); + bt.AddReturn(val); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected; + if (sadd_overflow(*i, *j, &expected)) expected = constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } +} + + +TEST(RunInt32SubWithOverflowP) { + int32_t actual_val = -1; + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + Node* add = m.Int32SubWithOverflow(bt.param0, bt.param1); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + bt.AddReturn(ovf); + FOR_INT32_INPUTS(i) { + FOR_INT32_INPUTS(j) { + int32_t expected_val; + int expected_ovf = ssub_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, bt.call(*i, *j)); + CHECK_EQ(expected_val, actual_val); + } + } +} + + +TEST(RunInt32SubWithOverflowImm) { + int32_t actual_val = -1, expected_val = 0; + FOR_INT32_INPUTS(i) { + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* add = m.Int32SubWithOverflow(m.Int32Constant(*i), m.Parameter(0)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + FOR_INT32_INPUTS(j) { + int expected_ovf = ssub_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, m.Call(*j)); + CHECK_EQ(expected_val, actual_val); + } + } + { + RawMachineAssemblerTester<int32_t> m(kMachineWord32); + Node* add = m.Int32SubWithOverflow(m.Parameter(0), m.Int32Constant(*i)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + FOR_INT32_INPUTS(j) { + int expected_ovf = ssub_overflow(*j, *i, &expected_val); + CHECK_EQ(expected_ovf, m.Call(*j)); + CHECK_EQ(expected_val, actual_val); + } + } + FOR_INT32_INPUTS(j) { + RawMachineAssemblerTester<int32_t> m; + Node* add = + m.Int32SubWithOverflow(m.Int32Constant(*i), m.Int32Constant(*j)); + Node* val = m.Projection(0, add); + Node* ovf = m.Projection(1, add); + m.StoreToPointer(&actual_val, kMachineWord32, val); + m.Return(ovf); + int expected_ovf = ssub_overflow(*i, *j, &expected_val); + CHECK_EQ(expected_ovf, m.Call()); + CHECK_EQ(expected_val, actual_val); + } + } +} + + +TEST(RunInt32SubWithOverflowInBranchP) { + int constant = 911999; + MLabel blocka, blockb; + RawMachineAssemblerTester<int32_t> m; + Int32BinopTester bt(&m); + Node* sub = m.Int32SubWithOverflow(bt.param0, bt.param1); + Node* ovf = m.Projection(1, sub); + m.Branch(ovf, &blocka, &blockb); + m.Bind(&blocka); + bt.AddReturn(m.Int32Constant(constant)); + m.Bind(&blockb); + Node* val = m.Projection(0, sub); + bt.AddReturn(val); + FOR_UINT32_INPUTS(i) { + FOR_UINT32_INPUTS(j) { + int32_t expected; + if (ssub_overflow(*i, *j, &expected)) expected = constant; + CHECK_EQ(expected, bt.call(*i, *j)); + } + } +} + +#endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-variables.cc b/deps/v8/test/cctest/compiler/test-run-variables.cc new file mode 100644 index 0000000000..bf86e0d42c --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-variables.cc @@ -0,0 +1,121 @@ +// 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/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +static const char* throws = NULL; + +static const char* load_tests[] = { + "var x = a; r = x", "123", "0", + "var x = (r = x)", "undefined", "undefined", + "var x = (a?1:2); r = x", "1", "2", + "const x = a; r = x", "123", "0", + "const x = (r = x)", "undefined", "undefined", + "const x = (a?3:4); r = x", "3", "4", + "'use strict'; const x = a; r = x", "123", "0", + "'use strict'; const x = (r = x)", throws, throws, + "'use strict'; const x = (a?5:6); r = x", "5", "6", + "'use strict'; let x = a; r = x", "123", "0", + "'use strict'; let x = (r = x)", throws, throws, + "'use strict'; let x = (a?7:8); r = x", "7", "8", + NULL}; + +static const char* store_tests[] = { + "var x = 1; x = a; r = x", "123", "0", + "var x = (a?(x=4,2):3); r = x", "2", "3", + "var x = (a?4:5); x = a; r = x", "123", "0", + "const x = 1; x = a; r = x", "1", "1", + "const x = (a?(x=4,2):3); r = x", "2", "3", + "const x = (a?4:5); x = a; r = x", "4", "5", + // Assignments to 'const' are SyntaxErrors, handled by the parser, + // hence we cannot test them here because they are early errors. + "'use strict'; let x = 1; x = a; r = x", "123", "0", + "'use strict'; let x = (a?(x=4,2):3); r = x", throws, "3", + "'use strict'; let x = (a?4:5); x = a; r = x", "123", "0", + NULL}; + +static const char* bind_tests[] = { + "if (a) { const x = a }; r = x;", "123", "undefined", + "for (; a > 0; a--) { const x = a }; r = x", "123", "undefined", + // Re-initialization of variables other than legacy 'const' is not + // possible due to sane variable scoping, hence no tests here. + NULL}; + + +static void RunVariableTests(const char* source, const char* tests[]) { + FLAG_harmony_scoping = true; + EmbeddedVector<char, 512> buffer; + + for (int i = 0; tests[i] != NULL; i += 3) { + SNPrintF(buffer, source, tests[i]); + PrintF("#%d: %s\n", i / 3, buffer.start()); + FunctionTester T(buffer.start()); + + // Check function with non-falsey parameter. + if (tests[i + 1] != throws) { + Handle<Object> r = v8::Utils::OpenHandle(*CompileRun(tests[i + 1])); + T.CheckCall(r, T.Val(123), T.Val("result")); + } else { + T.CheckThrows(T.Val(123), T.Val("result")); + } + + // Check function with falsey parameter. + if (tests[i + 2] != throws) { + Handle<Object> r = v8::Utils::OpenHandle(*CompileRun(tests[i + 2])); + T.CheckCall(r, T.Val(0.0), T.Val("result")); + } else { + T.CheckThrows(T.Val(0.0), T.Val("result")); + } + } +} + + +TEST(StackLoadVariables) { + const char* source = "(function(a,r) { %s; return r; })"; + RunVariableTests(source, load_tests); +} + + +TEST(ContextLoadVariables) { + const char* source = "(function(a,r) { %s; function f() {x} return r; })"; + RunVariableTests(source, load_tests); +} + + +TEST(StackStoreVariables) { + const char* source = "(function(a,r) { %s; return r; })"; + RunVariableTests(source, store_tests); +} + + +TEST(ContextStoreVariables) { + const char* source = "(function(a,r) { %s; function f() {x} return r; })"; + RunVariableTests(source, store_tests); +} + + +TEST(StackInitializeVariables) { + const char* source = "(function(a,r) { %s; return r; })"; + RunVariableTests(source, bind_tests); +} + + +TEST(ContextInitializeVariables) { + const char* source = "(function(a,r) { %s; function f() {x} return r; })"; + RunVariableTests(source, bind_tests); +} + + +TEST(SelfReferenceVariable) { + FunctionTester T("(function self() { return self; })"); + + T.CheckCall(T.function); + CompileRun("var self = 'not a function'"); + T.CheckCall(T.function); +} diff --git a/deps/v8/test/cctest/compiler/test-schedule.cc b/deps/v8/test/cctest/compiler/test-schedule.cc new file mode 100644 index 0000000000..bfa47d872a --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-schedule.cc @@ -0,0 +1,159 @@ +// Copyright 2013 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 "src/compiler/common-operator.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/graph.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" +#include "src/compiler/operator.h" +#include "src/compiler/schedule.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, + 0, 0, "dummy"); + +TEST(TestScheduleAllocation) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + CHECK_NE(NULL, schedule.entry()); + CHECK_EQ(schedule.entry(), *(schedule.all_blocks().begin())); +} + + +TEST(TestScheduleAddNode) { + HandleAndZoneScope scope; + Graph graph(scope.main_zone()); + Node* n0 = graph.NewNode(&dummy_operator); + Node* n1 = graph.NewNode(&dummy_operator); + + Schedule schedule(scope.main_zone()); + + BasicBlock* entry = schedule.entry(); + schedule.AddNode(entry, n0); + schedule.AddNode(entry, n1); + + CHECK_EQ(entry, schedule.block(n0)); + CHECK_EQ(entry, schedule.block(n1)); + CHECK(schedule.SameBasicBlock(n0, n1)); + + Node* n2 = graph.NewNode(&dummy_operator); + CHECK_EQ(NULL, schedule.block(n2)); +} + + +TEST(TestScheduleAddGoto) { + HandleAndZoneScope scope; + + Schedule schedule(scope.main_zone()); + BasicBlock* entry = schedule.entry(); + BasicBlock* next = schedule.NewBasicBlock(); + + schedule.AddGoto(entry, next); + + CHECK_EQ(0, entry->PredecessorCount()); + CHECK_EQ(1, entry->SuccessorCount()); + CHECK_EQ(next, entry->SuccessorAt(0)); + + CHECK_EQ(1, next->PredecessorCount()); + CHECK_EQ(entry, next->PredecessorAt(0)); + CHECK_EQ(0, next->SuccessorCount()); +} + + +TEST(TestScheduleAddBranch) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* entry = schedule.entry(); + BasicBlock* tblock = schedule.NewBasicBlock(); + BasicBlock* fblock = schedule.NewBasicBlock(); + + Graph graph(scope.main_zone()); + CommonOperatorBuilder common(scope.main_zone()); + Node* n0 = graph.NewNode(&dummy_operator); + Node* b = graph.NewNode(common.Branch(), n0); + + schedule.AddBranch(entry, b, tblock, fblock); + + CHECK_EQ(0, entry->PredecessorCount()); + CHECK_EQ(2, entry->SuccessorCount()); + CHECK_EQ(tblock, entry->SuccessorAt(0)); + CHECK_EQ(fblock, entry->SuccessorAt(1)); + + CHECK_EQ(1, tblock->PredecessorCount()); + CHECK_EQ(entry, tblock->PredecessorAt(0)); + CHECK_EQ(0, tblock->SuccessorCount()); + + CHECK_EQ(1, fblock->PredecessorCount()); + CHECK_EQ(entry, fblock->PredecessorAt(0)); + CHECK_EQ(0, fblock->SuccessorCount()); +} + + +TEST(TestScheduleAddReturn) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + Graph graph(scope.main_zone()); + Node* n0 = graph.NewNode(&dummy_operator); + BasicBlock* entry = schedule.entry(); + schedule.AddReturn(entry, n0); + + CHECK_EQ(0, entry->PredecessorCount()); + CHECK_EQ(1, entry->SuccessorCount()); + CHECK_EQ(schedule.exit(), entry->SuccessorAt(0)); +} + + +TEST(TestScheduleAddThrow) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + Graph graph(scope.main_zone()); + Node* n0 = graph.NewNode(&dummy_operator); + BasicBlock* entry = schedule.entry(); + schedule.AddThrow(entry, n0); + + CHECK_EQ(0, entry->PredecessorCount()); + CHECK_EQ(1, entry->SuccessorCount()); + CHECK_EQ(schedule.exit(), entry->SuccessorAt(0)); +} + + +TEST(TestScheduleAddDeopt) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + Graph graph(scope.main_zone()); + Node* n0 = graph.NewNode(&dummy_operator); + BasicBlock* entry = schedule.entry(); + schedule.AddDeoptimize(entry, n0); + + CHECK_EQ(0, entry->PredecessorCount()); + CHECK_EQ(1, entry->SuccessorCount()); + CHECK_EQ(schedule.exit(), entry->SuccessorAt(0)); +} + + +TEST(BuildMulNodeGraph) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common(scope.main_zone()); + MachineOperatorBuilder machine(scope.main_zone(), kMachineWord32); + + Node* start = graph.NewNode(common.Start(0)); + graph.SetStart(start); + Node* param0 = graph.NewNode(common.Parameter(0), graph.start()); + Node* param1 = graph.NewNode(common.Parameter(1), graph.start()); + + Node* mul = graph.NewNode(machine.Int32Mul(), param0, param1); + Node* ret = graph.NewNode(common.Return(), mul, start); + + USE(ret); +} diff --git a/deps/v8/test/cctest/compiler/test-scheduler.cc b/deps/v8/test/cctest/compiler/test-scheduler.cc new file mode 100644 index 0000000000..ec4e77e111 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-scheduler.cc @@ -0,0 +1,1809 @@ +// 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/common-operator.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/generic-node.h" +#include "src/compiler/graph.h" +#include "src/compiler/graph-visualizer.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" +#include "src/compiler/operator.h" +#include "src/compiler/schedule.h" +#include "src/compiler/scheduler.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +struct TestLoop { + int count; + BasicBlock** nodes; + BasicBlock* header() { return nodes[0]; } + BasicBlock* last() { return nodes[count - 1]; } + ~TestLoop() { delete[] nodes; } +}; + + +static TestLoop* CreateLoop(Schedule* schedule, int count) { + TestLoop* loop = new TestLoop(); + loop->count = count; + loop->nodes = new BasicBlock* [count]; + for (int i = 0; i < count; i++) { + loop->nodes[i] = schedule->NewBasicBlock(); + if (i > 0) schedule->AddSuccessor(loop->nodes[i - 1], loop->nodes[i]); + } + schedule->AddSuccessor(loop->nodes[count - 1], loop->nodes[0]); + return loop; +} + + +static void CheckRPONumbers(BasicBlockVector* order, int expected, + bool loops_allowed) { + CHECK_EQ(expected, static_cast<int>(order->size())); + for (int i = 0; i < static_cast<int>(order->size()); i++) { + CHECK(order->at(i)->rpo_number_ == i); + if (!loops_allowed) CHECK_LT(order->at(i)->loop_end_, 0); + } +} + + +static void CheckLoopContains(BasicBlock** blocks, int body_size) { + BasicBlock* header = blocks[0]; + CHECK_GT(header->loop_end_, 0); + CHECK_EQ(body_size, (header->loop_end_ - header->rpo_number_)); + for (int i = 0; i < body_size; i++) { + int num = blocks[i]->rpo_number_; + CHECK(num >= header->rpo_number_ && num < header->loop_end_); + CHECK(header->LoopContains(blocks[i])); + CHECK(header->IsLoopHeader() || blocks[i]->loop_header_ == header); + } +} + + +TEST(RPODegenerate1) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 1, false); + CHECK_EQ(schedule.entry(), order->at(0)); +} + + +TEST(RPODegenerate2) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + schedule.AddGoto(schedule.entry(), schedule.exit()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 2, false); + CHECK_EQ(schedule.entry(), order->at(0)); + CHECK_EQ(schedule.exit(), order->at(1)); +} + + +TEST(RPOLine) { + HandleAndZoneScope scope; + + for (int i = 0; i < 10; i++) { + Schedule schedule(scope.main_zone()); + + BasicBlock* last = schedule.entry(); + for (int j = 0; j < i; j++) { + BasicBlock* block = schedule.NewBasicBlock(); + schedule.AddGoto(last, block); + last = block; + } + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 1 + i, false); + + Schedule::BasicBlocks blocks(schedule.all_blocks()); + for (Schedule::BasicBlocks::iterator iter = blocks.begin(); + iter != blocks.end(); ++iter) { + BasicBlock* block = *iter; + if (block->rpo_number_ >= 0 && block->SuccessorCount() == 1) { + CHECK(block->rpo_number_ + 1 == block->SuccessorAt(0)->rpo_number_); + } + } + } +} + + +TEST(RPOSelfLoop) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + schedule.AddSuccessor(schedule.entry(), schedule.entry()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 1, true); + BasicBlock* loop[] = {schedule.entry()}; + CheckLoopContains(loop, 1); +} + + +TEST(RPOEntryLoop) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + schedule.AddSuccessor(schedule.entry(), schedule.exit()); + schedule.AddSuccessor(schedule.exit(), schedule.entry()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 2, true); + BasicBlock* loop[] = {schedule.entry(), schedule.exit()}; + CheckLoopContains(loop, 2); +} + + +TEST(RPOEndLoop) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessor(schedule.entry(), loop1->header()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 3, true); + CheckLoopContains(loop1->nodes, loop1->count); +} + + +TEST(RPOEndLoopNested) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessor(schedule.entry(), loop1->header()); + schedule.AddSuccessor(loop1->last(), schedule.entry()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 3, true); + CheckLoopContains(loop1->nodes, loop1->count); +} + + +TEST(RPODiamond) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(A, C); + schedule.AddSuccessor(B, D); + schedule.AddSuccessor(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 4, false); + + CHECK_EQ(0, A->rpo_number_); + CHECK((B->rpo_number_ == 1 && C->rpo_number_ == 2) || + (B->rpo_number_ == 2 && C->rpo_number_ == 1)); + CHECK_EQ(3, D->rpo_number_); +} + + +TEST(RPOLoop1) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(C, B); + schedule.AddSuccessor(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoopContains(loop, 2); +} + + +TEST(RPOLoop2) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(C, B); + schedule.AddSuccessor(B, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoopContains(loop, 2); +} + + +TEST(RPOLoopN) { + HandleAndZoneScope scope; + + for (int i = 0; i < 11; i++) { + Schedule schedule(scope.main_zone()); + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(C, D); + schedule.AddSuccessor(D, E); + schedule.AddSuccessor(E, F); + schedule.AddSuccessor(F, B); + schedule.AddSuccessor(B, G); + + // Throw in extra backedges from time to time. + if (i == 1) schedule.AddSuccessor(B, B); + if (i == 2) schedule.AddSuccessor(C, B); + if (i == 3) schedule.AddSuccessor(D, B); + if (i == 4) schedule.AddSuccessor(E, B); + if (i == 5) schedule.AddSuccessor(F, B); + + // Throw in extra loop exits from time to time. + if (i == 6) schedule.AddSuccessor(B, G); + if (i == 7) schedule.AddSuccessor(C, G); + if (i == 8) schedule.AddSuccessor(D, G); + if (i == 9) schedule.AddSuccessor(E, G); + if (i == 10) schedule.AddSuccessor(F, G); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 7, true); + BasicBlock* loop[] = {B, C, D, E, F}; + CheckLoopContains(loop, 5); + } +} + + +TEST(RPOLoopNest1) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(C, D); + schedule.AddSuccessor(D, C); + schedule.AddSuccessor(D, E); + schedule.AddSuccessor(E, B); + schedule.AddSuccessor(E, F); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 6, true); + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoopContains(loop1, 4); + + BasicBlock* loop2[] = {C, D}; + CheckLoopContains(loop2, 2); +} + + +TEST(RPOLoopNest2) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.NewBasicBlock(); + BasicBlock* H = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(C, D); + schedule.AddSuccessor(D, E); + schedule.AddSuccessor(E, F); + schedule.AddSuccessor(F, G); + schedule.AddSuccessor(G, H); + + schedule.AddSuccessor(E, D); + schedule.AddSuccessor(F, C); + schedule.AddSuccessor(G, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 8, true); + BasicBlock* loop1[] = {B, C, D, E, F, G}; + CheckLoopContains(loop1, 6); + + BasicBlock* loop2[] = {C, D, E, F}; + CheckLoopContains(loop2, 4); + + BasicBlock* loop3[] = {D, E}; + CheckLoopContains(loop3, 2); +} + + +TEST(RPOLoopFollow1) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.entry(); + BasicBlock* E = schedule.exit(); + + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->header(), loop2->header()); + schedule.AddSuccessor(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + + CheckLoopContains(loop1->nodes, loop1->count); + + CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); + CheckLoopContains(loop1->nodes, loop1->count); + CheckLoopContains(loop2->nodes, loop2->count); +} + + +TEST(RPOLoopFollow2) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.entry(); + BasicBlock* S = schedule.NewBasicBlock(); + BasicBlock* E = schedule.exit(); + + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->header(), S); + schedule.AddSuccessor(S, loop2->header()); + schedule.AddSuccessor(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + + CheckLoopContains(loop1->nodes, loop1->count); + + CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); + CheckLoopContains(loop1->nodes, loop1->count); + CheckLoopContains(loop2->nodes, loop2->count); +} + + +TEST(RPOLoopFollowN) { + HandleAndZoneScope scope; + + for (int size = 1; size < 5; size++) { + for (int exit = 0; exit < size; exit++) { + Schedule schedule(scope.main_zone()); + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); + BasicBlock* A = schedule.entry(); + BasicBlock* E = schedule.exit(); + + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->nodes[exit], loop2->header()); + schedule.AddSuccessor(loop2->nodes[exit], E); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckLoopContains(loop1->nodes, loop1->count); + + CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); + CheckLoopContains(loop1->nodes, loop1->count); + CheckLoopContains(loop2->nodes, loop2->count); + } + } +} + + +TEST(RPONestedLoopFollow1) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* E = schedule.exit(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, loop1->header()); + schedule.AddSuccessor(loop1->header(), loop2->header()); + schedule.AddSuccessor(loop2->last(), C); + schedule.AddSuccessor(C, E); + schedule.AddSuccessor(C, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + + CheckLoopContains(loop1->nodes, loop1->count); + + CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size())); + CheckLoopContains(loop1->nodes, loop1->count); + CheckLoopContains(loop2->nodes, loop2->count); + + BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C}; + CheckLoopContains(loop3, 4); +} + + +TEST(RPOLoopBackedges1) { + HandleAndZoneScope scope; + + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(scope.main_zone()); + BasicBlock* A = schedule.entry(); + BasicBlock* E = schedule.exit(); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->last(), E); + + schedule.AddSuccessor(loop1->nodes[i], loop1->header()); + schedule.AddSuccessor(loop1->nodes[j], E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoopContains(loop1->nodes, loop1->count); + } + } +} + + +TEST(RPOLoopOutedges1) { + HandleAndZoneScope scope; + + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(scope.main_zone()); + BasicBlock* A = schedule.entry(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.exit(); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->last(), E); + + schedule.AddSuccessor(loop1->nodes[i], loop1->header()); + schedule.AddSuccessor(loop1->nodes[j], D); + schedule.AddSuccessor(D, E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoopContains(loop1->nodes, loop1->count); + } + } +} + + +TEST(RPOLoopOutedges2) { + HandleAndZoneScope scope; + + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(scope.main_zone()); + BasicBlock* A = schedule.entry(); + BasicBlock* E = schedule.exit(); + + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->last(), E); + + for (int j = 0; j < size; j++) { + BasicBlock* O = schedule.NewBasicBlock(); + schedule.AddSuccessor(loop1->nodes[j], O); + schedule.AddSuccessor(O, E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoopContains(loop1->nodes, loop1->count); + } +} + + +TEST(RPOLoopOutloops1) { + HandleAndZoneScope scope; + + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(scope.main_zone()); + BasicBlock* A = schedule.entry(); + BasicBlock* E = schedule.exit(); + SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessor(A, loop1->header()); + schedule.AddSuccessor(loop1->last(), E); + + TestLoop** loopN = new TestLoop* [size]; + for (int j = 0; j < size; j++) { + loopN[j] = CreateLoop(&schedule, 2); + schedule.AddSuccessor(loop1->nodes[j], loopN[j]->header()); + schedule.AddSuccessor(loopN[j]->last(), E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoopContains(loop1->nodes, loop1->count); + + for (int j = 0; j < size; j++) { + CheckLoopContains(loopN[j]->nodes, loopN[j]->count); + delete loopN[j]; + } + delete[] loopN; + } +} + + +TEST(RPOLoopMultibackedge) { + HandleAndZoneScope scope; + Schedule schedule(scope.main_zone()); + + BasicBlock* A = schedule.entry(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.exit(); + BasicBlock* E = schedule.NewBasicBlock(); + + schedule.AddSuccessor(A, B); + schedule.AddSuccessor(B, C); + schedule.AddSuccessor(B, D); + schedule.AddSuccessor(B, E); + schedule.AddSuccessor(C, B); + schedule.AddSuccessor(D, B); + schedule.AddSuccessor(E, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule); + CheckRPONumbers(order, 5, true); + + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoopContains(loop1, 4); +} + + +TEST(BuildScheduleEmpty) { + HandleAndZoneScope scope; + Graph graph(scope.main_zone()); + CommonOperatorBuilder builder(scope.main_zone()); + graph.SetStart(graph.NewNode(builder.Start(0))); + graph.SetEnd(graph.NewNode(builder.End(), graph.start())); + + USE(Scheduler::ComputeSchedule(&graph)); +} + + +TEST(BuildScheduleOneParameter) { + HandleAndZoneScope scope; + Graph graph(scope.main_zone()); + CommonOperatorBuilder builder(scope.main_zone()); + graph.SetStart(graph.NewNode(builder.Start(0))); + + Node* p1 = graph.NewNode(builder.Parameter(0), graph.start()); + Node* ret = graph.NewNode(builder.Return(), p1, graph.start(), graph.start()); + + graph.SetEnd(graph.NewNode(builder.End(), ret)); + + USE(Scheduler::ComputeSchedule(&graph)); +} + + +static int GetScheduledNodeCount(Schedule* schedule) { + int node_count = 0; + for (BasicBlockVectorIter i = schedule->rpo_order()->begin(); + i != schedule->rpo_order()->end(); ++i) { + BasicBlock* block = *i; + for (BasicBlock::const_iterator j = block->begin(); j != block->end(); + ++j) { + ++node_count; + } + BasicBlock::Control control = block->control_; + if (control != BasicBlock::kNone) { + ++node_count; + } + } + return node_count; +} + + +static void PrintGraph(Graph* graph) { + OFStream os(stdout); + os << AsDOT(*graph); +} + + +static void PrintSchedule(Schedule* schedule) { + OFStream os(stdout); + os << *schedule << endl; +} + + +TEST(BuildScheduleIfSplit) { + HandleAndZoneScope scope; + Graph graph(scope.main_zone()); + CommonOperatorBuilder builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + graph.SetStart(graph.NewNode(builder.Start(3))); + + Node* p1 = graph.NewNode(builder.Parameter(0), graph.start()); + Node* p2 = graph.NewNode(builder.Parameter(1), graph.start()); + Node* p3 = graph.NewNode(builder.Parameter(2), graph.start()); + Node* p4 = graph.NewNode(builder.Parameter(3), graph.start()); + Node* p5 = graph.NewNode(builder.Parameter(4), graph.start()); + Node* cmp = graph.NewNode(js_builder.LessThanOrEqual(), p1, p2, p3, + graph.start(), graph.start()); + Node* branch = graph.NewNode(builder.Branch(), cmp, graph.start()); + Node* true_branch = graph.NewNode(builder.IfTrue(), branch); + Node* false_branch = graph.NewNode(builder.IfFalse(), branch); + + Node* ret1 = graph.NewNode(builder.Return(), p4, graph.start(), true_branch); + Node* ret2 = graph.NewNode(builder.Return(), p5, graph.start(), false_branch); + Node* merge = graph.NewNode(builder.Merge(2), ret1, ret2); + graph.SetEnd(graph.NewNode(builder.End(), merge)); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + + CHECK_EQ(13, GetScheduledNodeCount(schedule)); +} + + +TEST(BuildScheduleIfSplitWithEffects) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common_builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + Operator* op; + + Handle<Object> object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> unique_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), object); + + // Manually transcripted code for: + // function turbo_fan_test(a, b, c, y) { + // if (a < b) { + // return a + b - c * c - a + y; + // } else { + // return c * c - a; + // } + // } + op = common_builder.Start(0); + Node* n0 = graph.NewNode(op); + USE(n0); + Node* nil = graph.NewNode(common_builder.Dead()); + op = common_builder.End(); + Node* n23 = graph.NewNode(op, nil); + USE(n23); + op = common_builder.Merge(2); + Node* n22 = graph.NewNode(op, nil, nil); + USE(n22); + op = common_builder.Return(); + Node* n16 = graph.NewNode(op, nil, nil, nil); + USE(n16); + op = js_builder.Add(); + Node* n15 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n15); + op = js_builder.Subtract(); + Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n14); + op = js_builder.Subtract(); + Node* n13 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n13); + op = js_builder.Add(); + Node* n11 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n11); + op = common_builder.Parameter(0); + Node* n2 = graph.NewNode(op, n0); + USE(n2); + n11->ReplaceInput(0, n2); + op = common_builder.Parameter(0); + Node* n3 = graph.NewNode(op, n0); + USE(n3); + n11->ReplaceInput(1, n3); + op = common_builder.HeapConstant(unique_constant); + Node* n7 = graph.NewNode(op); + USE(n7); + n11->ReplaceInput(2, n7); + op = js_builder.LessThan(); + Node* n8 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n8); + n8->ReplaceInput(0, n2); + n8->ReplaceInput(1, n3); + n8->ReplaceInput(2, n7); + n8->ReplaceInput(3, n0); + n8->ReplaceInput(4, n0); + n11->ReplaceInput(3, n8); + op = common_builder.IfTrue(); + Node* n10 = graph.NewNode(op, nil); + USE(n10); + op = common_builder.Branch(); + Node* n9 = graph.NewNode(op, nil, nil); + USE(n9); + n9->ReplaceInput(0, n8); + n9->ReplaceInput(1, n0); + n10->ReplaceInput(0, n9); + n11->ReplaceInput(4, n10); + n13->ReplaceInput(0, n11); + op = js_builder.Multiply(); + Node* n12 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n12); + op = common_builder.Parameter(0); + Node* n4 = graph.NewNode(op, n0); + USE(n4); + n12->ReplaceInput(0, n4); + n12->ReplaceInput(1, n4); + n12->ReplaceInput(2, n7); + n12->ReplaceInput(3, n11); + n12->ReplaceInput(4, n10); + n13->ReplaceInput(1, n12); + n13->ReplaceInput(2, n7); + n13->ReplaceInput(3, n12); + n13->ReplaceInput(4, n10); + n14->ReplaceInput(0, n13); + n14->ReplaceInput(1, n2); + n14->ReplaceInput(2, n7); + n14->ReplaceInput(3, n13); + n14->ReplaceInput(4, n10); + n15->ReplaceInput(0, n14); + op = common_builder.Parameter(0); + Node* n5 = graph.NewNode(op, n0); + USE(n5); + n15->ReplaceInput(1, n5); + n15->ReplaceInput(2, n7); + n15->ReplaceInput(3, n14); + n15->ReplaceInput(4, n10); + n16->ReplaceInput(0, n15); + n16->ReplaceInput(1, n15); + n16->ReplaceInput(2, n10); + n22->ReplaceInput(0, n16); + op = common_builder.Return(); + Node* n21 = graph.NewNode(op, nil, nil, nil); + USE(n21); + op = js_builder.Subtract(); + Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n20); + op = js_builder.Multiply(); + Node* n19 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n19); + n19->ReplaceInput(0, n4); + n19->ReplaceInput(1, n4); + n19->ReplaceInput(2, n7); + n19->ReplaceInput(3, n8); + op = common_builder.IfFalse(); + Node* n18 = graph.NewNode(op, nil); + USE(n18); + n18->ReplaceInput(0, n9); + n19->ReplaceInput(4, n18); + n20->ReplaceInput(0, n19); + n20->ReplaceInput(1, n2); + n20->ReplaceInput(2, n7); + n20->ReplaceInput(3, n19); + n20->ReplaceInput(4, n18); + n21->ReplaceInput(0, n20); + n21->ReplaceInput(1, n20); + n21->ReplaceInput(2, n18); + n22->ReplaceInput(1, n21); + n23->ReplaceInput(0, n22); + + graph.SetStart(n0); + graph.SetEnd(n23); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + CHECK_EQ(20, GetScheduledNodeCount(schedule)); +} + + +TEST(BuildScheduleSimpleLoop) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common_builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + Operator* op; + + Handle<Object> object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> unique_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), object); + + // Manually transcripted code for: + // function turbo_fan_test(a, b) { + // while (a < b) { + // a++; + // } + // return a; + // } + op = common_builder.Start(0); + Node* n0 = graph.NewNode(op); + USE(n0); + Node* nil = graph.NewNode(common_builder.Dead()); + op = common_builder.End(); + Node* n20 = graph.NewNode(op, nil); + USE(n20); + op = common_builder.Return(); + Node* n19 = graph.NewNode(op, nil, nil, nil); + USE(n19); + op = common_builder.Phi(2); + Node* n8 = graph.NewNode(op, nil, nil, nil); + USE(n8); + op = common_builder.Parameter(0); + Node* n2 = graph.NewNode(op, n0); + USE(n2); + n8->ReplaceInput(0, n2); + op = js_builder.Add(); + Node* n18 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n18); + op = js_builder.ToNumber(); + Node* n16 = graph.NewNode(op, nil, nil, nil, nil); + USE(n16); + n16->ReplaceInput(0, n8); + op = common_builder.HeapConstant(unique_constant); + Node* n5 = graph.NewNode(op); + USE(n5); + n16->ReplaceInput(1, n5); + op = js_builder.LessThan(); + Node* n12 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n12); + n12->ReplaceInput(0, n8); + op = common_builder.Phi(2); + Node* n9 = graph.NewNode(op, nil, nil, nil); + USE(n9); + op = common_builder.Parameter(0); + Node* n3 = graph.NewNode(op, n0); + USE(n3); + n9->ReplaceInput(0, n3); + n9->ReplaceInput(1, n9); + op = common_builder.Loop(2); + Node* n6 = graph.NewNode(op, nil, nil); + USE(n6); + n6->ReplaceInput(0, n0); + op = common_builder.IfTrue(); + Node* n14 = graph.NewNode(op, nil); + USE(n14); + op = common_builder.Branch(); + Node* n13 = graph.NewNode(op, nil, nil); + USE(n13); + n13->ReplaceInput(0, n12); + n13->ReplaceInput(1, n6); + n14->ReplaceInput(0, n13); + n6->ReplaceInput(1, n14); + n9->ReplaceInput(2, n6); + n12->ReplaceInput(1, n9); + n12->ReplaceInput(2, n5); + op = common_builder.Phi(2); + Node* n10 = graph.NewNode(op, nil, nil, nil); + USE(n10); + n10->ReplaceInput(0, n0); + n10->ReplaceInput(1, n18); + n10->ReplaceInput(2, n6); + n12->ReplaceInput(3, n10); + n12->ReplaceInput(4, n6); + n16->ReplaceInput(2, n12); + n16->ReplaceInput(3, n14); + n18->ReplaceInput(0, n16); + op = common_builder.NumberConstant(0); + Node* n17 = graph.NewNode(op); + USE(n17); + n18->ReplaceInput(1, n17); + n18->ReplaceInput(2, n5); + n18->ReplaceInput(3, n16); + n18->ReplaceInput(4, n14); + n8->ReplaceInput(1, n18); + n8->ReplaceInput(2, n6); + n19->ReplaceInput(0, n8); + n19->ReplaceInput(1, n12); + op = common_builder.IfFalse(); + Node* n15 = graph.NewNode(op, nil); + USE(n15); + n15->ReplaceInput(0, n13); + n19->ReplaceInput(2, n15); + n20->ReplaceInput(0, n19); + + graph.SetStart(n0); + graph.SetEnd(n20); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + CHECK_EQ(19, GetScheduledNodeCount(schedule)); +} + + +TEST(BuildScheduleComplexLoops) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common_builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + Operator* op; + + Handle<Object> object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> unique_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), object); + + // Manually transcripted code for: + // function turbo_fan_test(a, b, c) { + // while (a < b) { + // a++; + // while (c < b) { + // c++; + // } + // } + // while (a < b) { + // a += 2; + // } + // return a; + // } + op = common_builder.Start(0); + Node* n0 = graph.NewNode(op); + USE(n0); + Node* nil = graph.NewNode(common_builder.Dead()); + op = common_builder.End(); + Node* n46 = graph.NewNode(op, nil); + USE(n46); + op = common_builder.Return(); + Node* n45 = graph.NewNode(op, nil, nil, nil); + USE(n45); + op = common_builder.Phi(2); + Node* n35 = graph.NewNode(op, nil, nil, nil); + USE(n35); + op = common_builder.Phi(2); + Node* n9 = graph.NewNode(op, nil, nil, nil); + USE(n9); + op = common_builder.Parameter(0); + Node* n2 = graph.NewNode(op, n0); + USE(n2); + n9->ReplaceInput(0, n2); + op = common_builder.Phi(2); + Node* n23 = graph.NewNode(op, nil, nil, nil); + USE(n23); + op = js_builder.Add(); + Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n20); + op = js_builder.ToNumber(); + Node* n18 = graph.NewNode(op, nil, nil, nil, nil); + USE(n18); + n18->ReplaceInput(0, n9); + op = common_builder.HeapConstant(unique_constant); + Node* n6 = graph.NewNode(op); + USE(n6); + n18->ReplaceInput(1, n6); + op = js_builder.LessThan(); + Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n14); + n14->ReplaceInput(0, n9); + op = common_builder.Phi(2); + Node* n10 = graph.NewNode(op, nil, nil, nil); + USE(n10); + op = common_builder.Parameter(0); + Node* n3 = graph.NewNode(op, n0); + USE(n3); + n10->ReplaceInput(0, n3); + op = common_builder.Phi(2); + Node* n24 = graph.NewNode(op, nil, nil, nil); + USE(n24); + n24->ReplaceInput(0, n10); + n24->ReplaceInput(1, n24); + op = common_builder.Loop(2); + Node* n21 = graph.NewNode(op, nil, nil); + USE(n21); + op = common_builder.IfTrue(); + Node* n16 = graph.NewNode(op, nil); + USE(n16); + op = common_builder.Branch(); + Node* n15 = graph.NewNode(op, nil, nil); + USE(n15); + n15->ReplaceInput(0, n14); + op = common_builder.Loop(2); + Node* n7 = graph.NewNode(op, nil, nil); + USE(n7); + n7->ReplaceInput(0, n0); + op = common_builder.IfFalse(); + Node* n30 = graph.NewNode(op, nil); + USE(n30); + op = common_builder.Branch(); + Node* n28 = graph.NewNode(op, nil, nil); + USE(n28); + op = js_builder.LessThan(); + Node* n27 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n27); + op = common_builder.Phi(2); + Node* n25 = graph.NewNode(op, nil, nil, nil); + USE(n25); + op = common_builder.Phi(2); + Node* n11 = graph.NewNode(op, nil, nil, nil); + USE(n11); + op = common_builder.Parameter(0); + Node* n4 = graph.NewNode(op, n0); + USE(n4); + n11->ReplaceInput(0, n4); + n11->ReplaceInput(1, n25); + n11->ReplaceInput(2, n7); + n25->ReplaceInput(0, n11); + op = js_builder.Add(); + Node* n32 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n32); + op = js_builder.ToNumber(); + Node* n31 = graph.NewNode(op, nil, nil, nil, nil); + USE(n31); + n31->ReplaceInput(0, n25); + n31->ReplaceInput(1, n6); + n31->ReplaceInput(2, n27); + op = common_builder.IfTrue(); + Node* n29 = graph.NewNode(op, nil); + USE(n29); + n29->ReplaceInput(0, n28); + n31->ReplaceInput(3, n29); + n32->ReplaceInput(0, n31); + op = common_builder.NumberConstant(0); + Node* n19 = graph.NewNode(op); + USE(n19); + n32->ReplaceInput(1, n19); + n32->ReplaceInput(2, n6); + n32->ReplaceInput(3, n31); + n32->ReplaceInput(4, n29); + n25->ReplaceInput(1, n32); + n25->ReplaceInput(2, n21); + n27->ReplaceInput(0, n25); + n27->ReplaceInput(1, n24); + n27->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n26 = graph.NewNode(op, nil, nil, nil); + USE(n26); + n26->ReplaceInput(0, n20); + n26->ReplaceInput(1, n32); + n26->ReplaceInput(2, n21); + n27->ReplaceInput(3, n26); + n27->ReplaceInput(4, n21); + n28->ReplaceInput(0, n27); + n28->ReplaceInput(1, n21); + n30->ReplaceInput(0, n28); + n7->ReplaceInput(1, n30); + n15->ReplaceInput(1, n7); + n16->ReplaceInput(0, n15); + n21->ReplaceInput(0, n16); + n21->ReplaceInput(1, n29); + n24->ReplaceInput(2, n21); + n10->ReplaceInput(1, n24); + n10->ReplaceInput(2, n7); + n14->ReplaceInput(1, n10); + n14->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n12 = graph.NewNode(op, nil, nil, nil); + USE(n12); + n12->ReplaceInput(0, n0); + n12->ReplaceInput(1, n27); + n12->ReplaceInput(2, n7); + n14->ReplaceInput(3, n12); + n14->ReplaceInput(4, n7); + n18->ReplaceInput(2, n14); + n18->ReplaceInput(3, n16); + n20->ReplaceInput(0, n18); + n20->ReplaceInput(1, n19); + n20->ReplaceInput(2, n6); + n20->ReplaceInput(3, n18); + n20->ReplaceInput(4, n16); + n23->ReplaceInput(0, n20); + n23->ReplaceInput(1, n23); + n23->ReplaceInput(2, n21); + n9->ReplaceInput(1, n23); + n9->ReplaceInput(2, n7); + n35->ReplaceInput(0, n9); + op = js_builder.Add(); + Node* n44 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n44); + n44->ReplaceInput(0, n35); + op = common_builder.NumberConstant(0); + Node* n43 = graph.NewNode(op); + USE(n43); + n44->ReplaceInput(1, n43); + n44->ReplaceInput(2, n6); + op = js_builder.LessThan(); + Node* n39 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n39); + n39->ReplaceInput(0, n35); + op = common_builder.Phi(2); + Node* n36 = graph.NewNode(op, nil, nil, nil); + USE(n36); + n36->ReplaceInput(0, n10); + n36->ReplaceInput(1, n36); + op = common_builder.Loop(2); + Node* n33 = graph.NewNode(op, nil, nil); + USE(n33); + op = common_builder.IfFalse(); + Node* n17 = graph.NewNode(op, nil); + USE(n17); + n17->ReplaceInput(0, n15); + n33->ReplaceInput(0, n17); + op = common_builder.IfTrue(); + Node* n41 = graph.NewNode(op, nil); + USE(n41); + op = common_builder.Branch(); + Node* n40 = graph.NewNode(op, nil, nil); + USE(n40); + n40->ReplaceInput(0, n39); + n40->ReplaceInput(1, n33); + n41->ReplaceInput(0, n40); + n33->ReplaceInput(1, n41); + n36->ReplaceInput(2, n33); + n39->ReplaceInput(1, n36); + n39->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n38 = graph.NewNode(op, nil, nil, nil); + USE(n38); + n38->ReplaceInput(0, n14); + n38->ReplaceInput(1, n44); + n38->ReplaceInput(2, n33); + n39->ReplaceInput(3, n38); + n39->ReplaceInput(4, n33); + n44->ReplaceInput(3, n39); + n44->ReplaceInput(4, n41); + n35->ReplaceInput(1, n44); + n35->ReplaceInput(2, n33); + n45->ReplaceInput(0, n35); + n45->ReplaceInput(1, n39); + op = common_builder.IfFalse(); + Node* n42 = graph.NewNode(op, nil); + USE(n42); + n42->ReplaceInput(0, n40); + n45->ReplaceInput(2, n42); + n46->ReplaceInput(0, n45); + + graph.SetStart(n0); + graph.SetEnd(n46); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + CHECK_EQ(46, GetScheduledNodeCount(schedule)); +} + + +TEST(BuildScheduleBreakAndContinue) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common_builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + Operator* op; + + Handle<Object> object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> unique_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), object); + + // Manually transcripted code for: + // function turbo_fan_test(a, b, c) { + // var d = 0; + // while (a < b) { + // a++; + // while (c < b) { + // c++; + // if (d == 0) break; + // a++; + // } + // if (a == 1) continue; + // d++; + // } + // return a + d; + // } + op = common_builder.Start(0); + Node* n0 = graph.NewNode(op); + USE(n0); + Node* nil = graph.NewNode(common_builder.Dead()); + op = common_builder.End(); + Node* n58 = graph.NewNode(op, nil); + USE(n58); + op = common_builder.Return(); + Node* n57 = graph.NewNode(op, nil, nil, nil); + USE(n57); + op = js_builder.Add(); + Node* n56 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n56); + op = common_builder.Phi(2); + Node* n10 = graph.NewNode(op, nil, nil, nil); + USE(n10); + op = common_builder.Parameter(0); + Node* n2 = graph.NewNode(op, n0); + USE(n2); + n10->ReplaceInput(0, n2); + op = common_builder.Phi(2); + Node* n25 = graph.NewNode(op, nil, nil, nil); + USE(n25); + op = js_builder.Add(); + Node* n22 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n22); + op = js_builder.ToNumber(); + Node* n20 = graph.NewNode(op, nil, nil, nil, nil); + USE(n20); + n20->ReplaceInput(0, n10); + op = common_builder.HeapConstant(unique_constant); + Node* n6 = graph.NewNode(op); + USE(n6); + n20->ReplaceInput(1, n6); + op = js_builder.LessThan(); + Node* n16 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n16); + n16->ReplaceInput(0, n10); + op = common_builder.Phi(2); + Node* n11 = graph.NewNode(op, nil, nil, nil); + USE(n11); + op = common_builder.Parameter(0); + Node* n3 = graph.NewNode(op, n0); + USE(n3); + n11->ReplaceInput(0, n3); + op = common_builder.Phi(2); + Node* n26 = graph.NewNode(op, nil, nil, nil); + USE(n26); + n26->ReplaceInput(0, n11); + n26->ReplaceInput(1, n26); + op = common_builder.Loop(2); + Node* n23 = graph.NewNode(op, nil, nil); + USE(n23); + op = common_builder.IfTrue(); + Node* n18 = graph.NewNode(op, nil); + USE(n18); + op = common_builder.Branch(); + Node* n17 = graph.NewNode(op, nil, nil); + USE(n17); + n17->ReplaceInput(0, n16); + op = common_builder.Loop(2); + Node* n8 = graph.NewNode(op, nil, nil); + USE(n8); + n8->ReplaceInput(0, n0); + op = common_builder.Merge(2); + Node* n53 = graph.NewNode(op, nil, nil); + USE(n53); + op = common_builder.IfTrue(); + Node* n49 = graph.NewNode(op, nil); + USE(n49); + op = common_builder.Branch(); + Node* n48 = graph.NewNode(op, nil, nil); + USE(n48); + op = js_builder.Equal(); + Node* n47 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n47); + n47->ReplaceInput(0, n25); + op = common_builder.NumberConstant(0); + Node* n46 = graph.NewNode(op); + USE(n46); + n47->ReplaceInput(1, n46); + n47->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n42 = graph.NewNode(op, nil, nil, nil); + USE(n42); + op = js_builder.LessThan(); + Node* n30 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n30); + op = common_builder.Phi(2); + Node* n27 = graph.NewNode(op, nil, nil, nil); + USE(n27); + op = common_builder.Phi(2); + Node* n12 = graph.NewNode(op, nil, nil, nil); + USE(n12); + op = common_builder.Parameter(0); + Node* n4 = graph.NewNode(op, n0); + USE(n4); + n12->ReplaceInput(0, n4); + op = common_builder.Phi(2); + Node* n41 = graph.NewNode(op, nil, nil, nil); + USE(n41); + n41->ReplaceInput(0, n27); + op = js_builder.Add(); + Node* n35 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n35); + op = js_builder.ToNumber(); + Node* n34 = graph.NewNode(op, nil, nil, nil, nil); + USE(n34); + n34->ReplaceInput(0, n27); + n34->ReplaceInput(1, n6); + n34->ReplaceInput(2, n30); + op = common_builder.IfTrue(); + Node* n32 = graph.NewNode(op, nil); + USE(n32); + op = common_builder.Branch(); + Node* n31 = graph.NewNode(op, nil, nil); + USE(n31); + n31->ReplaceInput(0, n30); + n31->ReplaceInput(1, n23); + n32->ReplaceInput(0, n31); + n34->ReplaceInput(3, n32); + n35->ReplaceInput(0, n34); + op = common_builder.NumberConstant(0); + Node* n21 = graph.NewNode(op); + USE(n21); + n35->ReplaceInput(1, n21); + n35->ReplaceInput(2, n6); + n35->ReplaceInput(3, n34); + n35->ReplaceInput(4, n32); + n41->ReplaceInput(1, n35); + op = common_builder.Merge(2); + Node* n40 = graph.NewNode(op, nil, nil); + USE(n40); + op = common_builder.IfFalse(); + Node* n33 = graph.NewNode(op, nil); + USE(n33); + n33->ReplaceInput(0, n31); + n40->ReplaceInput(0, n33); + op = common_builder.IfTrue(); + Node* n39 = graph.NewNode(op, nil); + USE(n39); + op = common_builder.Branch(); + Node* n38 = graph.NewNode(op, nil, nil); + USE(n38); + op = js_builder.Equal(); + Node* n37 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n37); + op = common_builder.Phi(2); + Node* n28 = graph.NewNode(op, nil, nil, nil); + USE(n28); + op = common_builder.Phi(2); + Node* n13 = graph.NewNode(op, nil, nil, nil); + USE(n13); + op = common_builder.NumberConstant(0); + Node* n7 = graph.NewNode(op); + USE(n7); + n13->ReplaceInput(0, n7); + op = common_builder.Phi(2); + Node* n54 = graph.NewNode(op, nil, nil, nil); + USE(n54); + n54->ReplaceInput(0, n28); + op = js_builder.Add(); + Node* n52 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n52); + op = js_builder.ToNumber(); + Node* n51 = graph.NewNode(op, nil, nil, nil, nil); + USE(n51); + n51->ReplaceInput(0, n28); + n51->ReplaceInput(1, n6); + n51->ReplaceInput(2, n47); + op = common_builder.IfFalse(); + Node* n50 = graph.NewNode(op, nil); + USE(n50); + n50->ReplaceInput(0, n48); + n51->ReplaceInput(3, n50); + n52->ReplaceInput(0, n51); + n52->ReplaceInput(1, n21); + n52->ReplaceInput(2, n6); + n52->ReplaceInput(3, n51); + n52->ReplaceInput(4, n50); + n54->ReplaceInput(1, n52); + n54->ReplaceInput(2, n53); + n13->ReplaceInput(1, n54); + n13->ReplaceInput(2, n8); + n28->ReplaceInput(0, n13); + n28->ReplaceInput(1, n28); + n28->ReplaceInput(2, n23); + n37->ReplaceInput(0, n28); + op = common_builder.NumberConstant(0); + Node* n36 = graph.NewNode(op); + USE(n36); + n37->ReplaceInput(1, n36); + n37->ReplaceInput(2, n6); + n37->ReplaceInput(3, n35); + n37->ReplaceInput(4, n32); + n38->ReplaceInput(0, n37); + n38->ReplaceInput(1, n32); + n39->ReplaceInput(0, n38); + n40->ReplaceInput(1, n39); + n41->ReplaceInput(2, n40); + n12->ReplaceInput(1, n41); + n12->ReplaceInput(2, n8); + n27->ReplaceInput(0, n12); + n27->ReplaceInput(1, n35); + n27->ReplaceInput(2, n23); + n30->ReplaceInput(0, n27); + n30->ReplaceInput(1, n26); + n30->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n29 = graph.NewNode(op, nil, nil, nil); + USE(n29); + n29->ReplaceInput(0, n22); + op = js_builder.Add(); + Node* n45 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n45); + op = js_builder.ToNumber(); + Node* n44 = graph.NewNode(op, nil, nil, nil, nil); + USE(n44); + n44->ReplaceInput(0, n25); + n44->ReplaceInput(1, n6); + n44->ReplaceInput(2, n37); + op = common_builder.IfFalse(); + Node* n43 = graph.NewNode(op, nil); + USE(n43); + n43->ReplaceInput(0, n38); + n44->ReplaceInput(3, n43); + n45->ReplaceInput(0, n44); + n45->ReplaceInput(1, n21); + n45->ReplaceInput(2, n6); + n45->ReplaceInput(3, n44); + n45->ReplaceInput(4, n43); + n29->ReplaceInput(1, n45); + n29->ReplaceInput(2, n23); + n30->ReplaceInput(3, n29); + n30->ReplaceInput(4, n23); + n42->ReplaceInput(0, n30); + n42->ReplaceInput(1, n37); + n42->ReplaceInput(2, n40); + n47->ReplaceInput(3, n42); + n47->ReplaceInput(4, n40); + n48->ReplaceInput(0, n47); + n48->ReplaceInput(1, n40); + n49->ReplaceInput(0, n48); + n53->ReplaceInput(0, n49); + n53->ReplaceInput(1, n50); + n8->ReplaceInput(1, n53); + n17->ReplaceInput(1, n8); + n18->ReplaceInput(0, n17); + n23->ReplaceInput(0, n18); + n23->ReplaceInput(1, n43); + n26->ReplaceInput(2, n23); + n11->ReplaceInput(1, n26); + n11->ReplaceInput(2, n8); + n16->ReplaceInput(1, n11); + n16->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n14 = graph.NewNode(op, nil, nil, nil); + USE(n14); + n14->ReplaceInput(0, n0); + op = common_builder.Phi(2); + Node* n55 = graph.NewNode(op, nil, nil, nil); + USE(n55); + n55->ReplaceInput(0, n47); + n55->ReplaceInput(1, n52); + n55->ReplaceInput(2, n53); + n14->ReplaceInput(1, n55); + n14->ReplaceInput(2, n8); + n16->ReplaceInput(3, n14); + n16->ReplaceInput(4, n8); + n20->ReplaceInput(2, n16); + n20->ReplaceInput(3, n18); + n22->ReplaceInput(0, n20); + n22->ReplaceInput(1, n21); + n22->ReplaceInput(2, n6); + n22->ReplaceInput(3, n20); + n22->ReplaceInput(4, n18); + n25->ReplaceInput(0, n22); + n25->ReplaceInput(1, n45); + n25->ReplaceInput(2, n23); + n10->ReplaceInput(1, n25); + n10->ReplaceInput(2, n8); + n56->ReplaceInput(0, n10); + n56->ReplaceInput(1, n13); + n56->ReplaceInput(2, n6); + n56->ReplaceInput(3, n16); + op = common_builder.IfFalse(); + Node* n19 = graph.NewNode(op, nil); + USE(n19); + n19->ReplaceInput(0, n17); + n56->ReplaceInput(4, n19); + n57->ReplaceInput(0, n56); + n57->ReplaceInput(1, n56); + n57->ReplaceInput(2, n19); + n58->ReplaceInput(0, n57); + + graph.SetStart(n0); + graph.SetEnd(n58); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + CHECK_EQ(62, GetScheduledNodeCount(schedule)); +} + + +TEST(BuildScheduleSimpleLoopWithCodeMotion) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common_builder(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + MachineOperatorBuilder machine_builder(scope.main_zone(), kMachineWord32); + Operator* op; + + Handle<Object> object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> unique_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), object); + + // Manually transcripted code for: + // function turbo_fan_test(a, b, c) { + // while (a < b) { + // a += b + c; + // } + // return a; + // } + op = common_builder.Start(0); + Node* n0 = graph.NewNode(op); + USE(n0); + Node* nil = graph.NewNode(common_builder.Dead()); + op = common_builder.End(); + Node* n22 = graph.NewNode(op, nil); + USE(n22); + op = common_builder.Return(); + Node* n21 = graph.NewNode(op, nil, nil, nil); + USE(n21); + op = common_builder.Phi(2); + Node* n9 = graph.NewNode(op, nil, nil, nil); + USE(n9); + op = common_builder.Parameter(0); + Node* n2 = graph.NewNode(op, n0); + USE(n2); + n9->ReplaceInput(0, n2); + op = js_builder.Add(); + Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n20); + n20->ReplaceInput(0, n9); + op = machine_builder.Int32Add(); + Node* n19 = graph.NewNode(op, nil, nil); + USE(n19); + op = common_builder.Phi(2); + Node* n10 = graph.NewNode(op, nil, nil, nil); + USE(n10); + op = common_builder.Parameter(0); + Node* n3 = graph.NewNode(op, n0); + USE(n3); + n10->ReplaceInput(0, n3); + n10->ReplaceInput(1, n10); + op = common_builder.Loop(2); + Node* n7 = graph.NewNode(op, nil, nil); + USE(n7); + n7->ReplaceInput(0, n0); + op = common_builder.IfTrue(); + Node* n17 = graph.NewNode(op, nil); + USE(n17); + op = common_builder.Branch(); + Node* n16 = graph.NewNode(op, nil, nil); + USE(n16); + op = js_builder.ToBoolean(); + Node* n15 = graph.NewNode(op, nil, nil, nil, nil); + USE(n15); + op = js_builder.LessThan(); + Node* n14 = graph.NewNode(op, nil, nil, nil, nil, nil); + USE(n14); + n14->ReplaceInput(0, n9); + n14->ReplaceInput(1, n10); + op = common_builder.HeapConstant(unique_constant); + Node* n6 = graph.NewNode(op); + USE(n6); + n14->ReplaceInput(2, n6); + op = common_builder.Phi(2); + Node* n12 = graph.NewNode(op, nil, nil, nil); + USE(n12); + n12->ReplaceInput(0, n0); + n12->ReplaceInput(1, n20); + n12->ReplaceInput(2, n7); + n14->ReplaceInput(3, n12); + n14->ReplaceInput(4, n7); + n15->ReplaceInput(0, n14); + n15->ReplaceInput(1, n6); + n15->ReplaceInput(2, n14); + n15->ReplaceInput(3, n7); + n16->ReplaceInput(0, n15); + n16->ReplaceInput(1, n7); + n17->ReplaceInput(0, n16); + n7->ReplaceInput(1, n17); + n10->ReplaceInput(2, n7); + n19->ReplaceInput(0, n2); + op = common_builder.Phi(2); + Node* n11 = graph.NewNode(op, nil, nil, nil); + USE(n11); + op = common_builder.Parameter(0); + Node* n4 = graph.NewNode(op, n0); + USE(n4); + n11->ReplaceInput(0, n4); + n11->ReplaceInput(1, n11); + n11->ReplaceInput(2, n7); + n19->ReplaceInput(1, n3); + n20->ReplaceInput(1, n19); + n20->ReplaceInput(2, n6); + n20->ReplaceInput(3, n19); + n20->ReplaceInput(4, n17); + n9->ReplaceInput(1, n20); + n9->ReplaceInput(2, n7); + n21->ReplaceInput(0, n9); + n21->ReplaceInput(1, n15); + op = common_builder.IfFalse(); + Node* n18 = graph.NewNode(op, nil); + USE(n18); + n18->ReplaceInput(0, n16); + n21->ReplaceInput(2, n18); + n22->ReplaceInput(0, n21); + + graph.SetStart(n0); + graph.SetEnd(n22); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + CHECK_EQ(19, GetScheduledNodeCount(schedule)); + + // Make sure the integer-only add gets hoisted to a different block that the + // JSAdd. + CHECK(schedule->block(n19) != schedule->block(n20)); +} + + +#if V8_TURBOFAN_TARGET + +// So we can get a real JS function. +static Handle<JSFunction> Compile(const char* source) { + Isolate* isolate = CcTest::i_isolate(); + Handle<String> source_code = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( + source_code, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, NULL, + v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE); + return isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared_function, isolate->native_context()); +} + + +TEST(BuildScheduleTrivialLazyDeoptCall) { + FLAG_turbo_deoptimization = true; + + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Graph graph(scope.main_zone()); + CommonOperatorBuilder common(scope.main_zone()); + JSOperatorBuilder js_builder(scope.main_zone()); + + InitializedHandleScope handles; + Handle<JSFunction> function = Compile("m()"); + CompilationInfoWithZone info(function); + Linkage linkage(&info); + + // Manually transcribed code for: + // function turbo_fan_test() { + // m(); + // } + // where m can lazy deopt (so it has a deopt block associated with it). + + + // Start // + // ^ // + // | (EC) // + // | // + // /------> Call <--------------\ // + // / ^ ^ \ // + // / | | \ undef // + // / / \ \ ^ // + // (E) | (C) / \ (C) \ (E) | // + // | Continuation LazyDeoptimization | | // + // \___ ^ ^ / | // + // \ | | ______/ Framestate // + // undef \ | (VC) | (C) / ^ // + // \ \ | | / / // + // Return Deoptimization ----------/ // + // ^ ^ // + // \ / // + // (C) \ / (C) // + // \ / // + // Merge // + // ^ // + // | // + // End // + + Handle<Object> undef_object = + Handle<Object>(isolate->heap()->undefined_value(), isolate); + PrintableUnique<Object> undef_constant = + PrintableUnique<Object>::CreateUninitialized(scope.main_zone(), + undef_object); + + Node* undef_node = graph.NewNode(common.HeapConstant(undef_constant)); + + Node* start_node = graph.NewNode(common.Start(0)); + + CallDescriptor* descriptor = linkage.GetJSCallDescriptor(0); + Node* call_node = graph.NewNode(common.Call(descriptor), + undef_node, // function + undef_node, // context + start_node, // effect + start_node); // control + + Node* cont_node = graph.NewNode(common.Continuation(), call_node); + Node* lazy_deopt_node = graph.NewNode(common.LazyDeoptimization(), call_node); + + Node* parameters = graph.NewNode(common.StateValues(1), undef_node); + Node* locals = graph.NewNode(common.StateValues(0)); + Node* stack = graph.NewNode(common.StateValues(0)); + + Node* state_node = graph.NewNode(common.FrameState(BailoutId(1234)), + parameters, locals, stack); + + Node* return_node = graph.NewNode(common.Return(), + undef_node, // return value + call_node, // effect + cont_node); // control + Node* deoptimization_node = graph.NewNode(common.Deoptimize(), + state_node, // deopt environment + call_node, // effect + lazy_deopt_node); // control + + Node* merge_node = + graph.NewNode(common.Merge(2), return_node, deoptimization_node); + + Node* end_node = graph.NewNode(common.End(), merge_node); + + graph.SetStart(start_node); + graph.SetEnd(end_node); + + PrintGraph(&graph); + + Schedule* schedule = Scheduler::ComputeSchedule(&graph); + + PrintSchedule(schedule); + + // Tests: + // Continuation and deopt have basic blocks. + BasicBlock* cont_block = schedule->block(cont_node); + BasicBlock* deopt_block = schedule->block(lazy_deopt_node); + BasicBlock* call_block = schedule->block(call_node); + CHECK_NE(NULL, cont_block); + CHECK_NE(NULL, deopt_block); + CHECK_NE(NULL, call_block); + // The basic blocks are different. + CHECK_NE(cont_block, deopt_block); + CHECK_NE(cont_block, call_block); + CHECK_NE(deopt_block, call_block); + // The call node finishes its own basic block. + CHECK_EQ(BasicBlock::kCall, call_block->control_); + CHECK_EQ(call_node, call_block->control_input_); + // The lazy deopt block is deferred. + CHECK(deopt_block->deferred_); + CHECK(!call_block->deferred_); + CHECK(!cont_block->deferred_); + // The lazy deopt block contains framestate + bailout (and nothing else). + CHECK_EQ(deoptimization_node, deopt_block->control_input_); + CHECK_EQ(5, static_cast<int>(deopt_block->nodes_.size())); + CHECK_EQ(lazy_deopt_node, deopt_block->nodes_[0]); + CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[1]->op()->opcode()); + CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[2]->op()->opcode()); + CHECK_EQ(IrOpcode::kStateValues, deopt_block->nodes_[3]->op()->opcode()); + CHECK_EQ(state_node, deopt_block->nodes_[4]); +} + +#endif diff --git a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc new file mode 100644 index 0000000000..18f4136b90 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc @@ -0,0 +1,1372 @@ +// 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 <limits> + +#include "src/compiler/control-builders.h" +#include "src/compiler/generic-node-inl.h" +#include "src/compiler/graph-visualizer.h" +#include "src/compiler/node-properties-inl.h" +#include "src/compiler/pipeline.h" +#include "src/compiler/representation-change.h" +#include "src/compiler/simplified-lowering.h" +#include "src/compiler/simplified-node-factory.h" +#include "src/compiler/typer.h" +#include "src/compiler/verifier.h" +#include "src/execution.h" +#include "src/parser.h" +#include "src/rewriter.h" +#include "src/scopes.h" +#include "test/cctest/cctest.h" +#include "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/graph-builder-tester.h" +#include "test/cctest/compiler/value-helper.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +template <typename ReturnType> +class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> { + public: + SimplifiedLoweringTester(MachineType p0 = kMachineLast, + MachineType p1 = kMachineLast, + MachineType p2 = kMachineLast, + MachineType p3 = kMachineLast, + MachineType p4 = kMachineLast) + : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4), + typer(this->zone()), + source_positions(this->graph()), + jsgraph(this->graph(), this->common(), &typer), + lowering(&jsgraph, &source_positions) {} + + Typer typer; + SourcePositionTable source_positions; + JSGraph jsgraph; + SimplifiedLowering lowering; + + void LowerAllNodes() { + this->End(); + lowering.LowerAllNodes(); + } + + Factory* factory() { return this->isolate()->factory(); } + Heap* heap() { return this->isolate()->heap(); } +}; + + +// TODO(dcarney): find a home for these functions. +namespace { + +FieldAccess ForJSObjectMap() { + FieldAccess access = {kTaggedBase, JSObject::kMapOffset, Handle<Name>(), + Type::Any(), kMachineTagged}; + return access; +} + + +FieldAccess ForJSObjectProperties() { + FieldAccess access = {kTaggedBase, JSObject::kPropertiesOffset, + Handle<Name>(), Type::Any(), kMachineTagged}; + return access; +} + + +FieldAccess ForArrayBufferBackingStore() { + FieldAccess access = { + kTaggedBase, JSArrayBuffer::kBackingStoreOffset, + Handle<Name>(), Type::UntaggedPtr(), + MachineOperatorBuilder::pointer_rep(), + }; + return access; +} + + +ElementAccess ForFixedArrayElement() { + ElementAccess access = {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), + kMachineTagged}; + return access; +} + + +ElementAccess ForBackingStoreElement(MachineType rep) { + ElementAccess access = {kUntaggedBase, + kNonHeapObjectHeaderSize - kHeapObjectTag, + Type::Any(), rep}; + return access; +} +} + + +// Create a simple JSObject with a unique map. +static Handle<JSObject> TestObject() { + static int index = 0; + char buffer[50]; + v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++); + return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer))); +} + + +TEST(RunLoadMap) { + SimplifiedLoweringTester<Object*> t(kMachineTagged); + FieldAccess access = ForJSObjectMap(); + Node* load = t.LoadField(access, t.Parameter(0)); + t.Return(load); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<JSObject> src = TestObject(); + Handle<Map> src_map(src->map()); + Object* result = t.Call(*src); // TODO(titzer): raw pointers in call + CHECK_EQ(*src_map, result); + } +} + + +TEST(RunStoreMap) { + SimplifiedLoweringTester<int32_t> t(kMachineTagged, kMachineTagged); + FieldAccess access = ForJSObjectMap(); + t.StoreField(access, t.Parameter(1), t.Parameter(0)); + t.Return(t.jsgraph.TrueConstant()); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<JSObject> src = TestObject(); + Handle<Map> src_map(src->map()); + Handle<JSObject> dst = TestObject(); + CHECK(src->map() != dst->map()); + t.Call(*src_map, *dst); // TODO(titzer): raw pointers in call + CHECK(*src_map == dst->map()); + } +} + + +TEST(RunLoadProperties) { + SimplifiedLoweringTester<Object*> t(kMachineTagged); + FieldAccess access = ForJSObjectProperties(); + Node* load = t.LoadField(access, t.Parameter(0)); + t.Return(load); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<JSObject> src = TestObject(); + Handle<FixedArray> src_props(src->properties()); + Object* result = t.Call(*src); // TODO(titzer): raw pointers in call + CHECK_EQ(*src_props, result); + } +} + + +TEST(RunLoadStoreMap) { + SimplifiedLoweringTester<Object*> t(kMachineTagged, kMachineTagged); + FieldAccess access = ForJSObjectMap(); + Node* load = t.LoadField(access, t.Parameter(0)); + t.StoreField(access, t.Parameter(1), load); + t.Return(load); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<JSObject> src = TestObject(); + Handle<Map> src_map(src->map()); + Handle<JSObject> dst = TestObject(); + CHECK(src->map() != dst->map()); + Object* result = t.Call(*src, *dst); // TODO(titzer): raw pointers in call + CHECK(result->IsMap()); + CHECK_EQ(*src_map, result); + CHECK(*src_map == dst->map()); + } +} + + +TEST(RunLoadStoreFixedArrayIndex) { + SimplifiedLoweringTester<Object*> t(kMachineTagged); + ElementAccess access = ForFixedArrayElement(); + Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0)); + t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load); + t.Return(load); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<FixedArray> array = t.factory()->NewFixedArray(2); + Handle<JSObject> src = TestObject(); + Handle<JSObject> dst = TestObject(); + array->set(0, *src); + array->set(1, *dst); + Object* result = t.Call(*array); + CHECK_EQ(*src, result); + CHECK_EQ(*src, array->get(0)); + CHECK_EQ(*src, array->get(1)); + } +} + + +TEST(RunLoadStoreArrayBuffer) { + SimplifiedLoweringTester<Object*> t(kMachineTagged); + const int index = 12; + ElementAccess buffer_access = ForBackingStoreElement(kMachineWord8); + Node* backing_store = + t.LoadField(ForArrayBufferBackingStore(), t.Parameter(0)); + Node* load = + t.LoadElement(buffer_access, backing_store, t.Int32Constant(index)); + t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1), + load); + t.Return(t.jsgraph.TrueConstant()); + + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer(); + const int array_length = 2 * index; + Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length); + uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store()); + for (int i = 0; i < array_length; i++) { + data[i] = i; + } + + // TODO(titzer): raw pointers in call + Object* result = t.Call(*array); + CHECK_EQ(t.isolate()->heap()->true_value(), result); + for (int i = 0; i < array_length; i++) { + uint8_t expected = i; + if (i == (index + 1)) expected = index; + CHECK_EQ(data[i], expected); + } + } +} + + +TEST(RunLoadFieldFromUntaggedBase) { + Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)}; + + for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { + int offset = static_cast<int>(i * sizeof(Smi*)); + FieldAccess access = {kUntaggedBase, offset, Handle<Name>(), + Type::Integral32(), kMachineTagged}; + + SimplifiedLoweringTester<Object*> t; + Node* load = t.LoadField(access, t.PointerConstant(smis)); + t.Return(load); + t.LowerAllNodes(); + + if (!Pipeline::SupportedTarget()) continue; + + for (int j = -5; j <= 5; j++) { + Smi* expected = Smi::FromInt(j); + smis[i] = expected; + CHECK_EQ(expected, t.Call()); + } + } +} + + +TEST(RunStoreFieldToUntaggedBase) { + Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)}; + + for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { + int offset = static_cast<int>(i * sizeof(Smi*)); + FieldAccess access = {kUntaggedBase, offset, Handle<Name>(), + Type::Integral32(), kMachineTagged}; + + SimplifiedLoweringTester<Object*> t(kMachineTagged); + Node* p0 = t.Parameter(0); + t.StoreField(access, t.PointerConstant(smis), p0); + t.Return(p0); + t.LowerAllNodes(); + + if (!Pipeline::SupportedTarget()) continue; + + for (int j = -5; j <= 5; j++) { + Smi* expected = Smi::FromInt(j); + smis[i] = Smi::FromInt(-100); + CHECK_EQ(expected, t.Call(expected)); + CHECK_EQ(expected, smis[i]); + } + } +} + + +TEST(RunLoadElementFromUntaggedBase) { + Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), + Smi::FromInt(4), Smi::FromInt(5)}; + + for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { // for header sizes + for (size_t j = 0; (i + j) < ARRAY_SIZE(smis); j++) { // for element index + int offset = static_cast<int>(i * sizeof(Smi*)); + ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), + kMachineTagged}; + + SimplifiedLoweringTester<Object*> t; + Node* load = t.LoadElement(access, t.PointerConstant(smis), + t.Int32Constant(static_cast<int>(j))); + t.Return(load); + t.LowerAllNodes(); + + if (!Pipeline::SupportedTarget()) continue; + + for (int k = -5; k <= 5; k++) { + Smi* expected = Smi::FromInt(k); + smis[i + j] = expected; + CHECK_EQ(expected, t.Call()); + } + } + } +} + + +TEST(RunStoreElementFromUntaggedBase) { + Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3), + Smi::FromInt(4), Smi::FromInt(5)}; + + for (size_t i = 0; i < ARRAY_SIZE(smis); i++) { // for header sizes + for (size_t j = 0; (i + j) < ARRAY_SIZE(smis); j++) { // for element index + int offset = static_cast<int>(i * sizeof(Smi*)); + ElementAccess access = {kUntaggedBase, offset, Type::Integral32(), + kMachineTagged}; + + SimplifiedLoweringTester<Object*> t(kMachineTagged); + Node* p0 = t.Parameter(0); + t.StoreElement(access, t.PointerConstant(smis), + t.Int32Constant(static_cast<int>(j)), p0); + t.Return(p0); + t.LowerAllNodes(); + + if (!Pipeline::SupportedTarget()) continue; + + for (int k = -5; k <= 5; k++) { + Smi* expected = Smi::FromInt(k); + smis[i + j] = Smi::FromInt(-100); + CHECK_EQ(expected, t.Call(expected)); + CHECK_EQ(expected, smis[i + j]); + } + + // TODO(titzer): assert the contents of the array. + } + } +} + + +// A helper class for accessing fields and elements of various types, on both +// tagged and untagged base pointers. Contains both tagged and untagged buffers +// for testing direct memory access from generated code. +template <typename E> +class AccessTester : public HandleAndZoneScope { + public: + bool tagged; + MachineType rep; + E* original_elements; + size_t num_elements; + E* untagged_array; + Handle<ByteArray> tagged_array; // TODO(titzer): use FixedArray for tagged. + + AccessTester(bool t, MachineType r, E* orig, size_t num) + : tagged(t), + rep(r), + original_elements(orig), + num_elements(num), + untagged_array(static_cast<E*>(malloc(ByteSize()))), + tagged_array(main_isolate()->factory()->NewByteArray( + static_cast<int>(ByteSize()))) { + Reinitialize(); + } + + ~AccessTester() { free(untagged_array); } + + size_t ByteSize() { return num_elements * sizeof(E); } + + // Nuke both {untagged_array} and {tagged_array} with {original_elements}. + void Reinitialize() { + memcpy(untagged_array, original_elements, ByteSize()); + CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length()); + E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); + memcpy(raw, original_elements, ByteSize()); + } + + // Create and run code that copies the element in either {untagged_array} + // or {tagged_array} at index {from_index} to index {to_index}. + void RunCopyElement(int from_index, int to_index) { + // TODO(titzer): test element and field accesses where the base is not + // a constant in the code. + BoundsCheck(from_index); + BoundsCheck(to_index); + ElementAccess access = GetElementAccess(); + + SimplifiedLoweringTester<Object*> t; + Node* ptr = GetBaseNode(&t); + Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index)); + t.StoreElement(access, ptr, t.Int32Constant(to_index), load); + t.Return(t.jsgraph.TrueConstant()); + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Object* result = t.Call(); + CHECK_EQ(t.isolate()->heap()->true_value(), result); + } + } + + // Create and run code that copies the field in either {untagged_array} + // or {tagged_array} at index {from_index} to index {to_index}. + void RunCopyField(int from_index, int to_index) { + BoundsCheck(from_index); + BoundsCheck(to_index); + FieldAccess from_access = GetFieldAccess(from_index); + FieldAccess to_access = GetFieldAccess(to_index); + + SimplifiedLoweringTester<Object*> t; + Node* ptr = GetBaseNode(&t); + Node* load = t.LoadField(from_access, ptr); + t.StoreField(to_access, ptr, load); + t.Return(t.jsgraph.TrueConstant()); + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Object* result = t.Call(); + CHECK_EQ(t.isolate()->heap()->true_value(), result); + } + } + + // Create and run code that copies the elements from {this} to {that}. + void RunCopyElements(AccessTester<E>* that) { + SimplifiedLoweringTester<Object*> t; + + Node* one = t.Int32Constant(1); + Node* index = t.Int32Constant(0); + Node* limit = t.Int32Constant(static_cast<int>(num_elements)); + t.environment()->Push(index); + Node* src = this->GetBaseNode(&t); + Node* dst = that->GetBaseNode(&t); + { + LoopBuilder loop(&t); + loop.BeginLoop(); + // Loop exit condition + index = t.environment()->Top(); + Node* condition = t.Int32LessThan(index, limit); + loop.BreakUnless(condition); + // dst[index] = src[index] + index = t.environment()->Pop(); + Node* load = t.LoadElement(this->GetElementAccess(), src, index); + t.StoreElement(that->GetElementAccess(), dst, index, load); + // index++ + index = t.Int32Add(index, one); + t.environment()->Push(index); + // continue + loop.EndBody(); + loop.EndLoop(); + } + index = t.environment()->Pop(); + t.Return(t.jsgraph.TrueConstant()); + t.LowerAllNodes(); + t.GenerateCode(); + + if (Pipeline::SupportedTarget()) { + Object* result = t.Call(); + CHECK_EQ(t.isolate()->heap()->true_value(), result); + } + } + + E GetElement(int index) { + BoundsCheck(index); + if (tagged) { + E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress()); + return raw[index]; + } else { + return untagged_array[index]; + } + } + + private: + ElementAccess GetElementAccess() { + ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase, + tagged ? FixedArrayBase::kHeaderSize : 0, + Type::Any(), rep}; + return access; + } + + FieldAccess GetFieldAccess(int field) { + int offset = field * sizeof(E); + FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase, + offset + (tagged ? FixedArrayBase::kHeaderSize : 0), + Handle<Name>(), Type::Any(), rep}; + return access; + } + + template <typename T> + Node* GetBaseNode(SimplifiedLoweringTester<T>* t) { + return tagged ? t->HeapConstant(tagged_array) + : t->PointerConstant(untagged_array); + } + + void BoundsCheck(int index) { + CHECK_GE(index, 0); + CHECK_LT(index, static_cast<int>(num_elements)); + CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length()); + } +}; + + +template <typename E> +static void RunAccessTest(MachineType rep, E* original_elements, size_t num) { + int num_elements = static_cast<int>(num); + + for (int taggedness = 0; taggedness < 2; taggedness++) { + AccessTester<E> a(taggedness == 1, rep, original_elements, num); + for (int field = 0; field < 2; field++) { + for (int i = 0; i < num_elements - 1; i++) { + a.Reinitialize(); + if (field == 0) { + a.RunCopyField(i, i + 1); // Test field read/write. + } else { + a.RunCopyElement(i, i + 1); // Test element read/write. + } + if (Pipeline::SupportedTarget()) { // verify. + for (int j = 0; j < num_elements; j++) { + E expect = + j == (i + 1) ? original_elements[i] : original_elements[j]; + CHECK_EQ(expect, a.GetElement(j)); + } + } + } + } + } + // Test array copy. + for (int tf = 0; tf < 2; tf++) { + for (int tt = 0; tt < 2; tt++) { + AccessTester<E> a(tf == 1, rep, original_elements, num); + AccessTester<E> b(tt == 1, rep, original_elements, num); + a.RunCopyElements(&b); + if (Pipeline::SupportedTarget()) { // verify. + for (int i = 0; i < num_elements; i++) { + CHECK_EQ(a.GetElement(i), b.GetElement(i)); + } + } + } + } +} + + +TEST(RunAccessTests_uint8) { + uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99, + 0xab, 0x78, 0x89, 0x19, 0x2b, 0x38}; + RunAccessTest<uint8_t>(kMachineWord8, data, ARRAY_SIZE(data)); +} + + +TEST(RunAccessTests_uint16) { + uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777}; + RunAccessTest<uint16_t>(kMachineWord16, data, ARRAY_SIZE(data)); +} + + +TEST(RunAccessTests_int32) { + int32_t data[] = {-211, 211, 628347, 2000000000, -2000000000, -1, -100000034}; + RunAccessTest<int32_t>(kMachineWord32, data, ARRAY_SIZE(data)); +} + + +#define V8_2PART_INT64(a, b) (((static_cast<int64_t>(a) << 32) + 0x##b##u)) + + +TEST(RunAccessTests_int64) { + if (kPointerSize != 8) return; + int64_t data[] = {V8_2PART_INT64(0x10111213, 14151617), + V8_2PART_INT64(0x20212223, 24252627), + V8_2PART_INT64(0x30313233, 34353637), + V8_2PART_INT64(0xa0a1a2a3, a4a5a6a7), + V8_2PART_INT64(0xf0f1f2f3, f4f5f6f7)}; + RunAccessTest<int64_t>(kMachineWord64, data, ARRAY_SIZE(data)); +} + + +TEST(RunAccessTests_float64) { + double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8}; + RunAccessTest<double>(kMachineFloat64, data, ARRAY_SIZE(data)); +} + + +TEST(RunAccessTests_Smi) { + Smi* data[] = {Smi::FromInt(-1), Smi::FromInt(-9), + Smi::FromInt(0), Smi::FromInt(666), + Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)}; + RunAccessTest<Smi*>(kMachineTagged, data, ARRAY_SIZE(data)); +} + + +// Fills in most of the nodes of the graph in order to make tests shorter. +class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { + public: + Typer typer; + JSGraph jsgraph; + Node* p0; + Node* p1; + Node* start; + Node* end; + Node* ret; + + explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None()) + : GraphAndBuilders(main_zone()), + typer(main_zone()), + jsgraph(graph(), common(), &typer) { + 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); + graph()->SetEnd(end); + p0 = graph()->NewNode(common()->Parameter(0), start); + p1 = graph()->NewNode(common()->Parameter(1), start); + NodeProperties::SetBounds(p0, Bounds(p0_type)); + NodeProperties::SetBounds(p1, Bounds(p1_type)); + } + + void CheckLoweringBinop(IrOpcode::Value expected, Operator* op) { + Node* node = Return(graph()->NewNode(op, p0, p1)); + Lower(); + CHECK_EQ(expected, node->opcode()); + } + + void CheckLoweringTruncatedBinop(IrOpcode::Value expected, Operator* op, + Operator* trunc) { + Node* node = graph()->NewNode(op, p0, p1); + Return(graph()->NewNode(trunc, node)); + Lower(); + CHECK_EQ(expected, node->opcode()); + } + + void Lower() { + SimplifiedLowering lowering(&jsgraph, NULL); + lowering.LowerAllNodes(); + } + + // Inserts the node as the return value of the graph. + Node* Return(Node* node) { + ret->ReplaceInput(0, node); + return node; + } + + // Inserts the node as the effect input to the return of the graph. + void Effect(Node* node) { ret->ReplaceInput(1, node); } + + Node* ExampleWithOutput(RepType type) { + // TODO(titzer): use parameters with guaranteed representations. + if (type & tInt32) { + return graph()->NewNode(machine()->Int32Add(), jsgraph.Int32Constant(1), + jsgraph.Int32Constant(1)); + } else if (type & tUint32) { + return graph()->NewNode(machine()->Word32Shr(), jsgraph.Int32Constant(1), + jsgraph.Int32Constant(1)); + } else if (type & rFloat64) { + return graph()->NewNode(machine()->Float64Add(), + jsgraph.Float64Constant(1), + jsgraph.Float64Constant(1)); + } else if (type & rBit) { + return graph()->NewNode(machine()->Word32Equal(), + jsgraph.Int32Constant(1), + jsgraph.Int32Constant(1)); + } else if (type & rWord64) { + return graph()->NewNode(machine()->Int64Add(), Int64Constant(1), + Int64Constant(1)); + } else { + CHECK(type & rTagged); + return p0; + } + } + + Node* Use(Node* node, RepType type) { + if (type & tInt32) { + return graph()->NewNode(machine()->Int32LessThan(), node, + jsgraph.Int32Constant(1)); + } else if (type & tUint32) { + return graph()->NewNode(machine()->Uint32LessThan(), node, + jsgraph.Int32Constant(1)); + } else if (type & rFloat64) { + return graph()->NewNode(machine()->Float64Add(), node, + jsgraph.Float64Constant(1)); + } else if (type & rWord64) { + return graph()->NewNode(machine()->Int64LessThan(), node, + Int64Constant(1)); + } else { + return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node, + jsgraph.TrueConstant()); + } + } + + Node* Branch(Node* cond) { + Node* br = graph()->NewNode(common()->Branch(), cond, start); + Node* tb = graph()->NewNode(common()->IfTrue(), br); + Node* fb = graph()->NewNode(common()->IfFalse(), br); + Node* m = graph()->NewNode(common()->Merge(2), tb, fb); + NodeProperties::ReplaceControlInput(ret, m); + return br; + } + + Node* Int64Constant(int64_t v) { + return graph()->NewNode(common()->Int64Constant(v)); + } + + SimplifiedOperatorBuilder* simplified() { return &main_simplified_; } + MachineOperatorBuilder* machine() { return &main_machine_; } + CommonOperatorBuilder* common() { return &main_common_; } + Graph* graph() { return main_graph_; } +}; + + +TEST(LowerBooleanNot_bit_bit) { + // BooleanNot(x: rBit) used as rBit + TestingGraph t(Type::Boolean()); + Node* b = t.ExampleWithOutput(rBit); + Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); + Node* use = t.Branch(inv); + t.Lower(); + Node* cmp = use->InputAt(0); + CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); + CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); + Node* f = t.jsgraph.Int32Constant(0); + CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); +} + + +TEST(LowerBooleanNot_bit_tagged) { + // BooleanNot(x: rBit) used as rTagged + TestingGraph t(Type::Boolean()); + Node* b = t.ExampleWithOutput(rBit); + Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); + Node* use = t.Use(inv, rTagged); + t.Return(use); + t.Lower(); + CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode()); + Node* cmp = use->InputAt(0)->InputAt(0); + CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); + CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); + Node* f = t.jsgraph.Int32Constant(0); + CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); +} + + +TEST(LowerBooleanNot_tagged_bit) { + // BooleanNot(x: rTagged) used as rBit + TestingGraph t(Type::Boolean()); + Node* b = t.p0; + Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); + Node* use = t.Branch(inv); + t.Lower(); + Node* cmp = use->InputAt(0); + CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); + CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); + Node* f = t.jsgraph.FalseConstant(); + CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); +} + + +TEST(LowerBooleanNot_tagged_tagged) { + // BooleanNot(x: rTagged) used as rTagged + TestingGraph t(Type::Boolean()); + Node* b = t.p0; + Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b); + Node* use = t.Use(inv, rTagged); + t.Return(use); + t.Lower(); + CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode()); + Node* cmp = use->InputAt(0)->InputAt(0); + CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode()); + CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1)); + Node* f = t.jsgraph.FalseConstant(); + CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1)); +} + + +static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(), + Type::Number(), Type::Any()}; + + +TEST(LowerNumberCmp_to_int32) { + TestingGraph t(Type::Signed32(), Type::Signed32()); + + t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual()); + t.CheckLoweringBinop(IrOpcode::kInt32LessThan, + t.simplified()->NumberLessThan()); + t.CheckLoweringBinop(IrOpcode::kInt32LessThanOrEqual, + t.simplified()->NumberLessThanOrEqual()); +} + + +TEST(LowerNumberCmp_to_uint32) { + TestingGraph t(Type::Unsigned32(), Type::Unsigned32()); + + t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual()); + t.CheckLoweringBinop(IrOpcode::kUint32LessThan, + t.simplified()->NumberLessThan()); + t.CheckLoweringBinop(IrOpcode::kUint32LessThanOrEqual, + t.simplified()->NumberLessThanOrEqual()); +} + + +TEST(LowerNumberCmp_to_float64) { + static Type* types[] = {Type::Number(), Type::Any()}; + + for (size_t i = 0; i < ARRAY_SIZE(types); i++) { + TestingGraph t(types[i], types[i]); + + t.CheckLoweringBinop(IrOpcode::kFloat64Equal, + t.simplified()->NumberEqual()); + t.CheckLoweringBinop(IrOpcode::kFloat64LessThan, + t.simplified()->NumberLessThan()); + t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual, + t.simplified()->NumberLessThanOrEqual()); + } +} + + +TEST(LowerNumberAddSub_to_int32) { + TestingGraph t(Type::Signed32(), Type::Signed32()); + t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add, + t.simplified()->NumberAdd(), + t.simplified()->NumberToInt32()); + t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub, + t.simplified()->NumberSubtract(), + t.simplified()->NumberToInt32()); +} + + +TEST(LowerNumberAddSub_to_uint32) { + TestingGraph t(Type::Unsigned32(), Type::Unsigned32()); + t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add, + t.simplified()->NumberAdd(), + t.simplified()->NumberToUint32()); + t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub, + t.simplified()->NumberSubtract(), + t.simplified()->NumberToUint32()); +} + + +TEST(LowerNumberAddSub_to_float64) { + for (size_t i = 0; i < ARRAY_SIZE(test_types); i++) { + TestingGraph t(test_types[i], test_types[i]); + + t.CheckLoweringBinop(IrOpcode::kFloat64Add, t.simplified()->NumberAdd()); + t.CheckLoweringBinop(IrOpcode::kFloat64Sub, + t.simplified()->NumberSubtract()); + } +} + + +TEST(LowerNumberDivMod_to_float64) { + for (size_t i = 0; i < ARRAY_SIZE(test_types); i++) { + TestingGraph t(test_types[i], test_types[i]); + + t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide()); + t.CheckLoweringBinop(IrOpcode::kFloat64Mod, + t.simplified()->NumberModulus()); + } +} + + +static void CheckChangeOf(IrOpcode::Value change, Node* of, Node* node) { + CHECK_EQ(change, node->opcode()); + CHECK_EQ(of, node->InputAt(0)); +} + + +TEST(LowerNumberToInt32_to_nop) { + // NumberToInt32(x: rTagged | tInt32) used as rTagged + TestingGraph t(Type::Signed32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0); + Node* use = t.Use(trunc, rTagged); + t.Return(use); + t.Lower(); + CHECK_EQ(t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToInt32_to_ChangeTaggedToFloat64) { + // NumberToInt32(x: rTagged | tInt32) used as rFloat64 + TestingGraph t(Type::Signed32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0); + Node* use = t.Use(trunc, rFloat64); + t.Return(use); + t.Lower(); + CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) { + // NumberToInt32(x: rTagged | tInt32) used as rWord32 + TestingGraph t(Type::Signed32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0); + Node* use = t.Use(trunc, tInt32); + t.Return(use); + t.Lower(); + CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) { + // TODO(titzer): NumberToInt32(x: rFloat64 | tInt32) used as rTagged +} + + +TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) { + // TODO(titzer): NumberToInt32(x: rFloat64 | tInt32) used as rWord32 | tInt32 +} + + +TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) { + // TODO(titzer): NumberToInt32(x: rFloat64) used as rWord32 | tUint32 +} + + +TEST(LowerNumberToUint32_to_nop) { + // NumberToUint32(x: rTagged | tUint32) used as rTagged + TestingGraph t(Type::Unsigned32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0); + Node* use = t.Use(trunc, rTagged); + t.Return(use); + t.Lower(); + CHECK_EQ(t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToUint32_to_ChangeTaggedToFloat64) { + // NumberToUint32(x: rTagged | tUint32) used as rWord32 + TestingGraph t(Type::Unsigned32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0); + Node* use = t.Use(trunc, rFloat64); + t.Return(use); + t.Lower(); + CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToUint32_to_ChangeTaggedToUint32) { + // NumberToUint32(x: rTagged | tUint32) used as rWord32 + TestingGraph t(Type::Unsigned32()); + Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0); + Node* use = t.Use(trunc, tUint32); + t.Return(use); + t.Lower(); + CheckChangeOf(IrOpcode::kChangeTaggedToUint32, t.p0, use->InputAt(0)); +} + + +TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) { + // TODO(titzer): NumberToUint32(x: rFloat64 | tUint32) used as rTagged +} + + +TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) { + // TODO(titzer): NumberToUint32(x: rFloat64 | tUint32) used as rWord32 +} + + +TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) { + // TODO(titzer): NumberToUint32(x: rFloat64) used as rWord32 +} + + +TEST(LowerReferenceEqual_to_wordeq) { + TestingGraph t(Type::Any(), Type::Any()); + IrOpcode::Value opcode = + static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode()); + t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any())); +} + + +TEST(LowerStringOps_to_rtcalls) { + if (false) { // TODO(titzer): lower StringOps to runtime calls + TestingGraph t(Type::String(), Type::String()); + t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringEqual()); + t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringLessThan()); + t.CheckLoweringBinop(IrOpcode::kCall, + t.simplified()->StringLessThanOrEqual()); + t.CheckLoweringBinop(IrOpcode::kCall, t.simplified()->StringAdd()); + } +} + + +void CheckChangeInsertion(IrOpcode::Value expected, RepType from, RepType to) { + TestingGraph t(Type::Any()); + Node* in = t.ExampleWithOutput(from); + Node* use = t.Use(in, to); + t.Return(use); + t.Lower(); + CHECK_EQ(expected, use->InputAt(0)->opcode()); + CHECK_EQ(in, use->InputAt(0)->InputAt(0)); +} + + +TEST(InsertBasicChanges) { + if (false) { + // TODO(titzer): these changes need the output to have the right type. + CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, rFloat64, tInt32); + CheckChangeInsertion(IrOpcode::kChangeFloat64ToUint32, rFloat64, tUint32); + CheckChangeInsertion(IrOpcode::kChangeTaggedToInt32, rTagged, tInt32); + CheckChangeInsertion(IrOpcode::kChangeTaggedToUint32, rTagged, tUint32); + } + + CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, rFloat64, rTagged); + CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64, rTagged, rFloat64); + + CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, tInt32, rFloat64); + CheckChangeInsertion(IrOpcode::kChangeInt32ToTagged, tInt32, rTagged); + + CheckChangeInsertion(IrOpcode::kChangeUint32ToFloat64, tUint32, rFloat64); + CheckChangeInsertion(IrOpcode::kChangeUint32ToTagged, tUint32, rTagged); +} + + +static void CheckChangesAroundBinop(TestingGraph* t, Operator* op, + IrOpcode::Value input_change, + IrOpcode::Value output_change) { + Node* binop = t->graph()->NewNode(op, t->p0, t->p1); + t->Return(binop); + t->Lower(); + CHECK_EQ(input_change, binop->InputAt(0)->opcode()); + CHECK_EQ(input_change, binop->InputAt(1)->opcode()); + CHECK_EQ(t->p0, binop->InputAt(0)->InputAt(0)); + CHECK_EQ(t->p1, binop->InputAt(1)->InputAt(0)); + CHECK_EQ(output_change, t->ret->InputAt(0)->opcode()); + CHECK_EQ(binop, t->ret->InputAt(0)->InputAt(0)); +} + + +TEST(InsertChangesAroundInt32Binops) { + TestingGraph t(Type::Signed32(), Type::Signed32()); + + Operator* ops[] = {t.machine()->Int32Add(), t.machine()->Int32Sub(), + t.machine()->Int32Mul(), t.machine()->Int32Div(), + t.machine()->Int32Mod(), t.machine()->Word32And(), + t.machine()->Word32Or(), t.machine()->Word32Xor(), + t.machine()->Word32Shl(), t.machine()->Word32Sar()}; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32, + IrOpcode::kChangeInt32ToTagged); + } +} + + +TEST(InsertChangesAroundInt32Cmp) { + TestingGraph t(Type::Signed32(), Type::Signed32()); + + Operator* ops[] = {t.machine()->Int32LessThan(), + t.machine()->Int32LessThanOrEqual()}; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32, + IrOpcode::kChangeBitToBool); + } +} + + +TEST(InsertChangesAroundUint32Cmp) { + TestingGraph t(Type::Unsigned32(), Type::Unsigned32()); + + Operator* ops[] = {t.machine()->Uint32LessThan(), + t.machine()->Uint32LessThanOrEqual()}; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToUint32, + IrOpcode::kChangeBitToBool); + } +} + + +TEST(InsertChangesAroundFloat64Binops) { + TestingGraph t(Type::Number(), Type::Number()); + + Operator* ops[] = { + t.machine()->Float64Add(), t.machine()->Float64Sub(), + t.machine()->Float64Mul(), t.machine()->Float64Div(), + t.machine()->Float64Mod(), + }; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64, + IrOpcode::kChangeFloat64ToTagged); + } +} + + +TEST(InsertChangesAroundFloat64Cmp) { + TestingGraph t(Type::Number(), Type::Number()); + + Operator* ops[] = {t.machine()->Float64Equal(), + t.machine()->Float64LessThan(), + t.machine()->Float64LessThanOrEqual()}; + + for (size_t i = 0; i < ARRAY_SIZE(ops); i++) { + CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64, + IrOpcode::kChangeBitToBool); + } +} + + +void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) { + Int32Matcher index = Int32Matcher(load_or_store->InputAt(1)); + CHECK(index.Is(access.offset - access.tag())); +} + + +Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) { + Int32BinopMatcher index(load_or_store->InputAt(1)); + CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode()); + CHECK(index.right().Is(access.header_size - access.tag())); + + int element_size = 0; + switch (access.representation) { + case kMachineTagged: + element_size = kPointerSize; + break; + case kMachineWord8: + element_size = 1; + break; + case kMachineWord16: + element_size = 2; + break; + case kMachineWord32: + element_size = 4; + break; + case kMachineWord64: + case kMachineFloat64: + element_size = 8; + break; + case kMachineLast: + UNREACHABLE(); + break; + } + + if (element_size != 1) { + Int32BinopMatcher mul(index.left().node()); + CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode()); + CHECK(mul.right().Is(element_size)); + return mul.left().node(); + } else { + return index.left().node(); + } +} + + +static const MachineType machine_reps[] = {kMachineWord8, kMachineWord16, + kMachineWord32, kMachineWord64, + kMachineFloat64, kMachineTagged}; + + +// Representation types corresponding to those above. +static const RepType rep_types[] = {static_cast<RepType>(rWord32 | tUint32), + static_cast<RepType>(rWord32 | tUint32), + static_cast<RepType>(rWord32 | tInt32), + static_cast<RepType>(rWord64), + static_cast<RepType>(rFloat64 | tNumber), + static_cast<RepType>(rTagged | tAny)}; + + +TEST(LowerLoadField_to_load) { + TestingGraph t(Type::Any(), Type::Signed32()); + + for (size_t i = 0; i < ARRAY_SIZE(machine_reps); i++) { + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), machine_reps[i]}; + + Node* load = + t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); + Node* use = t.Use(load, rep_types[i]); + t.Return(use); + t.Lower(); + CHECK_EQ(IrOpcode::kLoad, load->opcode()); + CHECK_EQ(t.p0, load->InputAt(0)); + CheckFieldAccessArithmetic(access, load); + + MachineType rep = OpParameter<MachineType>(load); + CHECK_EQ(machine_reps[i], rep); + } +} + + +TEST(LowerStoreField_to_store) { + TestingGraph t(Type::Any(), Type::Signed32()); + + for (size_t i = 0; i < ARRAY_SIZE(machine_reps); i++) { + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), machine_reps[i]}; + + + Node* val = t.ExampleWithOutput(rep_types[i]); + Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, + val, t.start, t.start); + t.Effect(store); + t.Lower(); + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(val, store->InputAt(2)); + CheckFieldAccessArithmetic(access, store); + + StoreRepresentation rep = OpParameter<StoreRepresentation>(store); + if (rep_types[i] & rTagged) { + CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind); + } + CHECK_EQ(machine_reps[i], rep.rep); + } +} + + +TEST(LowerLoadElement_to_load) { + TestingGraph t(Type::Any(), Type::Signed32()); + + for (size_t i = 0; i < ARRAY_SIZE(machine_reps); i++) { + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Type::Any(), machine_reps[i]}; + + Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, + t.p1, t.start); + Node* use = t.Use(load, rep_types[i]); + t.Return(use); + t.Lower(); + CHECK_EQ(IrOpcode::kLoad, load->opcode()); + CHECK_EQ(t.p0, load->InputAt(0)); + CheckElementAccessArithmetic(access, load); + + MachineType rep = OpParameter<MachineType>(load); + CHECK_EQ(machine_reps[i], rep); + } +} + + +TEST(LowerStoreElement_to_store) { + TestingGraph t(Type::Any(), Type::Signed32()); + + for (size_t i = 0; i < ARRAY_SIZE(machine_reps); i++) { + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Type::Any(), machine_reps[i]}; + + Node* val = t.ExampleWithOutput(rep_types[i]); + Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, + t.p1, val, t.start, t.start); + t.Effect(store); + t.Lower(); + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(val, store->InputAt(2)); + CheckElementAccessArithmetic(access, store); + + StoreRepresentation rep = OpParameter<StoreRepresentation>(store); + if (rep_types[i] & rTagged) { + CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind); + } + CHECK_EQ(machine_reps[i], rep.rep); + } +} + + +TEST(InsertChangeForLoadElementIndex) { + // LoadElement(obj: Tagged, index: tInt32 | rTagged) => + // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k)) + TestingGraph t(Type::Any(), Type::Signed32()); + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), + kMachineTagged}; + + Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, + t.p1, t.start); + t.Return(load); + t.Lower(); + CHECK_EQ(IrOpcode::kLoad, load->opcode()); + CHECK_EQ(t.p0, load->InputAt(0)); + + Node* index = CheckElementAccessArithmetic(access, load); + CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); +} + + +TEST(InsertChangeForStoreElementIndex) { + // StoreElement(obj: Tagged, index: tInt32 | rTagged, val) => + // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val) + TestingGraph t(Type::Any(), Type::Signed32()); + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), + kMachineTagged}; + + Node* store = + t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, + t.jsgraph.TrueConstant(), t.start, t.start); + t.Effect(store); + t.Lower(); + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(t.p0, store->InputAt(0)); + + Node* index = CheckElementAccessArithmetic(access, store); + CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, index); +} + + +TEST(InsertChangeForLoadElement) { + // TODO(titzer): test all load/store representation change insertions. + TestingGraph t(Type::Any(), Type::Signed32()); + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), + kMachineFloat64}; + + Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, + t.p1, t.start); + t.Return(load); + t.Lower(); + CHECK_EQ(IrOpcode::kLoad, load->opcode()); + CHECK_EQ(t.p0, load->InputAt(0)); + CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); +} + + +TEST(InsertChangeForLoadField) { + // TODO(titzer): test all load/store representation change insertions. + TestingGraph t(Type::Any(), Type::Signed32()); + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), kMachineFloat64}; + + Node* load = + t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start); + t.Return(load); + t.Lower(); + CHECK_EQ(IrOpcode::kLoad, load->opcode()); + CHECK_EQ(t.p0, load->InputAt(0)); + CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0)); +} + + +TEST(InsertChangeForStoreElement) { + // TODO(titzer): test all load/store representation change insertions. + TestingGraph t(Type::Any(), Type::Signed32()); + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(), + kMachineFloat64}; + + Node* store = + t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, + t.jsgraph.Int32Constant(0), t.p1, t.start, t.start); + t.Effect(store); + t.Lower(); + + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(t.p0, store->InputAt(0)); + CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2)); +} + + +TEST(InsertChangeForStoreField) { + // TODO(titzer): test all load/store representation change insertions. + TestingGraph t(Type::Any(), Type::Signed32()); + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), kMachineFloat64}; + + Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, + t.p1, t.start, t.start); + t.Effect(store); + t.Lower(); + + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(t.p0, store->InputAt(0)); + CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2)); +} diff --git a/deps/v8/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc b/deps/v8/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc new file mode 100644 index 0000000000..02232264d9 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-structured-ifbuilder-fuzzer.cc @@ -0,0 +1,667 @@ +// 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 <string> + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/base/utils/random-number-generator.h" +#include "test/cctest/compiler/codegen-tester.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal; +using namespace v8::internal::compiler; + +typedef StructuredMachineAssembler::IfBuilder IfBuilder; +typedef StructuredMachineAssembler::LoopBuilder Loop; + +static const int32_t kUninitializedVariableOffset = -1; +static const int32_t kUninitializedOutput = -1; +static const int32_t kVerifiedOutput = -2; + +static const int32_t kInitalVar = 1013; +static const int32_t kConjunctionInc = 1069; +static const int32_t kDisjunctionInc = 1151; +static const int32_t kThenInc = 1223; +static const int32_t kElseInc = 1291; +static const int32_t kIfInc = 1373; + +class IfBuilderModel { + public: + explicit IfBuilderModel(Zone* zone) + : zone_(zone), + variable_offset_(0), + root_(new (zone_) Node(NULL)), + current_node_(root_), + current_expression_(NULL) {} + + void If() { + if (current_node_->else_node != NULL) { + current_node_ = current_node_->else_node; + } else if (current_node_->then_node != NULL) { + current_node_ = current_node_->then_node; + } + DCHECK(current_expression_ == NULL); + current_expression_ = new (zone_) Expression(zone_, NULL); + current_node_->condition = current_expression_; + } + void IfNode() { LastChild()->variable_offset = variable_offset_++; } + + void OpenParen() { current_expression_ = LastChild(); } + void CloseParen() { current_expression_ = current_expression_->parent; } + + void And() { NewChild()->conjunction = true; } + void Or() { NewChild()->disjunction = true; } + + void Then() { + DCHECK(current_expression_ == NULL || current_expression_->parent == NULL); + current_expression_ = NULL; + DCHECK(current_node_->then_node == NULL); + current_node_->then_node = new (zone_) Node(current_node_); + } + void Else() { + DCHECK(current_expression_ == NULL || current_expression_->parent == NULL); + current_expression_ = NULL; + DCHECK(current_node_->else_node == NULL); + current_node_->else_node = new (zone_) Node(current_node_); + } + void Return() { + if (current_node_->else_node != NULL) { + current_node_->else_node->returns = true; + } else if (current_node_->then_node != NULL) { + current_node_->then_node->returns = true; + } else { + CHECK(false); + } + } + void End() {} + + void Print(std::vector<char>* v) { PrintRecursive(v, root_); } + + struct VerificationState { + int32_t* inputs; + int32_t* outputs; + int32_t var; + }; + + int32_t Verify(int length, int32_t* inputs, int32_t* outputs) { + CHECK_EQ(variable_offset_, length); + // Input/Output verification. + for (int i = 0; i < length; ++i) { + CHECK(inputs[i] == 0 || inputs[i] == 1); + CHECK(outputs[i] == kUninitializedOutput || outputs[i] >= 0); + } + // Do verification. + VerificationState state; + state.inputs = inputs; + state.outputs = outputs; + state.var = kInitalVar; + VerifyRecursive(root_, &state); + // Verify all outputs marked. + for (int i = 0; i < length; ++i) { + CHECK(outputs[i] == kUninitializedOutput || + outputs[i] == kVerifiedOutput); + } + return state.var; + } + + private: + struct Expression; + typedef std::vector<Expression*, zone_allocator<Expression*> > Expressions; + + struct Expression : public ZoneObject { + Expression(Zone* zone, Expression* p) + : variable_offset(kUninitializedVariableOffset), + disjunction(false), + conjunction(false), + parent(p), + children(Expressions::allocator_type(zone)) {} + int variable_offset; + bool disjunction; + bool conjunction; + Expression* parent; + Expressions children; + + private: + DISALLOW_COPY_AND_ASSIGN(Expression); + }; + + struct Node : public ZoneObject { + explicit Node(Node* p) + : parent(p), + condition(NULL), + then_node(NULL), + else_node(NULL), + returns(false) {} + Node* parent; + Expression* condition; + Node* then_node; + Node* else_node; + bool returns; + + private: + DISALLOW_COPY_AND_ASSIGN(Node); + }; + + Expression* LastChild() { + if (current_expression_->children.empty()) { + current_expression_->children.push_back( + new (zone_) Expression(zone_, current_expression_)); + } + return current_expression_->children.back(); + } + + Expression* NewChild() { + Expression* child = new (zone_) Expression(zone_, current_expression_); + current_expression_->children.push_back(child); + return child; + } + + static void PrintRecursive(std::vector<char>* v, Expression* expression) { + CHECK(expression != NULL); + if (expression->conjunction) { + DCHECK(!expression->disjunction); + v->push_back('&'); + } else if (expression->disjunction) { + v->push_back('|'); + } + if (expression->variable_offset != kUninitializedVariableOffset) { + v->push_back('v'); + } + Expressions& children = expression->children; + if (children.empty()) return; + v->push_back('('); + for (Expressions::iterator i = children.begin(); i != children.end(); ++i) { + PrintRecursive(v, *i); + } + v->push_back(')'); + } + + static void PrintRecursive(std::vector<char>* v, Node* node) { + // Termination condition. + if (node->condition == NULL) { + CHECK(node->then_node == NULL && node->else_node == NULL); + if (node->returns) v->push_back('r'); + return; + } + CHECK(!node->returns); + v->push_back('i'); + PrintRecursive(v, node->condition); + if (node->then_node != NULL) { + v->push_back('t'); + PrintRecursive(v, node->then_node); + } + if (node->else_node != NULL) { + v->push_back('e'); + PrintRecursive(v, node->else_node); + } + } + + static bool VerifyRecursive(Expression* expression, + VerificationState* state) { + bool result = false; + bool first_iteration = true; + Expressions& children = expression->children; + CHECK(!children.empty()); + for (Expressions::iterator i = children.begin(); i != children.end(); ++i) { + Expression* child = *i; + // Short circuit evaluation, + // but mixes of &&s and ||s have weird semantics. + if ((child->conjunction && !result) || (child->disjunction && result)) { + continue; + } + if (child->conjunction) state->var += kConjunctionInc; + if (child->disjunction) state->var += kDisjunctionInc; + bool child_result; + if (child->variable_offset != kUninitializedVariableOffset) { + // Verify output + CHECK_EQ(state->var, state->outputs[child->variable_offset]); + state->outputs[child->variable_offset] = kVerifiedOutput; // Mark seen. + child_result = state->inputs[child->variable_offset]; + CHECK(child->children.empty()); + state->var += kIfInc; + } else { + child_result = VerifyRecursive(child, state); + } + if (child->conjunction) { + result &= child_result; + } else if (child->disjunction) { + result |= child_result; + } else { + CHECK(first_iteration); + result = child_result; + } + first_iteration = false; + } + return result; + } + + static void VerifyRecursive(Node* node, VerificationState* state) { + if (node->condition == NULL) return; + bool result = VerifyRecursive(node->condition, state); + if (result) { + if (node->then_node) { + state->var += kThenInc; + return VerifyRecursive(node->then_node, state); + } + } else { + if (node->else_node) { + state->var += kElseInc; + return VerifyRecursive(node->else_node, state); + } + } + } + + Zone* zone_; + int variable_offset_; + Node* root_; + Node* current_node_; + Expression* current_expression_; + DISALLOW_COPY_AND_ASSIGN(IfBuilderModel); +}; + + +class IfBuilderGenerator : public StructuredMachineAssemblerTester<int32_t> { + public: + IfBuilderGenerator() + : StructuredMachineAssemblerTester<int32_t>( + MachineOperatorBuilder::pointer_rep(), + MachineOperatorBuilder::pointer_rep()), + var_(NewVariable(Int32Constant(kInitalVar))), + c_(this), + m_(this->zone()), + one_(Int32Constant(1)), + offset_(0) {} + + static void GenerateExpression(v8::base::RandomNumberGenerator* rng, + std::vector<char>* v, int n_vars) { + int depth = 1; + v->push_back('('); + bool need_if = true; + bool populated = false; + while (n_vars != 0) { + if (need_if) { + // can nest a paren or do a variable + if (rng->NextBool()) { + v->push_back('v'); + n_vars--; + need_if = false; + populated = true; + } else { + v->push_back('('); + depth++; + populated = false; + } + } else { + // can pop, do && or do || + int options = 3; + if (depth == 1 || !populated) { + options--; + } + switch (rng->NextInt(options)) { + case 0: + v->push_back('&'); + need_if = true; + break; + case 1: + v->push_back('|'); + need_if = true; + break; + case 2: + v->push_back(')'); + depth--; + break; + } + } + } + CHECK(!need_if); + while (depth != 0) { + v->push_back(')'); + depth--; + } + } + + static void GenerateIfThenElse(v8::base::RandomNumberGenerator* rng, + std::vector<char>* v, int n_ifs, + int max_exp_length) { + CHECK_GT(n_ifs, 0); + CHECK_GT(max_exp_length, 0); + bool have_env = true; + bool then_done = false; + bool else_done = false; + bool first_iteration = true; + while (n_ifs != 0) { + if (have_env) { + int options = 3; + if (else_done || first_iteration) { // Don't do else or return + options -= 2; + first_iteration = false; + } + switch (rng->NextInt(options)) { + case 0: + v->push_back('i'); + n_ifs--; + have_env = false; + GenerateExpression(rng, v, rng->NextInt(max_exp_length) + 1); + break; + case 1: + v->push_back('r'); + have_env = false; + break; + case 2: + v->push_back('e'); + else_done = true; + then_done = false; + break; + default: + CHECK(false); + } + } else { // Can only do then or else + int options = 2; + if (then_done) options--; + switch (rng->NextInt(options)) { + case 0: + v->push_back('e'); + else_done = true; + then_done = false; + break; + case 1: + v->push_back('t'); + then_done = true; + else_done = false; + break; + default: + CHECK(false); + } + have_env = true; + } + } + // Last instruction must have been an if, can complete it in several ways. + int options = 2; + if (then_done && !else_done) options++; + switch (rng->NextInt(3)) { + case 0: + // Do nothing. + break; + case 1: + v->push_back('t'); + switch (rng->NextInt(3)) { + case 0: + v->push_back('r'); + break; + case 1: + v->push_back('e'); + break; + case 2: + v->push_back('e'); + v->push_back('r'); + break; + default: + CHECK(false); + } + break; + case 2: + v->push_back('e'); + if (rng->NextBool()) v->push_back('r'); + break; + default: + CHECK(false); + } + } + + std::string::const_iterator ParseExpression(std::string::const_iterator it, + std::string::const_iterator end) { + // Prepare for expression. + m_.If(); + c_.If(); + int depth = 0; + for (; it != end; ++it) { + switch (*it) { + case 'v': + m_.IfNode(); + { + Node* offset = Int32Constant(offset_ * 4); + Store(kMachineWord32, Parameter(1), offset, var_.Get()); + var_.Set(Int32Add(var_.Get(), Int32Constant(kIfInc))); + c_.If(Load(kMachineWord32, Parameter(0), offset)); + offset_++; + } + break; + case '&': + m_.And(); + c_.And(); + var_.Set(Int32Add(var_.Get(), Int32Constant(kConjunctionInc))); + break; + case '|': + m_.Or(); + c_.Or(); + var_.Set(Int32Add(var_.Get(), Int32Constant(kDisjunctionInc))); + break; + case '(': + if (depth != 0) { + m_.OpenParen(); + c_.OpenParen(); + } + depth++; + break; + case ')': + depth--; + if (depth == 0) return it; + m_.CloseParen(); + c_.CloseParen(); + break; + default: + CHECK(false); + } + } + CHECK(false); + return it; + } + + void ParseIfThenElse(const std::string& str) { + int n_vars = 0; + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { + if (*it == 'v') n_vars++; + } + InitializeConstants(n_vars); + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { + switch (*it) { + case 'i': { + it++; + CHECK(it != str.end()); + CHECK_EQ('(', *it); + it = ParseExpression(it, str.end()); + CHECK_EQ(')', *it); + break; + } + case 't': + m_.Then(); + c_.Then(); + var_.Set(Int32Add(var_.Get(), Int32Constant(kThenInc))); + break; + case 'e': + m_.Else(); + c_.Else(); + var_.Set(Int32Add(var_.Get(), Int32Constant(kElseInc))); + break; + case 'r': + m_.Return(); + Return(var_.Get()); + break; + default: + CHECK(false); + } + } + m_.End(); + c_.End(); + Return(var_.Get()); + // Compare generated model to parsed version. + { + std::vector<char> v; + m_.Print(&v); + std::string m_str(v.begin(), v.end()); + CHECK(m_str == str); + } + } + + void ParseExpression(const std::string& str) { + CHECK(inputs_.is_empty()); + std::string wrapped = "i(" + str + ")te"; + ParseIfThenElse(wrapped); + } + + void ParseRandomIfThenElse(v8::base::RandomNumberGenerator* rng, int n_ifs, + int n_vars) { + std::vector<char> v; + GenerateIfThenElse(rng, &v, n_ifs, n_vars); + std::string str(v.begin(), v.end()); + ParseIfThenElse(str); + } + + void RunRandom(v8::base::RandomNumberGenerator* rng) { + // TODO(dcarney): permute inputs via model. + // TODO(dcarney): compute test_cases from n_ifs and n_vars. + int test_cases = 100; + for (int test = 0; test < test_cases; test++) { + Initialize(); + for (int i = 0; i < offset_; i++) { + inputs_[i] = rng->NextBool(); + } + DoCall(); + } + } + + void Run(const std::string& str, int32_t expected) { + Initialize(); + int offset = 0; + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { + switch (*it) { + case 't': + inputs_[offset++] = 1; + break; + case 'f': + inputs_[offset++] = 0; + break; + default: + CHECK(false); + } + } + CHECK_EQ(offset_, offset); + // Call. + int32_t result = DoCall(); + CHECK_EQ(result, expected); + } + + private: + typedef std::vector<int32_t, zone_allocator<int32_t> > IOVector; + + void InitializeConstants(int n_vars) { + CHECK(inputs_.is_empty()); + inputs_.Reset(new int32_t[n_vars]); + outputs_.Reset(new int32_t[n_vars]); + } + + void Initialize() { + for (int i = 0; i < offset_; i++) { + inputs_[i] = 0; + outputs_[i] = kUninitializedOutput; + } + } + + int32_t DoCall() { + int32_t result = Call(inputs_.get(), outputs_.get()); + int32_t expected = m_.Verify(offset_, inputs_.get(), outputs_.get()); + CHECK_EQ(result, expected); + return result; + } + + const v8::internal::compiler::Variable var_; + IfBuilder c_; + IfBuilderModel m_; + Node* one_; + int32_t offset_; + SmartArrayPointer<int32_t> inputs_; + SmartArrayPointer<int32_t> outputs_; +}; + + +TEST(RunExpressionString) { + IfBuilderGenerator m; + m.ParseExpression("((v|v)|v)"); + m.Run("ttt", kInitalVar + 1 * kIfInc + kThenInc); + m.Run("ftt", kInitalVar + 2 * kIfInc + kDisjunctionInc + kThenInc); + m.Run("fft", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kThenInc); + m.Run("fff", kInitalVar + 3 * kIfInc + 2 * kDisjunctionInc + kElseInc); +} + + +TEST(RunExpressionStrings) { + const char* strings[] = { + "v", "(v)", "((v))", "v|v", + "(v|v)", "((v|v))", "v&v", "(v&v)", + "((v&v))", "v&(v)", "v&(v|v)", "v&(v|v)&v", + "v|(v)", "v|(v&v)", "v|(v&v)|v", "v|(((v)|(v&v)|(v)|v)&(v))|v", + }; + v8::base::RandomNumberGenerator rng; + for (size_t i = 0; i < ARRAY_SIZE(strings); i++) { + IfBuilderGenerator m; + m.ParseExpression(strings[i]); + m.RunRandom(&rng); + } +} + + +TEST(RunSimpleIfElseTester) { + const char* tests[] = { + "i(v)", "i(v)t", "i(v)te", + "i(v)er", "i(v)ter", "i(v)ti(v)trei(v)ei(v)ei(v)ei(v)ei(v)ei(v)ei(v)e"}; + v8::base::RandomNumberGenerator rng; + for (size_t i = 0; i < ARRAY_SIZE(tests); ++i) { + IfBuilderGenerator m; + m.ParseIfThenElse(tests[i]); + m.RunRandom(&rng); + } +} + + +TEST(RunRandomExpressions) { + v8::base::RandomNumberGenerator rng; + for (int n_vars = 1; n_vars < 12; n_vars++) { + for (int i = 0; i < n_vars * n_vars + 10; i++) { + IfBuilderGenerator m; + m.ParseRandomIfThenElse(&rng, 1, n_vars); + m.RunRandom(&rng); + } + } +} + + +TEST(RunRandomIfElse) { + v8::base::RandomNumberGenerator rng; + for (int n_ifs = 1; n_ifs < 12; n_ifs++) { + for (int i = 0; i < n_ifs * n_ifs + 10; i++) { + IfBuilderGenerator m; + m.ParseRandomIfThenElse(&rng, n_ifs, 1); + m.RunRandom(&rng); + } + } +} + + +TEST(RunRandomIfElseExpressions) { + v8::base::RandomNumberGenerator rng; + for (int n_vars = 2; n_vars < 6; n_vars++) { + for (int n_ifs = 2; n_ifs < 7; n_ifs++) { + for (int i = 0; i < n_ifs * n_vars + 10; i++) { + IfBuilderGenerator m; + m.ParseRandomIfThenElse(&rng, n_ifs, n_vars); + m.RunRandom(&rng); + } + } + } +} + +#endif diff --git a/deps/v8/test/cctest/compiler/test-structured-machine-assembler.cc b/deps/v8/test/cctest/compiler/test-structured-machine-assembler.cc new file mode 100644 index 0000000000..6d8020baf4 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-structured-machine-assembler.cc @@ -0,0 +1,1055 @@ +// 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/utils/random-number-generator.h" +#include "src/compiler/structured-machine-assembler.h" +#include "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/value-helper.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal::compiler; + +typedef StructuredMachineAssembler::IfBuilder IfBuilder; +typedef StructuredMachineAssembler::LoopBuilder Loop; + +namespace v8 { +namespace internal { +namespace compiler { + +class StructuredMachineAssemblerFriend { + public: + static bool VariableAlive(StructuredMachineAssembler* m, + const Variable& var) { + CHECK(m->current_environment_ != NULL); + int offset = var.offset_; + return offset < static_cast<int>(m->CurrentVars()->size()) && + m->CurrentVars()->at(offset) != NULL; + } +}; +} +} +} // namespace v8::internal::compiler + + +TEST(RunVariable) { + StructuredMachineAssemblerTester<int32_t> m; + + int32_t constant = 0x86c2bb16; + + Variable v1 = m.NewVariable(m.Int32Constant(constant)); + Variable v2 = m.NewVariable(v1.Get()); + m.Return(v2.Get()); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunSimpleIf) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xc4a3e3a6; + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)).Then(); + m.Return(m.Int32Constant(constant)); + } + m.Return(m.Word32Not(m.Int32Constant(constant))); + + CHECK_EQ(~constant, m.Call(0)); + CHECK_EQ(constant, m.Call(1)); +} + + +TEST(RunSimpleIfVariable) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xdb6f20c2; + Variable var = m.NewVariable(m.Int32Constant(constant)); + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)).Then(); + var.Set(m.Word32Not(var.Get())); + } + m.Return(var.Get()); + + CHECK_EQ(constant, m.Call(0)); + CHECK_EQ(~constant, m.Call(1)); +} + + +TEST(RunSimpleElse) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xfc5eadf4; + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)).Else(); + m.Return(m.Int32Constant(constant)); + } + m.Return(m.Word32Not(m.Int32Constant(constant))); + + CHECK_EQ(constant, m.Call(0)); + CHECK_EQ(~constant, m.Call(1)); +} + + +TEST(RunSimpleIfElse) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xaa9c8cd3; + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)).Then(); + m.Return(m.Int32Constant(constant)); + cond.Else(); + m.Return(m.Word32Not(m.Int32Constant(constant))); + } + + CHECK_EQ(~constant, m.Call(0)); + CHECK_EQ(constant, m.Call(1)); +} + + +TEST(RunSimpleIfElseVariable) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0x67b6f39c; + Variable var = m.NewVariable(m.Int32Constant(constant)); + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)).Then(); + var.Set(m.Word32Not(m.Word32Not(var.Get()))); + cond.Else(); + var.Set(m.Word32Not(var.Get())); + } + m.Return(var.Get()); + + CHECK_EQ(~constant, m.Call(0)); + CHECK_EQ(constant, m.Call(1)); +} + + +TEST(RunSimpleIfNoThenElse) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xd5e550ed; + { + IfBuilder cond(&m); + cond.If(m.Parameter(0)); + } + m.Return(m.Int32Constant(constant)); + + CHECK_EQ(constant, m.Call(0)); + CHECK_EQ(constant, m.Call(1)); +} + + +TEST(RunSimpleConjunctionVariable) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0xf8fb9ec6; + Variable var = m.NewVariable(m.Int32Constant(constant)); + { + IfBuilder cond(&m); + cond.If(m.Int32Constant(1)).And(); + var.Set(m.Word32Not(var.Get())); + cond.If(m.Parameter(0)).Then(); + var.Set(m.Word32Not(m.Word32Not(var.Get()))); + cond.Else(); + var.Set(m.Word32Not(var.Get())); + } + m.Return(var.Get()); + + CHECK_EQ(constant, m.Call(0)); + CHECK_EQ(~constant, m.Call(1)); +} + + +TEST(RunSimpleDisjunctionVariable) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0x118f6ffc; + Variable var = m.NewVariable(m.Int32Constant(constant)); + { + IfBuilder cond(&m); + cond.If(m.Int32Constant(0)).Or(); + var.Set(m.Word32Not(var.Get())); + cond.If(m.Parameter(0)).Then(); + var.Set(m.Word32Not(m.Word32Not(var.Get()))); + cond.Else(); + var.Set(m.Word32Not(var.Get())); + } + m.Return(var.Get()); + + CHECK_EQ(constant, m.Call(0)); + CHECK_EQ(~constant, m.Call(1)); +} + + +TEST(RunIfElse) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + { + IfBuilder cond(&m); + bool first = true; + FOR_INT32_INPUTS(i) { + Node* c = m.Int32Constant(*i); + if (first) { + cond.If(m.Word32Equal(m.Parameter(0), c)).Then(); + m.Return(c); + first = false; + } else { + cond.Else(); + cond.If(m.Word32Equal(m.Parameter(0), c)).Then(); + m.Return(c); + } + } + } + m.Return(m.Int32Constant(333)); + + FOR_INT32_INPUTS(i) { CHECK_EQ(*i, m.Call(*i)); } +} + + +enum IfBuilderBranchType { kSkipBranch, kBranchFallsThrough, kBranchReturns }; + + +static IfBuilderBranchType all_branch_types[] = { + kSkipBranch, kBranchFallsThrough, kBranchReturns}; + + +static void RunIfBuilderDisjunction(size_t max, IfBuilderBranchType then_type, + IfBuilderBranchType else_type) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + std::vector<int32_t> inputs = ValueHelper::int32_vector(); + std::vector<int32_t>::const_iterator i = inputs.begin(); + int32_t hit = 0x8c723c9a; + int32_t miss = 0x88a6b9f3; + { + Node* p0 = m.Parameter(0); + IfBuilder cond(&m); + for (size_t j = 0; j < max; j++, ++i) { + CHECK(i != inputs.end()); // Thank you STL. + if (j > 0) cond.Or(); + cond.If(m.Word32Equal(p0, m.Int32Constant(*i))); + } + switch (then_type) { + case kSkipBranch: + break; + case kBranchFallsThrough: + cond.Then(); + break; + case kBranchReturns: + cond.Then(); + m.Return(m.Int32Constant(hit)); + break; + } + switch (else_type) { + case kSkipBranch: + break; + case kBranchFallsThrough: + cond.Else(); + break; + case kBranchReturns: + cond.Else(); + m.Return(m.Int32Constant(miss)); + break; + } + } + if (then_type != kBranchReturns || else_type != kBranchReturns) { + m.Return(m.Int32Constant(miss)); + } + + if (then_type != kBranchReturns) hit = miss; + + i = inputs.begin(); + for (size_t j = 0; i != inputs.end(); j++, ++i) { + int32_t result = m.Call(*i); + CHECK_EQ(j < max ? hit : miss, result); + } +} + + +TEST(RunIfBuilderDisjunction) { + size_t len = ValueHelper::int32_vector().size() - 1; + size_t max = len > 10 ? 10 : len - 1; + for (size_t i = 0; i < ARRAY_SIZE(all_branch_types); i++) { + for (size_t j = 0; j < ARRAY_SIZE(all_branch_types); j++) { + for (size_t size = 1; size < max; size++) { + RunIfBuilderDisjunction(size, all_branch_types[i], all_branch_types[j]); + } + RunIfBuilderDisjunction(len, all_branch_types[i], all_branch_types[j]); + } + } +} + + +static void RunIfBuilderConjunction(size_t max, IfBuilderBranchType then_type, + IfBuilderBranchType else_type) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + std::vector<int32_t> inputs = ValueHelper::int32_vector(); + std::vector<int32_t>::const_iterator i = inputs.begin(); + int32_t hit = 0xa0ceb9ca; + int32_t miss = 0x226cafaa; + { + IfBuilder cond(&m); + Node* p0 = m.Parameter(0); + for (size_t j = 0; j < max; j++, ++i) { + if (j > 0) cond.And(); + cond.If(m.Word32NotEqual(p0, m.Int32Constant(*i))); + } + switch (then_type) { + case kSkipBranch: + break; + case kBranchFallsThrough: + cond.Then(); + break; + case kBranchReturns: + cond.Then(); + m.Return(m.Int32Constant(hit)); + break; + } + switch (else_type) { + case kSkipBranch: + break; + case kBranchFallsThrough: + cond.Else(); + break; + case kBranchReturns: + cond.Else(); + m.Return(m.Int32Constant(miss)); + break; + } + } + if (then_type != kBranchReturns || else_type != kBranchReturns) { + m.Return(m.Int32Constant(miss)); + } + + if (then_type != kBranchReturns) hit = miss; + + i = inputs.begin(); + for (size_t j = 0; i != inputs.end(); j++, ++i) { + int32_t result = m.Call(*i); + CHECK_EQ(j >= max ? hit : miss, result); + } +} + + +TEST(RunIfBuilderConjunction) { + size_t len = ValueHelper::int32_vector().size() - 1; + size_t max = len > 10 ? 10 : len - 1; + for (size_t i = 0; i < ARRAY_SIZE(all_branch_types); i++) { + for (size_t j = 0; j < ARRAY_SIZE(all_branch_types); j++) { + for (size_t size = 1; size < max; size++) { + RunIfBuilderConjunction(size, all_branch_types[i], all_branch_types[j]); + } + RunIfBuilderConjunction(len, all_branch_types[i], all_branch_types[j]); + } + } +} + + +static void RunDisjunctionVariables(int disjunctions, bool explicit_then, + bool explicit_else) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0x65a09535; + + Node* cmp_val = m.Int32Constant(constant); + Node* one = m.Int32Constant(1); + Variable var = m.NewVariable(m.Parameter(0)); + { + IfBuilder cond(&m); + cond.If(m.Word32Equal(var.Get(), cmp_val)); + for (int i = 0; i < disjunctions; i++) { + cond.Or(); + var.Set(m.Int32Add(var.Get(), one)); + cond.If(m.Word32Equal(var.Get(), cmp_val)); + } + if (explicit_then) { + cond.Then(); + } + if (explicit_else) { + cond.Else(); + var.Set(m.Int32Add(var.Get(), one)); + } + } + m.Return(var.Get()); + + int adds = disjunctions + (explicit_else ? 1 : 0); + int32_t input = constant - 2 * adds; + for (int i = 0; i < adds; i++) { + CHECK_EQ(input + adds, m.Call(input)); + input++; + } + for (int i = 0; i < adds + 1; i++) { + CHECK_EQ(constant, m.Call(input)); + input++; + } + for (int i = 0; i < adds; i++) { + CHECK_EQ(input + adds, m.Call(input)); + input++; + } +} + + +TEST(RunDisjunctionVariables) { + for (int disjunctions = 0; disjunctions < 10; disjunctions++) { + RunDisjunctionVariables(disjunctions, false, false); + RunDisjunctionVariables(disjunctions, false, true); + RunDisjunctionVariables(disjunctions, true, false); + RunDisjunctionVariables(disjunctions, true, true); + } +} + + +static void RunConjunctionVariables(int conjunctions, bool explicit_then, + bool explicit_else) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + int32_t constant = 0x2c7f4b45; + Node* cmp_val = m.Int32Constant(constant); + Node* one = m.Int32Constant(1); + Variable var = m.NewVariable(m.Parameter(0)); + { + IfBuilder cond(&m); + cond.If(m.Word32NotEqual(var.Get(), cmp_val)); + for (int i = 0; i < conjunctions; i++) { + cond.And(); + var.Set(m.Int32Add(var.Get(), one)); + cond.If(m.Word32NotEqual(var.Get(), cmp_val)); + } + if (explicit_then) { + cond.Then(); + var.Set(m.Int32Add(var.Get(), one)); + } + if (explicit_else) { + cond.Else(); + } + } + m.Return(var.Get()); + + int adds = conjunctions + (explicit_then ? 1 : 0); + int32_t input = constant - 2 * adds; + for (int i = 0; i < adds; i++) { + CHECK_EQ(input + adds, m.Call(input)); + input++; + } + for (int i = 0; i < adds + 1; i++) { + CHECK_EQ(constant, m.Call(input)); + input++; + } + for (int i = 0; i < adds; i++) { + CHECK_EQ(input + adds, m.Call(input)); + input++; + } +} + + +TEST(RunConjunctionVariables) { + for (int conjunctions = 0; conjunctions < 10; conjunctions++) { + RunConjunctionVariables(conjunctions, false, false); + RunConjunctionVariables(conjunctions, false, true); + RunConjunctionVariables(conjunctions, true, false); + RunConjunctionVariables(conjunctions, true, true); + } +} + + +TEST(RunSimpleNestedIf) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); + const size_t NUM_VALUES = 7; + std::vector<int32_t> inputs = ValueHelper::int32_vector(); + CHECK(inputs.size() >= NUM_VALUES); + Node* values[NUM_VALUES]; + for (size_t j = 0; j < NUM_VALUES; j++) { + values[j] = m.Int32Constant(inputs[j]); + } + { + IfBuilder if_0(&m); + if_0.If(m.Word32Equal(m.Parameter(0), values[0])).Then(); + { + IfBuilder if_1(&m); + if_1.If(m.Word32Equal(m.Parameter(1), values[1])).Then(); + { m.Return(values[3]); } + if_1.Else(); + { m.Return(values[4]); } + } + if_0.Else(); + { + IfBuilder if_1(&m); + if_1.If(m.Word32Equal(m.Parameter(1), values[2])).Then(); + { m.Return(values[5]); } + if_1.Else(); + { m.Return(values[6]); } + } + } + + int32_t result = m.Call(inputs[0], inputs[1]); + CHECK_EQ(inputs[3], result); + + result = m.Call(inputs[0], inputs[1] + 1); + CHECK_EQ(inputs[4], result); + + result = m.Call(inputs[0] + 1, inputs[2]); + CHECK_EQ(inputs[5], result); + + result = m.Call(inputs[0] + 1, inputs[2] + 1); + CHECK_EQ(inputs[6], result); +} + + +TEST(RunUnreachableBlockAfterIf) { + StructuredMachineAssemblerTester<int32_t> m; + { + IfBuilder cond(&m); + cond.If(m.Int32Constant(0)).Then(); + m.Return(m.Int32Constant(1)); + cond.Else(); + m.Return(m.Int32Constant(2)); + } + // This is unreachable. + m.Return(m.Int32Constant(3)); + CHECK_EQ(2, m.Call()); +} + + +TEST(RunUnreachableBlockAfterLoop) { + StructuredMachineAssemblerTester<int32_t> m; + { + Loop loop(&m); + m.Return(m.Int32Constant(1)); + } + // This is unreachable. + m.Return(m.Int32Constant(3)); + CHECK_EQ(1, m.Call()); +} + + +TEST(RunSimpleLoop) { + StructuredMachineAssemblerTester<int32_t> m; + int32_t constant = 0x120c1f85; + { + Loop loop(&m); + m.Return(m.Int32Constant(constant)); + } + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunSimpleLoopBreak) { + StructuredMachineAssemblerTester<int32_t> m; + int32_t constant = 0x10ddb0a6; + { + Loop loop(&m); + loop.Break(); + } + m.Return(m.Int32Constant(constant)); + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunCountToTen) { + StructuredMachineAssemblerTester<int32_t> m; + Variable i = m.NewVariable(m.Int32Constant(0)); + Node* ten = m.Int32Constant(10); + Node* one = m.Int32Constant(1); + { + Loop loop(&m); + { + IfBuilder cond(&m); + cond.If(m.Word32Equal(i.Get(), ten)).Then(); + loop.Break(); + } + i.Set(m.Int32Add(i.Get(), one)); + } + m.Return(i.Get()); + CHECK_EQ(10, m.Call()); +} + + +TEST(RunCountToTenAcc) { + StructuredMachineAssemblerTester<int32_t> m; + int32_t constant = 0xf27aed64; + Variable i = m.NewVariable(m.Int32Constant(0)); + Variable var = m.NewVariable(m.Int32Constant(constant)); + Node* ten = m.Int32Constant(10); + Node* one = m.Int32Constant(1); + { + Loop loop(&m); + { + IfBuilder cond(&m); + cond.If(m.Word32Equal(i.Get(), ten)).Then(); + loop.Break(); + } + i.Set(m.Int32Add(i.Get(), one)); + var.Set(m.Int32Add(var.Get(), i.Get())); + } + m.Return(var.Get()); + + CHECK_EQ(constant + 10 + 9 * 5, m.Call()); +} + + +TEST(RunSimpleNestedLoop) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + Node* two = m.Int32Constant(2); + Node* three = m.Int32Constant(3); + { + Loop l1(&m); + { + Loop l2(&m); + { + IfBuilder cond(&m); + cond.If(m.Word32Equal(m.Parameter(0), one)).Then(); + l1.Break(); + } + { + Loop l3(&m); + { + IfBuilder cond(&m); + cond.If(m.Word32Equal(m.Parameter(0), two)).Then(); + l2.Break(); + cond.Else(); + cond.If(m.Word32Equal(m.Parameter(0), three)).Then(); + l3.Break(); + } + m.Return(three); + } + m.Return(two); + } + m.Return(one); + } + m.Return(zero); + + CHECK_EQ(0, m.Call(1)); + CHECK_EQ(1, m.Call(2)); + CHECK_EQ(2, m.Call(3)); + CHECK_EQ(3, m.Call(4)); +} + + +TEST(RunFib) { + StructuredMachineAssemblerTester<int32_t> m(kMachineWord32); + + // Constants. + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + Node* two = m.Int32Constant(2); + // Variables. + // cnt = input + Variable cnt = m.NewVariable(m.Parameter(0)); + // if (cnt < 2) return i + { + IfBuilder lt2(&m); + lt2.If(m.Int32LessThan(cnt.Get(), two)).Then(); + m.Return(cnt.Get()); + } + // cnt -= 2 + cnt.Set(m.Int32Sub(cnt.Get(), two)); + // res = 1 + Variable res = m.NewVariable(one); + { + // prv_0 = 1 + // prv_1 = 1 + Variable prv_0 = m.NewVariable(one); + Variable prv_1 = m.NewVariable(one); + // while (cnt != 0) { + Loop main(&m); + { + IfBuilder nz(&m); + nz.If(m.Word32Equal(cnt.Get(), zero)).Then(); + main.Break(); + } + // res = prv_0 + prv_1 + // prv_0 = prv_1 + // prv_1 = res + res.Set(m.Int32Add(prv_0.Get(), prv_1.Get())); + prv_0.Set(prv_1.Get()); + prv_1.Set(res.Get()); + // cnt-- + cnt.Set(m.Int32Sub(cnt.Get(), one)); + } + m.Return(res.Get()); + + int32_t values[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144}; + for (size_t i = 0; i < ARRAY_SIZE(values); i++) { + CHECK_EQ(values[i], m.Call(static_cast<int32_t>(i))); + } +} + + +static int VariableIntroduction() { + while (true) { + int ret = 0; + for (int i = 0; i < 10; i++) { + for (int j = i; j < 10; j++) { + for (int k = j; k < 10; k++) { + ret++; + } + ret++; + } + ret++; + } + return ret; + } +} + + +TEST(RunVariableIntroduction) { + StructuredMachineAssemblerTester<int32_t> m; + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + // Use an IfBuilder to get out of start block. + { + IfBuilder i0(&m); + i0.If(zero).Then(); + m.Return(one); + } + Node* ten = m.Int32Constant(10); + Variable v0 = + m.NewVariable(zero); // Introduce variable outside of start block. + { + Loop l0(&m); + Variable ret = m.NewVariable(zero); // Introduce loop variable. + { + Loop l1(&m); + { + IfBuilder i1(&m); + i1.If(m.Word32Equal(v0.Get(), ten)).Then(); + l1.Break(); + } + Variable v1 = m.NewVariable(v0.Get()); // Introduce loop variable. + { + Loop l2(&m); + { + IfBuilder i2(&m); + i2.If(m.Word32Equal(v1.Get(), ten)).Then(); + l2.Break(); + } + Variable v2 = m.NewVariable(v1.Get()); // Introduce loop variable. + { + Loop l3(&m); + { + IfBuilder i3(&m); + i3.If(m.Word32Equal(v2.Get(), ten)).Then(); + l3.Break(); + } + ret.Set(m.Int32Add(ret.Get(), one)); + v2.Set(m.Int32Add(v2.Get(), one)); + } + ret.Set(m.Int32Add(ret.Get(), one)); + v1.Set(m.Int32Add(v1.Get(), one)); + } + ret.Set(m.Int32Add(ret.Get(), one)); + v0.Set(m.Int32Add(v0.Get(), one)); + } + m.Return(ret.Get()); // Return loop variable. + } + CHECK_EQ(VariableIntroduction(), m.Call()); +} + + +TEST(RunIfBuilderVariableLiveness) { + StructuredMachineAssemblerTester<int32_t> m; + typedef i::compiler::StructuredMachineAssemblerFriend F; + Node* zero = m.Int32Constant(0); + Variable v_outer = m.NewVariable(zero); + IfBuilder cond(&m); + cond.If(zero).Then(); + Variable v_then = m.NewVariable(zero); + CHECK(F::VariableAlive(&m, v_outer)); + CHECK(F::VariableAlive(&m, v_then)); + cond.Else(); + Variable v_else = m.NewVariable(zero); + CHECK(F::VariableAlive(&m, v_outer)); + CHECK(F::VariableAlive(&m, v_else)); + CHECK(!F::VariableAlive(&m, v_then)); + cond.End(); + CHECK(F::VariableAlive(&m, v_outer)); + CHECK(!F::VariableAlive(&m, v_then)); + CHECK(!F::VariableAlive(&m, v_else)); +} + + +TEST(RunSimpleExpression1) { + StructuredMachineAssemblerTester<int32_t> m; + + int32_t constant = 0x0c2974ef; + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + { + // if (((1 && 1) && 1) && 1) return constant; return 0; + IfBuilder cond(&m); + cond.OpenParen(); + cond.OpenParen().If(one).And(); + cond.If(one).CloseParen().And(); + cond.If(one).CloseParen().And(); + cond.If(one).Then(); + m.Return(m.Int32Constant(constant)); + } + m.Return(zero); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunSimpleExpression2) { + StructuredMachineAssemblerTester<int32_t> m; + + int32_t constant = 0x2eddc11b; + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + { + // if (((0 || 1) && 1) && 1) return constant; return 0; + IfBuilder cond(&m); + cond.OpenParen(); + cond.OpenParen().If(zero).Or(); + cond.If(one).CloseParen().And(); + cond.If(one).CloseParen().And(); + cond.If(one).Then(); + m.Return(m.Int32Constant(constant)); + } + m.Return(zero); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunSimpleExpression3) { + StructuredMachineAssemblerTester<int32_t> m; + + int32_t constant = 0x9ed5e9ef; + Node* zero = m.Int32Constant(0); + Node* one = m.Int32Constant(1); + { + // if (1 && ((0 || 1) && 1) && 1) return constant; return 0; + IfBuilder cond(&m); + cond.If(one).And(); + cond.OpenParen(); + cond.OpenParen().If(zero).Or(); + cond.If(one).CloseParen().And(); + cond.If(one).CloseParen().And(); + cond.If(one).Then(); + m.Return(m.Int32Constant(constant)); + } + m.Return(zero); + + CHECK_EQ(constant, m.Call()); +} + + +TEST(RunSimpleExpressionVariable1) { + StructuredMachineAssemblerTester<int32_t> m; + + int32_t constant = 0x4b40a986; + Node* one = m.Int32Constant(1); + Variable var = m.NewVariable(m.Int32Constant(constant)); + { + // if (var.Get() && ((!var || var) && var) && var) {} return var; + // incrementing var in each environment. + IfBuilder cond(&m); + cond.If(var.Get()).And(); + var.Set(m.Int32Add(var.Get(), one)); + cond.OpenParen().OpenParen().If(m.Word32BinaryNot(var.Get())).Or(); + var.Set(m.Int32Add(var.Get(), one)); + cond.If(var.Get()).CloseParen().And(); + var.Set(m.Int32Add(var.Get(), one)); + cond.If(var.Get()).CloseParen().And(); + var.Set(m.Int32Add(var.Get(), one)); + cond.If(var.Get()); + } + m.Return(var.Get()); + + CHECK_EQ(constant + 4, m.Call()); +} + + +class QuicksortHelper : public StructuredMachineAssemblerTester<int32_t> { + public: + QuicksortHelper() + : StructuredMachineAssemblerTester<int32_t>( + MachineOperatorBuilder::pointer_rep(), kMachineWord32, + MachineOperatorBuilder::pointer_rep(), kMachineWord32), + input_(NULL), + stack_limit_(NULL), + one_(Int32Constant(1)), + stack_frame_size_(Int32Constant(kFrameVariables * 4)), + left_offset_(Int32Constant(0 * 4)), + right_offset_(Int32Constant(1 * 4)) { + Build(); + } + + int32_t DoCall(int32_t* input, int32_t input_length) { + int32_t stack_space[20]; + // Do call. + int32_t return_val = Call(input, input_length, stack_space, + static_cast<int32_t>(ARRAY_SIZE(stack_space))); + // Ran out of stack space. + if (return_val != 0) return return_val; + // Check sorted. + int32_t last = input[0]; + for (int32_t i = 0; i < input_length; i++) { + CHECK(last <= input[i]); + last = input[i]; + } + return return_val; + } + + private: + void Inc32(const Variable& var) { var.Set(Int32Add(var.Get(), one_)); } + Node* Index(Node* index) { return Word32Shl(index, Int32Constant(2)); } + Node* ArrayLoad(Node* index) { + return Load(kMachineWord32, input_, Index(index)); + } + void Swap(Node* a_index, Node* b_index) { + Node* a = ArrayLoad(a_index); + Node* b = ArrayLoad(b_index); + Store(kMachineWord32, input_, Index(a_index), b); + Store(kMachineWord32, input_, Index(b_index), a); + } + void AddToCallStack(const Variable& fp, Node* left, Node* right) { + { + // Stack limit check. + IfBuilder cond(this); + cond.If(IntPtrLessThanOrEqual(fp.Get(), stack_limit_)).Then(); + Return(Int32Constant(-1)); + } + Store(kMachineWord32, fp.Get(), left_offset_, left); + Store(kMachineWord32, fp.Get(), right_offset_, right); + fp.Set(IntPtrAdd(fp.Get(), ConvertInt32ToIntPtr(stack_frame_size_))); + } + void Build() { + Variable left = NewVariable(Int32Constant(0)); + Variable right = + NewVariable(Int32Sub(Parameter(kInputLengthParameter), one_)); + input_ = Parameter(kInputParameter); + Node* top_of_stack = Parameter(kStackParameter); + stack_limit_ = IntPtrSub( + top_of_stack, ConvertInt32ToIntPtr(Parameter(kStackLengthParameter))); + Variable fp = NewVariable(top_of_stack); + { + Loop outermost(this); + // Edge case - 2 element array. + { + IfBuilder cond(this); + cond.If(Word32Equal(left.Get(), Int32Sub(right.Get(), one_))).And(); + cond.If(Int32LessThanOrEqual(ArrayLoad(right.Get()), + ArrayLoad(left.Get()))).Then(); + Swap(left.Get(), right.Get()); + } + { + IfBuilder cond(this); + // Algorithm complete condition. + cond.If(WordEqual(top_of_stack, fp.Get())).And(); + cond.If(Int32LessThanOrEqual(Int32Sub(right.Get(), one_), left.Get())) + .Then(); + outermost.Break(); + // 'Recursion' exit condition. Pop frame and continue. + cond.Else(); + cond.If(Int32LessThanOrEqual(Int32Sub(right.Get(), one_), left.Get())) + .Then(); + fp.Set(IntPtrSub(fp.Get(), ConvertInt32ToIntPtr(stack_frame_size_))); + left.Set(Load(kMachineWord32, fp.Get(), left_offset_)); + right.Set(Load(kMachineWord32, fp.Get(), right_offset_)); + outermost.Continue(); + } + // Partition. + Variable store_index = NewVariable(left.Get()); + { + Node* pivot_index = + Int32Div(Int32Add(left.Get(), right.Get()), Int32Constant(2)); + Node* pivot = ArrayLoad(pivot_index); + Swap(pivot_index, right.Get()); + Variable i = NewVariable(left.Get()); + { + Loop partition(this); + { + IfBuilder cond(this); + // Parition complete. + cond.If(Word32Equal(i.Get(), right.Get())).Then(); + partition.Break(); + // Need swap. + cond.Else(); + cond.If(Int32LessThanOrEqual(ArrayLoad(i.Get()), pivot)).Then(); + Swap(i.Get(), store_index.Get()); + Inc32(store_index); + } + Inc32(i); + } // End partition loop. + Swap(store_index.Get(), right.Get()); + } + // 'Recurse' left and right halves of partition. + // Tail recurse second one. + AddToCallStack(fp, left.Get(), Int32Sub(store_index.Get(), one_)); + left.Set(Int32Add(store_index.Get(), one_)); + } // End outermost loop. + Return(Int32Constant(0)); + } + + static const int kFrameVariables = 2; // left, right + // Parameter offsets. + static const int kInputParameter = 0; + static const int kInputLengthParameter = 1; + static const int kStackParameter = 2; + static const int kStackLengthParameter = 3; + // Function inputs. + Node* input_; + Node* stack_limit_; + // Constants. + Node* const one_; + // Frame constants. + Node* const stack_frame_size_; + Node* const left_offset_; + Node* const right_offset_; +}; + + +TEST(RunSimpleQuicksort) { + QuicksortHelper m; + int32_t inputs[] = {9, 7, 1, 8, 11}; + CHECK_EQ(0, m.DoCall(inputs, ARRAY_SIZE(inputs))); +} + + +TEST(RunRandomQuicksort) { + QuicksortHelper m; + + v8::base::RandomNumberGenerator rng; + static const int kMaxLength = 40; + int32_t inputs[kMaxLength]; + + for (int length = 1; length < kMaxLength; length++) { + for (int i = 0; i < 70; i++) { + // Randomize inputs. + for (int j = 0; j < length; j++) { + inputs[j] = rng.NextInt(10) - 5; + } + CHECK_EQ(0, m.DoCall(inputs, length)); + } + } +} + + +TEST(MultipleScopes) { + StructuredMachineAssemblerTester<int32_t> m; + for (int i = 0; i < 10; i++) { + IfBuilder b(&m); + b.If(m.Int32Constant(0)).Then(); + m.NewVariable(m.Int32Constant(0)); + } + m.Return(m.Int32Constant(0)); + CHECK_EQ(0, m.Call()); +} + +#endif diff --git a/deps/v8/test/cctest/compiler/value-helper.h b/deps/v8/test/cctest/compiler/value-helper.h new file mode 100644 index 0000000000..5bfd7884d0 --- /dev/null +++ b/deps/v8/test/cctest/compiler/value-helper.h @@ -0,0 +1,131 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CCTEST_COMPILER_VALUE_HELPER_H_ +#define V8_CCTEST_COMPILER_VALUE_HELPER_H_ + +#include "src/v8.h" + +#include "src/compiler/common-operator.h" +#include "src/compiler/node.h" +#include "src/compiler/node-matchers.h" +#include "src/isolate.h" +#include "src/objects.h" +#include "test/cctest/cctest.h" + +namespace v8 { +namespace internal { +namespace compiler { + +// A collection of utilities related to numerical and heap values, including +// example input values of various types, including int32_t, uint32_t, double, +// etc. +class ValueHelper { + public: + Isolate* isolate_; + + ValueHelper() : isolate_(CcTest::InitIsolateOnce()) {} + + template <typename T> + void CheckConstant(T expected, Node* node) { + CHECK_EQ(expected, ValueOf<T>(node->op())); + } + + void CheckFloat64Constant(double expected, Node* node) { + CHECK_EQ(IrOpcode::kFloat64Constant, node->opcode()); + CHECK_EQ(expected, ValueOf<double>(node->op())); + } + + void CheckNumberConstant(double expected, Node* node) { + CHECK_EQ(IrOpcode::kNumberConstant, node->opcode()); + CHECK_EQ(expected, ValueOf<double>(node->op())); + } + + void CheckInt32Constant(int32_t expected, Node* node) { + CHECK_EQ(IrOpcode::kInt32Constant, node->opcode()); + CHECK_EQ(expected, ValueOf<int32_t>(node->op())); + } + + void CheckUint32Constant(int32_t expected, Node* node) { + CHECK_EQ(IrOpcode::kInt32Constant, node->opcode()); + CHECK_EQ(expected, ValueOf<uint32_t>(node->op())); + } + + void CheckHeapConstant(Object* expected, Node* node) { + CHECK_EQ(IrOpcode::kHeapConstant, node->opcode()); + CHECK_EQ(expected, *ValueOf<Handle<Object> >(node->op())); + } + + void CheckTrue(Node* node) { + CheckHeapConstant(isolate_->heap()->true_value(), node); + } + + void CheckFalse(Node* node) { + CheckHeapConstant(isolate_->heap()->false_value(), node); + } + + static std::vector<double> float64_vector() { + static const double nan = v8::base::OS::nan_value(); + static const double values[] = { + 0.125, 0.25, 0.375, 0.5, + 1.25, -1.75, 2, 5.125, + 6.25, 0.0, -0.0, 982983.25, + 888, 2147483647.0, -999.75, 3.1e7, + -2e66, 3e-88, -2147483648.0, V8_INFINITY, + -V8_INFINITY, nan, 2147483647.375, 2147483647.75, + 2147483648.0, 2147483648.25, 2147483649.25, -2147483647.0, + -2147483647.125, -2147483647.875, -2147483648.25, -2147483649.5}; + return std::vector<double>(&values[0], &values[ARRAY_SIZE(values)]); + } + + static const std::vector<int32_t> int32_vector() { + std::vector<uint32_t> values = uint32_vector(); + return std::vector<int32_t>(values.begin(), values.end()); + } + + static const std::vector<uint32_t> uint32_vector() { + static const uint32_t kValues[] = { + 0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf, + 0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344, + 0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c, + 0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00, + 0x761c4761, 0x80000000, 0x88888888, 0xa0000000, 0xdddddddd, 0xe0000000, + 0xeeeeeeee, 0xfffffffd, 0xf0000000, 0x007fffff, 0x003fffff, 0x001fffff, + 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff, + 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff}; + return std::vector<uint32_t>(&kValues[0], &kValues[ARRAY_SIZE(kValues)]); + } + + static const std::vector<double> nan_vector(size_t limit = 0) { + static const double nan = v8::base::OS::nan_value(); + static const double values[] = {-nan, -V8_INFINITY * -0.0, + -V8_INFINITY * 0.0, V8_INFINITY * -0.0, + V8_INFINITY * 0.0, nan}; + return std::vector<double>(&values[0], &values[ARRAY_SIZE(values)]); + } + + static const std::vector<uint32_t> ror_vector() { + static const uint32_t kValues[31] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + return std::vector<uint32_t>(&kValues[0], &kValues[ARRAY_SIZE(kValues)]); + } +}; + +// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... *i ... } +// Watch out, these macros aren't hygenic; they pollute your scope. Thanks STL. +#define FOR_INPUTS(ctype, itype, var) \ + std::vector<ctype> var##_vec = ValueHelper::itype##_vector(); \ + for (std::vector<ctype>::iterator var = var##_vec.begin(); \ + var != var##_vec.end(); ++var) + +#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var) +#define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var) +#define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var) + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_CCTEST_COMPILER_VALUE_HELPER_H_ diff --git a/deps/v8/test/cctest/gay-fixed.cc b/deps/v8/test/cctest/gay-fixed.cc index 071ea4f8c1..81463ac1fa 100644 --- a/deps/v8/test/cctest/gay-fixed.cc +++ b/deps/v8/test/cctest/gay-fixed.cc @@ -29,9 +29,9 @@ // have been generated using Gay's dtoa to produce the fixed representation: // dtoa(v, 3, number_digits, &decimal_point, &sign, NULL); -#include "v8.h" +#include "src/v8.h" -#include "gay-fixed.h" +#include "test/cctest/gay-fixed.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/gay-precision.cc b/deps/v8/test/cctest/gay-precision.cc index c0e993509f..6ab2715fea 100644 --- a/deps/v8/test/cctest/gay-precision.cc +++ b/deps/v8/test/cctest/gay-precision.cc @@ -29,9 +29,9 @@ // have been generated using Gay's dtoa to produce the precision representation: // dtoa(v, 2, number_digits, &decimal_point, &sign, NULL); -#include "v8.h" +#include "src/v8.h" -#include "gay-precision.h" +#include "test/cctest/gay-precision.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/gay-shortest.cc b/deps/v8/test/cctest/gay-shortest.cc index d065e97782..896ea4c514 100644 --- a/deps/v8/test/cctest/gay-shortest.cc +++ b/deps/v8/test/cctest/gay-shortest.cc @@ -29,9 +29,9 @@ // have been generated using Gay's dtoa to produce the shortest representation: // decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL); -#include "v8.h" +#include "src/v8.h" -#include "gay-shortest.h" +#include "test/cctest/gay-shortest.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/print-extension.cc b/deps/v8/test/cctest/print-extension.cc index 9f629195bd..d1af3596e8 100644 --- a/deps/v8/test/cctest/print-extension.cc +++ b/deps/v8/test/cctest/print-extension.cc @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "print-extension.h" +#include "test/cctest/print-extension.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/print-extension.h b/deps/v8/test/cctest/print-extension.h index 7fe9226f7b..b0d2b1ca19 100644 --- a/deps/v8/test/cctest/print-extension.h +++ b/deps/v8/test/cctest/print-extension.h @@ -28,7 +28,7 @@ #ifndef V8_TEST_CCTEST_PRINT_EXTENSION_H_ #define V8_TEST_CCTEST_PRINT_EXTENSION_H_ -#include "v8.h" +#include "src/v8.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/profiler-extension.cc b/deps/v8/test/cctest/profiler-extension.cc index 1fdd1ba247..263fc4f38d 100644 --- a/deps/v8/test/cctest/profiler-extension.cc +++ b/deps/v8/test/cctest/profiler-extension.cc @@ -27,8 +27,8 @@ // // Tests of profiles generator and utilities. -#include "profiler-extension.h" -#include "checks.h" +#include "src/base/logging.h" +#include "test/cctest/profiler-extension.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/profiler-extension.h b/deps/v8/test/cctest/profiler-extension.h index c26a29c39a..6f816b33fb 100644 --- a/deps/v8/test/cctest/profiler-extension.h +++ b/deps/v8/test/cctest/profiler-extension.h @@ -30,7 +30,7 @@ #ifndef V8_TEST_CCTEST_PROFILER_EXTENSION_H_ #define V8_TEST_CCTEST_PROFILER_EXTENSION_H_ -#include "../include/v8-profiler.h" +#include "include/v8-profiler.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index daafb244e3..5bf61c8fca 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -27,12 +27,12 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "api.h" -#include "cctest.h" -#include "frames-inl.h" -#include "string-stream.h" +#include "src/api.h" +#include "src/frames-inl.h" +#include "src/string-stream.h" +#include "test/cctest/cctest.h" using ::v8::ObjectTemplate; using ::v8::Value; @@ -229,54 +229,6 @@ THREADED_TEST(AccessorIC) { } -static void AccessorProhibitsOverwritingGetter( - Local<String> name, - const v8::PropertyCallbackInfo<v8::Value>& info) { - ApiTestFuzzer::Fuzz(); - info.GetReturnValue().Set(true); -} - - -THREADED_TEST(AccessorProhibitsOverwriting) { - LocalContext context; - v8::Isolate* isolate = context->GetIsolate(); - v8::HandleScope scope(isolate); - Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetAccessor(v8_str("x"), - AccessorProhibitsOverwritingGetter, - 0, - v8::Handle<Value>(), - v8::PROHIBITS_OVERWRITING, - v8::ReadOnly); - Local<v8::Object> instance = templ->NewInstance(); - context->Global()->Set(v8_str("obj"), instance); - Local<Value> value = CompileRun( - "obj.__defineGetter__('x', function() { return false; });" - "obj.x"); - CHECK(value->BooleanValue()); - value = CompileRun( - "var setter_called = false;" - "obj.__defineSetter__('x', function() { setter_called = true; });" - "obj.x = 42;" - "setter_called"); - CHECK(!value->BooleanValue()); - value = CompileRun( - "obj2 = {};" - "obj2.__proto__ = obj;" - "obj2.__defineGetter__('x', function() { return false; });" - "obj2.x"); - CHECK(value->BooleanValue()); - value = CompileRun( - "var setter_called = false;" - "obj2 = {};" - "obj2.__proto__ = obj;" - "obj2.__defineSetter__('x', function() { setter_called = true; });" - "obj2.x = 42;" - "setter_called"); - CHECK(!value->BooleanValue()); -} - - template <int C> static void HandleAllocatingGetter( Local<String> name, diff --git a/deps/v8/test/cctest/test-alloc.cc b/deps/v8/test/cctest/test-alloc.cc index 7a213ae4b5..314c3c1479 100644 --- a/deps/v8/test/cctest/test-alloc.cc +++ b/deps/v8/test/cctest/test-alloc.cc @@ -25,11 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" -#include "accessors.h" -#include "api.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "cctest.h" +#include "src/accessors.h" +#include "src/api.h" using namespace v8::internal; @@ -50,7 +50,6 @@ static AllocationResult AllocateAfterFailures() { // for specific kinds. heap->AllocateFixedArray(100).ToObjectChecked(); heap->AllocateHeapNumber(0.42).ToObjectChecked(); - heap->AllocateArgumentsObject(Smi::FromInt(87), 10).ToObjectChecked(); Object* object = heap->AllocateJSObject( *CcTest::i_isolate()->object_function()).ToObjectChecked(); heap->CopyJSObject(JSObject::cast(object)).ToObjectChecked(); @@ -67,7 +66,7 @@ static AllocationResult AllocateAfterFailures() { static const int kLargeObjectSpaceFillerLength = 300000; static const int kLargeObjectSpaceFillerSize = FixedArray::SizeFor( kLargeObjectSpaceFillerLength); - ASSERT(kLargeObjectSpaceFillerSize > heap->old_pointer_space()->AreaSize()); + DCHECK(kLargeObjectSpaceFillerSize > heap->old_pointer_space()->AreaSize()); while (heap->OldGenerationSpaceAvailable() > kLargeObjectSpaceFillerSize) { heap->AllocateFixedArray( kLargeObjectSpaceFillerLength, TENURED).ToObjectChecked(); @@ -137,8 +136,8 @@ TEST(StressJS) { v8::HandleScope scope(CcTest::isolate()); v8::Handle<v8::Context> env = v8::Context::New(CcTest::isolate()); env->Enter(); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - factory->function_string(), factory->null_value()); + Handle<JSFunction> function = factory->NewFunction( + factory->function_string()); // Force the creation of an initial map and set the code to // something empty. factory->NewJSObject(function); @@ -147,7 +146,7 @@ TEST(StressJS) { // Patch the map to have an accessor for "get". Handle<Map> map(function->initial_map()); Handle<DescriptorArray> instance_descriptors(map->instance_descriptors()); - ASSERT(instance_descriptors->IsEmpty()); + DCHECK(instance_descriptors->IsEmpty()); PropertyAttributes attrs = static_cast<PropertyAttributes>(0); Handle<AccessorInfo> foreign = TestAccessorInfo(isolate, attrs); @@ -196,13 +195,13 @@ class Block { TEST(CodeRange) { - const int code_range_size = 32*MB; + const size_t code_range_size = 32*MB; CcTest::InitializeVM(); CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate())); code_range.SetUp(code_range_size); - int current_allocated = 0; - int total_allocated = 0; - List<Block> blocks(1000); + size_t current_allocated = 0; + size_t total_allocated = 0; + List< ::Block> blocks(1000); while (total_allocated < 5 * code_range_size) { if (current_allocated < code_range_size / 10) { @@ -219,7 +218,7 @@ TEST(CodeRange) { requested, &allocated); CHECK(base != NULL); - blocks.Add(Block(base, static_cast<int>(allocated))); + blocks.Add(::Block(base, static_cast<int>(allocated))); current_allocated += static_cast<int>(allocated); total_allocated += static_cast<int>(allocated); } else { diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 14df05a8e8..9ddc9db71d 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -27,30 +27,30 @@ #include <climits> #include <csignal> -#include <string> #include <map> +#include <string> -#include "v8.h" +#include "src/v8.h" #if V8_OS_POSIX #include <unistd.h> // NOLINT #endif -#include "api.h" -#include "arguments.h" -#include "cctest.h" -#include "compilation-cache.h" -#include "cpu-profiler.h" -#include "execution.h" -#include "isolate.h" -#include "objects.h" -#include "parser.h" -#include "platform.h" -#include "snapshot.h" -#include "unicode-inl.h" -#include "utils.h" -#include "vm-state.h" -#include "../include/v8-util.h" +#include "include/v8-util.h" +#include "src/api.h" +#include "src/arguments.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/cpu-profiler.h" +#include "src/execution.h" +#include "src/isolate.h" +#include "src/objects.h" +#include "src/parser.h" +#include "src/snapshot.h" +#include "src/unicode-inl.h" +#include "src/utils.h" +#include "src/vm-state.h" +#include "test/cctest/cctest.h" static const bool kLogThreading = false; @@ -99,50 +99,6 @@ void RunWithProfiler(void (*test)()) { } -static void ExpectString(const char* code, const char* expected) { - Local<Value> result = CompileRun(code); - CHECK(result->IsString()); - String::Utf8Value utf8(result); - CHECK_EQ(expected, *utf8); -} - - -static void ExpectInt32(const char* code, int expected) { - Local<Value> result = CompileRun(code); - CHECK(result->IsInt32()); - CHECK_EQ(expected, result->Int32Value()); -} - - -static void ExpectBoolean(const char* code, bool expected) { - Local<Value> result = CompileRun(code); - CHECK(result->IsBoolean()); - CHECK_EQ(expected, result->BooleanValue()); -} - - -static void ExpectTrue(const char* code) { - ExpectBoolean(code, true); -} - - -static void ExpectFalse(const char* code) { - ExpectBoolean(code, false); -} - - -static void ExpectObject(const char* code, Local<Value> expected) { - Local<Value> result = CompileRun(code); - CHECK(result->Equals(expected)); -} - - -static void ExpectUndefined(const char* code) { - Local<Value> result = CompileRun(code); - CHECK(result->IsUndefined()); -} - - static int signature_callback_count; static Local<Value> signature_expected_receiver; static void IncrementingSignatureCallback( @@ -230,11 +186,11 @@ THREADED_TEST(IsolateOfContext) { static void TestSignature(const char* loop_js, Local<Value> receiver) { i::ScopedVector<char> source(200); - i::OS::SNPrintF(source, - "for (var i = 0; i < 10; i++) {" - " %s" - "}", - loop_js); + i::SNPrintF(source, + "for (var i = 0; i < 10; i++) {" + " %s" + "}", + loop_js); signature_callback_count = 0; signature_expected_receiver = receiver; bool expected_to_throw = receiver.IsEmpty(); @@ -307,7 +263,7 @@ THREADED_TEST(ReceiverSignature) { unsigned bad_signature_start_offset = 2; for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) { i::ScopedVector<char> source(200); - i::OS::SNPrintF( + i::SNPrintF( source, "var test_object = %s; test_object", test_objects[i]); Local<Value> test_object = CompileRun(source.start()); TestSignature("test_object.prop();", test_object); @@ -451,17 +407,10 @@ THREADED_TEST(Script) { } -static uint16_t* AsciiToTwoByteString(const char* source) { - int array_length = i::StrLength(source) + 1; - uint16_t* converted = i::NewArray<uint16_t>(array_length); - for (int i = 0; i < array_length; i++) converted[i] = source[i]; - return converted; -} - - class TestResource: public String::ExternalStringResource { public: - TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true) + explicit TestResource(uint16_t* data, int* counter = NULL, + bool owning_data = true) : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { while (data[length_]) ++length_; } @@ -489,11 +438,12 @@ class TestResource: public String::ExternalStringResource { class TestAsciiResource: public String::ExternalAsciiStringResource { public: - TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0) + explicit TestAsciiResource(const char* data, int* counter = NULL, + size_t offset = 0) : orig_data_(data), data_(data + offset), length_(strlen(data) - offset), - counter_(counter) { } + counter_(counter) {} ~TestAsciiResource() { i::DeleteArray(orig_data_); @@ -2004,6 +1954,27 @@ THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { } +THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + v8::Local<v8::Value> res = CompileRun("var a = []; a;"); + i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); + CHECK(a->map()->instance_descriptors()->IsFixedArray()); + CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); + CompileRun("Object.defineProperty(a, 'length', { writable: false });"); + CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); + // But we should still have an ExecutableAccessorInfo. + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::LookupResult lookup(i_isolate); + i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); + a->LookupOwnRealNamedProperty(name, &lookup); + CHECK(lookup.IsPropertyCallbacks()); + i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate); + CHECK(callback->IsExecutableAccessorInfo()); +} + + THREADED_TEST(EmptyInterceptorBreakTransitions) { v8::HandleScope scope(CcTest::isolate()); Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); @@ -2768,8 +2739,6 @@ THREADED_TEST(GlobalProxyIdentityHash) { THREADED_TEST(SymbolProperties) { - i::FLAG_harmony_symbols = true; - LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -2918,8 +2887,6 @@ THREADED_TEST(PrivateProperties) { THREADED_TEST(GlobalSymbols) { - i::FLAG_harmony_symbols = true; - LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -3003,7 +2970,7 @@ THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); - ASSERT(data != NULL); + DCHECK(data != NULL); env->Global()->Set(v8_str("ab"), ab); v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); @@ -3112,7 +3079,7 @@ static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) { static void CheckIsTypedArrayVarNeutered(const char* name) { i::ScopedVector<char> source(1024); - i::OS::SNPrintF(source, + i::SNPrintF(source, "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", name, name, name); CHECK(CompileRun(source.start())->IsTrue()); @@ -4184,7 +4151,7 @@ bool message_received; static void check_message_0(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK_EQ(5.76, data->NumberValue()); - CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); CHECK(!message->IsSharedCrossOrigin()); message_received = true; } @@ -4258,7 +4225,7 @@ TEST(MessageHandler2) { static void check_message_3(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK(message->IsSharedCrossOrigin()); - CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); message_received = true; } @@ -4287,7 +4254,7 @@ TEST(MessageHandler3) { static void check_message_4(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK(!message->IsSharedCrossOrigin()); - CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); message_received = true; } @@ -4316,7 +4283,7 @@ TEST(MessageHandler4) { static void check_message_5a(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK(message->IsSharedCrossOrigin()); - CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); message_received = true; } @@ -4324,7 +4291,7 @@ static void check_message_5a(v8::Handle<v8::Message> message, static void check_message_5b(v8::Handle<v8::Message> message, v8::Handle<Value> data) { CHECK(!message->IsSharedCrossOrigin()); - CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); + CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); message_received = true; } @@ -4404,7 +4371,7 @@ THREADED_TEST(PropertyAttributes) { CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); // read-only prop = v8_str("read_only"); - context->Global()->Set(prop, v8_num(7), v8::ReadOnly); + context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly); CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); CompileRun("read_only = 9"); @@ -4413,14 +4380,14 @@ THREADED_TEST(PropertyAttributes) { CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); // dont-delete prop = v8_str("dont_delete"); - context->Global()->Set(prop, v8_num(13), v8::DontDelete); + context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete); CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); CompileRun("delete dont_delete"); CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); // dont-enum prop = v8_str("dont_enum"); - context->Global()->Set(prop, v8_num(28), v8::DontEnum); + context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum); CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); // absent prop = v8_str("absent"); @@ -5343,15 +5310,28 @@ THREADED_TEST(TryCatchAndFinally) { } -static void TryCatchNestedHelper(int depth) { +static void TryCatchNested1Helper(int depth) { + if (depth > 0) { + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + TryCatchNested1Helper(depth - 1); + CHECK(try_catch.HasCaught()); + try_catch.ReThrow(); + } else { + CcTest::isolate()->ThrowException(v8_str("E1")); + } +} + + +static void TryCatchNested2Helper(int depth) { if (depth > 0) { v8::TryCatch try_catch; try_catch.SetVerbose(true); - TryCatchNestedHelper(depth - 1); + TryCatchNested2Helper(depth - 1); CHECK(try_catch.HasCaught()); try_catch.ReThrow(); } else { - CcTest::isolate()->ThrowException(v8_str("back")); + CompileRun("throw 'E2';"); } } @@ -5360,17 +5340,29 @@ TEST(TryCatchNested) { v8::V8::Initialize(); LocalContext context; v8::HandleScope scope(context->GetIsolate()); - v8::TryCatch try_catch; - TryCatchNestedHelper(5); - CHECK(try_catch.HasCaught()); - CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); + + { + // Test nested try-catch with a native throw in the end. + v8::TryCatch try_catch; + TryCatchNested1Helper(5); + CHECK(try_catch.HasCaught()); + CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1")); + } + + { + // Test nested try-catch with a JavaScript throw in the end. + v8::TryCatch try_catch; + TryCatchNested2Helper(5); + CHECK(try_catch.HasCaught()); + CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2")); + } } void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { CHECK(try_catch->HasCaught()); Handle<Message> message = try_catch->Message(); - Handle<Value> resource = message->GetScriptResourceName(); + Handle<Value> resource = message->GetScriptOrigin().ResourceName(); CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a")); @@ -5409,6 +5401,53 @@ TEST(TryCatchMixedNesting) { } +void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) { + ApiTestFuzzer::Fuzz(); + v8::TryCatch try_catch; + args.GetIsolate()->ThrowException(v8_str("boom")); + CHECK(try_catch.HasCaught()); +} + + +TEST(TryCatchNative) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::V8::Initialize(); + v8::TryCatch try_catch; + Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); + templ->Set(v8_str("TryCatchNativeHelper"), + v8::FunctionTemplate::New(isolate, TryCatchNativeHelper)); + LocalContext context(0, templ); + CompileRun("TryCatchNativeHelper();"); + CHECK(!try_catch.HasCaught()); +} + + +void TryCatchNativeResetHelper( + const v8::FunctionCallbackInfo<v8::Value>& args) { + ApiTestFuzzer::Fuzz(); + v8::TryCatch try_catch; + args.GetIsolate()->ThrowException(v8_str("boom")); + CHECK(try_catch.HasCaught()); + try_catch.Reset(); + CHECK(!try_catch.HasCaught()); +} + + +TEST(TryCatchNativeReset) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::V8::Initialize(); + v8::TryCatch try_catch; + Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); + templ->Set(v8_str("TryCatchNativeResetHelper"), + v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper)); + LocalContext context(0, templ); + CompileRun("TryCatchNativeResetHelper();"); + CHECK(!try_catch.HasCaught()); +} + + THREADED_TEST(Equality) { LocalContext context; v8::Isolate* isolate = context->GetIsolate(); @@ -5430,7 +5469,7 @@ THREADED_TEST(Equality) { CHECK(v8_num(1)->StrictEquals(v8_num(1))); CHECK(!v8_num(1)->StrictEquals(v8_num(2))); CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); - Local<Value> not_a_number = v8_num(i::OS::nan_value()); + Local<Value> not_a_number = v8_num(v8::base::OS::nan_value()); CHECK(!not_a_number->StrictEquals(not_a_number)); CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); @@ -6162,15 +6201,17 @@ THREADED_TEST(IndexedInterceptorWithAccessorCheck) { context->Global()->Set(v8_str("obj"), obj); const char* code = - "try {" - " for (var i = 0; i < 100; i++) {" + "var result = 'PASSED';" + "for (var i = 0; i < 100; i++) {" + " try {" " var v = obj[0];" - " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;" + " result = 'Wrong value ' + v + ' at iteration ' + i;" + " break;" + " } catch (e) {" + " /* pass */" " }" - " 'PASSED'" - "} catch(e) {" - " e" - "}"; + "}" + "result"; ExpectString(code, "PASSED"); } @@ -6187,21 +6228,29 @@ THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { context->Global()->Set(v8_str("obj"), obj); const char* code = - "try {" - " for (var i = 0; i < 100; i++) {" - " var expected = i;" + "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) {" - " %EnableAccessChecks(obj);" - " expected = undefined;" + " 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;" " }" - " var v = obj[i];" - " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" - " if (i == 5) %DisableAccessChecks(obj);" " }" - " 'PASSED'" - "} catch(e) {" - " e" - "}"; + " if (i == 5) %DisableAccessChecks(obj);" + "}" + "result"; ExpectString(code, "PASSED"); } @@ -6670,9 +6719,6 @@ TEST(UndetectableOptimized) { } -template <typename T> static void USE(T) { } - - // The point of this test is type checking. We run it only so compilers // don't complain about an unused function. TEST(PersistentHandles) { @@ -6728,6 +6774,33 @@ TEST(SimpleExtensions) { } +static const char* kStackTraceFromExtensionSource = + "function foo() {" + " throw new Error();" + "}" + "function bar() {" + " foo();" + "}"; + + +TEST(StackTraceInExtension) { + v8::HandleScope handle_scope(CcTest::isolate()); + v8::RegisterExtension(new Extension("stacktracetest", + kStackTraceFromExtensionSource)); + const char* extension_names[] = { "stacktracetest" }; + v8::ExtensionConfiguration extensions(1, extension_names); + v8::Handle<Context> context = + Context::New(CcTest::isolate(), &extensions); + Context::Scope lock(context); + CompileRun("function user() { bar(); }" + "var error;" + "try{ user(); } catch (e) { error = e; }"); + CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value()); + CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value()); + CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value()); +} + + TEST(NullExtensions) { v8::HandleScope handle_scope(CcTest::isolate()); v8::RegisterExtension(new Extension("nulltest", NULL)); @@ -6764,7 +6837,7 @@ TEST(ExtensionWithSourceLength) { source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { v8::HandleScope handle_scope(CcTest::isolate()); i::ScopedVector<char> extension_name(32); - i::OS::SNPrintF(extension_name, "ext #%d", source_len); + i::SNPrintF(extension_name, "ext #%d", source_len); v8::RegisterExtension(new Extension(extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len)); @@ -7144,8 +7217,9 @@ TEST(ErrorReporting) { static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, v8::Handle<Value> data) { - CHECK(message->GetScriptResourceName()->IsUndefined()); - CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName()); + CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined()); + CHECK_EQ(v8::Undefined(CcTest::isolate()), + message->GetScriptOrigin().ResourceName()); message->GetLineNumber(); message->GetSourceLine(); } @@ -7924,7 +7998,7 @@ THREADED_TEST(StringWrite) { static void Utf16Helper( - LocalContext& context, + LocalContext& context, // NOLINT const char* name, const char* lengths_name, int len) { @@ -7951,7 +8025,7 @@ static uint16_t StringGet(Handle<String> str, int index) { static void WriteUtf8Helper( - LocalContext& context, + LocalContext& context, // NOLINT const char* name, const char* lengths_name, int len) { @@ -8330,9 +8404,9 @@ TEST(ApiUncaughtException) { static const char* script_resource_name = "ExceptionInNativeScript.js"; static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, v8::Handle<Value>) { - v8::Handle<v8::Value> name_val = message->GetScriptResourceName(); + v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName(); CHECK(!name_val.IsEmpty() && name_val->IsString()); - v8::String::Utf8Value name(message->GetScriptResourceName()); + v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); CHECK_EQ(script_resource_name, *name); CHECK_EQ(3, message->GetLineNumber()); v8::String::Utf8Value source_line(message->GetSourceLine()); @@ -8396,6 +8470,41 @@ TEST(TryCatchFinallyUsingTryCatchHandler) { } +void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::HandleScope scope(args.GetIsolate()); + CompileRun(args[0]->ToString()); +} + + +TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); + templ->Set(v8_str("CEvaluate"), + v8::FunctionTemplate::New(isolate, CEvaluate)); + LocalContext context(0, templ); + v8::TryCatch try_catch; + CompileRun("try {" + " CEvaluate('throw 1;');" + "} finally {" + "}"); + CHECK(try_catch.HasCaught()); + CHECK(!try_catch.Message().IsEmpty()); + String::Utf8Value exception_value(try_catch.Exception()); + CHECK_EQ(*exception_value, "1"); + try_catch.Reset(); + CompileRun("try {" + " CEvaluate('throw 1;');" + "} finally {" + " throw 2;" + "}"); + CHECK(try_catch.HasCaught()); + CHECK(!try_catch.Message().IsEmpty()); + String::Utf8Value finally_exception_value(try_catch.Exception()); + CHECK_EQ(*finally_exception_value, "2"); +} + + // For use within the TestSecurityHandler() test. static bool g_security_callback_result = false; static bool NamedSecurityTestCallback(Local<v8::Object> global, @@ -8552,10 +8661,8 @@ THREADED_TEST(SecurityChecksForPrototypeChain) { v8::Local<Script> access_other0 = v8_compile("other.Object"); v8::Local<Script> access_other1 = v8_compile("other[42]"); for (int i = 0; i < 5; i++) { - CHECK(!access_other0->Run()->Equals(other_object)); - CHECK(access_other0->Run()->IsUndefined()); - CHECK(!access_other1->Run()->Equals(v8_num(87))); - CHECK(access_other1->Run()->IsUndefined()); + CHECK(access_other0->Run().IsEmpty()); + CHECK(access_other1->Run().IsEmpty()); } // Create an object that has 'other' in its prototype chain and make @@ -8567,10 +8674,8 @@ THREADED_TEST(SecurityChecksForPrototypeChain) { v8::Local<Script> access_f0 = v8_compile("f.Object"); v8::Local<Script> access_f1 = v8_compile("f[42]"); for (int j = 0; j < 5; j++) { - CHECK(!access_f0->Run()->Equals(other_object)); - CHECK(access_f0->Run()->IsUndefined()); - CHECK(!access_f1->Run()->Equals(v8_num(87))); - CHECK(access_f1->Run()->IsUndefined()); + CHECK(access_f0->Run().IsEmpty()); + CHECK(access_f1->Run().IsEmpty()); } // Now it gets hairy: Set the prototype for the other global object @@ -8589,10 +8694,8 @@ THREADED_TEST(SecurityChecksForPrototypeChain) { Local<Script> access_f2 = v8_compile("f.foo"); Local<Script> access_f3 = v8_compile("f[99]"); for (int k = 0; k < 5; k++) { - CHECK(!access_f2->Run()->Equals(v8_num(100))); - CHECK(access_f2->Run()->IsUndefined()); - CHECK(!access_f3->Run()->Equals(v8_num(101))); - CHECK(access_f3->Run()->IsUndefined()); + CHECK(access_f2->Run().IsEmpty()); + CHECK(access_f3->Run().IsEmpty()); } } @@ -8673,7 +8776,7 @@ THREADED_TEST(CrossDomainDelete) { Context::Scope scope_env2(env2); Local<Value> result = CompileRun("delete env1.prop"); - CHECK(result->IsFalse()); + CHECK(result.IsEmpty()); } // Check that env1.prop still exists. @@ -8711,7 +8814,7 @@ THREADED_TEST(CrossDomainIsPropertyEnumerable) { { Context::Scope scope_env2(env2); Local<Value> result = CompileRun(test); - CHECK(result->IsFalse()); + CHECK(result.IsEmpty()); } } @@ -8738,11 +8841,18 @@ THREADED_TEST(CrossDomainForIn) { env2->SetSecurityToken(bar); { Context::Scope scope_env2(env2); - Local<Value> result = - CompileRun("(function(){var obj = {'__proto__':env1};" - "for (var p in obj)" - " if (p == 'prop') return false;" - "return true;})()"); + Local<Value> result = CompileRun( + "(function() {" + " var obj = { '__proto__': env1 };" + " try {" + " for (var p in obj) {" + " if (p == 'prop') return false;" + " }" + " return false;" + " } catch (e) {" + " return true;" + " }" + "})()"); CHECK(result->IsTrue()); } } @@ -8804,7 +8914,7 @@ TEST(ContextDetachGlobal) { // Check that env3 is not accessible from env1 { Local<Value> r = global3->Get(v8_str("prop2")); - CHECK(r->IsUndefined()); + CHECK(r.IsEmpty()); } } @@ -8843,7 +8953,7 @@ TEST(DetachGlobal) { // Check that the global has been detached. No other.p property can // be found. result = CompileRun("other.p"); - CHECK(result->IsUndefined()); + CHECK(result.IsEmpty()); // Reuse global2 for env3. v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), @@ -8873,7 +8983,7 @@ TEST(DetachGlobal) { // the global object for env3 which has a different security token, // so access should be blocked. result = CompileRun("other.p"); - CHECK(result->IsUndefined()); + CHECK(result.IsEmpty()); } @@ -8926,9 +9036,9 @@ TEST(DetachedAccesses) { result = CompileRun("bound_x()"); CHECK_EQ(v8_str("env2_x"), result); result = CompileRun("get_x()"); - CHECK(result->IsUndefined()); + CHECK(result.IsEmpty()); result = CompileRun("get_x_w()"); - CHECK(result->IsUndefined()); + CHECK(result.IsEmpty()); result = CompileRun("this_x()"); CHECK_EQ(v8_str("env2_x"), result); @@ -9018,19 +9128,13 @@ static bool IndexedAccessBlocker(Local<v8::Object> global, } -static int g_echo_value_1 = -1; -static int g_echo_value_2 = -1; +static int g_echo_value = -1; static void EchoGetter( Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { - info.GetReturnValue().Set(v8_num(g_echo_value_1)); -} - - -static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { - info.GetReturnValue().Set(v8_num(g_echo_value_2)); + info.GetReturnValue().Set(v8_num(g_echo_value)); } @@ -9038,14 +9142,7 @@ static void EchoSetter(Local<String> name, Local<Value> value, const v8::PropertyCallbackInfo<void>&) { if (value->IsNumber()) - g_echo_value_1 = value->Int32Value(); -} - - -static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) { - v8::Handle<v8::Value> value = info[0]; - if (value->IsNumber()) - g_echo_value_2 = value->Int32Value(); + g_echo_value = value->Int32Value(); } @@ -9086,13 +9183,6 @@ TEST(AccessControl) { v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); - global_template->SetAccessorProperty( - v8_str("accessible_js_prop"), - v8::FunctionTemplate::New(isolate, EchoGetter), - v8::FunctionTemplate::New(isolate, EchoSetter), - v8::None, - v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); - // Add an accessor that is not accessible by cross-domain JS code. global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter, UnreachableSetter, @@ -9144,54 +9234,35 @@ TEST(AccessControl) { // Access blocked property. CompileRun("other.blocked_prop = 1"); - ExpectUndefined("other.blocked_prop"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); - ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')"); - - // Enable ACCESS_HAS - allowed_access_type[v8::ACCESS_HAS] = true; - ExpectUndefined("other.blocked_prop"); - // ... and now we can get the descriptor... - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value"); - // ... and enumerate the property. - ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')"); - allowed_access_type[v8::ACCESS_HAS] = false; + CHECK(CompileRun("other.blocked_prop").IsEmpty()); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") + .IsEmpty()); + CHECK( + CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty()); // Access blocked element. - CompileRun("other[239] = 1"); + CHECK(CompileRun("other[239] = 1").IsEmpty()); - ExpectUndefined("other[239]"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')"); - ExpectFalse("propertyIsEnumerable.call(other, '239')"); + CHECK(CompileRun("other[239]").IsEmpty()); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty()); + CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty()); // Enable ACCESS_HAS allowed_access_type[v8::ACCESS_HAS] = true; - ExpectUndefined("other[239]"); + CHECK(CompileRun("other[239]").IsEmpty()); // ... and now we can get the descriptor... - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value"); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value") + .IsEmpty()); // ... and enumerate the property. ExpectTrue("propertyIsEnumerable.call(other, '239')"); allowed_access_type[v8::ACCESS_HAS] = false; // Access a property with JS accessor. - CompileRun("other.js_accessor_p = 2"); + CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty()); - ExpectUndefined("other.js_accessor_p"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')"); - - // Enable ACCESS_HAS. - allowed_access_type[v8::ACCESS_HAS] = true; - ExpectUndefined("other.js_accessor_p"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); - allowed_access_type[v8::ACCESS_HAS] = false; + CHECK(CompileRun("other.js_accessor_p").IsEmpty()); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')") + .IsEmpty()); // Enable both ACCESS_HAS and ACCESS_GET. allowed_access_type[v8::ACCESS_HAS] = true; @@ -9200,59 +9271,19 @@ TEST(AccessControl) { ExpectString("other.js_accessor_p", "getter"); ExpectObject( "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); - - allowed_access_type[v8::ACCESS_GET] = false; - allowed_access_type[v8::ACCESS_HAS] = false; - - // Enable both ACCESS_HAS and ACCESS_SET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_SET] = true; - - ExpectUndefined("other.js_accessor_p"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); ExpectObject( "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); ExpectUndefined( "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); - allowed_access_type[v8::ACCESS_SET] = false; allowed_access_type[v8::ACCESS_HAS] = false; - - // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_GET] = true; - allowed_access_type[v8::ACCESS_SET] = true; - - ExpectString("other.js_accessor_p", "getter"); - ExpectObject( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); - ExpectObject( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); - - allowed_access_type[v8::ACCESS_SET] = false; allowed_access_type[v8::ACCESS_GET] = false; - allowed_access_type[v8::ACCESS_HAS] = false; // Access an element with JS accessor. - CompileRun("other[42] = 2"); + CHECK(CompileRun("other[42] = 2").IsEmpty()); - ExpectUndefined("other[42]"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')"); - - // Enable ACCESS_HAS. - allowed_access_type[v8::ACCESS_HAS] = true; - ExpectUndefined("other[42]"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); - allowed_access_type[v8::ACCESS_HAS] = false; + CHECK(CompileRun("other[42]").IsEmpty()); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty()); // Enable both ACCESS_HAS and ACCESS_GET. allowed_access_type[v8::ACCESS_HAS] = true; @@ -9260,37 +9291,11 @@ TEST(AccessControl) { ExpectString("other[42]", "el_getter"); ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); - - allowed_access_type[v8::ACCESS_GET] = false; - allowed_access_type[v8::ACCESS_HAS] = false; - - // Enable both ACCESS_HAS and ACCESS_SET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_SET] = true; - - ExpectUndefined("other[42]"); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); - allowed_access_type[v8::ACCESS_SET] = false; allowed_access_type[v8::ACCESS_HAS] = false; - - // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_GET] = true; - allowed_access_type[v8::ACCESS_SET] = true; - - ExpectString("other[42]", "el_getter"); - ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); - ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); - ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); - - allowed_access_type[v8::ACCESS_SET] = false; allowed_access_type[v8::ACCESS_GET] = false; - allowed_access_type[v8::ACCESS_HAS] = false; v8::Handle<Value> value; @@ -9298,50 +9303,38 @@ TEST(AccessControl) { value = CompileRun("other.accessible_prop = 3"); CHECK(value->IsNumber()); CHECK_EQ(3, value->Int32Value()); - CHECK_EQ(3, g_echo_value_1); - - // Access accessible js property - value = CompileRun("other.accessible_js_prop = 3"); - CHECK(value->IsNumber()); - CHECK_EQ(3, value->Int32Value()); - CHECK_EQ(3, g_echo_value_2); + CHECK_EQ(3, g_echo_value); value = CompileRun("other.accessible_prop"); CHECK(value->IsNumber()); CHECK_EQ(3, value->Int32Value()); - value = CompileRun("other.accessible_js_prop"); - CHECK(value->IsNumber()); - CHECK_EQ(3, value->Int32Value()); - value = CompileRun( "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); CHECK(value->IsNumber()); CHECK_EQ(3, value->Int32Value()); - value = CompileRun( - "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()"); - CHECK(value->IsNumber()); - CHECK_EQ(3, value->Int32Value()); - value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); CHECK(value->IsTrue()); - value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')"); - CHECK(value->IsTrue()); - // Enumeration doesn't enumerate accessors from inaccessible objects in // the prototype chain even if the accessors are in themselves accessible. - value = - CompileRun("(function(){var obj = {'__proto__':other};" - "for (var p in obj)" - " if (p == 'accessible_prop' ||" - " p == 'accessible_js_prop' ||" - " p == 'blocked_js_prop' ||" - " p == 'blocked_js_prop') {" - " return false;" - " }" - "return true;})()"); + value = CompileRun( + "(function() {" + " var obj = { '__proto__': other };" + " try {" + " for (var p in obj) {" + " if (p == 'accessible_prop' ||" + " p == 'blocked_js_prop' ||" + " p == 'blocked_js_prop') {" + " return false;" + " }" + " }" + " return false;" + " } catch (e) {" + " return true;" + " }" + "})()"); CHECK(value->IsTrue()); context1->Exit(); @@ -9384,16 +9377,15 @@ TEST(AccessControlES5) { global1->Set(v8_str("other"), global0); // Regression test for issue 1154. - ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1"); - - ExpectUndefined("other.blocked_prop"); + CHECK(CompileRun("Object.keys(other)").IsEmpty()); + CHECK(CompileRun("other.blocked_prop").IsEmpty()); // Regression test for issue 1027. CompileRun("Object.defineProperty(\n" " other, 'blocked_prop', {configurable: false})"); - ExpectUndefined("other.blocked_prop"); - ExpectUndefined( - "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); + CHECK(CompileRun("other.blocked_prop").IsEmpty()); + CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") + .IsEmpty()); // Regression test for issue 1171. ExpectTrue("Object.isExtensible(other)"); @@ -9411,7 +9403,7 @@ TEST(AccessControlES5) { // Make sure that we can set the accessible accessors value using normal // assignment. CompileRun("other.accessible_prop = 42"); - CHECK_EQ(42, g_echo_value_1); + CHECK_EQ(42, g_echo_value); v8::Handle<Value> value; CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); @@ -9469,10 +9461,10 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) { // proxy object. Accessing the object that requires access checks // is blocked by the access checks on the object itself. value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); - CHECK(value->IsTrue()); + CHECK(value.IsEmpty()); value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); - CHECK(value->IsTrue()); + CHECK(value.IsEmpty()); context1->Exit(); context0->Exit(); @@ -9580,7 +9572,7 @@ THREADED_TEST(CrossDomainAccessors) { CHECK_EQ(10, value->Int32Value()); value = v8_compile("other.unreachable")->Run(); - CHECK(value->IsUndefined()); + CHECK(value.IsEmpty()); context1->Exit(); context0->Exit(); @@ -10219,7 +10211,7 @@ THREADED_TEST(HiddenPrototypeIdentityHash) { int hash = o->GetIdentityHash(); USE(hash); o->Set(v8_str("foo"), v8_num(42)); - ASSERT_EQ(hash, o->GetIdentityHash()); + DCHECK_EQ(hash, o->GetIdentityHash()); } @@ -10282,7 +10274,7 @@ THREADED_TEST(SetPrototype) { // Getting property names of an object with a prototype chain that -// triggers dictionary elements in GetLocalPropertyNames() shouldn't +// triggers dictionary elements in GetOwnPropertyNames() shouldn't // crash the runtime. THREADED_TEST(Regress91517) { i::FLAG_allow_natives_syntax = true; @@ -10307,7 +10299,7 @@ THREADED_TEST(Regress91517) { // Force dictionary-based properties. i::ScopedVector<char> name_buf(1024); for (int i = 1; i <= 1000; i++) { - i::OS::SNPrintF(name_buf, "sdf%d", i); + i::SNPrintF(name_buf, "sdf%d", i); t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); } @@ -10321,11 +10313,11 @@ THREADED_TEST(Regress91517) { CHECK(o3->SetPrototype(o2)); CHECK(o2->SetPrototype(o1)); - // Call the runtime version of GetLocalPropertyNames() on the natively + // Call the runtime version of GetOwnPropertyNames() on the natively // created object through JavaScript. context->Global()->Set(v8_str("obj"), o4); // PROPERTY_ATTRIBUTES_NONE = 0 - CompileRun("var names = %GetLocalPropertyNames(obj, 0);"); + CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); ExpectInt32("names.length", 1006); ExpectTrue("names.indexOf(\"baz\") >= 0"); @@ -10376,12 +10368,12 @@ THREADED_TEST(Regress269562) { o1->SetHiddenValue( v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013)); - // Call the runtime version of GetLocalPropertyNames() on + // Call the runtime version of GetOwnPropertyNames() on // the natively created object through JavaScript. context->Global()->Set(v8_str("obj"), o2); context->Global()->Set(v8_str("sym"), sym); // PROPERTY_ATTRIBUTES_NONE = 0 - CompileRun("var names = %GetLocalPropertyNames(obj, 0);"); + CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); ExpectInt32("names.length", 7); ExpectTrue("names.indexOf(\"foo\") >= 0"); @@ -10442,7 +10434,7 @@ THREADED_TEST(SetPrototypeThrows) { v8::TryCatch try_catch; CHECK(!o1->SetPrototype(o0)); CHECK(!try_catch.HasCaught()); - ASSERT(!CcTest::i_isolate()->has_pending_exception()); + DCHECK(!CcTest::i_isolate()->has_pending_exception()); CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); } @@ -13027,7 +13019,7 @@ static void WebKitLike(Handle<Message> message, Handle<Value> data) { Handle<String> errorMessageString = message->Get(); CHECK(!errorMessageString.IsEmpty()); message->GetStackTrace(); - message->GetScriptResourceName(); + message->GetScriptOrigin().ResourceName(); } @@ -13220,7 +13212,7 @@ THREADED_TEST(ObjectGetConstructorName) { bool ApiTestFuzzer::fuzzing_ = false; -i::Semaphore ApiTestFuzzer::all_tests_done_(0); +v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0); int ApiTestFuzzer::active_tests_; int ApiTestFuzzer::tests_being_run_; int ApiTestFuzzer::current_; @@ -13514,7 +13506,6 @@ THREADED_TEST(LockUnlockLock) { static int GetGlobalObjectsCount() { - CcTest::heap()->EnsureHeapIsIterable(); int count = 0; i::HeapIterator it(CcTest::heap()); for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) @@ -13549,21 +13540,21 @@ TEST(DontLeakGlobalObjects) { { v8::HandleScope scope(CcTest::isolate()); LocalContext context; } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope(CcTest::isolate()); LocalContext context; v8_compile("Date")->Run(); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope(CcTest::isolate()); LocalContext context; v8_compile("/aaa/")->Run(); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); { v8::HandleScope scope(CcTest::isolate()); @@ -13572,7 +13563,7 @@ TEST(DontLeakGlobalObjects) { LocalContext context(&extensions); v8_compile("gc();")->Run(); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(0); } } @@ -14026,12 +14017,12 @@ void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { CompileRun(script); bar_func_ = i::Handle<i::JSFunction>::cast( v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar")))); - ASSERT(!bar_func_.is_null()); + DCHECK(!bar_func_.is_null()); foo_func_ = i::Handle<i::JSFunction>::cast( v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo")))); - ASSERT(!foo_func_.is_null()); + DCHECK(!foo_func_.is_null()); v8::Handle<v8::Value> value = CompileRun("bar();"); CHECK(value->IsNumber()); @@ -14424,7 +14415,7 @@ static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, CHECK_EQ(3, message->GetEndColumn()); v8::String::Utf8Value line(message->GetSourceLine()); CHECK_EQ(" throw 'nirk';", *line); - v8::String::Utf8Value name(message->GetScriptResourceName()); + v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); CHECK_EQ(resource_name, *name); } @@ -14693,13 +14684,13 @@ THREADED_TEST(AccessChecksReenabledCorrectly) { context->Global()->Set(v8_str("obj_1"), instance_1); Local<Value> value_1 = CompileRun("obj_1.a"); - CHECK(value_1->IsUndefined()); + CHECK(value_1.IsEmpty()); Local<v8::Object> instance_2 = templ->NewInstance(); context->Global()->Set(v8_str("obj_2"), instance_2); Local<Value> value_2 = CompileRun("obj_2.a"); - CHECK(value_2->IsUndefined()); + CHECK(value_2.IsEmpty()); } @@ -14780,11 +14771,9 @@ THREADED_TEST(TurnOnAccessCheck) { context->DetachGlobal(); hidden_global->TurnOnAccessCheck(); - // Failing access check to property get results in undefined. - CHECK(f1->Call(global, 0, NULL)->IsUndefined()); - CHECK(f2->Call(global, 0, NULL)->IsUndefined()); - - // Failing access check to function call results in exception. + // 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()); @@ -14868,11 +14857,9 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) { context->DetachGlobal(); hidden_global->TurnOnAccessCheck(); - // Failing access check to property get results in undefined. - CHECK(f1->Call(global, 0, NULL)->IsUndefined()); - CHECK(f2->Call(global, 0, NULL)->IsUndefined()); - - // Failing access check to function call results in exception. + // 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()); @@ -14886,13 +14873,13 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) { f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2"))); g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1"))); g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2"))); - CHECK(hidden_global->Get(v8_str("h"))->IsUndefined()); + CHECK(hidden_global->Get(v8_str("h")).IsEmpty()); - // Failing access check to property get results in undefined. - CHECK(f1->Call(global, 0, NULL)->IsUndefined()); - CHECK(f2->Call(global, 0, NULL)->IsUndefined()); - - // Failing access check to function call results in exception. + // Failing access check results in exception. + v8::Local<v8::Value> result = f1->Call(global, 0, NULL); + CHECK(result.IsEmpty()); + 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()); } @@ -14909,137 +14896,24 @@ TEST(PreCompileSerialization) { const char* script = "function foo(a) { return a+1; }"; v8::ScriptCompiler::Source source(v8_str(script)); v8::ScriptCompiler::Compile(isolate, &source, - v8::ScriptCompiler::kProduceDataToCache); + v8::ScriptCompiler::kProduceParserCache); // Serialize. const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); - char* serialized_data = i::NewArray<char>(cd->length); - i::OS::MemCopy(serialized_data, cd->data, cd->length); + i::byte* serialized_data = i::NewArray<i::byte>(cd->length); + i::MemCopy(serialized_data, cd->data, cd->length); // Deserialize. - i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length); + i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length); // Verify that the original is the same as the deserialized. - CHECK_EQ(cd->length, deserialized->Length()); - CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length)); + CHECK_EQ(cd->length, deserialized->length()); + CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length)); delete deserialized; i::DeleteArray(serialized_data); } -// Attempts to deserialize bad data. -TEST(PreCompileDeserializationError) { - v8::V8::Initialize(); - const char* data = "DONT CARE"; - int invalid_size = 3; - i::ScriptData* sd = i::ScriptData::New(data, invalid_size); - CHECK_EQ(NULL, sd); -} - - -TEST(CompileWithInvalidCachedData) { - v8::V8::Initialize(); - v8::Isolate* isolate = CcTest::isolate(); - LocalContext context; - v8::HandleScope scope(context->GetIsolate()); - i::FLAG_min_preparse_length = 0; - - const char* script = "function foo(){ return 5;}\n" - "function bar(){ return 6 + 7;} foo();"; - v8::ScriptCompiler::Source source(v8_str(script)); - v8::ScriptCompiler::Compile(isolate, &source, - v8::ScriptCompiler::kProduceDataToCache); - // source owns its cached data. Create a ScriptData based on it. The user - // never needs to create ScriptDatas any more; we only need it here because we - // want to modify the data before passing it back. - const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); - // ScriptData does not take ownership of the buffers passed to it. - i::ScriptData* sd = - i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); - CHECK(!sd->HasError()); - // ScriptData private implementation details - const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; - const int kFunctionEntrySize = i::FunctionEntry::kSize; - const int kFunctionEntryStartOffset = 0; - const int kFunctionEntryEndOffset = 1; - unsigned* sd_data = - reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); - - // Overwrite function bar's end position with 0. - sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; - v8::TryCatch try_catch; - - // Make the script slightly different so that we don't hit the compilation - // cache. Don't change the lenghts of tokens. - const char* script2 = "function foo(){ return 6;}\n" - "function bar(){ return 6 + 7;} foo();"; - v8::ScriptCompiler::Source source2( - v8_str(script2), - // CachedData doesn't take ownership of the buffers, Source takes - // ownership of CachedData. - new v8::ScriptCompiler::CachedData( - reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); - Local<v8::UnboundScript> compiled_script = - v8::ScriptCompiler::CompileUnbound(isolate, &source2); - - CHECK(try_catch.HasCaught()); - { - String::Utf8Value exception_value(try_catch.Message()->Get()); - CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar", - *exception_value); - } - - try_catch.Reset(); - delete sd; - - // Overwrite function bar's start position with 200. The function entry will - // not be found when searching for it by position, and the compilation fails. - - // ScriptData does not take ownership of the buffers passed to it. - sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); - sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); - sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = - 200; - const char* script3 = "function foo(){ return 7;}\n" - "function bar(){ return 6 + 7;} foo();"; - v8::ScriptCompiler::Source source3( - v8_str(script3), - new v8::ScriptCompiler::CachedData( - reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); - compiled_script = - v8::ScriptCompiler::CompileUnbound(isolate, &source3); - CHECK(try_catch.HasCaught()); - { - String::Utf8Value exception_value(try_catch.Message()->Get()); - CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar", - *exception_value); - } - CHECK(compiled_script.IsEmpty()); - try_catch.Reset(); - delete sd; - - // Try passing in cached data which is obviously invalid (wrong length). - sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); - const char* script4 = - "function foo(){ return 8;}\n" - "function bar(){ return 6 + 7;} foo();"; - v8::ScriptCompiler::Source source4( - v8_str(script4), - new v8::ScriptCompiler::CachedData( - reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1)); - compiled_script = - v8::ScriptCompiler::CompileUnbound(isolate, &source4); - CHECK(try_catch.HasCaught()); - { - String::Utf8Value exception_value(try_catch.Message()->Get()); - CHECK_EQ("Uncaught SyntaxError: Invalid cached data", - *exception_value); - } - CHECK(compiled_script.IsEmpty()); - delete sd; -} - - // This tests that we do not allow dictionary load/call inline caches // to use functions that have not yet been compiled. The potential // problem of loading a function that has not yet been compiled can @@ -15283,19 +15157,19 @@ struct RegExpInterruptionData { } regexp_interruption_data; -class RegExpInterruptionThread : public i::Thread { +class RegExpInterruptionThread : public v8::base::Thread { public: explicit RegExpInterruptionThread(v8::Isolate* isolate) - : Thread("TimeoutThread"), isolate_(isolate) {} + : Thread(Options("TimeoutThread")), isolate_(isolate) {} virtual void Run() { for (regexp_interruption_data.loop_count = 0; regexp_interruption_data.loop_count < 7; regexp_interruption_data.loop_count++) { - i::OS::Sleep(50); // Wait a bit before requesting GC. + v8::base::OS::Sleep(50); // Wait a bit before requesting GC. reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); } - i::OS::Sleep(50); // Wait a bit before terminating. + v8::base::OS::Sleep(50); // Wait a bit before terminating. v8::V8::TerminateExecution(isolate_); } @@ -15358,8 +15232,10 @@ TEST(ReadOnlyPropertyInGlobalProto) { v8::Handle<v8::Object> global = context->Global(); v8::Handle<v8::Object> global_proto = v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); - global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly); - global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly); + global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0), + v8::ReadOnly); + global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0), + v8::ReadOnly); // Check without 'eval' or 'with'. v8::Handle<v8::Value> res = CompileRun("function f() { x = 42; return x; }; f()"); @@ -15417,7 +15293,7 @@ TEST(ForceSet) { // Ordinary properties v8::Handle<v8::String> simple_property = v8::String::NewFromUtf8(isolate, "p"); - global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly); + global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly); CHECK_EQ(4, global->Get(simple_property)->Int32Value()); // This should fail because the property is read-only global->Set(simple_property, v8::Int32::New(isolate, 5)); @@ -15505,7 +15381,7 @@ THREADED_TEST(ForceDelete) { // Ordinary properties v8::Handle<v8::String> simple_property = v8::String::NewFromUtf8(isolate, "p"); - global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete); + global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete); CHECK_EQ(4, global->Get(simple_property)->Int32Value()); // This should fail because the property is dont-delete. CHECK(!global->Delete(simple_property)); @@ -15542,7 +15418,8 @@ THREADED_TEST(ForceDeleteWithInterceptor) { v8::Handle<v8::String> some_property = v8::String::NewFromUtf8(isolate, "a"); - global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete); + global->ForceSet(some_property, v8::Integer::New(isolate, 42), + v8::DontDelete); // Deleting a property should get intercepted and nothing should // happen. @@ -15831,20 +15708,20 @@ THREADED_TEST(PixelArray) { i::Handle<i::Object> no_failure; no_failure = i::JSObject::SetElement( jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); - ASSERT(!no_failure.is_null()); - i::USE(no_failure); + DCHECK(!no_failure.is_null()); + USE(no_failure); CheckElementValue(isolate, 2, jsobj, 1); *value.location() = i::Smi::FromInt(256); no_failure = i::JSObject::SetElement( jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); - ASSERT(!no_failure.is_null()); - i::USE(no_failure); + DCHECK(!no_failure.is_null()); + USE(no_failure); CheckElementValue(isolate, 255, jsobj, 1); *value.location() = i::Smi::FromInt(-1); no_failure = i::JSObject::SetElement( jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); - ASSERT(!no_failure.is_null()); - i::USE(no_failure); + DCHECK(!no_failure.is_null()); + USE(no_failure); CheckElementValue(isolate, 0, jsobj, 1); result = CompileRun("for (var i = 0; i < 8; i++) {" @@ -16316,15 +16193,15 @@ static void ObjectWithExternalArrayTestHelper( " }" "}" "res;"; - i::OS::SNPrintF(test_buf, - boundary_program, - low); + i::SNPrintF(test_buf, + boundary_program, + low); result = CompileRun(test_buf.start()); CHECK_EQ(low, result->IntegerValue()); - i::OS::SNPrintF(test_buf, - boundary_program, - high); + i::SNPrintF(test_buf, + boundary_program, + high); result = CompileRun(test_buf.start()); CHECK_EQ(high, result->IntegerValue()); @@ -16344,28 +16221,28 @@ static void ObjectWithExternalArrayTestHelper( CHECK_EQ(28, result->Int32Value()); // Make sure out-of-range loads do not throw. - i::OS::SNPrintF(test_buf, - "var caught_exception = false;" - "try {" - " ext_array[%d];" - "} catch (e) {" - " caught_exception = true;" - "}" - "caught_exception;", - element_count); + i::SNPrintF(test_buf, + "var caught_exception = false;" + "try {" + " ext_array[%d];" + "} catch (e) {" + " caught_exception = true;" + "}" + "caught_exception;", + element_count); result = CompileRun(test_buf.start()); CHECK_EQ(false, result->BooleanValue()); // Make sure out-of-range stores do not throw. - i::OS::SNPrintF(test_buf, - "var caught_exception = false;" - "try {" - " ext_array[%d] = 1;" - "} catch (e) {" - " caught_exception = true;" - "}" - "caught_exception;", - element_count); + i::SNPrintF(test_buf, + "var caught_exception = false;" + "try {" + " ext_array[%d] = 1;" + "} catch (e) {" + " caught_exception = true;" + "}" + "caught_exception;", + element_count); result = CompileRun(test_buf.start()); CHECK_EQ(false, result->BooleanValue()); @@ -16377,7 +16254,7 @@ static void ObjectWithExternalArrayTestHelper( CHECK_EQ(0, result->Int32Value()); if (array_type == v8::kExternalFloat64Array || array_type == v8::kExternalFloat32Array) { - CHECK_EQ(static_cast<int>(i::OS::nan_value()), + CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()), static_cast<int>( i::Object::GetElement( isolate, jsobj, 7).ToHandleChecked()->Number())); @@ -16447,20 +16324,20 @@ static void ObjectWithExternalArrayTestHelper( array_type == v8::kExternalUint32Array); bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray; - i::OS::SNPrintF(test_buf, - "%s" - "var all_passed = true;" - "for (var i = 0; i < source_data.length; i++) {" - " for (var j = 0; j < 8; j++) {" - " ext_array[j] = source_data[i];" - " }" - " all_passed = all_passed &&" - " (ext_array[5] == expected_results[i]);" - "}" - "all_passed;", - (is_unsigned ? - unsigned_data : - (is_pixel_data ? pixel_data : signed_data))); + i::SNPrintF(test_buf, + "%s" + "var all_passed = true;" + "for (var i = 0; i < source_data.length; i++) {" + " for (var j = 0; j < 8; j++) {" + " ext_array[j] = source_data[i];" + " }" + " all_passed = all_passed &&" + " (ext_array[5] == expected_results[i]);" + "}" + "all_passed;", + (is_unsigned ? + unsigned_data : + (is_pixel_data ? pixel_data : signed_data))); result = CompileRun(test_buf.start()); CHECK_EQ(true, result->BooleanValue()); } @@ -17215,7 +17092,7 @@ void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { const int kOverviewTest = 1; const int kDetailedTest = 2; - ASSERT(args.Length() == 1); + DCHECK(args.Length() == 1); int testGroup = args[0]->Int32Value(); if (testGroup == kOverviewTest) { @@ -17541,9 +17418,9 @@ TEST(SourceURLInStackTrace) { "eval('(' + outer +')()%s');"; i::ScopedVector<char> code(1024); - i::OS::SNPrintF(code, source, "//# sourceURL=eval_url"); + i::SNPrintF(code, source, "//# sourceURL=eval_url"); CHECK(CompileRun(code.start())->IsUndefined()); - i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url"); + i::SNPrintF(code, source, "//@ sourceURL=eval_url"); CHECK(CompileRun(code.start())->IsUndefined()); } @@ -17580,7 +17457,7 @@ TEST(ScriptIdInStackTrace) { script->Run(); for (int i = 0; i < 2; i++) { CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); - CHECK_EQ(scriptIdInStack[i], script->GetId()); + CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId()); } } @@ -17624,9 +17501,9 @@ TEST(InlineScriptWithSourceURLInStackTrace) { "outer()\n%s"; i::ScopedVector<char> code(1024); - i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); + i::SNPrintF(code, source, "//# sourceURL=source_url"); CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); - i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); + i::SNPrintF(code, source, "//@ sourceURL=source_url"); CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); } @@ -17670,9 +17547,9 @@ TEST(DynamicWithSourceURLInStackTrace) { "outer()\n%s"; i::ScopedVector<char> code(1024); - i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); + i::SNPrintF(code, source, "//# sourceURL=source_url"); CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); - i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); + i::SNPrintF(code, source, "//@ sourceURL=source_url"); CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); } @@ -17691,7 +17568,7 @@ TEST(DynamicWithSourceURLInStackTraceString) { "outer()\n%s"; i::ScopedVector<char> code(1024); - i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); + i::SNPrintF(code, source, "//# sourceURL=source_url"); v8::TryCatch try_catch; CompileRunWithOrigin(code.start(), "", 0, 0); CHECK(try_catch.HasCaught()); @@ -17700,6 +17577,54 @@ TEST(DynamicWithSourceURLInStackTraceString) { } +TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + + const char *source = + "function outer() {\n" + " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n" + " //# sourceURL=source_url\";\n" + " eval(scriptContents);\n" + " foo(); }\n" + "outer();\n" + "//# sourceURL=outer_url"; + + v8::TryCatch try_catch; + CompileRun(source); + CHECK(try_catch.HasCaught()); + + Local<v8::Message> message = try_catch.Message(); + Handle<Value> sourceURL = + message->GetScriptOrigin().ResourceName(); + CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url"); +} + + +TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) { + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + + const char *source = + "function outer() {\n" + " var scriptContents = \"function boo(){ boo(); }\\\n" + " //# sourceURL=source_url\";\n" + " eval(scriptContents);\n" + " boo(); }\n" + "outer();\n" + "//# sourceURL=outer_url"; + + v8::TryCatch try_catch; + CompileRun(source); + CHECK(try_catch.HasCaught()); + + Local<v8::Message> message = try_catch.Message(); + Handle<Value> sourceURL = + message->GetScriptOrigin().ResourceName(); + CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url"); +} + + static void CreateGarbageInOldSpace() { i::Factory* factory = CcTest::i_isolate()->factory(); v8::HandleScope scope(CcTest::isolate()); @@ -17713,6 +17638,7 @@ static void CreateGarbageInOldSpace() { // Test that idle notification can be handled and eventually returns true. TEST(IdleNotification) { const intptr_t MB = 1024 * 1024; + const int IdlePauseInMs = 1000; LocalContext env; v8::HandleScope scope(env->GetIsolate()); intptr_t initial_size = CcTest::heap()->SizeOfObjects(); @@ -17721,7 +17647,7 @@ TEST(IdleNotification) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { - finished = v8::V8::IdleNotification(); + finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); } intptr_t final_size = CcTest::heap()->SizeOfObjects(); CHECK(finished); @@ -17741,7 +17667,7 @@ TEST(IdleNotificationWithSmallHint) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { - finished = v8::V8::IdleNotification(IdlePauseInMs); + finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); } intptr_t final_size = CcTest::heap()->SizeOfObjects(); CHECK(finished); @@ -17761,7 +17687,7 @@ TEST(IdleNotificationWithLargeHint) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { - finished = v8::V8::IdleNotification(IdlePauseInMs); + finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); } intptr_t final_size = CcTest::heap()->SizeOfObjects(); CHECK(finished); @@ -17778,7 +17704,7 @@ TEST(Regress2107) { v8::HandleScope scope(env->GetIsolate()); intptr_t initial_size = CcTest::heap()->SizeOfObjects(); // Send idle notification to start a round of incremental GCs. - v8::V8::IdleNotification(kShortIdlePauseInMs); + env->GetIsolate()->IdleNotification(kShortIdlePauseInMs); // Emulate 7 page reloads. for (int i = 0; i < 7; i++) { { @@ -17788,8 +17714,8 @@ TEST(Regress2107) { CreateGarbageInOldSpace(); ctx->Exit(); } - v8::V8::ContextDisposedNotification(); - v8::V8::IdleNotification(kLongIdlePauseInMs); + env->GetIsolate()->ContextDisposedNotification(); + env->GetIsolate()->IdleNotification(kLongIdlePauseInMs); } // Create garbage and check that idle notification still collects it. CreateGarbageInOldSpace(); @@ -17797,7 +17723,7 @@ TEST(Regress2107) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { - finished = v8::V8::IdleNotification(kShortIdlePauseInMs); + finished = env->GetIsolate()->IdleNotification(kShortIdlePauseInMs); } intptr_t final_size = CcTest::heap()->SizeOfObjects(); CHECK_LT(final_size, initial_size + 1); @@ -18093,14 +18019,14 @@ TEST(ExternalInternalizedStringCollectedAtGC) { static double DoubleFromBits(uint64_t value) { double target; - i::OS::MemCopy(&target, &value, sizeof(target)); + i::MemCopy(&target, &value, sizeof(target)); return target; } static uint64_t DoubleToBits(double value) { uint64_t target; - i::OS::MemCopy(&target, &value, sizeof(target)); + i::MemCopy(&target, &value, sizeof(target)); return target; } @@ -18108,7 +18034,7 @@ static uint64_t DoubleToBits(double value) { static double DoubleToDateTime(double input) { double date_limit = 864e13; if (std::isnan(input) || input < -date_limit || input > date_limit) { - return i::OS::nan_value(); + return v8::base::OS::nan_value(); } return (input < 0) ? -(std::floor(-input)) : std::floor(input); } @@ -18175,7 +18101,8 @@ THREADED_TEST(QuietSignalingNaNs) { } else { uint64_t stored_bits = DoubleToBits(stored_number); // Check if quiet nan (bits 51..62 all set). -#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) +#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ + !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR) // Most significant fraction bit for quiet nan is set to 0 // on MIPS architecture. Allowed by IEEE-754. CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); @@ -18195,7 +18122,8 @@ THREADED_TEST(QuietSignalingNaNs) { } else { uint64_t stored_bits = DoubleToBits(stored_date); // Check if quiet nan (bits 51..62 all set). -#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) +#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ + !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR) // Most significant fraction bit for quiet nan is set to 0 // on MIPS architecture. Allowed by IEEE-754. CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); @@ -18271,7 +18199,7 @@ TEST(Regress528) { CompileRun(source_simple); context->Exit(); } - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); for (gc_count = 1; gc_count < 10; gc_count++) { other_context->Enter(); CompileRun(source_simple); @@ -18293,7 +18221,7 @@ TEST(Regress528) { CompileRun(source_eval); context->Exit(); } - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); for (gc_count = 1; gc_count < 10; gc_count++) { other_context->Enter(); CompileRun(source_eval); @@ -18320,7 +18248,7 @@ TEST(Regress528) { CHECK_EQ(1, message->GetLineNumber()); context->Exit(); } - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); for (gc_count = 1; gc_count < 10; gc_count++) { other_context->Enter(); CompileRun(source_exception); @@ -18331,7 +18259,7 @@ TEST(Regress528) { CHECK_GE(2, gc_count); CHECK_EQ(1, GetGlobalObjectsCount()); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } @@ -18511,8 +18439,8 @@ THREADED_TEST(FunctionGetScriptId) { env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"))); v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar"))); - CHECK_EQ(script->GetId(), foo->ScriptId()); - CHECK_EQ(script->GetId(), bar->ScriptId()); + CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId()); + CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId()); } @@ -18586,8 +18514,7 @@ TEST(SetterOnConstructorPrototype) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetAccessor(v8_str("x"), - GetterWhichReturns42, + templ->SetAccessor(v8_str("x"), GetterWhichReturns42, SetterWhichSetsYOnThisTo23); LocalContext context; context->Global()->Set(v8_str("P"), templ->NewInstance()); @@ -18700,8 +18627,7 @@ TEST(Regress618) { // Use an API object with accessors as prototype. Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetAccessor(v8_str("x"), - GetterWhichReturns42, + templ->SetAccessor(v8_str("x"), GetterWhichReturns42, SetterWhichSetsYOnThisTo23); context->Global()->Set(v8_str("P"), templ->NewInstance()); @@ -19252,7 +19178,7 @@ TEST(GCInFailedAccessCheckCallback) { ExpectUndefined("Object.prototype.__lookupGetter__.call(" " other, \'x\')"); - // HasLocalElement. + // HasOwnElement. ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); CHECK_EQ(false, global0->HasRealIndexedProperty(0)); @@ -19269,7 +19195,6 @@ TEST(IsolateNewDispose) { v8::Isolate* current_isolate = CcTest::isolate(); v8::Isolate* isolate = v8::Isolate::New(); CHECK(isolate != NULL); - CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); CHECK(current_isolate != isolate); CHECK(current_isolate == CcTest::isolate()); @@ -19430,23 +19355,23 @@ static int CalcFibonacci(v8::Isolate* isolate, int limit) { v8::HandleScope scope(isolate); LocalContext context(isolate); i::ScopedVector<char> code(1024); - i::OS::SNPrintF(code, "function fib(n) {" - " if (n <= 2) return 1;" - " return fib(n-1) + fib(n-2);" - "}" - "fib(%d)", limit); + i::SNPrintF(code, "function fib(n) {" + " if (n <= 2) return 1;" + " return fib(n-1) + fib(n-2);" + "}" + "fib(%d)", limit); Local<Value> value = CompileRun(code.start()); CHECK(value->IsNumber()); return static_cast<int>(value->NumberValue()); } -class IsolateThread : public v8::internal::Thread { +class IsolateThread : public v8::base::Thread { public: IsolateThread(v8::Isolate* isolate, int fib_limit) - : Thread("IsolateThread"), + : Thread(Options("IsolateThread")), isolate_(isolate), fib_limit_(fib_limit), - result_(0) { } + result_(0) {} void Run() { result_ = CalcFibonacci(isolate_, fib_limit_); @@ -19514,7 +19439,7 @@ TEST(IsolateDifferentContexts) { isolate->Dispose(); } -class InitDefaultIsolateThread : public v8::internal::Thread { +class InitDefaultIsolateThread : public v8::base::Thread { public: enum TestCase { SetResourceConstraints, @@ -19525,19 +19450,18 @@ class InitDefaultIsolateThread : public v8::internal::Thread { }; explicit InitDefaultIsolateThread(TestCase testCase) - : Thread("InitDefaultIsolateThread"), + : Thread(Options("InitDefaultIsolateThread")), testCase_(testCase), - result_(false) { } + result_(false) {} void Run() { v8::Isolate* isolate = v8::Isolate::New(); isolate->Enter(); switch (testCase_) { case SetResourceConstraints: { - static const int K = 1024; v8::ResourceConstraints constraints; - constraints.set_max_new_space_size(2 * K * K); - constraints.set_max_old_space_size(4 * K * K); + constraints.set_max_semi_space_size(1); + constraints.set_max_old_space_size(4); v8::SetResourceConstraints(CcTest::isolate(), &constraints); break; } @@ -19547,15 +19471,15 @@ class InitDefaultIsolateThread : public v8::internal::Thread { break; case SetCounterFunction: - v8::V8::SetCounterFunction(NULL); + CcTest::isolate()->SetCounterFunction(NULL); break; case SetCreateHistogramFunction: - v8::V8::SetCreateHistogramFunction(NULL); + CcTest::isolate()->SetCreateHistogramFunction(NULL); break; case SetAddHistogramSampleFunction: - v8::V8::SetAddHistogramSampleFunction(NULL); + CcTest::isolate()->SetAddHistogramSampleFunction(NULL); break; } isolate->Exit(); @@ -19749,7 +19673,7 @@ TEST(DontDeleteCellLoadICAPI) { // cell created using the API. LocalContext context; v8::HandleScope scope(context->GetIsolate()); - context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); + context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete); ExpectBoolean("delete cell", false); CompileRun(function_code); ExpectString("readCell()", "value"); @@ -19832,6 +19756,7 @@ TEST(PersistentHandleInNewSpaceVisitor) { CHECK_EQ(42, object1.WrapperClassId()); CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); + CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); CHECK_EQ(0, object2.WrapperClassId()); @@ -20345,15 +20270,15 @@ THREADED_TEST(ReadOnlyIndexedProperties) { LocalContext context; Local<v8::Object> obj = templ->NewInstance(); context->Global()->Set(v8_str("obj"), obj); - obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); + obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); obj->Set(v8_str("1"), v8_str("foobar")); CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); - obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); + obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); obj->Set(v8_num(2), v8_str("foobar")); CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); // Test non-smi case. - obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); + obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); obj->Set(v8_str("2000000000"), v8_str("foobar")); CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); } @@ -20477,20 +20402,20 @@ THREADED_TEST(Regress93759) { CHECK(result1->Equals(simple_object->GetPrototype())); Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); - CHECK(result2->Equals(Undefined(isolate))); + CHECK(result2.IsEmpty()); Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); CHECK(result3->Equals(global_object->GetPrototype())); Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); - CHECK(result4->Equals(Undefined(isolate))); + CHECK(result4.IsEmpty()); Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); CHECK(result5->Equals( object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); - CHECK(result6->Equals(Undefined(isolate))); + CHECK(result6.IsEmpty()); } @@ -20624,13 +20549,13 @@ uint8_t callback_fired = 0; void CallCompletedCallback1() { - i::OS::Print("Firing callback 1.\n"); + v8::base::OS::Print("Firing callback 1.\n"); callback_fired ^= 1; // Toggle first bit. } void CallCompletedCallback2() { - i::OS::Print("Firing callback 2.\n"); + v8::base::OS::Print("Firing callback 2.\n"); callback_fired ^= 2; // Toggle second bit. } @@ -20639,15 +20564,15 @@ void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { int32_t level = args[0]->Int32Value(); if (level < 3) { level++; - i::OS::Print("Entering recursion level %d.\n", level); + v8::base::OS::Print("Entering recursion level %d.\n", level); char script[64]; i::Vector<char> script_vector(script, sizeof(script)); - i::OS::SNPrintF(script_vector, "recursion(%d)", level); + i::SNPrintF(script_vector, "recursion(%d)", level); CompileRun(script_vector.start()); - i::OS::Print("Leaving recursion level %d.\n", level); + v8::base::OS::Print("Leaving recursion level %d.\n", level); CHECK_EQ(0, callback_fired); } else { - i::OS::Print("Recursion ends.\n"); + v8::base::OS::Print("Recursion ends.\n"); CHECK_EQ(0, callback_fired); } } @@ -20664,19 +20589,19 @@ TEST(CallCompletedCallback) { env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); - i::OS::Print("--- Script (1) ---\n"); + v8::base::OS::Print("--- Script (1) ---\n"); Local<Script> script = v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)")); script->Run(); CHECK_EQ(3, callback_fired); - i::OS::Print("\n--- Script (2) ---\n"); + v8::base::OS::Print("\n--- Script (2) ---\n"); callback_fired = 0; env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); script->Run(); CHECK_EQ(2, callback_fired); - i::OS::Print("\n--- Function ---\n"); + v8::base::OS::Print("\n--- Function ---\n"); callback_fired = 0; Local<Function> recursive_function = Local<Function>::Cast(env->Global()->Get(v8_str("recursion"))); @@ -20726,6 +20651,14 @@ static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) { } +void* g_passed_to_three = NULL; + + +static void MicrotaskThree(void* data) { + g_passed_to_three = data; +} + + TEST(EnqueueMicrotask) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -20759,6 +20692,62 @@ TEST(EnqueueMicrotask) { CompileRun("1+1;"); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); + + g_passed_to_three = NULL; + env->GetIsolate()->EnqueueMicrotask(MicrotaskThree); + CompileRun("1+1;"); + CHECK_EQ(NULL, g_passed_to_three); + CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); + CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); + + int dummy; + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskOne)); + env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); + CompileRun("1+1;"); + CHECK_EQ(&dummy, g_passed_to_three); + CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value()); + CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); + g_passed_to_three = NULL; +} + + +static void MicrotaskExceptionOne( + const v8::FunctionCallbackInfo<Value>& info) { + v8::HandleScope scope(info.GetIsolate()); + CompileRun("exception1Calls++;"); + info.GetIsolate()->ThrowException( + v8::Exception::Error(v8_str("first"))); +} + + +static void MicrotaskExceptionTwo( + const v8::FunctionCallbackInfo<Value>& info) { + v8::HandleScope scope(info.GetIsolate()); + CompileRun("exception2Calls++;"); + info.GetIsolate()->ThrowException( + v8::Exception::Error(v8_str("second"))); +} + + +TEST(RunMicrotasksIgnoresThrownExceptions) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + CompileRun( + "var exception1Calls = 0;" + "var exception2Calls = 0;"); + isolate->EnqueueMicrotask( + Function::New(isolate, MicrotaskExceptionOne)); + isolate->EnqueueMicrotask( + Function::New(isolate, MicrotaskExceptionTwo)); + TryCatch try_catch; + CompileRun("1+1;"); + CHECK(!try_catch.HasCaught()); + CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value()); + CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value()); } @@ -20823,6 +20812,57 @@ TEST(SetAutorunMicrotasks) { } +TEST(RunMicrotasksWithoutEnteringContext) { + v8::Isolate* isolate = CcTest::isolate(); + HandleScope handle_scope(isolate); + isolate->SetAutorunMicrotasks(false); + Handle<Context> context = Context::New(isolate); + { + Context::Scope context_scope(context); + CompileRun("var ext1Calls = 0;"); + isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne)); + } + isolate->RunMicrotasks(); + { + Context::Scope context_scope(context); + CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); + } + isolate->SetAutorunMicrotasks(true); +} + + +static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) { + v8::DebugEvent event = event_details.GetEvent(); + if (event != v8::Break) return; + Handle<Object> exec_state = event_details.GetExecutionState(); + Handle<Value> break_id = exec_state->Get(v8_str("break_id")); + CompileRun("function f(id) { new FrameDetails(id, 0); }"); + Handle<Function> fun = Handle<Function>::Cast( + CcTest::global()->Get(v8_str("f"))->ToObject()); + fun->Call(CcTest::global(), 1, &break_id); +} + + +TEST(Regress385349) { + i::FLAG_allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + HandleScope handle_scope(isolate); + isolate->SetAutorunMicrotasks(false); + Handle<Context> context = Context::New(isolate); + v8::Debug::SetDebugEventListener(DebugEventInObserver); + { + Context::Scope context_scope(context); + CompileRun("var obj = {};" + "Object.observe(obj, function(changes) { debugger; });" + "obj.a = 0;"); + } + isolate->RunMicrotasks(); + isolate->SetAutorunMicrotasks(true); + v8::Debug::SetDebugEventListener(NULL); +} + + +#ifdef DEBUG static int probes_counter = 0; static int misses_counter = 0; static int updates_counter = 0; @@ -20852,11 +20892,10 @@ static const char* kMegamorphicTestProgram = " fooify(a);" " fooify(b);" "}"; +#endif static void StubCacheHelper(bool primary) { - V8::SetCounterFunction(LookupCounter); - USE(kMegamorphicTestProgram); #ifdef DEBUG i::FLAG_native_code_counters = true; if (primary) { @@ -20866,6 +20905,7 @@ static void StubCacheHelper(bool primary) { } i::FLAG_crankshaft = false; LocalContext env; + env->GetIsolate()->SetCounterFunction(LookupCounter); v8::HandleScope scope(env->GetIsolate()); int initial_probes = probes_counter; int initial_misses = misses_counter; @@ -20895,6 +20935,7 @@ TEST(PrimaryStubCache) { } +#ifdef DEBUG static int cow_arrays_created_runtime = 0; @@ -20904,13 +20945,14 @@ static int* LookupCounterCOWArrays(const char* name) { } return NULL; } +#endif TEST(CheckCOWArraysCreatedRuntimeCounter) { - V8::SetCounterFunction(LookupCounterCOWArrays); #ifdef DEBUG i::FLAG_native_code_counters = true; LocalContext env; + env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays); v8::HandleScope scope(env->GetIsolate()); int initial_cow_arrays = cow_arrays_created_runtime; CompileRun("var o = [1, 2, 3];"); @@ -21001,8 +21043,7 @@ static void InstanceCheckedSetter(Local<String> name, } -static void CheckInstanceCheckedResult(int getters, - int setters, +static void CheckInstanceCheckedResult(int getters, int setters, bool expects_callbacks, TryCatch* try_catch) { if (expects_callbacks) { @@ -21125,10 +21166,8 @@ THREADED_TEST(InstanceCheckOnPrototypeAccessor) { Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); Local<ObjectTemplate> proto = templ->PrototypeTemplate(); - proto->SetAccessor(v8_str("foo"), - InstanceCheckedGetter, InstanceCheckedSetter, - Handle<Value>(), - v8::DEFAULT, + proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter, + InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT, v8::None, v8::AccessorSignature::New(context->GetIsolate(), templ)); context->Global()->Set(v8_str("f"), templ->GetFunction()); @@ -21394,7 +21433,6 @@ THREADED_TEST(Regress157124) { THREADED_TEST(Regress2535) { - i::FLAG_harmony_collections = true; LocalContext context; v8::HandleScope scope(context->GetIsolate()); Local<Value> set_value = CompileRun("new Set();"); @@ -21469,16 +21507,16 @@ class ThreadInterruptTest { private: static const int kExpectedValue = 1; - class InterruptThread : public i::Thread { + class InterruptThread : public v8::base::Thread { public: explicit InterruptThread(ThreadInterruptTest* test) - : Thread("InterruptThread"), test_(test) {} + : Thread(Options("InterruptThread")), test_(test) {} virtual void Run() { struct sigaction action; // Ensure that we'll enter waiting condition - i::OS::Sleep(100); + v8::base::OS::Sleep(100); // Setup signal handler memset(&action, 0, sizeof(action)); @@ -21489,7 +21527,7 @@ class ThreadInterruptTest { kill(getpid(), SIGCHLD); // Ensure that if wait has returned because of error - i::OS::Sleep(100); + v8::base::OS::Sleep(100); // Set value and signal semaphore test_->sem_value_ = 1; @@ -21503,7 +21541,7 @@ class ThreadInterruptTest { ThreadInterruptTest* test_; }; - i::Semaphore sem_; + v8::base::Semaphore sem_; volatile int sem_value_; }; @@ -21570,11 +21608,9 @@ TEST(JSONStringifyAccessCheck) { LocalContext context1(NULL, global_template); context1->Global()->Set(v8_str("other"), global0); - ExpectString("JSON.stringify(other)", "{}"); - ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })", - "{\"a\":{},\"b\":[\"c\"]}"); - ExpectString("JSON.stringify([other, 'b', 'c'])", - "[{},\"b\",\"c\"]"); + 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")); @@ -21582,9 +21618,9 @@ TEST(JSONStringifyAccessCheck) { context1->Global()->Set(v8_str("array"), array); ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); array->TurnOnAccessCheck(); - ExpectString("JSON.stringify(array)", "[]"); - ExpectString("JSON.stringify([array])", "[[]]"); - ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}"); + CHECK(CompileRun("JSON.stringify(array)").IsEmpty()); + CHECK(CompileRun("JSON.stringify([array])").IsEmpty()); + CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty()); } } @@ -21624,7 +21660,7 @@ void CheckCorrectThrow(const char* script) { access_check_fail_thrown = false; catch_callback_called = false; i::ScopedVector<char> source(1024); - i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); + i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); CompileRun(source.start()); CHECK(access_check_fail_thrown); CHECK(catch_callback_called); @@ -21682,18 +21718,18 @@ TEST(AccessCheckThrows) { CheckCorrectThrow("JSON.stringify(other)"); CheckCorrectThrow("has_own_property(other, 'x')"); CheckCorrectThrow("%GetProperty(other, 'x')"); - CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)"); - CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')"); + CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)"); + CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)"); CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); - CheckCorrectThrow("%HasLocalProperty(other, 'x')"); + CheckCorrectThrow("%HasOwnProperty(other, 'x')"); CheckCorrectThrow("%HasProperty(other, 'x')"); CheckCorrectThrow("%HasElement(other, 1)"); CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); CheckCorrectThrow("%GetPropertyNames(other)"); // PROPERTY_ATTRIBUTES_NONE = 0 - CheckCorrectThrow("%GetLocalPropertyNames(other, 0)"); - CheckCorrectThrow("%DefineOrRedefineAccessorProperty(" + CheckCorrectThrow("%GetOwnPropertyNames(other, 0)"); + CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" "other, 'x', null, null, 1)"); // Reset the failed access check callback so it does not influence @@ -21819,11 +21855,12 @@ class RequestInterruptTestBase { virtual ~RequestInterruptTestBase() { } + virtual void StartInterruptThread() = 0; + virtual void TestBody() = 0; void RunTest() { - InterruptThread i_thread(this); - i_thread.Start(); + StartInterruptThread(); v8::HandleScope handle_scope(isolate_); @@ -21852,7 +21889,6 @@ class RequestInterruptTestBase { return should_continue_; } - protected: static void ShouldContinueCallback( const v8::FunctionCallbackInfo<Value>& info) { RequestInterruptTestBase* test = @@ -21861,10 +21897,28 @@ class RequestInterruptTestBase { info.GetReturnValue().Set(test->ShouldContinue()); } - class InterruptThread : public i::Thread { + LocalContext env_; + v8::Isolate* isolate_; + v8::base::Semaphore sem_; + int warmup_; + bool should_continue_; +}; + + +class RequestInterruptTestBaseWithSimpleInterrupt + : public RequestInterruptTestBase { + public: + RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { } + + virtual void StartInterruptThread() { + i_thread.Start(); + } + + private: + class InterruptThread : public v8::base::Thread { public: explicit InterruptThread(RequestInterruptTestBase* test) - : Thread("RequestInterruptTest"), test_(test) {} + : Thread(Options("RequestInterruptTest")), test_(test) {} virtual void Run() { test_->sem_.Wait(); @@ -21880,15 +21934,12 @@ class RequestInterruptTestBase { RequestInterruptTestBase* test_; }; - LocalContext env_; - v8::Isolate* isolate_; - i::Semaphore sem_; - int warmup_; - bool should_continue_; + InterruptThread i_thread; }; -class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase { +class RequestInterruptTestWithFunctionCall + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { Local<Function> func = Function::New( @@ -21900,7 +21951,8 @@ class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase { }; -class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase { +class RequestInterruptTestWithMethodCall + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); @@ -21914,7 +21966,8 @@ class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase { }; -class RequestInterruptTestWithAccessor : public RequestInterruptTestBase { +class RequestInterruptTestWithAccessor + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); @@ -21928,7 +21981,8 @@ class RequestInterruptTestWithAccessor : public RequestInterruptTestBase { }; -class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase { +class RequestInterruptTestWithNativeAccessor + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); @@ -21955,7 +22009,7 @@ class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase { class RequestInterruptTestWithMethodCallAndInterceptor - : public RequestInterruptTestBase { + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); @@ -21978,7 +22032,8 @@ class RequestInterruptTestWithMethodCallAndInterceptor }; -class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase { +class RequestInterruptTestWithMathAbs + : public RequestInterruptTestBaseWithSimpleInterrupt { public: virtual void TestBody() { env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New( @@ -22062,6 +22117,61 @@ TEST(RequestInterruptTestWithMathAbs) { } +class ClearInterruptFromAnotherThread + : public RequestInterruptTestBase { + public: + ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { } + + virtual void StartInterruptThread() { + i_thread.Start(); + } + + virtual void TestBody() { + Local<Function> func = Function::New( + isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); + env_->Global()->Set(v8_str("ShouldContinue"), func); + + CompileRun("while (ShouldContinue()) { }"); + } + + private: + class InterruptThread : public v8::base::Thread { + public: + explicit InterruptThread(ClearInterruptFromAnotherThread* test) + : Thread(Options("RequestInterruptTest")), test_(test) {} + + virtual void Run() { + test_->sem_.Wait(); + test_->isolate_->RequestInterrupt(&OnInterrupt, test_); + test_->sem_.Wait(); + test_->isolate_->ClearInterrupt(); + test_->sem2_.Signal(); + } + + static void OnInterrupt(v8::Isolate* isolate, void* data) { + ClearInterruptFromAnotherThread* test = + reinterpret_cast<ClearInterruptFromAnotherThread*>(data); + test->sem_.Signal(); + bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2)); + // Crash instead of timeout to make this failure more prominent. + CHECK(success); + test->should_continue_ = false; + } + + private: + ClearInterruptFromAnotherThread* test_; + }; + + InterruptThread i_thread; + v8::base::Semaphore sem2_; +}; + + +TEST(ClearInterruptFromAnotherThread) { + ClearInterruptFromAnotherThread().RunTest(); +} + + static Local<Value> function_new_expected_env; static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { CHECK_EQ(function_new_expected_env, info.Data()); @@ -22167,152 +22277,152 @@ class ApiCallOptimizationChecker { info.GetReturnValue().Set(v8_str("returned")); } - public: - enum SignatureType { - kNoSignature, - kSignatureOnReceiver, - kSignatureOnPrototype - }; - - void RunAll() { - SignatureType signature_types[] = - {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; - for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) { - SignatureType signature_type = signature_types[i]; - for (int j = 0; j < 2; j++) { - bool global = j == 0; - int key = signature_type + - ARRAY_SIZE(signature_types) * (global ? 1 : 0); - Run(signature_type, global, key); - } + public: + enum SignatureType { + kNoSignature, + kSignatureOnReceiver, + kSignatureOnPrototype + }; + + void RunAll() { + SignatureType signature_types[] = + {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; + for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) { + SignatureType signature_type = signature_types[i]; + for (int j = 0; j < 2; j++) { + bool global = j == 0; + int key = signature_type + + ARRAY_SIZE(signature_types) * (global ? 1 : 0); + Run(signature_type, global, key); } } + } - void Run(SignatureType signature_type, bool global, int key) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - // Build a template for signature checks. - Local<v8::ObjectTemplate> signature_template; - Local<v8::Signature> signature; - { - Local<v8::FunctionTemplate> parent_template = - FunctionTemplate::New(isolate); - parent_template->SetHiddenPrototype(true); - Local<v8::FunctionTemplate> function_template - = FunctionTemplate::New(isolate); - function_template->Inherit(parent_template); - switch (signature_type) { - case kNoSignature: - break; - case kSignatureOnReceiver: - signature = v8::Signature::New(isolate, function_template); - break; - case kSignatureOnPrototype: - signature = v8::Signature::New(isolate, parent_template); - break; - } - signature_template = function_template->InstanceTemplate(); - } - // Global object must pass checks. - Local<v8::Context> context = - v8::Context::New(isolate, NULL, signature_template); - v8::Context::Scope context_scope(context); - // Install regular object that can pass signature checks. - Local<Object> function_receiver = signature_template->NewInstance(); - context->Global()->Set(v8_str("function_receiver"), function_receiver); - // Get the holder objects. - Local<Object> inner_global = - Local<Object>::Cast(context->Global()->GetPrototype()); - // Install functions on hidden prototype object if there is one. - data = Object::New(isolate); - Local<FunctionTemplate> function_template = FunctionTemplate::New( - isolate, OptimizationCallback, data, signature); - Local<Function> function = function_template->GetFunction(); - Local<Object> global_holder = inner_global; - Local<Object> function_holder = function_receiver; - if (signature_type == kSignatureOnPrototype) { - function_holder = Local<Object>::Cast(function_holder->GetPrototype()); - global_holder = Local<Object>::Cast(global_holder->GetPrototype()); + void Run(SignatureType signature_type, bool global, int key) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + // Build a template for signature checks. + Local<v8::ObjectTemplate> signature_template; + Local<v8::Signature> signature; + { + Local<v8::FunctionTemplate> parent_template = + FunctionTemplate::New(isolate); + parent_template->SetHiddenPrototype(true); + Local<v8::FunctionTemplate> function_template + = FunctionTemplate::New(isolate); + function_template->Inherit(parent_template); + switch (signature_type) { + case kNoSignature: + break; + case kSignatureOnReceiver: + signature = v8::Signature::New(isolate, function_template); + break; + case kSignatureOnPrototype: + signature = v8::Signature::New(isolate, parent_template); + break; } - global_holder->Set(v8_str("g_f"), function); - global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); - function_holder->Set(v8_str("f"), function); - function_holder->SetAccessorProperty(v8_str("acc"), function, function); - // Initialize expected values. - callee = function; - count = 0; - if (global) { - receiver = context->Global(); - holder = inner_global; - } else { - holder = function_receiver; - // If not using a signature, add something else to the prototype chain - // to test the case that holder != receiver - if (signature_type == kNoSignature) { - receiver = Local<Object>::Cast(CompileRun( - "var receiver_subclass = {};\n" - "receiver_subclass.__proto__ = function_receiver;\n" - "receiver_subclass")); - } else { - receiver = Local<Object>::Cast(CompileRun( - "var receiver_subclass = function_receiver;\n" + signature_template = function_template->InstanceTemplate(); + } + // Global object must pass checks. + Local<v8::Context> context = + v8::Context::New(isolate, NULL, signature_template); + v8::Context::Scope context_scope(context); + // Install regular object that can pass signature checks. + Local<Object> function_receiver = signature_template->NewInstance(); + context->Global()->Set(v8_str("function_receiver"), function_receiver); + // Get the holder objects. + Local<Object> inner_global = + Local<Object>::Cast(context->Global()->GetPrototype()); + // Install functions on hidden prototype object if there is one. + data = Object::New(isolate); + Local<FunctionTemplate> function_template = FunctionTemplate::New( + isolate, OptimizationCallback, data, signature); + Local<Function> function = function_template->GetFunction(); + Local<Object> global_holder = inner_global; + Local<Object> function_holder = function_receiver; + if (signature_type == kSignatureOnPrototype) { + function_holder = Local<Object>::Cast(function_holder->GetPrototype()); + global_holder = Local<Object>::Cast(global_holder->GetPrototype()); + } + global_holder->Set(v8_str("g_f"), function); + global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); + function_holder->Set(v8_str("f"), function); + function_holder->SetAccessorProperty(v8_str("acc"), function, function); + // Initialize expected values. + callee = function; + count = 0; + if (global) { + receiver = context->Global(); + holder = inner_global; + } else { + holder = function_receiver; + // If not using a signature, add something else to the prototype chain + // to test the case that holder != receiver + if (signature_type == kNoSignature) { + receiver = Local<Object>::Cast(CompileRun( + "var receiver_subclass = {};\n" + "receiver_subclass.__proto__ = function_receiver;\n" "receiver_subclass")); - } - } - // With no signature, the holder is not set. - if (signature_type == kNoSignature) holder = receiver; - // build wrap_function - i::ScopedVector<char> wrap_function(200); - if (global) { - i::OS::SNPrintF( - wrap_function, - "function wrap_f_%d() { var f = g_f; return f(); }\n" - "function wrap_get_%d() { return this.g_acc; }\n" - "function wrap_set_%d() { return this.g_acc = 1; }\n", - key, key, key); } else { - i::OS::SNPrintF( - wrap_function, - "function wrap_f_%d() { return receiver_subclass.f(); }\n" - "function wrap_get_%d() { return receiver_subclass.acc; }\n" - "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", - key, key, key); + receiver = Local<Object>::Cast(CompileRun( + "var receiver_subclass = function_receiver;\n" + "receiver_subclass")); } - // build source string - i::ScopedVector<char> source(1000); - i::OS::SNPrintF( - source, - "%s\n" // wrap functions - "function wrap_f() { return wrap_f_%d(); }\n" - "function wrap_get() { return wrap_get_%d(); }\n" - "function wrap_set() { return wrap_set_%d(); }\n" - "check = function(returned) {\n" - " if (returned !== 'returned') { throw returned; }\n" - "}\n" - "\n" - "check(wrap_f());\n" - "check(wrap_f());\n" - "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" - "check(wrap_f());\n" - "\n" - "check(wrap_get());\n" - "check(wrap_get());\n" - "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" - "check(wrap_get());\n" - "\n" - "check = function(returned) {\n" - " if (returned !== 1) { throw returned; }\n" - "}\n" - "check(wrap_set());\n" - "check(wrap_set());\n" - "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" - "check(wrap_set());\n", - wrap_function.start(), key, key, key, key, key, key); - v8::TryCatch try_catch; - CompileRun(source.start()); - ASSERT(!try_catch.HasCaught()); - CHECK_EQ(9, count); } + // With no signature, the holder is not set. + if (signature_type == kNoSignature) holder = receiver; + // build wrap_function + i::ScopedVector<char> wrap_function(200); + if (global) { + i::SNPrintF( + wrap_function, + "function wrap_f_%d() { var f = g_f; return f(); }\n" + "function wrap_get_%d() { return this.g_acc; }\n" + "function wrap_set_%d() { return this.g_acc = 1; }\n", + key, key, key); + } else { + i::SNPrintF( + wrap_function, + "function wrap_f_%d() { return receiver_subclass.f(); }\n" + "function wrap_get_%d() { return receiver_subclass.acc; }\n" + "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", + key, key, key); + } + // build source string + i::ScopedVector<char> source(1000); + i::SNPrintF( + source, + "%s\n" // wrap functions + "function wrap_f() { return wrap_f_%d(); }\n" + "function wrap_get() { return wrap_get_%d(); }\n" + "function wrap_set() { return wrap_set_%d(); }\n" + "check = function(returned) {\n" + " if (returned !== 'returned') { throw returned; }\n" + "}\n" + "\n" + "check(wrap_f());\n" + "check(wrap_f());\n" + "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" + "check(wrap_f());\n" + "\n" + "check(wrap_get());\n" + "check(wrap_get());\n" + "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" + "check(wrap_get());\n" + "\n" + "check = function(returned) {\n" + " if (returned !== 1) { throw returned; }\n" + "}\n" + "check(wrap_set());\n" + "check(wrap_set());\n" + "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" + "check(wrap_set());\n", + wrap_function.start(), key, key, key, key, key, key); + v8::TryCatch try_catch; + CompileRun(source.start()); + DCHECK(!try_catch.HasCaught()); + CHECK_EQ(9, count); + } }; @@ -22341,14 +22451,13 @@ void StoringEventLoggerCallback(const char* message, int status) { TEST(EventLogging) { v8::Isolate* isolate = CcTest::isolate(); isolate->SetEventLogger(StoringEventLoggerCallback); - v8::internal::HistogramTimer* histogramTimer = - new v8::internal::HistogramTimer( - "V8.Test", 0, 10000, 50, - reinterpret_cast<v8::internal::Isolate*>(isolate)); - histogramTimer->Start(); + v8::internal::HistogramTimer histogramTimer( + "V8.Test", 0, 10000, 50, + reinterpret_cast<v8::internal::Isolate*>(isolate)); + histogramTimer.Start(); CHECK_EQ("V8.Test", last_event_message); CHECK_EQ(0, last_event_status); - histogramTimer->Stop(); + histogramTimer.Stop(); CHECK_EQ("V8.Test", last_event_message); CHECK_EQ(1, last_event_status); } @@ -22448,6 +22557,72 @@ TEST(Promises) { } +TEST(PromiseThen) { + LocalContext context; + v8::Isolate* isolate = context->GetIsolate(); + v8::HandleScope scope(isolate); + Handle<Object> global = context->Global(); + + // Creation. + Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate); + Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate); + Handle<v8::Promise> p = pr->GetPromise(); + Handle<v8::Promise> q = qr->GetPromise(); + + CHECK(p->IsPromise()); + CHECK(q->IsPromise()); + + pr->Resolve(v8::Integer::New(isolate, 1)); + qr->Resolve(p); + + // Chaining non-pending promises. + CompileRun( + "var x1 = 0;\n" + "var x2 = 0;\n" + "function f1(x) { x1 = x; return x+1 };\n" + "function f2(x) { x2 = x; return x+1 };\n"); + Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1"))); + Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2"))); + + // Chain + q->Chain(f1); + CHECK(global->Get(v8_str("x1"))->IsNumber()); + CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); + isolate->RunMicrotasks(); + CHECK(!global->Get(v8_str("x1"))->IsNumber()); + CHECK_EQ(p, global->Get(v8_str("x1"))); + + // Then + CompileRun("x1 = x2 = 0;"); + q->Then(f1); + CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); + isolate->RunMicrotasks(); + CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); + + // Then + CompileRun("x1 = x2 = 0;"); + pr = v8::Promise::Resolver::New(isolate); + qr = v8::Promise::Resolver::New(isolate); + + qr->Resolve(pr); + qr->GetPromise()->Then(f1)->Then(f2); + + CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); + CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); + isolate->RunMicrotasks(); + CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); + CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); + + pr->Resolve(v8::Integer::New(isolate, 3)); + + CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); + CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); + isolate->RunMicrotasks(); + CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); + CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); +} + + TEST(DisallowJavascriptExecutionScope) { LocalContext context; v8::Isolate* isolate = context->GetIsolate(); @@ -22540,3 +22715,158 @@ TEST(CaptureStackTraceForStackOverflow) { CompileRun("(function f(x) { f(x+1); })(0)"); CHECK(try_catch.HasCaught()); } + + +TEST(ScriptNameAndLineNumber) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + const char* url = "http://www.foo.com/foo.js"; + v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); + v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin); + Local<Script> script = v8::ScriptCompiler::Compile( + isolate, &script_source); + Local<Value> script_name = script->GetUnboundScript()->GetScriptName(); + CHECK(!script_name.IsEmpty()); + CHECK(script_name->IsString()); + String::Utf8Value utf8_name(script_name); + CHECK_EQ(url, *utf8_name); + int line_number = script->GetUnboundScript()->GetLineNumber(0); + CHECK_EQ(13, line_number); +} + + +Local<v8::Context> call_eval_context; +Local<v8::Function> call_eval_bound_function; +static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Context::Scope scope(call_eval_context); + args.GetReturnValue().Set( + call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL)); +} + + +TEST(CrossActivationEval) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + { + call_eval_context = v8::Context::New(isolate); + v8::Context::Scope scope(call_eval_context); + call_eval_bound_function = + Local<Function>::Cast(CompileRun("eval.bind(this, '1')")); + } + env->Global()->Set(v8_str("CallEval"), + v8::FunctionTemplate::New(isolate, CallEval)->GetFunction()); + Local<Value> result = CompileRun("CallEval();"); + CHECK_EQ(result, v8::Integer::New(isolate, 1)); +} + + +void SourceURLHelper(const char* source, const char* expected_source_url, + const char* expected_source_mapping_url) { + Local<Script> script = v8_compile(source); + if (expected_source_url != NULL) { + v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL()); + CHECK_EQ(expected_source_url, *url); + } else { + CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined()); + } + if (expected_source_mapping_url != NULL) { + v8::String::Utf8Value url( + script->GetUnboundScript()->GetSourceMappingURL()); + CHECK_EQ(expected_source_mapping_url, *url); + } else { + CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined()); + } +} + + +TEST(ScriptSourceURLAndSourceMappingURL) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar1.js\n", "bar1.js", NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js"); + + // Both sourceURL and sourceMappingURL. + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar3.js\n" + "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js"); + + // Two source URLs; the first one is ignored. + SourceURLHelper("function foo() {}\n" + "//# sourceURL=ignoreme.js\n" + "//# sourceURL=bar5.js\n", "bar5.js", NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceMappingURL=ignoreme.js\n" + "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js"); + + // SourceURL or sourceMappingURL in the middle of the script. + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar7.js\n" + "function baz() {}\n", "bar7.js", NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceMappingURL=bar8.js\n" + "function baz() {}\n", NULL, "bar8.js"); + + // Too much whitespace. + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar9.js\n" + "//# sourceMappingURL=bar10.js\n", NULL, NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceURL =bar11.js\n" + "//# sourceMappingURL =bar12.js\n", NULL, NULL); + + // Disallowed characters in value. + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar13 .js \n" + "//# sourceMappingURL=bar14 .js \n", + NULL, NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar15\t.js \n" + "//# sourceMappingURL=bar16\t.js \n", + NULL, NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar17'.js \n" + "//# sourceMappingURL=bar18'.js \n", + NULL, NULL); + SourceURLHelper("function foo() {}\n" + "//# sourceURL=bar19\".js \n" + "//# sourceMappingURL=bar20\".js \n", + NULL, NULL); + + // Not too much whitespace. + SourceURLHelper("function foo() {}\n" + "//# sourceURL= bar21.js \n" + "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js"); +} + + +TEST(GetOwnPropertyDescriptor) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + CompileRun( + "var x = { value : 13};" + "Object.defineProperty(x, 'p0', {value : 12});" + "Object.defineProperty(x, 'p1', {" + " set : function(value) { this.value = value; }," + " get : function() { return this.value; }," + "});"); + Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x"))); + Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop")); + CHECK(desc->IsUndefined()); + desc = x->GetOwnPropertyDescriptor(v8_str("p0")); + CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value"))); + desc = x->GetOwnPropertyDescriptor(v8_str("p1")); + Local<Function> set = + Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set"))); + Local<Function> get = + Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get"))); + CHECK_EQ(v8_num(13), get->Call(x, 0, NULL)); + Handle<Value> args[] = { v8_num(14) }; + set->Call(x, 1, args); + CHECK_EQ(v8_num(14), get->Call(x, 0, NULL)); +} diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 470cd61638..4c339a32b4 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -25,13 +25,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "disassembler.h" -#include "factory.h" -#include "arm/simulator-arm.h" -#include "arm/assembler-arm-inl.h" -#include "cctest.h" +#include "src/arm/assembler-arm-inl.h" +#include "src/arm/simulator-arm.h" +#include "src/disassembler.h" +#include "src/factory.h" +#include "src/ostreams.h" using namespace v8::internal; @@ -60,7 +61,8 @@ TEST(0) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F2 f = FUNCTION_CAST<F2>(code->entry()); int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 3, 4, 0, 0, 0)); @@ -95,7 +97,8 @@ TEST(1) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 100, 0, 0, 0, 0)); @@ -139,7 +142,8 @@ TEST(2) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 10, 0, 0, 0, 0)); @@ -185,7 +189,8 @@ TEST(3) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.i = 100000; @@ -308,7 +313,8 @@ TEST(4) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.a = 1.5; @@ -368,7 +374,8 @@ TEST(5) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = reinterpret_cast<int>( @@ -401,7 +408,8 @@ TEST(6) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = reinterpret_cast<int>( @@ -474,7 +482,8 @@ static void TestRoundingMode(VCVTTypes types, Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = reinterpret_cast<int>( @@ -657,7 +666,8 @@ TEST(8) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F4 fn = FUNCTION_CAST<F4>(code->entry()); d.a = 1.1; @@ -766,7 +776,8 @@ TEST(9) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F4 fn = FUNCTION_CAST<F4>(code->entry()); d.a = 1.1; @@ -871,7 +882,8 @@ TEST(10) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F4 fn = FUNCTION_CAST<F4>(code->entry()); d.a = 1.1; @@ -965,7 +977,8 @@ TEST(11) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); Object* dummy = CALL_GENERATED_CODE(f, &i, 0, 0, 0, 0); @@ -1092,7 +1105,8 @@ TEST(13) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.a = 1.5; @@ -1164,7 +1178,8 @@ TEST(14) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.left = BitCast<double>(kHoleNanInt64); @@ -1180,7 +1195,7 @@ TEST(14) { #ifdef DEBUG const uint64_t kArmNanInt64 = (static_cast<uint64_t>(kArmNanUpper32) << 32) | kArmNanLower32; - ASSERT(kArmNanInt64 != kHoleNanInt64); + DCHECK(kArmNanInt64 != kHoleNanInt64); #endif // With VFP2 the sign of the canonicalized Nan is undefined. So // we remove the sign bit for the upper tests. @@ -1267,7 +1282,8 @@ TEST(15) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.src0 = 0x01020304; @@ -1369,7 +1385,8 @@ TEST(16) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); t.src0 = 0x01020304; @@ -1451,7 +1468,8 @@ TEST(18) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef DEBUG - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); Object* dummy; diff --git a/deps/v8/test/cctest/test-assembler-arm64.cc b/deps/v8/test/cctest/test-assembler-arm64.cc index 25f3adb502..3d05487f39 100644 --- a/deps/v8/test/cctest/test-assembler-arm64.cc +++ b/deps/v8/test/cctest/test-assembler-arm64.cc @@ -31,15 +31,15 @@ #include <cmath> #include <limits> -#include "v8.h" +#include "src/v8.h" -#include "macro-assembler.h" -#include "arm64/simulator-arm64.h" -#include "arm64/decoder-arm64-inl.h" -#include "arm64/disasm-arm64.h" -#include "arm64/utils-arm64.h" -#include "cctest.h" -#include "test-utils-arm64.h" +#include "src/arm64/decoder-arm64-inl.h" +#include "src/arm64/disasm-arm64.h" +#include "src/arm64/simulator-arm64.h" +#include "src/arm64/utils-arm64.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-utils-arm64.h" using namespace v8::internal; @@ -58,7 +58,7 @@ using namespace v8::internal; // // RUN(); // -// ASSERT_EQUAL_64(1, x0); +// CHECK_EQUAL_64(1, x0); // // TEARDOWN(); // } @@ -74,22 +74,22 @@ using namespace v8::internal; // // We provide some helper assert to handle common cases: // -// ASSERT_EQUAL_32(int32_t, int_32t) -// ASSERT_EQUAL_FP32(float, float) -// ASSERT_EQUAL_32(int32_t, W register) -// ASSERT_EQUAL_FP32(float, S register) -// ASSERT_EQUAL_64(int64_t, int_64t) -// ASSERT_EQUAL_FP64(double, double) -// ASSERT_EQUAL_64(int64_t, X register) -// ASSERT_EQUAL_64(X register, X register) -// ASSERT_EQUAL_FP64(double, D register) +// CHECK_EQUAL_32(int32_t, int_32t) +// CHECK_EQUAL_FP32(float, float) +// CHECK_EQUAL_32(int32_t, W register) +// CHECK_EQUAL_FP32(float, S register) +// CHECK_EQUAL_64(int64_t, int_64t) +// CHECK_EQUAL_FP64(double, double) +// CHECK_EQUAL_64(int64_t, X register) +// CHECK_EQUAL_64(X register, X register) +// CHECK_EQUAL_FP64(double, D register) // -// e.g. ASSERT_EQUAL_64(0.5, d30); +// e.g. CHECK_EQUAL_64(0.5, d30); // // If more advance computation is required before the assert then access the // RegisterDump named core directly: // -// ASSERT_EQUAL_64(0x1234, core.xreg(0) & 0xffff); +// CHECK_EQUAL_64(0x1234, core.xreg(0) & 0xffff); #if 0 // TODO(all): enable. @@ -116,7 +116,7 @@ static void InitializeVM() { #define SETUP_SIZE(buf_size) \ Isolate* isolate = Isolate::Current(); \ HandleScope scope(isolate); \ - ASSERT(isolate != NULL); \ + DCHECK(isolate != NULL); \ byte* buf = new byte[buf_size]; \ MacroAssembler masm(isolate, buf, buf_size); \ Decoder<DispatchingDecoderVisitor>* decoder = \ @@ -170,11 +170,10 @@ static void InitializeVM() { #define SETUP_SIZE(buf_size) \ Isolate* isolate = Isolate::Current(); \ HandleScope scope(isolate); \ - ASSERT(isolate != NULL); \ + DCHECK(isolate != NULL); \ byte* buf = new byte[buf_size]; \ MacroAssembler masm(isolate, buf, buf_size); \ - RegisterDump core; \ - CpuFeatures::Probe(false); + RegisterDump core; #define RESET() \ __ Reset(); \ @@ -191,12 +190,12 @@ static void InitializeVM() { RESET(); \ START_AFTER_RESET(); -#define RUN() \ - CPU::FlushICache(buf, masm.SizeOfGeneratedCode()); \ - { \ - void (*test_function)(void); \ - memcpy(&test_function, &buf, sizeof(buf)); \ - test_function(); \ +#define RUN() \ + CpuFeatures::FlushICache(buf, masm.SizeOfGeneratedCode()); \ + { \ + void (*test_function)(void); \ + memcpy(&test_function, &buf, sizeof(buf)); \ + test_function(); \ } #define END() \ @@ -210,29 +209,29 @@ static void InitializeVM() { #endif // ifdef USE_SIMULATOR. -#define ASSERT_EQUAL_NZCV(expected) \ +#define CHECK_EQUAL_NZCV(expected) \ CHECK(EqualNzcv(expected, core.flags_nzcv())) -#define ASSERT_EQUAL_REGISTERS(expected) \ +#define CHECK_EQUAL_REGISTERS(expected) \ CHECK(EqualRegisters(&expected, &core)) -#define ASSERT_EQUAL_32(expected, result) \ +#define CHECK_EQUAL_32(expected, result) \ CHECK(Equal32(static_cast<uint32_t>(expected), &core, result)) -#define ASSERT_EQUAL_FP32(expected, result) \ +#define CHECK_EQUAL_FP32(expected, result) \ CHECK(EqualFP32(expected, &core, result)) -#define ASSERT_EQUAL_64(expected, result) \ +#define CHECK_EQUAL_64(expected, result) \ CHECK(Equal64(expected, &core, result)) -#define ASSERT_EQUAL_FP64(expected, result) \ +#define CHECK_EQUAL_FP64(expected, result) \ CHECK(EqualFP64(expected, &core, result)) #ifdef DEBUG -#define ASSERT_LITERAL_POOL_SIZE(expected) \ +#define DCHECK_LITERAL_POOL_SIZE(expected) \ CHECK((expected) == (__ LiteralPoolSize())) #else -#define ASSERT_LITERAL_POOL_SIZE(expected) \ +#define DCHECK_LITERAL_POOL_SIZE(expected) \ ((void) 0) #endif @@ -277,12 +276,12 @@ TEST(stack_ops) { RUN(); - ASSERT_EQUAL_64(0x1000, x0); - ASSERT_EQUAL_64(0x1050, x1); - ASSERT_EQUAL_64(0x104f, x2); - ASSERT_EQUAL_64(0x1fff, x3); - ASSERT_EQUAL_64(0xfffffff8, x4); - ASSERT_EQUAL_64(0xfffffff8, x5); + CHECK_EQUAL_64(0x1000, x0); + CHECK_EQUAL_64(0x1050, x1); + CHECK_EQUAL_64(0x104f, x2); + CHECK_EQUAL_64(0x1fff, x3); + CHECK_EQUAL_64(0xfffffff8, x4); + CHECK_EQUAL_64(0xfffffff8, x5); TEARDOWN(); } @@ -313,22 +312,22 @@ TEST(mvn) { RUN(); - ASSERT_EQUAL_64(0xfffff000, x0); - ASSERT_EQUAL_64(0xfffffffffffff000UL, x1); - ASSERT_EQUAL_64(0x00001fff, x2); - ASSERT_EQUAL_64(0x0000000000003fffUL, x3); - ASSERT_EQUAL_64(0xe00001ff, x4); - ASSERT_EQUAL_64(0xf0000000000000ffUL, x5); - ASSERT_EQUAL_64(0x00000001, x6); - ASSERT_EQUAL_64(0x0, x7); - ASSERT_EQUAL_64(0x7ff80000, x8); - ASSERT_EQUAL_64(0x3ffc000000000000UL, x9); - ASSERT_EQUAL_64(0xffffff00, x10); - ASSERT_EQUAL_64(0x0000000000000001UL, x11); - ASSERT_EQUAL_64(0xffff8003, x12); - ASSERT_EQUAL_64(0xffffffffffff0007UL, x13); - ASSERT_EQUAL_64(0xfffffffffffe000fUL, x14); - ASSERT_EQUAL_64(0xfffffffffffe000fUL, x15); + CHECK_EQUAL_64(0xfffff000, x0); + CHECK_EQUAL_64(0xfffffffffffff000UL, x1); + CHECK_EQUAL_64(0x00001fff, x2); + CHECK_EQUAL_64(0x0000000000003fffUL, x3); + CHECK_EQUAL_64(0xe00001ff, x4); + CHECK_EQUAL_64(0xf0000000000000ffUL, x5); + CHECK_EQUAL_64(0x00000001, x6); + CHECK_EQUAL_64(0x0, x7); + CHECK_EQUAL_64(0x7ff80000, x8); + CHECK_EQUAL_64(0x3ffc000000000000UL, x9); + CHECK_EQUAL_64(0xffffff00, x10); + CHECK_EQUAL_64(0x0000000000000001UL, x11); + CHECK_EQUAL_64(0xffff8003, x12); + CHECK_EQUAL_64(0xffffffffffff0007UL, x13); + CHECK_EQUAL_64(0xfffffffffffe000fUL, x14); + CHECK_EQUAL_64(0xfffffffffffe000fUL, x15); TEARDOWN(); } @@ -385,31 +384,31 @@ TEST(mov) { RUN(); - ASSERT_EQUAL_64(0x0123456789abcdefL, x0); - ASSERT_EQUAL_64(0x00000000abcd0000L, x1); - ASSERT_EQUAL_64(0xffffabcdffffffffL, x2); - ASSERT_EQUAL_64(0x5432ffffffffffffL, x3); - ASSERT_EQUAL_64(x4, x5); - ASSERT_EQUAL_32(-1, w6); - ASSERT_EQUAL_64(0x0123456789abcdefL, x7); - ASSERT_EQUAL_32(0x89abcdefL, w8); - ASSERT_EQUAL_64(0x0123456789abcdefL, x9); - ASSERT_EQUAL_32(0x89abcdefL, w10); - ASSERT_EQUAL_64(0x00000fff, x11); - ASSERT_EQUAL_64(0x0000000000000fffUL, x12); - ASSERT_EQUAL_64(0x00001ffe, x13); - ASSERT_EQUAL_64(0x0000000000003ffcUL, x14); - ASSERT_EQUAL_64(0x000001ff, x15); - ASSERT_EQUAL_64(0x00000000000000ffUL, x18); - ASSERT_EQUAL_64(0x00000001, x19); - ASSERT_EQUAL_64(0x0, x20); - ASSERT_EQUAL_64(0x7ff80000, x21); - ASSERT_EQUAL_64(0x3ffc000000000000UL, x22); - ASSERT_EQUAL_64(0x000000fe, x23); - ASSERT_EQUAL_64(0xfffffffffffffffcUL, x24); - ASSERT_EQUAL_64(0x00007ff8, x25); - ASSERT_EQUAL_64(0x000000000000fff0UL, x26); - ASSERT_EQUAL_64(0x000000000001ffe0UL, x27); + CHECK_EQUAL_64(0x0123456789abcdefL, x0); + CHECK_EQUAL_64(0x00000000abcd0000L, x1); + CHECK_EQUAL_64(0xffffabcdffffffffL, x2); + CHECK_EQUAL_64(0x5432ffffffffffffL, x3); + CHECK_EQUAL_64(x4, x5); + CHECK_EQUAL_32(-1, w6); + CHECK_EQUAL_64(0x0123456789abcdefL, x7); + CHECK_EQUAL_32(0x89abcdefL, w8); + CHECK_EQUAL_64(0x0123456789abcdefL, x9); + CHECK_EQUAL_32(0x89abcdefL, w10); + CHECK_EQUAL_64(0x00000fff, x11); + CHECK_EQUAL_64(0x0000000000000fffUL, x12); + CHECK_EQUAL_64(0x00001ffe, x13); + CHECK_EQUAL_64(0x0000000000003ffcUL, x14); + CHECK_EQUAL_64(0x000001ff, x15); + CHECK_EQUAL_64(0x00000000000000ffUL, x18); + CHECK_EQUAL_64(0x00000001, x19); + CHECK_EQUAL_64(0x0, x20); + CHECK_EQUAL_64(0x7ff80000, x21); + CHECK_EQUAL_64(0x3ffc000000000000UL, x22); + CHECK_EQUAL_64(0x000000fe, x23); + CHECK_EQUAL_64(0xfffffffffffffffcUL, x24); + CHECK_EQUAL_64(0x00007ff8, x25); + CHECK_EQUAL_64(0x000000000000fff0UL, x26); + CHECK_EQUAL_64(0x000000000001ffe0UL, x27); TEARDOWN(); } @@ -427,17 +426,23 @@ TEST(mov_imm_w) { __ Mov(w4, 0x00001234L); __ Mov(w5, 0x12340000L); __ Mov(w6, 0x12345678L); + __ Mov(w7, (int32_t)0x80000000); + __ Mov(w8, (int32_t)0xffff0000); + __ Mov(w9, kWMinInt); END(); RUN(); - ASSERT_EQUAL_64(0xffffffffL, x0); - ASSERT_EQUAL_64(0xffff1234L, x1); - ASSERT_EQUAL_64(0x1234ffffL, x2); - ASSERT_EQUAL_64(0x00000000L, x3); - ASSERT_EQUAL_64(0x00001234L, x4); - ASSERT_EQUAL_64(0x12340000L, x5); - ASSERT_EQUAL_64(0x12345678L, x6); + CHECK_EQUAL_64(0xffffffffL, x0); + CHECK_EQUAL_64(0xffff1234L, x1); + CHECK_EQUAL_64(0x1234ffffL, x2); + CHECK_EQUAL_64(0x00000000L, x3); + CHECK_EQUAL_64(0x00001234L, x4); + CHECK_EQUAL_64(0x12340000L, x5); + CHECK_EQUAL_64(0x12345678L, x6); + CHECK_EQUAL_64(0x80000000L, x7); + CHECK_EQUAL_64(0xffff0000L, x8); + CHECK_EQUAL_32(kWMinInt, w9); TEARDOWN(); } @@ -479,32 +484,32 @@ TEST(mov_imm_x) { RUN(); - ASSERT_EQUAL_64(0xffffffffffff1234L, x1); - ASSERT_EQUAL_64(0xffffffff12345678L, x2); - ASSERT_EQUAL_64(0xffff1234ffff5678L, x3); - ASSERT_EQUAL_64(0x1234ffffffff5678L, x4); - ASSERT_EQUAL_64(0x1234ffff5678ffffL, x5); - ASSERT_EQUAL_64(0x12345678ffffffffL, x6); - ASSERT_EQUAL_64(0x1234ffffffffffffL, x7); - ASSERT_EQUAL_64(0x123456789abcffffL, x8); - ASSERT_EQUAL_64(0x12345678ffff9abcL, x9); - ASSERT_EQUAL_64(0x1234ffff56789abcL, x10); - ASSERT_EQUAL_64(0xffff123456789abcL, x11); - ASSERT_EQUAL_64(0x0000000000000000L, x12); - ASSERT_EQUAL_64(0x0000000000001234L, x13); - ASSERT_EQUAL_64(0x0000000012345678L, x14); - ASSERT_EQUAL_64(0x0000123400005678L, x15); - ASSERT_EQUAL_64(0x1234000000005678L, x18); - ASSERT_EQUAL_64(0x1234000056780000L, x19); - ASSERT_EQUAL_64(0x1234567800000000L, x20); - ASSERT_EQUAL_64(0x1234000000000000L, x21); - ASSERT_EQUAL_64(0x123456789abc0000L, x22); - ASSERT_EQUAL_64(0x1234567800009abcL, x23); - ASSERT_EQUAL_64(0x1234000056789abcL, x24); - ASSERT_EQUAL_64(0x0000123456789abcL, x25); - ASSERT_EQUAL_64(0x123456789abcdef0L, x26); - ASSERT_EQUAL_64(0xffff000000000001L, x27); - ASSERT_EQUAL_64(0x8000ffff00000000L, x28); + CHECK_EQUAL_64(0xffffffffffff1234L, x1); + CHECK_EQUAL_64(0xffffffff12345678L, x2); + CHECK_EQUAL_64(0xffff1234ffff5678L, x3); + CHECK_EQUAL_64(0x1234ffffffff5678L, x4); + CHECK_EQUAL_64(0x1234ffff5678ffffL, x5); + CHECK_EQUAL_64(0x12345678ffffffffL, x6); + CHECK_EQUAL_64(0x1234ffffffffffffL, x7); + CHECK_EQUAL_64(0x123456789abcffffL, x8); + CHECK_EQUAL_64(0x12345678ffff9abcL, x9); + CHECK_EQUAL_64(0x1234ffff56789abcL, x10); + CHECK_EQUAL_64(0xffff123456789abcL, x11); + CHECK_EQUAL_64(0x0000000000000000L, x12); + CHECK_EQUAL_64(0x0000000000001234L, x13); + CHECK_EQUAL_64(0x0000000012345678L, x14); + CHECK_EQUAL_64(0x0000123400005678L, x15); + CHECK_EQUAL_64(0x1234000000005678L, x18); + CHECK_EQUAL_64(0x1234000056780000L, x19); + CHECK_EQUAL_64(0x1234567800000000L, x20); + CHECK_EQUAL_64(0x1234000000000000L, x21); + CHECK_EQUAL_64(0x123456789abc0000L, x22); + CHECK_EQUAL_64(0x1234567800009abcL, x23); + CHECK_EQUAL_64(0x1234000056789abcL, x24); + CHECK_EQUAL_64(0x0000123456789abcL, x25); + CHECK_EQUAL_64(0x123456789abcdef0L, x26); + CHECK_EQUAL_64(0xffff000000000001L, x27); + CHECK_EQUAL_64(0x8000ffff00000000L, x28); TEARDOWN(); } @@ -532,16 +537,16 @@ TEST(orr) { RUN(); - ASSERT_EQUAL_64(0xf000f0ff, x2); - ASSERT_EQUAL_64(0xf000f0f0, x3); - ASSERT_EQUAL_64(0xf00000ff0000f0f0L, x4); - ASSERT_EQUAL_64(0x0f00f0ff, x5); - ASSERT_EQUAL_64(0xff00f0ff, x6); - ASSERT_EQUAL_64(0x0f00f0ff, x7); - ASSERT_EQUAL_64(0x0ffff0f0, x8); - ASSERT_EQUAL_64(0x0ff00000000ff0f0L, x9); - ASSERT_EQUAL_64(0xf0ff, x10); - ASSERT_EQUAL_64(0xf0000000f000f0f0L, x11); + CHECK_EQUAL_64(0xf000f0ff, x2); + CHECK_EQUAL_64(0xf000f0f0, x3); + CHECK_EQUAL_64(0xf00000ff0000f0f0L, x4); + CHECK_EQUAL_64(0x0f00f0ff, x5); + CHECK_EQUAL_64(0xff00f0ff, x6); + CHECK_EQUAL_64(0x0f00f0ff, x7); + CHECK_EQUAL_64(0x0ffff0f0, x8); + CHECK_EQUAL_64(0x0ff00000000ff0f0L, x9); + CHECK_EQUAL_64(0xf0ff, x10); + CHECK_EQUAL_64(0xf0000000f000f0f0L, x11); TEARDOWN(); } @@ -566,14 +571,14 @@ TEST(orr_extend) { RUN(); - ASSERT_EQUAL_64(0x00000081, x6); - ASSERT_EQUAL_64(0x00010101, x7); - ASSERT_EQUAL_64(0x00020201, x8); - ASSERT_EQUAL_64(0x0000000400040401UL, x9); - ASSERT_EQUAL_64(0x00000000ffffff81UL, x10); - ASSERT_EQUAL_64(0xffffffffffff0101UL, x11); - ASSERT_EQUAL_64(0xfffffffe00020201UL, x12); - ASSERT_EQUAL_64(0x0000000400040401UL, x13); + CHECK_EQUAL_64(0x00000081, x6); + CHECK_EQUAL_64(0x00010101, x7); + CHECK_EQUAL_64(0x00020201, x8); + CHECK_EQUAL_64(0x0000000400040401UL, x9); + CHECK_EQUAL_64(0x00000000ffffff81UL, x10); + CHECK_EQUAL_64(0xffffffffffff0101UL, x11); + CHECK_EQUAL_64(0xfffffffe00020201UL, x12); + CHECK_EQUAL_64(0x0000000400040401UL, x13); TEARDOWN(); } @@ -589,14 +594,19 @@ TEST(bitwise_wide_imm) { __ Orr(x10, x0, Operand(0x1234567890abcdefUL)); __ Orr(w11, w1, Operand(0x90abcdef)); + + __ Orr(w12, w0, kWMinInt); + __ Eor(w13, w0, kWMinInt); END(); RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(0xf0f0f0f0f0f0f0f0UL, x1); - ASSERT_EQUAL_64(0x1234567890abcdefUL, x10); - ASSERT_EQUAL_64(0xf0fbfdffUL, x11); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(0xf0f0f0f0f0f0f0f0UL, x1); + CHECK_EQUAL_64(0x1234567890abcdefUL, x10); + CHECK_EQUAL_64(0xf0fbfdffUL, x11); + CHECK_EQUAL_32(kWMinInt, w12); + CHECK_EQUAL_32(kWMinInt, w13); TEARDOWN(); } @@ -624,16 +634,16 @@ TEST(orn) { RUN(); - ASSERT_EQUAL_64(0xffffffff0ffffff0L, x2); - ASSERT_EQUAL_64(0xfffff0ff, x3); - ASSERT_EQUAL_64(0xfffffff0fffff0ffL, x4); - ASSERT_EQUAL_64(0xffffffff87fffff0L, x5); - ASSERT_EQUAL_64(0x07fffff0, x6); - ASSERT_EQUAL_64(0xffffffff87fffff0L, x7); - ASSERT_EQUAL_64(0xff00ffff, x8); - ASSERT_EQUAL_64(0xff00ffffffffffffL, x9); - ASSERT_EQUAL_64(0xfffff0f0, x10); - ASSERT_EQUAL_64(0xffff0000fffff0f0L, x11); + CHECK_EQUAL_64(0xffffffff0ffffff0L, x2); + CHECK_EQUAL_64(0xfffff0ff, x3); + CHECK_EQUAL_64(0xfffffff0fffff0ffL, x4); + CHECK_EQUAL_64(0xffffffff87fffff0L, x5); + CHECK_EQUAL_64(0x07fffff0, x6); + CHECK_EQUAL_64(0xffffffff87fffff0L, x7); + CHECK_EQUAL_64(0xff00ffff, x8); + CHECK_EQUAL_64(0xff00ffffffffffffL, x9); + CHECK_EQUAL_64(0xfffff0f0, x10); + CHECK_EQUAL_64(0xffff0000fffff0f0L, x11); TEARDOWN(); } @@ -658,14 +668,14 @@ TEST(orn_extend) { RUN(); - ASSERT_EQUAL_64(0xffffff7f, x6); - ASSERT_EQUAL_64(0xfffffffffffefefdUL, x7); - ASSERT_EQUAL_64(0xfffdfdfb, x8); - ASSERT_EQUAL_64(0xfffffffbfffbfbf7UL, x9); - ASSERT_EQUAL_64(0x0000007f, x10); - ASSERT_EQUAL_64(0x0000fefd, x11); - ASSERT_EQUAL_64(0x00000001fffdfdfbUL, x12); - ASSERT_EQUAL_64(0xfffffffbfffbfbf7UL, x13); + CHECK_EQUAL_64(0xffffff7f, x6); + CHECK_EQUAL_64(0xfffffffffffefefdUL, x7); + CHECK_EQUAL_64(0xfffdfdfb, x8); + CHECK_EQUAL_64(0xfffffffbfffbfbf7UL, x9); + CHECK_EQUAL_64(0x0000007f, x10); + CHECK_EQUAL_64(0x0000fefd, x11); + CHECK_EQUAL_64(0x00000001fffdfdfbUL, x12); + CHECK_EQUAL_64(0xfffffffbfffbfbf7UL, x13); TEARDOWN(); } @@ -693,16 +703,16 @@ TEST(and_) { RUN(); - ASSERT_EQUAL_64(0x000000f0, x2); - ASSERT_EQUAL_64(0x00000ff0, x3); - ASSERT_EQUAL_64(0x00000ff0, x4); - ASSERT_EQUAL_64(0x00000070, x5); - ASSERT_EQUAL_64(0x0000ff00, x6); - ASSERT_EQUAL_64(0x00000f00, x7); - ASSERT_EQUAL_64(0x00000ff0, x8); - ASSERT_EQUAL_64(0x00000000, x9); - ASSERT_EQUAL_64(0x0000ff00, x10); - ASSERT_EQUAL_64(0x000000f0, x11); + CHECK_EQUAL_64(0x000000f0, x2); + CHECK_EQUAL_64(0x00000ff0, x3); + CHECK_EQUAL_64(0x00000ff0, x4); + CHECK_EQUAL_64(0x00000070, x5); + CHECK_EQUAL_64(0x0000ff00, x6); + CHECK_EQUAL_64(0x00000f00, x7); + CHECK_EQUAL_64(0x00000ff0, x8); + CHECK_EQUAL_64(0x00000000, x9); + CHECK_EQUAL_64(0x0000ff00, x10); + CHECK_EQUAL_64(0x000000f0, x11); TEARDOWN(); } @@ -727,14 +737,14 @@ TEST(and_extend) { RUN(); - ASSERT_EQUAL_64(0x00000081, x6); - ASSERT_EQUAL_64(0x00010102, x7); - ASSERT_EQUAL_64(0x00020204, x8); - ASSERT_EQUAL_64(0x0000000400040408UL, x9); - ASSERT_EQUAL_64(0xffffff81, x10); - ASSERT_EQUAL_64(0xffffffffffff0102UL, x11); - ASSERT_EQUAL_64(0xfffffffe00020204UL, x12); - ASSERT_EQUAL_64(0x0000000400040408UL, x13); + CHECK_EQUAL_64(0x00000081, x6); + CHECK_EQUAL_64(0x00010102, x7); + CHECK_EQUAL_64(0x00020204, x8); + CHECK_EQUAL_64(0x0000000400040408UL, x9); + CHECK_EQUAL_64(0xffffff81, x10); + CHECK_EQUAL_64(0xffffffffffff0102UL, x11); + CHECK_EQUAL_64(0xfffffffe00020204UL, x12); + CHECK_EQUAL_64(0x0000000400040408UL, x13); TEARDOWN(); } @@ -751,8 +761,8 @@ TEST(ands) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0xf00000ff, x0); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0xf00000ff, x0); START(); __ Mov(x0, 0xfff0); @@ -762,8 +772,8 @@ TEST(ands) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0x00000000, x0); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0x00000000, x0); START(); __ Mov(x0, 0x8000000000000000L); @@ -773,8 +783,8 @@ TEST(ands) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x8000000000000000L, x0); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x8000000000000000L, x0); START(); __ Mov(x0, 0xfff0); @@ -783,8 +793,8 @@ TEST(ands) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0x00000000, x0); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0x00000000, x0); START(); __ Mov(x0, 0xff000000); @@ -793,8 +803,8 @@ TEST(ands) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x80000000, x0); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x80000000, x0); TEARDOWN(); } @@ -832,18 +842,18 @@ TEST(bic) { RUN(); - ASSERT_EQUAL_64(0x0000ff00, x2); - ASSERT_EQUAL_64(0x0000f000, x3); - ASSERT_EQUAL_64(0x0000f000, x4); - ASSERT_EQUAL_64(0x0000ff80, x5); - ASSERT_EQUAL_64(0x000000f0, x6); - ASSERT_EQUAL_64(0x0000f0f0, x7); - ASSERT_EQUAL_64(0x0000f000, x8); - ASSERT_EQUAL_64(0x0000ff00, x9); - ASSERT_EQUAL_64(0x0000ffe0, x10); - ASSERT_EQUAL_64(0x0000fef0, x11); + CHECK_EQUAL_64(0x0000ff00, x2); + CHECK_EQUAL_64(0x0000f000, x3); + CHECK_EQUAL_64(0x0000f000, x4); + CHECK_EQUAL_64(0x0000ff80, x5); + CHECK_EQUAL_64(0x000000f0, x6); + CHECK_EQUAL_64(0x0000f0f0, x7); + CHECK_EQUAL_64(0x0000f000, x8); + CHECK_EQUAL_64(0x0000ff00, x9); + CHECK_EQUAL_64(0x0000ffe0, x10); + CHECK_EQUAL_64(0x0000fef0, x11); - ASSERT_EQUAL_64(0x543210, x21); + CHECK_EQUAL_64(0x543210, x21); TEARDOWN(); } @@ -868,14 +878,14 @@ TEST(bic_extend) { RUN(); - ASSERT_EQUAL_64(0xffffff7e, x6); - ASSERT_EQUAL_64(0xfffffffffffefefdUL, x7); - ASSERT_EQUAL_64(0xfffdfdfb, x8); - ASSERT_EQUAL_64(0xfffffffbfffbfbf7UL, x9); - ASSERT_EQUAL_64(0x0000007e, x10); - ASSERT_EQUAL_64(0x0000fefd, x11); - ASSERT_EQUAL_64(0x00000001fffdfdfbUL, x12); - ASSERT_EQUAL_64(0xfffffffbfffbfbf7UL, x13); + CHECK_EQUAL_64(0xffffff7e, x6); + CHECK_EQUAL_64(0xfffffffffffefefdUL, x7); + CHECK_EQUAL_64(0xfffdfdfb, x8); + CHECK_EQUAL_64(0xfffffffbfffbfbf7UL, x9); + CHECK_EQUAL_64(0x0000007e, x10); + CHECK_EQUAL_64(0x0000fefd, x11); + CHECK_EQUAL_64(0x00000001fffdfdfbUL, x12); + CHECK_EQUAL_64(0xfffffffbfffbfbf7UL, x13); TEARDOWN(); } @@ -892,8 +902,8 @@ TEST(bics) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0x00000000, x0); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0x00000000, x0); START(); __ Mov(x0, 0xffffffff); @@ -902,8 +912,8 @@ TEST(bics) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x80000000, x0); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x80000000, x0); START(); __ Mov(x0, 0x8000000000000000L); @@ -913,8 +923,8 @@ TEST(bics) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0x00000000, x0); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0x00000000, x0); START(); __ Mov(x0, 0xffffffffffffffffL); @@ -923,8 +933,8 @@ TEST(bics) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x8000000000000000L, x0); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x8000000000000000L, x0); START(); __ Mov(w0, 0xffff0000); @@ -933,8 +943,8 @@ TEST(bics) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0x00000000, x0); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0x00000000, x0); TEARDOWN(); } @@ -962,16 +972,16 @@ TEST(eor) { RUN(); - ASSERT_EQUAL_64(0xf000ff0f, x2); - ASSERT_EQUAL_64(0x0000f000, x3); - ASSERT_EQUAL_64(0x0000000f0000f000L, x4); - ASSERT_EQUAL_64(0x7800ff8f, x5); - ASSERT_EQUAL_64(0xffff00f0, x6); - ASSERT_EQUAL_64(0x0000f0f0, x7); - ASSERT_EQUAL_64(0x0000f00f, x8); - ASSERT_EQUAL_64(0x00000ff00000ffffL, x9); - ASSERT_EQUAL_64(0xff0000f0, x10); - ASSERT_EQUAL_64(0xff00ff00ff0000f0L, x11); + CHECK_EQUAL_64(0xf000ff0f, x2); + CHECK_EQUAL_64(0x0000f000, x3); + CHECK_EQUAL_64(0x0000000f0000f000L, x4); + CHECK_EQUAL_64(0x7800ff8f, x5); + CHECK_EQUAL_64(0xffff00f0, x6); + CHECK_EQUAL_64(0x0000f0f0, x7); + CHECK_EQUAL_64(0x0000f00f, x8); + CHECK_EQUAL_64(0x00000ff00000ffffL, x9); + CHECK_EQUAL_64(0xff0000f0, x10); + CHECK_EQUAL_64(0xff00ff00ff0000f0L, x11); TEARDOWN(); } @@ -996,14 +1006,14 @@ TEST(eor_extend) { RUN(); - ASSERT_EQUAL_64(0x11111190, x6); - ASSERT_EQUAL_64(0x1111111111101013UL, x7); - ASSERT_EQUAL_64(0x11131315, x8); - ASSERT_EQUAL_64(0x1111111511151519UL, x9); - ASSERT_EQUAL_64(0xeeeeee90, x10); - ASSERT_EQUAL_64(0xeeeeeeeeeeee1013UL, x11); - ASSERT_EQUAL_64(0xeeeeeeef11131315UL, x12); - ASSERT_EQUAL_64(0x1111111511151519UL, x13); + CHECK_EQUAL_64(0x11111190, x6); + CHECK_EQUAL_64(0x1111111111101013UL, x7); + CHECK_EQUAL_64(0x11131315, x8); + CHECK_EQUAL_64(0x1111111511151519UL, x9); + CHECK_EQUAL_64(0xeeeeee90, x10); + CHECK_EQUAL_64(0xeeeeeeeeeeee1013UL, x11); + CHECK_EQUAL_64(0xeeeeeeef11131315UL, x12); + CHECK_EQUAL_64(0x1111111511151519UL, x13); TEARDOWN(); } @@ -1031,16 +1041,16 @@ TEST(eon) { RUN(); - ASSERT_EQUAL_64(0xffffffff0fff00f0L, x2); - ASSERT_EQUAL_64(0xffff0fff, x3); - ASSERT_EQUAL_64(0xfffffff0ffff0fffL, x4); - ASSERT_EQUAL_64(0xffffffff87ff0070L, x5); - ASSERT_EQUAL_64(0x0000ff0f, x6); - ASSERT_EQUAL_64(0xffffffffffff0f0fL, x7); - ASSERT_EQUAL_64(0xffff0ff0, x8); - ASSERT_EQUAL_64(0xfffff00fffff0000L, x9); - ASSERT_EQUAL_64(0xfc3f03cf, x10); - ASSERT_EQUAL_64(0xffffefffffff100fL, x11); + CHECK_EQUAL_64(0xffffffff0fff00f0L, x2); + CHECK_EQUAL_64(0xffff0fff, x3); + CHECK_EQUAL_64(0xfffffff0ffff0fffL, x4); + CHECK_EQUAL_64(0xffffffff87ff0070L, x5); + CHECK_EQUAL_64(0x0000ff0f, x6); + CHECK_EQUAL_64(0xffffffffffff0f0fL, x7); + CHECK_EQUAL_64(0xffff0ff0, x8); + CHECK_EQUAL_64(0xfffff00fffff0000L, x9); + CHECK_EQUAL_64(0xfc3f03cf, x10); + CHECK_EQUAL_64(0xffffefffffff100fL, x11); TEARDOWN(); } @@ -1065,14 +1075,14 @@ TEST(eon_extend) { RUN(); - ASSERT_EQUAL_64(0xeeeeee6f, x6); - ASSERT_EQUAL_64(0xeeeeeeeeeeefefecUL, x7); - ASSERT_EQUAL_64(0xeeececea, x8); - ASSERT_EQUAL_64(0xeeeeeeeaeeeaeae6UL, x9); - ASSERT_EQUAL_64(0x1111116f, x10); - ASSERT_EQUAL_64(0x111111111111efecUL, x11); - ASSERT_EQUAL_64(0x11111110eeececeaUL, x12); - ASSERT_EQUAL_64(0xeeeeeeeaeeeaeae6UL, x13); + CHECK_EQUAL_64(0xeeeeee6f, x6); + CHECK_EQUAL_64(0xeeeeeeeeeeefefecUL, x7); + CHECK_EQUAL_64(0xeeececea, x8); + CHECK_EQUAL_64(0xeeeeeeeaeeeaeae6UL, x9); + CHECK_EQUAL_64(0x1111116f, x10); + CHECK_EQUAL_64(0x111111111111efecUL, x11); + CHECK_EQUAL_64(0x11111110eeececeaUL, x12); + CHECK_EQUAL_64(0xeeeeeeeaeeeaeae6UL, x13); TEARDOWN(); } @@ -1111,25 +1121,25 @@ TEST(mul) { RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(0, x1); - ASSERT_EQUAL_64(0xffffffff, x2); - ASSERT_EQUAL_64(1, x3); - ASSERT_EQUAL_64(0, x4); - ASSERT_EQUAL_64(0xffffffff, x5); - ASSERT_EQUAL_64(0xffffffff00000001UL, x6); - ASSERT_EQUAL_64(1, x7); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(1, x10); - ASSERT_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0, x12); - ASSERT_EQUAL_64(1, x13); - ASSERT_EQUAL_64(0xffffffff, x14); - ASSERT_EQUAL_64(0, x20); - ASSERT_EQUAL_64(0xffffffff00000001UL, x21); - ASSERT_EQUAL_64(0xffffffff, x22); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x23); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(0, x1); + CHECK_EQUAL_64(0xffffffff, x2); + CHECK_EQUAL_64(1, x3); + CHECK_EQUAL_64(0, x4); + CHECK_EQUAL_64(0xffffffff, x5); + CHECK_EQUAL_64(0xffffffff00000001UL, x6); + CHECK_EQUAL_64(1, x7); + CHECK_EQUAL_64(0xffffffffffffffffUL, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(1, x10); + CHECK_EQUAL_64(0, x11); + CHECK_EQUAL_64(0, x12); + CHECK_EQUAL_64(1, x13); + CHECK_EQUAL_64(0xffffffff, x14); + CHECK_EQUAL_64(0, x20); + CHECK_EQUAL_64(0xffffffff00000001UL, x21); + CHECK_EQUAL_64(0xffffffff, x22); + CHECK_EQUAL_64(0xffffffffffffffffUL, x23); TEARDOWN(); } @@ -1143,7 +1153,7 @@ static void SmullHelper(int64_t expected, int64_t a, int64_t b) { __ Smull(x2, w0, w1); END(); RUN(); - ASSERT_EQUAL_64(expected, x2); + CHECK_EQUAL_64(expected, x2); TEARDOWN(); } @@ -1199,31 +1209,31 @@ TEST(madd) { RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(0xffffffff, x2); - ASSERT_EQUAL_64(0xffffffff, x3); - ASSERT_EQUAL_64(1, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0, x6); - ASSERT_EQUAL_64(0xffffffff, x7); - ASSERT_EQUAL_64(0xfffffffe, x8); - ASSERT_EQUAL_64(2, x9); - ASSERT_EQUAL_64(0, x10); - ASSERT_EQUAL_64(0, x11); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(0xffffffff, x2); + CHECK_EQUAL_64(0xffffffff, x3); + CHECK_EQUAL_64(1, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0, x6); + CHECK_EQUAL_64(0xffffffff, x7); + CHECK_EQUAL_64(0xfffffffe, x8); + CHECK_EQUAL_64(2, x9); + CHECK_EQUAL_64(0, x10); + CHECK_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0, x12); - ASSERT_EQUAL_64(1, x13); - ASSERT_EQUAL_64(0xffffffff, x14); - ASSERT_EQUAL_64(0xffffffffffffffff, x15); - ASSERT_EQUAL_64(1, x20); - ASSERT_EQUAL_64(0x100000000UL, x21); - ASSERT_EQUAL_64(0, x22); - ASSERT_EQUAL_64(0xffffffff, x23); - ASSERT_EQUAL_64(0x1fffffffe, x24); - ASSERT_EQUAL_64(0xfffffffe00000002UL, x25); - ASSERT_EQUAL_64(0, x26); - ASSERT_EQUAL_64(0, x27); + CHECK_EQUAL_64(0, x12); + CHECK_EQUAL_64(1, x13); + CHECK_EQUAL_64(0xffffffff, x14); + CHECK_EQUAL_64(0xffffffffffffffff, x15); + CHECK_EQUAL_64(1, x20); + CHECK_EQUAL_64(0x100000000UL, x21); + CHECK_EQUAL_64(0, x22); + CHECK_EQUAL_64(0xffffffff, x23); + CHECK_EQUAL_64(0x1fffffffe, x24); + CHECK_EQUAL_64(0xfffffffe00000002UL, x25); + CHECK_EQUAL_64(0, x26); + CHECK_EQUAL_64(0, x27); TEARDOWN(); } @@ -1269,31 +1279,31 @@ TEST(msub) { RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(0xffffffff, x2); - ASSERT_EQUAL_64(0xffffffff, x3); - ASSERT_EQUAL_64(1, x4); - ASSERT_EQUAL_64(0xfffffffe, x5); - ASSERT_EQUAL_64(0xfffffffe, x6); - ASSERT_EQUAL_64(1, x7); - ASSERT_EQUAL_64(0, x8); - ASSERT_EQUAL_64(0, x9); - ASSERT_EQUAL_64(0xfffffffe, x10); - ASSERT_EQUAL_64(0xfffffffe, x11); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(0xffffffff, x2); + CHECK_EQUAL_64(0xffffffff, x3); + CHECK_EQUAL_64(1, x4); + CHECK_EQUAL_64(0xfffffffe, x5); + CHECK_EQUAL_64(0xfffffffe, x6); + CHECK_EQUAL_64(1, x7); + CHECK_EQUAL_64(0, x8); + CHECK_EQUAL_64(0, x9); + CHECK_EQUAL_64(0xfffffffe, x10); + CHECK_EQUAL_64(0xfffffffe, x11); - ASSERT_EQUAL_64(0, x12); - ASSERT_EQUAL_64(1, x13); - ASSERT_EQUAL_64(0xffffffff, x14); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x15); - ASSERT_EQUAL_64(1, x20); - ASSERT_EQUAL_64(0xfffffffeUL, x21); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x22); - ASSERT_EQUAL_64(0xffffffff00000001UL, x23); - ASSERT_EQUAL_64(0, x24); - ASSERT_EQUAL_64(0x200000000UL, x25); - ASSERT_EQUAL_64(0x1fffffffeUL, x26); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x27); + CHECK_EQUAL_64(0, x12); + CHECK_EQUAL_64(1, x13); + CHECK_EQUAL_64(0xffffffff, x14); + CHECK_EQUAL_64(0xffffffffffffffffUL, x15); + CHECK_EQUAL_64(1, x20); + CHECK_EQUAL_64(0xfffffffeUL, x21); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x22); + CHECK_EQUAL_64(0xffffffff00000001UL, x23); + CHECK_EQUAL_64(0, x24); + CHECK_EQUAL_64(0x200000000UL, x25); + CHECK_EQUAL_64(0x1fffffffeUL, x26); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x27); TEARDOWN(); } @@ -1331,18 +1341,18 @@ TEST(smulh) { RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(0, x1); - ASSERT_EQUAL_64(0, x2); - ASSERT_EQUAL_64(0x01234567, x3); - ASSERT_EQUAL_64(0x02468acf, x4); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x5); - ASSERT_EQUAL_64(0x4000000000000000UL, x6); - ASSERT_EQUAL_64(0, x7); - ASSERT_EQUAL_64(0, x8); - ASSERT_EQUAL_64(0x1c71c71c71c71c71UL, x9); - ASSERT_EQUAL_64(0xe38e38e38e38e38eUL, x10); - ASSERT_EQUAL_64(0x1c71c71c71c71c72UL, x11); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(0, x1); + CHECK_EQUAL_64(0, x2); + CHECK_EQUAL_64(0x01234567, x3); + CHECK_EQUAL_64(0x02468acf, x4); + CHECK_EQUAL_64(0xffffffffffffffffUL, x5); + CHECK_EQUAL_64(0x4000000000000000UL, x6); + CHECK_EQUAL_64(0, x7); + CHECK_EQUAL_64(0, x8); + CHECK_EQUAL_64(0x1c71c71c71c71c71UL, x9); + CHECK_EQUAL_64(0xe38e38e38e38e38eUL, x10); + CHECK_EQUAL_64(0x1c71c71c71c71c72UL, x11); TEARDOWN(); } @@ -1371,14 +1381,14 @@ TEST(smaddl_umaddl) { RUN(); - ASSERT_EQUAL_64(3, x9); - ASSERT_EQUAL_64(5, x10); - ASSERT_EQUAL_64(5, x11); - ASSERT_EQUAL_64(0x200000001UL, x12); - ASSERT_EQUAL_64(0x100000003UL, x13); - ASSERT_EQUAL_64(0xfffffffe00000005UL, x14); - ASSERT_EQUAL_64(0xfffffffe00000005UL, x15); - ASSERT_EQUAL_64(0x1, x22); + CHECK_EQUAL_64(3, x9); + CHECK_EQUAL_64(5, x10); + CHECK_EQUAL_64(5, x11); + CHECK_EQUAL_64(0x200000001UL, x12); + CHECK_EQUAL_64(0x100000003UL, x13); + CHECK_EQUAL_64(0xfffffffe00000005UL, x14); + CHECK_EQUAL_64(0xfffffffe00000005UL, x15); + CHECK_EQUAL_64(0x1, x22); TEARDOWN(); } @@ -1407,14 +1417,14 @@ TEST(smsubl_umsubl) { RUN(); - ASSERT_EQUAL_64(5, x9); - ASSERT_EQUAL_64(3, x10); - ASSERT_EQUAL_64(3, x11); - ASSERT_EQUAL_64(0x1ffffffffUL, x12); - ASSERT_EQUAL_64(0xffffffff00000005UL, x13); - ASSERT_EQUAL_64(0x200000003UL, x14); - ASSERT_EQUAL_64(0x200000003UL, x15); - ASSERT_EQUAL_64(0x3ffffffffUL, x22); + CHECK_EQUAL_64(5, x9); + CHECK_EQUAL_64(3, x10); + CHECK_EQUAL_64(3, x11); + CHECK_EQUAL_64(0x1ffffffffUL, x12); + CHECK_EQUAL_64(0xffffffff00000005UL, x13); + CHECK_EQUAL_64(0x200000003UL, x14); + CHECK_EQUAL_64(0x200000003UL, x15); + CHECK_EQUAL_64(0x3ffffffffUL, x22); TEARDOWN(); } @@ -1470,34 +1480,34 @@ TEST(div) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(0xffffffff, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0xffffffff, x3); - ASSERT_EQUAL_64(1, x4); - ASSERT_EQUAL_64(1, x5); - ASSERT_EQUAL_64(0, x6); - ASSERT_EQUAL_64(1, x7); - ASSERT_EQUAL_64(0, x8); - ASSERT_EQUAL_64(0xffffffff00000001UL, x9); - ASSERT_EQUAL_64(0x40000000, x10); - ASSERT_EQUAL_64(0xC0000000, x11); - ASSERT_EQUAL_64(0x40000000, x12); - ASSERT_EQUAL_64(0x40000000, x13); - ASSERT_EQUAL_64(0x4000000000000000UL, x14); - ASSERT_EQUAL_64(0xC000000000000000UL, x15); - ASSERT_EQUAL_64(0, x22); - ASSERT_EQUAL_64(0x80000000, x23); - ASSERT_EQUAL_64(0, x24); - ASSERT_EQUAL_64(0x8000000000000000UL, x25); - ASSERT_EQUAL_64(0, x26); - ASSERT_EQUAL_64(0, x27); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x28); - ASSERT_EQUAL_64(0, x29); - ASSERT_EQUAL_64(0, x18); - ASSERT_EQUAL_64(0, x19); - ASSERT_EQUAL_64(0, x20); - ASSERT_EQUAL_64(0, x21); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(0xffffffff, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0xffffffff, x3); + CHECK_EQUAL_64(1, x4); + CHECK_EQUAL_64(1, x5); + CHECK_EQUAL_64(0, x6); + CHECK_EQUAL_64(1, x7); + CHECK_EQUAL_64(0, x8); + CHECK_EQUAL_64(0xffffffff00000001UL, x9); + CHECK_EQUAL_64(0x40000000, x10); + CHECK_EQUAL_64(0xC0000000, x11); + CHECK_EQUAL_64(0x40000000, x12); + CHECK_EQUAL_64(0x40000000, x13); + CHECK_EQUAL_64(0x4000000000000000UL, x14); + CHECK_EQUAL_64(0xC000000000000000UL, x15); + CHECK_EQUAL_64(0, x22); + CHECK_EQUAL_64(0x80000000, x23); + CHECK_EQUAL_64(0, x24); + CHECK_EQUAL_64(0x8000000000000000UL, x25); + CHECK_EQUAL_64(0, x26); + CHECK_EQUAL_64(0, x27); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x28); + CHECK_EQUAL_64(0, x29); + CHECK_EQUAL_64(0, x18); + CHECK_EQUAL_64(0, x19); + CHECK_EQUAL_64(0, x20); + CHECK_EQUAL_64(0, x21); TEARDOWN(); } @@ -1520,13 +1530,13 @@ TEST(rbit_rev) { RUN(); - ASSERT_EQUAL_64(0x084c2a6e, x0); - ASSERT_EQUAL_64(0x084c2a6e195d3b7fUL, x1); - ASSERT_EQUAL_64(0x54761032, x2); - ASSERT_EQUAL_64(0xdcfe98ba54761032UL, x3); - ASSERT_EQUAL_64(0x10325476, x4); - ASSERT_EQUAL_64(0x98badcfe10325476UL, x5); - ASSERT_EQUAL_64(0x1032547698badcfeUL, x6); + CHECK_EQUAL_64(0x084c2a6e, x0); + CHECK_EQUAL_64(0x084c2a6e195d3b7fUL, x1); + CHECK_EQUAL_64(0x54761032, x2); + CHECK_EQUAL_64(0xdcfe98ba54761032UL, x3); + CHECK_EQUAL_64(0x10325476, x4); + CHECK_EQUAL_64(0x98badcfe10325476UL, x5); + CHECK_EQUAL_64(0x1032547698badcfeUL, x6); TEARDOWN(); } @@ -1556,18 +1566,18 @@ TEST(clz_cls) { RUN(); - ASSERT_EQUAL_64(8, x0); - ASSERT_EQUAL_64(12, x1); - ASSERT_EQUAL_64(0, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(32, x4); - ASSERT_EQUAL_64(64, x5); - ASSERT_EQUAL_64(7, x6); - ASSERT_EQUAL_64(11, x7); - ASSERT_EQUAL_64(12, x8); - ASSERT_EQUAL_64(8, x9); - ASSERT_EQUAL_64(31, x10); - ASSERT_EQUAL_64(63, x11); + CHECK_EQUAL_64(8, x0); + CHECK_EQUAL_64(12, x1); + CHECK_EQUAL_64(0, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(32, x4); + CHECK_EQUAL_64(64, x5); + CHECK_EQUAL_64(7, x6); + CHECK_EQUAL_64(11, x7); + CHECK_EQUAL_64(12, x8); + CHECK_EQUAL_64(8, x9); + CHECK_EQUAL_64(31, x10); + CHECK_EQUAL_64(63, x11); TEARDOWN(); } @@ -1605,8 +1615,8 @@ TEST(label) { RUN(); - ASSERT_EQUAL_64(0x1, x0); - ASSERT_EQUAL_64(0x1, x1); + CHECK_EQUAL_64(0x1, x0); + CHECK_EQUAL_64(0x1, x1); TEARDOWN(); } @@ -1639,7 +1649,7 @@ TEST(branch_at_start) { RUN(); - ASSERT_EQUAL_64(0x1, x0); + CHECK_EQUAL_64(0x1, x0); TEARDOWN(); } @@ -1683,8 +1693,8 @@ TEST(adr) { RUN(); - ASSERT_EQUAL_64(0x0, x0); - ASSERT_EQUAL_64(0x0, x1); + CHECK_EQUAL_64(0x0, x0); + CHECK_EQUAL_64(0x0, x1); TEARDOWN(); } @@ -1749,7 +1759,7 @@ TEST(adr_far) { RUN(); - ASSERT_EQUAL_64(0xf, x0); + CHECK_EQUAL_64(0xf, x0); TEARDOWN(); } @@ -1839,7 +1849,7 @@ TEST(branch_cond) { RUN(); - ASSERT_EQUAL_64(0x1, x0); + CHECK_EQUAL_64(0x1, x0); TEARDOWN(); } @@ -1886,9 +1896,9 @@ TEST(branch_to_reg) { RUN(); - ASSERT_EQUAL_64(core.xreg(3) + kInstructionSize, x0); - ASSERT_EQUAL_64(42, x1); - ASSERT_EQUAL_64(84, x2); + CHECK_EQUAL_64(core.xreg(3) + kInstructionSize, x0); + CHECK_EQUAL_64(42, x1); + CHECK_EQUAL_64(84, x2); TEARDOWN(); } @@ -1956,12 +1966,12 @@ TEST(compare_branch) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(0, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(1, x4); - ASSERT_EQUAL_64(0, x5); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(0, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(1, x4); + CHECK_EQUAL_64(0, x5); TEARDOWN(); } @@ -2009,10 +2019,10 @@ TEST(test_branch) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(0, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0, x3); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(0, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0, x3); TEARDOWN(); } @@ -2085,8 +2095,8 @@ TEST(far_branch_backward) { RUN(); - ASSERT_EQUAL_64(0x7, x0); - ASSERT_EQUAL_64(0x1, x1); + CHECK_EQUAL_64(0x7, x0); + CHECK_EQUAL_64(0x1, x1); TEARDOWN(); } @@ -2155,8 +2165,8 @@ TEST(far_branch_simple_veneer) { RUN(); - ASSERT_EQUAL_64(0x7, x0); - ASSERT_EQUAL_64(0x1, x1); + CHECK_EQUAL_64(0x7, x0); + CHECK_EQUAL_64(0x1, x1); TEARDOWN(); } @@ -2250,8 +2260,8 @@ TEST(far_branch_veneer_link_chain) { RUN(); - ASSERT_EQUAL_64(0x7, x0); - ASSERT_EQUAL_64(0x1, x1); + CHECK_EQUAL_64(0x7, x0); + CHECK_EQUAL_64(0x1, x1); TEARDOWN(); } @@ -2340,8 +2350,8 @@ TEST(far_branch_veneer_broken_link_chain) { RUN(); - ASSERT_EQUAL_64(0x3, x0); - ASSERT_EQUAL_64(0x1, x1); + CHECK_EQUAL_64(0x3, x0); + CHECK_EQUAL_64(0x1, x1); TEARDOWN(); } @@ -2398,7 +2408,7 @@ TEST(branch_type) { RUN(); - ASSERT_EQUAL_64(0x0, x0); + CHECK_EQUAL_64(0x0, x0); TEARDOWN(); } @@ -2430,18 +2440,18 @@ TEST(ldr_str_offset) { RUN(); - ASSERT_EQUAL_64(0x76543210, x0); - ASSERT_EQUAL_64(0x76543210, dst[0]); - ASSERT_EQUAL_64(0xfedcba98, x1); - ASSERT_EQUAL_64(0xfedcba9800000000UL, dst[1]); - ASSERT_EQUAL_64(0x0123456789abcdefUL, x2); - ASSERT_EQUAL_64(0x0123456789abcdefUL, dst[2]); - ASSERT_EQUAL_64(0x32, x3); - ASSERT_EQUAL_64(0x3200, dst[3]); - ASSERT_EQUAL_64(0x7654, x4); - ASSERT_EQUAL_64(0x765400, dst[4]); - ASSERT_EQUAL_64(src_base, x17); - ASSERT_EQUAL_64(dst_base, x18); + CHECK_EQUAL_64(0x76543210, x0); + CHECK_EQUAL_64(0x76543210, dst[0]); + CHECK_EQUAL_64(0xfedcba98, x1); + CHECK_EQUAL_64(0xfedcba9800000000UL, dst[1]); + CHECK_EQUAL_64(0x0123456789abcdefUL, x2); + CHECK_EQUAL_64(0x0123456789abcdefUL, dst[2]); + CHECK_EQUAL_64(0x32, x3); + CHECK_EQUAL_64(0x3200, dst[3]); + CHECK_EQUAL_64(0x7654, x4); + CHECK_EQUAL_64(0x765400, dst[4]); + CHECK_EQUAL_64(src_base, x17); + CHECK_EQUAL_64(dst_base, x18); TEARDOWN(); } @@ -2479,18 +2489,18 @@ TEST(ldr_str_wide) { RUN(); - ASSERT_EQUAL_32(8191, w0); - ASSERT_EQUAL_32(8191, dst[8191]); - ASSERT_EQUAL_64(src_base, x22); - ASSERT_EQUAL_64(dst_base, x23); - ASSERT_EQUAL_32(0, w1); - ASSERT_EQUAL_32(0, dst[0]); - ASSERT_EQUAL_64(src_base + 4096 * sizeof(src[0]), x24); - ASSERT_EQUAL_64(dst_base + 4096 * sizeof(dst[0]), x25); - ASSERT_EQUAL_32(6144, w2); - ASSERT_EQUAL_32(6144, dst[6144]); - ASSERT_EQUAL_64(src_base + 6144 * sizeof(src[0]), x26); - ASSERT_EQUAL_64(dst_base + 6144 * sizeof(dst[0]), x27); + CHECK_EQUAL_32(8191, w0); + CHECK_EQUAL_32(8191, dst[8191]); + CHECK_EQUAL_64(src_base, x22); + CHECK_EQUAL_64(dst_base, x23); + CHECK_EQUAL_32(0, w1); + CHECK_EQUAL_32(0, dst[0]); + CHECK_EQUAL_64(src_base + 4096 * sizeof(src[0]), x24); + CHECK_EQUAL_64(dst_base + 4096 * sizeof(dst[0]), x25); + CHECK_EQUAL_32(6144, w2); + CHECK_EQUAL_32(6144, dst[6144]); + CHECK_EQUAL_64(src_base + 6144 * sizeof(src[0]), x26); + CHECK_EQUAL_64(dst_base + 6144 * sizeof(dst[0]), x27); TEARDOWN(); } @@ -2530,26 +2540,26 @@ TEST(ldr_str_preindex) { RUN(); - ASSERT_EQUAL_64(0xfedcba98, x0); - ASSERT_EQUAL_64(0xfedcba9800000000UL, dst[1]); - ASSERT_EQUAL_64(0x0123456789abcdefUL, x1); - ASSERT_EQUAL_64(0x0123456789abcdefUL, dst[2]); - ASSERT_EQUAL_64(0x01234567, x2); - ASSERT_EQUAL_64(0x0123456700000000UL, dst[4]); - ASSERT_EQUAL_64(0x32, x3); - ASSERT_EQUAL_64(0x3200, dst[3]); - ASSERT_EQUAL_64(0x9876, x4); - ASSERT_EQUAL_64(0x987600, dst[5]); - ASSERT_EQUAL_64(src_base + 4, x17); - ASSERT_EQUAL_64(dst_base + 12, x18); - ASSERT_EQUAL_64(src_base + 8, x19); - ASSERT_EQUAL_64(dst_base + 16, x20); - ASSERT_EQUAL_64(src_base + 12, x21); - ASSERT_EQUAL_64(dst_base + 36, x22); - ASSERT_EQUAL_64(src_base + 1, x23); - ASSERT_EQUAL_64(dst_base + 25, x24); - ASSERT_EQUAL_64(src_base + 3, x25); - ASSERT_EQUAL_64(dst_base + 41, x26); + CHECK_EQUAL_64(0xfedcba98, x0); + CHECK_EQUAL_64(0xfedcba9800000000UL, dst[1]); + CHECK_EQUAL_64(0x0123456789abcdefUL, x1); + CHECK_EQUAL_64(0x0123456789abcdefUL, dst[2]); + CHECK_EQUAL_64(0x01234567, x2); + CHECK_EQUAL_64(0x0123456700000000UL, dst[4]); + CHECK_EQUAL_64(0x32, x3); + CHECK_EQUAL_64(0x3200, dst[3]); + CHECK_EQUAL_64(0x9876, x4); + CHECK_EQUAL_64(0x987600, dst[5]); + CHECK_EQUAL_64(src_base + 4, x17); + CHECK_EQUAL_64(dst_base + 12, x18); + CHECK_EQUAL_64(src_base + 8, x19); + CHECK_EQUAL_64(dst_base + 16, x20); + CHECK_EQUAL_64(src_base + 12, x21); + CHECK_EQUAL_64(dst_base + 36, x22); + CHECK_EQUAL_64(src_base + 1, x23); + CHECK_EQUAL_64(dst_base + 25, x24); + CHECK_EQUAL_64(src_base + 3, x25); + CHECK_EQUAL_64(dst_base + 41, x26); TEARDOWN(); } @@ -2589,26 +2599,26 @@ TEST(ldr_str_postindex) { RUN(); - ASSERT_EQUAL_64(0xfedcba98, x0); - ASSERT_EQUAL_64(0xfedcba9800000000UL, dst[1]); - ASSERT_EQUAL_64(0x0123456789abcdefUL, x1); - ASSERT_EQUAL_64(0x0123456789abcdefUL, dst[2]); - ASSERT_EQUAL_64(0x0123456789abcdefUL, x2); - ASSERT_EQUAL_64(0x0123456789abcdefUL, dst[4]); - ASSERT_EQUAL_64(0x32, x3); - ASSERT_EQUAL_64(0x3200, dst[3]); - ASSERT_EQUAL_64(0x9876, x4); - ASSERT_EQUAL_64(0x987600, dst[5]); - ASSERT_EQUAL_64(src_base + 8, x17); - ASSERT_EQUAL_64(dst_base + 24, x18); - ASSERT_EQUAL_64(src_base + 16, x19); - ASSERT_EQUAL_64(dst_base + 32, x20); - ASSERT_EQUAL_64(src_base, x21); - ASSERT_EQUAL_64(dst_base, x22); - ASSERT_EQUAL_64(src_base + 2, x23); - ASSERT_EQUAL_64(dst_base + 30, x24); - ASSERT_EQUAL_64(src_base, x25); - ASSERT_EQUAL_64(dst_base, x26); + CHECK_EQUAL_64(0xfedcba98, x0); + CHECK_EQUAL_64(0xfedcba9800000000UL, dst[1]); + CHECK_EQUAL_64(0x0123456789abcdefUL, x1); + CHECK_EQUAL_64(0x0123456789abcdefUL, dst[2]); + CHECK_EQUAL_64(0x0123456789abcdefUL, x2); + CHECK_EQUAL_64(0x0123456789abcdefUL, dst[4]); + CHECK_EQUAL_64(0x32, x3); + CHECK_EQUAL_64(0x3200, dst[3]); + CHECK_EQUAL_64(0x9876, x4); + CHECK_EQUAL_64(0x987600, dst[5]); + CHECK_EQUAL_64(src_base + 8, x17); + CHECK_EQUAL_64(dst_base + 24, x18); + CHECK_EQUAL_64(src_base + 16, x19); + CHECK_EQUAL_64(dst_base + 32, x20); + CHECK_EQUAL_64(src_base, x21); + CHECK_EQUAL_64(dst_base, x22); + CHECK_EQUAL_64(src_base + 2, x23); + CHECK_EQUAL_64(dst_base + 30, x24); + CHECK_EQUAL_64(src_base, x25); + CHECK_EQUAL_64(dst_base, x26); TEARDOWN(); } @@ -2637,16 +2647,16 @@ TEST(load_signed) { RUN(); - ASSERT_EQUAL_64(0xffffff80, x0); - ASSERT_EQUAL_64(0x0000007f, x1); - ASSERT_EQUAL_64(0xffff8080, x2); - ASSERT_EQUAL_64(0x00007f7f, x3); - ASSERT_EQUAL_64(0xffffffffffffff80UL, x4); - ASSERT_EQUAL_64(0x000000000000007fUL, x5); - ASSERT_EQUAL_64(0xffffffffffff8080UL, x6); - ASSERT_EQUAL_64(0x0000000000007f7fUL, x7); - ASSERT_EQUAL_64(0xffffffff80008080UL, x8); - ASSERT_EQUAL_64(0x000000007fff7f7fUL, x9); + CHECK_EQUAL_64(0xffffff80, x0); + CHECK_EQUAL_64(0x0000007f, x1); + CHECK_EQUAL_64(0xffff8080, x2); + CHECK_EQUAL_64(0x00007f7f, x3); + CHECK_EQUAL_64(0xffffffffffffff80UL, x4); + CHECK_EQUAL_64(0x000000000000007fUL, x5); + CHECK_EQUAL_64(0xffffffffffff8080UL, x6); + CHECK_EQUAL_64(0x0000000000007f7fUL, x7); + CHECK_EQUAL_64(0xffffffff80008080UL, x8); + CHECK_EQUAL_64(0x000000007fff7f7fUL, x9); TEARDOWN(); } @@ -2686,15 +2696,15 @@ TEST(load_store_regoffset) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(0x0000000300000002UL, x1); - ASSERT_EQUAL_64(3, x2); - ASSERT_EQUAL_64(3, x3); - ASSERT_EQUAL_64(2, x4); - ASSERT_EQUAL_32(1, dst[0]); - ASSERT_EQUAL_32(2, dst[1]); - ASSERT_EQUAL_32(3, dst[2]); - ASSERT_EQUAL_32(3, dst[3]); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(0x0000000300000002UL, x1); + CHECK_EQUAL_64(3, x2); + CHECK_EQUAL_64(3, x3); + CHECK_EQUAL_64(2, x4); + CHECK_EQUAL_32(1, dst[0]); + CHECK_EQUAL_32(2, dst[1]); + CHECK_EQUAL_32(3, dst[2]); + CHECK_EQUAL_32(3, dst[3]); TEARDOWN(); } @@ -2726,18 +2736,18 @@ TEST(load_store_float) { RUN(); - ASSERT_EQUAL_FP32(2.0, s0); - ASSERT_EQUAL_FP32(2.0, dst[0]); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(1.0, dst[2]); - ASSERT_EQUAL_FP32(3.0, s2); - ASSERT_EQUAL_FP32(3.0, dst[1]); - ASSERT_EQUAL_64(src_base, x17); - ASSERT_EQUAL_64(dst_base + sizeof(dst[0]), x18); - ASSERT_EQUAL_64(src_base + sizeof(src[0]), x19); - ASSERT_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); - ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); - ASSERT_EQUAL_64(dst_base, x22); + CHECK_EQUAL_FP32(2.0, s0); + CHECK_EQUAL_FP32(2.0, dst[0]); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(1.0, dst[2]); + CHECK_EQUAL_FP32(3.0, s2); + CHECK_EQUAL_FP32(3.0, dst[1]); + CHECK_EQUAL_64(src_base, x17); + CHECK_EQUAL_64(dst_base + sizeof(dst[0]), x18); + CHECK_EQUAL_64(src_base + sizeof(src[0]), x19); + CHECK_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); + CHECK_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); + CHECK_EQUAL_64(dst_base, x22); TEARDOWN(); } @@ -2769,18 +2779,18 @@ TEST(load_store_double) { RUN(); - ASSERT_EQUAL_FP64(2.0, d0); - ASSERT_EQUAL_FP64(2.0, dst[0]); - ASSERT_EQUAL_FP64(1.0, d1); - ASSERT_EQUAL_FP64(1.0, dst[2]); - ASSERT_EQUAL_FP64(3.0, d2); - ASSERT_EQUAL_FP64(3.0, dst[1]); - ASSERT_EQUAL_64(src_base, x17); - ASSERT_EQUAL_64(dst_base + sizeof(dst[0]), x18); - ASSERT_EQUAL_64(src_base + sizeof(src[0]), x19); - ASSERT_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); - ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); - ASSERT_EQUAL_64(dst_base, x22); + CHECK_EQUAL_FP64(2.0, d0); + CHECK_EQUAL_FP64(2.0, dst[0]); + CHECK_EQUAL_FP64(1.0, d1); + CHECK_EQUAL_FP64(1.0, dst[2]); + CHECK_EQUAL_FP64(3.0, d2); + CHECK_EQUAL_FP64(3.0, dst[1]); + CHECK_EQUAL_64(src_base, x17); + CHECK_EQUAL_64(dst_base + sizeof(dst[0]), x18); + CHECK_EQUAL_64(src_base + sizeof(src[0]), x19); + CHECK_EQUAL_64(dst_base + 2 * sizeof(dst[0]), x20); + CHECK_EQUAL_64(src_base + 2 * sizeof(src[0]), x21); + CHECK_EQUAL_64(dst_base, x22); TEARDOWN(); } @@ -2804,13 +2814,13 @@ TEST(ldp_stp_float) { RUN(); - ASSERT_EQUAL_FP32(1.0, s31); - ASSERT_EQUAL_FP32(2.0, s0); - ASSERT_EQUAL_FP32(0.0, dst[0]); - ASSERT_EQUAL_FP32(2.0, dst[1]); - ASSERT_EQUAL_FP32(1.0, dst[2]); - ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); - ASSERT_EQUAL_64(dst_base + sizeof(dst[1]), x17); + CHECK_EQUAL_FP32(1.0, s31); + CHECK_EQUAL_FP32(2.0, s0); + CHECK_EQUAL_FP32(0.0, dst[0]); + CHECK_EQUAL_FP32(2.0, dst[1]); + CHECK_EQUAL_FP32(1.0, dst[2]); + CHECK_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); + CHECK_EQUAL_64(dst_base + sizeof(dst[1]), x17); TEARDOWN(); } @@ -2834,13 +2844,13 @@ TEST(ldp_stp_double) { RUN(); - ASSERT_EQUAL_FP64(1.0, d31); - ASSERT_EQUAL_FP64(2.0, d0); - ASSERT_EQUAL_FP64(0.0, dst[0]); - ASSERT_EQUAL_FP64(2.0, dst[1]); - ASSERT_EQUAL_FP64(1.0, dst[2]); - ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); - ASSERT_EQUAL_64(dst_base + sizeof(dst[1]), x17); + CHECK_EQUAL_FP64(1.0, d31); + CHECK_EQUAL_FP64(2.0, d0); + CHECK_EQUAL_FP64(0.0, dst[0]); + CHECK_EQUAL_FP64(2.0, dst[1]); + CHECK_EQUAL_FP64(1.0, dst[2]); + CHECK_EQUAL_64(src_base + 2 * sizeof(src[0]), x16); + CHECK_EQUAL_64(dst_base + sizeof(dst[1]), x17); TEARDOWN(); } @@ -2875,27 +2885,85 @@ TEST(ldp_stp_offset) { RUN(); - ASSERT_EQUAL_64(0x44556677, x0); - ASSERT_EQUAL_64(0x00112233, x1); - ASSERT_EQUAL_64(0x0011223344556677UL, dst[0]); - ASSERT_EQUAL_64(0x00112233, x2); - ASSERT_EQUAL_64(0xccddeeff, x3); - ASSERT_EQUAL_64(0xccddeeff00112233UL, dst[1]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x4); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[2]); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x5); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[3]); - ASSERT_EQUAL_64(0x8899aabb, x6); - ASSERT_EQUAL_64(0xbbaa9988, x7); - ASSERT_EQUAL_64(0xbbaa99888899aabbUL, dst[4]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x8); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[5]); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x9); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[6]); - ASSERT_EQUAL_64(src_base, x16); - ASSERT_EQUAL_64(dst_base, x17); - ASSERT_EQUAL_64(src_base + 24, x18); - ASSERT_EQUAL_64(dst_base + 56, x19); + CHECK_EQUAL_64(0x44556677, x0); + CHECK_EQUAL_64(0x00112233, x1); + CHECK_EQUAL_64(0x0011223344556677UL, dst[0]); + CHECK_EQUAL_64(0x00112233, x2); + CHECK_EQUAL_64(0xccddeeff, x3); + CHECK_EQUAL_64(0xccddeeff00112233UL, dst[1]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x4); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[2]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x5); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[3]); + CHECK_EQUAL_64(0x8899aabb, x6); + CHECK_EQUAL_64(0xbbaa9988, x7); + CHECK_EQUAL_64(0xbbaa99888899aabbUL, dst[4]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x8); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[5]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x9); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[6]); + CHECK_EQUAL_64(src_base, x16); + CHECK_EQUAL_64(dst_base, x17); + CHECK_EQUAL_64(src_base + 24, x18); + CHECK_EQUAL_64(dst_base + 56, x19); + + TEARDOWN(); +} + + +TEST(ldp_stp_offset_wide) { + INIT_V8(); + SETUP(); + + uint64_t src[3] = {0x0011223344556677, 0x8899aabbccddeeff, + 0xffeeddccbbaa9988}; + uint64_t dst[7] = {0, 0, 0, 0, 0, 0, 0}; + uintptr_t src_base = reinterpret_cast<uintptr_t>(src); + uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst); + // Move base too far from the array to force multiple instructions + // to be emitted. + const int64_t base_offset = 1024; + + START(); + __ Mov(x20, src_base - base_offset); + __ Mov(x21, dst_base - base_offset); + __ Mov(x18, src_base + base_offset + 24); + __ Mov(x19, dst_base + base_offset + 56); + __ Ldp(w0, w1, MemOperand(x20, base_offset)); + __ Ldp(w2, w3, MemOperand(x20, base_offset + 4)); + __ Ldp(x4, x5, MemOperand(x20, base_offset + 8)); + __ Ldp(w6, w7, MemOperand(x18, -12 - base_offset)); + __ Ldp(x8, x9, MemOperand(x18, -16 - base_offset)); + __ Stp(w0, w1, MemOperand(x21, base_offset)); + __ Stp(w2, w3, MemOperand(x21, base_offset + 8)); + __ Stp(x4, x5, MemOperand(x21, base_offset + 16)); + __ Stp(w6, w7, MemOperand(x19, -24 - base_offset)); + __ Stp(x8, x9, MemOperand(x19, -16 - base_offset)); + END(); + + RUN(); + + CHECK_EQUAL_64(0x44556677, x0); + CHECK_EQUAL_64(0x00112233, x1); + CHECK_EQUAL_64(0x0011223344556677UL, dst[0]); + CHECK_EQUAL_64(0x00112233, x2); + CHECK_EQUAL_64(0xccddeeff, x3); + CHECK_EQUAL_64(0xccddeeff00112233UL, dst[1]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x4); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[2]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x5); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[3]); + CHECK_EQUAL_64(0x8899aabb, x6); + CHECK_EQUAL_64(0xbbaa9988, x7); + CHECK_EQUAL_64(0xbbaa99888899aabbUL, dst[4]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x8); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[5]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x9); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[6]); + CHECK_EQUAL_64(src_base - base_offset, x20); + CHECK_EQUAL_64(dst_base - base_offset, x21); + CHECK_EQUAL_64(src_base + base_offset + 24, x18); + CHECK_EQUAL_64(dst_base + base_offset + 56, x19); TEARDOWN(); } @@ -2930,27 +2998,27 @@ TEST(ldnp_stnp_offset) { RUN(); - ASSERT_EQUAL_64(0x44556677, x0); - ASSERT_EQUAL_64(0x00112233, x1); - ASSERT_EQUAL_64(0x0011223344556677UL, dst[0]); - ASSERT_EQUAL_64(0x00112233, x2); - ASSERT_EQUAL_64(0xccddeeff, x3); - ASSERT_EQUAL_64(0xccddeeff00112233UL, dst[1]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x4); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[2]); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x5); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[3]); - ASSERT_EQUAL_64(0x8899aabb, x6); - ASSERT_EQUAL_64(0xbbaa9988, x7); - ASSERT_EQUAL_64(0xbbaa99888899aabbUL, dst[4]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x8); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[5]); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x9); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[6]); - ASSERT_EQUAL_64(src_base, x16); - ASSERT_EQUAL_64(dst_base, x17); - ASSERT_EQUAL_64(src_base + 24, x18); - ASSERT_EQUAL_64(dst_base + 56, x19); + CHECK_EQUAL_64(0x44556677, x0); + CHECK_EQUAL_64(0x00112233, x1); + CHECK_EQUAL_64(0x0011223344556677UL, dst[0]); + CHECK_EQUAL_64(0x00112233, x2); + CHECK_EQUAL_64(0xccddeeff, x3); + CHECK_EQUAL_64(0xccddeeff00112233UL, dst[1]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x4); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[2]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x5); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[3]); + CHECK_EQUAL_64(0x8899aabb, x6); + CHECK_EQUAL_64(0xbbaa9988, x7); + CHECK_EQUAL_64(0xbbaa99888899aabbUL, dst[4]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x8); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[5]); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x9); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[6]); + CHECK_EQUAL_64(src_base, x16); + CHECK_EQUAL_64(dst_base, x17); + CHECK_EQUAL_64(src_base + 24, x18); + CHECK_EQUAL_64(dst_base + 56, x19); TEARDOWN(); } @@ -2986,26 +3054,89 @@ TEST(ldp_stp_preindex) { RUN(); - ASSERT_EQUAL_64(0x00112233, x0); - ASSERT_EQUAL_64(0xccddeeff, x1); - ASSERT_EQUAL_64(0x44556677, x2); - ASSERT_EQUAL_64(0x00112233, x3); - ASSERT_EQUAL_64(0xccddeeff00112233UL, dst[0]); - ASSERT_EQUAL_64(0x0000000000112233UL, dst[1]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x4); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x5); - ASSERT_EQUAL_64(0x0011223344556677UL, x6); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x7); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); - ASSERT_EQUAL_64(0x0011223344556677UL, dst[4]); - ASSERT_EQUAL_64(src_base, x16); - ASSERT_EQUAL_64(dst_base, x17); - ASSERT_EQUAL_64(dst_base + 16, x18); - ASSERT_EQUAL_64(src_base + 4, x19); - ASSERT_EQUAL_64(dst_base + 4, x20); - ASSERT_EQUAL_64(src_base + 8, x21); - ASSERT_EQUAL_64(dst_base + 24, x22); + CHECK_EQUAL_64(0x00112233, x0); + CHECK_EQUAL_64(0xccddeeff, x1); + CHECK_EQUAL_64(0x44556677, x2); + CHECK_EQUAL_64(0x00112233, x3); + CHECK_EQUAL_64(0xccddeeff00112233UL, dst[0]); + CHECK_EQUAL_64(0x0000000000112233UL, dst[1]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x4); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x5); + CHECK_EQUAL_64(0x0011223344556677UL, x6); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x7); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); + CHECK_EQUAL_64(0x0011223344556677UL, dst[4]); + CHECK_EQUAL_64(src_base, x16); + CHECK_EQUAL_64(dst_base, x17); + CHECK_EQUAL_64(dst_base + 16, x18); + CHECK_EQUAL_64(src_base + 4, x19); + CHECK_EQUAL_64(dst_base + 4, x20); + CHECK_EQUAL_64(src_base + 8, x21); + CHECK_EQUAL_64(dst_base + 24, x22); + + TEARDOWN(); +} + + +TEST(ldp_stp_preindex_wide) { + INIT_V8(); + SETUP(); + + uint64_t src[3] = {0x0011223344556677, 0x8899aabbccddeeff, + 0xffeeddccbbaa9988}; + uint64_t dst[5] = {0, 0, 0, 0, 0}; + uintptr_t src_base = reinterpret_cast<uintptr_t>(src); + uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst); + // Move base too far from the array to force multiple instructions + // to be emitted. + const int64_t base_offset = 1024; + + START(); + __ Mov(x24, src_base - base_offset); + __ Mov(x25, dst_base + base_offset); + __ Mov(x18, dst_base + base_offset + 16); + __ Ldp(w0, w1, MemOperand(x24, base_offset + 4, PreIndex)); + __ Mov(x19, x24); + __ Mov(x24, src_base - base_offset + 4); + __ Ldp(w2, w3, MemOperand(x24, base_offset - 4, PreIndex)); + __ Stp(w2, w3, MemOperand(x25, 4 - base_offset, PreIndex)); + __ Mov(x20, x25); + __ Mov(x25, dst_base + base_offset + 4); + __ Mov(x24, src_base - base_offset); + __ Stp(w0, w1, MemOperand(x25, -4 - base_offset, PreIndex)); + __ Ldp(x4, x5, MemOperand(x24, base_offset + 8, PreIndex)); + __ Mov(x21, x24); + __ Mov(x24, src_base - base_offset + 8); + __ Ldp(x6, x7, MemOperand(x24, base_offset - 8, PreIndex)); + __ Stp(x7, x6, MemOperand(x18, 8 - base_offset, PreIndex)); + __ Mov(x22, x18); + __ Mov(x18, dst_base + base_offset + 16 + 8); + __ Stp(x5, x4, MemOperand(x18, -8 - base_offset, PreIndex)); + END(); + + RUN(); + + CHECK_EQUAL_64(0x00112233, x0); + CHECK_EQUAL_64(0xccddeeff, x1); + CHECK_EQUAL_64(0x44556677, x2); + CHECK_EQUAL_64(0x00112233, x3); + CHECK_EQUAL_64(0xccddeeff00112233UL, dst[0]); + CHECK_EQUAL_64(0x0000000000112233UL, dst[1]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x4); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x5); + CHECK_EQUAL_64(0x0011223344556677UL, x6); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x7); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); + CHECK_EQUAL_64(0x0011223344556677UL, dst[4]); + CHECK_EQUAL_64(src_base, x24); + CHECK_EQUAL_64(dst_base, x25); + CHECK_EQUAL_64(dst_base + 16, x18); + CHECK_EQUAL_64(src_base + 4, x19); + CHECK_EQUAL_64(dst_base + 4, x20); + CHECK_EQUAL_64(src_base + 8, x21); + CHECK_EQUAL_64(dst_base + 24, x22); TEARDOWN(); } @@ -3041,26 +3172,89 @@ TEST(ldp_stp_postindex) { RUN(); - ASSERT_EQUAL_64(0x44556677, x0); - ASSERT_EQUAL_64(0x00112233, x1); - ASSERT_EQUAL_64(0x00112233, x2); - ASSERT_EQUAL_64(0xccddeeff, x3); - ASSERT_EQUAL_64(0x4455667700112233UL, dst[0]); - ASSERT_EQUAL_64(0x0000000000112233UL, dst[1]); - ASSERT_EQUAL_64(0x0011223344556677UL, x4); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x5); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, x6); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, x7); - ASSERT_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); - ASSERT_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); - ASSERT_EQUAL_64(0x0011223344556677UL, dst[4]); - ASSERT_EQUAL_64(src_base, x16); - ASSERT_EQUAL_64(dst_base, x17); - ASSERT_EQUAL_64(dst_base + 16, x18); - ASSERT_EQUAL_64(src_base + 4, x19); - ASSERT_EQUAL_64(dst_base + 4, x20); - ASSERT_EQUAL_64(src_base + 8, x21); - ASSERT_EQUAL_64(dst_base + 24, x22); + CHECK_EQUAL_64(0x44556677, x0); + CHECK_EQUAL_64(0x00112233, x1); + CHECK_EQUAL_64(0x00112233, x2); + CHECK_EQUAL_64(0xccddeeff, x3); + CHECK_EQUAL_64(0x4455667700112233UL, dst[0]); + CHECK_EQUAL_64(0x0000000000112233UL, dst[1]); + CHECK_EQUAL_64(0x0011223344556677UL, x4); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x5); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x6); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x7); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); + CHECK_EQUAL_64(0x0011223344556677UL, dst[4]); + CHECK_EQUAL_64(src_base, x16); + CHECK_EQUAL_64(dst_base, x17); + CHECK_EQUAL_64(dst_base + 16, x18); + CHECK_EQUAL_64(src_base + 4, x19); + CHECK_EQUAL_64(dst_base + 4, x20); + CHECK_EQUAL_64(src_base + 8, x21); + CHECK_EQUAL_64(dst_base + 24, x22); + + TEARDOWN(); +} + + +TEST(ldp_stp_postindex_wide) { + INIT_V8(); + SETUP(); + + uint64_t src[4] = {0x0011223344556677, 0x8899aabbccddeeff, 0xffeeddccbbaa9988, + 0x7766554433221100}; + uint64_t dst[5] = {0, 0, 0, 0, 0}; + uintptr_t src_base = reinterpret_cast<uintptr_t>(src); + uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst); + // Move base too far from the array to force multiple instructions + // to be emitted. + const int64_t base_offset = 1024; + + START(); + __ Mov(x24, src_base); + __ Mov(x25, dst_base); + __ Mov(x18, dst_base + 16); + __ Ldp(w0, w1, MemOperand(x24, base_offset + 4, PostIndex)); + __ Mov(x19, x24); + __ Sub(x24, x24, base_offset); + __ Ldp(w2, w3, MemOperand(x24, base_offset - 4, PostIndex)); + __ Stp(w2, w3, MemOperand(x25, 4 - base_offset, PostIndex)); + __ Mov(x20, x25); + __ Sub(x24, x24, base_offset); + __ Add(x25, x25, base_offset); + __ Stp(w0, w1, MemOperand(x25, -4 - base_offset, PostIndex)); + __ Ldp(x4, x5, MemOperand(x24, base_offset + 8, PostIndex)); + __ Mov(x21, x24); + __ Sub(x24, x24, base_offset); + __ Ldp(x6, x7, MemOperand(x24, base_offset - 8, PostIndex)); + __ Stp(x7, x6, MemOperand(x18, 8 - base_offset, PostIndex)); + __ Mov(x22, x18); + __ Add(x18, x18, base_offset); + __ Stp(x5, x4, MemOperand(x18, -8 - base_offset, PostIndex)); + END(); + + RUN(); + + CHECK_EQUAL_64(0x44556677, x0); + CHECK_EQUAL_64(0x00112233, x1); + CHECK_EQUAL_64(0x00112233, x2); + CHECK_EQUAL_64(0xccddeeff, x3); + CHECK_EQUAL_64(0x4455667700112233UL, dst[0]); + CHECK_EQUAL_64(0x0000000000112233UL, dst[1]); + CHECK_EQUAL_64(0x0011223344556677UL, x4); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x5); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, x6); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, x7); + CHECK_EQUAL_64(0xffeeddccbbaa9988UL, dst[2]); + CHECK_EQUAL_64(0x8899aabbccddeeffUL, dst[3]); + CHECK_EQUAL_64(0x0011223344556677UL, dst[4]); + CHECK_EQUAL_64(src_base + base_offset, x24); + CHECK_EQUAL_64(dst_base - base_offset, x25); + CHECK_EQUAL_64(dst_base - base_offset + 16, x18); + CHECK_EQUAL_64(src_base + base_offset + 4, x19); + CHECK_EQUAL_64(dst_base - base_offset + 4, x20); + CHECK_EQUAL_64(src_base + base_offset + 8, x21); + CHECK_EQUAL_64(dst_base - base_offset + 24, x22); TEARDOWN(); } @@ -3080,8 +3274,8 @@ TEST(ldp_sign_extend) { RUN(); - ASSERT_EQUAL_64(0xffffffff80000000UL, x0); - ASSERT_EQUAL_64(0x000000007fffffffUL, x1); + CHECK_EQUAL_64(0xffffffff80000000UL, x0); + CHECK_EQUAL_64(0x000000007fffffffUL, x1); TEARDOWN(); } @@ -3114,19 +3308,19 @@ TEST(ldur_stur) { RUN(); - ASSERT_EQUAL_64(0x6789abcd, x0); - ASSERT_EQUAL_64(0x6789abcd0000L, dst[0]); - ASSERT_EQUAL_64(0xabcdef0123456789L, x1); - ASSERT_EQUAL_64(0xcdef012345678900L, dst[1]); - ASSERT_EQUAL_64(0x000000ab, dst[2]); - ASSERT_EQUAL_64(0xabcdef01, x2); - ASSERT_EQUAL_64(0x00abcdef01000000L, dst[3]); - ASSERT_EQUAL_64(0x00000001, x3); - ASSERT_EQUAL_64(0x0100000000000000L, dst[4]); - ASSERT_EQUAL_64(src_base, x17); - ASSERT_EQUAL_64(dst_base, x18); - ASSERT_EQUAL_64(src_base + 16, x19); - ASSERT_EQUAL_64(dst_base + 32, x20); + CHECK_EQUAL_64(0x6789abcd, x0); + CHECK_EQUAL_64(0x6789abcd0000L, dst[0]); + CHECK_EQUAL_64(0xabcdef0123456789L, x1); + CHECK_EQUAL_64(0xcdef012345678900L, dst[1]); + CHECK_EQUAL_64(0x000000ab, dst[2]); + CHECK_EQUAL_64(0xabcdef01, x2); + CHECK_EQUAL_64(0x00abcdef01000000L, dst[3]); + CHECK_EQUAL_64(0x00000001, x3); + CHECK_EQUAL_64(0x0100000000000000L, dst[4]); + CHECK_EQUAL_64(src_base, x17); + CHECK_EQUAL_64(dst_base, x18); + CHECK_EQUAL_64(src_base + 16, x19); + CHECK_EQUAL_64(dst_base + 32, x20); TEARDOWN(); } @@ -3147,10 +3341,10 @@ TEST(ldr_literal) { RUN(); - ASSERT_EQUAL_64(0x1234567890abcdefUL, x2); - ASSERT_EQUAL_64(0xfedcba09, x3); - ASSERT_EQUAL_FP64(1.234, d13); - ASSERT_EQUAL_FP32(2.5, s25); + CHECK_EQUAL_64(0x1234567890abcdefUL, x2); + CHECK_EQUAL_64(0xfedcba09, x3); + CHECK_EQUAL_FP64(1.234, d13); + CHECK_EQUAL_FP32(2.5, s25); TEARDOWN(); } @@ -3159,7 +3353,7 @@ TEST(ldr_literal) { static void LdrLiteralRangeHelper(ptrdiff_t range_, LiteralPoolEmitOption option, bool expect_dump) { - ASSERT(range_ > 0); + DCHECK(range_ > 0); SETUP_SIZE(range_ + 1024); Label label_1, label_2; @@ -3178,19 +3372,19 @@ static void LdrLiteralRangeHelper(ptrdiff_t range_, START(); // Force a pool dump so the pool starts off empty. __ EmitLiteralPool(JumpRequired); - ASSERT_LITERAL_POOL_SIZE(0); + DCHECK_LITERAL_POOL_SIZE(0); __ Ldr(x0, 0x1234567890abcdefUL); __ Ldr(w1, 0xfedcba09); __ Ldr(d0, 1.234); __ Ldr(s1, 2.5); - ASSERT_LITERAL_POOL_SIZE(4); + DCHECK_LITERAL_POOL_SIZE(4); code_size += 4 * sizeof(Instr); // Check that the requested range (allowing space for a branch over the pool) // can be handled by this test. - ASSERT((code_size + pool_guard_size) <= range); + DCHECK((code_size + pool_guard_size) <= range); // Emit NOPs up to 'range', leaving space for the pool guard. while ((code_size + pool_guard_size) < range) { @@ -3204,41 +3398,41 @@ static void LdrLiteralRangeHelper(ptrdiff_t range_, code_size += sizeof(Instr); } - ASSERT(code_size == range); - ASSERT_LITERAL_POOL_SIZE(4); + DCHECK(code_size == range); + DCHECK_LITERAL_POOL_SIZE(4); // Possibly generate a literal pool. __ CheckLiteralPool(option); __ Bind(&label_1); if (expect_dump) { - ASSERT_LITERAL_POOL_SIZE(0); + DCHECK_LITERAL_POOL_SIZE(0); } else { - ASSERT_LITERAL_POOL_SIZE(4); + DCHECK_LITERAL_POOL_SIZE(4); } // Force a pool flush to check that a second pool functions correctly. __ EmitLiteralPool(JumpRequired); - ASSERT_LITERAL_POOL_SIZE(0); + DCHECK_LITERAL_POOL_SIZE(0); // These loads should be after the pool (and will require a new one). __ Ldr(x4, 0x34567890abcdef12UL); __ Ldr(w5, 0xdcba09fe); __ Ldr(d4, 123.4); __ Ldr(s5, 250.0); - ASSERT_LITERAL_POOL_SIZE(4); + DCHECK_LITERAL_POOL_SIZE(4); END(); RUN(); // Check that the literals loaded correctly. - ASSERT_EQUAL_64(0x1234567890abcdefUL, x0); - ASSERT_EQUAL_64(0xfedcba09, x1); - ASSERT_EQUAL_FP64(1.234, d0); - ASSERT_EQUAL_FP32(2.5, s1); - ASSERT_EQUAL_64(0x34567890abcdef12UL, x4); - ASSERT_EQUAL_64(0xdcba09fe, x5); - ASSERT_EQUAL_FP64(123.4, d4); - ASSERT_EQUAL_FP32(250.0, s5); + CHECK_EQUAL_64(0x1234567890abcdefUL, x0); + CHECK_EQUAL_64(0xfedcba09, x1); + CHECK_EQUAL_FP64(1.234, d0); + CHECK_EQUAL_FP32(2.5, s1); + CHECK_EQUAL_64(0x34567890abcdef12UL, x4); + CHECK_EQUAL_64(0xdcba09fe, x5); + CHECK_EQUAL_FP64(123.4, d4); + CHECK_EQUAL_FP32(250.0, s5); TEARDOWN(); } @@ -3325,25 +3519,25 @@ TEST(add_sub_imm) { RUN(); - ASSERT_EQUAL_64(0x123, x10); - ASSERT_EQUAL_64(0x123111, x11); - ASSERT_EQUAL_64(0xabc000, x12); - ASSERT_EQUAL_64(0x0, x13); + CHECK_EQUAL_64(0x123, x10); + CHECK_EQUAL_64(0x123111, x11); + CHECK_EQUAL_64(0xabc000, x12); + CHECK_EQUAL_64(0x0, x13); - ASSERT_EQUAL_32(0x123, w14); - ASSERT_EQUAL_32(0x123111, w15); - ASSERT_EQUAL_32(0xabc000, w16); - ASSERT_EQUAL_32(0x0, w17); + CHECK_EQUAL_32(0x123, w14); + CHECK_EQUAL_32(0x123111, w15); + CHECK_EQUAL_32(0xabc000, w16); + CHECK_EQUAL_32(0x0, w17); - ASSERT_EQUAL_64(0xffffffffffffffffL, x20); - ASSERT_EQUAL_64(0x1000, x21); - ASSERT_EQUAL_64(0x111, x22); - ASSERT_EQUAL_64(0x7fffffffffffffffL, x23); + CHECK_EQUAL_64(0xffffffffffffffffL, x20); + CHECK_EQUAL_64(0x1000, x21); + CHECK_EQUAL_64(0x111, x22); + CHECK_EQUAL_64(0x7fffffffffffffffL, x23); - ASSERT_EQUAL_32(0xffffffff, w24); - ASSERT_EQUAL_32(0x1000, w25); - ASSERT_EQUAL_32(0x111, w26); - ASSERT_EQUAL_32(0xffffffff, w27); + CHECK_EQUAL_32(0xffffffff, w24); + CHECK_EQUAL_32(0x1000, w25); + CHECK_EQUAL_32(0x111, w26); + CHECK_EQUAL_32(0xffffffff, w27); TEARDOWN(); } @@ -3363,22 +3557,26 @@ TEST(add_sub_wide_imm) { __ Add(w12, w0, Operand(0x12345678)); __ Add(w13, w1, Operand(0xffffffff)); - __ Sub(x20, x0, Operand(0x1234567890abcdefUL)); + __ Add(w18, w0, Operand(kWMinInt)); + __ Sub(w19, w0, Operand(kWMinInt)); + __ Sub(x20, x0, Operand(0x1234567890abcdefUL)); __ Sub(w21, w0, Operand(0x12345678)); END(); RUN(); - ASSERT_EQUAL_64(0x1234567890abcdefUL, x10); - ASSERT_EQUAL_64(0x100000000UL, x11); + CHECK_EQUAL_64(0x1234567890abcdefUL, x10); + CHECK_EQUAL_64(0x100000000UL, x11); - ASSERT_EQUAL_32(0x12345678, w12); - ASSERT_EQUAL_64(0x0, x13); + CHECK_EQUAL_32(0x12345678, w12); + CHECK_EQUAL_64(0x0, x13); - ASSERT_EQUAL_64(-0x1234567890abcdefUL, x20); + CHECK_EQUAL_32(kWMinInt, w18); + CHECK_EQUAL_32(kWMinInt, w19); - ASSERT_EQUAL_32(-0x12345678, w21); + CHECK_EQUAL_64(-0x1234567890abcdefUL, x20); + CHECK_EQUAL_32(-0x12345678, w21); TEARDOWN(); } @@ -3415,23 +3613,23 @@ TEST(add_sub_shifted) { RUN(); - ASSERT_EQUAL_64(0xffffffffffffffffL, x10); - ASSERT_EQUAL_64(0x23456789abcdef00L, x11); - ASSERT_EQUAL_64(0x000123456789abcdL, x12); - ASSERT_EQUAL_64(0x000123456789abcdL, x13); - ASSERT_EQUAL_64(0xfffedcba98765432L, x14); - ASSERT_EQUAL_64(0xff89abcd, x15); - ASSERT_EQUAL_64(0xef89abcc, x18); - ASSERT_EQUAL_64(0xef0123456789abccL, x19); + CHECK_EQUAL_64(0xffffffffffffffffL, x10); + CHECK_EQUAL_64(0x23456789abcdef00L, x11); + CHECK_EQUAL_64(0x000123456789abcdL, x12); + CHECK_EQUAL_64(0x000123456789abcdL, x13); + CHECK_EQUAL_64(0xfffedcba98765432L, x14); + CHECK_EQUAL_64(0xff89abcd, x15); + CHECK_EQUAL_64(0xef89abcc, x18); + CHECK_EQUAL_64(0xef0123456789abccL, x19); - ASSERT_EQUAL_64(0x0123456789abcdefL, x20); - ASSERT_EQUAL_64(0xdcba9876543210ffL, x21); - ASSERT_EQUAL_64(0xfffedcba98765432L, x22); - ASSERT_EQUAL_64(0xfffedcba98765432L, x23); - ASSERT_EQUAL_64(0x000123456789abcdL, x24); - ASSERT_EQUAL_64(0x00765432, x25); - ASSERT_EQUAL_64(0x10765432, x26); - ASSERT_EQUAL_64(0x10fedcba98765432L, x27); + CHECK_EQUAL_64(0x0123456789abcdefL, x20); + CHECK_EQUAL_64(0xdcba9876543210ffL, x21); + CHECK_EQUAL_64(0xfffedcba98765432L, x22); + CHECK_EQUAL_64(0xfffedcba98765432L, x23); + CHECK_EQUAL_64(0x000123456789abcdL, x24); + CHECK_EQUAL_64(0x00765432, x25); + CHECK_EQUAL_64(0x10765432, x26); + CHECK_EQUAL_64(0x10fedcba98765432L, x27); TEARDOWN(); } @@ -3477,32 +3675,32 @@ TEST(add_sub_extended) { RUN(); - ASSERT_EQUAL_64(0xefL, x10); - ASSERT_EQUAL_64(0x1deL, x11); - ASSERT_EQUAL_64(0x337bcL, x12); - ASSERT_EQUAL_64(0x89abcdef0L, x13); + CHECK_EQUAL_64(0xefL, x10); + CHECK_EQUAL_64(0x1deL, x11); + CHECK_EQUAL_64(0x337bcL, x12); + CHECK_EQUAL_64(0x89abcdef0L, x13); - ASSERT_EQUAL_64(0xffffffffffffffefL, x14); - ASSERT_EQUAL_64(0xffffffffffffffdeL, x15); - ASSERT_EQUAL_64(0xffffffffffff37bcL, x16); - ASSERT_EQUAL_64(0xfffffffc4d5e6f78L, x17); - ASSERT_EQUAL_64(0x10L, x18); - ASSERT_EQUAL_64(0x20L, x19); - ASSERT_EQUAL_64(0xc840L, x20); - ASSERT_EQUAL_64(0x3b2a19080L, x21); + CHECK_EQUAL_64(0xffffffffffffffefL, x14); + CHECK_EQUAL_64(0xffffffffffffffdeL, x15); + CHECK_EQUAL_64(0xffffffffffff37bcL, x16); + CHECK_EQUAL_64(0xfffffffc4d5e6f78L, x17); + CHECK_EQUAL_64(0x10L, x18); + CHECK_EQUAL_64(0x20L, x19); + CHECK_EQUAL_64(0xc840L, x20); + CHECK_EQUAL_64(0x3b2a19080L, x21); - ASSERT_EQUAL_64(0x0123456789abce0fL, x22); - ASSERT_EQUAL_64(0x0123456789abcdcfL, x23); + CHECK_EQUAL_64(0x0123456789abce0fL, x22); + CHECK_EQUAL_64(0x0123456789abcdcfL, x23); - ASSERT_EQUAL_32(0x89abce2f, w24); - ASSERT_EQUAL_32(0xffffffef, w25); - ASSERT_EQUAL_32(0xffffffde, w26); - ASSERT_EQUAL_32(0xc3b2a188, w27); + CHECK_EQUAL_32(0x89abce2f, w24); + CHECK_EQUAL_32(0xffffffef, w25); + CHECK_EQUAL_32(0xffffffde, w26); + CHECK_EQUAL_32(0xc3b2a188, w27); - ASSERT_EQUAL_32(0x4d5e6f78, w28); - ASSERT_EQUAL_64(0xfffffffc4d5e6f78L, x29); + CHECK_EQUAL_32(0x4d5e6f78, w28); + CHECK_EQUAL_64(0xfffffffc4d5e6f78L, x29); - ASSERT_EQUAL_64(256, x30); + CHECK_EQUAL_64(256, x30); TEARDOWN(); } @@ -3536,19 +3734,19 @@ TEST(add_sub_negative) { RUN(); - ASSERT_EQUAL_64(-42, x10); - ASSERT_EQUAL_64(4000, x11); - ASSERT_EQUAL_64(0x1122334455667700, x12); + CHECK_EQUAL_64(-42, x10); + CHECK_EQUAL_64(4000, x11); + CHECK_EQUAL_64(0x1122334455667700, x12); - ASSERT_EQUAL_64(600, x13); - ASSERT_EQUAL_64(5000, x14); - ASSERT_EQUAL_64(0x1122334455667cdd, x15); + CHECK_EQUAL_64(600, x13); + CHECK_EQUAL_64(5000, x14); + CHECK_EQUAL_64(0x1122334455667cdd, x15); - ASSERT_EQUAL_32(0x11223000, w19); - ASSERT_EQUAL_32(398000, w20); + CHECK_EQUAL_32(0x11223000, w19); + CHECK_EQUAL_32(398000, w20); - ASSERT_EQUAL_32(0x11223400, w21); - ASSERT_EQUAL_32(402000, w22); + CHECK_EQUAL_32(0x11223400, w21); + CHECK_EQUAL_32(402000, w22); TEARDOWN(); } @@ -3584,9 +3782,9 @@ TEST(add_sub_zero) { RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(0, x1); - ASSERT_EQUAL_64(0, x2); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(0, x1); + CHECK_EQUAL_64(0, x2); TEARDOWN(); } @@ -3652,20 +3850,20 @@ TEST(neg) { RUN(); - ASSERT_EQUAL_64(0xfffffffffffffeddUL, x1); - ASSERT_EQUAL_64(0xfffffedd, x2); - ASSERT_EQUAL_64(0x1db97530eca86422UL, x3); - ASSERT_EQUAL_64(0xd950c844, x4); - ASSERT_EQUAL_64(0xe1db97530eca8643UL, x5); - ASSERT_EQUAL_64(0xf7654322, x6); - ASSERT_EQUAL_64(0x0076e5d4c3b2a191UL, x7); - ASSERT_EQUAL_64(0x01d950c9, x8); - ASSERT_EQUAL_64(0xffffff11, x9); - ASSERT_EQUAL_64(0x0000000000000022UL, x10); - ASSERT_EQUAL_64(0xfffcc844, x11); - ASSERT_EQUAL_64(0x0000000000019088UL, x12); - ASSERT_EQUAL_64(0x65432110, x13); - ASSERT_EQUAL_64(0x0000000765432110UL, x14); + CHECK_EQUAL_64(0xfffffffffffffeddUL, x1); + CHECK_EQUAL_64(0xfffffedd, x2); + CHECK_EQUAL_64(0x1db97530eca86422UL, x3); + CHECK_EQUAL_64(0xd950c844, x4); + CHECK_EQUAL_64(0xe1db97530eca8643UL, x5); + CHECK_EQUAL_64(0xf7654322, x6); + CHECK_EQUAL_64(0x0076e5d4c3b2a191UL, x7); + CHECK_EQUAL_64(0x01d950c9, x8); + CHECK_EQUAL_64(0xffffff11, x9); + CHECK_EQUAL_64(0x0000000000000022UL, x10); + CHECK_EQUAL_64(0xfffcc844, x11); + CHECK_EQUAL_64(0x0000000000019088UL, x12); + CHECK_EQUAL_64(0x65432110, x13); + CHECK_EQUAL_64(0x0000000765432110UL, x14); TEARDOWN(); } @@ -3715,29 +3913,29 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_64(0xffffffffffffffffL, x5); - ASSERT_EQUAL_64(1L << 60, x6); - ASSERT_EQUAL_64(0xf0123456789abcddL, x7); - ASSERT_EQUAL_64(0x0111111111111110L, x8); - ASSERT_EQUAL_64(0x1222222222222221L, x9); + CHECK_EQUAL_64(0xffffffffffffffffL, x5); + CHECK_EQUAL_64(1L << 60, x6); + CHECK_EQUAL_64(0xf0123456789abcddL, x7); + CHECK_EQUAL_64(0x0111111111111110L, x8); + CHECK_EQUAL_64(0x1222222222222221L, x9); - ASSERT_EQUAL_32(0xffffffff, w10); - ASSERT_EQUAL_32(1 << 30, w11); - ASSERT_EQUAL_32(0xf89abcdd, w12); - ASSERT_EQUAL_32(0x91111110, w13); - ASSERT_EQUAL_32(0x9a222221, w14); + CHECK_EQUAL_32(0xffffffff, w10); + CHECK_EQUAL_32(1 << 30, w11); + CHECK_EQUAL_32(0xf89abcdd, w12); + CHECK_EQUAL_32(0x91111110, w13); + CHECK_EQUAL_32(0x9a222221, w14); - ASSERT_EQUAL_64(0xffffffffffffffffL + 1, x18); - ASSERT_EQUAL_64((1L << 60) + 1, x19); - ASSERT_EQUAL_64(0xf0123456789abcddL + 1, x20); - ASSERT_EQUAL_64(0x0111111111111110L + 1, x21); - ASSERT_EQUAL_64(0x1222222222222221L + 1, x22); + CHECK_EQUAL_64(0xffffffffffffffffL + 1, x18); + CHECK_EQUAL_64((1L << 60) + 1, x19); + CHECK_EQUAL_64(0xf0123456789abcddL + 1, x20); + CHECK_EQUAL_64(0x0111111111111110L + 1, x21); + CHECK_EQUAL_64(0x1222222222222221L + 1, x22); - ASSERT_EQUAL_32(0xffffffff + 1, w23); - ASSERT_EQUAL_32((1 << 30) + 1, w24); - ASSERT_EQUAL_32(0xf89abcdd + 1, w25); - ASSERT_EQUAL_32(0x91111110 + 1, w26); - ASSERT_EQUAL_32(0x9a222221 + 1, w27); + CHECK_EQUAL_32(0xffffffff + 1, w23); + CHECK_EQUAL_32((1 << 30) + 1, w24); + CHECK_EQUAL_32(0xf89abcdd + 1, w25); + CHECK_EQUAL_32(0x91111110 + 1, w26); + CHECK_EQUAL_32(0x9a222221 + 1, w27); // Check that adc correctly sets the condition flags. START(); @@ -3750,8 +3948,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); - ASSERT_EQUAL_64(0, x10); + CHECK_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_64(0, x10); START(); __ Mov(x0, 1); @@ -3763,8 +3961,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); - ASSERT_EQUAL_64(0, x10); + CHECK_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_64(0, x10); START(); __ Mov(x0, 0x10); @@ -3776,8 +3974,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NVFlag); - ASSERT_EQUAL_64(0x8000000000000000L, x10); + CHECK_EQUAL_NZCV(NVFlag); + CHECK_EQUAL_64(0x8000000000000000L, x10); // Check that sbc correctly sets the condition flags. START(); @@ -3790,8 +3988,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0, x10); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0, x10); START(); __ Mov(x0, 1); @@ -3803,8 +4001,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x8000000000000001L, x10); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x8000000000000001L, x10); START(); __ Mov(x0, 0); @@ -3815,8 +4013,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(ZFlag); - ASSERT_EQUAL_64(0, x10); + CHECK_EQUAL_NZCV(ZFlag); + CHECK_EQUAL_64(0, x10); START() __ Mov(w0, 0x7fffffff); @@ -3827,8 +4025,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x80000000, x10); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x80000000, x10); START(); // Clear the C flag. @@ -3838,8 +4036,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x8000000000000000L, x10); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x8000000000000000L, x10); START() __ Mov(x0, 0); @@ -3850,8 +4048,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0xffffffffffffffffL, x10); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0xffffffffffffffffL, x10); START() __ Mov(x0, 0); @@ -3862,8 +4060,8 @@ TEST(adc_sbc_shift) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); - ASSERT_EQUAL_64(0x8000000000000001L, x10); + CHECK_EQUAL_NZCV(NFlag); + CHECK_EQUAL_64(0x8000000000000001L, x10); TEARDOWN(); } @@ -3905,23 +4103,23 @@ TEST(adc_sbc_extend) { RUN(); - ASSERT_EQUAL_64(0x1df, x10); - ASSERT_EQUAL_64(0xffffffffffff37bdL, x11); - ASSERT_EQUAL_64(0xfffffff765432110L, x12); - ASSERT_EQUAL_64(0x123456789abcdef1L, x13); + CHECK_EQUAL_64(0x1df, x10); + CHECK_EQUAL_64(0xffffffffffff37bdL, x11); + CHECK_EQUAL_64(0xfffffff765432110L, x12); + CHECK_EQUAL_64(0x123456789abcdef1L, x13); - ASSERT_EQUAL_32(0x1df, w14); - ASSERT_EQUAL_32(0xffff37bd, w15); - ASSERT_EQUAL_32(0x9abcdef1, w9); + CHECK_EQUAL_32(0x1df, w14); + CHECK_EQUAL_32(0xffff37bd, w15); + CHECK_EQUAL_32(0x9abcdef1, w9); - ASSERT_EQUAL_64(0x1df + 1, x20); - ASSERT_EQUAL_64(0xffffffffffff37bdL + 1, x21); - ASSERT_EQUAL_64(0xfffffff765432110L + 1, x22); - ASSERT_EQUAL_64(0x123456789abcdef1L + 1, x23); + CHECK_EQUAL_64(0x1df + 1, x20); + CHECK_EQUAL_64(0xffffffffffff37bdL + 1, x21); + CHECK_EQUAL_64(0xfffffff765432110L + 1, x22); + CHECK_EQUAL_64(0x123456789abcdef1L + 1, x23); - ASSERT_EQUAL_32(0x1df + 1, w24); - ASSERT_EQUAL_32(0xffff37bd + 1, w25); - ASSERT_EQUAL_32(0x9abcdef1 + 1, w26); + CHECK_EQUAL_32(0x1df + 1, w24); + CHECK_EQUAL_32(0xffff37bd + 1, w25); + CHECK_EQUAL_32(0x9abcdef1 + 1, w26); // Check that adc correctly sets the condition flags. START(); @@ -3934,7 +4132,7 @@ TEST(adc_sbc_extend) { RUN(); - ASSERT_EQUAL_NZCV(CFlag); + CHECK_EQUAL_NZCV(CFlag); START(); __ Mov(x0, 0x7fffffffffffffffL); @@ -3946,7 +4144,7 @@ TEST(adc_sbc_extend) { RUN(); - ASSERT_EQUAL_NZCV(NVFlag); + CHECK_EQUAL_NZCV(NVFlag); START(); __ Mov(x0, 0x7fffffffffffffffL); @@ -3957,7 +4155,7 @@ TEST(adc_sbc_extend) { RUN(); - ASSERT_EQUAL_NZCV(NVFlag); + CHECK_EQUAL_NZCV(NVFlag); TEARDOWN(); } @@ -3993,19 +4191,19 @@ TEST(adc_sbc_wide_imm) { RUN(); - ASSERT_EQUAL_64(0x1234567890abcdefUL, x7); - ASSERT_EQUAL_64(0xffffffff, x8); - ASSERT_EQUAL_64(0xedcba9876f543210UL, x9); - ASSERT_EQUAL_64(0, x10); - ASSERT_EQUAL_64(0xffffffff, x11); - ASSERT_EQUAL_64(0xffff, x12); + CHECK_EQUAL_64(0x1234567890abcdefUL, x7); + CHECK_EQUAL_64(0xffffffff, x8); + CHECK_EQUAL_64(0xedcba9876f543210UL, x9); + CHECK_EQUAL_64(0, x10); + CHECK_EQUAL_64(0xffffffff, x11); + CHECK_EQUAL_64(0xffff, x12); - ASSERT_EQUAL_64(0x1234567890abcdefUL + 1, x18); - ASSERT_EQUAL_64(0, x19); - ASSERT_EQUAL_64(0xedcba9876f543211UL, x20); - ASSERT_EQUAL_64(1, x21); - ASSERT_EQUAL_64(0x100000000UL, x22); - ASSERT_EQUAL_64(0x10000, x23); + CHECK_EQUAL_64(0x1234567890abcdefUL + 1, x18); + CHECK_EQUAL_64(0, x19); + CHECK_EQUAL_64(0xedcba9876f543211UL, x20); + CHECK_EQUAL_64(1, x21); + CHECK_EQUAL_64(0x100000000UL, x22); + CHECK_EQUAL_64(0x10000, x23); TEARDOWN(); } @@ -4031,11 +4229,11 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_64(0, x10); - ASSERT_EQUAL_64(-0x1111111111111111L, x11); - ASSERT_EQUAL_32(-0x11111111, w12); - ASSERT_EQUAL_64(-1L, x13); - ASSERT_EQUAL_32(0, w14); + CHECK_EQUAL_64(0, x10); + CHECK_EQUAL_64(-0x1111111111111111L, x11); + CHECK_EQUAL_32(-0x11111111, w12); + CHECK_EQUAL_64(-1L, x13); + CHECK_EQUAL_32(0, w14); START(); __ Mov(x0, 0); @@ -4044,7 +4242,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_NZCV(ZCFlag); START(); __ Mov(w0, 0); @@ -4053,7 +4251,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_NZCV(ZCFlag); START(); __ Mov(x0, 0); @@ -4063,7 +4261,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); + CHECK_EQUAL_NZCV(NFlag); START(); __ Mov(w0, 0); @@ -4073,7 +4271,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); + CHECK_EQUAL_NZCV(NFlag); START(); __ Mov(x1, 0x1111111111111111L); @@ -4082,7 +4280,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(CFlag); + CHECK_EQUAL_NZCV(CFlag); START(); __ Mov(w1, 0x11111111); @@ -4091,7 +4289,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(CFlag); + CHECK_EQUAL_NZCV(CFlag); START(); __ Mov(x0, 1); @@ -4101,7 +4299,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(NVFlag); + CHECK_EQUAL_NZCV(NVFlag); START(); __ Mov(w0, 1); @@ -4111,7 +4309,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(NVFlag); + CHECK_EQUAL_NZCV(NVFlag); START(); __ Mov(x0, 1); @@ -4121,7 +4319,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_NZCV(ZCFlag); START(); __ Mov(w0, 1); @@ -4131,7 +4329,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_NZCV(ZCFlag); START(); __ Mov(w0, 0); @@ -4143,7 +4341,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(NFlag); + CHECK_EQUAL_NZCV(NFlag); START(); __ Mov(w0, 0); @@ -4155,7 +4353,7 @@ TEST(flags) { RUN(); - ASSERT_EQUAL_NZCV(ZCFlag); + CHECK_EQUAL_NZCV(ZCFlag); TEARDOWN(); } @@ -4204,14 +4402,14 @@ TEST(cmp_shift) { RUN(); - ASSERT_EQUAL_32(ZCFlag, w0); - ASSERT_EQUAL_32(ZCFlag, w1); - ASSERT_EQUAL_32(ZCFlag, w2); - ASSERT_EQUAL_32(ZCFlag, w3); - ASSERT_EQUAL_32(ZCFlag, w4); - ASSERT_EQUAL_32(ZCFlag, w5); - ASSERT_EQUAL_32(ZCFlag, w6); - ASSERT_EQUAL_32(ZCFlag, w7); + CHECK_EQUAL_32(ZCFlag, w0); + CHECK_EQUAL_32(ZCFlag, w1); + CHECK_EQUAL_32(ZCFlag, w2); + CHECK_EQUAL_32(ZCFlag, w3); + CHECK_EQUAL_32(ZCFlag, w4); + CHECK_EQUAL_32(ZCFlag, w5); + CHECK_EQUAL_32(ZCFlag, w6); + CHECK_EQUAL_32(ZCFlag, w7); TEARDOWN(); } @@ -4257,14 +4455,14 @@ TEST(cmp_extend) { RUN(); - ASSERT_EQUAL_32(ZCFlag, w0); - ASSERT_EQUAL_32(ZCFlag, w1); - ASSERT_EQUAL_32(ZCFlag, w2); - ASSERT_EQUAL_32(NCFlag, w3); - ASSERT_EQUAL_32(NCFlag, w4); - ASSERT_EQUAL_32(ZCFlag, w5); - ASSERT_EQUAL_32(NCFlag, w6); - ASSERT_EQUAL_32(ZCFlag, w7); + CHECK_EQUAL_32(ZCFlag, w0); + CHECK_EQUAL_32(ZCFlag, w1); + CHECK_EQUAL_32(ZCFlag, w2); + CHECK_EQUAL_32(NCFlag, w3); + CHECK_EQUAL_32(NCFlag, w4); + CHECK_EQUAL_32(ZCFlag, w5); + CHECK_EQUAL_32(NCFlag, w6); + CHECK_EQUAL_32(ZCFlag, w7); TEARDOWN(); } @@ -4303,12 +4501,12 @@ TEST(ccmp) { RUN(); - ASSERT_EQUAL_32(NFlag, w0); - ASSERT_EQUAL_32(NCFlag, w1); - ASSERT_EQUAL_32(NoFlag, w2); - ASSERT_EQUAL_32(NZCVFlag, w3); - ASSERT_EQUAL_32(ZCFlag, w4); - ASSERT_EQUAL_32(ZCFlag, w5); + CHECK_EQUAL_32(NFlag, w0); + CHECK_EQUAL_32(NCFlag, w1); + CHECK_EQUAL_32(NoFlag, w2); + CHECK_EQUAL_32(NZCVFlag, w3); + CHECK_EQUAL_32(ZCFlag, w4); + CHECK_EQUAL_32(ZCFlag, w5); TEARDOWN(); } @@ -4332,8 +4530,8 @@ TEST(ccmp_wide_imm) { RUN(); - ASSERT_EQUAL_32(NFlag, w0); - ASSERT_EQUAL_32(NoFlag, w1); + CHECK_EQUAL_32(NFlag, w0); + CHECK_EQUAL_32(NoFlag, w1); TEARDOWN(); } @@ -4373,11 +4571,11 @@ TEST(ccmp_shift_extend) { RUN(); - ASSERT_EQUAL_32(ZCFlag, w0); - ASSERT_EQUAL_32(ZCFlag, w1); - ASSERT_EQUAL_32(ZCFlag, w2); - ASSERT_EQUAL_32(NCFlag, w3); - ASSERT_EQUAL_32(NZCVFlag, w4); + CHECK_EQUAL_32(ZCFlag, w0); + CHECK_EQUAL_32(ZCFlag, w1); + CHECK_EQUAL_32(ZCFlag, w2); + CHECK_EQUAL_32(NCFlag, w3); + CHECK_EQUAL_32(NZCVFlag, w4); TEARDOWN(); } @@ -4427,27 +4625,27 @@ TEST(csel) { RUN(); - ASSERT_EQUAL_64(0x0000000f, x0); - ASSERT_EQUAL_64(0x0000001f, x1); - ASSERT_EQUAL_64(0x00000020, x2); - ASSERT_EQUAL_64(0x0000000f, x3); - ASSERT_EQUAL_64(0xffffffe0ffffffe0UL, x4); - ASSERT_EQUAL_64(0x0000000f0000000fUL, x5); - ASSERT_EQUAL_64(0xffffffe0ffffffe1UL, x6); - ASSERT_EQUAL_64(0x0000000f0000000fUL, x7); - ASSERT_EQUAL_64(0x00000001, x8); - ASSERT_EQUAL_64(0xffffffff, x9); - ASSERT_EQUAL_64(0x0000001f00000020UL, x10); - ASSERT_EQUAL_64(0xfffffff0fffffff0UL, x11); - ASSERT_EQUAL_64(0xfffffff0fffffff1UL, x12); - ASSERT_EQUAL_64(0x0000000f, x13); - ASSERT_EQUAL_64(0x0000000f0000000fUL, x14); - ASSERT_EQUAL_64(0x0000000f, x15); - ASSERT_EQUAL_64(0x0000000f0000000fUL, x18); - ASSERT_EQUAL_64(0, x24); - ASSERT_EQUAL_64(0x0000001f0000001fUL, x25); - ASSERT_EQUAL_64(0x0000001f0000001fUL, x26); - ASSERT_EQUAL_64(0, x27); + CHECK_EQUAL_64(0x0000000f, x0); + CHECK_EQUAL_64(0x0000001f, x1); + CHECK_EQUAL_64(0x00000020, x2); + CHECK_EQUAL_64(0x0000000f, x3); + CHECK_EQUAL_64(0xffffffe0ffffffe0UL, x4); + CHECK_EQUAL_64(0x0000000f0000000fUL, x5); + CHECK_EQUAL_64(0xffffffe0ffffffe1UL, x6); + CHECK_EQUAL_64(0x0000000f0000000fUL, x7); + CHECK_EQUAL_64(0x00000001, x8); + CHECK_EQUAL_64(0xffffffff, x9); + CHECK_EQUAL_64(0x0000001f00000020UL, x10); + CHECK_EQUAL_64(0xfffffff0fffffff0UL, x11); + CHECK_EQUAL_64(0xfffffff0fffffff1UL, x12); + CHECK_EQUAL_64(0x0000000f, x13); + CHECK_EQUAL_64(0x0000000f0000000fUL, x14); + CHECK_EQUAL_64(0x0000000f, x15); + CHECK_EQUAL_64(0x0000000f0000000fUL, x18); + CHECK_EQUAL_64(0, x24); + CHECK_EQUAL_64(0x0000001f0000001fUL, x25); + CHECK_EQUAL_64(0x0000001f0000001fUL, x26); + CHECK_EQUAL_64(0, x27); TEARDOWN(); } @@ -4485,23 +4683,23 @@ TEST(csel_imm) { RUN(); - ASSERT_EQUAL_32(-2, w0); - ASSERT_EQUAL_32(-1, w1); - ASSERT_EQUAL_32(0, w2); - ASSERT_EQUAL_32(1, w3); - ASSERT_EQUAL_32(2, w4); - ASSERT_EQUAL_32(-1, w5); - ASSERT_EQUAL_32(0x40000000, w6); - ASSERT_EQUAL_32(0x80000000, w7); + CHECK_EQUAL_32(-2, w0); + CHECK_EQUAL_32(-1, w1); + CHECK_EQUAL_32(0, w2); + CHECK_EQUAL_32(1, w3); + CHECK_EQUAL_32(2, w4); + CHECK_EQUAL_32(-1, w5); + CHECK_EQUAL_32(0x40000000, w6); + CHECK_EQUAL_32(0x80000000, w7); - ASSERT_EQUAL_64(-2, x8); - ASSERT_EQUAL_64(-1, x9); - ASSERT_EQUAL_64(0, x10); - ASSERT_EQUAL_64(1, x11); - ASSERT_EQUAL_64(2, x12); - ASSERT_EQUAL_64(-1, x13); - ASSERT_EQUAL_64(0x4000000000000000UL, x14); - ASSERT_EQUAL_64(0x8000000000000000UL, x15); + CHECK_EQUAL_64(-2, x8); + CHECK_EQUAL_64(-1, x9); + CHECK_EQUAL_64(0, x10); + CHECK_EQUAL_64(1, x11); + CHECK_EQUAL_64(2, x12); + CHECK_EQUAL_64(-1, x13); + CHECK_EQUAL_64(0x4000000000000000UL, x14); + CHECK_EQUAL_64(0x8000000000000000UL, x15); TEARDOWN(); } @@ -4542,19 +4740,19 @@ TEST(lslv) { RUN(); - ASSERT_EQUAL_64(value, x0); - ASSERT_EQUAL_64(value << (shift[0] & 63), x16); - ASSERT_EQUAL_64(value << (shift[1] & 63), x17); - ASSERT_EQUAL_64(value << (shift[2] & 63), x18); - ASSERT_EQUAL_64(value << (shift[3] & 63), x19); - ASSERT_EQUAL_64(value << (shift[4] & 63), x20); - ASSERT_EQUAL_64(value << (shift[5] & 63), x21); - ASSERT_EQUAL_32(value << (shift[0] & 31), w22); - ASSERT_EQUAL_32(value << (shift[1] & 31), w23); - ASSERT_EQUAL_32(value << (shift[2] & 31), w24); - ASSERT_EQUAL_32(value << (shift[3] & 31), w25); - ASSERT_EQUAL_32(value << (shift[4] & 31), w26); - ASSERT_EQUAL_32(value << (shift[5] & 31), w27); + CHECK_EQUAL_64(value, x0); + CHECK_EQUAL_64(value << (shift[0] & 63), x16); + CHECK_EQUAL_64(value << (shift[1] & 63), x17); + CHECK_EQUAL_64(value << (shift[2] & 63), x18); + CHECK_EQUAL_64(value << (shift[3] & 63), x19); + CHECK_EQUAL_64(value << (shift[4] & 63), x20); + CHECK_EQUAL_64(value << (shift[5] & 63), x21); + CHECK_EQUAL_32(value << (shift[0] & 31), w22); + CHECK_EQUAL_32(value << (shift[1] & 31), w23); + CHECK_EQUAL_32(value << (shift[2] & 31), w24); + CHECK_EQUAL_32(value << (shift[3] & 31), w25); + CHECK_EQUAL_32(value << (shift[4] & 31), w26); + CHECK_EQUAL_32(value << (shift[5] & 31), w27); TEARDOWN(); } @@ -4595,21 +4793,21 @@ TEST(lsrv) { RUN(); - ASSERT_EQUAL_64(value, x0); - ASSERT_EQUAL_64(value >> (shift[0] & 63), x16); - ASSERT_EQUAL_64(value >> (shift[1] & 63), x17); - ASSERT_EQUAL_64(value >> (shift[2] & 63), x18); - ASSERT_EQUAL_64(value >> (shift[3] & 63), x19); - ASSERT_EQUAL_64(value >> (shift[4] & 63), x20); - ASSERT_EQUAL_64(value >> (shift[5] & 63), x21); + CHECK_EQUAL_64(value, x0); + CHECK_EQUAL_64(value >> (shift[0] & 63), x16); + CHECK_EQUAL_64(value >> (shift[1] & 63), x17); + CHECK_EQUAL_64(value >> (shift[2] & 63), x18); + CHECK_EQUAL_64(value >> (shift[3] & 63), x19); + CHECK_EQUAL_64(value >> (shift[4] & 63), x20); + CHECK_EQUAL_64(value >> (shift[5] & 63), x21); value &= 0xffffffffUL; - ASSERT_EQUAL_32(value >> (shift[0] & 31), w22); - ASSERT_EQUAL_32(value >> (shift[1] & 31), w23); - ASSERT_EQUAL_32(value >> (shift[2] & 31), w24); - ASSERT_EQUAL_32(value >> (shift[3] & 31), w25); - ASSERT_EQUAL_32(value >> (shift[4] & 31), w26); - ASSERT_EQUAL_32(value >> (shift[5] & 31), w27); + CHECK_EQUAL_32(value >> (shift[0] & 31), w22); + CHECK_EQUAL_32(value >> (shift[1] & 31), w23); + CHECK_EQUAL_32(value >> (shift[2] & 31), w24); + CHECK_EQUAL_32(value >> (shift[3] & 31), w25); + CHECK_EQUAL_32(value >> (shift[4] & 31), w26); + CHECK_EQUAL_32(value >> (shift[5] & 31), w27); TEARDOWN(); } @@ -4650,21 +4848,21 @@ TEST(asrv) { RUN(); - ASSERT_EQUAL_64(value, x0); - ASSERT_EQUAL_64(value >> (shift[0] & 63), x16); - ASSERT_EQUAL_64(value >> (shift[1] & 63), x17); - ASSERT_EQUAL_64(value >> (shift[2] & 63), x18); - ASSERT_EQUAL_64(value >> (shift[3] & 63), x19); - ASSERT_EQUAL_64(value >> (shift[4] & 63), x20); - ASSERT_EQUAL_64(value >> (shift[5] & 63), x21); + CHECK_EQUAL_64(value, x0); + CHECK_EQUAL_64(value >> (shift[0] & 63), x16); + CHECK_EQUAL_64(value >> (shift[1] & 63), x17); + CHECK_EQUAL_64(value >> (shift[2] & 63), x18); + CHECK_EQUAL_64(value >> (shift[3] & 63), x19); + CHECK_EQUAL_64(value >> (shift[4] & 63), x20); + CHECK_EQUAL_64(value >> (shift[5] & 63), x21); int32_t value32 = static_cast<int32_t>(value & 0xffffffffUL); - ASSERT_EQUAL_32(value32 >> (shift[0] & 31), w22); - ASSERT_EQUAL_32(value32 >> (shift[1] & 31), w23); - ASSERT_EQUAL_32(value32 >> (shift[2] & 31), w24); - ASSERT_EQUAL_32(value32 >> (shift[3] & 31), w25); - ASSERT_EQUAL_32(value32 >> (shift[4] & 31), w26); - ASSERT_EQUAL_32(value32 >> (shift[5] & 31), w27); + CHECK_EQUAL_32(value32 >> (shift[0] & 31), w22); + CHECK_EQUAL_32(value32 >> (shift[1] & 31), w23); + CHECK_EQUAL_32(value32 >> (shift[2] & 31), w24); + CHECK_EQUAL_32(value32 >> (shift[3] & 31), w25); + CHECK_EQUAL_32(value32 >> (shift[4] & 31), w26); + CHECK_EQUAL_32(value32 >> (shift[5] & 31), w27); TEARDOWN(); } @@ -4705,19 +4903,19 @@ TEST(rorv) { RUN(); - ASSERT_EQUAL_64(value, x0); - ASSERT_EQUAL_64(0xf0123456789abcdeUL, x16); - ASSERT_EQUAL_64(0xef0123456789abcdUL, x17); - ASSERT_EQUAL_64(0xdef0123456789abcUL, x18); - ASSERT_EQUAL_64(0xcdef0123456789abUL, x19); - ASSERT_EQUAL_64(0xabcdef0123456789UL, x20); - ASSERT_EQUAL_64(0x789abcdef0123456UL, x21); - ASSERT_EQUAL_32(0xf89abcde, w22); - ASSERT_EQUAL_32(0xef89abcd, w23); - ASSERT_EQUAL_32(0xdef89abc, w24); - ASSERT_EQUAL_32(0xcdef89ab, w25); - ASSERT_EQUAL_32(0xabcdef89, w26); - ASSERT_EQUAL_32(0xf89abcde, w27); + CHECK_EQUAL_64(value, x0); + CHECK_EQUAL_64(0xf0123456789abcdeUL, x16); + CHECK_EQUAL_64(0xef0123456789abcdUL, x17); + CHECK_EQUAL_64(0xdef0123456789abcUL, x18); + CHECK_EQUAL_64(0xcdef0123456789abUL, x19); + CHECK_EQUAL_64(0xabcdef0123456789UL, x20); + CHECK_EQUAL_64(0x789abcdef0123456UL, x21); + CHECK_EQUAL_32(0xf89abcde, w22); + CHECK_EQUAL_32(0xef89abcd, w23); + CHECK_EQUAL_32(0xdef89abc, w24); + CHECK_EQUAL_32(0xcdef89ab, w25); + CHECK_EQUAL_32(0xabcdef89, w26); + CHECK_EQUAL_32(0xf89abcde, w27); TEARDOWN(); } @@ -4751,14 +4949,14 @@ TEST(bfm) { RUN(); - ASSERT_EQUAL_64(0x88888888888889abL, x10); - ASSERT_EQUAL_64(0x8888cdef88888888L, x11); + CHECK_EQUAL_64(0x88888888888889abL, x10); + CHECK_EQUAL_64(0x8888cdef88888888L, x11); - ASSERT_EQUAL_32(0x888888ab, w20); - ASSERT_EQUAL_32(0x88cdef88, w21); + CHECK_EQUAL_32(0x888888ab, w20); + CHECK_EQUAL_32(0x88cdef88, w21); - ASSERT_EQUAL_64(0x8888888888ef8888L, x12); - ASSERT_EQUAL_64(0x88888888888888abL, x13); + CHECK_EQUAL_64(0x8888888888ef8888L, x12); + CHECK_EQUAL_64(0x88888888888888abL, x13); TEARDOWN(); } @@ -4800,28 +4998,28 @@ TEST(sbfm) { RUN(); - ASSERT_EQUAL_64(0xffffffffffff89abL, x10); - ASSERT_EQUAL_64(0xffffcdef00000000L, x11); - ASSERT_EQUAL_64(0x4567L, x12); - ASSERT_EQUAL_64(0x789abcdef0000L, x13); + CHECK_EQUAL_64(0xffffffffffff89abL, x10); + CHECK_EQUAL_64(0xffffcdef00000000L, x11); + CHECK_EQUAL_64(0x4567L, x12); + CHECK_EQUAL_64(0x789abcdef0000L, x13); - ASSERT_EQUAL_32(0xffffffab, w14); - ASSERT_EQUAL_32(0xffcdef00, w15); - ASSERT_EQUAL_32(0x54, w16); - ASSERT_EQUAL_32(0x00321000, w17); + CHECK_EQUAL_32(0xffffffab, w14); + CHECK_EQUAL_32(0xffcdef00, w15); + CHECK_EQUAL_32(0x54, w16); + CHECK_EQUAL_32(0x00321000, w17); - ASSERT_EQUAL_64(0x01234567L, x18); - ASSERT_EQUAL_64(0xfffffffffedcba98L, x19); - ASSERT_EQUAL_64(0xffffffffffcdef00L, x20); - ASSERT_EQUAL_64(0x321000L, x21); - ASSERT_EQUAL_64(0xffffffffffffabcdL, x22); - ASSERT_EQUAL_64(0x5432L, x23); - ASSERT_EQUAL_64(0xffffffffffffffefL, x24); - ASSERT_EQUAL_64(0x10, x25); - ASSERT_EQUAL_64(0xffffffffffffcdefL, x26); - ASSERT_EQUAL_64(0x3210, x27); - ASSERT_EQUAL_64(0xffffffff89abcdefL, x28); - ASSERT_EQUAL_64(0x76543210, x29); + CHECK_EQUAL_64(0x01234567L, x18); + CHECK_EQUAL_64(0xfffffffffedcba98L, x19); + CHECK_EQUAL_64(0xffffffffffcdef00L, x20); + CHECK_EQUAL_64(0x321000L, x21); + CHECK_EQUAL_64(0xffffffffffffabcdL, x22); + CHECK_EQUAL_64(0x5432L, x23); + CHECK_EQUAL_64(0xffffffffffffffefL, x24); + CHECK_EQUAL_64(0x10, x25); + CHECK_EQUAL_64(0xffffffffffffcdefL, x26); + CHECK_EQUAL_64(0x3210, x27); + CHECK_EQUAL_64(0xffffffff89abcdefL, x28); + CHECK_EQUAL_64(0x76543210, x29); TEARDOWN(); } @@ -4861,24 +5059,24 @@ TEST(ubfm) { RUN(); - ASSERT_EQUAL_64(0x00000000000089abL, x10); - ASSERT_EQUAL_64(0x0000cdef00000000L, x11); - ASSERT_EQUAL_64(0x4567L, x12); - ASSERT_EQUAL_64(0x789abcdef0000L, x13); + CHECK_EQUAL_64(0x00000000000089abL, x10); + CHECK_EQUAL_64(0x0000cdef00000000L, x11); + CHECK_EQUAL_64(0x4567L, x12); + CHECK_EQUAL_64(0x789abcdef0000L, x13); - ASSERT_EQUAL_32(0x000000ab, w25); - ASSERT_EQUAL_32(0x00cdef00, w26); - ASSERT_EQUAL_32(0x54, w27); - ASSERT_EQUAL_32(0x00321000, w28); + CHECK_EQUAL_32(0x000000ab, w25); + CHECK_EQUAL_32(0x00cdef00, w26); + CHECK_EQUAL_32(0x54, w27); + CHECK_EQUAL_32(0x00321000, w28); - ASSERT_EQUAL_64(0x8000000000000000L, x15); - ASSERT_EQUAL_64(0x0123456789abcdefL, x16); - ASSERT_EQUAL_64(0x01234567L, x17); - ASSERT_EQUAL_64(0xcdef00L, x18); - ASSERT_EQUAL_64(0xabcdL, x19); - ASSERT_EQUAL_64(0xefL, x20); - ASSERT_EQUAL_64(0xcdefL, x21); - ASSERT_EQUAL_64(0x89abcdefL, x22); + CHECK_EQUAL_64(0x8000000000000000L, x15); + CHECK_EQUAL_64(0x0123456789abcdefL, x16); + CHECK_EQUAL_64(0x01234567L, x17); + CHECK_EQUAL_64(0xcdef00L, x18); + CHECK_EQUAL_64(0xabcdL, x19); + CHECK_EQUAL_64(0xefL, x20); + CHECK_EQUAL_64(0xcdefL, x21); + CHECK_EQUAL_64(0x89abcdefL, x22); TEARDOWN(); } @@ -4893,26 +5091,30 @@ TEST(extr) { __ Mov(x2, 0xfedcba9876543210L); __ Extr(w10, w1, w2, 0); - __ Extr(w11, w1, w2, 1); - __ Extr(x12, x2, x1, 2); + __ Extr(x11, x1, x2, 0); + __ Extr(w12, w1, w2, 1); + __ Extr(x13, x2, x1, 2); - __ Ror(w13, w1, 0); - __ Ror(w14, w2, 17); - __ Ror(w15, w1, 31); - __ Ror(x18, x2, 1); - __ Ror(x19, x1, 63); + __ Ror(w20, w1, 0); + __ Ror(x21, x1, 0); + __ Ror(w22, w2, 17); + __ Ror(w23, w1, 31); + __ Ror(x24, x2, 1); + __ Ror(x25, x1, 63); END(); RUN(); - ASSERT_EQUAL_64(0x76543210, x10); - ASSERT_EQUAL_64(0xbb2a1908, x11); - ASSERT_EQUAL_64(0x0048d159e26af37bUL, x12); - ASSERT_EQUAL_64(0x89abcdef, x13); - ASSERT_EQUAL_64(0x19083b2a, x14); - ASSERT_EQUAL_64(0x13579bdf, x15); - ASSERT_EQUAL_64(0x7f6e5d4c3b2a1908UL, x18); - ASSERT_EQUAL_64(0x02468acf13579bdeUL, x19); + CHECK_EQUAL_64(0x76543210, x10); + CHECK_EQUAL_64(0xfedcba9876543210L, x11); + CHECK_EQUAL_64(0xbb2a1908, x12); + CHECK_EQUAL_64(0x0048d159e26af37bUL, x13); + CHECK_EQUAL_64(0x89abcdef, x20); + CHECK_EQUAL_64(0x0123456789abcdefL, x21); + CHECK_EQUAL_64(0x19083b2a, x22); + CHECK_EQUAL_64(0x13579bdf, x23); + CHECK_EQUAL_64(0x7f6e5d4c3b2a1908UL, x24); + CHECK_EQUAL_64(0x02468acf13579bdeUL, x25); TEARDOWN(); } @@ -4935,14 +5137,14 @@ TEST(fmov_imm) { RUN(); - ASSERT_EQUAL_FP32(1.0, s11); - ASSERT_EQUAL_FP64(-13.0, d22); - ASSERT_EQUAL_FP32(255.0, s1); - ASSERT_EQUAL_FP64(12.34567, d2); - ASSERT_EQUAL_FP32(0.0, s3); - ASSERT_EQUAL_FP64(0.0, d4); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d6); + CHECK_EQUAL_FP32(1.0, s11); + CHECK_EQUAL_FP64(-13.0, d22); + CHECK_EQUAL_FP32(255.0, s1); + CHECK_EQUAL_FP64(12.34567, d2); + CHECK_EQUAL_FP32(0.0, s3); + CHECK_EQUAL_FP64(0.0, d4); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s5); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d6); TEARDOWN(); } @@ -4967,13 +5169,13 @@ TEST(fmov_reg) { RUN(); - ASSERT_EQUAL_32(float_to_rawbits(1.0), w10); - ASSERT_EQUAL_FP32(1.0, s30); - ASSERT_EQUAL_FP32(1.0, s5); - ASSERT_EQUAL_64(double_to_rawbits(-13.0), x1); - ASSERT_EQUAL_FP64(-13.0, d2); - ASSERT_EQUAL_FP64(-13.0, d4); - ASSERT_EQUAL_FP32(rawbits_to_float(0x89abcdef), s6); + CHECK_EQUAL_32(float_to_rawbits(1.0), w10); + CHECK_EQUAL_FP32(1.0, s30); + CHECK_EQUAL_FP32(1.0, s5); + CHECK_EQUAL_64(double_to_rawbits(-13.0), x1); + CHECK_EQUAL_FP64(-13.0, d2); + CHECK_EQUAL_FP64(-13.0, d4); + CHECK_EQUAL_FP32(rawbits_to_float(0x89abcdef), s6); TEARDOWN(); } @@ -5017,20 +5219,20 @@ TEST(fadd) { RUN(); - ASSERT_EQUAL_FP32(4.25, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(1.0, s2); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s3); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s4); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6); - ASSERT_EQUAL_FP64(0.25, d7); - ASSERT_EQUAL_FP64(2.25, d8); - ASSERT_EQUAL_FP64(2.25, d9); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d10); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d11); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP32(4.25, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(1.0, s2); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s3); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s4); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s5); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s6); + CHECK_EQUAL_FP64(0.25, d7); + CHECK_EQUAL_FP64(2.25, d8); + CHECK_EQUAL_FP64(2.25, d9); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d10); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d11); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); TEARDOWN(); } @@ -5074,20 +5276,20 @@ TEST(fsub) { RUN(); - ASSERT_EQUAL_FP32(2.25, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(-1.0, s2); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6); - ASSERT_EQUAL_FP64(-4.25, d7); - ASSERT_EQUAL_FP64(-2.25, d8); - ASSERT_EQUAL_FP64(-2.25, d9); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP32(2.25, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(-1.0, s2); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s3); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s4); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s5); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s6); + CHECK_EQUAL_FP64(-4.25, d7); + CHECK_EQUAL_FP64(-2.25, d8); + CHECK_EQUAL_FP64(-2.25, d9); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d10); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d11); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); TEARDOWN(); } @@ -5132,20 +5334,20 @@ TEST(fmul) { RUN(); - ASSERT_EQUAL_FP32(6.5, s0); - ASSERT_EQUAL_FP32(0.0, s1); - ASSERT_EQUAL_FP32(0.0, s2); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s3); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s4); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6); - ASSERT_EQUAL_FP64(-4.5, d7); - ASSERT_EQUAL_FP64(0.0, d8); - ASSERT_EQUAL_FP64(0.0, d9); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP32(6.5, s0); + CHECK_EQUAL_FP32(0.0, s1); + CHECK_EQUAL_FP32(0.0, s2); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s3); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s4); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s5); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s6); + CHECK_EQUAL_FP64(-4.5, d7); + CHECK_EQUAL_FP64(0.0, d8); + CHECK_EQUAL_FP64(0.0, d9); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d10); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d11); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); TEARDOWN(); } @@ -5168,10 +5370,10 @@ static void FmaddFmsubHelper(double n, double m, double a, END(); RUN(); - ASSERT_EQUAL_FP64(fmadd, d28); - ASSERT_EQUAL_FP64(fmsub, d29); - ASSERT_EQUAL_FP64(fnmadd, d30); - ASSERT_EQUAL_FP64(fnmsub, d31); + CHECK_EQUAL_FP64(fmadd, d28); + CHECK_EQUAL_FP64(fmsub, d29); + CHECK_EQUAL_FP64(fnmadd, d30); + CHECK_EQUAL_FP64(fnmsub, d31); TEARDOWN(); } @@ -5236,10 +5438,10 @@ static void FmaddFmsubHelper(float n, float m, float a, END(); RUN(); - ASSERT_EQUAL_FP32(fmadd, s28); - ASSERT_EQUAL_FP32(fmsub, s29); - ASSERT_EQUAL_FP32(fnmadd, s30); - ASSERT_EQUAL_FP32(fnmsub, s31); + CHECK_EQUAL_FP32(fmadd, s28); + CHECK_EQUAL_FP32(fmsub, s29); + CHECK_EQUAL_FP32(fnmadd, s30); + CHECK_EQUAL_FP32(fnmsub, s31); TEARDOWN(); } @@ -5295,12 +5497,12 @@ TEST(fmadd_fmsub_double_nans) { double q1 = rawbits_to_double(0x7ffaaaaa11111111); double q2 = rawbits_to_double(0x7ffaaaaa22222222); double qa = rawbits_to_double(0x7ffaaaaaaaaaaaaa); - ASSERT(IsSignallingNaN(s1)); - ASSERT(IsSignallingNaN(s2)); - ASSERT(IsSignallingNaN(sa)); - ASSERT(IsQuietNaN(q1)); - ASSERT(IsQuietNaN(q2)); - ASSERT(IsQuietNaN(qa)); + DCHECK(IsSignallingNaN(s1)); + DCHECK(IsSignallingNaN(s2)); + DCHECK(IsSignallingNaN(sa)); + DCHECK(IsQuietNaN(q1)); + DCHECK(IsQuietNaN(q2)); + DCHECK(IsQuietNaN(qa)); // The input NaNs after passing through ProcessNaN. double s1_proc = rawbits_to_double(0x7ffd555511111111); @@ -5309,22 +5511,22 @@ TEST(fmadd_fmsub_double_nans) { double q1_proc = q1; double q2_proc = q2; double qa_proc = qa; - ASSERT(IsQuietNaN(s1_proc)); - ASSERT(IsQuietNaN(s2_proc)); - ASSERT(IsQuietNaN(sa_proc)); - ASSERT(IsQuietNaN(q1_proc)); - ASSERT(IsQuietNaN(q2_proc)); - ASSERT(IsQuietNaN(qa_proc)); + DCHECK(IsQuietNaN(s1_proc)); + DCHECK(IsQuietNaN(s2_proc)); + DCHECK(IsQuietNaN(sa_proc)); + DCHECK(IsQuietNaN(q1_proc)); + DCHECK(IsQuietNaN(q2_proc)); + DCHECK(IsQuietNaN(qa_proc)); // Negated NaNs as it would be done on ARMv8 hardware. double s1_proc_neg = rawbits_to_double(0xfffd555511111111); double sa_proc_neg = rawbits_to_double(0xfffd5555aaaaaaaa); double q1_proc_neg = rawbits_to_double(0xfffaaaaa11111111); double qa_proc_neg = rawbits_to_double(0xfffaaaaaaaaaaaaa); - ASSERT(IsQuietNaN(s1_proc_neg)); - ASSERT(IsQuietNaN(sa_proc_neg)); - ASSERT(IsQuietNaN(q1_proc_neg)); - ASSERT(IsQuietNaN(qa_proc_neg)); + DCHECK(IsQuietNaN(s1_proc_neg)); + DCHECK(IsQuietNaN(sa_proc_neg)); + DCHECK(IsQuietNaN(q1_proc_neg)); + DCHECK(IsQuietNaN(qa_proc_neg)); // Quiet NaNs are propagated. FmaddFmsubHelper(q1, 0, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); @@ -5378,12 +5580,12 @@ TEST(fmadd_fmsub_float_nans) { float q1 = rawbits_to_float(0x7fea1111); float q2 = rawbits_to_float(0x7fea2222); float qa = rawbits_to_float(0x7feaaaaa); - ASSERT(IsSignallingNaN(s1)); - ASSERT(IsSignallingNaN(s2)); - ASSERT(IsSignallingNaN(sa)); - ASSERT(IsQuietNaN(q1)); - ASSERT(IsQuietNaN(q2)); - ASSERT(IsQuietNaN(qa)); + DCHECK(IsSignallingNaN(s1)); + DCHECK(IsSignallingNaN(s2)); + DCHECK(IsSignallingNaN(sa)); + DCHECK(IsQuietNaN(q1)); + DCHECK(IsQuietNaN(q2)); + DCHECK(IsQuietNaN(qa)); // The input NaNs after passing through ProcessNaN. float s1_proc = rawbits_to_float(0x7fd51111); @@ -5392,22 +5594,22 @@ TEST(fmadd_fmsub_float_nans) { float q1_proc = q1; float q2_proc = q2; float qa_proc = qa; - ASSERT(IsQuietNaN(s1_proc)); - ASSERT(IsQuietNaN(s2_proc)); - ASSERT(IsQuietNaN(sa_proc)); - ASSERT(IsQuietNaN(q1_proc)); - ASSERT(IsQuietNaN(q2_proc)); - ASSERT(IsQuietNaN(qa_proc)); + DCHECK(IsQuietNaN(s1_proc)); + DCHECK(IsQuietNaN(s2_proc)); + DCHECK(IsQuietNaN(sa_proc)); + DCHECK(IsQuietNaN(q1_proc)); + DCHECK(IsQuietNaN(q2_proc)); + DCHECK(IsQuietNaN(qa_proc)); // Negated NaNs as it would be done on ARMv8 hardware. float s1_proc_neg = rawbits_to_float(0xffd51111); float sa_proc_neg = rawbits_to_float(0xffd5aaaa); float q1_proc_neg = rawbits_to_float(0xffea1111); float qa_proc_neg = rawbits_to_float(0xffeaaaaa); - ASSERT(IsQuietNaN(s1_proc_neg)); - ASSERT(IsQuietNaN(sa_proc_neg)); - ASSERT(IsQuietNaN(q1_proc_neg)); - ASSERT(IsQuietNaN(qa_proc_neg)); + DCHECK(IsQuietNaN(s1_proc_neg)); + DCHECK(IsQuietNaN(sa_proc_neg)); + DCHECK(IsQuietNaN(q1_proc_neg)); + DCHECK(IsQuietNaN(qa_proc_neg)); // Quiet NaNs are propagated. FmaddFmsubHelper(q1, 0, 0, q1_proc, q1_proc_neg, q1_proc_neg, q1_proc); @@ -5491,20 +5693,20 @@ TEST(fdiv) { RUN(); - ASSERT_EQUAL_FP32(1.625f, s0); - ASSERT_EQUAL_FP32(1.0f, s1); - ASSERT_EQUAL_FP32(-0.0f, s2); - ASSERT_EQUAL_FP32(0.0f, s3); - ASSERT_EQUAL_FP32(-0.0f, s4); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s5); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6); - ASSERT_EQUAL_FP64(-1.125, d7); - ASSERT_EQUAL_FP64(0.0, d8); - ASSERT_EQUAL_FP64(-0.0, d9); - ASSERT_EQUAL_FP64(0.0, d10); - ASSERT_EQUAL_FP64(-0.0, d11); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP32(1.625f, s0); + CHECK_EQUAL_FP32(1.0f, s1); + CHECK_EQUAL_FP32(-0.0f, s2); + CHECK_EQUAL_FP32(0.0f, s3); + CHECK_EQUAL_FP32(-0.0f, s4); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s5); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s6); + CHECK_EQUAL_FP64(-1.125, d7); + CHECK_EQUAL_FP64(0.0, d8); + CHECK_EQUAL_FP64(-0.0, d9); + CHECK_EQUAL_FP64(0.0, d10); + CHECK_EQUAL_FP64(-0.0, d11); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); TEARDOWN(); } @@ -5607,10 +5809,10 @@ static void FminFmaxDoubleHelper(double n, double m, double min, double max, RUN(); - ASSERT_EQUAL_FP64(min, d28); - ASSERT_EQUAL_FP64(max, d29); - ASSERT_EQUAL_FP64(minnm, d30); - ASSERT_EQUAL_FP64(maxnm, d31); + CHECK_EQUAL_FP64(min, d28); + CHECK_EQUAL_FP64(max, d29); + CHECK_EQUAL_FP64(minnm, d30); + CHECK_EQUAL_FP64(maxnm, d31); TEARDOWN(); } @@ -5625,10 +5827,10 @@ TEST(fmax_fmin_d) { double snan_processed = rawbits_to_double(0x7ffd555512345678); double qnan_processed = qnan; - ASSERT(IsSignallingNaN(snan)); - ASSERT(IsQuietNaN(qnan)); - ASSERT(IsQuietNaN(snan_processed)); - ASSERT(IsQuietNaN(qnan_processed)); + DCHECK(IsSignallingNaN(snan)); + DCHECK(IsQuietNaN(qnan)); + DCHECK(IsQuietNaN(snan_processed)); + DCHECK(IsQuietNaN(qnan_processed)); // Bootstrap tests. FminFmaxDoubleHelper(0, 0, 0, 0, 0, 0); @@ -5692,10 +5894,10 @@ static void FminFmaxFloatHelper(float n, float m, float min, float max, RUN(); - ASSERT_EQUAL_FP32(min, s28); - ASSERT_EQUAL_FP32(max, s29); - ASSERT_EQUAL_FP32(minnm, s30); - ASSERT_EQUAL_FP32(maxnm, s31); + CHECK_EQUAL_FP32(min, s28); + CHECK_EQUAL_FP32(max, s29); + CHECK_EQUAL_FP32(minnm, s30); + CHECK_EQUAL_FP32(maxnm, s31); TEARDOWN(); } @@ -5710,10 +5912,10 @@ TEST(fmax_fmin_s) { float snan_processed = rawbits_to_float(0x7fd51234); float qnan_processed = qnan; - ASSERT(IsSignallingNaN(snan)); - ASSERT(IsQuietNaN(qnan)); - ASSERT(IsQuietNaN(snan_processed)); - ASSERT(IsQuietNaN(qnan_processed)); + DCHECK(IsSignallingNaN(snan)); + DCHECK(IsQuietNaN(qnan)); + DCHECK(IsQuietNaN(snan_processed)); + DCHECK(IsQuietNaN(qnan_processed)); // Bootstrap tests. FminFmaxFloatHelper(0, 0, 0, 0, 0, 0); @@ -5815,16 +6017,16 @@ TEST(fccmp) { RUN(); - ASSERT_EQUAL_32(ZCFlag, w0); - ASSERT_EQUAL_32(VFlag, w1); - ASSERT_EQUAL_32(NFlag, w2); - ASSERT_EQUAL_32(CVFlag, w3); - ASSERT_EQUAL_32(ZCFlag, w4); - ASSERT_EQUAL_32(ZVFlag, w5); - ASSERT_EQUAL_32(CFlag, w6); - ASSERT_EQUAL_32(NFlag, w7); - ASSERT_EQUAL_32(ZCFlag, w8); - ASSERT_EQUAL_32(ZCFlag, w9); + CHECK_EQUAL_32(ZCFlag, w0); + CHECK_EQUAL_32(VFlag, w1); + CHECK_EQUAL_32(NFlag, w2); + CHECK_EQUAL_32(CVFlag, w3); + CHECK_EQUAL_32(ZCFlag, w4); + CHECK_EQUAL_32(ZVFlag, w5); + CHECK_EQUAL_32(CFlag, w6); + CHECK_EQUAL_32(NFlag, w7); + CHECK_EQUAL_32(ZCFlag, w8); + CHECK_EQUAL_32(ZCFlag, w9); TEARDOWN(); } @@ -5894,20 +6096,20 @@ TEST(fcmp) { RUN(); - ASSERT_EQUAL_32(ZCFlag, w0); - ASSERT_EQUAL_32(NFlag, w1); - ASSERT_EQUAL_32(CFlag, w2); - ASSERT_EQUAL_32(CVFlag, w3); - ASSERT_EQUAL_32(CVFlag, w4); - ASSERT_EQUAL_32(ZCFlag, w5); - ASSERT_EQUAL_32(NFlag, w6); - ASSERT_EQUAL_32(ZCFlag, w10); - ASSERT_EQUAL_32(NFlag, w11); - ASSERT_EQUAL_32(CFlag, w12); - ASSERT_EQUAL_32(CVFlag, w13); - ASSERT_EQUAL_32(CVFlag, w14); - ASSERT_EQUAL_32(ZCFlag, w15); - ASSERT_EQUAL_32(NFlag, w16); + CHECK_EQUAL_32(ZCFlag, w0); + CHECK_EQUAL_32(NFlag, w1); + CHECK_EQUAL_32(CFlag, w2); + CHECK_EQUAL_32(CVFlag, w3); + CHECK_EQUAL_32(CVFlag, w4); + CHECK_EQUAL_32(ZCFlag, w5); + CHECK_EQUAL_32(NFlag, w6); + CHECK_EQUAL_32(ZCFlag, w10); + CHECK_EQUAL_32(NFlag, w11); + CHECK_EQUAL_32(CFlag, w12); + CHECK_EQUAL_32(CVFlag, w13); + CHECK_EQUAL_32(CVFlag, w14); + CHECK_EQUAL_32(ZCFlag, w15); + CHECK_EQUAL_32(NFlag, w16); TEARDOWN(); } @@ -5935,12 +6137,12 @@ TEST(fcsel) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(2.0, s1); - ASSERT_EQUAL_FP64(3.0, d2); - ASSERT_EQUAL_FP64(4.0, d3); - ASSERT_EQUAL_FP32(1.0, s4); - ASSERT_EQUAL_FP64(3.0, d5); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(2.0, s1); + CHECK_EQUAL_FP64(3.0, d2); + CHECK_EQUAL_FP64(4.0, d3); + CHECK_EQUAL_FP32(1.0, s4); + CHECK_EQUAL_FP64(3.0, d5); TEARDOWN(); } @@ -5974,18 +6176,18 @@ TEST(fneg) { RUN(); - ASSERT_EQUAL_FP32(-1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(-0.0, s2); - ASSERT_EQUAL_FP32(0.0, s3); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s4); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); - ASSERT_EQUAL_FP64(-1.0, d6); - ASSERT_EQUAL_FP64(1.0, d7); - ASSERT_EQUAL_FP64(-0.0, d8); - ASSERT_EQUAL_FP64(0.0, d9); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d10); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d11); + CHECK_EQUAL_FP32(-1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(-0.0, s2); + CHECK_EQUAL_FP32(0.0, s3); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s4); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s5); + CHECK_EQUAL_FP64(-1.0, d6); + CHECK_EQUAL_FP64(1.0, d7); + CHECK_EQUAL_FP64(-0.0, d8); + CHECK_EQUAL_FP64(0.0, d9); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d10); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d11); TEARDOWN(); } @@ -6015,14 +6217,14 @@ TEST(fabs) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(0.0, s2); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s3); - ASSERT_EQUAL_FP64(1.0, d4); - ASSERT_EQUAL_FP64(1.0, d5); - ASSERT_EQUAL_FP64(0.0, d6); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d7); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(0.0, s2); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s3); + CHECK_EQUAL_FP64(1.0, d4); + CHECK_EQUAL_FP64(1.0, d5); + CHECK_EQUAL_FP64(0.0, d6); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d7); TEARDOWN(); } @@ -6066,20 +6268,20 @@ TEST(fsqrt) { RUN(); - ASSERT_EQUAL_FP32(0.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(0.5, s2); - ASSERT_EQUAL_FP32(256.0, s3); - ASSERT_EQUAL_FP32(-0.0, s4); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s5); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s6); - ASSERT_EQUAL_FP64(0.0, d7); - ASSERT_EQUAL_FP64(1.0, d8); - ASSERT_EQUAL_FP64(0.5, d9); - ASSERT_EQUAL_FP64(65536.0, d10); - ASSERT_EQUAL_FP64(-0.0, d11); - ASSERT_EQUAL_FP64(kFP32PositiveInfinity, d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP32(0.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(0.5, s2); + CHECK_EQUAL_FP32(256.0, s3); + CHECK_EQUAL_FP32(-0.0, s4); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s5); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s6); + CHECK_EQUAL_FP64(0.0, d7); + CHECK_EQUAL_FP64(1.0, d8); + CHECK_EQUAL_FP64(0.5, d9); + CHECK_EQUAL_FP64(65536.0, d10); + CHECK_EQUAL_FP64(-0.0, d11); + CHECK_EQUAL_FP64(kFP32PositiveInfinity, d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); TEARDOWN(); } @@ -6145,30 +6347,30 @@ TEST(frinta) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(2.0, s2); - ASSERT_EQUAL_FP32(2.0, s3); - ASSERT_EQUAL_FP32(3.0, s4); - ASSERT_EQUAL_FP32(-2.0, s5); - ASSERT_EQUAL_FP32(-3.0, s6); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); - ASSERT_EQUAL_FP32(0.0, s9); - ASSERT_EQUAL_FP32(-0.0, s10); - ASSERT_EQUAL_FP32(-0.0, s11); - ASSERT_EQUAL_FP64(1.0, d12); - ASSERT_EQUAL_FP64(1.0, d13); - ASSERT_EQUAL_FP64(2.0, d14); - ASSERT_EQUAL_FP64(2.0, d15); - ASSERT_EQUAL_FP64(3.0, d16); - ASSERT_EQUAL_FP64(-2.0, d17); - ASSERT_EQUAL_FP64(-3.0, d18); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); - ASSERT_EQUAL_FP64(0.0, d21); - ASSERT_EQUAL_FP64(-0.0, d22); - ASSERT_EQUAL_FP64(-0.0, d23); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(2.0, s2); + CHECK_EQUAL_FP32(2.0, s3); + CHECK_EQUAL_FP32(3.0, s4); + CHECK_EQUAL_FP32(-2.0, s5); + CHECK_EQUAL_FP32(-3.0, s6); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8); + CHECK_EQUAL_FP32(0.0, s9); + CHECK_EQUAL_FP32(-0.0, s10); + CHECK_EQUAL_FP32(-0.0, s11); + CHECK_EQUAL_FP64(1.0, d12); + CHECK_EQUAL_FP64(1.0, d13); + CHECK_EQUAL_FP64(2.0, d14); + CHECK_EQUAL_FP64(2.0, d15); + CHECK_EQUAL_FP64(3.0, d16); + CHECK_EQUAL_FP64(-2.0, d17); + CHECK_EQUAL_FP64(-3.0, d18); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20); + CHECK_EQUAL_FP64(0.0, d21); + CHECK_EQUAL_FP64(-0.0, d22); + CHECK_EQUAL_FP64(-0.0, d23); TEARDOWN(); } @@ -6234,30 +6436,30 @@ TEST(frintm) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(1.0, s2); - ASSERT_EQUAL_FP32(1.0, s3); - ASSERT_EQUAL_FP32(2.0, s4); - ASSERT_EQUAL_FP32(-2.0, s5); - ASSERT_EQUAL_FP32(-3.0, s6); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); - ASSERT_EQUAL_FP32(0.0, s9); - ASSERT_EQUAL_FP32(-0.0, s10); - ASSERT_EQUAL_FP32(-1.0, s11); - ASSERT_EQUAL_FP64(1.0, d12); - ASSERT_EQUAL_FP64(1.0, d13); - ASSERT_EQUAL_FP64(1.0, d14); - ASSERT_EQUAL_FP64(1.0, d15); - ASSERT_EQUAL_FP64(2.0, d16); - ASSERT_EQUAL_FP64(-2.0, d17); - ASSERT_EQUAL_FP64(-3.0, d18); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); - ASSERT_EQUAL_FP64(0.0, d21); - ASSERT_EQUAL_FP64(-0.0, d22); - ASSERT_EQUAL_FP64(-1.0, d23); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(1.0, s2); + CHECK_EQUAL_FP32(1.0, s3); + CHECK_EQUAL_FP32(2.0, s4); + CHECK_EQUAL_FP32(-2.0, s5); + CHECK_EQUAL_FP32(-3.0, s6); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8); + CHECK_EQUAL_FP32(0.0, s9); + CHECK_EQUAL_FP32(-0.0, s10); + CHECK_EQUAL_FP32(-1.0, s11); + CHECK_EQUAL_FP64(1.0, d12); + CHECK_EQUAL_FP64(1.0, d13); + CHECK_EQUAL_FP64(1.0, d14); + CHECK_EQUAL_FP64(1.0, d15); + CHECK_EQUAL_FP64(2.0, d16); + CHECK_EQUAL_FP64(-2.0, d17); + CHECK_EQUAL_FP64(-3.0, d18); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20); + CHECK_EQUAL_FP64(0.0, d21); + CHECK_EQUAL_FP64(-0.0, d22); + CHECK_EQUAL_FP64(-1.0, d23); TEARDOWN(); } @@ -6323,30 +6525,30 @@ TEST(frintn) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(2.0, s2); - ASSERT_EQUAL_FP32(2.0, s3); - ASSERT_EQUAL_FP32(2.0, s4); - ASSERT_EQUAL_FP32(-2.0, s5); - ASSERT_EQUAL_FP32(-2.0, s6); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); - ASSERT_EQUAL_FP32(0.0, s9); - ASSERT_EQUAL_FP32(-0.0, s10); - ASSERT_EQUAL_FP32(-0.0, s11); - ASSERT_EQUAL_FP64(1.0, d12); - ASSERT_EQUAL_FP64(1.0, d13); - ASSERT_EQUAL_FP64(2.0, d14); - ASSERT_EQUAL_FP64(2.0, d15); - ASSERT_EQUAL_FP64(2.0, d16); - ASSERT_EQUAL_FP64(-2.0, d17); - ASSERT_EQUAL_FP64(-2.0, d18); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d19); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d20); - ASSERT_EQUAL_FP64(0.0, d21); - ASSERT_EQUAL_FP64(-0.0, d22); - ASSERT_EQUAL_FP64(-0.0, d23); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(2.0, s2); + CHECK_EQUAL_FP32(2.0, s3); + CHECK_EQUAL_FP32(2.0, s4); + CHECK_EQUAL_FP32(-2.0, s5); + CHECK_EQUAL_FP32(-2.0, s6); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8); + CHECK_EQUAL_FP32(0.0, s9); + CHECK_EQUAL_FP32(-0.0, s10); + CHECK_EQUAL_FP32(-0.0, s11); + CHECK_EQUAL_FP64(1.0, d12); + CHECK_EQUAL_FP64(1.0, d13); + CHECK_EQUAL_FP64(2.0, d14); + CHECK_EQUAL_FP64(2.0, d15); + CHECK_EQUAL_FP64(2.0, d16); + CHECK_EQUAL_FP64(-2.0, d17); + CHECK_EQUAL_FP64(-2.0, d18); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20); + CHECK_EQUAL_FP64(0.0, d21); + CHECK_EQUAL_FP64(-0.0, d22); + CHECK_EQUAL_FP64(-0.0, d23); TEARDOWN(); } @@ -6408,28 +6610,28 @@ TEST(frintz) { RUN(); - ASSERT_EQUAL_FP32(1.0, s0); - ASSERT_EQUAL_FP32(1.0, s1); - ASSERT_EQUAL_FP32(1.0, s2); - ASSERT_EQUAL_FP32(1.0, s3); - ASSERT_EQUAL_FP32(2.0, s4); - ASSERT_EQUAL_FP32(-1.0, s5); - ASSERT_EQUAL_FP32(-2.0, s6); - ASSERT_EQUAL_FP32(kFP32PositiveInfinity, s7); - ASSERT_EQUAL_FP32(kFP32NegativeInfinity, s8); - ASSERT_EQUAL_FP32(0.0, s9); - ASSERT_EQUAL_FP32(-0.0, s10); - ASSERT_EQUAL_FP64(1.0, d11); - ASSERT_EQUAL_FP64(1.0, d12); - ASSERT_EQUAL_FP64(1.0, d13); - ASSERT_EQUAL_FP64(1.0, d14); - ASSERT_EQUAL_FP64(2.0, d15); - ASSERT_EQUAL_FP64(-1.0, d16); - ASSERT_EQUAL_FP64(-2.0, d17); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d18); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d19); - ASSERT_EQUAL_FP64(0.0, d20); - ASSERT_EQUAL_FP64(-0.0, d21); + CHECK_EQUAL_FP32(1.0, s0); + CHECK_EQUAL_FP32(1.0, s1); + CHECK_EQUAL_FP32(1.0, s2); + CHECK_EQUAL_FP32(1.0, s3); + CHECK_EQUAL_FP32(2.0, s4); + CHECK_EQUAL_FP32(-1.0, s5); + CHECK_EQUAL_FP32(-2.0, s6); + CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7); + CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8); + CHECK_EQUAL_FP32(0.0, s9); + CHECK_EQUAL_FP32(-0.0, s10); + CHECK_EQUAL_FP64(1.0, d11); + CHECK_EQUAL_FP64(1.0, d12); + CHECK_EQUAL_FP64(1.0, d13); + CHECK_EQUAL_FP64(1.0, d14); + CHECK_EQUAL_FP64(2.0, d15); + CHECK_EQUAL_FP64(-1.0, d16); + CHECK_EQUAL_FP64(-2.0, d17); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d18); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d19); + CHECK_EQUAL_FP64(0.0, d20); + CHECK_EQUAL_FP64(-0.0, d21); TEARDOWN(); } @@ -6475,19 +6677,19 @@ TEST(fcvt_ds) { RUN(); - ASSERT_EQUAL_FP64(1.0f, d0); - ASSERT_EQUAL_FP64(1.1f, d1); - ASSERT_EQUAL_FP64(1.5f, d2); - ASSERT_EQUAL_FP64(1.9f, d3); - ASSERT_EQUAL_FP64(2.5f, d4); - ASSERT_EQUAL_FP64(-1.5f, d5); - ASSERT_EQUAL_FP64(-2.5f, d6); - ASSERT_EQUAL_FP64(kFP64PositiveInfinity, d7); - ASSERT_EQUAL_FP64(kFP64NegativeInfinity, d8); - ASSERT_EQUAL_FP64(0.0f, d9); - ASSERT_EQUAL_FP64(-0.0f, d10); - ASSERT_EQUAL_FP64(FLT_MAX, d11); - ASSERT_EQUAL_FP64(FLT_MIN, d12); + CHECK_EQUAL_FP64(1.0f, d0); + CHECK_EQUAL_FP64(1.1f, d1); + CHECK_EQUAL_FP64(1.5f, d2); + CHECK_EQUAL_FP64(1.9f, d3); + CHECK_EQUAL_FP64(2.5f, d4); + CHECK_EQUAL_FP64(-1.5f, d5); + CHECK_EQUAL_FP64(-2.5f, d6); + CHECK_EQUAL_FP64(kFP64PositiveInfinity, d7); + CHECK_EQUAL_FP64(kFP64NegativeInfinity, d8); + CHECK_EQUAL_FP64(0.0f, d9); + CHECK_EQUAL_FP64(-0.0f, d10); + CHECK_EQUAL_FP64(FLT_MAX, d11); + CHECK_EQUAL_FP64(FLT_MIN, d12); // Check that the NaN payload is preserved according to ARM64 conversion // rules: @@ -6495,8 +6697,8 @@ TEST(fcvt_ds) { // - The top bit of the mantissa is forced to 1 (making it a quiet NaN). // - The remaining mantissa bits are copied until they run out. // - The low-order bits that haven't already been assigned are set to 0. - ASSERT_EQUAL_FP64(rawbits_to_double(0x7ff82468a0000000), d13); - ASSERT_EQUAL_FP64(rawbits_to_double(0x7ff82468a0000000), d14); + CHECK_EQUAL_FP64(rawbits_to_double(0x7ff82468a0000000), d13); + CHECK_EQUAL_FP64(rawbits_to_double(0x7ff82468a0000000), d14); TEARDOWN(); } @@ -6596,8 +6798,8 @@ TEST(fcvt_sd) { float expected = test[i].expected; // We only expect positive input. - ASSERT(std::signbit(in) == 0); - ASSERT(std::signbit(expected) == 0); + DCHECK(std::signbit(in) == 0); + DCHECK(std::signbit(expected) == 0); SETUP(); START(); @@ -6610,8 +6812,8 @@ TEST(fcvt_sd) { END(); RUN(); - ASSERT_EQUAL_FP32(expected, s20); - ASSERT_EQUAL_FP32(-expected, s21); + CHECK_EQUAL_FP32(expected, s20); + CHECK_EQUAL_FP32(-expected, s21); TEARDOWN(); } } @@ -6687,36 +6889,36 @@ TEST(fcvtas) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(3, x2); - ASSERT_EQUAL_64(0xfffffffd, x3); - ASSERT_EQUAL_64(0x7fffffff, x4); - ASSERT_EQUAL_64(0x80000000, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0x80000080, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(3, x10); - ASSERT_EQUAL_64(0xfffffffd, x11); - ASSERT_EQUAL_64(0x7fffffff, x12); - ASSERT_EQUAL_64(0x80000000, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(0x80000001, x15); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(3, x18); - ASSERT_EQUAL_64(0xfffffffffffffffdUL, x19); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x8000000000000000UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x8000008000000000UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(3, x25); - ASSERT_EQUAL_64(0xfffffffffffffffdUL, x26); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x27); - ASSERT_EQUAL_64(0x8000000000000000UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x8000000000000400UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(3, x2); + CHECK_EQUAL_64(0xfffffffd, x3); + CHECK_EQUAL_64(0x7fffffff, x4); + CHECK_EQUAL_64(0x80000000, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0x80000080, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(3, x10); + CHECK_EQUAL_64(0xfffffffd, x11); + CHECK_EQUAL_64(0x7fffffff, x12); + CHECK_EQUAL_64(0x80000000, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(0x80000001, x15); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(3, x18); + CHECK_EQUAL_64(0xfffffffffffffffdUL, x19); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x20); + CHECK_EQUAL_64(0x8000000000000000UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x8000008000000000UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(3, x25); + CHECK_EQUAL_64(0xfffffffffffffffdUL, x26); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x27); + CHECK_EQUAL_64(0x8000000000000000UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x8000000000000400UL, x30); TEARDOWN(); } @@ -6789,34 +6991,34 @@ TEST(fcvtau) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(3, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(0xffffffff, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0xffffff00, x6); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(3, x10); - ASSERT_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0xffffffff, x12); - ASSERT_EQUAL_64(0, x13); - ASSERT_EQUAL_64(0xfffffffe, x14); - ASSERT_EQUAL_64(1, x16); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(3, x18); - ASSERT_EQUAL_64(0, x19); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x20); - ASSERT_EQUAL_64(0, x21); - ASSERT_EQUAL_64(0xffffff0000000000UL, x22); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(3, x25); - ASSERT_EQUAL_64(0, x26); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x27); - ASSERT_EQUAL_64(0, x28); - ASSERT_EQUAL_64(0xfffffffffffff800UL, x29); - ASSERT_EQUAL_64(0xffffffff, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(3, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(0xffffffff, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0xffffff00, x6); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(3, x10); + CHECK_EQUAL_64(0, x11); + CHECK_EQUAL_64(0xffffffff, x12); + CHECK_EQUAL_64(0, x13); + CHECK_EQUAL_64(0xfffffffe, x14); + CHECK_EQUAL_64(1, x16); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(3, x18); + CHECK_EQUAL_64(0, x19); + CHECK_EQUAL_64(0xffffffffffffffffUL, x20); + CHECK_EQUAL_64(0, x21); + CHECK_EQUAL_64(0xffffff0000000000UL, x22); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(3, x25); + CHECK_EQUAL_64(0, x26); + CHECK_EQUAL_64(0xffffffffffffffffUL, x27); + CHECK_EQUAL_64(0, x28); + CHECK_EQUAL_64(0xfffffffffffff800UL, x29); + CHECK_EQUAL_64(0xffffffff, x30); TEARDOWN(); } @@ -6892,36 +7094,36 @@ TEST(fcvtms) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0xfffffffe, x3); - ASSERT_EQUAL_64(0x7fffffff, x4); - ASSERT_EQUAL_64(0x80000000, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0x80000080, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(1, x10); - ASSERT_EQUAL_64(0xfffffffe, x11); - ASSERT_EQUAL_64(0x7fffffff, x12); - ASSERT_EQUAL_64(0x80000000, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(0x80000001, x15); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(1, x18); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x19); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x8000000000000000UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x8000008000000000UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(1, x25); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x26); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x27); - ASSERT_EQUAL_64(0x8000000000000000UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x8000000000000400UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0xfffffffe, x3); + CHECK_EQUAL_64(0x7fffffff, x4); + CHECK_EQUAL_64(0x80000000, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0x80000080, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(1, x10); + CHECK_EQUAL_64(0xfffffffe, x11); + CHECK_EQUAL_64(0x7fffffff, x12); + CHECK_EQUAL_64(0x80000000, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(0x80000001, x15); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(1, x18); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x19); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x20); + CHECK_EQUAL_64(0x8000000000000000UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x8000008000000000UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(1, x25); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x26); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x27); + CHECK_EQUAL_64(0x8000000000000000UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x8000000000000400UL, x30); TEARDOWN(); } @@ -6996,35 +7198,35 @@ TEST(fcvtmu) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(0xffffffff, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(1, x10); - ASSERT_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0xffffffff, x12); - ASSERT_EQUAL_64(0, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(1, x18); - ASSERT_EQUAL_64(0x0UL, x19); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x0UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x0UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(1, x25); - ASSERT_EQUAL_64(0x0UL, x26); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x27); - ASSERT_EQUAL_64(0x0UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x0UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(0xffffffff, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(1, x10); + CHECK_EQUAL_64(0, x11); + CHECK_EQUAL_64(0xffffffff, x12); + CHECK_EQUAL_64(0, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(1, x18); + CHECK_EQUAL_64(0x0UL, x19); + CHECK_EQUAL_64(0xffffffffffffffffUL, x20); + CHECK_EQUAL_64(0x0UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x0UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(1, x25); + CHECK_EQUAL_64(0x0UL, x26); + CHECK_EQUAL_64(0xffffffffffffffffUL, x27); + CHECK_EQUAL_64(0x0UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x0UL, x30); TEARDOWN(); } @@ -7100,36 +7302,36 @@ TEST(fcvtns) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(2, x2); - ASSERT_EQUAL_64(0xfffffffe, x3); - ASSERT_EQUAL_64(0x7fffffff, x4); - ASSERT_EQUAL_64(0x80000000, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0x80000080, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(2, x10); - ASSERT_EQUAL_64(0xfffffffe, x11); - ASSERT_EQUAL_64(0x7fffffff, x12); - ASSERT_EQUAL_64(0x80000000, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(0x80000001, x15); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(2, x18); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x19); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x8000000000000000UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x8000008000000000UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(2, x25); - ASSERT_EQUAL_64(0xfffffffffffffffeUL, x26); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x27); -// ASSERT_EQUAL_64(0x8000000000000000UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x8000000000000400UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(2, x2); + CHECK_EQUAL_64(0xfffffffe, x3); + CHECK_EQUAL_64(0x7fffffff, x4); + CHECK_EQUAL_64(0x80000000, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0x80000080, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(2, x10); + CHECK_EQUAL_64(0xfffffffe, x11); + CHECK_EQUAL_64(0x7fffffff, x12); + CHECK_EQUAL_64(0x80000000, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(0x80000001, x15); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(2, x18); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x19); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x20); + CHECK_EQUAL_64(0x8000000000000000UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x8000008000000000UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(2, x25); + CHECK_EQUAL_64(0xfffffffffffffffeUL, x26); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x27); +// CHECK_EQUAL_64(0x8000000000000000UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x8000000000000400UL, x30); TEARDOWN(); } @@ -7202,34 +7404,34 @@ TEST(fcvtnu) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(2, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(0xffffffff, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0xffffff00, x6); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(2, x10); - ASSERT_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0xffffffff, x12); - ASSERT_EQUAL_64(0, x13); - ASSERT_EQUAL_64(0xfffffffe, x14); - ASSERT_EQUAL_64(1, x16); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(2, x18); - ASSERT_EQUAL_64(0, x19); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x20); - ASSERT_EQUAL_64(0, x21); - ASSERT_EQUAL_64(0xffffff0000000000UL, x22); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(2, x25); - ASSERT_EQUAL_64(0, x26); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x27); -// ASSERT_EQUAL_64(0, x28); - ASSERT_EQUAL_64(0xfffffffffffff800UL, x29); - ASSERT_EQUAL_64(0xffffffff, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(2, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(0xffffffff, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0xffffff00, x6); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(2, x10); + CHECK_EQUAL_64(0, x11); + CHECK_EQUAL_64(0xffffffff, x12); + CHECK_EQUAL_64(0, x13); + CHECK_EQUAL_64(0xfffffffe, x14); + CHECK_EQUAL_64(1, x16); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(2, x18); + CHECK_EQUAL_64(0, x19); + CHECK_EQUAL_64(0xffffffffffffffffUL, x20); + CHECK_EQUAL_64(0, x21); + CHECK_EQUAL_64(0xffffff0000000000UL, x22); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(2, x25); + CHECK_EQUAL_64(0, x26); + CHECK_EQUAL_64(0xffffffffffffffffUL, x27); +// CHECK_EQUAL_64(0, x28); + CHECK_EQUAL_64(0xfffffffffffff800UL, x29); + CHECK_EQUAL_64(0xffffffff, x30); TEARDOWN(); } @@ -7305,36 +7507,36 @@ TEST(fcvtzs) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0xffffffff, x3); - ASSERT_EQUAL_64(0x7fffffff, x4); - ASSERT_EQUAL_64(0x80000000, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0x80000080, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(1, x10); - ASSERT_EQUAL_64(0xffffffff, x11); - ASSERT_EQUAL_64(0x7fffffff, x12); - ASSERT_EQUAL_64(0x80000000, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(0x80000001, x15); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(1, x18); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x19); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x8000000000000000UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x8000008000000000UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(1, x25); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x26); - ASSERT_EQUAL_64(0x7fffffffffffffffUL, x27); - ASSERT_EQUAL_64(0x8000000000000000UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x8000000000000400UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0xffffffff, x3); + CHECK_EQUAL_64(0x7fffffff, x4); + CHECK_EQUAL_64(0x80000000, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0x80000080, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(1, x10); + CHECK_EQUAL_64(0xffffffff, x11); + CHECK_EQUAL_64(0x7fffffff, x12); + CHECK_EQUAL_64(0x80000000, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(0x80000001, x15); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(1, x18); + CHECK_EQUAL_64(0xffffffffffffffffUL, x19); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x20); + CHECK_EQUAL_64(0x8000000000000000UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x8000008000000000UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(1, x25); + CHECK_EQUAL_64(0xffffffffffffffffUL, x26); + CHECK_EQUAL_64(0x7fffffffffffffffUL, x27); + CHECK_EQUAL_64(0x8000000000000000UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x8000000000000400UL, x30); TEARDOWN(); } @@ -7409,35 +7611,35 @@ TEST(fcvtzu) { RUN(); - ASSERT_EQUAL_64(1, x0); - ASSERT_EQUAL_64(1, x1); - ASSERT_EQUAL_64(1, x2); - ASSERT_EQUAL_64(0, x3); - ASSERT_EQUAL_64(0xffffffff, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0x7fffff80, x6); - ASSERT_EQUAL_64(0, x7); - ASSERT_EQUAL_64(1, x8); - ASSERT_EQUAL_64(1, x9); - ASSERT_EQUAL_64(1, x10); - ASSERT_EQUAL_64(0, x11); - ASSERT_EQUAL_64(0xffffffff, x12); - ASSERT_EQUAL_64(0, x13); - ASSERT_EQUAL_64(0x7ffffffe, x14); - ASSERT_EQUAL_64(1, x17); - ASSERT_EQUAL_64(1, x18); - ASSERT_EQUAL_64(0x0UL, x19); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x20); - ASSERT_EQUAL_64(0x0UL, x21); - ASSERT_EQUAL_64(0x7fffff8000000000UL, x22); - ASSERT_EQUAL_64(0x0UL, x23); - ASSERT_EQUAL_64(1, x24); - ASSERT_EQUAL_64(1, x25); - ASSERT_EQUAL_64(0x0UL, x26); - ASSERT_EQUAL_64(0xffffffffffffffffUL, x27); - ASSERT_EQUAL_64(0x0UL, x28); - ASSERT_EQUAL_64(0x7ffffffffffffc00UL, x29); - ASSERT_EQUAL_64(0x0UL, x30); + CHECK_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x1); + CHECK_EQUAL_64(1, x2); + CHECK_EQUAL_64(0, x3); + CHECK_EQUAL_64(0xffffffff, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0x7fffff80, x6); + CHECK_EQUAL_64(0, x7); + CHECK_EQUAL_64(1, x8); + CHECK_EQUAL_64(1, x9); + CHECK_EQUAL_64(1, x10); + CHECK_EQUAL_64(0, x11); + CHECK_EQUAL_64(0xffffffff, x12); + CHECK_EQUAL_64(0, x13); + CHECK_EQUAL_64(0x7ffffffe, x14); + CHECK_EQUAL_64(1, x17); + CHECK_EQUAL_64(1, x18); + CHECK_EQUAL_64(0x0UL, x19); + CHECK_EQUAL_64(0xffffffffffffffffUL, x20); + CHECK_EQUAL_64(0x0UL, x21); + CHECK_EQUAL_64(0x7fffff8000000000UL, x22); + CHECK_EQUAL_64(0x0UL, x23); + CHECK_EQUAL_64(1, x24); + CHECK_EQUAL_64(1, x25); + CHECK_EQUAL_64(0x0UL, x26); + CHECK_EQUAL_64(0xffffffffffffffffUL, x27); + CHECK_EQUAL_64(0x0UL, x28); + CHECK_EQUAL_64(0x7ffffffffffffc00UL, x29); + CHECK_EQUAL_64(0x0UL, x30); TEARDOWN(); } @@ -7525,16 +7727,16 @@ static void TestUScvtfHelper(uint64_t in, for (int fbits = 0; fbits <= 32; fbits++) { double expected_scvtf = expected_scvtf_base / pow(2.0, fbits); double expected_ucvtf = expected_ucvtf_base / pow(2.0, fbits); - ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); - ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); - if (cvtf_s32) ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_w[fbits]); - if (cvtf_u32) ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_w[fbits]); + CHECK_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); + CHECK_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); + if (cvtf_s32) CHECK_EQUAL_FP64(expected_scvtf, results_scvtf_w[fbits]); + if (cvtf_u32) CHECK_EQUAL_FP64(expected_ucvtf, results_ucvtf_w[fbits]); } for (int fbits = 33; fbits <= 64; fbits++) { double expected_scvtf = expected_scvtf_base / pow(2.0, fbits); double expected_ucvtf = expected_ucvtf_base / pow(2.0, fbits); - ASSERT_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); - ASSERT_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); + CHECK_EQUAL_FP64(expected_scvtf, results_scvtf_x[fbits]); + CHECK_EQUAL_FP64(expected_ucvtf, results_ucvtf_x[fbits]); } TEARDOWN(); @@ -7680,18 +7882,18 @@ static void TestUScvtf32Helper(uint64_t in, for (int fbits = 0; fbits <= 32; fbits++) { float expected_scvtf = expected_scvtf_base / powf(2, fbits); float expected_ucvtf = expected_ucvtf_base / powf(2, fbits); - ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); - ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); - if (cvtf_s32) ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_w[fbits]); - if (cvtf_u32) ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_w[fbits]); + CHECK_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); + CHECK_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); + if (cvtf_s32) CHECK_EQUAL_FP32(expected_scvtf, results_scvtf_w[fbits]); + if (cvtf_u32) CHECK_EQUAL_FP32(expected_ucvtf, results_ucvtf_w[fbits]); break; } for (int fbits = 33; fbits <= 64; fbits++) { break; float expected_scvtf = expected_scvtf_base / powf(2, fbits); float expected_ucvtf = expected_ucvtf_base / powf(2, fbits); - ASSERT_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); - ASSERT_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); + CHECK_EQUAL_FP32(expected_scvtf, results_scvtf_x[fbits]); + CHECK_EQUAL_FP32(expected_ucvtf, results_ucvtf_x[fbits]); } TEARDOWN(); @@ -7795,13 +7997,13 @@ TEST(system_mrs) { RUN(); // NZCV - ASSERT_EQUAL_32(ZCFlag, w3); - ASSERT_EQUAL_32(NFlag, w4); - ASSERT_EQUAL_32(ZCVFlag, w5); + CHECK_EQUAL_32(ZCFlag, w3); + CHECK_EQUAL_32(NFlag, w4); + CHECK_EQUAL_32(ZCVFlag, w5); // FPCR // The default FPCR on Linux-based platforms is 0. - ASSERT_EQUAL_32(0, w6); + CHECK_EQUAL_32(0, w6); TEARDOWN(); } @@ -7869,11 +8071,11 @@ TEST(system_msr) { RUN(); // We should have incremented x7 (from 0) exactly 8 times. - ASSERT_EQUAL_64(8, x7); + CHECK_EQUAL_64(8, x7); - ASSERT_EQUAL_64(fpcr_core, x8); - ASSERT_EQUAL_64(fpcr_core, x9); - ASSERT_EQUAL_64(0, x10); + CHECK_EQUAL_64(fpcr_core, x8); + CHECK_EQUAL_64(fpcr_core, x9); + CHECK_EQUAL_64(0, x10); TEARDOWN(); } @@ -7891,8 +8093,8 @@ TEST(system_nop) { RUN(); - ASSERT_EQUAL_REGISTERS(before); - ASSERT_EQUAL_NZCV(before.flags_nzcv()); + CHECK_EQUAL_REGISTERS(before); + CHECK_EQUAL_NZCV(before.flags_nzcv()); TEARDOWN(); } @@ -7958,8 +8160,8 @@ TEST(zero_dest) { RUN(); - ASSERT_EQUAL_REGISTERS(before); - ASSERT_EQUAL_NZCV(before.flags_nzcv()); + CHECK_EQUAL_REGISTERS(before); + CHECK_EQUAL_NZCV(before.flags_nzcv()); TEARDOWN(); } @@ -8023,7 +8225,7 @@ TEST(zero_dest_setflags) { RUN(); - ASSERT_EQUAL_REGISTERS(before); + CHECK_EQUAL_REGISTERS(before); TEARDOWN(); } @@ -8136,15 +8338,15 @@ TEST(peek_poke_simple) { END(); RUN(); - ASSERT_EQUAL_64(literal_base * 1, x0); - ASSERT_EQUAL_64(literal_base * 2, x1); - ASSERT_EQUAL_64(literal_base * 3, x2); - ASSERT_EQUAL_64(literal_base * 4, x3); + CHECK_EQUAL_64(literal_base * 1, x0); + CHECK_EQUAL_64(literal_base * 2, x1); + CHECK_EQUAL_64(literal_base * 3, x2); + CHECK_EQUAL_64(literal_base * 4, x3); - ASSERT_EQUAL_64((literal_base * 1) & 0xffffffff, x10); - ASSERT_EQUAL_64((literal_base * 2) & 0xffffffff, x11); - ASSERT_EQUAL_64((literal_base * 3) & 0xffffffff, x12); - ASSERT_EQUAL_64((literal_base * 4) & 0xffffffff, x13); + CHECK_EQUAL_64((literal_base * 1) & 0xffffffff, x10); + CHECK_EQUAL_64((literal_base * 2) & 0xffffffff, x11); + CHECK_EQUAL_64((literal_base * 3) & 0xffffffff, x12); + CHECK_EQUAL_64((literal_base * 4) & 0xffffffff, x13); TEARDOWN(); } @@ -8214,17 +8416,17 @@ TEST(peek_poke_unaligned) { END(); RUN(); - ASSERT_EQUAL_64(literal_base * 1, x0); - ASSERT_EQUAL_64(literal_base * 2, x1); - ASSERT_EQUAL_64(literal_base * 3, x2); - ASSERT_EQUAL_64(literal_base * 4, x3); - ASSERT_EQUAL_64(literal_base * 5, x4); - ASSERT_EQUAL_64(literal_base * 6, x5); - ASSERT_EQUAL_64(literal_base * 7, x6); + CHECK_EQUAL_64(literal_base * 1, x0); + CHECK_EQUAL_64(literal_base * 2, x1); + CHECK_EQUAL_64(literal_base * 3, x2); + CHECK_EQUAL_64(literal_base * 4, x3); + CHECK_EQUAL_64(literal_base * 5, x4); + CHECK_EQUAL_64(literal_base * 6, x5); + CHECK_EQUAL_64(literal_base * 7, x6); - ASSERT_EQUAL_64((literal_base * 1) & 0xffffffff, x10); - ASSERT_EQUAL_64((literal_base * 2) & 0xffffffff, x11); - ASSERT_EQUAL_64((literal_base * 3) & 0xffffffff, x12); + CHECK_EQUAL_64((literal_base * 1) & 0xffffffff, x10); + CHECK_EQUAL_64((literal_base * 2) & 0xffffffff, x11); + CHECK_EQUAL_64((literal_base * 3) & 0xffffffff, x12); TEARDOWN(); } @@ -8271,10 +8473,10 @@ TEST(peek_poke_endianness) { uint64_t x5_expected = ((x1_expected << 16) & 0xffff0000) | ((x1_expected >> 16) & 0x0000ffff); - ASSERT_EQUAL_64(x0_expected, x0); - ASSERT_EQUAL_64(x1_expected, x1); - ASSERT_EQUAL_64(x4_expected, x4); - ASSERT_EQUAL_64(x5_expected, x5); + CHECK_EQUAL_64(x0_expected, x0); + CHECK_EQUAL_64(x1_expected, x1); + CHECK_EQUAL_64(x4_expected, x4); + CHECK_EQUAL_64(x5_expected, x5); TEARDOWN(); } @@ -8308,7 +8510,7 @@ TEST(peek_poke_mixed) { __ Poke(x1, 8); __ Poke(x0, 0); { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(x4, __ StackPointer()); __ SetStackPointer(x4); @@ -8340,12 +8542,12 @@ TEST(peek_poke_mixed) { uint64_t x7_expected = ((x1_expected << 16) & 0xffff0000) | ((x0_expected >> 48) & 0x0000ffff); - ASSERT_EQUAL_64(x0_expected, x0); - ASSERT_EQUAL_64(x1_expected, x1); - ASSERT_EQUAL_64(x2_expected, x2); - ASSERT_EQUAL_64(x3_expected, x3); - ASSERT_EQUAL_64(x6_expected, x6); - ASSERT_EQUAL_64(x7_expected, x7); + CHECK_EQUAL_64(x0_expected, x0); + CHECK_EQUAL_64(x1_expected, x1); + CHECK_EQUAL_64(x2_expected, x2); + CHECK_EQUAL_64(x3_expected, x3); + CHECK_EQUAL_64(x6_expected, x6); + CHECK_EQUAL_64(x7_expected, x7); TEARDOWN(); } @@ -8384,10 +8586,10 @@ static void PushPopJsspSimpleHelper(int reg_count, START(); - // Registers x8 and x9 are used by the macro assembler for debug code (for - // example in 'Pop'), so we can't use them here. We can't use jssp because it - // will be the stack pointer for this test. - static RegList const allowed = ~(x8.Bit() | x9.Bit() | jssp.Bit()); + // Registers in the TmpList can be used by the macro assembler for debug code + // (for example in 'Pop'), so we can't use them here. We can't use jssp + // because it will be the stack pointer for this test. + static RegList const allowed = ~(masm.TmpList()->list() | jssp.Bit()); if (reg_count == kPushPopJsspMaxRegCount) { reg_count = CountSetBits(allowed, kNumberOfRegisters); } @@ -8405,7 +8607,7 @@ static void PushPopJsspSimpleHelper(int reg_count, uint64_t literal_base = 0x0100001000100101UL; { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -8434,7 +8636,7 @@ static void PushPopJsspSimpleHelper(int reg_count, case 3: __ Push(r[2], r[1], r[0]); break; case 2: __ Push(r[1], r[0]); break; case 1: __ Push(r[0]); break; - default: ASSERT(i == 0); break; + default: DCHECK(i == 0); break; } break; case PushPopRegList: @@ -8456,7 +8658,7 @@ static void PushPopJsspSimpleHelper(int reg_count, case 3: __ Pop(r[i], r[i+1], r[i+2]); break; case 2: __ Pop(r[i], r[i+1]); break; case 1: __ Pop(r[i]); break; - default: ASSERT(i == reg_count); break; + default: DCHECK(i == reg_count); break; } break; case PushPopRegList: @@ -8476,14 +8678,14 @@ static void PushPopJsspSimpleHelper(int reg_count, RUN(); // Check that the register contents were preserved. - // Always use ASSERT_EQUAL_64, even when testing W registers, so we can test + // Always use CHECK_EQUAL_64, even when testing W registers, so we can test // that the upper word was properly cleared by Pop. literal_base &= (0xffffffffffffffffUL >> (64-reg_size)); for (int i = 0; i < reg_count; i++) { if (x[i].IsZero()) { - ASSERT_EQUAL_64(0, x[i]); + CHECK_EQUAL_64(0, x[i]); } else { - ASSERT_EQUAL_64(literal_base * i, x[i]); + CHECK_EQUAL_64(literal_base * i, x[i]); } } @@ -8587,7 +8789,7 @@ static void PushPopFPJsspSimpleHelper(int reg_count, uint64_t literal_base = 0x0100001000100101UL; { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -8618,7 +8820,7 @@ static void PushPopFPJsspSimpleHelper(int reg_count, case 3: __ Push(v[2], v[1], v[0]); break; case 2: __ Push(v[1], v[0]); break; case 1: __ Push(v[0]); break; - default: ASSERT(i == 0); break; + default: DCHECK(i == 0); break; } break; case PushPopRegList: @@ -8640,7 +8842,7 @@ static void PushPopFPJsspSimpleHelper(int reg_count, case 3: __ Pop(v[i], v[i+1], v[i+2]); break; case 2: __ Pop(v[i], v[i+1]); break; case 1: __ Pop(v[i]); break; - default: ASSERT(i == reg_count); break; + default: DCHECK(i == reg_count); break; } break; case PushPopRegList: @@ -8660,14 +8862,14 @@ static void PushPopFPJsspSimpleHelper(int reg_count, RUN(); // Check that the register contents were preserved. - // Always use ASSERT_EQUAL_FP64, even when testing S registers, so we can + // Always use CHECK_EQUAL_FP64, even when testing S registers, so we can // test that the upper word was properly cleared by Pop. literal_base &= (0xffffffffffffffffUL >> (64-reg_size)); for (int i = 0; i < reg_count; i++) { uint64_t literal = literal_base * i; double expected; memcpy(&expected, &literal, sizeof(expected)); - ASSERT_EQUAL_FP64(expected, d[i]); + CHECK_EQUAL_FP64(expected, d[i]); } TEARDOWN(); @@ -8764,7 +8966,7 @@ static void PushPopJsspMixedMethodsHelper(int claim, int reg_size) { START(); { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -8800,16 +9002,16 @@ static void PushPopJsspMixedMethodsHelper(int claim, int reg_size) { RUN(); - // Always use ASSERT_EQUAL_64, even when testing W registers, so we can test + // Always use CHECK_EQUAL_64, even when testing W registers, so we can test // that the upper word was properly cleared by Pop. literal_base &= (0xffffffffffffffffUL >> (64-reg_size)); - ASSERT_EQUAL_64(literal_base * 3, x[9]); - ASSERT_EQUAL_64(literal_base * 2, x[8]); - ASSERT_EQUAL_64(literal_base * 0, x[7]); - ASSERT_EQUAL_64(literal_base * 3, x[6]); - ASSERT_EQUAL_64(literal_base * 1, x[5]); - ASSERT_EQUAL_64(literal_base * 2, x[4]); + CHECK_EQUAL_64(literal_base * 3, x[9]); + CHECK_EQUAL_64(literal_base * 2, x[8]); + CHECK_EQUAL_64(literal_base * 0, x[7]); + CHECK_EQUAL_64(literal_base * 3, x[6]); + CHECK_EQUAL_64(literal_base * 1, x[5]); + CHECK_EQUAL_64(literal_base * 2, x[4]); TEARDOWN(); } @@ -8869,7 +9071,7 @@ static void PushPopJsspWXOverlapHelper(int reg_count, int claim) { START(); { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -8917,7 +9119,7 @@ static void PushPopJsspWXOverlapHelper(int reg_count, int claim) { int active_w_slots = 0; for (int i = 0; active_w_slots < requested_w_slots; i++) { - ASSERT(i < reg_count); + DCHECK(i < reg_count); // In order to test various arguments to PushMultipleTimes, and to try to // exercise different alignment and overlap effects, we push each // register a different number of times. @@ -8990,7 +9192,7 @@ static void PushPopJsspWXOverlapHelper(int reg_count, int claim) { } next_is_64 = !next_is_64; } - ASSERT(active_w_slots == 0); + DCHECK(active_w_slots == 0); // Drop memory to restore jssp. __ Drop(claim, kByteSizeInBytes); @@ -9018,15 +9220,15 @@ static void PushPopJsspWXOverlapHelper(int reg_count, int claim) { expected = stack[slot++]; } - // Always use ASSERT_EQUAL_64, even when testing W registers, so we can + // Always use CHECK_EQUAL_64, even when testing W registers, so we can // test that the upper word was properly cleared by Pop. if (x[i].IsZero()) { - ASSERT_EQUAL_64(0, x[i]); + CHECK_EQUAL_64(0, x[i]); } else { - ASSERT_EQUAL_64(expected, x[i]); + CHECK_EQUAL_64(expected, x[i]); } } - ASSERT(slot == requested_w_slots); + DCHECK(slot == requested_w_slots); TEARDOWN(); } @@ -9056,7 +9258,7 @@ TEST(push_pop_csp) { START(); - ASSERT(csp.Is(__ StackPointer())); + DCHECK(csp.Is(__ StackPointer())); __ Mov(x3, 0x3333333333333333UL); __ Mov(x2, 0x2222222222222222UL); @@ -9101,40 +9303,40 @@ TEST(push_pop_csp) { RUN(); - ASSERT_EQUAL_64(0x1111111111111111UL, x3); - ASSERT_EQUAL_64(0x0000000000000000UL, x2); - ASSERT_EQUAL_64(0x3333333333333333UL, x1); - ASSERT_EQUAL_64(0x2222222222222222UL, x0); - ASSERT_EQUAL_64(0x3333333333333333UL, x9); - ASSERT_EQUAL_64(0x2222222222222222UL, x8); - ASSERT_EQUAL_64(0x0000000000000000UL, x7); - ASSERT_EQUAL_64(0x3333333333333333UL, x6); - ASSERT_EQUAL_64(0x1111111111111111UL, x5); - ASSERT_EQUAL_64(0x2222222222222222UL, x4); + CHECK_EQUAL_64(0x1111111111111111UL, x3); + CHECK_EQUAL_64(0x0000000000000000UL, x2); + CHECK_EQUAL_64(0x3333333333333333UL, x1); + CHECK_EQUAL_64(0x2222222222222222UL, x0); + CHECK_EQUAL_64(0x3333333333333333UL, x9); + CHECK_EQUAL_64(0x2222222222222222UL, x8); + CHECK_EQUAL_64(0x0000000000000000UL, x7); + CHECK_EQUAL_64(0x3333333333333333UL, x6); + CHECK_EQUAL_64(0x1111111111111111UL, x5); + CHECK_EQUAL_64(0x2222222222222222UL, x4); - ASSERT_EQUAL_32(0x11111111U, w13); - ASSERT_EQUAL_32(0x33333333U, w12); - ASSERT_EQUAL_32(0x00000000U, w11); - ASSERT_EQUAL_32(0x22222222U, w10); - ASSERT_EQUAL_32(0x11111111U, w17); - ASSERT_EQUAL_32(0x00000000U, w16); - ASSERT_EQUAL_32(0x33333333U, w15); - ASSERT_EQUAL_32(0x22222222U, w14); + CHECK_EQUAL_32(0x11111111U, w13); + CHECK_EQUAL_32(0x33333333U, w12); + CHECK_EQUAL_32(0x00000000U, w11); + CHECK_EQUAL_32(0x22222222U, w10); + CHECK_EQUAL_32(0x11111111U, w17); + CHECK_EQUAL_32(0x00000000U, w16); + CHECK_EQUAL_32(0x33333333U, w15); + CHECK_EQUAL_32(0x22222222U, w14); - ASSERT_EQUAL_32(0x11111111U, w18); - ASSERT_EQUAL_32(0x11111111U, w19); - ASSERT_EQUAL_32(0x11111111U, w20); - ASSERT_EQUAL_32(0x11111111U, w21); - ASSERT_EQUAL_64(0x3333333333333333UL, x22); - ASSERT_EQUAL_64(0x0000000000000000UL, x23); + CHECK_EQUAL_32(0x11111111U, w18); + CHECK_EQUAL_32(0x11111111U, w19); + CHECK_EQUAL_32(0x11111111U, w20); + CHECK_EQUAL_32(0x11111111U, w21); + CHECK_EQUAL_64(0x3333333333333333UL, x22); + CHECK_EQUAL_64(0x0000000000000000UL, x23); - ASSERT_EQUAL_64(0x3333333333333333UL, x24); - ASSERT_EQUAL_64(0x3333333333333333UL, x26); + CHECK_EQUAL_64(0x3333333333333333UL, x24); + CHECK_EQUAL_64(0x3333333333333333UL, x26); - ASSERT_EQUAL_32(0x33333333U, w25); - ASSERT_EQUAL_32(0x00000000U, w27); - ASSERT_EQUAL_32(0x22222222U, w28); - ASSERT_EQUAL_32(0x33333333U, w29); + CHECK_EQUAL_32(0x33333333U, w25); + CHECK_EQUAL_32(0x00000000U, w27); + CHECK_EQUAL_32(0x22222222U, w28); + CHECK_EQUAL_32(0x33333333U, w29); TEARDOWN(); } @@ -9145,7 +9347,7 @@ TEST(push_queued) { START(); - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -9196,19 +9398,19 @@ TEST(push_queued) { RUN(); - ASSERT_EQUAL_64(0x1234000000000000, x0); - ASSERT_EQUAL_64(0x1234000100010001, x1); - ASSERT_EQUAL_64(0x1234000200020002, x2); - ASSERT_EQUAL_64(0x1234000300030003, x3); + CHECK_EQUAL_64(0x1234000000000000, x0); + CHECK_EQUAL_64(0x1234000100010001, x1); + CHECK_EQUAL_64(0x1234000200020002, x2); + CHECK_EQUAL_64(0x1234000300030003, x3); - ASSERT_EQUAL_32(0x12340004, w4); - ASSERT_EQUAL_32(0x12340005, w5); - ASSERT_EQUAL_32(0x12340006, w6); + CHECK_EQUAL_32(0x12340004, w4); + CHECK_EQUAL_32(0x12340005, w5); + CHECK_EQUAL_32(0x12340006, w6); - ASSERT_EQUAL_FP64(123400.0, d0); - ASSERT_EQUAL_FP64(123401.0, d1); + CHECK_EQUAL_FP64(123400.0, d0); + CHECK_EQUAL_FP64(123401.0, d1); - ASSERT_EQUAL_FP32(123402.0, s2); + CHECK_EQUAL_FP32(123402.0, s2); TEARDOWN(); } @@ -9220,7 +9422,7 @@ TEST(pop_queued) { START(); - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); __ Mov(jssp, __ StackPointer()); __ SetStackPointer(jssp); @@ -9271,19 +9473,19 @@ TEST(pop_queued) { RUN(); - ASSERT_EQUAL_64(0x1234000000000000, x0); - ASSERT_EQUAL_64(0x1234000100010001, x1); - ASSERT_EQUAL_64(0x1234000200020002, x2); - ASSERT_EQUAL_64(0x1234000300030003, x3); + CHECK_EQUAL_64(0x1234000000000000, x0); + CHECK_EQUAL_64(0x1234000100010001, x1); + CHECK_EQUAL_64(0x1234000200020002, x2); + CHECK_EQUAL_64(0x1234000300030003, x3); - ASSERT_EQUAL_64(0x0000000012340004, x4); - ASSERT_EQUAL_64(0x0000000012340005, x5); - ASSERT_EQUAL_64(0x0000000012340006, x6); + CHECK_EQUAL_64(0x0000000012340004, x4); + CHECK_EQUAL_64(0x0000000012340005, x5); + CHECK_EQUAL_64(0x0000000012340006, x6); - ASSERT_EQUAL_FP64(123400.0, d0); - ASSERT_EQUAL_FP64(123401.0, d1); + CHECK_EQUAL_FP64(123400.0, d0); + CHECK_EQUAL_FP64(123401.0, d1); - ASSERT_EQUAL_FP32(123402.0, s2); + CHECK_EQUAL_FP32(123402.0, s2); TEARDOWN(); } @@ -9349,14 +9551,14 @@ TEST(jump_both_smi) { RUN(); - ASSERT_EQUAL_64(0x5555555500000001UL, x0); - ASSERT_EQUAL_64(0xaaaaaaaa00000001UL, x1); - ASSERT_EQUAL_64(0x1234567800000000UL, x2); - ASSERT_EQUAL_64(0x8765432100000000UL, x3); - ASSERT_EQUAL_64(0, x4); - ASSERT_EQUAL_64(0, x5); - ASSERT_EQUAL_64(0, x6); - ASSERT_EQUAL_64(1, x7); + CHECK_EQUAL_64(0x5555555500000001UL, x0); + CHECK_EQUAL_64(0xaaaaaaaa00000001UL, x1); + CHECK_EQUAL_64(0x1234567800000000UL, x2); + CHECK_EQUAL_64(0x8765432100000000UL, x3); + CHECK_EQUAL_64(0, x4); + CHECK_EQUAL_64(0, x5); + CHECK_EQUAL_64(0, x6); + CHECK_EQUAL_64(1, x7); TEARDOWN(); } @@ -9422,14 +9624,14 @@ TEST(jump_either_smi) { RUN(); - ASSERT_EQUAL_64(0x5555555500000001UL, x0); - ASSERT_EQUAL_64(0xaaaaaaaa00000001UL, x1); - ASSERT_EQUAL_64(0x1234567800000000UL, x2); - ASSERT_EQUAL_64(0x8765432100000000UL, x3); - ASSERT_EQUAL_64(0, x4); - ASSERT_EQUAL_64(1, x5); - ASSERT_EQUAL_64(1, x6); - ASSERT_EQUAL_64(1, x7); + CHECK_EQUAL_64(0x5555555500000001UL, x0); + CHECK_EQUAL_64(0xaaaaaaaa00000001UL, x1); + CHECK_EQUAL_64(0x1234567800000000UL, x2); + CHECK_EQUAL_64(0x8765432100000000UL, x3); + CHECK_EQUAL_64(0, x4); + CHECK_EQUAL_64(1, x5); + CHECK_EQUAL_64(1, x6); + CHECK_EQUAL_64(1, x7); TEARDOWN(); } @@ -9780,7 +9982,7 @@ TEST(cpureglist_utils_empty) { TEST(printf) { INIT_V8(); - SETUP(); + SETUP_SIZE(BUF_SIZE * 2); START(); char const * test_plain_string = "Printf with no arguments.\n"; @@ -9821,41 +10023,49 @@ TEST(printf) { __ Mov(x11, 40); __ Mov(x12, 500); - // x8 and x9 are used by debug code in part of the macro assembler. However, - // Printf guarantees to preserve them (so we can use Printf in debug code), - // and we need to test that they are properly preserved. The above code - // shouldn't need to use them, but we initialize x8 and x9 last to be on the - // safe side. This test still assumes that none of the code from - // before->Dump() to the end of the test can clobber x8 or x9, so where - // possible we use the Assembler directly to be safe. - __ orr(x8, xzr, 0x8888888888888888); - __ orr(x9, xzr, 0x9999999999999999); - - // Check that we don't clobber any registers, except those that we explicitly - // write results into. + // A single character. + __ Mov(w13, 'x'); + + // Check that we don't clobber any registers. before.Dump(&masm); __ Printf(test_plain_string); // NOLINT(runtime/printf) - __ Printf("x0: %" PRId64", x1: 0x%08" PRIx64 "\n", x0, x1); + __ Printf("x0: %" PRId64 ", x1: 0x%08" PRIx64 "\n", x0, x1); + __ Printf("w5: %" PRId32 ", x5: %" PRId64"\n", w5, x5); __ Printf("d0: %f\n", d0); __ Printf("Test %%s: %s\n", x2); __ Printf("w3(uint32): %" PRIu32 "\nw4(int32): %" PRId32 "\n" "x5(uint64): %" PRIu64 "\nx6(int64): %" PRId64 "\n", w3, w4, x5, x6); __ Printf("%%f: %f\n%%g: %g\n%%e: %e\n%%E: %E\n", s1, s2, d3, d4); - __ Printf("0x%08" PRIx32 ", 0x%016" PRIx64 "\n", x28, x28); + __ Printf("0x%" PRIx32 ", 0x%" PRIx64 "\n", w28, x28); __ Printf("%g\n", d10); + __ Printf("%%%%%s%%%c%%\n", x2, w13); + + // Print the stack pointer (csp). + DCHECK(csp.Is(__ StackPointer())); + __ Printf("StackPointer(csp): 0x%016" PRIx64 ", 0x%08" PRIx32 "\n", + __ StackPointer(), __ StackPointer().W()); // Test with a different stack pointer. const Register old_stack_pointer = __ StackPointer(); - __ mov(x29, old_stack_pointer); + __ Mov(x29, old_stack_pointer); __ SetStackPointer(x29); - __ Printf("old_stack_pointer: 0x%016" PRIx64 "\n", old_stack_pointer); - __ mov(old_stack_pointer, __ StackPointer()); + // Print the stack pointer (not csp). + __ Printf("StackPointer(not csp): 0x%016" PRIx64 ", 0x%08" PRIx32 "\n", + __ StackPointer(), __ StackPointer().W()); + __ Mov(old_stack_pointer, __ StackPointer()); __ SetStackPointer(old_stack_pointer); + // Test with three arguments. __ Printf("3=%u, 4=%u, 5=%u\n", x10, x11, x12); + // Mixed argument types. + __ Printf("w3: %" PRIu32 ", s1: %f, x5: %" PRIu64 ", d3: %f\n", + w3, s1, x5, d3); + __ Printf("s1: %f, d3: %f, w3: %" PRId32 ", x5: %" PRId64 "\n", + s1, d3, w3, x5); + END(); RUN(); @@ -9863,7 +10073,7 @@ TEST(printf) { // Printf preserves all registers by default, we can't look at the number of // bytes that were printed. However, the printf_no_preserve test should check // that, and here we just test that we didn't clobber any registers. - ASSERT_EQUAL_REGISTERS(before); + CHECK_EQUAL_REGISTERS(before); TEARDOWN(); } @@ -9877,7 +10087,7 @@ TEST(printf_no_preserve) { char const * test_plain_string = "Printf with no arguments.\n"; char const * test_substring = "'This is a substring.'"; - __ PrintfNoPreserve(test_plain_string); // NOLINT(runtime/printf) + __ PrintfNoPreserve(test_plain_string); __ Mov(x19, x0); // Test simple integer arguments. @@ -9915,7 +10125,7 @@ TEST(printf_no_preserve) { // Test printing callee-saved registers. __ Mov(x28, 0x123456789abcdef); - __ PrintfNoPreserve("0x%08" PRIx32 ", 0x%016" PRIx64 "\n", x28, x28); + __ PrintfNoPreserve("0x%" PRIx32 ", 0x%" PRIx64 "\n", w28, x28); __ Mov(x25, x0); __ Fmov(d10, 42.0); @@ -9926,11 +10136,11 @@ TEST(printf_no_preserve) { const Register old_stack_pointer = __ StackPointer(); __ Mov(x29, old_stack_pointer); __ SetStackPointer(x29); - - __ PrintfNoPreserve("old_stack_pointer: 0x%016" PRIx64 "\n", - old_stack_pointer); + // Print the stack pointer (not csp). + __ PrintfNoPreserve( + "StackPointer(not csp): 0x%016" PRIx64 ", 0x%08" PRIx32 "\n", + __ StackPointer(), __ StackPointer().W()); __ Mov(x27, x0); - __ Mov(old_stack_pointer, __ StackPointer()); __ SetStackPointer(old_stack_pointer); @@ -9941,6 +10151,15 @@ TEST(printf_no_preserve) { __ PrintfNoPreserve("3=%u, 4=%u, 5=%u\n", x3, x4, x5); __ Mov(x28, x0); + // Mixed argument types. + __ Mov(w3, 0xffffffff); + __ Fmov(s1, 1.234); + __ Mov(x5, 0xffffffffffffffff); + __ Fmov(d3, 3.456); + __ PrintfNoPreserve("w3: %" PRIu32 ", s1: %f, x5: %" PRIu64 ", d3: %f\n", + w3, s1, x5, d3); + __ Mov(x29, x0); + END(); RUN(); @@ -9948,33 +10167,35 @@ TEST(printf_no_preserve) { // use the return code to check that the string length was correct. // Printf with no arguments. - ASSERT_EQUAL_64(strlen(test_plain_string), x19); + CHECK_EQUAL_64(strlen(test_plain_string), x19); // x0: 1234, x1: 0x00001234 - ASSERT_EQUAL_64(25, x20); + CHECK_EQUAL_64(25, x20); // d0: 1.234000 - ASSERT_EQUAL_64(13, x21); + CHECK_EQUAL_64(13, x21); // Test %s: 'This is a substring.' - ASSERT_EQUAL_64(32, x22); + CHECK_EQUAL_64(32, x22); // w3(uint32): 4294967295 // w4(int32): -1 // x5(uint64): 18446744073709551615 // x6(int64): -1 - ASSERT_EQUAL_64(23 + 14 + 33 + 14, x23); + CHECK_EQUAL_64(23 + 14 + 33 + 14, x23); // %f: 1.234000 // %g: 2.345 // %e: 3.456000e+00 // %E: 4.567000E+00 - ASSERT_EQUAL_64(13 + 10 + 17 + 17, x24); - // 0x89abcdef, 0x0123456789abcdef - ASSERT_EQUAL_64(31, x25); + CHECK_EQUAL_64(13 + 10 + 17 + 17, x24); + // 0x89abcdef, 0x123456789abcdef + CHECK_EQUAL_64(30, x25); // 42 - ASSERT_EQUAL_64(3, x26); - // old_stack_pointer: 0x00007fb037ae2370 + CHECK_EQUAL_64(3, x26); + // StackPointer(not csp): 0x00007fb037ae2370, 0x37ae2370 // Note: This is an example value, but the field width is fixed here so the // string length is still predictable. - ASSERT_EQUAL_64(38, x27); + CHECK_EQUAL_64(54, x27); // 3=3, 4=40, 5=500 - ASSERT_EQUAL_64(17, x28); + CHECK_EQUAL_64(17, x28); + // w3: 4294967295, s1: 1.234000, x5: 18446744073709551615, d3: 3.456000 + CHECK_EQUAL_64(69, x29); TEARDOWN(); } @@ -10071,14 +10292,14 @@ static void DoSmiAbsTest(int32_t value, bool must_fail = false) { if (must_fail) { // We tested an invalid conversion. The code must have jump on slow. - ASSERT_EQUAL_64(0xbad, x2); + CHECK_EQUAL_64(0xbad, x2); } else { // The conversion is valid, check the result. int32_t result = (value >= 0) ? value : -value; - ASSERT_EQUAL_64(result, x1); + CHECK_EQUAL_64(result, x1); // Check that we didn't jump on slow. - ASSERT_EQUAL_64(0xc001c0de, x2); + CHECK_EQUAL_64(0xc001c0de, x2); } TEARDOWN(); @@ -10125,7 +10346,7 @@ TEST(blr_lr) { RUN(); - ASSERT_EQUAL_64(0xc001c0de, x0); + CHECK_EQUAL_64(0xc001c0de, x0); TEARDOWN(); } @@ -10196,14 +10417,14 @@ TEST(process_nan_double) { // Make sure that NaN propagation works correctly. double sn = rawbits_to_double(0x7ff5555511111111); double qn = rawbits_to_double(0x7ffaaaaa11111111); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsQuietNaN(qn)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsQuietNaN(qn)); // The input NaNs after passing through ProcessNaN. double sn_proc = rawbits_to_double(0x7ffd555511111111); double qn_proc = qn; - ASSERT(IsQuietNaN(sn_proc)); - ASSERT(IsQuietNaN(qn_proc)); + DCHECK(IsQuietNaN(sn_proc)); + DCHECK(IsQuietNaN(qn_proc)); SETUP(); START(); @@ -10244,24 +10465,24 @@ TEST(process_nan_double) { uint64_t sn_raw = double_to_rawbits(sn); // - Signalling NaN - ASSERT_EQUAL_FP64(sn, d1); - ASSERT_EQUAL_FP64(rawbits_to_double(sn_raw & ~kDSignMask), d2); - ASSERT_EQUAL_FP64(rawbits_to_double(sn_raw ^ kDSignMask), d3); + CHECK_EQUAL_FP64(sn, d1); + CHECK_EQUAL_FP64(rawbits_to_double(sn_raw & ~kDSignMask), d2); + CHECK_EQUAL_FP64(rawbits_to_double(sn_raw ^ kDSignMask), d3); // - Quiet NaN - ASSERT_EQUAL_FP64(qn, d11); - ASSERT_EQUAL_FP64(rawbits_to_double(qn_raw & ~kDSignMask), d12); - ASSERT_EQUAL_FP64(rawbits_to_double(qn_raw ^ kDSignMask), d13); + CHECK_EQUAL_FP64(qn, d11); + CHECK_EQUAL_FP64(rawbits_to_double(qn_raw & ~kDSignMask), d12); + CHECK_EQUAL_FP64(rawbits_to_double(qn_raw ^ kDSignMask), d13); // - Signalling NaN - ASSERT_EQUAL_FP64(sn_proc, d4); - ASSERT_EQUAL_FP64(sn_proc, d5); - ASSERT_EQUAL_FP64(sn_proc, d6); - ASSERT_EQUAL_FP64(sn_proc, d7); + CHECK_EQUAL_FP64(sn_proc, d4); + CHECK_EQUAL_FP64(sn_proc, d5); + CHECK_EQUAL_FP64(sn_proc, d6); + CHECK_EQUAL_FP64(sn_proc, d7); // - Quiet NaN - ASSERT_EQUAL_FP64(qn_proc, d14); - ASSERT_EQUAL_FP64(qn_proc, d15); - ASSERT_EQUAL_FP64(qn_proc, d16); - ASSERT_EQUAL_FP64(qn_proc, d17); + CHECK_EQUAL_FP64(qn_proc, d14); + CHECK_EQUAL_FP64(qn_proc, d15); + CHECK_EQUAL_FP64(qn_proc, d16); + CHECK_EQUAL_FP64(qn_proc, d17); TEARDOWN(); } @@ -10272,14 +10493,14 @@ TEST(process_nan_float) { // Make sure that NaN propagation works correctly. float sn = rawbits_to_float(0x7f951111); float qn = rawbits_to_float(0x7fea1111); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsQuietNaN(qn)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsQuietNaN(qn)); // The input NaNs after passing through ProcessNaN. float sn_proc = rawbits_to_float(0x7fd51111); float qn_proc = qn; - ASSERT(IsQuietNaN(sn_proc)); - ASSERT(IsQuietNaN(qn_proc)); + DCHECK(IsQuietNaN(sn_proc)); + DCHECK(IsQuietNaN(qn_proc)); SETUP(); START(); @@ -10320,32 +10541,32 @@ TEST(process_nan_float) { uint32_t sn_raw = float_to_rawbits(sn); // - Signalling NaN - ASSERT_EQUAL_FP32(sn, s1); - ASSERT_EQUAL_FP32(rawbits_to_float(sn_raw & ~kSSignMask), s2); - ASSERT_EQUAL_FP32(rawbits_to_float(sn_raw ^ kSSignMask), s3); + CHECK_EQUAL_FP32(sn, s1); + CHECK_EQUAL_FP32(rawbits_to_float(sn_raw & ~kSSignMask), s2); + CHECK_EQUAL_FP32(rawbits_to_float(sn_raw ^ kSSignMask), s3); // - Quiet NaN - ASSERT_EQUAL_FP32(qn, s11); - ASSERT_EQUAL_FP32(rawbits_to_float(qn_raw & ~kSSignMask), s12); - ASSERT_EQUAL_FP32(rawbits_to_float(qn_raw ^ kSSignMask), s13); + CHECK_EQUAL_FP32(qn, s11); + CHECK_EQUAL_FP32(rawbits_to_float(qn_raw & ~kSSignMask), s12); + CHECK_EQUAL_FP32(rawbits_to_float(qn_raw ^ kSSignMask), s13); // - Signalling NaN - ASSERT_EQUAL_FP32(sn_proc, s4); - ASSERT_EQUAL_FP32(sn_proc, s5); - ASSERT_EQUAL_FP32(sn_proc, s6); - ASSERT_EQUAL_FP32(sn_proc, s7); + CHECK_EQUAL_FP32(sn_proc, s4); + CHECK_EQUAL_FP32(sn_proc, s5); + CHECK_EQUAL_FP32(sn_proc, s6); + CHECK_EQUAL_FP32(sn_proc, s7); // - Quiet NaN - ASSERT_EQUAL_FP32(qn_proc, s14); - ASSERT_EQUAL_FP32(qn_proc, s15); - ASSERT_EQUAL_FP32(qn_proc, s16); - ASSERT_EQUAL_FP32(qn_proc, s17); + CHECK_EQUAL_FP32(qn_proc, s14); + CHECK_EQUAL_FP32(qn_proc, s15); + CHECK_EQUAL_FP32(qn_proc, s16); + CHECK_EQUAL_FP32(qn_proc, s17); TEARDOWN(); } static void ProcessNaNsHelper(double n, double m, double expected) { - ASSERT(std::isnan(n) || std::isnan(m)); - ASSERT(isnan(expected)); + DCHECK(std::isnan(n) || std::isnan(m)); + DCHECK(std::isnan(expected)); SETUP(); START(); @@ -10365,12 +10586,12 @@ static void ProcessNaNsHelper(double n, double m, double expected) { END(); RUN(); - ASSERT_EQUAL_FP64(expected, d2); - ASSERT_EQUAL_FP64(expected, d3); - ASSERT_EQUAL_FP64(expected, d4); - ASSERT_EQUAL_FP64(expected, d5); - ASSERT_EQUAL_FP64(expected, d6); - ASSERT_EQUAL_FP64(expected, d7); + CHECK_EQUAL_FP64(expected, d2); + CHECK_EQUAL_FP64(expected, d3); + CHECK_EQUAL_FP64(expected, d4); + CHECK_EQUAL_FP64(expected, d5); + CHECK_EQUAL_FP64(expected, d6); + CHECK_EQUAL_FP64(expected, d7); TEARDOWN(); } @@ -10383,20 +10604,20 @@ TEST(process_nans_double) { double sm = rawbits_to_double(0x7ff5555522222222); double qn = rawbits_to_double(0x7ffaaaaa11111111); double qm = rawbits_to_double(0x7ffaaaaa22222222); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsSignallingNaN(sm)); - ASSERT(IsQuietNaN(qn)); - ASSERT(IsQuietNaN(qm)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsSignallingNaN(sm)); + DCHECK(IsQuietNaN(qn)); + DCHECK(IsQuietNaN(qm)); // The input NaNs after passing through ProcessNaN. double sn_proc = rawbits_to_double(0x7ffd555511111111); double sm_proc = rawbits_to_double(0x7ffd555522222222); double qn_proc = qn; double qm_proc = qm; - ASSERT(IsQuietNaN(sn_proc)); - ASSERT(IsQuietNaN(sm_proc)); - ASSERT(IsQuietNaN(qn_proc)); - ASSERT(IsQuietNaN(qm_proc)); + DCHECK(IsQuietNaN(sn_proc)); + DCHECK(IsQuietNaN(sm_proc)); + DCHECK(IsQuietNaN(qn_proc)); + DCHECK(IsQuietNaN(qm_proc)); // Quiet NaNs are propagated. ProcessNaNsHelper(qn, 0, qn_proc); @@ -10416,8 +10637,8 @@ TEST(process_nans_double) { static void ProcessNaNsHelper(float n, float m, float expected) { - ASSERT(std::isnan(n) || std::isnan(m)); - ASSERT(isnan(expected)); + DCHECK(std::isnan(n) || std::isnan(m)); + DCHECK(std::isnan(expected)); SETUP(); START(); @@ -10437,12 +10658,12 @@ static void ProcessNaNsHelper(float n, float m, float expected) { END(); RUN(); - ASSERT_EQUAL_FP32(expected, s2); - ASSERT_EQUAL_FP32(expected, s3); - ASSERT_EQUAL_FP32(expected, s4); - ASSERT_EQUAL_FP32(expected, s5); - ASSERT_EQUAL_FP32(expected, s6); - ASSERT_EQUAL_FP32(expected, s7); + CHECK_EQUAL_FP32(expected, s2); + CHECK_EQUAL_FP32(expected, s3); + CHECK_EQUAL_FP32(expected, s4); + CHECK_EQUAL_FP32(expected, s5); + CHECK_EQUAL_FP32(expected, s6); + CHECK_EQUAL_FP32(expected, s7); TEARDOWN(); } @@ -10455,20 +10676,20 @@ TEST(process_nans_float) { float sm = rawbits_to_float(0x7f952222); float qn = rawbits_to_float(0x7fea1111); float qm = rawbits_to_float(0x7fea2222); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsSignallingNaN(sm)); - ASSERT(IsQuietNaN(qn)); - ASSERT(IsQuietNaN(qm)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsSignallingNaN(sm)); + DCHECK(IsQuietNaN(qn)); + DCHECK(IsQuietNaN(qm)); // The input NaNs after passing through ProcessNaN. float sn_proc = rawbits_to_float(0x7fd51111); float sm_proc = rawbits_to_float(0x7fd52222); float qn_proc = qn; float qm_proc = qm; - ASSERT(IsQuietNaN(sn_proc)); - ASSERT(IsQuietNaN(sm_proc)); - ASSERT(IsQuietNaN(qn_proc)); - ASSERT(IsQuietNaN(qm_proc)); + DCHECK(IsQuietNaN(sn_proc)); + DCHECK(IsQuietNaN(sm_proc)); + DCHECK(IsQuietNaN(qn_proc)); + DCHECK(IsQuietNaN(qm_proc)); // Quiet NaNs are propagated. ProcessNaNsHelper(qn, 0, qn_proc); @@ -10488,7 +10709,7 @@ TEST(process_nans_float) { static void DefaultNaNHelper(float n, float m, float a) { - ASSERT(std::isnan(n) || std::isnan(m) || isnan(a)); + DCHECK(std::isnan(n) || std::isnan(m) || std::isnan(a)); bool test_1op = std::isnan(n); bool test_2op = std::isnan(n) || std::isnan(m); @@ -10545,29 +10766,29 @@ static void DefaultNaNHelper(float n, float m, float a) { if (test_1op) { uint32_t n_raw = float_to_rawbits(n); - ASSERT_EQUAL_FP32(n, s10); - ASSERT_EQUAL_FP32(rawbits_to_float(n_raw & ~kSSignMask), s11); - ASSERT_EQUAL_FP32(rawbits_to_float(n_raw ^ kSSignMask), s12); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s13); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s14); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s15); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s16); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d17); + CHECK_EQUAL_FP32(n, s10); + CHECK_EQUAL_FP32(rawbits_to_float(n_raw & ~kSSignMask), s11); + CHECK_EQUAL_FP32(rawbits_to_float(n_raw ^ kSSignMask), s12); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s13); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s14); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s15); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s16); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d17); } if (test_2op) { - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s18); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s19); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s20); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s21); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s22); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s23); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s18); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s19); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s20); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s21); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s22); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s23); } - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s24); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s25); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s26); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s27); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s24); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s25); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s26); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s27); TEARDOWN(); } @@ -10581,12 +10802,12 @@ TEST(default_nan_float) { float qn = rawbits_to_float(0x7fea1111); float qm = rawbits_to_float(0x7fea2222); float qa = rawbits_to_float(0x7feaaaaa); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsSignallingNaN(sm)); - ASSERT(IsSignallingNaN(sa)); - ASSERT(IsQuietNaN(qn)); - ASSERT(IsQuietNaN(qm)); - ASSERT(IsQuietNaN(qa)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsSignallingNaN(sm)); + DCHECK(IsSignallingNaN(sa)); + DCHECK(IsQuietNaN(qn)); + DCHECK(IsQuietNaN(qm)); + DCHECK(IsQuietNaN(qa)); // - Signalling NaNs DefaultNaNHelper(sn, 0.0f, 0.0f); @@ -10616,7 +10837,7 @@ TEST(default_nan_float) { static void DefaultNaNHelper(double n, double m, double a) { - ASSERT(std::isnan(n) || std::isnan(m) || isnan(a)); + DCHECK(std::isnan(n) || std::isnan(m) || std::isnan(a)); bool test_1op = std::isnan(n); bool test_2op = std::isnan(n) || std::isnan(m); @@ -10673,29 +10894,29 @@ static void DefaultNaNHelper(double n, double m, double a) { if (test_1op) { uint64_t n_raw = double_to_rawbits(n); - ASSERT_EQUAL_FP64(n, d10); - ASSERT_EQUAL_FP64(rawbits_to_double(n_raw & ~kDSignMask), d11); - ASSERT_EQUAL_FP64(rawbits_to_double(n_raw ^ kDSignMask), d12); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d13); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d14); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d15); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d16); - ASSERT_EQUAL_FP32(kFP32DefaultNaN, s17); + CHECK_EQUAL_FP64(n, d10); + CHECK_EQUAL_FP64(rawbits_to_double(n_raw & ~kDSignMask), d11); + CHECK_EQUAL_FP64(rawbits_to_double(n_raw ^ kDSignMask), d12); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d13); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d14); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d15); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d16); + CHECK_EQUAL_FP32(kFP32DefaultNaN, s17); } if (test_2op) { - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d18); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d19); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d20); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d21); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d22); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d23); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d18); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d19); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d20); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d21); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d22); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d23); } - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d24); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d25); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d26); - ASSERT_EQUAL_FP64(kFP64DefaultNaN, d27); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d24); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d25); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d26); + CHECK_EQUAL_FP64(kFP64DefaultNaN, d27); TEARDOWN(); } @@ -10709,12 +10930,12 @@ TEST(default_nan_double) { double qn = rawbits_to_double(0x7ffaaaaa11111111); double qm = rawbits_to_double(0x7ffaaaaa22222222); double qa = rawbits_to_double(0x7ffaaaaaaaaaaaaa); - ASSERT(IsSignallingNaN(sn)); - ASSERT(IsSignallingNaN(sm)); - ASSERT(IsSignallingNaN(sa)); - ASSERT(IsQuietNaN(qn)); - ASSERT(IsQuietNaN(qm)); - ASSERT(IsQuietNaN(qa)); + DCHECK(IsSignallingNaN(sn)); + DCHECK(IsSignallingNaN(sm)); + DCHECK(IsSignallingNaN(sa)); + DCHECK(IsQuietNaN(qn)); + DCHECK(IsQuietNaN(qm)); + DCHECK(IsQuietNaN(qa)); // - Signalling NaNs DefaultNaNHelper(sn, 0.0, 0.0); @@ -10775,7 +10996,7 @@ TEST(call_no_relocation) { RUN(); - ASSERT_EQUAL_64(1, x0); + CHECK_EQUAL_64(1, x0); // The return_address_from_call_start function doesn't currently encounter any // non-relocatable sequences, so we check it here to make sure it works. @@ -10832,12 +11053,12 @@ static void AbsHelperX(int64_t value) { END(); RUN(); - ASSERT_EQUAL_64(0, x0); - ASSERT_EQUAL_64(value, x1); - ASSERT_EQUAL_64(expected, x10); - ASSERT_EQUAL_64(expected, x11); - ASSERT_EQUAL_64(expected, x12); - ASSERT_EQUAL_64(expected, x13); + CHECK_EQUAL_64(0, x0); + CHECK_EQUAL_64(value, x1); + CHECK_EQUAL_64(expected, x10); + CHECK_EQUAL_64(expected, x11); + CHECK_EQUAL_64(expected, x12); + CHECK_EQUAL_64(expected, x13); TEARDOWN(); } @@ -10889,12 +11110,12 @@ static void AbsHelperW(int32_t value) { END(); RUN(); - ASSERT_EQUAL_32(0, w0); - ASSERT_EQUAL_32(value, w1); - ASSERT_EQUAL_32(expected, w10); - ASSERT_EQUAL_32(expected, w11); - ASSERT_EQUAL_32(expected, w12); - ASSERT_EQUAL_32(expected, w13); + CHECK_EQUAL_32(0, w0); + CHECK_EQUAL_32(value, w1); + CHECK_EQUAL_32(expected, w10); + CHECK_EQUAL_32(expected, w11); + CHECK_EQUAL_32(expected, w12); + CHECK_EQUAL_32(expected, w13); TEARDOWN(); } @@ -10952,16 +11173,16 @@ TEST(pool_size) { for (RelocIterator it(*code, pool_mask); !it.done(); it.next()) { RelocInfo* info = it.rinfo(); if (RelocInfo::IsConstPool(info->rmode())) { - ASSERT(info->data() == constant_pool_size); + DCHECK(info->data() == constant_pool_size); ++pool_count; } if (RelocInfo::IsVeneerPool(info->rmode())) { - ASSERT(info->data() == veneer_pool_size); + DCHECK(info->data() == veneer_pool_size); ++pool_count; } } - ASSERT(pool_count == 2); + DCHECK(pool_count == 2); TEARDOWN(); } diff --git a/deps/v8/test/cctest/test-assembler-ia32.cc b/deps/v8/test/cctest/test-assembler-ia32.cc index ba83b3d7ea..e8c7f951fe 100644 --- a/deps/v8/test/cctest/test-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-assembler-ia32.cc @@ -27,14 +27,15 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "disassembler.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" -#include "serialize.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "src/disassembler.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/ostreams.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -63,7 +64,8 @@ TEST(AssemblerIa320) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F2 f = FUNCTION_CAST<F2>(code->entry()); int res = f(3, 4); @@ -99,7 +101,8 @@ TEST(AssemblerIa321) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = f(100); @@ -139,7 +142,8 @@ TEST(AssemblerIa322) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); int res = f(10); @@ -152,7 +156,6 @@ typedef int (*F3)(float x); TEST(AssemblerIa323) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); @@ -160,11 +163,8 @@ TEST(AssemblerIa323) { v8::internal::byte buffer[256]; Assembler assm(isolate, buffer, sizeof buffer); - CHECK(CpuFeatures::IsSupported(SSE2)); - { CpuFeatureScope fscope(&assm, SSE2); - __ cvttss2si(eax, Operand(esp, 4)); - __ ret(0); - } + __ cvttss2si(eax, Operand(esp, 4)); + __ ret(0); CodeDesc desc; assm.GetCode(&desc); @@ -186,7 +186,6 @@ typedef int (*F4)(double x); TEST(AssemblerIa324) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); @@ -194,8 +193,6 @@ TEST(AssemblerIa324) { v8::internal::byte buffer[256]; Assembler assm(isolate, buffer, sizeof buffer); - CHECK(CpuFeatures::IsSupported(SSE2)); - CpuFeatureScope fscope(&assm, SSE2); __ cvttsd2si(eax, Operand(esp, 4)); __ ret(0); @@ -241,14 +238,12 @@ typedef double (*F5)(double x, double y); TEST(AssemblerIa326) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); v8::internal::byte buffer[256]; Assembler assm(isolate, buffer, sizeof buffer); - CpuFeatureScope fscope(&assm, SSE2); __ movsd(xmm0, Operand(esp, 1 * kPointerSize)); __ movsd(xmm1, Operand(esp, 3 * kPointerSize)); __ addsd(xmm0, xmm1); @@ -285,13 +280,11 @@ typedef double (*F6)(int x); TEST(AssemblerIa328) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); v8::internal::byte buffer[256]; Assembler assm(isolate, buffer, sizeof buffer); - CpuFeatureScope fscope(&assm, SSE2); __ mov(eax, Operand(esp, 4)); __ cvtsi2sd(xmm0, eax); // Copy xmm0 to st(0) using eight bytes of stack. @@ -305,7 +298,8 @@ TEST(AssemblerIa328) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F6 f = FUNCTION_CAST<F6>(code->entry()); double res = f(12); @@ -358,14 +352,15 @@ TEST(AssemblerIa329) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F7 f = FUNCTION_CAST<F7>(code->entry()); CHECK_EQ(kLess, f(1.1, 2.2)); CHECK_EQ(kEqual, f(2.2, 2.2)); CHECK_EQ(kGreater, f(3.3, 2.2)); - CHECK_EQ(kNaN, f(OS::nan_value(), 1.1)); + CHECK_EQ(kNaN, f(v8::base::OS::nan_value(), 1.1)); } @@ -462,9 +457,6 @@ void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) { v8::internal::byte buffer[256]; Assembler assm(isolate, buffer, sizeof buffer); - ASSERT(CpuFeatures::IsSupported(SSE2)); - CpuFeatureScope fscope(&assm, SSE2); - // Remove return address from the stack for fix stack frame alignment. __ pop(ecx); @@ -500,9 +492,7 @@ void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) { TEST(StackAlignmentForSSE2) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; - - CHECK_EQ(0, OS::ActivationFrameAlignment() % 16); + CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16); v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); @@ -540,15 +530,13 @@ TEST(StackAlignmentForSSE2) { TEST(AssemblerIa32Extractps) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2) || - !CpuFeatures::IsSupported(SSE4_1)) return; + if (!CpuFeatures::IsSupported(SSE4_1)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); v8::internal::byte buffer[256]; MacroAssembler assm(isolate, buffer, sizeof buffer); - { CpuFeatureScope fscope2(&assm, SSE2); - CpuFeatureScope fscope41(&assm, SSE4_1); + { CpuFeatureScope fscope41(&assm, SSE4_1); __ movsd(xmm1, Operand(esp, 4)); __ extractps(eax, xmm1, 0x1); __ ret(0); @@ -559,7 +547,8 @@ TEST(AssemblerIa32Extractps) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F4 f = FUNCTION_CAST<F4>(code->entry()); @@ -573,14 +562,12 @@ TEST(AssemblerIa32Extractps) { typedef int (*F8)(float x, float y); TEST(AssemblerIa32SSE) { CcTest::InitializeVM(); - if (!CpuFeatures::IsSupported(SSE2)) return; Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); HandleScope scope(isolate); v8::internal::byte buffer[256]; MacroAssembler assm(isolate, buffer, sizeof buffer); { - CpuFeatureScope fscope(&assm, SSE2); __ movss(xmm0, Operand(esp, kPointerSize)); __ movss(xmm1, Operand(esp, 2 * kPointerSize)); __ shufps(xmm0, xmm0, 0x0); @@ -599,7 +586,8 @@ TEST(AssemblerIa32SSE) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F8 f = FUNCTION_CAST<F8>(code->entry()); diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc index e93c1ca45d..cd1d5d6cc7 100644 --- a/deps/v8/test/cctest/test-assembler-mips.cc +++ b/deps/v8/test/cctest/test-assembler-mips.cc @@ -25,15 +25,15 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "disassembler.h" -#include "factory.h" -#include "macro-assembler.h" -#include "mips/macro-assembler-mips.h" -#include "mips/simulator-mips.h" +#include "src/disassembler.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/mips/macro-assembler-mips.h" +#include "src/mips/simulator-mips.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc new file mode 100644 index 0000000000..4e9238930a --- /dev/null +++ b/deps/v8/test/cctest/test-assembler-mips64.cc @@ -0,0 +1,1375 @@ +// Copyright 2012 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. + +#include "src/v8.h" + +#include "src/disassembler.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/mips64/macro-assembler-mips64.h" +#include "src/mips64/simulator-mips64.h" + +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +// Define these function prototypes to match JSEntryFunction in execution.cc. +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); + + +#define __ assm. + + +TEST(MIPS0) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + // Addition. + __ addu(v0, a0, a1); + __ 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, 0xab0, 0xc, 0, 0, 0)); + ::printf("f() = %ld\n", res); + CHECK_EQ(0xabcL, res); +} + + +TEST(MIPS1) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + Label L, C; + + __ mov(a1, a0); + __ li(v0, 0); + __ b(&C); + __ nop(); + + __ bind(&L); + __ addu(v0, v0, a1); + __ addiu(a1, a1, -1); + + __ bind(&C); + __ xori(v1, a1, 0); + __ Branch(&L, ne, v1, Operand((int64_t)0)); + __ nop(); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F1 f = FUNCTION_CAST<F1>(code->entry()); + int64_t res = + reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 50, 0, 0, 0, 0)); + ::printf("f() = %ld\n", res); + CHECK_EQ(1275L, res); +} + + +TEST(MIPS2) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + + Label exit, error; + + // ----- Test all instructions. + + // Test lui, ori, and addiu, used in the li pseudo-instruction. + // This way we can then safely load registers with chosen values. + + __ ori(a4, zero_reg, 0); + __ lui(a4, 0x1234); + __ ori(a4, a4, 0); + __ ori(a4, a4, 0x0f0f); + __ ori(a4, a4, 0xf0f0); + __ addiu(a5, a4, 1); + __ addiu(a6, a5, -0x10); + + // Load values in temporary registers. + __ li(a4, 0x00000004); + __ li(a5, 0x00001234); + __ li(a6, 0x12345678); + __ li(a7, 0x7fffffff); + __ li(t0, 0xfffffffc); + __ li(t1, 0xffffedcc); + __ li(t2, 0xedcba988); + __ li(t3, 0x80000000); + + // SPECIAL class. + __ srl(v0, a6, 8); // 0x00123456 + __ sll(v0, v0, 11); // 0x91a2b000 + __ sra(v0, v0, 3); // 0xf2345600 + __ srav(v0, v0, a4); // 0xff234560 + __ sllv(v0, v0, a4); // 0xf2345600 + __ srlv(v0, v0, a4); // 0x0f234560 + __ Branch(&error, ne, v0, Operand(0x0f234560)); + __ nop(); + + __ addu(v0, a4, a5); // 0x00001238 + __ subu(v0, v0, a4); // 0x00001234 + __ Branch(&error, ne, v0, Operand(0x00001234)); + __ nop(); + __ addu(v1, a7, a4); // 32bit addu result is sign-extended into 64bit reg. + __ Branch(&error, ne, v1, Operand(0xffffffff80000003)); + __ nop(); + __ subu(v1, t3, a4); // 0x7ffffffc + __ Branch(&error, ne, v1, Operand(0x7ffffffc)); + __ nop(); + + __ and_(v0, a5, a6); // 0x0000000000001230 + __ or_(v0, v0, a5); // 0x0000000000001234 + __ xor_(v0, v0, a6); // 0x000000001234444c + __ nor(v0, v0, a6); // 0xffffffffedcba987 + __ Branch(&error, ne, v0, Operand(0xffffffffedcba983)); + __ nop(); + + // Shift both 32bit number to left, to preserve meaning of next comparison. + __ dsll32(a7, a7, 0); + __ dsll32(t3, t3, 0); + + __ slt(v0, t3, a7); + __ Branch(&error, ne, v0, Operand(0x1)); + __ nop(); + __ sltu(v0, t3, a7); + __ Branch(&error, ne, v0, Operand(zero_reg)); + __ nop(); + + // Restore original values in registers. + __ dsrl32(a7, a7, 0); + __ dsrl32(t3, t3, 0); + // End of SPECIAL class. + + __ addiu(v0, zero_reg, 0x7421); // 0x00007421 + __ addiu(v0, v0, -0x1); // 0x00007420 + __ addiu(v0, v0, -0x20); // 0x00007400 + __ Branch(&error, ne, v0, Operand(0x00007400)); + __ nop(); + __ addiu(v1, a7, 0x1); // 0x80000000 - result is sign-extended. + __ Branch(&error, ne, v1, Operand(0xffffffff80000000)); + __ nop(); + + __ slti(v0, a5, 0x00002000); // 0x1 + __ slti(v0, v0, 0xffff8000); // 0x0 + __ Branch(&error, ne, v0, Operand(zero_reg)); + __ nop(); + __ sltiu(v0, a5, 0x00002000); // 0x1 + __ sltiu(v0, v0, 0x00008000); // 0x1 + __ Branch(&error, ne, v0, Operand(0x1)); + __ nop(); + + __ andi(v0, a5, 0xf0f0); // 0x00001030 + __ ori(v0, v0, 0x8a00); // 0x00009a30 + __ xori(v0, v0, 0x83cc); // 0x000019fc + __ Branch(&error, ne, v0, Operand(0x000019fc)); + __ nop(); + __ lui(v1, 0x8123); // Result is sign-extended into 64bit register. + __ Branch(&error, ne, v1, Operand(0xffffffff81230000)); + __ nop(); + + // Bit twiddling instructions & conditional moves. + // Uses a4-t3 as set above. + __ Clz(v0, a4); // 29 + __ Clz(v1, a5); // 19 + __ addu(v0, v0, v1); // 48 + __ Clz(v1, a6); // 3 + __ addu(v0, v0, v1); // 51 + __ Clz(v1, t3); // 0 + __ addu(v0, v0, v1); // 51 + __ Branch(&error, ne, v0, Operand(51)); + __ Movn(a0, a7, a4); // Move a0<-a7 (a4 is NOT 0). + __ Ins(a0, a5, 12, 8); // 0x7ff34fff + __ Branch(&error, ne, a0, Operand(0x7ff34fff)); + __ Movz(a0, t2, t3); // a0 not updated (t3 is NOT 0). + __ Ext(a1, a0, 8, 12); // 0x34f + __ Branch(&error, ne, a1, Operand(0x34f)); + __ Movz(a0, t2, v1); // a0<-t2, v0 is 0, from 8 instr back. + __ Branch(&error, ne, a0, Operand(t2)); + + // Everything was correctly executed. Load the expected result. + __ li(v0, 0x31415926); + __ b(&exit); + __ nop(); + + __ bind(&error); + // Got an error. Return a wrong result. + __ li(v0, 666); + + __ bind(&exit); + __ 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, 0xab0, 0xc, 0, 0, 0)); + ::printf("f() = %ld\n", res); + + CHECK_EQ(0x31415926L, res); +} + + +TEST(MIPS3) { + // Test floating point instructions. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double a; + double b; + double c; + double d; + double e; + double f; + double g; + double h; + double i; + } 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); + Label L, C; + + __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); + __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + __ add_d(f8, f4, f6); + __ sdc1(f8, MemOperand(a0, OFFSET_OF(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(f4, MemOperand(a0, OFFSET_OF(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. + + __ div_d(f12, f10, f4); + __ sdc1(f12, MemOperand(a0, OFFSET_OF(T, f)) ); // f = e / a = 120.44. + + __ sqrt_d(f14, f12); + __ sdc1(f14, MemOperand(a0, OFFSET_OF(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)) ); + __ madd_d(f14, f6, f4, f6); + __ sdc1(f14, MemOperand(a0, OFFSET_OF(T, h)) ); + } + + __ 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.a = 1.5e14; + t.b = 2.75e11; + t.c = 0.0; + t.d = 0.0; + t.e = 0.0; + t.f = 0.0; + t.h = 1.5; + t.i = 2.75; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + CHECK_EQ(1.5e14, t.a); + CHECK_EQ(1.5e14, t.b); + CHECK_EQ(1.50275e14, t.c); + CHECK_EQ(1.50550e14, t.d); + CHECK_EQ(1.8066e16, t.e); + CHECK_EQ(120.44, t.f); + CHECK_EQ(10.97451593465515908537, t.g); + if (kArchVariant == kMips64r2) { + CHECK_EQ(6.875, t.h); + } +} + + +TEST(MIPS4) { + // Test moves between floating point and integer registers. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double a; + double b; + double c; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + Label L, C; + + __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); + __ ldc1(f5, MemOperand(a0, OFFSET_OF(T, b)) ); + + // Swap f4 and f5, by using 3 integer registers, a4-a6, + // both two 32-bit chunks, and one 64-bit chunk. + // mXhc1 is mips32/64-r2 only, not r1, + // but we will not support r1 in practice. + __ mfc1(a4, f4); + __ mfhc1(a5, f4); + __ dmfc1(a6, f5); + + __ mtc1(a4, f5); + __ mthc1(a5, f5); + __ 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)) ); + + __ 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.a = 1.5e22; + t.b = 2.75e11; + t.c = 17.17; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(2.75e11, t.a); + CHECK_EQ(2.75e11, t.b); + CHECK_EQ(1.5e22, t.c); +} + + +TEST(MIPS5) { + // Test conversions between doubles and integers. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double a; + double b; + int i; + int j; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + 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)) ); + + // 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)) ); + + // 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)) ); + + // 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)) ); + + // 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)) ); + + __ 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.a = 1.5e4; + t.b = 2.75e8; + t.i = 12345678; + t.j = -100000; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(12345678.0, t.a); + CHECK_EQ(-100000.0, t.b); + CHECK_EQ(15000, t.i); + CHECK_EQ(275000000, t.j); +} + + +TEST(MIPS6) { + // Test simple memory loads and stores. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + uint32_t ui; + int32_t si; + int32_t r1; + int32_t r2; + int32_t r3; + int32_t r4; + int32_t r5; + int32_t r6; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + Label L, C; + + // Basic word load/store. + __ lw(a4, MemOperand(a0, OFFSET_OF(T, ui)) ); + __ sw(a4, MemOperand(a0, OFFSET_OF(T, r1)) ); + + // lh with positive data. + __ lh(a5, MemOperand(a0, OFFSET_OF(T, ui)) ); + __ sw(a5, MemOperand(a0, OFFSET_OF(T, r2)) ); + + // lh with negative data. + __ lh(a6, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(a6, MemOperand(a0, OFFSET_OF(T, r3)) ); + + // lhu with negative data. + __ lhu(a7, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(a7, MemOperand(a0, OFFSET_OF(T, r4)) ); + + // lb with negative data. + __ lb(t0, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(t0, MemOperand(a0, OFFSET_OF(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)) ); + + __ 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.ui = 0x11223344; + t.si = 0x99aabbcc; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x11223344, t.r1); + CHECK_EQ(0x3344, t.r2); + CHECK_EQ(0xffffbbcc, t.r3); + CHECK_EQ(0x0000bbcc, t.r4); + CHECK_EQ(0xffffffcc, t.r5); + CHECK_EQ(0x3333bbcc, t.r6); +} + + +TEST(MIPS7) { + // Test floating point compare and branch instructions. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double a; + double b; + double c; + double d; + double e; + double f; + int32_t result; + } 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); + Label neither_is_nan, less_than, outa_here; + + __ ldc1(f4, MemOperand(a0, OFFSET_OF(T, a)) ); + __ ldc1(f6, MemOperand(a0, OFFSET_OF(T, b)) ); + if (kArchVariant != kMips64r6) { + __ c(UN, D, f4, f6); + __ bc1f(&neither_is_nan); + } else { + __ cmp(UN, L, f2, f4, f6); + __ bc1eqz(&neither_is_nan, f2); + } + __ nop(); + __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ Branch(&outa_here); + + __ bind(&neither_is_nan); + + if (kArchVariant == kMips64r6) { + __ cmp(OLT, L, f2, f6, f4); + __ bc1nez(&less_than, f2); + } else { + __ c(OLT, D, f6, f4, 2); + __ bc1t(&less_than, 2); + } + + __ nop(); + __ sw(zero_reg, MemOperand(a0, OFFSET_OF(T, result)) ); + __ Branch(&outa_here); + + __ bind(&less_than); + __ Addu(a4, zero_reg, Operand(1)); + __ sw(a4, MemOperand(a0, OFFSET_OF(T, result)) ); // Set true. + + + // This test-case should have additional tests. + + __ bind(&outa_here); + + __ 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.a = 1.5e14; + t.b = 2.75e11; + t.c = 2.0; + t.d = -4.0; + t.e = 0.0; + t.f = 0.0; + t.result = 0; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + CHECK_EQ(1.5e14, t.a); + CHECK_EQ(2.75e11, t.b); + CHECK_EQ(1, t.result); +} + + +TEST(MIPS8) { + // Test ROTR and ROTRV instructions. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + int32_t input; + int32_t result_rotr_4; + int32_t result_rotr_8; + int32_t result_rotr_12; + int32_t result_rotr_16; + int32_t result_rotr_20; + int32_t result_rotr_24; + int32_t result_rotr_28; + int32_t result_rotrv_4; + int32_t result_rotrv_8; + int32_t result_rotrv_12; + int32_t result_rotrv_16; + int32_t result_rotrv_20; + int32_t result_rotrv_24; + int32_t result_rotrv_28; + } T; + T t; + + MacroAssembler assm(isolate, NULL, 0); + + // Basic word load. + __ lw(a4, MemOperand(a0, OFFSET_OF(T, input)) ); + + // ROTR instruction (called through the Ror macro). + __ Ror(a5, a4, 0x0004); + __ Ror(a6, a4, 0x0008); + __ Ror(a7, a4, 0x000c); + __ Ror(t0, a4, 0x0010); + __ Ror(t1, a4, 0x0014); + __ Ror(t2, a4, 0x0018); + __ 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)) ); + + // ROTRV instruction (called through the Ror macro). + __ li(t3, 0x0004); + __ Ror(a5, a4, t3); + __ li(t3, 0x0008); + __ Ror(a6, a4, t3); + __ li(t3, 0x000C); + __ Ror(a7, a4, t3); + __ li(t3, 0x0010); + __ Ror(t0, a4, t3); + __ li(t3, 0x0014); + __ Ror(t1, a4, t3); + __ li(t3, 0x0018); + __ Ror(t2, a4, t3); + __ li(t3, 0x001C); + __ 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)) ); + + __ 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.input = 0x12345678; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0x0, 0, 0, 0); + USE(dummy); + CHECK_EQ(0x81234567, t.result_rotr_4); + CHECK_EQ(0x78123456, t.result_rotr_8); + CHECK_EQ(0x67812345, t.result_rotr_12); + CHECK_EQ(0x56781234, t.result_rotr_16); + CHECK_EQ(0x45678123, t.result_rotr_20); + CHECK_EQ(0x34567812, t.result_rotr_24); + CHECK_EQ(0x23456781, t.result_rotr_28); + + CHECK_EQ(0x81234567, t.result_rotrv_4); + CHECK_EQ(0x78123456, t.result_rotrv_8); + CHECK_EQ(0x67812345, t.result_rotrv_12); + CHECK_EQ(0x56781234, t.result_rotrv_16); + CHECK_EQ(0x45678123, t.result_rotrv_20); + CHECK_EQ(0x34567812, t.result_rotrv_24); + CHECK_EQ(0x23456781, t.result_rotrv_28); +} + + +TEST(MIPS9) { + // Test BRANCH improvements. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0); + Label exit, exit2, exit3; + + __ Branch(&exit, ge, a0, Operand(zero_reg)); + __ Branch(&exit2, ge, a0, Operand(0x00001FFF)); + __ Branch(&exit3, ge, a0, Operand(0x0001FFFF)); + + __ bind(&exit); + __ bind(&exit2); + __ bind(&exit3); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +} + + +TEST(MIPS10) { + // Test conversions between doubles and long integers. + // Test hos the long ints map to FP regs pairs. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double a; + double a_converted; + double b; + int32_t dbl_mant; + int32_t dbl_exp; + int32_t long_hi; + int32_t long_lo; + int64_t long_as_int64; + int32_t b_long_hi; + int32_t b_long_lo; + int64_t b_long_as_int64; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + Label L, C; + + if (kArchVariant == kMips64r2) { + // Rewritten for FR=1 FPU mode: + // - 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))); + + // 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))); + + // 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))); + + // 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))); + + + // 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))); + __ 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))); + + // Convert double b back to long-int. + __ ldc1(f31, MemOperand(a0, OFFSET_OF(T, b))); + __ cvt_l_d(f31, f31); + __ dmfc1(a7, f31); + __ sd(a7, MemOperand(a0, OFFSET_OF(T, b_long_as_int64))); + + + __ 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.a = 2.147483647e9; // 0x7fffffff -> 0x41DFFFFFFFC00000 as double. + t.b_long_hi = 0x000000ff; // 0xFF00FF00FF -> 0x426FE01FE01FE000 as double. + t.b_long_lo = 0x00ff00ff; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x41DFFFFF, t.dbl_exp); + CHECK_EQ(0xFFC00000, t.dbl_mant); + CHECK_EQ(0, t.long_hi); + CHECK_EQ(0x7fffffff, t.long_lo); + CHECK_EQ(2.147483647e9, t.a_converted); + + // 0xFF00FF00FF -> 1.095233372415e12. + CHECK_EQ(1.095233372415e12, t.b); + CHECK_EQ(0xFF00FF00FF, t.b_long_as_int64); + } +} + + +TEST(MIPS11) { + // Do not run test on MIPS64r6, as these instructions are removed. + if (kArchVariant != kMips64r6) { + // Test LWL, LWR, SWL and SWR instructions. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + int32_t reg_init; + int32_t mem_init; + int32_t lwl_0; + int32_t lwl_1; + int32_t lwl_2; + int32_t lwl_3; + int32_t lwr_0; + int32_t lwr_1; + int32_t lwr_2; + int32_t lwr_3; + int32_t swl_0; + int32_t swl_1; + int32_t swl_2; + int32_t swl_3; + int32_t swr_0; + int32_t swr_1; + int32_t swr_2; + int32_t swr_3; + } T; + T t; + + 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(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(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(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)) ); + + // 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(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(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(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)) ); + + // 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) ); + + // 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) ); + + __ 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.reg_init = 0xaabbccdd; + t.mem_init = 0x11223344; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x44bbccdd, t.lwl_0); + CHECK_EQ(0x3344ccdd, t.lwl_1); + CHECK_EQ(0x223344dd, t.lwl_2); + CHECK_EQ(0x11223344, t.lwl_3); + + CHECK_EQ(0x11223344, t.lwr_0); + CHECK_EQ(0xaa112233, t.lwr_1); + CHECK_EQ(0xaabb1122, t.lwr_2); + CHECK_EQ(0xaabbcc11, t.lwr_3); + + CHECK_EQ(0x112233aa, t.swl_0); + CHECK_EQ(0x1122aabb, t.swl_1); + CHECK_EQ(0x11aabbcc, t.swl_2); + CHECK_EQ(0xaabbccdd, t.swl_3); + + CHECK_EQ(0xaabbccdd, t.swr_0); + CHECK_EQ(0xbbccdd44, t.swr_1); + CHECK_EQ(0xccdd3344, t.swr_2); + CHECK_EQ(0xdd223344, t.swr_3); + } +} + + +TEST(MIPS12) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + int32_t x; + int32_t y; + int32_t y1; + int32_t y2; + int32_t y3; + int32_t y4; + } T; + T t; + + MacroAssembler assm(isolate, NULL, 0); + + __ 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)) ); + + __ addu(a5, a4, a7); + __ subu(t0, a4, a7); + __ nop(); + __ push(a4); // These instructions disappear after opt. + __ Pop(); + __ addu(a4, a4, a4); + __ nop(); + __ Pop(); // These instructions disappear after opt. + __ push(a7); + __ nop(); + __ push(a7); // These instructions disappear after opt. + __ pop(a7); + __ nop(); + __ push(a7); + __ pop(t0); + __ nop(); + __ sw(a4, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(a4, MemOperand(fp, OFFSET_OF(T, y)) ); + __ nop(); + __ sw(a4, MemOperand(fp, OFFSET_OF(T, y)) ); + __ lw(a5, MemOperand(fp, OFFSET_OF(T, y)) ); + __ nop(); + __ push(a5); + __ lw(a5, MemOperand(fp, OFFSET_OF(T, y)) ); + __ pop(a5); + __ nop(); + __ push(a5); + __ lw(a6, MemOperand(fp, OFFSET_OF(T, y)) ); + __ pop(a5); + __ nop(); + __ push(a5); + __ lw(a6, MemOperand(fp, OFFSET_OF(T, y)) ); + __ pop(a6); + __ nop(); + __ push(a6); + __ lw(a6, MemOperand(fp, OFFSET_OF(T, y)) ); + __ pop(a5); + __ nop(); + __ push(a5); + __ lw(a6, MemOperand(fp, OFFSET_OF(T, y)) ); + __ pop(a7); + __ nop(); + + __ mov(fp, t2); + __ 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.x = 1; + t.y = 2; + t.y1 = 3; + t.y2 = 4; + t.y3 = 0XBABA; + t.y4 = 0xDEDA; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(3, t.y1); +} + + +TEST(MIPS13) { + // Test Cvt_d_uw and Trunc_uw_d macros. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + double cvt_big_out; + double cvt_small_out; + uint32_t trunc_big_out; + uint32_t trunc_small_out; + uint32_t cvt_big_in; + uint32_t cvt_small_in; + } T; + T t; + + MacroAssembler assm(isolate, NULL, 0); + + __ sw(a4, MemOperand(a0, OFFSET_OF(T, cvt_small_in))); + __ Cvt_d_uw(f10, a4, f22); + __ sdc1(f10, MemOperand(a0, OFFSET_OF(T, cvt_small_out))); + + __ Trunc_uw_d(f10, f10, f22); + __ swc1(f10, MemOperand(a0, OFFSET_OF(T, trunc_small_out))); + + __ sw(a4, MemOperand(a0, OFFSET_OF(T, cvt_big_in))); + __ Cvt_d_uw(f8, a4, f22); + __ sdc1(f8, MemOperand(a0, OFFSET_OF(T, cvt_big_out))); + + __ Trunc_uw_d(f8, f8, f22); + __ swc1(f8, MemOperand(a0, OFFSET_OF(T, trunc_big_out))); + + __ 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.cvt_big_in = 0xFFFFFFFF; + t.cvt_small_in = 333; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(t.cvt_big_out, static_cast<double>(t.cvt_big_in)); + CHECK_EQ(t.cvt_small_out, static_cast<double>(t.cvt_small_in)); + + CHECK_EQ(static_cast<int>(t.trunc_big_out), static_cast<int>(t.cvt_big_in)); + CHECK_EQ(static_cast<int>(t.trunc_small_out), + static_cast<int>(t.cvt_small_in)); +} + + +TEST(MIPS14) { + // Test round, floor, ceil, trunc, cvt. + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + +#define ROUND_STRUCT_ELEMENT(x) \ + int32_t x##_up_out; \ + int32_t x##_down_out; \ + int32_t neg_##x##_up_out; \ + int32_t neg_##x##_down_out; \ + uint32_t x##_err1_out; \ + uint32_t x##_err2_out; \ + uint32_t x##_err3_out; \ + uint32_t x##_err4_out; \ + int32_t x##_invalid_result; + + typedef struct { + double round_up_in; + double round_down_in; + double neg_round_up_in; + double neg_round_down_in; + double err1_in; + double err2_in; + double err3_in; + double err4_in; + + ROUND_STRUCT_ELEMENT(round) + ROUND_STRUCT_ELEMENT(floor) + ROUND_STRUCT_ELEMENT(ceil) + ROUND_STRUCT_ELEMENT(trunc) + ROUND_STRUCT_ELEMENT(cvt) + } T; + T t; + +#undef ROUND_STRUCT_ELEMENT + + MacroAssembler assm(isolate, NULL, 0); + + // Save FCSR. + __ cfc1(a1, FCSR); + // Disable FPU exceptions. + __ ctc1(zero_reg, FCSR); +#define RUN_ROUND_TEST(x) \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_up_in))); \ + __ x##_w_d(f0, f0); \ + __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_up_out))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, round_down_in))); \ + __ x##_w_d(f0, f0); \ + __ swc1(f0, MemOperand(a0, OFFSET_OF(T, x##_down_out))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_up_in))); \ + __ x##_w_d(f0, f0); \ + __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_up_out))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(T, neg_round_down_in))); \ + __ x##_w_d(f0, f0); \ + __ swc1(f0, MemOperand(a0, OFFSET_OF(T, neg_##x##_down_out))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(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))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(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))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(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))); \ + \ + __ ldc1(f0, MemOperand(a0, OFFSET_OF(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))); + + RUN_ROUND_TEST(round) + RUN_ROUND_TEST(floor) + RUN_ROUND_TEST(ceil) + RUN_ROUND_TEST(trunc) + RUN_ROUND_TEST(cvt) + + // 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()); + + t.round_up_in = 123.51; + t.round_down_in = 123.49; + t.neg_round_up_in = -123.5; + t.neg_round_down_in = -123.49; + t.err1_in = 123.51; + t.err2_in = 1; + t.err3_in = static_cast<double>(1) + 0xFFFFFFFF; + t.err4_in = NAN; + + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + +#define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask)) +#define CHECK_ROUND_RESULT(type) \ + CHECK(GET_FPU_ERR(t.type##_err1_out) & kFCSRInexactFlagMask); \ + CHECK_EQ(0, GET_FPU_ERR(t.type##_err2_out)); \ + CHECK(GET_FPU_ERR(t.type##_err3_out) & kFCSRInvalidOpFlagMask); \ + CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \ + CHECK_EQ(static_cast<int32_t>(kFPUInvalidResult), t.type##_invalid_result); + + CHECK_ROUND_RESULT(round); + CHECK_ROUND_RESULT(floor); + CHECK_ROUND_RESULT(ceil); + CHECK_ROUND_RESULT(cvt); +} + + +TEST(MIPS15) { + // Test chaining of label usages within instructions (issue 1644). + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + Assembler assm(isolate, NULL, 0); + + Label target; + __ beq(v0, v1, &target); + __ nop(); + __ bne(v0, v1, &target); + __ nop(); + __ bind(&target); + __ nop(); +} + + +// ----- mips64 tests ----------------------------------------------- + +TEST(MIPS16) { + // Test 64-bit memory loads and stores. + 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; + uint32_t ui; + int32_t si; + } T; + T t; + + Assembler assm(isolate, NULL, 0); + 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)) ); + + // Check that the data got zero-extended into 64-bit a4. + __ sd(a4, MemOperand(a0, OFFSET_OF(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)) ); + + // Check that the data got sign-extended into 64-bit a4. + __ sd(a5, MemOperand(a0, OFFSET_OF(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)) ); + + // Check that the data got zero-extended into 64-bit a4. + __ sd(a6, MemOperand(a0, OFFSET_OF(T, r6)) ); + + // lh with positive data. + __ lh(a5, MemOperand(a0, OFFSET_OF(T, ui)) ); + __ sw(a5, MemOperand(a0, OFFSET_OF(T, r2)) ); + + // lh with negative data. + __ lh(a6, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(a6, MemOperand(a0, OFFSET_OF(T, r3)) ); + + // lhu with negative data. + __ lhu(a7, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(a7, MemOperand(a0, OFFSET_OF(T, r4)) ); + + // lb with negative data. + __ lb(t0, MemOperand(a0, OFFSET_OF(T, si)) ); + __ sw(t0, MemOperand(a0, OFFSET_OF(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)) ); + + __ 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.ui = 0x44332211; + t.si = 0x99aabbcc; + t.r1 = 0x1111111111111111; + t.r2 = 0x2222222222222222; + t.r3 = 0x3333333333333333; + t.r4 = 0x4444444444444444; + t.r5 = 0x5555555555555555; + t.r6 = 0x6666666666666666; + Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); + USE(dummy); + + // Unsigned data, 32 & 64. + CHECK_EQ(0x1111111144332211L, t.r1); + CHECK_EQ(0x0000000000002211L, t.r2); + + // Signed data, 32 & 64. + CHECK_EQ(0x33333333ffffbbccL, t.r3); + CHECK_EQ(0xffffffff0000bbccL, t.r4); + + // Signed data, 32 & 64. + CHECK_EQ(0x55555555ffffffccL, t.r5); + CHECK_EQ(0x000000003333bbccL, t.r6); +} + +#undef __ diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc index eb9fee8545..3d305b650e 100644 --- a/deps/v8/test/cctest/test-assembler-x64.cc +++ b/deps/v8/test/cctest/test-assembler-x64.cc @@ -27,13 +27,14 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "macro-assembler.h" -#include "factory.h" -#include "platform.h" -#include "serialize.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/ostreams.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -66,11 +67,11 @@ static const Register arg2 = rsi; TEST(AssemblerX64ReturnOperation) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -88,11 +89,11 @@ TEST(AssemblerX64ReturnOperation) { TEST(AssemblerX64StackOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -120,11 +121,11 @@ TEST(AssemblerX64StackOperations) { TEST(AssemblerX64ArithmeticOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -142,11 +143,11 @@ TEST(AssemblerX64ArithmeticOperations) { TEST(AssemblerX64CmpbOperation) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -173,11 +174,11 @@ TEST(AssemblerX64CmpbOperation) { TEST(AssemblerX64ImulOperation) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -201,11 +202,11 @@ TEST(AssemblerX64ImulOperation) { TEST(AssemblerX64XchglOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -229,11 +230,11 @@ TEST(AssemblerX64XchglOperations) { TEST(AssemblerX64OrlOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -253,11 +254,11 @@ TEST(AssemblerX64OrlOperations) { TEST(AssemblerX64RollOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -275,11 +276,11 @@ TEST(AssemblerX64RollOperations) { TEST(AssemblerX64SublOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -299,11 +300,11 @@ TEST(AssemblerX64SublOperations) { TEST(AssemblerX64TestlOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -328,11 +329,11 @@ TEST(AssemblerX64TestlOperations) { TEST(AssemblerX64XorlOperations) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -352,11 +353,11 @@ TEST(AssemblerX64XorlOperations) { TEST(AssemblerX64MemoryOperands) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -386,11 +387,11 @@ TEST(AssemblerX64MemoryOperands) { TEST(AssemblerX64ControlFlow) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); @@ -415,11 +416,11 @@ TEST(AssemblerX64ControlFlow) { TEST(AssemblerX64LoopImmediates) { + CcTest::InitializeVM(); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size)); // Assemble two loops using rax as counter, and verify the ending counts. @@ -635,7 +636,7 @@ void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) { TEST(StackAlignmentForSSE2) { CcTest::InitializeVM(); - CHECK_EQ(0, OS::ActivationFrameAlignment() % 16); + CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16); v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); @@ -689,7 +690,8 @@ TEST(AssemblerX64Extractps) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -727,7 +729,8 @@ TEST(AssemblerX64SSE) { Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); #endif F6 f = FUNCTION_CAST<F6>(code->entry()); diff --git a/deps/v8/test/cctest/test-assembler-x87.cc b/deps/v8/test/cctest/test-assembler-x87.cc new file mode 100644 index 0000000000..8341f9b49e --- /dev/null +++ b/deps/v8/test/cctest/test-assembler-x87.cc @@ -0,0 +1,315 @@ +// Copyright 2011 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. + +#include <stdlib.h> + +#include "src/v8.h" + +#include "src/base/platform/platform.h" +#include "src/disassembler.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/ostreams.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +typedef int (*F0)(); +typedef int (*F1)(int x); +typedef int (*F2)(int x, int y); + + +#define __ assm. + +TEST(AssemblerIa320) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + + v8::internal::byte buffer[256]; + Assembler assm(isolate, buffer, sizeof buffer); + + __ mov(eax, Operand(esp, 4)); + __ add(eax, Operand(esp, 8)); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + F2 f = FUNCTION_CAST<F2>(code->entry()); + int res = f(3, 4); + ::printf("f() = %d\n", res); + CHECK_EQ(7, res); +} + + +TEST(AssemblerIa321) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + + v8::internal::byte buffer[256]; + Assembler assm(isolate, buffer, sizeof buffer); + Label L, C; + + __ mov(edx, Operand(esp, 4)); + __ xor_(eax, eax); // clear eax + __ jmp(&C); + + __ bind(&L); + __ add(eax, edx); + __ sub(edx, Immediate(1)); + + __ bind(&C); + __ test(edx, edx); + __ j(not_zero, &L); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + F1 f = FUNCTION_CAST<F1>(code->entry()); + int res = f(100); + ::printf("f() = %d\n", res); + CHECK_EQ(5050, res); +} + + +TEST(AssemblerIa322) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + + v8::internal::byte buffer[256]; + Assembler assm(isolate, buffer, sizeof buffer); + Label L, C; + + __ mov(edx, Operand(esp, 4)); + __ mov(eax, 1); + __ jmp(&C); + + __ bind(&L); + __ imul(eax, edx); + __ sub(edx, Immediate(1)); + + __ bind(&C); + __ test(edx, edx); + __ j(not_zero, &L); + __ ret(0); + + // some relocated stuff here, not executed + __ mov(eax, isolate->factory()->true_value()); + __ jmp(NULL, RelocInfo::RUNTIME_ENTRY); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + F1 f = FUNCTION_CAST<F1>(code->entry()); + int res = f(10); + ::printf("f() = %d\n", res); + CHECK_EQ(3628800, res); +} + + +typedef int (*F3)(float x); + +typedef int (*F4)(double x); + +static int baz = 42; +TEST(AssemblerIa325) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + + v8::internal::byte buffer[256]; + Assembler assm(isolate, buffer, sizeof buffer); + + __ mov(eax, Operand(reinterpret_cast<intptr_t>(&baz), RelocInfo::NONE32)); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F0 f = FUNCTION_CAST<F0>(code->entry()); + int res = f(); + CHECK_EQ(42, res); +} + + +typedef int (*F7)(double x, double y); + +TEST(AssemblerIa329) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + v8::internal::byte buffer[256]; + MacroAssembler assm(isolate, buffer, sizeof buffer); + enum { kEqual = 0, kGreater = 1, kLess = 2, kNaN = 3, kUndefined = 4 }; + Label equal_l, less_l, greater_l, nan_l; + __ fld_d(Operand(esp, 3 * kPointerSize)); + __ fld_d(Operand(esp, 1 * kPointerSize)); + __ FCmp(); + __ j(parity_even, &nan_l); + __ j(equal, &equal_l); + __ j(below, &less_l); + __ j(above, &greater_l); + + __ mov(eax, kUndefined); + __ ret(0); + + __ bind(&equal_l); + __ mov(eax, kEqual); + __ ret(0); + + __ bind(&greater_l); + __ mov(eax, kGreater); + __ ret(0); + + __ bind(&less_l); + __ mov(eax, kLess); + __ ret(0); + + __ bind(&nan_l); + __ mov(eax, kNaN); + __ ret(0); + + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); +#endif + + F7 f = FUNCTION_CAST<F7>(code->entry()); + CHECK_EQ(kLess, f(1.1, 2.2)); + CHECK_EQ(kEqual, f(2.2, 2.2)); + CHECK_EQ(kGreater, f(3.3, 2.2)); + CHECK_EQ(kNaN, f(v8::base::OS::nan_value(), 1.1)); +} + + +TEST(AssemblerIa3210) { + // Test chaining of label usages within instructions (issue 1644). + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + Assembler assm(isolate, NULL, 0); + + Label target; + __ j(equal, &target); + __ j(not_equal, &target); + __ bind(&target); + __ nop(); +} + + +TEST(AssemblerMultiByteNop) { + CcTest::InitializeVM(); + Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate()); + HandleScope scope(isolate); + v8::internal::byte buffer[1024]; + Assembler assm(isolate, buffer, sizeof(buffer)); + __ push(ebx); + __ push(ecx); + __ push(edx); + __ push(edi); + __ push(esi); + __ mov(eax, 1); + __ mov(ebx, 2); + __ mov(ecx, 3); + __ mov(edx, 4); + __ mov(edi, 5); + __ mov(esi, 6); + for (int i = 0; i < 16; i++) { + int before = assm.pc_offset(); + __ Nop(i); + CHECK_EQ(assm.pc_offset() - before, i); + } + + Label fail; + __ cmp(eax, 1); + __ j(not_equal, &fail); + __ cmp(ebx, 2); + __ j(not_equal, &fail); + __ cmp(ecx, 3); + __ j(not_equal, &fail); + __ cmp(edx, 4); + __ j(not_equal, &fail); + __ cmp(edi, 5); + __ j(not_equal, &fail); + __ cmp(esi, 6); + __ j(not_equal, &fail); + __ mov(eax, 42); + __ pop(esi); + __ pop(edi); + __ pop(edx); + __ pop(ecx); + __ pop(ebx); + __ ret(0); + __ bind(&fail); + __ mov(eax, 13); + __ pop(esi); + __ pop(edi); + __ pop(edx); + __ pop(ecx); + __ pop(ebx); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + CHECK(code->IsCode()); + + F0 f = FUNCTION_CAST<F0>(code->entry()); + int res = f(); + CHECK_EQ(42, res); +} + + +#undef __ diff --git a/deps/v8/test/cctest/test-ast.cc b/deps/v8/test/cctest/test-ast.cc index d6431371aa..a25ae69b61 100644 --- a/deps/v8/test/cctest/test-ast.cc +++ b/deps/v8/test/cctest/test-ast.cc @@ -27,10 +27,10 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "ast.h" -#include "cctest.h" +#include "src/ast.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -41,7 +41,7 @@ TEST(List) { Isolate* isolate = CcTest::i_isolate(); Zone zone(isolate); - AstNodeFactory<AstNullVisitor> factory(&zone); + AstNodeFactory<AstNullVisitor> factory(&zone, NULL); AstNode* node = factory.NewEmptyStatement(RelocInfo::kNoPosition); list->Add(node); CHECK_EQ(1, list->length()); diff --git a/deps/v8/test/cctest/test-atomicops.cc b/deps/v8/test/cctest/test-atomicops.cc index 53df22963d..8b47208ba0 100644 --- a/deps/v8/test/cctest/test-atomicops.cc +++ b/deps/v8/test/cctest/test-atomicops.cc @@ -25,11 +25,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "atomicops.h" +#include "src/base/atomicops.h" +#include "test/cctest/cctest.h" +using namespace v8::base; using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-bignum-dtoa.cc b/deps/v8/test/cctest/test-bignum-dtoa.cc index a696ed8e3f..9262e018c8 100644 --- a/deps/v8/test/cctest/test-bignum-dtoa.cc +++ b/deps/v8/test/cctest/test-bignum-dtoa.cc @@ -27,16 +27,16 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "bignum-dtoa.h" +#include "src/bignum-dtoa.h" -#include "cctest.h" -#include "double.h" -#include "gay-fixed.h" -#include "gay-precision.h" -#include "gay-shortest.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "src/double.h" +#include "test/cctest/cctest.h" +#include "test/cctest/gay-fixed.h" +#include "test/cctest/gay-precision.h" +#include "test/cctest/gay-shortest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-bignum.cc b/deps/v8/test/cctest/test-bignum.cc index 9aa5ef30d0..47ce2a48a9 100644 --- a/deps/v8/test/cctest/test-bignum.cc +++ b/deps/v8/test/cctest/test-bignum.cc @@ -27,11 +27,11 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" -#include "bignum.h" +#include "src/base/platform/platform.h" +#include "src/bignum.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-checks.cc b/deps/v8/test/cctest/test-checks.cc new file mode 100644 index 0000000000..a49a7dbe2a --- /dev/null +++ b/deps/v8/test/cctest/test-checks.cc @@ -0,0 +1,26 @@ +// 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/checks.h" + +#include "test/cctest/cctest.h" + + +TEST(CheckEqualsZeroAndMinusZero) { + CHECK_EQ(0.0, 0.0); + CHECK_NE(0.0, -0.0); + CHECK_NE(-0.0, 0.0); + CHECK_EQ(-0.0, -0.0); +} + + +TEST(CheckEqualsReflexivity) { + double inf = V8_INFINITY; + double nan = v8::base::OS::nan_value(); + double constants[] = {-nan, -inf, -3.1415, -1.0, -0.1, -0.0, + 0.0, 0.1, 1.0, 3.1415, inf, nan}; + for (size_t i = 0; i < ARRAY_SIZE(constants); ++i) { + CHECK_EQ(constants[i], constants[i]); + } +} diff --git a/deps/v8/test/cctest/test-circular-queue.cc b/deps/v8/test/cctest/test-circular-queue.cc index c900be1a64..736a9b7c88 100644 --- a/deps/v8/test/cctest/test-circular-queue.cc +++ b/deps/v8/test/cctest/test-circular-queue.cc @@ -27,15 +27,16 @@ // // Tests of the circular queue. -#include "v8.h" -#include "circular-queue-inl.h" -#include "cctest.h" +#include "src/v8.h" + +#include "src/circular-queue-inl.h" +#include "test/cctest/cctest.h" using i::SamplingCircularQueue; TEST(SamplingCircularQueue) { - typedef i::AtomicWord Record; + typedef v8::base::AtomicWord Record; const int kMaxRecordsInQueue = 4; SamplingCircularQueue<Record, kMaxRecordsInQueue> scq; @@ -99,20 +100,18 @@ TEST(SamplingCircularQueue) { namespace { -typedef i::AtomicWord Record; +typedef v8::base::AtomicWord Record; typedef SamplingCircularQueue<Record, 12> TestSampleQueue; -class ProducerThread: public i::Thread { +class ProducerThread: public v8::base::Thread { public: - ProducerThread(TestSampleQueue* scq, - int records_per_chunk, - Record value, - i::Semaphore* finished) - : Thread("producer"), + ProducerThread(TestSampleQueue* scq, int records_per_chunk, Record value, + v8::base::Semaphore* finished) + : Thread(Options("producer")), scq_(scq), records_per_chunk_(records_per_chunk), value_(value), - finished_(finished) { } + finished_(finished) {} virtual void Run() { for (Record i = value_; i < value_ + records_per_chunk_; ++i) { @@ -129,7 +128,7 @@ class ProducerThread: public i::Thread { TestSampleQueue* scq_; const int records_per_chunk_; Record value_; - i::Semaphore* finished_; + v8::base::Semaphore* finished_; }; } // namespace @@ -142,7 +141,7 @@ TEST(SamplingCircularQueueMultithreading) { const int kRecordsPerChunk = 4; TestSampleQueue scq; - i::Semaphore semaphore(0); + v8::base::Semaphore semaphore(0); ProducerThread producer1(&scq, kRecordsPerChunk, 1, &semaphore); ProducerThread producer2(&scq, kRecordsPerChunk, 10, &semaphore); diff --git a/deps/v8/test/cctest/test-code-stubs-arm.cc b/deps/v8/test/cctest/test-code-stubs-arm.cc index 43233472bb..80403440da 100644 --- a/deps/v8/test/cctest/test-code-stubs-arm.cc +++ b/deps/v8/test/cctest/test-code-stubs-arm.cc @@ -27,15 +27,15 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" -#include "simulator.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/simulator.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -47,9 +47,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, bool inline_fastpath) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); HandleScope handles(isolate); MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size)); @@ -127,7 +126,7 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, CodeDesc desc; masm.GetCode(&desc); - CPU::FlushICache(buffer, actual_size); + CpuFeatures::FlushICache(buffer, actual_size); return (reinterpret_cast<ConvertDToIFunc>( reinterpret_cast<intptr_t>(buffer))); } diff --git a/deps/v8/test/cctest/test-code-stubs-arm64.cc b/deps/v8/test/cctest/test-code-stubs-arm64.cc index 3ad07bf809..6d5b0f49be 100644 --- a/deps/v8/test/cctest/test-code-stubs-arm64.cc +++ b/deps/v8/test/cctest/test-code-stubs-arm64.cc @@ -27,15 +27,15 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" -#include "simulator.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/simulator.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -46,10 +46,9 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, Register destination_reg, bool inline_fastpath) { // Allocate an executable page of memory. - size_t actual_size = 2 * Assembler::kMinimalBufferSize; - byte* buffer = static_cast<byte*>(OS::Allocate(actual_size, - &actual_size, - true)); + size_t actual_size = 4 * Assembler::kMinimalBufferSize; + byte* buffer = static_cast<byte*>( + v8::base::OS::Allocate(actual_size, &actual_size, true)); CHECK(buffer); HandleScope handles(isolate); MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size)); @@ -123,7 +122,7 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, CodeDesc desc; masm.GetCode(&desc); - CPU::FlushICache(buffer, actual_size); + CpuFeatures::FlushICache(buffer, actual_size); return (reinterpret_cast<ConvertDToIFunc>( reinterpret_cast<intptr_t>(buffer))); } diff --git a/deps/v8/test/cctest/test-code-stubs-ia32.cc b/deps/v8/test/cctest/test-code-stubs-ia32.cc index 96639577b4..0b4a8d417b 100644 --- a/deps/v8/test/cctest/test-code-stubs-ia32.cc +++ b/deps/v8/test/cctest/test-code-stubs-ia32.cc @@ -29,14 +29,14 @@ #include <limits> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -47,9 +47,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, Register destination_reg) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); HandleScope handles(isolate); MacroAssembler assm(isolate, buffer, static_cast<int>(actual_size)); diff --git a/deps/v8/test/cctest/test-code-stubs-mips.cc b/deps/v8/test/cctest/test-code-stubs-mips.cc index f889796783..796aa1d610 100644 --- a/deps/v8/test/cctest/test-code-stubs-mips.cc +++ b/deps/v8/test/cctest/test-code-stubs-mips.cc @@ -27,16 +27,16 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "mips/constants-mips.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" -#include "simulator.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/mips/constants-mips.h" +#include "src/simulator.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -48,9 +48,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, bool inline_fastpath) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); HandleScope handles(isolate); MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size)); @@ -128,7 +127,7 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, CodeDesc desc; masm.GetCode(&desc); - CPU::FlushICache(buffer, actual_size); + CpuFeatures::FlushICache(buffer, actual_size); return (reinterpret_cast<ConvertDToIFunc>( reinterpret_cast<intptr_t>(buffer))); } diff --git a/deps/v8/test/cctest/test-code-stubs-mips64.cc b/deps/v8/test/cctest/test-code-stubs-mips64.cc new file mode 100644 index 0000000000..025a8ba04b --- /dev/null +++ b/deps/v8/test/cctest/test-code-stubs-mips64.cc @@ -0,0 +1,188 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Rrdistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Rrdistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Rrdistributions 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. + +#include <stdlib.h> + +#include "src/v8.h" + +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/mips64/constants-mips64.h" +#include "src/simulator.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" + +using namespace v8::internal; + +#define __ masm. + +ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, + Register source_reg, + Register destination_reg, + bool inline_fastpath) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); + CHECK(buffer); + HandleScope handles(isolate); + MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size)); + DoubleToIStub stub(isolate, source_reg, destination_reg, 0, true, + inline_fastpath); + + byte* start = stub.GetCode()->instruction_start(); + Label done; + + // Save callee save registers. + __ MultiPush(kCalleeSaved | ra.bit()); + + // For softfp, move the input value into f12. + if (IsMipsSoftFloatABI) { + __ Move(f12, a0, a1); + } + // Push the double argument. + __ Dsubu(sp, sp, Operand(kDoubleSize)); + __ sdc1(f12, MemOperand(sp)); + __ Move(source_reg, sp); + + // Save registers make sure they don't get clobbered. + int source_reg_offset = kDoubleSize; + int reg_num = 2; + for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { + Register reg = Register::from_code(reg_num); + if (!reg.is(destination_reg)) { + __ push(reg); + source_reg_offset += kPointerSize; + } + } + + // Re-push the double argument. + __ Dsubu(sp, sp, Operand(kDoubleSize)); + __ sdc1(f12, MemOperand(sp)); + + // Call through to the actual stub + if (inline_fastpath) { + __ ldc1(f12, MemOperand(source_reg)); + __ TryInlineTruncateDoubleToI(destination_reg, f12, &done); + if (destination_reg.is(source_reg) && !source_reg.is(sp)) { + // Restore clobbered source_reg. + __ Daddu(source_reg, sp, Operand(source_reg_offset)); + } + } + __ Call(start, RelocInfo::EXTERNAL_REFERENCE); + __ bind(&done); + + __ Daddu(sp, sp, Operand(kDoubleSize)); + + // Make sure no registers have been unexpectedly clobbered + for (--reg_num; reg_num >= 2; --reg_num) { + Register reg = Register::from_code(reg_num); + if (!reg.is(destination_reg)) { + __ lw(at, MemOperand(sp, 0)); + __ Assert(eq, kRegisterWasClobbered, reg, Operand(at)); + __ Daddu(sp, sp, Operand(kPointerSize)); + } + } + + __ Daddu(sp, sp, Operand(kDoubleSize)); + + __ Move(v0, destination_reg); + Label ok; + __ Branch(&ok, eq, v0, Operand(zero_reg)); + __ bind(&ok); + + // Restore callee save registers. + __ MultiPop(kCalleeSaved | ra.bit()); + + Label ok1; + __ Branch(&ok1, eq, v0, Operand(zero_reg)); + __ bind(&ok1); + __ Ret(); + + CodeDesc desc; + masm.GetCode(&desc); + CpuFeatures::FlushICache(buffer, actual_size); + return (reinterpret_cast<ConvertDToIFunc>( + reinterpret_cast<intptr_t>(buffer))); +} + +#undef __ + + +static Isolate* GetIsolateFrom(LocalContext* context) { + return reinterpret_cast<Isolate*>((*context)->GetIsolate()); +} + + +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()); +#else + return (*func)(from); +#endif +} + + +TEST(ConvertDToI) { + CcTest::InitializeVM(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + HandleScope scope(isolate); + +#if DEBUG + // Verify that the tests actually work with the C version. In the release + // code, the compiler optimizes it away because it's all constant, but does it + // wrong, triggering an assert on gcc. + RunAllTruncationTests(&ConvertDToICVersion); +#endif + + Register source_registers[] = { + sp, v0, v1, a0, a1, a2, a3, a4, a5, a6, a7, t0, t1}; + Register dest_registers[] = { + v0, v1, a0, a1, a2, a3, a4, a5, a6, a7, t0, t1}; + + for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) { + for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) { + RunAllTruncationTests( + RunGeneratedCodeCallWrapper, + MakeConvertDToIFuncTrampoline(isolate, + source_registers[s], + dest_registers[d], + false)); + RunAllTruncationTests( + RunGeneratedCodeCallWrapper, + MakeConvertDToIFuncTrampoline(isolate, + source_registers[s], + dest_registers[d], + true)); + } + } +} diff --git a/deps/v8/test/cctest/test-code-stubs-x64.cc b/deps/v8/test/cctest/test-code-stubs-x64.cc index 3ffd292c5f..b58b073f3b 100644 --- a/deps/v8/test/cctest/test-code-stubs-x64.cc +++ b/deps/v8/test/cctest/test-code-stubs-x64.cc @@ -27,14 +27,14 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -46,9 +46,8 @@ ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, Register destination_reg) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); HandleScope handles(isolate); MacroAssembler assm(isolate, buffer, static_cast<int>(actual_size)); diff --git a/deps/v8/test/cctest/test-code-stubs-x87.cc b/deps/v8/test/cctest/test-code-stubs-x87.cc new file mode 100644 index 0000000000..0b4a8d417b --- /dev/null +++ b/deps/v8/test/cctest/test-code-stubs-x87.cc @@ -0,0 +1,148 @@ +// 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. + +#include <stdlib.h> + +#include <limits> + +#include "src/v8.h" + +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" + +using namespace v8::internal; + +#define __ assm. + +ConvertDToIFunc MakeConvertDToIFuncTrampoline(Isolate* isolate, + Register source_reg, + Register destination_reg) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); + CHECK(buffer); + HandleScope handles(isolate); + MacroAssembler assm(isolate, buffer, static_cast<int>(actual_size)); + int offset = + source_reg.is(esp) ? 0 : (HeapNumber::kValueOffset - kSmiTagSize); + DoubleToIStub stub(isolate, source_reg, destination_reg, offset, true); + byte* start = stub.GetCode()->instruction_start(); + + __ push(ebx); + __ push(ecx); + __ push(edx); + __ push(esi); + __ push(edi); + + if (!source_reg.is(esp)) { + __ lea(source_reg, MemOperand(esp, 6 * kPointerSize - offset)); + } + + int param_offset = 7 * kPointerSize; + // Save registers make sure they don't get clobbered. + int reg_num = 0; + for (;reg_num < Register::NumAllocatableRegisters(); ++reg_num) { + Register reg = Register::FromAllocationIndex(reg_num); + if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) { + __ push(reg); + param_offset += kPointerSize; + } + } + + // Re-push the double argument + __ push(MemOperand(esp, param_offset)); + __ push(MemOperand(esp, param_offset)); + + // Call through to the actual stub + __ call(start, RelocInfo::EXTERNAL_REFERENCE); + + __ add(esp, Immediate(kDoubleSize)); + + // Make sure no registers have been unexpectedly clobbered + for (--reg_num; reg_num >= 0; --reg_num) { + Register reg = Register::FromAllocationIndex(reg_num); + if (!reg.is(esp) && !reg.is(ebp) && !reg.is(destination_reg)) { + __ cmp(reg, MemOperand(esp, 0)); + __ Assert(equal, kRegisterWasClobbered); + __ add(esp, Immediate(kPointerSize)); + } + } + + __ mov(eax, destination_reg); + + __ pop(edi); + __ pop(esi); + __ pop(edx); + __ pop(ecx); + __ pop(ebx); + + __ ret(kDoubleSize); + + CodeDesc desc; + assm.GetCode(&desc); + return reinterpret_cast<ConvertDToIFunc>( + reinterpret_cast<intptr_t>(buffer)); +} + +#undef __ + + +static Isolate* GetIsolateFrom(LocalContext* context) { + return reinterpret_cast<Isolate*>((*context)->GetIsolate()); +} + + +TEST(ConvertDToI) { + CcTest::InitializeVM(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + HandleScope scope(isolate); + +#if DEBUG + // Verify that the tests actually work with the C version. In the release + // code, the compiler optimizes it away because it's all constant, but does it + // wrong, triggering an assert on gcc. + RunAllTruncationTests(&ConvertDToICVersion); +#endif + + Register source_registers[] = {esp, eax, ebx, ecx, edx, edi, esi}; + Register dest_registers[] = {eax, ebx, ecx, edx, edi, esi}; + + for (size_t s = 0; s < sizeof(source_registers) / sizeof(Register); s++) { + for (size_t d = 0; d < sizeof(dest_registers) / sizeof(Register); d++) { + RunAllTruncationTests( + MakeConvertDToIFuncTrampoline(isolate, + source_registers[s], + dest_registers[d])); + } + } +} diff --git a/deps/v8/test/cctest/test-code-stubs.cc b/deps/v8/test/cctest/test-code-stubs.cc index 999febf777..0784aac78e 100644 --- a/deps/v8/test/cctest/test-code-stubs.cc +++ b/deps/v8/test/cctest/test-code-stubs.cc @@ -29,14 +29,14 @@ #include <limits> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "code-stubs.h" -#include "test-code-stubs.h" -#include "factory.h" -#include "macro-assembler.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-code-stubs.h" using namespace v8::internal; @@ -92,7 +92,7 @@ int32_t DefaultCallWrapper(ConvertDToIFunc func, // #define NaN and Infinity so that it's possible to cut-and-paste these tests // directly to a .js file and run them. -#define NaN (OS::nan_value()) +#define NaN (v8::base::OS::nan_value()) #define Infinity (std::numeric_limits<double>::infinity()) #define RunOneTruncationTest(p1, p2) \ RunOneTruncationTestWithTest(callWrapper, func, p1, p2) diff --git a/deps/v8/test/cctest/test-code-stubs.h b/deps/v8/test/cctest/test-code-stubs.h index 910e0d1701..0cfa0ec7c8 100644 --- a/deps/v8/test/cctest/test-code-stubs.h +++ b/deps/v8/test/cctest/test-code-stubs.h @@ -28,7 +28,7 @@ #ifndef V8_TEST_CODE_STUBS_H_ #define V8_TEST_CODE_STUBS_H_ -#if V8_TARGET_ARCH_IA32 +#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 #if __GNUC__ #define STDCALL __attribute__((stdcall)) #else diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index 9974ff5702..2d913715e1 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -28,11 +28,12 @@ #include <stdlib.h> #include <wchar.h> -#include "v8.h" +#include "src/v8.h" -#include "compiler.h" -#include "disasm.h" -#include "cctest.h" +#include "src/compiler.h" +#include "src/disasm.h" +#include "src/parser.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -49,7 +50,7 @@ static void SetGlobalProperty(const char* name, Object* value) { Handle<String> internalized_name = isolate->factory()->InternalizeUtf8String(name); Handle<JSObject> global(isolate->context()->global_object()); - Runtime::SetObjectProperty(isolate, global, internalized_name, object, NONE, + Runtime::SetObjectProperty(isolate, global, internalized_name, object, SLOPPY).Check(); } @@ -58,15 +59,10 @@ static Handle<JSFunction> Compile(const char* source) { Isolate* isolate = CcTest::i_isolate(); Handle<String> source_code = isolate->factory()->NewStringFromUtf8( CStrVector(source)).ToHandleChecked(); - Handle<SharedFunctionInfo> shared_function = - Compiler::CompileScript(source_code, - Handle<String>(), - 0, - 0, - false, - Handle<Context>(isolate->native_context()), - NULL, NULL, NO_CACHED_DATA, - NOT_NATIVES_CODE); + Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( + source_code, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, NULL, + v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE); return isolate->factory()->NewFunctionFromSharedFunctionInfo( shared_function, isolate->native_context()); } @@ -75,7 +71,7 @@ static Handle<JSFunction> Compile(const char* source) { static double Inc(Isolate* isolate, int x) { const char* source = "result = %d + 1;"; EmbeddedVector<char, 512> buffer; - OS::SNPrintF(buffer, source, x); + SNPrintF(buffer, source, x); Handle<JSFunction> fun = Compile(buffer.start()); if (fun.is_null()) return -1; @@ -278,7 +274,7 @@ TEST(GetScriptLineNumber) { for (int i = 0; i < max_rows; ++i) { if (i > 0) buffer[i - 1] = '\n'; - OS::MemCopy(&buffer[i], function_f, sizeof(function_f) - 1); + MemCopy(&buffer[i], function_f, sizeof(function_f) - 1); v8::Handle<v8::String> script_body = v8::String::NewFromUtf8(CcTest::isolate(), buffer.start()); v8::Script::Compile(script_body, &origin)->Run(); @@ -313,8 +309,9 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { Handle<FixedArray> feedback_vector(f->shared()->feedback_vector()); // Verify that we gathered feedback. - CHECK_EQ(1, feedback_vector->length()); - CHECK(feedback_vector->get(0)->IsJSFunction()); + int expected_count = FLAG_vector_ics ? 2 : 1; + CHECK_EQ(expected_count, feedback_vector->length()); + CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction()); CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);"); @@ -322,7 +319,8 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { // of the full code. CHECK(f->IsOptimized()); CHECK(f->shared()->has_deoptimization_support()); - CHECK(f->shared()->feedback_vector()->get(0)->IsJSFunction()); + CHECK(f->shared()->feedback_vector()-> + get(expected_count - 1)->IsJSFunction()); } @@ -348,16 +346,15 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) { *v8::Handle<v8::Function>::Cast( CcTest::global()->Get(v8_str("morphing_call")))); - // morphing_call should have one feedback vector slot for the call to - // call_target(). - CHECK_EQ(1, f->shared()->feedback_vector()->length()); + int expected_count = FLAG_vector_ics ? 2 : 1; + CHECK_EQ(expected_count, f->shared()->feedback_vector()->length()); // And yet it's not compiled. CHECK(!f->shared()->is_compiled()); CompileRun("morphing_call();"); // The vector should have the same size despite the new scoping. - CHECK_EQ(1, f->shared()->feedback_vector()->length()); + CHECK_EQ(expected_count, f->shared()->feedback_vector()->length()); CHECK(f->shared()->is_compiled()); } @@ -422,7 +419,7 @@ static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) { v8::internal::EmbeddedVector<char, 128> decode_buffer; v8::internal::EmbeddedVector<char, 128> smi_hex_buffer; Smi* smi = Smi::FromInt(12345678); - OS::SNPrintF(smi_hex_buffer, "0x%lx", reinterpret_cast<intptr_t>(smi)); + SNPrintF(smi_hex_buffer, "0x%" V8PRIxPTR, reinterpret_cast<intptr_t>(smi)); while (pc < end) { int num_const = d.ConstantPoolSizeAt(pc); if (num_const >= 0) { diff --git a/deps/v8/test/cctest/test-condition-variable.cc b/deps/v8/test/cctest/test-condition-variable.cc deleted file mode 100644 index a7bd6500dc..0000000000 --- a/deps/v8/test/cctest/test-condition-variable.cc +++ /dev/null @@ -1,304 +0,0 @@ -// 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. - -#include "v8.h" - -#include "cctest.h" -#include "platform/condition-variable.h" -#include "platform/time.h" - -using namespace ::v8::internal; - - -TEST(WaitForAfterNofityOnSameThread) { - for (int n = 0; n < 10; ++n) { - Mutex mutex; - ConditionVariable cv; - - LockGuard<Mutex> lock_guard(&mutex); - - cv.NotifyOne(); - CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n))); - - cv.NotifyAll(); - CHECK_EQ(false, cv.WaitFor(&mutex, TimeDelta::FromMicroseconds(n))); - } -} - - -class ThreadWithMutexAndConditionVariable V8_FINAL : public Thread { - public: - ThreadWithMutexAndConditionVariable() - : Thread("ThreadWithMutexAndConditionVariable"), - running_(false), finished_(false) {} - virtual ~ThreadWithMutexAndConditionVariable() {} - - virtual void Run() V8_OVERRIDE { - LockGuard<Mutex> lock_guard(&mutex_); - running_ = true; - cv_.NotifyOne(); - while (running_) { - cv_.Wait(&mutex_); - } - finished_ = true; - cv_.NotifyAll(); - } - - bool running_; - bool finished_; - ConditionVariable cv_; - Mutex mutex_; -}; - - -TEST(MultipleThreadsWithSeparateConditionVariables) { - static const int kThreadCount = 128; - ThreadWithMutexAndConditionVariable threads[kThreadCount]; - - for (int n = 0; n < kThreadCount; ++n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); - CHECK(!threads[n].running_); - CHECK(!threads[n].finished_); - threads[n].Start(); - // Wait for nth thread to start. - while (!threads[n].running_) { - threads[n].cv_.Wait(&threads[n].mutex_); - } - } - - for (int n = kThreadCount - 1; n >= 0; --n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); - CHECK(threads[n].running_); - CHECK(!threads[n].finished_); - } - - for (int n = 0; n < kThreadCount; ++n) { - LockGuard<Mutex> lock_guard(&threads[n].mutex_); - CHECK(threads[n].running_); - CHECK(!threads[n].finished_); - // Tell the nth thread to quit. - threads[n].running_ = false; - threads[n].cv_.NotifyOne(); - } - - for (int n = kThreadCount - 1; n >= 0; --n) { - // Wait for nth thread to quit. - LockGuard<Mutex> lock_guard(&threads[n].mutex_); - while (!threads[n].finished_) { - threads[n].cv_.Wait(&threads[n].mutex_); - } - CHECK(!threads[n].running_); - CHECK(threads[n].finished_); - } - - for (int n = 0; n < kThreadCount; ++n) { - threads[n].Join(); - LockGuard<Mutex> lock_guard(&threads[n].mutex_); - CHECK(!threads[n].running_); - CHECK(threads[n].finished_); - } -} - - -class ThreadWithSharedMutexAndConditionVariable V8_FINAL : public Thread { - public: - ThreadWithSharedMutexAndConditionVariable() - : Thread("ThreadWithSharedMutexAndConditionVariable"), - running_(false), finished_(false), cv_(NULL), mutex_(NULL) {} - virtual ~ThreadWithSharedMutexAndConditionVariable() {} - - virtual void Run() V8_OVERRIDE { - LockGuard<Mutex> lock_guard(mutex_); - running_ = true; - cv_->NotifyAll(); - while (running_) { - cv_->Wait(mutex_); - } - finished_ = true; - cv_->NotifyAll(); - } - - bool running_; - bool finished_; - ConditionVariable* cv_; - Mutex* mutex_; -}; - - -TEST(MultipleThreadsWithSharedSeparateConditionVariables) { - static const int kThreadCount = 128; - ThreadWithSharedMutexAndConditionVariable threads[kThreadCount]; - ConditionVariable cv; - Mutex mutex; - - for (int n = 0; n < kThreadCount; ++n) { - threads[n].mutex_ = &mutex; - threads[n].cv_ = &cv; - } - - // Start all threads. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = 0; n < kThreadCount; ++n) { - CHECK(!threads[n].running_); - CHECK(!threads[n].finished_); - threads[n].Start(); - } - } - - // Wait for all threads to start. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = kThreadCount - 1; n >= 0; --n) { - while (!threads[n].running_) { - cv.Wait(&mutex); - } - } - } - - // Make sure that all threads are running. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = 0; n < kThreadCount; ++n) { - CHECK(threads[n].running_); - CHECK(!threads[n].finished_); - } - } - - // Tell all threads to quit. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = kThreadCount - 1; n >= 0; --n) { - CHECK(threads[n].running_); - CHECK(!threads[n].finished_); - // Tell the nth thread to quit. - threads[n].running_ = false; - } - cv.NotifyAll(); - } - - // Wait for all threads to quit. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = 0; n < kThreadCount; ++n) { - while (!threads[n].finished_) { - cv.Wait(&mutex); - } - } - } - - // Make sure all threads are finished. - { - LockGuard<Mutex> lock_guard(&mutex); - for (int n = kThreadCount - 1; n >= 0; --n) { - CHECK(!threads[n].running_); - CHECK(threads[n].finished_); - } - } - - // Join all threads. - for (int n = 0; n < kThreadCount; ++n) { - threads[n].Join(); - } -} - - -class LoopIncrementThread V8_FINAL : public Thread { - public: - LoopIncrementThread(int rem, - int* counter, - int limit, - int thread_count, - ConditionVariable* cv, - Mutex* mutex) - : Thread("LoopIncrementThread"), rem_(rem), counter_(counter), - limit_(limit), thread_count_(thread_count), cv_(cv), mutex_(mutex) { - CHECK_LT(rem, thread_count); - CHECK_EQ(0, limit % thread_count); - } - - virtual void Run() V8_OVERRIDE { - int last_count = -1; - while (true) { - LockGuard<Mutex> lock_guard(mutex_); - int count = *counter_; - while (count % thread_count_ != rem_ && count < limit_) { - cv_->Wait(mutex_); - count = *counter_; - } - if (count >= limit_) break; - CHECK_EQ(*counter_, count); - if (last_count != -1) { - CHECK_EQ(last_count + (thread_count_ - 1), count); - } - count++; - *counter_ = count; - last_count = count; - cv_->NotifyAll(); - } - } - - private: - const int rem_; - int* counter_; - const int limit_; - const int thread_count_; - ConditionVariable* cv_; - Mutex* mutex_; -}; - - -TEST(LoopIncrement) { - static const int kMaxThreadCount = 16; - Mutex mutex; - ConditionVariable cv; - for (int thread_count = 1; thread_count < kMaxThreadCount; ++thread_count) { - int limit = thread_count * 100; - int counter = 0; - - // Setup the threads. - Thread** threads = new Thread*[thread_count]; - for (int n = 0; n < thread_count; ++n) { - threads[n] = new LoopIncrementThread( - n, &counter, limit, thread_count, &cv, &mutex); - } - - // Start all threads. - for (int n = thread_count - 1; n >= 0; --n) { - threads[n]->Start(); - } - - // Join and cleanup all threads. - for (int n = 0; n < thread_count; ++n) { - threads[n]->Join(); - delete threads[n]; - } - delete[] threads; - - CHECK_EQ(limit, counter); - } -} diff --git a/deps/v8/test/cctest/test-constantpool.cc b/deps/v8/test/cctest/test-constantpool.cc index e16e45a57d..453657609e 100644 --- a/deps/v8/test/cctest/test-constantpool.cc +++ b/deps/v8/test/cctest/test-constantpool.cc @@ -2,14 +2,22 @@ // Test constant pool array code. -#include "v8.h" +#include "src/v8.h" -#include "factory.h" -#include "objects.h" -#include "cctest.h" +#include "src/factory.h" +#include "src/objects.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() {};"); @@ -20,28 +28,29 @@ Code* DummyCode(LocalContext* context) { } -TEST(ConstantPool) { +TEST(ConstantPoolSmall) { LocalContext context; Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); Factory* factory = isolate->factory(); v8::HandleScope scope(context->GetIsolate()); // Check construction. - Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(3, 1, 2, 1); - CHECK_EQ(array->count_of_int64_entries(), 3); - CHECK_EQ(array->count_of_code_ptr_entries(), 1); - CHECK_EQ(array->count_of_heap_ptr_entries(), 2); - CHECK_EQ(array->count_of_int32_entries(), 1); - CHECK_EQ(array->length(), 7); - CHECK_EQ(array->first_int64_index(), 0); - CHECK_EQ(array->first_code_ptr_index(), 3); - CHECK_EQ(array->first_heap_ptr_index(), 4); - CHECK_EQ(array->first_int32_index(), 6); + ConstantPoolArray::NumberOfEntries small(3, 1, 2, 1); + Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); + + 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(!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); + Handle<Object> object = factory->NewHeapNumber(4.0, IMMUTABLE, TENURED); Code* code = DummyCode(&context); array->set(0, big_number); array->set(1, 0.5); @@ -50,19 +59,253 @@ TEST(ConstantPool) { array->set(4, code); array->set(5, *object); array->set(6, 50); - CHECK_EQ(array->get_int64_entry(0), big_number); - CHECK_EQ(array->get_int64_entry_as_double(1), 0.5); - CHECK_EQ(array->get_int64_entry_as_double(2), 3e-24); - CHECK_EQ(array->get_code_ptr_entry(3), code->entry()); - CHECK_EQ(array->get_heap_ptr_entry(4), code); - CHECK_EQ(array->get_heap_ptr_entry(5), *object); - CHECK_EQ(array->get_int32_entry(6), 50); - - // Check pointers are updated on GC. - Object* old_ptr = array->get_heap_ptr_entry(5); - CHECK_EQ(*object, old_ptr); + 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)); +} + + +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)); + } + + // 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 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); + } + } + + 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)); + } else { + CHECK(i <= array->last_index(ConstantPoolArray::INT32, kExtended)); + CHECK_EQ(extended_section_int32, array->get_int32_entry(i)); + } + } +} + + +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()); + } + CHECK_EQ(count, i); +} + + +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); + + 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); +} + + +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(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); - Object* new_ptr = array->get_heap_ptr_entry(5); - CHECK_NE(*object, old_ptr); - CHECK_EQ(*object, new_ptr); + + // 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)); +} + + +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_data_space()->anchor()->next_page(); + { + HandleScope scope(isolate); + Handle<HeapObject> temp = + factory->NewFixedDoubleArray(900 * KB / kDoubleSize, TENURED); + CHECK(heap->InOldDataSpace(temp->address())); + Handle<HeapObject> heap_ptr = + factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); + CHECK(heap->InOldDataSpace(heap_ptr->address())); + CHECK(!first_page->Contains(heap_ptr->address())); + array->set(0, *heap_ptr); + array->set(1, *heap_ptr); + } + + // 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)); + + // Force compacting garbage collection. + CHECK(FLAG_always_compact); + heap->CollectAllGarbage(Heap::kNoGCFlags); + + CHECK_NE(old_ptr, *object); + CHECK_EQ(*object, array->get_heap_ptr_entry(0)); + CHECK_EQ(*object, array->get_heap_ptr_entry(1)); } diff --git a/deps/v8/test/cctest/test-conversions.cc b/deps/v8/test/cctest/test-conversions.cc index 9e194eafff..93bed7f4de 100644 --- a/deps/v8/test/cctest/test-conversions.cc +++ b/deps/v8/test/cctest/test-conversions.cc @@ -27,10 +27,10 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -172,9 +172,12 @@ TEST(TrailingJunk) { TEST(NonStrDecimalLiteral) { UnicodeCache uc; - CHECK(std::isnan(StringToDouble(&uc, " ", NO_FLAGS, OS::nan_value()))); - CHECK(std::isnan(StringToDouble(&uc, "", NO_FLAGS, OS::nan_value()))); - CHECK(std::isnan(StringToDouble(&uc, " ", NO_FLAGS, OS::nan_value()))); + CHECK(std::isnan( + StringToDouble(&uc, " ", NO_FLAGS, v8::base::OS::nan_value()))); + CHECK( + std::isnan(StringToDouble(&uc, "", NO_FLAGS, v8::base::OS::nan_value()))); + CHECK(std::isnan( + StringToDouble(&uc, " ", NO_FLAGS, v8::base::OS::nan_value()))); CHECK_EQ(0.0, StringToDouble(&uc, "", NO_FLAGS)); CHECK_EQ(0.0, StringToDouble(&uc, " ", NO_FLAGS)); } diff --git a/deps/v8/test/cctest/test-cpu-ia32.cc b/deps/v8/test/cctest/test-cpu-ia32.cc deleted file mode 100644 index 245450bf92..0000000000 --- a/deps/v8/test/cctest/test-cpu-ia32.cc +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -#include "v8.h" - -#include "cctest.h" -#include "cpu.h" - -using namespace v8::internal; - - -TEST(RequiredFeaturesX64) { - // Test for the features required by every x86 CPU in compat/legacy mode. - CPU cpu; - CHECK(cpu.has_sahf()); -} diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 6cff7424b7..6051c3fd7f 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -27,14 +27,15 @@ // // Tests of profiles generator and utilities. -#include "v8.h" -#include "cpu-profiler-inl.h" -#include "cctest.h" -#include "platform.h" -#include "profiler-extension.h" -#include "smart-pointers.h" -#include "utils.h" -#include "../include/v8-profiler.h" +#include "src/v8.h" + +#include "include/v8-profiler.h" +#include "src/base/platform/platform.h" +#include "src/cpu-profiler-inl.h" +#include "src/smart-pointers.h" +#include "src/utils.h" +#include "test/cctest/cctest.h" +#include "test/cctest/profiler-extension.h" using i::CodeEntry; using i::CpuProfile; using i::CpuProfiler; @@ -45,7 +46,6 @@ using i::ProfileNode; using i::ProfilerEventsProcessor; using i::ScopedVector; using i::SmartPointer; -using i::TimeDelta; using i::Vector; @@ -54,7 +54,7 @@ TEST(StartStop) { CpuProfilesCollection profiles(isolate->heap()); ProfileGenerator generator(&profiles); SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( - &generator, NULL, TimeDelta::FromMicroseconds(100))); + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); processor->StopSynchronously(); } @@ -104,9 +104,9 @@ i::Code* CreateCode(LocalContext* env) { i::EmbeddedVector<char, 256> script; i::EmbeddedVector<char, 32> name; - i::OS::SNPrintF(name, "function_%d", ++counter); + i::SNPrintF(name, "function_%d", ++counter); const char* name_start = name.start(); - i::OS::SNPrintF(script, + i::SNPrintF(script, "function %s() {\n" "var counter = 0;\n" "for (var i = 0; i < %d; ++i) counter += i;\n" @@ -142,7 +142,7 @@ TEST(CodeEvents) { profiles->StartProfiling("", false); ProfileGenerator generator(profiles); SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( - &generator, NULL, TimeDelta::FromMicroseconds(100))); + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); CpuProfiler profiler(isolate, profiles, &generator, processor.get()); @@ -203,7 +203,7 @@ TEST(TickEvents) { profiles->StartProfiling("", false); ProfileGenerator generator(profiles); SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( - &generator, NULL, TimeDelta::FromMicroseconds(100))); + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); CpuProfiler profiler(isolate, profiles, &generator, processor.get()); @@ -272,7 +272,7 @@ TEST(Issue1398) { profiles->StartProfiling("", false); ProfileGenerator generator(profiles); SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( - &generator, NULL, TimeDelta::FromMicroseconds(100))); + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); CpuProfiler profiler(isolate, profiles, &generator, processor.get()); @@ -282,7 +282,7 @@ TEST(Issue1398) { sample->pc = code->address(); sample->tos = 0; sample->frames_count = i::TickSample::kMaxFramesCount; - for (int i = 0; i < sample->frames_count; ++i) { + for (unsigned i = 0; i < sample->frames_count; ++i) { sample->stack[i] = code->address(); } processor->FinishTickSample(); @@ -469,8 +469,8 @@ static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate, const v8::CpuProfileNode* result = FindChild(isolate, node, name); if (!result) { char buffer[100]; - i::OS::SNPrintF(Vector<char>(buffer, ARRAY_SIZE(buffer)), - "Failed to GetChild: %s", name); + i::SNPrintF(Vector<char>(buffer, ARRAY_SIZE(buffer)), + "Failed to GetChild: %s", name); FATAL(buffer); } return result; @@ -587,6 +587,72 @@ TEST(CollectCpuProfile) { } +static const char* hot_deopt_no_frame_entry_test_source = +"function foo(a, b) {\n" +" try {\n" +" return a + b;\n" +" } catch (e) { }\n" +"}\n" +"function start(timeout) {\n" +" var start = Date.now();\n" +" do {\n" +" for (var i = 1; i < 1000; ++i) foo(1, i);\n" +" var duration = Date.now() - start;\n" +" } while (duration < timeout);\n" +" return duration;\n" +"}\n"; + +// Check that the profile tree for the script above will look like the +// following: +// +// [Top down]: +// 1062 0 (root) [-1] +// 1054 0 start [-1] +// 1054 1 foo [-1] +// 2 2 (program) [-1] +// 6 6 (garbage collector) [-1] +// +// The test checks no FP ranges are present in a deoptimized funcion. +// If 'foo' has no ranges the samples falling into the prologue will miss the +// 'start' function on the stack, so 'foo' will be attached to the (root). +TEST(HotDeoptNoFrameEntry) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + + v8::Script::Compile(v8::String::NewFromUtf8( + env->GetIsolate(), + hot_deopt_no_frame_entry_test_source))->Run(); + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( + env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); + + int32_t profiling_interval_ms = 200; + v8::Handle<v8::Value> args[] = { + v8::Integer::New(env->GetIsolate(), profiling_interval_ms) + }; + v8::CpuProfile* profile = + RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200); + function->Call(env->Global(), ARRAY_SIZE(args), args); + + const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + + ScopedVector<v8::Handle<v8::String> > names(3); + names[0] = v8::String::NewFromUtf8( + env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName); + names[1] = v8::String::NewFromUtf8(env->GetIsolate(), + ProfileGenerator::kProgramEntryName); + names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start"); + CheckChildrenNames(root, names); + + const v8::CpuProfileNode* startNode = + GetChild(env->GetIsolate(), root, "start"); + CHECK_EQ(1, startNode->GetChildrenCount()); + + GetChild(env->GetIsolate(), startNode, "foo"); + + profile->Delete(); +} + + TEST(CollectCpuProfileSamples) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -724,11 +790,11 @@ class TestApiCallbacks { private: void Wait() { if (is_warming_up_) return; - double start = i::OS::TimeCurrentMillis(); + double start = v8::base::OS::TimeCurrentMillis(); double duration = 0; while (duration < min_duration_ms_) { - i::OS::Sleep(1); - duration = i::OS::TimeCurrentMillis() - start; + v8::base::OS::Sleep(1); + duration = v8::base::OS::TimeCurrentMillis() - start; } } @@ -957,23 +1023,20 @@ TEST(NativeMethodMonomorphicIC) { } -static const char* bound_function_test_source = "function foo(iterations) {\n" -" var r = 0;\n" -" for (var i = 0; i < iterations; i++) { r += i; }\n" -" return r;\n" -"}\n" -"function start(duration) {\n" -" var callback = foo.bind(this);\n" -" var start = Date.now();\n" -" while (Date.now() - start < duration) {\n" -" callback(10 * 1000);\n" -" }\n" -"}"; +static const char* bound_function_test_source = + "function foo() {\n" + " startProfiling('my_profile');\n" + "}\n" + "function start() {\n" + " var callback = foo.bind(this);\n" + " callback();\n" + "}"; TEST(BoundFunctionCall) { - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), bound_function_test_source)) @@ -981,12 +1044,7 @@ TEST(BoundFunctionCall) { v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); - int32_t duration_ms = 100; - v8::Handle<v8::Value> args[] = { - v8::Integer::New(env->GetIsolate(), duration_ms) - }; - v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 100); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); ScopedVector<v8::Handle<v8::String> > names(3); @@ -1158,9 +1216,12 @@ TEST(FunctionApplySample) { const v8::CpuProfileNode* testNode = FindChild(env->GetIsolate(), startNode, "test"); if (testNode) { - ScopedVector<v8::Handle<v8::String> > names(2); + ScopedVector<v8::Handle<v8::String> > names(3); names[0] = v8::String::NewFromUtf8(env->GetIsolate(), "bar"); names[1] = v8::String::NewFromUtf8(env->GetIsolate(), "apply"); + // apply calls "get length" before invoking the function itself + // and we may get hit into it. + names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "get length"); CheckChildrenNames(testNode, names); } @@ -1178,28 +1239,84 @@ TEST(FunctionApplySample) { } -static const char* js_native_js_test_source = -"var is_profiling = false;\n" -"function foo(iterations) {\n" -" if (!is_profiling) {\n" -" is_profiling = true;\n" +static const char* cpu_profiler_deep_stack_test_source = +"function foo(n) {\n" +" if (n)\n" +" foo(n - 1);\n" +" else\n" " startProfiling('my_profile');\n" -" }\n" -" var r = 0;\n" -" for (var i = 0; i < iterations; i++) { r += i; }\n" -" return r;\n" "}\n" -"function bar(iterations) {\n" -" try { foo(iterations); } catch(e) {}\n" -"}\n" -"function start(duration) {\n" -" var start = Date.now();\n" -" while (Date.now() - start < duration) {\n" -" try {\n" -" CallJsFunction(bar, 10 * 1000);\n" -" } catch(e) {}\n" -" }\n" -"}"; +"function start() {\n" +" foo(250);\n" +"}\n"; + + +// Check a deep stack +// +// [Top down]: +// 0 (root) 0 #1 +// 2 (program) 0 #2 +// 0 start 21 #3 no reason +// 0 foo 21 #4 no reason +// 0 foo 21 #5 no reason +// .... +// 0 foo 21 #253 no reason +// 1 startProfiling 0 #254 +TEST(CpuProfileDeepStack) { + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); + + v8::Script::Compile(v8::String::NewFromUtf8( + env->GetIsolate(), cpu_profiler_deep_stack_test_source))->Run(); + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( + env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); + + v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); + v8::Local<v8::String> profile_name = + v8::String::NewFromUtf8(env->GetIsolate(), "my_profile"); + function->Call(env->Global(), 0, NULL); + v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name); + CHECK_NE(NULL, profile); + // Dump collected profile to have a better diagnostic in case of failure. + reinterpret_cast<i::CpuProfile*>(profile)->Print(); + + const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + { + ScopedVector<v8::Handle<v8::String> > names(3); + names[0] = v8::String::NewFromUtf8( + env->GetIsolate(), ProfileGenerator::kGarbageCollectorEntryName); + names[1] = v8::String::NewFromUtf8(env->GetIsolate(), + ProfileGenerator::kProgramEntryName); + names[2] = v8::String::NewFromUtf8(env->GetIsolate(), "start"); + CheckChildrenNames(root, names); + } + + const v8::CpuProfileNode* node = + GetChild(env->GetIsolate(), root, "start"); + for (int i = 0; i < 250; ++i) { + node = GetChild(env->GetIsolate(), node, "foo"); + } + // TODO(alph): + // In theory there must be one more 'foo' and a 'startProfiling' nodes, + // but due to unstable top frame extraction these might be missing. + + profile->Delete(); +} + + +static const char* js_native_js_test_source = + "function foo() {\n" + " startProfiling('my_profile');\n" + "}\n" + "function bar() {\n" + " try { foo(); } catch(e) {}\n" + "}\n" + "function start() {\n" + " try {\n" + " CallJsFunction(bar);\n" + " } catch(e) {}\n" + "}"; static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) { v8::Handle<v8::Function> function = info[0].As<v8::Function>(); @@ -1232,12 +1349,7 @@ TEST(JsNativeJsSample) { v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); - int32_t duration_ms = 20; - v8::Handle<v8::Value> args[] = { - v8::Integer::New(env->GetIsolate(), duration_ms) - }; - v8::CpuProfile* profile = - RunProfiler(env, function, args, ARRAY_SIZE(args), 10); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); { @@ -1268,28 +1380,18 @@ TEST(JsNativeJsSample) { static const char* js_native_js_runtime_js_test_source = -"var is_profiling = false;\n" -"function foo(iterations) {\n" -" if (!is_profiling) {\n" -" is_profiling = true;\n" -" startProfiling('my_profile');\n" -" }\n" -" var r = 0;\n" -" for (var i = 0; i < iterations; i++) { r += i; }\n" -" return r;\n" -"}\n" -"var bound = foo.bind(this);\n" -"function bar(iterations) {\n" -" try { bound(iterations); } catch(e) {}\n" -"}\n" -"function start(duration) {\n" -" var start = Date.now();\n" -" while (Date.now() - start < duration) {\n" -" try {\n" -" CallJsFunction(bar, 10 * 1000);\n" -" } catch(e) {}\n" -" }\n" -"}"; + "function foo() {\n" + " startProfiling('my_profile');\n" + "}\n" + "var bound = foo.bind(this);\n" + "function bar() {\n" + " try { bound(); } catch(e) {}\n" + "}\n" + "function start() {\n" + " try {\n" + " CallJsFunction(bar);\n" + " } catch(e) {}\n" + "}"; // [Top down]: @@ -1317,12 +1419,7 @@ TEST(JsNativeJsRuntimeJsSample) { v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); - int32_t duration_ms = 20; - v8::Handle<v8::Value> args[] = { - v8::Integer::New(env->GetIsolate(), duration_ms) - }; - v8::CpuProfile* profile = - RunProfiler(env, function, args, ARRAY_SIZE(args), 10); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); ScopedVector<v8::Handle<v8::String> > names(3); @@ -1343,7 +1440,11 @@ TEST(JsNativeJsRuntimeJsSample) { const v8::CpuProfileNode* barNode = GetChild(env->GetIsolate(), nativeFunctionNode, "bar"); - CHECK_EQ(1, barNode->GetChildrenCount()); + // The child is in fact a bound foo. + // A bound function has a wrapper that may make calls to + // other functions e.g. "get length". + CHECK_LE(1, barNode->GetChildrenCount()); + CHECK_GE(2, barNode->GetChildrenCount()); GetChild(env->GetIsolate(), barNode, "foo"); profile->Delete(); @@ -1351,32 +1452,25 @@ TEST(JsNativeJsRuntimeJsSample) { static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) { + v8::base::OS::Print("In CallJsFunction2\n"); CallJsFunction(info); } static const char* js_native1_js_native2_js_test_source = -"var is_profiling = false;\n" -"function foo(iterations) {\n" -" if (!is_profiling) {\n" -" is_profiling = true;\n" -" startProfiling('my_profile');\n" -" }\n" -" var r = 0;\n" -" for (var i = 0; i < iterations; i++) { r += i; }\n" -" return r;\n" -"}\n" -"function bar(iterations) {\n" -" CallJsFunction2(foo, iterations);\n" -"}\n" -"function start(duration) {\n" -" var start = Date.now();\n" -" while (Date.now() - start < duration) {\n" -" try {\n" -" CallJsFunction1(bar, 10 * 1000);\n" -" } catch(e) {}\n" -" }\n" -"}"; + "function foo() {\n" + " try {\n" + " startProfiling('my_profile');\n" + " } catch(e) {}\n" + "}\n" + "function bar() {\n" + " CallJsFunction2(foo);\n" + "}\n" + "function start() {\n" + " try {\n" + " CallJsFunction1(bar);\n" + " } catch(e) {}\n" + "}"; // [Top down]: @@ -1411,12 +1505,7 @@ TEST(JsNative1JsNative2JsSample) { v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start"))); - int32_t duration_ms = 20; - v8::Handle<v8::Value> args[] = { - v8::Integer::New(env->GetIsolate(), duration_ms) - }; - v8::CpuProfile* profile = - RunProfiler(env, function, args, ARRAY_SIZE(args), 10); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); ScopedVector<v8::Handle<v8::String> > names(3); @@ -1540,25 +1629,23 @@ TEST(FunctionDetails) { const_cast<v8::CpuProfileNode*>(current))->Print(0); // The tree should look like this: // 0 (root) 0 #1 - // 0 (anonymous function) 19 #2 no reason script_b:1 + // 0 "" 19 #2 no reason script_b:1 // 0 baz 19 #3 TryCatchStatement script_b:3 // 0 foo 18 #4 TryCatchStatement script_a:2 // 1 bar 18 #5 no reason script_a:3 const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root, - ProfileGenerator::kAnonymousFunctionName); - CheckFunctionDetails(env->GetIsolate(), script, - ProfileGenerator::kAnonymousFunctionName, "script_b", - script_b->GetId(), 1, 1); + const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root, ""); + CheckFunctionDetails(env->GetIsolate(), script, "", "script_b", + script_b->GetUnboundScript()->GetId(), 1, 1); const v8::CpuProfileNode* baz = GetChild(env->GetIsolate(), script, "baz"); CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b", - script_b->GetId(), 3, 16); + script_b->GetUnboundScript()->GetId(), 3, 16); const v8::CpuProfileNode* foo = GetChild(env->GetIsolate(), baz, "foo"); CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a", - script_a->GetId(), 2, 1); + script_a->GetUnboundScript()->GetId(), 2, 1); const v8::CpuProfileNode* bar = GetChild(env->GetIsolate(), foo, "bar"); CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a", - script_a->GetId(), 3, 14); + script_a->GetUnboundScript()->GetId(), 3, 14); } diff --git a/deps/v8/test/cctest/test-cpu-x64.cc b/deps/v8/test/cctest/test-cpu-x64.cc deleted file mode 100644 index a2c45cf862..0000000000 --- a/deps/v8/test/cctest/test-cpu-x64.cc +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -#include "v8.h" - -#include "cctest.h" -#include "cpu.h" - -using namespace v8::internal; - - -TEST(RequiredFeaturesX64) { - // Test for the features required by every x64 CPU. - CPU cpu; - CHECK(cpu.has_fpu()); - CHECK(cpu.has_cmov()); - CHECK(cpu.has_mmx()); - CHECK(cpu.has_sse()); - CHECK(cpu.has_sse2()); -} diff --git a/deps/v8/test/cctest/test-cpu.cc b/deps/v8/test/cctest/test-cpu.cc deleted file mode 100644 index 06966c68c8..0000000000 --- a/deps/v8/test/cctest/test-cpu.cc +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -#include "v8.h" - -#include "cctest.h" -#include "cpu.h" - -using namespace v8::internal; - - -TEST(FeatureImplications) { - // Test for features implied by other features. - CPU cpu; - - // ia32 and x64 features - CHECK(!cpu.has_sse() || cpu.has_mmx()); - CHECK(!cpu.has_sse2() || cpu.has_sse()); - CHECK(!cpu.has_sse3() || cpu.has_sse2()); - CHECK(!cpu.has_ssse3() || cpu.has_sse3()); - CHECK(!cpu.has_sse41() || cpu.has_sse3()); - CHECK(!cpu.has_sse42() || cpu.has_sse41()); - - // arm features - CHECK(!cpu.has_vfp3_d32() || cpu.has_vfp3()); -} - - -TEST(NumberOfProcessorsOnline) { - CHECK_GT(CPU::NumberOfProcessorsOnline(), 0); -} diff --git a/deps/v8/test/cctest/test-dataflow.cc b/deps/v8/test/cctest/test-dataflow.cc index 532c9207b6..fc1a7fa13f 100644 --- a/deps/v8/test/cctest/test-dataflow.cc +++ b/deps/v8/test/cctest/test-dataflow.cc @@ -27,10 +27,10 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "data-flow.h" -#include "cctest.h" +#include "src/data-flow.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-date.cc b/deps/v8/test/cctest/test-date.cc index 5190729fad..f2187955ad 100644 --- a/deps/v8/test/cctest/test-date.cc +++ b/deps/v8/test/cctest/test-date.cc @@ -25,11 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "global-handles.h" -#include "snapshot.h" -#include "cctest.h" +#include "src/global-handles.h" +#include "src/snapshot.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 85e4512ea5..5c0b0f392d 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -27,28 +27,27 @@ #include <stdlib.h> -#include "v8.h" - -#include "api.h" -#include "cctest.h" -#include "compilation-cache.h" -#include "debug.h" -#include "deoptimizer.h" -#include "frames.h" -#include "platform.h" -#include "platform/condition-variable.h" -#include "platform/socket.h" -#include "stub-cache.h" -#include "utils.h" - - -using ::v8::internal::Mutex; -using ::v8::internal::LockGuard; -using ::v8::internal::ConditionVariable; -using ::v8::internal::Semaphore; +#include "src/v8.h" + +#include "src/api.h" +#include "src/base/platform/condition-variable.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/debug.h" +#include "src/deoptimizer.h" +#include "src/frames.h" +#include "src/stub-cache.h" +#include "src/utils.h" +#include "test/cctest/cctest.h" + + +using ::v8::base::Mutex; +using ::v8::base::LockGuard; +using ::v8::base::ConditionVariable; +using ::v8::base::OS; +using ::v8::base::Semaphore; using ::v8::internal::EmbeddedVector; using ::v8::internal::Object; -using ::v8::internal::OS; using ::v8::internal::Handle; using ::v8::internal::Heap; using ::v8::internal::JSGlobalProxy; @@ -99,20 +98,19 @@ class DebugLocalContext { v8::internal::Isolate* isolate = reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate()); v8::internal::Factory* factory = isolate->factory(); - v8::internal::Debug* debug = isolate->debug(); // Expose the debug context global object in the global object for testing. - debug->Load(); - debug->debug_context()->set_security_token( + CHECK(isolate->debug()->Load()); + Handle<v8::internal::Context> debug_context = + isolate->debug()->debug_context(); + debug_context->set_security_token( v8::Utils::OpenHandle(*context_)->security_token()); Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast( v8::Utils::OpenHandle(*context_->Global()))); Handle<v8::internal::String> debug_string = factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("debug")); - v8::internal::Runtime::SetObjectProperty(isolate, global, debug_string, - Handle<Object>(debug->debug_context()->global_proxy(), isolate), - DONT_ENUM, - ::v8::internal::SLOPPY).Check(); + v8::internal::Runtime::DefineObjectProperty(global, debug_string, + handle(debug_context->global_proxy(), isolate), DONT_ENUM).Check(); } private: @@ -182,9 +180,9 @@ static int SetBreakPointFromJS(v8::Isolate* isolate, const char* function_name, int line, int position) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.setBreakPoint(%s,%d,%d)", - function_name, line, position); + SNPrintF(buffer, + "debug.Debug.setBreakPoint(%s,%d,%d)", + function_name, line, position); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Handle<v8::String> str = v8::String::NewFromUtf8(isolate, buffer.start()); return v8::Script::Compile(str)->Run()->Int32Value(); @@ -197,14 +195,14 @@ static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id, EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; if (column >= 0) { // Column specified set script break point on precise location. - OS::SNPrintF(buffer, - "debug.Debug.setScriptBreakPointById(%d,%d,%d)", - script_id, line, column); + SNPrintF(buffer, + "debug.Debug.setScriptBreakPointById(%d,%d,%d)", + script_id, line, column); } else { // Column not specified set script break point on line. - OS::SNPrintF(buffer, - "debug.Debug.setScriptBreakPointById(%d,%d)", - script_id, line); + SNPrintF(buffer, + "debug.Debug.setScriptBreakPointById(%d,%d)", + script_id, line); } buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; { @@ -226,14 +224,14 @@ static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate, EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; if (column >= 0) { // Column specified set script break point on precise location. - OS::SNPrintF(buffer, - "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)", - script_name, line, column); + SNPrintF(buffer, + "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)", + script_name, line, column); } else { // Column not specified set script break point on line. - OS::SNPrintF(buffer, - "debug.Debug.setScriptBreakPointByName(\"%s\",%d)", - script_name, line); + SNPrintF(buffer, + "debug.Debug.setScriptBreakPointByName(\"%s\",%d)", + script_name, line); } buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; { @@ -260,9 +258,9 @@ static void ClearBreakPoint(int break_point) { static void ClearBreakPointFromJS(v8::Isolate* isolate, int break_point_number) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.clearBreakPoint(%d)", - break_point_number); + SNPrintF(buffer, + "debug.Debug.clearBreakPoint(%d)", + break_point_number); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run(); } @@ -271,9 +269,9 @@ static void ClearBreakPointFromJS(v8::Isolate* isolate, static void EnableScriptBreakPointFromJS(v8::Isolate* isolate, int break_point_number) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.enableScriptBreakPoint(%d)", - break_point_number); + SNPrintF(buffer, + "debug.Debug.enableScriptBreakPoint(%d)", + break_point_number); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run(); } @@ -282,9 +280,9 @@ static void EnableScriptBreakPointFromJS(v8::Isolate* isolate, static void DisableScriptBreakPointFromJS(v8::Isolate* isolate, int break_point_number) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.disableScriptBreakPoint(%d)", - break_point_number); + SNPrintF(buffer, + "debug.Debug.disableScriptBreakPoint(%d)", + break_point_number); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run(); } @@ -294,9 +292,9 @@ static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate, int break_point_number, const char* condition) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")", - break_point_number, condition); + SNPrintF(buffer, + "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")", + break_point_number, condition); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run(); } @@ -306,9 +304,9 @@ static void ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate* isolate, int break_point_number, int ignoreCount) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)", - break_point_number, ignoreCount); + SNPrintF(buffer, + "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)", + break_point_number, ignoreCount); buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run(); } @@ -422,12 +420,6 @@ void CheckDebuggerUnloaded(bool check_functions) { } -void ForceUnloadDebugger() { - CcTest::i_isolate()->debugger()->never_unload_debugger_ = false; - CcTest::i_isolate()->debugger()->UnloadDebugger(); -} - - } } // namespace v8::internal @@ -1094,7 +1086,7 @@ TEST(BreakPointICStore) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){bar=0;}"))->Run(); v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( @@ -1116,7 +1108,7 @@ TEST(BreakPointICStore) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1126,7 +1118,7 @@ TEST(BreakPointICLoad) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "bar=1")) ->Run(); v8::Script::Compile( @@ -1151,7 +1143,7 @@ TEST(BreakPointICLoad) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1161,7 +1153,7 @@ TEST(BreakPointICCall) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run(); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), @@ -1185,7 +1177,7 @@ TEST(BreakPointICCall) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1195,7 +1187,7 @@ TEST(BreakPointICCallWithGC) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointCollectGarbage); + v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){return 1;}")) ->Run(); @@ -1221,7 +1213,7 @@ TEST(BreakPointICCallWithGC) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1231,7 +1223,7 @@ TEST(BreakPointConstructCallWithGC) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointCollectGarbage); + v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){ this.x = 1;}")) ->Run(); @@ -1257,7 +1249,7 @@ TEST(BreakPointConstructCallWithGC) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1278,7 +1270,7 @@ TEST(BreakPointReturn) { "frame_source_column"); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){}"))->Run(); v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( @@ -1304,7 +1296,7 @@ TEST(BreakPointReturn) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1327,7 +1319,7 @@ TEST(GCDuringBreakPointProcessing) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointCollectGarbage); + v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage); v8::Local<v8::Function> foo; // Test IC store break point with garbage collection. @@ -1355,7 +1347,7 @@ TEST(GCDuringBreakPointProcessing) { SetBreakPoint(foo, 0); CallWithBreakPoints(env->Global(), foo, 1, 25); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1390,7 +1382,7 @@ TEST(BreakPointSurviveGC) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Function> foo; // Test IC store break point with garbage collection. @@ -1436,7 +1428,7 @@ TEST(BreakPointSurviveGC) { CallAndGC(env->Global(), foo); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1448,7 +1440,7 @@ TEST(BreakPointThroughJavaScript) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run(); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), @@ -1490,7 +1482,7 @@ TEST(BreakPointThroughJavaScript) { foo->Run(); CHECK_EQ(8, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Make sure that the break point numbers are consecutive. @@ -1507,7 +1499,7 @@ TEST(ScriptBreakPointByNameThroughJavaScript) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), @@ -1592,7 +1584,7 @@ TEST(ScriptBreakPointByNameThroughJavaScript) { g->Call(env->Global(), 0, NULL); CHECK_EQ(0, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Make sure that the break point numbers are consecutive. @@ -1611,7 +1603,7 @@ TEST(ScriptBreakPointByIdThroughJavaScript) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> source = v8::String::NewFromUtf8( env->GetIsolate(), @@ -1644,7 +1636,7 @@ TEST(ScriptBreakPointByIdThroughJavaScript) { env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); // Get the script id knowing that internally it is a 32 integer. - int script_id = script->GetId(); + int script_id = script->GetUnboundScript()->GetId(); // Call f and g without break points. break_point_hit_count = 0; @@ -1700,7 +1692,7 @@ TEST(ScriptBreakPointByIdThroughJavaScript) { g->Call(env->Global(), 0, NULL); CHECK_EQ(0, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Make sure that the break point numbers are consecutive. @@ -1720,7 +1712,7 @@ TEST(EnableDisableScriptBreakPoint) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), @@ -1766,7 +1758,7 @@ TEST(EnableDisableScriptBreakPoint) { f->Call(env->Global(), 0, NULL); CHECK_EQ(3, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1778,7 +1770,7 @@ TEST(ConditionalScriptBreakPoint) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), @@ -1829,7 +1821,7 @@ TEST(ConditionalScriptBreakPoint) { } CHECK_EQ(5, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1841,7 +1833,7 @@ TEST(ScriptBreakPointIgnoreCount) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), @@ -1885,7 +1877,7 @@ TEST(ScriptBreakPointIgnoreCount) { } CHECK_EQ(5, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1897,7 +1889,7 @@ TEST(ScriptBreakPointReload) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Function> f; v8::Local<v8::String> script = v8::String::NewFromUtf8( @@ -1949,7 +1941,7 @@ TEST(ScriptBreakPointReload) { f->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -1961,7 +1953,7 @@ TEST(ScriptBreakPointMultiple) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Function> f; v8::Local<v8::String> script_f = @@ -2018,7 +2010,7 @@ TEST(ScriptBreakPointMultiple) { g->Call(env->Global(), 0, NULL); CHECK_EQ(2, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2030,7 +2022,7 @@ TEST(ScriptBreakPointLineOffset) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Function> f; v8::Local<v8::String> script = v8::String::NewFromUtf8( @@ -2078,7 +2070,7 @@ TEST(ScriptBreakPointLineOffset) { f->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2094,7 +2086,7 @@ TEST(ScriptBreakPointLine) { frame_function_name_source, "frame_function_name"); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Function> f; v8::Local<v8::Function> g; @@ -2194,7 +2186,7 @@ TEST(ScriptBreakPointLine) { v8::Script::Compile(script, &origin)->Run(); CHECK_EQ(0, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2205,7 +2197,7 @@ TEST(ScriptBreakPointLineTopLevel) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script = v8::String::NewFromUtf8(env->GetIsolate(), @@ -2241,7 +2233,7 @@ TEST(ScriptBreakPointLineTopLevel) { env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); CHECK_EQ(0, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2253,7 +2245,7 @@ TEST(ScriptBreakPointTopLevelCrash) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::String> script_source = v8::String::NewFromUtf8(env->GetIsolate(), @@ -2276,7 +2268,7 @@ TEST(ScriptBreakPointTopLevelCrash) { ClearBreakPointFromJS(env->GetIsolate(), sbp1); ClearBreakPointFromJS(env->GetIsolate(), sbp2); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2292,7 +2284,7 @@ TEST(RemoveBreakPointInBreak) { debug_event_remove_break_point = SetBreakPoint(foo, 0); // Register the debug event listener pasing the function - v8::Debug::SetDebugEventListener2(DebugEventRemoveBreakPoint, foo); + v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo); break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); @@ -2302,7 +2294,7 @@ TEST(RemoveBreakPointInBreak) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(0, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2312,7 +2304,7 @@ TEST(DebuggerStatement) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){debugger}")) ->Run(); @@ -2332,7 +2324,7 @@ TEST(DebuggerStatement) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(3, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2342,7 +2334,7 @@ TEST(DebuggerStatementBreakpoint) { break_point_hit_count = 0; DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Script::Compile( v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){debugger;}")) ->Run(); @@ -2360,7 +2352,7 @@ TEST(DebuggerStatementBreakpoint) { CHECK_EQ(2, break_point_hit_count); ClearBreakPoint(bp); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2378,7 +2370,7 @@ TEST(DebugEvaluate) { evaluate_check_source, "evaluate_check"); // Register the debug event listener - v8::Debug::SetDebugEventListener2(DebugEventEvaluate); + v8::Debug::SetDebugEventListener(DebugEventEvaluate); // Different expected vaules of x and a when in a break point (u = undefined, // d = Hello, world!). @@ -2479,7 +2471,7 @@ TEST(DebugEvaluate) { }; bar->Call(env->Global(), 2, argv_bar_3); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2497,7 +2489,7 @@ TEST(ConditionalBreakpointWithCodeGenerationDisallowed) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(CheckDebugEvent); + v8::Debug::SetDebugEventListener(CheckDebugEvent); v8::Local<v8::Function> foo = CompileFunction(&env, "function foo(x) {\n" @@ -2514,7 +2506,7 @@ TEST(ConditionalBreakpointWithCodeGenerationDisallowed) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(1, debugEventCount); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2544,7 +2536,7 @@ TEST(DebugEvaluateWithCodeGenerationDisallowed) { v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(CheckDebugEval); + v8::Debug::SetDebugEventListener(CheckDebugEval); v8::Local<v8::Function> foo = CompileFunction(&env, "var global = 'Global';\n" @@ -2572,7 +2564,7 @@ TEST(DebugEvaluateWithCodeGenerationDisallowed) { checkGlobalEvalFunction.Clear(); checkFrameEvalFunction.Clear(); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2630,7 +2622,7 @@ bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) { if (len > buffer_size - 1) { len = buffer_size - 1; } - OS::StrNCpy(buf, pos1, len); + StrNCpy(buf, pos1, len); buffer[buffer_size - 1] = '\0'; return true; } @@ -2677,7 +2669,7 @@ static void DebugProcessDebugMessagesHandler( // Test that the evaluation of expressions works even from ProcessDebugMessages // i.e. with empty stack. TEST(DebugEvaluateWithoutStack) { - v8::Debug::SetMessageHandler2(DebugProcessDebugMessagesHandler); + v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler); DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -2733,8 +2725,8 @@ TEST(DebugEvaluateWithoutStack) { 0); CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0); - v8::Debug::SetMessageHandler2(NULL); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetMessageHandler(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2755,7 +2747,7 @@ TEST(DebugStepLinear) { SetBreakPoint(foo, 3); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); step_action = StepIn; break_point_hit_count = 0; @@ -2764,11 +2756,11 @@ TEST(DebugStepLinear) { // With stepping all break locations are hit. CHECK_EQ(4, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Register a debug event listener which just counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); SetBreakPoint(foo, 3); break_point_hit_count = 0; @@ -2777,7 +2769,7 @@ TEST(DebugStepLinear) { // Without stepping only active break points are hit. CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2788,7 +2780,7 @@ TEST(DebugStepKeyedLoadLoop) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping of keyed load. The statement 'y=1' // is there to have more than one breakable statement in the loop, TODO(315). @@ -2826,7 +2818,7 @@ TEST(DebugStepKeyedLoadLoop) { // With stepping all break locations are hit. CHECK_EQ(35, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2837,7 +2829,7 @@ TEST(DebugStepKeyedStoreLoop) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping of keyed store. The statement 'y=1' // is there to have more than one breakable statement in the loop, TODO(315). @@ -2874,7 +2866,7 @@ TEST(DebugStepKeyedStoreLoop) { // With stepping all break locations are hit. CHECK_EQ(34, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2885,7 +2877,7 @@ TEST(DebugStepNamedLoadLoop) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping of named load. v8::Local<v8::Function> foo = CompileFunction( @@ -2918,7 +2910,7 @@ TEST(DebugStepNamedLoadLoop) { // With stepping all break locations are hit. CHECK_EQ(55, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2928,7 +2920,7 @@ static void DoDebugStepNamedStoreLoop(int expected) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping of named store. v8::Local<v8::Function> foo = CompileFunction( @@ -2953,7 +2945,7 @@ static void DoDebugStepNamedStoreLoop(int expected) { // With stepping all expected break locations are hit. CHECK_EQ(expected, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -2970,7 +2962,7 @@ TEST(DebugStepLinearMixedICs) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. v8::Local<v8::Function> foo = CompileFunction(&env, @@ -2993,11 +2985,11 @@ TEST(DebugStepLinearMixedICs) { // With stepping all break locations are hit. CHECK_EQ(11, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Register a debug event listener which just counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); SetBreakPoint(foo, 0); break_point_hit_count = 0; @@ -3006,7 +2998,7 @@ TEST(DebugStepLinearMixedICs) { // Without stepping only active break points are hit. CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3016,7 +3008,7 @@ TEST(DebugStepDeclarations) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3039,7 +3031,7 @@ TEST(DebugStepDeclarations) { CHECK_EQ(6, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3049,7 +3041,7 @@ TEST(DebugStepLocals) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3072,7 +3064,7 @@ TEST(DebugStepLocals) { CHECK_EQ(6, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3083,7 +3075,7 @@ TEST(DebugStepIf) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3116,7 +3108,7 @@ TEST(DebugStepIf) { CHECK_EQ(5, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3127,7 +3119,7 @@ TEST(DebugStepSwitch) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3173,7 +3165,7 @@ TEST(DebugStepSwitch) { CHECK_EQ(7, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3184,7 +3176,7 @@ TEST(DebugStepWhile) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3199,22 +3191,29 @@ TEST(DebugStepWhile) { v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo"); SetBreakPoint(foo, 8); // "var a = 0;" + // Looping 0 times. We still should break at the while-condition once. + 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(3, 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(22, break_point_hit_count); + CHECK_EQ(23, 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(202, break_point_hit_count); + CHECK_EQ(203, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3225,7 +3224,7 @@ TEST(DebugStepDoWhile) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3255,7 +3254,7 @@ TEST(DebugStepDoWhile) { CHECK_EQ(202, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3266,7 +3265,7 @@ TEST(DebugStepFor) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3297,7 +3296,7 @@ TEST(DebugStepFor) { CHECK_EQ(203, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3308,7 +3307,7 @@ TEST(DebugStepForContinue) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3349,7 +3348,7 @@ TEST(DebugStepForContinue) { CHECK_EQ(457, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3360,7 +3359,7 @@ TEST(DebugStepForBreak) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3402,7 +3401,7 @@ TEST(DebugStepForBreak) { CHECK_EQ(505, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3412,7 +3411,7 @@ TEST(DebugStepForIn) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3450,7 +3449,7 @@ TEST(DebugStepForIn) { CHECK_EQ(8, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3460,7 +3459,7 @@ TEST(DebugStepWith) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3482,7 +3481,7 @@ TEST(DebugStepWith) { CHECK_EQ(4, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3493,7 +3492,7 @@ TEST(DebugConditional) { v8::HandleScope scope(isolate); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3519,7 +3518,7 @@ TEST(DebugConditional) { CHECK_EQ(5, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3534,7 +3533,7 @@ TEST(StepInOutSimple) { "frame_function_name"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStepSequence); + v8::Debug::SetDebugEventListener(DebugEventStepSequence); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3570,7 +3569,7 @@ TEST(StepInOutSimple) { break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3585,7 +3584,7 @@ TEST(StepInOutTree) { "frame_function_name"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStepSequence); + v8::Debug::SetDebugEventListener(DebugEventStepSequence); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3622,7 +3621,7 @@ TEST(StepInOutTree) { break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(true); } @@ -3637,7 +3636,7 @@ TEST(StepInOutBranch) { "frame_function_name"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStepSequence); + v8::Debug::SetDebugEventListener(DebugEventStepSequence); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3657,7 +3656,7 @@ TEST(StepInOutBranch) { break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3674,7 +3673,7 @@ TEST(DebugStepNatives) { "foo"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); step_action = StepIn; break_point_hit_count = 0; @@ -3683,11 +3682,11 @@ TEST(DebugStepNatives) { // With stepping all break locations are hit. CHECK_EQ(3, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Register a debug event listener which just counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); @@ -3695,7 +3694,7 @@ TEST(DebugStepNatives) { // Without stepping only active break points are hit. CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3713,7 +3712,7 @@ TEST(DebugStepFunctionApply) { "foo"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); step_action = StepIn; break_point_hit_count = 0; @@ -3722,11 +3721,11 @@ TEST(DebugStepFunctionApply) { // With stepping all break locations are hit. CHECK_EQ(7, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Register a debug event listener which just counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); @@ -3734,7 +3733,7 @@ TEST(DebugStepFunctionApply) { // Without stepping only the debugger statement is hit. CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3759,7 +3758,7 @@ TEST(DebugStepFunctionCall) { "foo"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStep); + v8::Debug::SetDebugEventListener(DebugEventStep); step_action = StepIn; // Check stepping where the if condition in bar is false. @@ -3774,11 +3773,11 @@ TEST(DebugStepFunctionCall) { foo->Call(env->Global(), argc, argv); CHECK_EQ(8, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); // Register a debug event listener which just counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); @@ -3786,7 +3785,7 @@ TEST(DebugStepFunctionCall) { // Without stepping only the debugger statement is hit. CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3798,7 +3797,7 @@ TEST(PauseInScript) { env.ExposeDebug(); // Register a debug event listener which counts. - v8::Debug::SetDebugEventListener2(DebugEventCounter); + v8::Debug::SetDebugEventListener(DebugEventCounter); // Create a script that returns a function. const char* src = "(function (evt) {})"; @@ -3819,7 +3818,7 @@ TEST(PauseInScript) { CHECK_EQ(1, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -3845,7 +3844,7 @@ TEST(BreakOnException) { CompileFunction(&env, "function notCaught(){throws();}", "notCaught"); v8::V8::AddMessageListener(MessageCallbackCount); - v8::Debug::SetDebugEventListener2(DebugEventCounter); + v8::Debug::SetDebugEventListener(DebugEventCounter); // Initial state should be no break on exceptions. DebugEventCounterClear(); @@ -3963,7 +3962,7 @@ TEST(BreakOnException) { CHECK_EQ(1, uncaught_exception_hit_count); CHECK_EQ(1, message_callback_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); v8::V8::RemoveMessageListeners(MessageCallbackCount); } @@ -3983,7 +3982,7 @@ TEST(BreakOnCompileException) { frame_count = CompileFunction(&env, frame_count_source, "frame_count"); v8::V8::AddMessageListener(MessageCallbackCount); - v8::Debug::SetDebugEventListener2(DebugEventCounter); + v8::Debug::SetDebugEventListener(DebugEventCounter); DebugEventCounterClear(); MessageCallbackCountClear(); @@ -4039,7 +4038,7 @@ TEST(StepWithException) { "frame_function_name"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventStepSequence); + v8::Debug::SetDebugEventListener(DebugEventStepSequence); // Create functions for testing stepping. const char* src = "function a() { n(); }; " @@ -4111,7 +4110,7 @@ TEST(StepWithException) { break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -4126,7 +4125,7 @@ TEST(DebugBreak) { v8::HandleScope scope(isolate); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetDebugEventListener2(DebugEventBreak); + v8::Debug::SetDebugEventListener(DebugEventBreak); // Create a function for testing stepping. const char* src = "function f0() {}" @@ -4166,7 +4165,7 @@ TEST(DebugBreak) { CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -4178,7 +4177,7 @@ TEST(DisableBreak) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetDebugEventListener2(DebugEventCounter); + v8::Debug::SetDebugEventListener(DebugEventCounter); // Create a function for testing stepping. const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}"; @@ -4195,7 +4194,7 @@ TEST(DisableBreak) { { v8::Debug::DebugBreak(env->GetIsolate()); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate()); - v8::internal::DisableBreak disable_break(isolate, true); + v8::internal::DisableBreak disable_break(isolate->debug(), true); f->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); } @@ -4204,7 +4203,7 @@ TEST(DisableBreak) { CHECK_EQ(2, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -4220,7 +4219,7 @@ TEST(NoBreakWhenBootstrapping) { v8::HandleScope scope(isolate); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetDebugEventListener2(DebugEventCounter); + v8::Debug::SetDebugEventListener(DebugEventCounter); // Set the debug break flag. v8::Debug::DebugBreak(isolate); @@ -4239,7 +4238,7 @@ TEST(NoBreakWhenBootstrapping) { CHECK_EQ(0, break_point_hit_count); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -4374,15 +4373,15 @@ TEST(InterceptorPropertyMirror) { // Check that the properties are interceptor properties. for (int i = 0; i < 3; i++) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "named_values[%d] instanceof debug.PropertyMirror", i); + SNPrintF(buffer, + "named_values[%d] instanceof debug.PropertyMirror", i); CHECK(CompileRun(buffer.start())->BooleanValue()); - OS::SNPrintF(buffer, "named_values[%d].propertyType()", i); + SNPrintF(buffer, "named_values[%d].propertyType()", i); CHECK_EQ(v8::internal::INTERCEPTOR, CompileRun(buffer.start())->Int32Value()); - OS::SNPrintF(buffer, "named_values[%d].isNative()", i); + SNPrintF(buffer, "named_values[%d].isNative()", i); CHECK(CompileRun(buffer.start())->BooleanValue()); } @@ -4393,8 +4392,8 @@ TEST(InterceptorPropertyMirror) { // Check that the properties are interceptor properties. for (int i = 0; i < 2; i++) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, - "indexed_values[%d] instanceof debug.PropertyMirror", i); + SNPrintF(buffer, + "indexed_values[%d] instanceof debug.PropertyMirror", i); CHECK(CompileRun(buffer.start())->BooleanValue()); } @@ -4405,7 +4404,7 @@ TEST(InterceptorPropertyMirror) { // Check that the properties are interceptor properties. for (int i = 0; i < 5; i++) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i); + SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i); CHECK(CompileRun(buffer.start())->BooleanValue()); } @@ -4730,7 +4729,7 @@ class ThreadBarrier V8_FINAL { Mutex mutex_; int num_blocked_; - STATIC_CHECK(N > 0); + STATIC_ASSERT(N > 0); DISALLOW_COPY_AND_ASSIGN(ThreadBarrier); }; @@ -4745,8 +4744,8 @@ class Barriers { ThreadBarrier<2> barrier_3; ThreadBarrier<2> barrier_4; ThreadBarrier<2> barrier_5; - v8::internal::Semaphore semaphore_1; - v8::internal::Semaphore semaphore_2; + v8::base::Semaphore semaphore_1; + v8::base::Semaphore semaphore_2; }; @@ -4846,10 +4845,10 @@ Barriers message_queue_barriers; // This is the debugger thread, that executes no v8 calls except // placing JSON debugger commands in the queue. -class MessageQueueDebuggerThread : public v8::internal::Thread { +class MessageQueueDebuggerThread : public v8::base::Thread { public: MessageQueueDebuggerThread() - : Thread("MessageQueueDebuggerThread") { } + : Thread(Options("MessageQueueDebuggerThread")) {} void Run(); }; @@ -4961,7 +4960,7 @@ TEST(MessageQueues) { // Create a V8 environment DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetMessageHandler2(MessageHandler); + v8::Debug::SetMessageHandler(MessageHandler); message_queue_debugger_thread.Start(); const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; @@ -5055,7 +5054,7 @@ TEST(SendClientDataToHandler) { v8::HandleScope scope(isolate); TestClientData::ResetCounters(); handled_client_data_instances_count = 0; - v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData); + v8::Debug::SetMessageHandler(MessageHandlerCountingClientData); const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;"; const int kBufferSize = 1000; uint16_t buffer[kBufferSize]; @@ -5103,15 +5102,15 @@ TEST(SendClientDataToHandler) { Barriers threaded_debugging_barriers; -class V8Thread : public v8::internal::Thread { +class V8Thread : public v8::base::Thread { public: - V8Thread() : Thread("V8Thread") { } + V8Thread() : Thread(Options("V8Thread")) {} void Run(); }; -class DebuggerThread : public v8::internal::Thread { +class DebuggerThread : public v8::base::Thread { public: - DebuggerThread() : Thread("DebuggerThread") { } + DebuggerThread() : Thread(Options("DebuggerThread")) {} void Run(); }; @@ -5129,10 +5128,7 @@ static void ThreadedMessageHandler(const v8::Debug::Message& message) { if (IsBreakEventMessage(print_buffer)) { // Check that we are inside the while loop. int source_line = GetSourceLineFromBreakEventMessage(print_buffer); - // TODO(2047): This should really be 8 <= source_line <= 13; but we - // currently have an off-by-one error when calculating the source - // position corresponding to the program counter at the debug break. - CHECK(7 <= source_line && source_line <= 13); + CHECK(8 <= source_line && source_line <= 13); threaded_debugging_barriers.barrier_2.Wait(); } } @@ -5162,7 +5158,7 @@ void V8Thread::Run() { v8::Isolate::Scope isolate_scope(isolate); DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetMessageHandler2(&ThreadedMessageHandler); + v8::Debug::SetMessageHandler(&ThreadedMessageHandler); v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(env->GetIsolate()); global_template->Set( @@ -5218,16 +5214,16 @@ TEST(ThreadedDebugging) { * breakpoint is hit when enabled, and missed when disabled. */ -class BreakpointsV8Thread : public v8::internal::Thread { +class BreakpointsV8Thread : public v8::base::Thread { public: - BreakpointsV8Thread() : Thread("BreakpointsV8Thread") { } + BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {} void Run(); }; -class BreakpointsDebuggerThread : public v8::internal::Thread { +class BreakpointsDebuggerThread : public v8::base::Thread { public: explicit BreakpointsDebuggerThread(bool global_evaluate) - : Thread("BreakpointsDebuggerThread"), + : Thread(Options("BreakpointsDebuggerThread")), global_evaluate_(global_evaluate) {} void Run(); @@ -5281,7 +5277,7 @@ void BreakpointsV8Thread::Run() { v8::Isolate::Scope isolate_scope(isolate); DebugLocalContext env; v8::HandleScope scope(isolate); - v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler); + v8::Debug::SetMessageHandler(&BreakpointsMessageHandler); CompileRun(source_1); breakpoints_barriers->barrier_1.Wait(); @@ -5438,7 +5434,7 @@ static void DummyDebugEventListener( TEST(SetDebugEventListenerOnUninitializedVM) { - v8::Debug::SetDebugEventListener2(DummyDebugEventListener); + v8::Debug::SetDebugEventListener(DummyDebugEventListener); } @@ -5447,7 +5443,7 @@ static void DummyMessageHandler(const v8::Debug::Message& message) { TEST(SetMessageHandlerOnUninitializedVM) { - v8::Debug::SetMessageHandler2(DummyMessageHandler); + v8::Debug::SetMessageHandler(DummyMessageHandler); } @@ -5501,13 +5497,12 @@ static void CheckDataParameter( v8::String::NewFromUtf8(args.GetIsolate(), "Test"); CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString()); - CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty()); - CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty()); - - v8::TryCatch catcher; - v8::Debug::Call(debugger_call_with_data); - CHECK(catcher.HasCaught()); - CHECK(catcher.Exception()->IsString()); + for (int i = 0; i < 3; i++) { + v8::TryCatch catcher; + CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty()); + CHECK(catcher.HasCaught()); + CHECK(catcher.Exception()->IsString()); + } } @@ -5639,7 +5634,7 @@ TEST(DebuggerUnload) { // Set a debug event listener. break_point_hit_count = 0; - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); { v8::HandleScope scope(env->GetIsolate()); // Create a couple of functions for the test. @@ -5664,12 +5659,12 @@ TEST(DebuggerUnload) { // Remove the debug event listener without clearing breakpoints. Do this // outside a handle scope. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(true); // Now set a debug message handler. break_point_hit_count = 0; - v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount); + v8::Debug::SetMessageHandler(MessageHandlerBreakPointHitCount); { v8::HandleScope scope(env->GetIsolate()); @@ -5689,7 +5684,7 @@ TEST(DebuggerUnload) { // Remove the debug message handler without clearing breakpoints. Do this // outside a handle scope. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(true); } @@ -5732,7 +5727,7 @@ TEST(DebuggerClearMessageHandler) { CheckDebuggerUnloaded(); // Set a debug message handler. - v8::Debug::SetMessageHandler2(MessageHandlerHitCount); + v8::Debug::SetMessageHandler(MessageHandlerHitCount); // Run code to throw a unhandled exception. This should end up in the message // handler. @@ -5743,7 +5738,7 @@ TEST(DebuggerClearMessageHandler) { // Clear debug message handler. message_handler_hit_count = 0; - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); // Run code to throw a unhandled exception. This should end up in the message // handler. @@ -5762,7 +5757,7 @@ static void MessageHandlerClearingMessageHandler( message_handler_hit_count++; // Clear debug message handler. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); } @@ -5775,7 +5770,7 @@ TEST(DebuggerClearMessageHandlerWhileActive) { CheckDebuggerUnloaded(); // Set a debug message handler. - v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler); + v8::Debug::SetMessageHandler(MessageHandlerClearingMessageHandler); // Run code to throw a unhandled exception. This should end up in the message // handler. @@ -5788,344 +5783,6 @@ TEST(DebuggerClearMessageHandlerWhileActive) { } -/* Test DebuggerHostDispatch */ -/* In this test, the debugger waits for a command on a breakpoint - * and is dispatching host commands while in the infinite loop. - */ - -class HostDispatchV8Thread : public v8::internal::Thread { - public: - HostDispatchV8Thread() : Thread("HostDispatchV8Thread") { } - void Run(); -}; - -class HostDispatchDebuggerThread : public v8::internal::Thread { - public: - HostDispatchDebuggerThread() : Thread("HostDispatchDebuggerThread") { } - void Run(); -}; - -Barriers* host_dispatch_barriers; - -static void HostDispatchMessageHandler(const v8::Debug::Message& message) { - static char print_buffer[1000]; - v8::String::Value json(message.GetJSON()); - Utf16ToAscii(*json, json.length(), print_buffer); -} - - -static void HostDispatchDispatchHandler() { - host_dispatch_barriers->semaphore_1.Signal(); -} - - -void HostDispatchV8Thread::Run() { - const char* source_1 = "var y_global = 3;\n" - "function cat( new_value ) {\n" - " var x = new_value;\n" - " y_global = 4;\n" - " x = 3 * x + 1;\n" - " y_global = 5;\n" - " return x;\n" - "}\n" - "\n"; - const char* source_2 = "cat(17);\n"; - - v8::Isolate::Scope isolate_scope(CcTest::isolate()); - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - // Set up message and host dispatch handlers. - v8::Debug::SetMessageHandler2(HostDispatchMessageHandler); - v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */); - - CompileRun(source_1); - host_dispatch_barriers->barrier_1.Wait(); - host_dispatch_barriers->barrier_2.Wait(); - CompileRun(source_2); -} - - -void HostDispatchDebuggerThread::Run() { - const int kBufSize = 1000; - uint16_t buffer[kBufSize]; - - const char* command_1 = "{\"seq\":101," - "\"type\":\"request\"," - "\"command\":\"setbreakpoint\"," - "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}"; - const char* command_2 = "{\"seq\":102," - "\"type\":\"request\"," - "\"command\":\"continue\"}"; - - v8::Isolate* isolate = CcTest::isolate(); - // v8 thread initializes, runs source_1 - host_dispatch_barriers->barrier_1.Wait(); - // 1: Set breakpoint in cat(). - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer)); - - host_dispatch_barriers->barrier_2.Wait(); - // v8 thread starts compiling source_2. - // Break happens, to run queued commands and host dispatches. - // Wait for host dispatch to be processed. - host_dispatch_barriers->semaphore_1.Wait(); - // 2: Continue evaluation - v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer)); -} - - -TEST(DebuggerHostDispatch) { - HostDispatchDebuggerThread host_dispatch_debugger_thread; - HostDispatchV8Thread host_dispatch_v8_thread; - - // Create a V8 environment - Barriers stack_allocated_host_dispatch_barriers; - host_dispatch_barriers = &stack_allocated_host_dispatch_barriers; - - host_dispatch_v8_thread.Start(); - host_dispatch_debugger_thread.Start(); - - host_dispatch_v8_thread.Join(); - host_dispatch_debugger_thread.Join(); -} - - -/* Test DebugMessageDispatch */ -/* In this test, the V8 thread waits for a message from the debug thread. - * The DebugMessageDispatchHandler is executed from the debugger thread - * which signals the V8 thread to wake up. - */ - -class DebugMessageDispatchV8Thread : public v8::internal::Thread { - public: - DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { } - void Run(); -}; - -class DebugMessageDispatchDebuggerThread : public v8::internal::Thread { - public: - DebugMessageDispatchDebuggerThread() - : Thread("DebugMessageDispatchDebuggerThread") { } - void Run(); -}; - -Barriers* debug_message_dispatch_barriers; - - -static void DebugMessageHandler() { - debug_message_dispatch_barriers->semaphore_1.Signal(); -} - - -void DebugMessageDispatchV8Thread::Run() { - v8::Isolate::Scope isolate_scope(CcTest::isolate()); - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - // Set up debug message dispatch handler. - v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler); - - CompileRun("var y = 1 + 2;\n"); - debug_message_dispatch_barriers->barrier_1.Wait(); - debug_message_dispatch_barriers->semaphore_1.Wait(); - debug_message_dispatch_barriers->barrier_2.Wait(); -} - - -void DebugMessageDispatchDebuggerThread::Run() { - debug_message_dispatch_barriers->barrier_1.Wait(); - SendContinueCommand(); - debug_message_dispatch_barriers->barrier_2.Wait(); -} - - -TEST(DebuggerDebugMessageDispatch) { - DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread; - DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread; - - // Create a V8 environment - Barriers stack_allocated_debug_message_dispatch_barriers; - debug_message_dispatch_barriers = - &stack_allocated_debug_message_dispatch_barriers; - - debug_message_dispatch_v8_thread.Start(); - debug_message_dispatch_debugger_thread.Start(); - - debug_message_dispatch_v8_thread.Join(); - debug_message_dispatch_debugger_thread.Join(); -} - - -TEST(DebuggerAgent) { - v8::V8::Initialize(); - i::Debugger* debugger = CcTest::i_isolate()->debugger(); - // Make sure these ports is not used by other tests to allow tests to run in - // parallel. - const int kPort1 = 5858 + FlagDependentPortOffset(); - const int kPort2 = 5857 + FlagDependentPortOffset(); - const int kPort3 = 5856 + FlagDependentPortOffset(); - - // Make a string with the port2 number. - const int kPortBufferLen = 6; - char port2_str[kPortBufferLen]; - OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2); - - bool ok; - - // Test starting and stopping the agent without any client connection. - debugger->StartAgent("test", kPort1); - debugger->StopAgent(); - // Test starting the agent, connecting a client and shutting down the agent - // with the client connected. - ok = debugger->StartAgent("test", kPort2); - CHECK(ok); - debugger->WaitForAgent(); - i::Socket* client = new i::Socket; - ok = client->Connect("localhost", port2_str); - CHECK(ok); - // It is important to wait for a message from the agent. Otherwise, - // we can close the server socket during "accept" syscall, making it failing - // (at least on Linux), and the test will work incorrectly. - char buf; - ok = client->Receive(&buf, 1) == 1; - CHECK(ok); - debugger->StopAgent(); - delete client; - - // Test starting and stopping the agent with the required port already - // occoupied. - i::Socket* server = new i::Socket; - ok = server->Bind(kPort3); - CHECK(ok); - - debugger->StartAgent("test", kPort3); - debugger->StopAgent(); - - delete server; -} - - -class DebuggerAgentProtocolServerThread : public i::Thread { - public: - explicit DebuggerAgentProtocolServerThread(int port) - : Thread("DebuggerAgentProtocolServerThread"), - port_(port), - server_(NULL), - client_(NULL), - listening_(0) { - } - ~DebuggerAgentProtocolServerThread() { - // Close both sockets. - delete client_; - delete server_; - } - - void Run(); - void WaitForListening() { listening_.Wait(); } - char* body() { return body_.get(); } - - private: - int port_; - i::SmartArrayPointer<char> body_; - i::Socket* server_; // Server socket used for bind/accept. - i::Socket* client_; // Single client connection used by the test. - i::Semaphore listening_; // Signalled when the server is in listen mode. -}; - - -void DebuggerAgentProtocolServerThread::Run() { - bool ok; - - // Create the server socket and bind it to the requested port. - server_ = new i::Socket; - CHECK(server_ != NULL); - ok = server_->Bind(port_); - CHECK(ok); - - // Listen for new connections. - ok = server_->Listen(1); - CHECK(ok); - listening_.Signal(); - - // Accept a connection. - client_ = server_->Accept(); - CHECK(client_ != NULL); - - // Receive a debugger agent protocol message. - i::DebuggerAgentUtil::ReceiveMessage(client_); -} - - -TEST(DebuggerAgentProtocolOverflowHeader) { - // Make sure this port is not used by other tests to allow tests to run in - // parallel. - const int kPort = 5860 + FlagDependentPortOffset(); - static const char* kLocalhost = "localhost"; - - // Make a string with the port number. - const int kPortBufferLen = 6; - char port_str[kPortBufferLen]; - OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort); - - // Create a socket server to receive a debugger agent message. - DebuggerAgentProtocolServerThread* server = - new DebuggerAgentProtocolServerThread(kPort); - server->Start(); - server->WaitForListening(); - - // Connect. - i::Socket* client = new i::Socket; - CHECK(client != NULL); - bool ok = client->Connect(kLocalhost, port_str); - CHECK(ok); - - // Send headers which overflow the receive buffer. - static const int kBufferSize = 1000; - char buffer[kBufferSize]; - - // Long key and short value: XXXX....XXXX:0\r\n. - for (int i = 0; i < kBufferSize - 4; i++) { - buffer[i] = 'X'; - } - buffer[kBufferSize - 4] = ':'; - buffer[kBufferSize - 3] = '0'; - buffer[kBufferSize - 2] = '\r'; - buffer[kBufferSize - 1] = '\n'; - int result = client->Send(buffer, kBufferSize); - CHECK_EQ(kBufferSize, result); - - // Short key and long value: X:XXXX....XXXX\r\n. - buffer[0] = 'X'; - buffer[1] = ':'; - for (int i = 2; i < kBufferSize - 2; i++) { - buffer[i] = 'X'; - } - buffer[kBufferSize - 2] = '\r'; - buffer[kBufferSize - 1] = '\n'; - result = client->Send(buffer, kBufferSize); - CHECK_EQ(kBufferSize, result); - - // Add empty body to request. - const char* content_length_zero_header = "Content-Length:0\r\n"; - int length = StrLength(content_length_zero_header); - result = client->Send(content_length_zero_header, length); - CHECK_EQ(length, result); - result = client->Send("\r\n", 2); - CHECK_EQ(2, result); - - // Wait until data is received. - server->Join(); - - // Check for empty body. - CHECK(server->body() == NULL); - - // Close the client before the server to avoid TIME_WAIT issues. - client->Shutdown(); - delete client; - delete server; -} - - // Test for issue http://code.google.com/p/v8/issues/detail?id=289. // Make sure that DebugGetLoadedScripts doesn't return scripts // with disposed external source. @@ -6189,7 +5846,7 @@ TEST(ScriptNameAndData) { frame_script_name_source, "frame_script_name"); - v8::Debug::SetDebugEventListener2(DebugEventBreakPointHitCount); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); // Test function source. v8::Local<v8::String> script = v8::String::NewFromUtf8(env->GetIsolate(), @@ -6282,7 +5939,7 @@ TEST(ContextData) { context_1 = v8::Context::New(isolate, NULL, global_template, global_object); context_2 = v8::Context::New(isolate, NULL, global_template, global_object); - v8::Debug::SetMessageHandler2(ContextCheckMessageHandler); + v8::Debug::SetMessageHandler(ContextCheckMessageHandler); // Default data value is undefined. CHECK(context_1->GetEmbedderData(0)->IsUndefined()); @@ -6321,7 +5978,7 @@ TEST(ContextData) { // Two times compile event and two times break event. CHECK_GT(message_handler_hit_count, 4); - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); } @@ -6350,7 +6007,7 @@ TEST(DebugBreakInMessageHandler) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetMessageHandler2(DebugBreakMessageHandler); + v8::Debug::SetMessageHandler(DebugBreakMessageHandler); // Test functions. const char* script = "function f() { debugger; g(); } function g() { }"; @@ -6430,7 +6087,7 @@ TEST(RegExpDebugBreak) { v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv); CHECK_EQ(12, result->Int32Value()); - v8::Debug::SetDebugEventListener2(DebugEventDebugBreak); + v8::Debug::SetDebugEventListener(DebugEventDebugBreak); v8::Debug::DebugBreak(env->GetIsolate()); result = f->Call(env->Global(), argc, argv); @@ -6444,7 +6101,7 @@ TEST(RegExpDebugBreak) { // Common part of EvalContextData and NestedBreakEventContextData tests. static void ExecuteScriptForContextCheck( - v8::Debug::MessageHandler2 message_handler) { + v8::Debug::MessageHandler message_handler) { // Create a context. v8::Handle<v8::Context> context_1; v8::Handle<v8::ObjectTemplate> global_template = @@ -6452,7 +6109,7 @@ static void ExecuteScriptForContextCheck( context_1 = v8::Context::New(CcTest::isolate(), NULL, global_template); - v8::Debug::SetMessageHandler2(message_handler); + v8::Debug::SetMessageHandler(message_handler); // Default data value is undefined. CHECK(context_1->GetEmbedderData(0)->IsUndefined()); @@ -6475,7 +6132,7 @@ static void ExecuteScriptForContextCheck( f->Call(context_1->Global(), 0, NULL); } - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); } @@ -6562,120 +6219,6 @@ TEST(NestedBreakEventContextData) { } -// Debug event listener which counts the script collected events. -int script_collected_count = 0; -static void DebugEventScriptCollectedEvent( - const v8::Debug::EventDetails& event_details) { - v8::DebugEvent event = event_details.GetEvent(); - // Count the number of breaks. - if (event == v8::ScriptCollected) { - script_collected_count++; - } -} - - -// Test that scripts collected are reported through the debug event listener. -TEST(ScriptCollectedEvent) { - v8::internal::Debug* debug = CcTest::i_isolate()->debug(); - break_point_hit_count = 0; - script_collected_count = 0; - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - - // Request the loaded scripts to initialize the debugger script cache. - debug->GetLoadedScripts(); - - // Do garbage collection to ensure that only the script in this test will be - // collected afterwards. - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - - script_collected_count = 0; - v8::Debug::SetDebugEventListener2(DebugEventScriptCollectedEvent); - { - v8::Script::Compile( - v8::String::NewFromUtf8(env->GetIsolate(), "eval('a=1')"))->Run(); - v8::Script::Compile( - v8::String::NewFromUtf8(env->GetIsolate(), "eval('a=2')"))->Run(); - } - - // Do garbage collection to collect the script above which is no longer - // referenced. - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - - CHECK_EQ(2, script_collected_count); - - v8::Debug::SetDebugEventListener2(NULL); - CheckDebuggerUnloaded(); -} - - -// Debug event listener which counts the script collected events. -int script_collected_message_count = 0; -static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) { - // Count the number of scripts collected. - if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) { - script_collected_message_count++; - v8::Handle<v8::Context> context = message.GetEventContext(); - CHECK(context.IsEmpty()); - } -} - - -// Test that GetEventContext doesn't fail and return empty handle for -// ScriptCollected events. -TEST(ScriptCollectedEventContext) { - i::FLAG_stress_compaction = false; - v8::Isolate* isolate = CcTest::isolate(); - v8::internal::Debug* debug = - reinterpret_cast<v8::internal::Isolate*>(isolate)->debug(); - script_collected_message_count = 0; - v8::HandleScope scope(isolate); - - v8::Persistent<v8::Context> context; - { - v8::HandleScope scope(isolate); - context.Reset(isolate, v8::Context::New(isolate)); - } - - // Enter context. We can't have a handle to the context in the outer - // scope, so we have to do it the hard way. - { - v8::HandleScope scope(isolate); - v8::Local<v8::Context> local_context = - v8::Local<v8::Context>::New(isolate, context); - local_context->Enter(); - } - - // Request the loaded scripts to initialize the debugger script cache. - debug->GetLoadedScripts(); - - // Do garbage collection to ensure that only the script in this test will be - // collected afterwards. - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - - v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler); - v8::Script::Compile(v8::String::NewFromUtf8(isolate, "eval('a=1')"))->Run(); - v8::Script::Compile(v8::String::NewFromUtf8(isolate, "eval('a=2')"))->Run(); - - // Leave context - { - v8::HandleScope scope(isolate); - v8::Local<v8::Context> local_context = - v8::Local<v8::Context>::New(isolate, context); - local_context->Exit(); - } - context.Reset(); - - // Do garbage collection to collect the script above which is no longer - // referenced. - CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - - CHECK_EQ(2, script_collected_message_count); - - v8::Debug::SetMessageHandler2(NULL); -} - - // Debug event listener which counts the after compile events. int after_compile_message_count = 0; static void AfterCompileMessageHandler(const v8::Debug::Message& message) { @@ -6698,18 +6241,18 @@ TEST(AfterCompileMessageWhenMessageHandlerIsReset) { after_compile_message_count = 0; const char* script = "var a=1"; - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script)) ->Run(); - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::Debug::DebugBreak(env->GetIsolate()); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script)) ->Run(); // Setting listener to NULL should cause debugger unload. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); // Compilation cache should be disabled when debugger is active. @@ -6717,6 +6260,60 @@ TEST(AfterCompileMessageWhenMessageHandlerIsReset) { } +// Syntax error event handler which counts a number of events. +int compile_error_event_count = 0; + +static void CompileErrorEventCounterClear() { + compile_error_event_count = 0; +} + +static void CompileErrorEventCounter( + const v8::Debug::EventDetails& event_details) { + v8::DebugEvent event = event_details.GetEvent(); + + if (event == v8::CompileError) { + compile_error_event_count++; + } +} + + +// Tests that syntax error event is sent as many times as there are scripts +// with syntax error compiled. +TEST(SyntaxErrorMessageOnSyntaxException) { + DebugLocalContext env; + v8::HandleScope scope(env->GetIsolate()); + + // For this test, we want to break on uncaught exceptions: + ChangeBreakOnException(false, true); + + v8::Debug::SetDebugEventListener(CompileErrorEventCounter); + + CompileErrorEventCounterClear(); + + // Check initial state. + CHECK_EQ(0, compile_error_event_count); + + // Throws SyntaxError: Unexpected end of input + v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "+++")); + CHECK_EQ(1, compile_error_event_count); + + v8::Script::Compile( + v8::String::NewFromUtf8(env->GetIsolate(), "/sel\\/: \\")); + CHECK_EQ(2, compile_error_event_count); + + v8::Script::Compile( + v8::String::NewFromUtf8(env->GetIsolate(), "JSON.parse('1234:')")); + CHECK_EQ(2, compile_error_event_count); + + v8::Script::Compile( + v8::String::NewFromUtf8(env->GetIsolate(), "new RegExp('/\\/\\\\');")); + CHECK_EQ(2, compile_error_event_count); + + v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "throw 1;")); + CHECK_EQ(2, compile_error_event_count); +} + + // Tests that break event is sent when message handler is reset. TEST(BreakMessageWhenMessageHandlerIsReset) { DebugLocalContext env; @@ -6724,19 +6321,19 @@ TEST(BreakMessageWhenMessageHandlerIsReset) { after_compile_message_count = 0; const char* script = "function f() {};"; - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script)) ->Run(); - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::Debug::DebugBreak(env->GetIsolate()); v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); f->Call(env->Global(), 0, NULL); // Setting message handler to NULL should cause debugger unload. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); // Compilation cache should be disabled when debugger is active. @@ -6764,18 +6361,18 @@ TEST(ExceptionMessageWhenMessageHandlerIsReset) { exception_event_count = 0; const char* script = "function f() {throw new Error()};"; - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script)) ->Run(); - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); - v8::Debug::SetMessageHandler2(ExceptionMessageHandler); + v8::Debug::SetMessageHandler(ExceptionMessageHandler); v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); f->Call(env->Global(), 0, NULL); // Setting message handler to NULL should cause debugger unload. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); CHECK_EQ(1, exception_event_count); @@ -6799,7 +6396,7 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5); after_compile_message_count = 0; - v8::Debug::SetMessageHandler2(AfterCompileMessageHandler); + v8::Debug::SetMessageHandler(AfterCompileMessageHandler); v8::ScriptOrigin origin( v8::String::NewFromUtf8(env->GetIsolate(), resource_name), @@ -6817,7 +6414,7 @@ TEST(ProvisionalBreakpointOnLineOutOfRange) { ClearBreakPointFromJS(env->GetIsolate(), sbp1); ClearBreakPointFromJS(env->GetIsolate(), sbp2); - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); } @@ -6834,19 +6431,12 @@ static void BreakMessageHandler(const v8::Debug::Message& message) { } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) { i::HandleScope scope(isolate); - bool is_debug_break = isolate->stack_guard()->IsDebugBreak(); - // Force DebugBreak flag while serializer is working. - isolate->stack_guard()->DebugBreak(); + int current_count = break_point_hit_count; // Force serialization to trigger some internal JS execution. message.GetJSON(); - // Restore previous state. - if (is_debug_break) { - isolate->stack_guard()->DebugBreak(); - } else { - isolate->stack_guard()->Continue(i::DEBUGBREAK); - } + CHECK_EQ(current_count, break_point_hit_count); } } @@ -6858,7 +6448,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetMessageHandler2(BreakMessageHandler); + v8::Debug::SetMessageHandler(BreakMessageHandler); // Set the debug break flag. v8::Debug::DebugBreak(env->GetIsolate()); @@ -6877,7 +6467,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) { CHECK_EQ(2, break_point_hit_count); // Get rid of the debug message handler. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); } @@ -6885,7 +6475,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) { static int counting_message_handler_counter; static void CountingMessageHandler(const v8::Debug::Message& message) { - counting_message_handler_counter++; + if (message.IsResponse()) counting_message_handler_counter++; } @@ -6897,7 +6487,7 @@ TEST(ProcessDebugMessages) { counting_message_handler_counter = 0; - v8::Debug::SetMessageHandler2(CountingMessageHandler); + v8::Debug::SetMessageHandler(CountingMessageHandler); const int kBufferSize = 1000; uint16_t buffer[kBufferSize]; @@ -6927,7 +6517,84 @@ TEST(ProcessDebugMessages) { CHECK_GE(counting_message_handler_counter, 2); // Get rid of the debug message handler. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); + CheckDebuggerUnloaded(); +} + + +class SendCommandThread : public v8::base::Thread { + public: + explicit SendCommandThread(v8::Isolate* isolate) + : Thread(Options("SendCommandThread")), + semaphore_(0), + isolate_(isolate) {} + + static void ProcessDebugMessages(v8::Isolate* isolate, void* data) { + v8::Debug::ProcessDebugMessages(); + reinterpret_cast<v8::base::Semaphore*>(data)->Signal(); + } + + virtual void Run() { + semaphore_.Wait(); + const int kBufferSize = 1000; + uint16_t buffer[kBufferSize]; + const char* scripts_command = + "{\"seq\":0," + "\"type\":\"request\"," + "\"command\":\"scripts\"}"; + int length = AsciiToUtf16(scripts_command, buffer); + // Send scripts command. + + for (int i = 0; i < 100; i++) { + CHECK_EQ(i, counting_message_handler_counter); + // Queue debug message. + v8::Debug::SendCommand(isolate_, buffer, length); + // Synchronize with the main thread to force message processing. + isolate_->RequestInterrupt(ProcessDebugMessages, &semaphore_); + semaphore_.Wait(); + } + + v8::V8::TerminateExecution(isolate_); + } + + void StartSending() { + semaphore_.Signal(); + } + + private: + v8::base::Semaphore semaphore_; + v8::Isolate* isolate_; +}; + + +static SendCommandThread* send_command_thread_ = NULL; + +static void StartSendingCommands( + const v8::FunctionCallbackInfo<v8::Value>& info) { + send_command_thread_->StartSending(); +} + + +TEST(ProcessDebugMessagesThreaded) { + DebugLocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + counting_message_handler_counter = 0; + + v8::Debug::SetMessageHandler(CountingMessageHandler); + send_command_thread_ = new SendCommandThread(isolate); + send_command_thread_->Start(); + + v8::Handle<v8::FunctionTemplate> start = + v8::FunctionTemplate::New(isolate, StartSendingCommands); + env->Global()->Set(v8_str("start"), start->GetFunction()); + + CompileRun("start(); while (true) { }"); + + CHECK_EQ(100, counting_message_handler_counter); + + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); } @@ -6955,7 +6622,7 @@ TEST(Backtrace) { v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); - v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler); + v8::Debug::SetMessageHandler(BacktraceData::MessageHandler); const int kBufferSize = 1000; uint16_t buffer[kBufferSize]; @@ -6989,7 +6656,7 @@ TEST(Backtrace) { CHECK_EQ(BacktraceData::frame_counter, 1); // Get rid of the debug message handler. - v8::Debug::SetMessageHandler2(NULL); + v8::Debug::SetMessageHandler(NULL); CheckDebuggerUnloaded(); } @@ -7029,7 +6696,7 @@ TEST(DebugBreakFunctionApply) { "foo"); // Register a debug event listener which steps and counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakMax); + v8::Debug::SetDebugEventListener(DebugEventBreakMax); // Set the debug break flag before calling the code using function.apply. v8::Debug::DebugBreak(env->GetIsolate()); @@ -7043,7 +6710,7 @@ TEST(DebugBreakFunctionApply) { // When keeping the debug break several break will happen. CHECK_GT(break_point_hit_count, 1); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -7112,7 +6779,7 @@ TEST(CallingContextIsNotDebugContext) { named->NewInstance()); // Register the debug event listener - v8::Debug::SetDebugEventListener2(DebugEventGetAtgumentPropertyValue); + v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue); // Create a function that invokes debugger. v8::Local<v8::Function> foo = CompileFunction( @@ -7125,7 +6792,7 @@ TEST(CallingContextIsNotDebugContext) { foo->Call(env->Global(), 0, NULL); CHECK_EQ(1, break_point_hit_count); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); debugee_context = v8::Handle<v8::Context>(); debugger_context = v8::Handle<v8::Context>(); CheckDebuggerUnloaded(); @@ -7134,9 +6801,12 @@ TEST(CallingContextIsNotDebugContext) { TEST(DebugContextIsPreservedBetweenAccesses) { v8::HandleScope scope(CcTest::isolate()); + v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount); v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext(); v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext(); - CHECK_EQ(*context1, *context2); + CHECK(v8::Utils::OpenHandle(*context1).is_identical_to( + v8::Utils::OpenHandle(*context2))); + v8::Debug::SetDebugEventListener(NULL); } @@ -7153,13 +6823,13 @@ TEST(DebugEventContext) { v8::HandleScope scope(isolate); expected_context = v8::Context::New(isolate); expected_callback_data = v8::Int32::New(isolate, 2010); - v8::Debug::SetDebugEventListener2(DebugEventContextChecker, + v8::Debug::SetDebugEventListener(DebugEventContextChecker, expected_callback_data); v8::Context::Scope context_scope(expected_context); v8::Script::Compile( v8::String::NewFromUtf8(isolate, "(function(){debugger;})();"))->Run(); expected_context.Clear(); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); expected_context_data = v8::Handle<v8::Value>(); CheckDebuggerUnloaded(); } @@ -7183,7 +6853,7 @@ TEST(DebugEventBreakData) { DebugLocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); - v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker); + v8::Debug::SetDebugEventListener(DebugEventBreakDataChecker); TestClientData::constructor_call_counter = 0; TestClientData::destructor_call_counter = 0; @@ -7191,7 +6861,7 @@ TEST(DebugEventBreakData) { expected_break_data = NULL; was_debug_event_called = false; was_debug_break_called = false; - v8::Debug::DebugBreakForCommand(NULL, isolate); + v8::Debug::DebugBreakForCommand(isolate, NULL); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "(function(x){return x;})(1);")) ->Run(); @@ -7202,7 +6872,7 @@ TEST(DebugEventBreakData) { expected_break_data = data1; was_debug_event_called = false; was_debug_break_called = false; - v8::Debug::DebugBreakForCommand(data1, isolate); + v8::Debug::DebugBreakForCommand(isolate, data1); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "(function(x){return x+1;})(1);")) ->Run(); @@ -7224,7 +6894,7 @@ TEST(DebugEventBreakData) { was_debug_event_called = false; was_debug_break_called = false; v8::Debug::DebugBreak(isolate); - v8::Debug::DebugBreakForCommand(data2, isolate); + v8::Debug::DebugBreakForCommand(isolate, data2); v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "(function(x){return x+3;})(1);")) ->Run(); @@ -7235,7 +6905,7 @@ TEST(DebugEventBreakData) { CHECK_EQ(TestClientData::constructor_call_counter, TestClientData::destructor_call_counter); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -7289,7 +6959,7 @@ TEST(DeoptimizeDuringDebugBreak) { // This tests lazy deoptimization bailout for the stack check, as the first // time in function bar when using debug break and no break points will be at // the initial stack check. - v8::Debug::SetDebugEventListener2(DebugEventBreakDeoptimize); + v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize); // Compile and run function bar which will optimize it for some flag settings. v8::Script::Compile(v8::String::NewFromUtf8( @@ -7302,7 +6972,7 @@ TEST(DeoptimizeDuringDebugBreak) { CHECK(debug_event_break_deoptimize_done); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); } @@ -7357,7 +7027,7 @@ static void DebugEventBreakWithOptimizedStack( static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Debug::SetDebugEventListener2(DebugEventBreakWithOptimizedStack); + v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack); v8::Debug::DebugBreak(args.GetIsolate()); } @@ -7415,9 +7085,9 @@ static void TestDebugBreakInLoop(const char* loop_head, terminate_after_max_break_point_hit = true; EmbeddedVector<char, 1024> buffer; - OS::SNPrintF(buffer, - "function f() {%s%s%s}", - loop_head, loop_bodies[i], loop_tail); + SNPrintF(buffer, + "function f() {%s%s%s}", + loop_head, loop_bodies[i], loop_tail); // Function with infinite loop. CompileRun(buffer.start()); @@ -7440,7 +7110,7 @@ TEST(DebugBreakLoop) { v8::HandleScope scope(env->GetIsolate()); // Register a debug event listener which sets the break flag and counts. - v8::Debug::SetDebugEventListener2(DebugEventBreakMax); + v8::Debug::SetDebugEventListener(DebugEventBreakMax); // Create a function for getting the frame count when hitting the break. frame_count = CompileFunction(&env, frame_count_source, "frame_count"); @@ -7474,7 +7144,7 @@ TEST(DebugBreakLoop) { TestDebugBreakInLoop("for (;a == 1;) {", loop_bodies, "}"); // Get rid of the debug event listener. - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -7496,7 +7166,7 @@ static void DebugBreakInlineListener( int break_id = CcTest::i_isolate()->debug()->break_id(); char script[128]; i::Vector<char> script_vector(script, sizeof(script)); - OS::SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id); + SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id); v8::Local<v8::Value> result = CompileRun(script); int frame_count = result->Int32Value(); @@ -7505,12 +7175,12 @@ static void DebugBreakInlineListener( for (int i = 0; i < frame_count; i++) { // The 5. element in the returned array of GetFrameDetails contains the // source position of that frame. - OS::SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i); + SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i); v8::Local<v8::Value> result = CompileRun(script); CHECK_EQ(expected_line_number[i], i::Script::GetLineNumber(source_script, result->Int32Value())); } - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); v8::V8::TerminateExecution(CcTest::isolate()); } @@ -7533,7 +7203,7 @@ TEST(DebugBreakInline) { "g(false); \n" "%OptimizeFunctionOnNextCall(g); \n" "g(true);"; - v8::Debug::SetDebugEventListener2(DebugBreakInlineListener); + v8::Debug::SetDebugEventListener(DebugBreakInlineListener); inline_script = v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source)); inline_script->Run(); @@ -7567,7 +7237,7 @@ TEST(Regress131642) { // on the stack. DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugEventStepNext); + v8::Debug::SetDebugEventListener(DebugEventStepNext); // We step through the first script. It exits through an exception. We run // this inside a new frame to record a different FP than the second script @@ -7579,7 +7249,7 @@ TEST(Regress131642) { const char* script_2 = "[0].forEach(function() { });"; CompileRun(script_2); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); } @@ -7596,15 +7266,15 @@ TEST(DebuggerCreatesContextIffActive) { v8::HandleScope scope(env->GetIsolate()); CHECK_EQ(1, CountNativeContexts()); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CompileRun("debugger;"); CHECK_EQ(1, CountNativeContexts()); - v8::Debug::SetDebugEventListener2(NopListener); + v8::Debug::SetDebugEventListener(NopListener); CompileRun("debugger;"); CHECK_EQ(2, CountNativeContexts()); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); } @@ -7612,7 +7282,7 @@ TEST(LiveEditEnabled) { v8::internal::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetLiveEditEnabled(true, env->GetIsolate()); + v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true); CompileRun("%LiveEditCompareStrings('', '')"); } @@ -7621,7 +7291,7 @@ TEST(LiveEditDisabled) { v8::internal::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetLiveEditEnabled(false, env->GetIsolate()); + v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false); CompileRun("%LiveEditCompareStrings('', '')"); } @@ -7634,7 +7304,7 @@ TEST(PrecompiledFunction) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); env.ExposeDebug(); - v8::Debug::SetDebugEventListener2(DebugBreakInlineListener); + v8::Debug::SetDebugEventListener(DebugBreakInlineListener); v8::Local<v8::Function> break_here = CompileFunction(&env, "function break_here(){}", "break_here"); @@ -7651,12 +7321,12 @@ TEST(PrecompiledFunction) { "}; \n" "a = b = c = 2; \n" "bar(); \n"; - v8::Local<v8::Value> result = PreCompileCompileRun(source); + v8::Local<v8::Value> result = ParserCacheCompileRun(source); CHECK(result->IsString()); v8::String::Utf8Value utf8(result); CHECK_EQ("bar", *utf8); - v8::Debug::SetDebugEventListener2(NULL); + v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); } @@ -7675,7 +7345,7 @@ static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) { TEST(DebugBreakStackTrace) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); - v8::Debug::SetDebugEventListener2(DebugBreakStackTraceListener); + v8::Debug::SetDebugEventListener(DebugBreakStackTraceListener); v8::Handle<v8::FunctionTemplate> add_debug_break_template = v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak); v8::Handle<v8::Function> add_debug_break = @@ -7690,3 +7360,48 @@ TEST(DebugBreakStackTrace) { " }" "})()"); } + + +v8::base::Semaphore terminate_requested_semaphore(0); +v8::base::Semaphore terminate_fired_semaphore(0); +bool terminate_already_fired = false; + + +static void DebugBreakTriggerTerminate( + const v8::Debug::EventDetails& event_details) { + if (event_details.GetEvent() != v8::Break || terminate_already_fired) return; + terminate_requested_semaphore.Signal(); + // Wait for at most 2 seconds for the terminate request. + CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2))); + terminate_already_fired = true; +} + + +class TerminationThread : public v8::base::Thread { + public: + explicit TerminationThread(v8::Isolate* isolate) + : Thread(Options("terminator")), isolate_(isolate) {} + + virtual void Run() { + terminate_requested_semaphore.Wait(); + v8::V8::TerminateExecution(isolate_); + terminate_fired_semaphore.Signal(); + } + + private: + v8::Isolate* isolate_; +}; + + +TEST(DebugBreakOffThreadTerminate) { + DebugLocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + v8::Debug::SetDebugEventListener(DebugBreakTriggerTerminate); + TerminationThread terminator(isolate); + terminator.Start(); + v8::TryCatch try_catch; + v8::Debug::DebugBreak(isolate); + CompileRun("while (true);"); + CHECK(try_catch.HasTerminated()); +} diff --git a/deps/v8/test/cctest/test-declarative-accessors.cc b/deps/v8/test/cctest/test-declarative-accessors.cc index f2169a9fb8..8d93245eb6 100644 --- a/deps/v8/test/cctest/test-declarative-accessors.cc +++ b/deps/v8/test/cctest/test-declarative-accessors.cc @@ -27,9 +27,9 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -37,7 +37,7 @@ using namespace v8::internal; class HandleArray : public Malloced { public: static const unsigned kArraySize = 200; - explicit HandleArray() {} + HandleArray() {} ~HandleArray() { Reset(); } void Reset() { for (unsigned i = 0; i < kArraySize; i++) { diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index d6738a31ae..34f0b69643 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -27,10 +27,10 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "heap.h" -#include "cctest.h" +#include "src/heap/heap.h" +#include "test/cctest/cctest.h" using namespace v8; @@ -236,17 +236,14 @@ TEST(Unknown) { { DeclarationContext context; context.Check("var x; x", 1, // access - 1, // declaration - 2, // declaration + initialization - EXPECT_RESULT, Undefined(CcTest::isolate())); + 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); } { DeclarationContext context; context.Check("var x = 0; x", 1, // access - 2, // declaration + initialization - 2, // declaration + initialization - EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); + 1, // initialization + 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); } { DeclarationContext context; @@ -260,78 +257,19 @@ TEST(Unknown) { { DeclarationContext context; context.Check("const x; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); + 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); } { DeclarationContext context; - // SB 0 - BUG 1213579 context.Check("const x = 0; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); - } -} - - - -class PresentPropertyContext: public DeclarationContext { - protected: - virtual v8::Handle<Integer> Query(Local<String> key) { - return Integer::New(isolate(), v8::None); - } -}; - - - -TEST(Present) { - HandleScope scope(CcTest::isolate()); - - { PresentPropertyContext context; - context.Check("var x; x", - 1, // access 0, - 2, // declaration + initialization - EXPECT_EXCEPTION); // x is not defined! - } - - { PresentPropertyContext context; - context.Check("var x = 0; x", - 1, // access - 1, // initialization - 2, // declaration + initialization - EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); - } - - { PresentPropertyContext context; - context.Check("function x() { }; x", - 1, // access 0, - 0, - EXPECT_RESULT); - } - - { PresentPropertyContext context; - context.Check("const x; x", - 1, // access - 1, // initialization - 1, // (re-)declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); - } - - { PresentPropertyContext context; - context.Check("const x = 0; x", - 1, // access - 1, // initialization - 1, // (re-)declaration EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); } } - class AbsentPropertyContext: public DeclarationContext { protected: virtual v8::Handle<Integer> Query(Local<String> key) { @@ -348,17 +286,14 @@ TEST(Absent) { { AbsentPropertyContext context; context.Check("var x; x", 1, // access - 1, // declaration - 2, // declaration + initialization - EXPECT_RESULT, Undefined(isolate)); + 0, 0, EXPECT_RESULT, Undefined(isolate)); } { AbsentPropertyContext context; context.Check("var x = 0; x", 1, // access - 2, // declaration + initialization - 2, // declaration + initialization - EXPECT_RESULT, Number::New(isolate, 0)); + 1, // initialization + 0, EXPECT_RESULT, Number::New(isolate, 0)); } { AbsentPropertyContext context; @@ -372,25 +307,19 @@ TEST(Absent) { { AbsentPropertyContext context; context.Check("const x; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(isolate)); + 0, 0, EXPECT_RESULT, Undefined(isolate)); } { AbsentPropertyContext context; context.Check("const x = 0; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(isolate)); // SB 0 - BUG 1213579 + 0, 0, EXPECT_RESULT, Number::New(isolate, 0)); } { AbsentPropertyContext context; context.Check("if (false) { var x = 0 }; x", 1, // access - 1, // declaration - 1, // declaration + initialization - EXPECT_RESULT, Undefined(isolate)); + 0, 0, EXPECT_RESULT, Undefined(isolate)); } } @@ -439,17 +368,14 @@ TEST(Appearing) { { AppearingPropertyContext context; context.Check("var x; x", 1, // access - 1, // declaration - 2, // declaration + initialization - EXPECT_RESULT, Undefined(CcTest::isolate())); + 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); } { AppearingPropertyContext context; context.Check("var x = 0; x", 1, // access - 2, // declaration + initialization - 2, // declaration + initialization - EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); + 1, // initialization + 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); } { AppearingPropertyContext context; @@ -463,78 +389,13 @@ TEST(Appearing) { { AppearingPropertyContext context; context.Check("const x; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); + 0, 0, EXPECT_RESULT, Undefined(CcTest::isolate())); } { AppearingPropertyContext context; context.Check("const x = 0; x", 1, // access - 2, // declaration + initialization - 1, // declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); - // Result is undefined because declaration succeeded but - // initialization to 0 failed (due to context behavior). - } -} - - - -class ReappearingPropertyContext: public DeclarationContext { - public: - enum State { - DECLARE, - DONT_DECLARE, - INITIALIZE, - UNKNOWN - }; - - ReappearingPropertyContext() : state_(DECLARE) { } - - protected: - virtual v8::Handle<Integer> Query(Local<String> key) { - switch (state_) { - case DECLARE: - // Force the first declaration by returning that - // the property is absent. - state_ = DONT_DECLARE; - return Handle<Integer>(); - case DONT_DECLARE: - // Ignore the second declaration by returning - // that the property is already there. - state_ = INITIALIZE; - return Integer::New(isolate(), v8::None); - case INITIALIZE: - // Force an initialization by returning that - // the property is absent. This will make sure - // that the setter is called and it will not - // lead to redeclaration conflicts (yet). - state_ = UNKNOWN; - return Handle<Integer>(); - default: - CHECK(state_ == UNKNOWN); - break; - } - // Do the lookup in the object. - return Handle<Integer>(); - } - - private: - State state_; -}; - - -TEST(Reappearing) { - v8::V8::Initialize(); - HandleScope scope(CcTest::isolate()); - - { ReappearingPropertyContext context; - context.Check("const x; var x = 0", - 0, - 3, // const declaration+initialization, var initialization - 3, // 2 x declaration + var initialization - EXPECT_RESULT, Undefined(CcTest::isolate())); + 0, 0, EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); } } @@ -562,11 +423,8 @@ TEST(ExistsInPrototype) { // Sanity check to make sure that the holder of the interceptor // really is the prototype object. { ExistsInPrototypeContext context; - context.Check("this.x = 87; this.x", - 0, - 0, - 0, - EXPECT_RESULT, Number::New(CcTest::isolate(), 87)); + context.Check("this.x = 87; this.x", 0, 0, 1, EXPECT_RESULT, + Number::New(CcTest::isolate(), 87)); } { ExistsInPrototypeContext context; @@ -669,19 +527,13 @@ TEST(ExistsInHiddenPrototype) { HandleScope scope(CcTest::isolate()); { ExistsInHiddenPrototypeContext context; - context.Check("var x; x", - 1, // access - 0, - 2, // declaration + initialization - EXPECT_EXCEPTION); // x is not defined! + context.Check("var x; x", 0, 0, 0, EXPECT_RESULT, + Undefined(CcTest::isolate())); } { ExistsInHiddenPrototypeContext context; - context.Check("var x = 0; x", - 1, // access - 1, // initialization - 2, // declaration + initialization - EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); + context.Check("var x = 0; x", 0, 0, 0, EXPECT_RESULT, + Number::New(CcTest::isolate(), 0)); } { ExistsInHiddenPrototypeContext context; @@ -694,20 +546,14 @@ TEST(ExistsInHiddenPrototype) { // TODO(mstarzinger): The semantics of global const is vague. { ExistsInHiddenPrototypeContext context; - context.Check("const x; x", - 0, - 0, - 1, // (re-)declaration - EXPECT_RESULT, Undefined(CcTest::isolate())); + context.Check("const x; x", 0, 0, 0, EXPECT_RESULT, + Undefined(CcTest::isolate())); } // TODO(mstarzinger): The semantics of global const is vague. { ExistsInHiddenPrototypeContext context; - context.Check("const x = 0; x", - 0, - 0, - 1, // (re-)declaration - EXPECT_RESULT, Number::New(CcTest::isolate(), 0)); + context.Check("const x = 0; x", 0, 0, 0, EXPECT_RESULT, + Number::New(CcTest::isolate(), 0)); } } @@ -768,10 +614,8 @@ TEST(CrossScriptReferences) { EXPECT_RESULT, Number::New(isolate, 1)); context.Check("var x = 2; x", EXPECT_RESULT, Number::New(isolate, 2)); - context.Check("const x = 3; x", - EXPECT_RESULT, Number::New(isolate, 3)); - context.Check("const x = 4; x", - EXPECT_RESULT, Number::New(isolate, 4)); + context.Check("const x = 3; x", EXPECT_EXCEPTION); + context.Check("const x = 4; x", EXPECT_EXCEPTION); context.Check("x = 5; x", EXPECT_RESULT, Number::New(isolate, 5)); context.Check("var x = 6; x", @@ -787,8 +631,7 @@ TEST(CrossScriptReferences) { EXPECT_RESULT, Number::New(isolate, 1)); context.Check("var x = 2; x", // assignment ignored EXPECT_RESULT, Number::New(isolate, 1)); - context.Check("const x = 3; x", - EXPECT_RESULT, Number::New(isolate, 1)); + context.Check("const x = 3; x", EXPECT_EXCEPTION); context.Check("x = 4; x", // assignment ignored EXPECT_RESULT, Number::New(isolate, 1)); context.Check("var x = 5; x", // assignment ignored diff --git a/deps/v8/test/cctest/test-deoptimization.cc b/deps/v8/test/cctest/test-deoptimization.cc index dbbb3edb09..3127acc6a6 100644 --- a/deps/v8/test/cctest/test-deoptimization.cc +++ b/deps/v8/test/cctest/test-deoptimization.cc @@ -27,23 +27,23 @@ #include <stdlib.h> -#include "v8.h" - -#include "api.h" -#include "cctest.h" -#include "compilation-cache.h" -#include "debug.h" -#include "deoptimizer.h" -#include "isolate.h" -#include "platform.h" -#include "stub-cache.h" - +#include "src/v8.h" + +#include "src/api.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/debug.h" +#include "src/deoptimizer.h" +#include "src/isolate.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" + +using ::v8::base::OS; using ::v8::internal::Deoptimizer; using ::v8::internal::EmbeddedVector; using ::v8::internal::Handle; using ::v8::internal::Isolate; using ::v8::internal::JSFunction; -using ::v8::internal::OS; using ::v8::internal::Object; // Size of temp buffer for formatting small strings. @@ -113,6 +113,8 @@ static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj, TEST(DeoptimizeSimple) { + i::FLAG_turbo_deoptimization = true; + LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -151,6 +153,8 @@ TEST(DeoptimizeSimple) { TEST(DeoptimizeSimpleWithArguments) { + i::FLAG_turbo_deoptimization = true; + LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -190,6 +194,8 @@ TEST(DeoptimizeSimpleWithArguments) { TEST(DeoptimizeSimpleNested) { + i::FLAG_turbo_deoptimization = true; + LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -215,6 +221,7 @@ TEST(DeoptimizeSimpleNested) { TEST(DeoptimizeRecursive) { + i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -242,6 +249,7 @@ TEST(DeoptimizeRecursive) { TEST(DeoptimizeMultiple) { + i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -270,6 +278,7 @@ TEST(DeoptimizeMultiple) { TEST(DeoptimizeConstructor) { + i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -308,6 +317,7 @@ TEST(DeoptimizeConstructor) { TEST(DeoptimizeConstructorMultiple) { + i::FLAG_turbo_deoptimization = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -337,6 +347,7 @@ TEST(DeoptimizeConstructorMultiple) { TEST(DeoptimizeBinaryOperationADDString) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; AllowNativesSyntaxNoInlining options; LocalContext env; @@ -397,9 +408,9 @@ static void CompileConstructorWithDeoptimizingValueOf() { static void TestDeoptimizeBinaryOpHelper(LocalContext* env, const char* binary_op) { EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer; - OS::SNPrintF(f_source_buffer, - "function f(x, y) { return x %s y; };", - binary_op); + SNPrintF(f_source_buffer, + "function f(x, y) { return x %s y; };", + binary_op); char* f_source = f_source_buffer.start(); AllowNativesSyntaxNoInlining options; @@ -428,6 +439,7 @@ static void TestDeoptimizeBinaryOpHelper(LocalContext* env, TEST(DeoptimizeBinaryOperationADD) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -441,6 +453,7 @@ TEST(DeoptimizeBinaryOperationADD) { TEST(DeoptimizeBinaryOperationSUB) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -454,6 +467,7 @@ TEST(DeoptimizeBinaryOperationSUB) { TEST(DeoptimizeBinaryOperationMUL) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -467,6 +481,7 @@ TEST(DeoptimizeBinaryOperationMUL) { TEST(DeoptimizeBinaryOperationDIV) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -480,6 +495,7 @@ TEST(DeoptimizeBinaryOperationDIV) { TEST(DeoptimizeBinaryOperationMOD) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -493,6 +509,7 @@ TEST(DeoptimizeBinaryOperationMOD) { TEST(DeoptimizeCompare) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -537,6 +554,7 @@ TEST(DeoptimizeCompare) { TEST(DeoptimizeLoadICStoreIC) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -617,6 +635,7 @@ TEST(DeoptimizeLoadICStoreIC) { TEST(DeoptimizeLoadICStoreICNested) { + i::FLAG_turbo_deoptimization = true; i::FLAG_concurrent_recompilation = false; LocalContext env; v8::HandleScope scope(env->GetIsolate()); diff --git a/deps/v8/test/cctest/test-dictionary.cc b/deps/v8/test/cctest/test-dictionary.cc index aa1bc86231..9a1914237f 100644 --- a/deps/v8/test/cctest/test-dictionary.cc +++ b/deps/v8/test/cctest/test-dictionary.cc @@ -25,16 +25,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "api.h" -#include "debug.h" -#include "execution.h" -#include "factory.h" -#include "macro-assembler.h" -#include "objects.h" -#include "global-handles.h" -#include "cctest.h" +#include "src/api.h" +#include "src/debug.h" +#include "src/execution.h" +#include "src/factory.h" +#include "src/global-handles.h" +#include "src/macro-assembler.h" +#include "src/objects.h" using namespace v8::internal; @@ -51,6 +51,7 @@ static void TestHashMap(Handle<HashMap> table) { table = HashMap::Put(table, a, b); CHECK_EQ(table->NumberOfElements(), 1); CHECK_EQ(table->Lookup(a), *b); + // When the key does not exist in the map, Lookup returns the hole. CHECK_EQ(table->Lookup(b), CcTest::heap()->the_hole_value()); // Keys still have to be valid after objects were moved. @@ -64,8 +65,10 @@ static void TestHashMap(Handle<HashMap> table) { CHECK_EQ(table->NumberOfElements(), 1); CHECK_NE(table->Lookup(a), *b); - // Keys mapped to the hole should be removed permanently. - table = HashMap::Put(table, a, factory->the_hole_value()); + // Keys that have been removed are mapped to the hole. + bool was_present = false; + table = HashMap::Remove(table, a, &was_present); + CHECK(was_present); CHECK_EQ(table->NumberOfElements(), 0); CHECK_EQ(table->Lookup(a), CcTest::heap()->the_hole_value()); @@ -187,7 +190,9 @@ static void TestHashSetCausesGC(Handle<HashSet> table) { CHECK(gc_count == isolate->heap()->gc_count()); // Calling Remove() will not cause GC in this case. - table = HashSet::Remove(table, key); + bool was_present = false; + table = HashSet::Remove(table, key, &was_present); + CHECK(!was_present); CHECK(gc_count == isolate->heap()->gc_count()); // Calling Add() should cause GC. diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc index 24453bc88e..c1f6ce2690 100644 --- a/deps/v8/test/cctest/test-disasm-arm.cc +++ b/deps/v8/test/cctest/test-disasm-arm.cc @@ -28,14 +28,14 @@ #include <stdlib.h> -#include "v8.h" - -#include "debug.h" -#include "disasm.h" -#include "disassembler.h" -#include "macro-assembler.h" -#include "serialize.h" -#include "cctest.h" +#include "src/v8.h" + +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-arm64.cc b/deps/v8/test/cctest/test-disasm-arm64.cc index 23f7b6daf2..fb01347c6a 100644 --- a/deps/v8/test/cctest/test-disasm-arm64.cc +++ b/deps/v8/test/cctest/test-disasm-arm64.cc @@ -27,16 +27,17 @@ #include <stdio.h> #include <cstring> -#include "cctest.h" -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "macro-assembler.h" -#include "arm64/assembler-arm64.h" -#include "arm64/macro-assembler-arm64.h" -#include "arm64/decoder-arm64-inl.h" -#include "arm64/disasm-arm64.h" -#include "arm64/utils-arm64.h" +#include "src/macro-assembler.h" + +#include "src/arm64/assembler-arm64.h" +#include "src/arm64/decoder-arm64-inl.h" +#include "src/arm64/disasm-arm64.h" +#include "src/arm64/macro-assembler-arm64.h" +#include "src/arm64/utils-arm64.h" using namespace v8::internal; @@ -1601,7 +1602,7 @@ TEST_(system_nop) { TEST_(debug) { SET_UP(); - ASSERT(kImmExceptionIsDebug == 0xdeb0); + DCHECK(kImmExceptionIsDebug == 0xdeb0); // All debug codes should produce the same instruction, and the debug code // can be any uint32_t. diff --git a/deps/v8/test/cctest/test-disasm-ia32.cc b/deps/v8/test/cctest/test-disasm-ia32.cc index 6972aeabad..8436df7c5a 100644 --- a/deps/v8/test/cctest/test-disasm-ia32.cc +++ b/deps/v8/test/cctest/test-disasm-ia32.cc @@ -27,15 +27,15 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "debug.h" -#include "disasm.h" -#include "disassembler.h" -#include "macro-assembler.h" -#include "serialize.h" -#include "stub-cache.h" -#include "cctest.h" +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -168,6 +168,11 @@ TEST(DisasmIa320) { __ nop(); __ idiv(edx); + __ idiv(Operand(edx, ecx, times_1, 1)); + __ idiv(Operand(esp, 12)); + __ div(edx); + __ div(Operand(edx, ecx, times_1, 1)); + __ div(Operand(esp, 12)); __ mul(edx); __ neg(edx); __ not_(edx); @@ -175,7 +180,9 @@ TEST(DisasmIa320) { __ imul(edx, Operand(ebx, ecx, times_4, 10000)); __ imul(edx, ecx, 12); + __ imul(edx, Operand(edx, eax, times_2, 42), 8); __ imul(edx, ecx, 1000); + __ imul(edx, Operand(ebx, ecx, times_4, 1), 9000); __ inc(edx); __ inc(Operand(ebx, ecx, times_4, 10000)); @@ -197,15 +204,24 @@ TEST(DisasmIa320) { __ sar(edx, 1); __ sar(edx, 6); __ sar_cl(edx); + __ sar(Operand(ebx, ecx, times_4, 10000), 1); + __ sar(Operand(ebx, ecx, times_4, 10000), 6); + __ sar_cl(Operand(ebx, ecx, times_4, 10000)); __ sbb(edx, Operand(ebx, ecx, times_4, 10000)); __ shld(edx, Operand(ebx, ecx, times_4, 10000)); __ shl(edx, 1); __ shl(edx, 6); __ shl_cl(edx); + __ shl(Operand(ebx, ecx, times_4, 10000), 1); + __ shl(Operand(ebx, ecx, times_4, 10000), 6); + __ shl_cl(Operand(ebx, ecx, times_4, 10000)); __ shrd(edx, Operand(ebx, ecx, times_4, 10000)); __ shr(edx, 1); __ shr(edx, 7); __ shr_cl(edx); + __ shr(Operand(ebx, ecx, times_4, 10000), 1); + __ shr(Operand(ebx, ecx, times_4, 10000), 6); + __ shr_cl(Operand(ebx, ecx, times_4, 10000)); // Immediates @@ -275,7 +291,7 @@ TEST(DisasmIa320) { __ jmp(&L1); __ jmp(Operand(ebx, ecx, times_4, 10000)); ExternalReference after_break_target = - ExternalReference(Debug_Address::AfterBreakTarget(), isolate); + ExternalReference::debug_after_break_target_address(isolate); __ jmp(Operand::StaticVariable(after_break_target)); __ jmp(ic, RelocInfo::CODE_TARGET); __ nop(); @@ -364,86 +380,76 @@ TEST(DisasmIa320) { // SSE instruction { - if (CpuFeatures::IsSupported(SSE2)) { - CpuFeatureScope fscope(&assm, SSE2); - // Move operation - __ movaps(xmm0, xmm1); - __ shufps(xmm0, xmm0, 0x0); - - // logic operation - __ andps(xmm0, xmm1); - __ andps(xmm0, Operand(ebx, ecx, times_4, 10000)); - __ orps(xmm0, xmm1); - __ orps(xmm0, Operand(ebx, ecx, times_4, 10000)); - __ xorps(xmm0, xmm1); - __ xorps(xmm0, Operand(ebx, ecx, times_4, 10000)); - - // Arithmetic operation - __ addps(xmm1, xmm0); - __ addps(xmm1, Operand(ebx, ecx, times_4, 10000)); - __ subps(xmm1, xmm0); - __ subps(xmm1, Operand(ebx, ecx, times_4, 10000)); - __ mulps(xmm1, xmm0); - __ mulps(xmm1, Operand(ebx, ecx, times_4, 10000)); - __ divps(xmm1, xmm0); - __ divps(xmm1, Operand(ebx, ecx, times_4, 10000)); - } + // Move operation + __ movaps(xmm0, xmm1); + __ shufps(xmm0, xmm0, 0x0); + + // logic operation + __ andps(xmm0, xmm1); + __ andps(xmm0, Operand(ebx, ecx, times_4, 10000)); + __ orps(xmm0, xmm1); + __ orps(xmm0, Operand(ebx, ecx, times_4, 10000)); + __ xorps(xmm0, xmm1); + __ xorps(xmm0, Operand(ebx, ecx, times_4, 10000)); + + // Arithmetic operation + __ addps(xmm1, xmm0); + __ addps(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ subps(xmm1, xmm0); + __ subps(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ mulps(xmm1, xmm0); + __ mulps(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ divps(xmm1, xmm0); + __ divps(xmm1, Operand(ebx, ecx, times_4, 10000)); } { - if (CpuFeatures::IsSupported(SSE2)) { - CpuFeatureScope fscope(&assm, SSE2); - __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000)); - __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000)); - __ movsd(xmm1, Operand(ebx, ecx, times_4, 10000)); - __ movsd(Operand(ebx, ecx, times_4, 10000), xmm1); - // 128 bit move instructions. - __ movdqa(xmm0, Operand(ebx, ecx, times_4, 10000)); - __ movdqa(Operand(ebx, ecx, times_4, 10000), xmm0); - __ movdqu(xmm0, Operand(ebx, ecx, times_4, 10000)); - __ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0); - - __ addsd(xmm1, xmm0); - __ mulsd(xmm1, xmm0); - __ subsd(xmm1, xmm0); - __ divsd(xmm1, xmm0); - __ ucomisd(xmm0, xmm1); - __ cmpltsd(xmm0, xmm1); - - __ andpd(xmm0, xmm1); - __ psllq(xmm0, 17); - __ psllq(xmm0, xmm1); - __ psrlq(xmm0, 17); - __ psrlq(xmm0, xmm1); - __ por(xmm0, xmm1); - } + __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000)); + __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ movsd(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ movsd(Operand(ebx, ecx, times_4, 10000), xmm1); + // 128 bit move instructions. + __ movdqa(xmm0, Operand(ebx, ecx, times_4, 10000)); + __ movdqa(Operand(ebx, ecx, times_4, 10000), xmm0); + __ movdqu(xmm0, Operand(ebx, ecx, times_4, 10000)); + __ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0); + + __ addsd(xmm1, xmm0); + __ mulsd(xmm1, xmm0); + __ subsd(xmm1, xmm0); + __ divsd(xmm1, xmm0); + __ ucomisd(xmm0, xmm1); + __ cmpltsd(xmm0, xmm1); + + __ andpd(xmm0, xmm1); + __ psllq(xmm0, 17); + __ psllq(xmm0, xmm1); + __ psrlq(xmm0, 17); + __ psrlq(xmm0, xmm1); + __ por(xmm0, xmm1); } // cmov. { - if (CpuFeatures::IsSupported(CMOV)) { - CpuFeatureScope use_cmov(&assm, CMOV); - __ cmov(overflow, eax, Operand(eax, 0)); - __ cmov(no_overflow, eax, Operand(eax, 1)); - __ cmov(below, eax, Operand(eax, 2)); - __ cmov(above_equal, eax, Operand(eax, 3)); - __ cmov(equal, eax, Operand(ebx, 0)); - __ cmov(not_equal, eax, Operand(ebx, 1)); - __ cmov(below_equal, eax, Operand(ebx, 2)); - __ cmov(above, eax, Operand(ebx, 3)); - __ cmov(sign, eax, Operand(ecx, 0)); - __ cmov(not_sign, eax, Operand(ecx, 1)); - __ cmov(parity_even, eax, Operand(ecx, 2)); - __ cmov(parity_odd, eax, Operand(ecx, 3)); - __ cmov(less, eax, Operand(edx, 0)); - __ cmov(greater_equal, eax, Operand(edx, 1)); - __ cmov(less_equal, eax, Operand(edx, 2)); - __ cmov(greater, eax, Operand(edx, 3)); - } + __ cmov(overflow, eax, Operand(eax, 0)); + __ cmov(no_overflow, eax, Operand(eax, 1)); + __ cmov(below, eax, Operand(eax, 2)); + __ cmov(above_equal, eax, Operand(eax, 3)); + __ cmov(equal, eax, Operand(ebx, 0)); + __ cmov(not_equal, eax, Operand(ebx, 1)); + __ cmov(below_equal, eax, Operand(ebx, 2)); + __ cmov(above, eax, Operand(ebx, 3)); + __ cmov(sign, eax, Operand(ecx, 0)); + __ cmov(not_sign, eax, Operand(ecx, 1)); + __ cmov(parity_even, eax, Operand(ecx, 2)); + __ cmov(parity_odd, eax, Operand(ecx, 3)); + __ cmov(less, eax, Operand(edx, 0)); + __ cmov(greater_equal, eax, Operand(edx, 1)); + __ cmov(less_equal, eax, Operand(edx, 2)); + __ cmov(greater, eax, Operand(edx, 3)); } { - if (CpuFeatures::IsSupported(SSE2) && - CpuFeatures::IsSupported(SSE4_1)) { + if (CpuFeatures::IsSupported(SSE4_1)) { CpuFeatureScope scope(&assm, SSE4_1); __ pextrd(eax, xmm0, 1); __ pinsrd(xmm1, eax, 0); @@ -451,6 +457,14 @@ TEST(DisasmIa320) { } } + // xchg. + { + __ xchg(eax, eax); + __ xchg(eax, ebx); + __ xchg(ebx, ebx); + __ xchg(ebx, Operand(esp, 12)); + } + // Nop instructions for (int i = 0; i < 16; i++) { __ Nop(i); @@ -464,7 +478,8 @@ TEST(DisasmIa320) { desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); USE(code); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); byte* begin = code->instruction_start(); byte* end = begin + code->instruction_size(); disasm::Disassembler::Disassemble(stdout, begin, end); diff --git a/deps/v8/test/cctest/test-disasm-mips.cc b/deps/v8/test/cctest/test-disasm-mips.cc index 725b3a5674..cfd861e241 100644 --- a/deps/v8/test/cctest/test-disasm-mips.cc +++ b/deps/v8/test/cctest/test-disasm-mips.cc @@ -28,14 +28,14 @@ #include <stdlib.h> -#include "v8.h" - -#include "debug.h" -#include "disasm.h" -#include "disassembler.h" -#include "macro-assembler.h" -#include "serialize.h" -#include "cctest.h" +#include "src/v8.h" + +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-mips64.cc b/deps/v8/test/cctest/test-disasm-mips64.cc new file mode 100644 index 0000000000..d682d33480 --- /dev/null +++ b/deps/v8/test/cctest/test-disasm-mips64.cc @@ -0,0 +1,674 @@ +// Copyright 2012 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. +// + +#include <stdlib.h> + +#include "src/v8.h" + +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +bool DisassembleAndCompare(byte* pc, const char* compare_string) { + disasm::NameConverter converter; + disasm::Disassembler disasm(converter); + EmbeddedVector<char, 128> disasm_buffer; + + disasm.InstructionDecode(disasm_buffer, pc); + + if (strcmp(compare_string, disasm_buffer.start()) != 0) { + fprintf(stderr, + "expected: \n" + "%s\n" + "disassembled: \n" + "%s\n\n", + compare_string, disasm_buffer.start()); + return false; + } + return true; +} + + +// Set up V8 to a state where we can at least run the assembler and +// disassembler. Declare the variables and allocate the data structures used +// in the rest of the macros. +#define SET_UP() \ + CcTest::InitializeVM(); \ + Isolate* isolate = CcTest::i_isolate(); \ + HandleScope scope(isolate); \ + byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \ + Assembler assm(isolate, buffer, 4*1024); \ + bool failure = false; + + +// This macro assembles one instruction using the preallocated assembler and +// disassembles the generated instruction, comparing the output to the expected +// value. If the comparison fails an error message is printed, but the test +// continues to run until the end. +#define COMPARE(asm_, compare_string) \ + { \ + int pc_offset = assm.pc_offset(); \ + byte *progcounter = &buffer[pc_offset]; \ + assm.asm_; \ + if (!DisassembleAndCompare(progcounter, compare_string)) failure = true; \ + } + + +// Verify that all invocations of the COMPARE macro passed successfully. +// Exit with a failure if at least one of the tests failed. +#define VERIFY_RUN() \ +if (failure) { \ + V8_Fatal(__FILE__, __LINE__, "MIPS Disassembler tests failed.\n"); \ + } + + +TEST(Type0) { + SET_UP(); + + COMPARE(addu(a0, a1, a2), + "00a62021 addu a0, a1, a2"); + COMPARE(daddu(a0, a1, a2), + "00a6202d daddu a0, a1, a2"); + COMPARE(addu(a6, a7, t0), + "016c5021 addu a6, a7, t0"); + COMPARE(daddu(a6, a7, t0), + "016c502d daddu a6, a7, t0"); + COMPARE(addu(v0, v1, s0), + "00701021 addu v0, v1, s0"); + COMPARE(daddu(v0, v1, s0), + "0070102d daddu v0, v1, s0"); + + COMPARE(subu(a0, a1, a2), + "00a62023 subu a0, a1, a2"); + COMPARE(dsubu(a0, a1, a2), + "00a6202f dsubu a0, a1, a2"); + COMPARE(subu(a6, a7, t0), + "016c5023 subu a6, a7, t0"); + COMPARE(dsubu(a6, a7, t0), + "016c502f dsubu a6, a7, t0"); + COMPARE(subu(v0, v1, s0), + "00701023 subu v0, v1, s0"); + COMPARE(dsubu(v0, v1, s0), + "0070102f dsubu v0, v1, s0"); + + if (kArchVariant != kMips64r6) { + COMPARE(mult(a0, a1), + "00850018 mult a0, a1"); + COMPARE(dmult(a0, a1), + "0085001c dmult a0, a1"); + COMPARE(mult(a6, a7), + "014b0018 mult a6, a7"); + COMPARE(dmult(a6, a7), + "014b001c dmult a6, a7"); + COMPARE(mult(v0, v1), + "00430018 mult v0, v1"); + COMPARE(dmult(v0, v1), + "0043001c dmult v0, v1"); + + COMPARE(multu(a0, a1), + "00850019 multu a0, a1"); + COMPARE(dmultu(a0, a1), + "0085001d dmultu a0, a1"); + COMPARE(multu(a6, a7), + "014b0019 multu a6, a7"); + COMPARE(dmultu(a6, a7), + "014b001d dmultu a6, a7"); + COMPARE(multu(v0, v1), + "00430019 multu v0, v1"); + COMPARE(dmultu(v0, v1), + "0043001d dmultu v0, v1"); + + COMPARE(div(a0, a1), + "0085001a div a0, a1"); + COMPARE(div(a6, a7), + "014b001a div a6, a7"); + COMPARE(div(v0, v1), + "0043001a div v0, v1"); + COMPARE(ddiv(a0, a1), + "0085001e ddiv a0, a1"); + COMPARE(ddiv(a6, a7), + "014b001e ddiv a6, a7"); + COMPARE(ddiv(v0, v1), + "0043001e ddiv v0, v1"); + + COMPARE(divu(a0, a1), + "0085001b divu a0, a1"); + COMPARE(divu(a6, a7), + "014b001b divu a6, a7"); + COMPARE(divu(v0, v1), + "0043001b divu v0, v1"); + COMPARE(ddivu(a0, a1), + "0085001f ddivu a0, a1"); + COMPARE(ddivu(a6, a7), + "014b001f ddivu a6, a7"); + COMPARE(ddivu(v0, v1), + "0043001f ddivu v0, v1"); + COMPARE(mul(a0, a1, a2), + "70a62002 mul a0, a1, a2"); + COMPARE(mul(a6, a7, t0), + "716c5002 mul a6, a7, t0"); + COMPARE(mul(v0, v1, s0), + "70701002 mul v0, v1, s0"); + } else { // MIPS64r6. + COMPARE(mul(a0, a1, a2), + "00a62098 mul a0, a1, a2"); + COMPARE(muh(a0, a1, a2), + "00a620d8 muh a0, a1, a2"); + COMPARE(dmul(a0, a1, a2), + "00a6209c dmul a0, a1, a2"); + COMPARE(dmuh(a0, a1, a2), + "00a620dc dmuh a0, a1, a2"); + COMPARE(mul(a5, a6, a7), + "014b4898 mul a5, a6, a7"); + COMPARE(muh(a5, a6, a7), + "014b48d8 muh a5, a6, a7"); + COMPARE(dmul(a5, a6, a7), + "014b489c dmul a5, a6, a7"); + COMPARE(dmuh(a5, a6, a7), + "014b48dc dmuh a5, a6, a7"); + COMPARE(mul(v0, v1, a0), + "00641098 mul v0, v1, a0"); + COMPARE(muh(v0, v1, a0), + "006410d8 muh v0, v1, a0"); + COMPARE(dmul(v0, v1, a0), + "0064109c dmul v0, v1, a0"); + COMPARE(dmuh(v0, v1, a0), + "006410dc dmuh v0, v1, a0"); + + COMPARE(mulu(a0, a1, a2), + "00a62099 mulu a0, a1, a2"); + COMPARE(muhu(a0, a1, a2), + "00a620d9 muhu a0, a1, a2"); + COMPARE(dmulu(a0, a1, a2), + "00a6209d dmulu a0, a1, a2"); + COMPARE(dmuhu(a0, a1, a2), + "00a620dd dmuhu a0, a1, a2"); + COMPARE(mulu(a5, a6, a7), + "014b4899 mulu a5, a6, a7"); + COMPARE(muhu(a5, a6, a7), + "014b48d9 muhu a5, a6, a7"); + COMPARE(dmulu(a5, a6, a7), + "014b489d dmulu a5, a6, a7"); + COMPARE(dmuhu(a5, a6, a7), + "014b48dd dmuhu a5, a6, a7"); + COMPARE(mulu(v0, v1, a0), + "00641099 mulu v0, v1, a0"); + COMPARE(muhu(v0, v1, a0), + "006410d9 muhu v0, v1, a0"); + COMPARE(dmulu(v0, v1, a0), + "0064109d dmulu v0, v1, a0"); + COMPARE(dmuhu(v0, v1, a0), + "006410dd dmuhu v0, v1, a0"); + + COMPARE(div(a0, a1, a2), + "00a6209a div a0, a1, a2"); + COMPARE(mod(a0, a1, a2), + "00a620da mod a0, a1, a2"); + COMPARE(ddiv(a0, a1, a2), + "00a6209e ddiv a0, a1, a2"); + COMPARE(dmod(a0, a1, a2), + "00a620de dmod a0, a1, a2"); + COMPARE(div(a5, a6, a7), + "014b489a div a5, a6, a7"); + COMPARE(mod(a5, a6, a7), + "014b48da mod a5, a6, a7"); + COMPARE(ddiv(a5, a6, a7), + "014b489e ddiv a5, a6, a7"); + COMPARE(dmod(a5, a6, a7), + "014b48de dmod a5, a6, a7"); + COMPARE(div(v0, v1, a0), + "0064109a div v0, v1, a0"); + COMPARE(mod(v0, v1, a0), + "006410da mod v0, v1, a0"); + COMPARE(ddiv(v0, v1, a0), + "0064109e ddiv v0, v1, a0"); + COMPARE(dmod(v0, v1, a0), + "006410de dmod v0, v1, a0"); + + COMPARE(divu(a0, a1, a2), + "00a6209b divu a0, a1, a2"); + COMPARE(modu(a0, a1, a2), + "00a620db modu a0, a1, a2"); + COMPARE(ddivu(a0, a1, a2), + "00a6209f ddivu a0, a1, a2"); + COMPARE(dmodu(a0, a1, a2), + "00a620df dmodu a0, a1, a2"); + COMPARE(divu(a5, a6, a7), + "014b489b divu a5, a6, a7"); + COMPARE(modu(a5, a6, a7), + "014b48db modu a5, a6, a7"); + COMPARE(ddivu(a5, a6, a7), + "014b489f ddivu a5, a6, a7"); + COMPARE(dmodu(a5, a6, a7), + "014b48df dmodu a5, a6, a7"); + COMPARE(divu(v0, v1, a0), + "0064109b divu v0, v1, a0"); + COMPARE(modu(v0, v1, a0), + "006410db modu v0, v1, a0"); + COMPARE(ddivu(v0, v1, a0), + "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), + "24a40000 addiu a0, a1, 0"); + COMPARE(addiu(s0, s1, 32767), + "26307fff addiu s0, s1, 32767"); + COMPARE(addiu(a6, a7, -32768), + "256a8000 addiu a6, a7, -32768"); + COMPARE(addiu(v0, v1, -1), + "2462ffff addiu v0, v1, -1"); + COMPARE(daddiu(a0, a1, 0x0), + "64a40000 daddiu a0, a1, 0"); + COMPARE(daddiu(s0, s1, 32767), + "66307fff daddiu s0, s1, 32767"); + COMPARE(daddiu(a6, a7, -32768), + "656a8000 daddiu a6, a7, -32768"); + COMPARE(daddiu(v0, v1, -1), + "6462ffff daddiu v0, v1, -1"); + + COMPARE(and_(a0, a1, a2), + "00a62024 and a0, a1, a2"); + COMPARE(and_(s0, s1, s2), + "02328024 and s0, s1, s2"); + COMPARE(and_(a6, a7, t0), + "016c5024 and a6, a7, t0"); + COMPARE(and_(v0, v1, a2), + "00661024 and v0, v1, a2"); + + COMPARE(or_(a0, a1, a2), + "00a62025 or a0, a1, a2"); + COMPARE(or_(s0, s1, s2), + "02328025 or s0, s1, s2"); + COMPARE(or_(a6, a7, t0), + "016c5025 or a6, a7, t0"); + COMPARE(or_(v0, v1, a2), + "00661025 or v0, v1, a2"); + + COMPARE(xor_(a0, a1, a2), + "00a62026 xor a0, a1, a2"); + COMPARE(xor_(s0, s1, s2), + "02328026 xor s0, s1, s2"); + COMPARE(xor_(a6, a7, t0), + "016c5026 xor a6, a7, t0"); + COMPARE(xor_(v0, v1, a2), + "00661026 xor v0, v1, a2"); + + COMPARE(nor(a0, a1, a2), + "00a62027 nor a0, a1, a2"); + COMPARE(nor(s0, s1, s2), + "02328027 nor s0, s1, s2"); + COMPARE(nor(a6, a7, t0), + "016c5027 nor a6, a7, t0"); + COMPARE(nor(v0, v1, a2), + "00661027 nor v0, v1, a2"); + + COMPARE(andi(a0, a1, 0x1), + "30a40001 andi a0, a1, 0x1"); + COMPARE(andi(v0, v1, 0xffff), + "3062ffff andi v0, v1, 0xffff"); + + COMPARE(ori(a0, a1, 0x1), + "34a40001 ori a0, a1, 0x1"); + COMPARE(ori(v0, v1, 0xffff), + "3462ffff ori v0, v1, 0xffff"); + + COMPARE(xori(a0, a1, 0x1), + "38a40001 xori a0, a1, 0x1"); + COMPARE(xori(v0, v1, 0xffff), + "3862ffff xori v0, v1, 0xffff"); + + COMPARE(lui(a0, 0x1), + "3c040001 lui a0, 0x1"); + COMPARE(lui(v0, 0xffff), + "3c02ffff lui v0, 0xffff"); + + COMPARE(sll(a0, a1, 0), + "00052000 sll a0, a1, 0"); + COMPARE(sll(s0, s1, 8), + "00118200 sll s0, s1, 8"); + COMPARE(sll(a6, a7, 24), + "000b5600 sll a6, a7, 24"); + COMPARE(sll(v0, v1, 31), + "000317c0 sll v0, v1, 31"); + COMPARE(dsll(a0, a1, 0), + "00052038 dsll a0, a1, 0"); + COMPARE(dsll(s0, s1, 8), + "00118238 dsll s0, s1, 8"); + COMPARE(dsll(a6, a7, 24), + "000b5638 dsll a6, a7, 24"); + COMPARE(dsll(v0, v1, 31), + "000317f8 dsll v0, v1, 31"); + + COMPARE(sllv(a0, a1, a2), + "00c52004 sllv a0, a1, a2"); + COMPARE(sllv(s0, s1, s2), + "02518004 sllv s0, s1, s2"); + COMPARE(sllv(a6, a7, t0), + "018b5004 sllv a6, a7, t0"); + COMPARE(sllv(v0, v1, fp), + "03c31004 sllv v0, v1, fp"); + COMPARE(dsllv(a0, a1, a2), + "00c52014 dsllv a0, a1, a2"); + COMPARE(dsllv(s0, s1, s2), + "02518014 dsllv s0, s1, s2"); + COMPARE(dsllv(a6, a7, t0), + "018b5014 dsllv a6, a7, t0"); + COMPARE(dsllv(v0, v1, fp), + "03c31014 dsllv v0, v1, fp"); + + COMPARE(srl(a0, a1, 0), + "00052002 srl a0, a1, 0"); + COMPARE(srl(s0, s1, 8), + "00118202 srl s0, s1, 8"); + COMPARE(srl(a6, a7, 24), + "000b5602 srl a6, a7, 24"); + COMPARE(srl(v0, v1, 31), + "000317c2 srl v0, v1, 31"); + COMPARE(dsrl(a0, a1, 0), + "0005203a dsrl a0, a1, 0"); + COMPARE(dsrl(s0, s1, 8), + "0011823a dsrl s0, s1, 8"); + COMPARE(dsrl(a6, a7, 24), + "000b563a dsrl a6, a7, 24"); + COMPARE(dsrl(v0, v1, 31), + "000317fa dsrl v0, v1, 31"); + + COMPARE(srlv(a0, a1, a2), + "00c52006 srlv a0, a1, a2"); + COMPARE(srlv(s0, s1, s2), + "02518006 srlv s0, s1, s2"); + COMPARE(srlv(a6, a7, t0), + "018b5006 srlv a6, a7, t0"); + COMPARE(srlv(v0, v1, fp), + "03c31006 srlv v0, v1, fp"); + COMPARE(dsrlv(a0, a1, a2), + "00c52016 dsrlv a0, a1, a2"); + COMPARE(dsrlv(s0, s1, s2), + "02518016 dsrlv s0, s1, s2"); + COMPARE(dsrlv(a6, a7, t0), + "018b5016 dsrlv a6, a7, t0"); + COMPARE(dsrlv(v0, v1, fp), + "03c31016 dsrlv v0, v1, fp"); + + COMPARE(sra(a0, a1, 0), + "00052003 sra a0, a1, 0"); + COMPARE(sra(s0, s1, 8), + "00118203 sra s0, s1, 8"); + COMPARE(sra(a6, a7, 24), + "000b5603 sra a6, a7, 24"); + COMPARE(sra(v0, v1, 31), + "000317c3 sra v0, v1, 31"); + COMPARE(dsra(a0, a1, 0), + "0005203b dsra a0, a1, 0"); + COMPARE(dsra(s0, s1, 8), + "0011823b dsra s0, s1, 8"); + COMPARE(dsra(a6, a7, 24), + "000b563b dsra a6, a7, 24"); + COMPARE(dsra(v0, v1, 31), + "000317fb dsra v0, v1, 31"); + + COMPARE(srav(a0, a1, a2), + "00c52007 srav a0, a1, a2"); + COMPARE(srav(s0, s1, s2), + "02518007 srav s0, s1, s2"); + COMPARE(srav(a6, a7, t0), + "018b5007 srav a6, a7, t0"); + COMPARE(srav(v0, v1, fp), + "03c31007 srav v0, v1, fp"); + COMPARE(dsrav(a0, a1, a2), + "00c52017 dsrav a0, a1, a2"); + COMPARE(dsrav(s0, s1, s2), + "02518017 dsrav s0, s1, s2"); + COMPARE(dsrav(a6, a7, t0), + "018b5017 dsrav a6, a7, t0"); + COMPARE(dsrav(v0, v1, fp), + "03c31017 dsrav v0, v1, fp"); + + if (kArchVariant == kMips64r2) { + COMPARE(rotr(a0, a1, 0), + "00252002 rotr a0, a1, 0"); + COMPARE(rotr(s0, s1, 8), + "00318202 rotr s0, s1, 8"); + COMPARE(rotr(a6, a7, 24), + "002b5602 rotr a6, a7, 24"); + COMPARE(rotr(v0, v1, 31), + "002317c2 rotr v0, v1, 31"); + COMPARE(drotr(a0, a1, 0), + "0025203a drotr a0, a1, 0"); + COMPARE(drotr(s0, s1, 8), + "0031823a drotr s0, s1, 8"); + COMPARE(drotr(a6, a7, 24), + "002b563a drotr a6, a7, 24"); + COMPARE(drotr(v0, v1, 31), + "002317fa drotr v0, v1, 31"); + + COMPARE(rotrv(a0, a1, a2), + "00c52046 rotrv a0, a1, a2"); + COMPARE(rotrv(s0, s1, s2), + "02518046 rotrv s0, s1, s2"); + COMPARE(rotrv(a6, a7, t0), + "018b5046 rotrv a6, a7, t0"); + COMPARE(rotrv(v0, v1, fp), + "03c31046 rotrv v0, v1, fp"); + COMPARE(drotrv(a0, a1, a2), + "00c52056 drotrv a0, a1, a2"); + COMPARE(drotrv(s0, s1, s2), + "02518056 drotrv s0, s1, s2"); + COMPARE(drotrv(a6, a7, t0), + "018b5056 drotrv a6, a7, t0"); + COMPARE(drotrv(v0, v1, fp), + "03c31056 drotrv v0, v1, fp"); + } + + COMPARE(break_(0), + "0000000d break, code: 0x00000 (0)"); + COMPARE(break_(261120), + "00ff000d break, code: 0x3fc00 (261120)"); + COMPARE(break_(1047552), + "03ff000d break, code: 0xffc00 (1047552)"); + + COMPARE(tge(a0, a1, 0), + "00850030 tge a0, a1, code: 0x000"); + COMPARE(tge(s0, s1, 1023), + "0211fff0 tge s0, s1, code: 0x3ff"); + COMPARE(tgeu(a0, a1, 0), + "00850031 tgeu a0, a1, code: 0x000"); + COMPARE(tgeu(s0, s1, 1023), + "0211fff1 tgeu s0, s1, code: 0x3ff"); + COMPARE(tlt(a0, a1, 0), + "00850032 tlt a0, a1, code: 0x000"); + COMPARE(tlt(s0, s1, 1023), + "0211fff2 tlt s0, s1, code: 0x3ff"); + COMPARE(tltu(a0, a1, 0), + "00850033 tltu a0, a1, code: 0x000"); + COMPARE(tltu(s0, s1, 1023), + "0211fff3 tltu s0, s1, code: 0x3ff"); + COMPARE(teq(a0, a1, 0), + "00850034 teq a0, a1, code: 0x000"); + COMPARE(teq(s0, s1, 1023), + "0211fff4 teq s0, s1, code: 0x3ff"); + COMPARE(tne(a0, a1, 0), + "00850036 tne a0, a1, code: 0x000"); + COMPARE(tne(s0, s1, 1023), + "0211fff6 tne s0, s1, code: 0x3ff"); + + COMPARE(mfhi(a0), + "00002010 mfhi a0"); + COMPARE(mfhi(s2), + "00009010 mfhi s2"); + COMPARE(mfhi(t0), + "00006010 mfhi t0"); + COMPARE(mfhi(v1), + "00001810 mfhi v1"); + COMPARE(mflo(a0), + "00002012 mflo a0"); + COMPARE(mflo(s2), + "00009012 mflo s2"); + COMPARE(mflo(t0), + "00006012 mflo t0"); + COMPARE(mflo(v1), + "00001812 mflo v1"); + + COMPARE(slt(a0, a1, a2), + "00a6202a slt a0, a1, a2"); + COMPARE(slt(s0, s1, s2), + "0232802a slt s0, s1, s2"); + COMPARE(slt(a6, a7, t0), + "016c502a slt a6, a7, t0"); + COMPARE(slt(v0, v1, a2), + "0066102a slt v0, v1, a2"); + COMPARE(sltu(a0, a1, a2), + "00a6202b sltu a0, a1, a2"); + COMPARE(sltu(s0, s1, s2), + "0232802b sltu s0, s1, s2"); + COMPARE(sltu(a6, a7, t0), + "016c502b sltu a6, a7, t0"); + COMPARE(sltu(v0, v1, a2), + "0066102b sltu v0, v1, a2"); + + COMPARE(slti(a0, a1, 0), + "28a40000 slti a0, a1, 0"); + COMPARE(slti(s0, s1, 32767), + "2a307fff slti s0, s1, 32767"); + COMPARE(slti(a6, a7, -32768), + "296a8000 slti a6, a7, -32768"); + COMPARE(slti(v0, v1, -1), + "2862ffff slti v0, v1, -1"); + COMPARE(sltiu(a0, a1, 0), + "2ca40000 sltiu a0, a1, 0"); + COMPARE(sltiu(s0, s1, 32767), + "2e307fff sltiu s0, s1, 32767"); + COMPARE(sltiu(a6, a7, -32768), + "2d6a8000 sltiu a6, a7, -32768"); + COMPARE(sltiu(v0, v1, -1), + "2c62ffff sltiu v0, v1, -1"); + COMPARE(movz(a0, a1, a2), + "00a6200a movz a0, a1, a2"); + COMPARE(movz(s0, s1, s2), + "0232800a movz s0, s1, s2"); + COMPARE(movz(a6, a7, t0), + "016c500a movz a6, a7, t0"); + COMPARE(movz(v0, v1, a2), + "0066100a movz v0, v1, a2"); + COMPARE(movn(a0, a1, a2), + "00a6200b movn a0, a1, a2"); + COMPARE(movn(s0, s1, s2), + "0232800b movn s0, s1, s2"); + COMPARE(movn(a6, a7, t0), + "016c500b movn a6, a7, t0"); + COMPARE(movn(v0, v1, a2), + "0066100b movn v0, v1, a2"); + + COMPARE(movt(a0, a1, 1), + "00a52001 movt a0, a1, 1"); + COMPARE(movt(s0, s1, 2), + "02298001 movt s0, s1, 2"); + COMPARE(movt(a6, a7, 3), + "016d5001 movt a6, a7, 3"); + COMPARE(movt(v0, v1, 7), + "007d1001 movt v0, v1, 7"); + COMPARE(movf(a0, a1, 0), + "00a02001 movf a0, a1, 0"); + COMPARE(movf(s0, s1, 4), + "02308001 movf s0, s1, 4"); + COMPARE(movf(a6, a7, 5), + "01745001 movf a6, a7, 5"); + COMPARE(movf(v0, v1, 6), + "00781001 movf v0, v1, 6"); + + if (kArchVariant == kMips64r6) { + COMPARE(clz(a0, a1), + "00a02050 clz a0, a1"); + COMPARE(clz(s6, s7), + "02e0b050 clz s6, s7"); + COMPARE(clz(v0, v1), + "00601050 clz v0, v1"); + } else { + COMPARE(clz(a0, a1), + "70a42020 clz a0, a1"); + COMPARE(clz(s6, s7), + "72f6b020 clz s6, s7"); + COMPARE(clz(v0, v1), + "70621020 clz v0, v1"); + } + + COMPARE(ins_(a0, a1, 31, 1), + "7ca4ffc4 ins a0, a1, 31, 1"); + COMPARE(ins_(s6, s7, 30, 2), + "7ef6ff84 ins s6, s7, 30, 2"); + COMPARE(ins_(v0, v1, 0, 32), + "7c62f804 ins v0, v1, 0, 32"); + COMPARE(ext_(a0, a1, 31, 1), + "7ca407c0 ext a0, a1, 31, 1"); + COMPARE(ext_(s6, s7, 30, 2), + "7ef60f80 ext s6, s7, 30, 2"); + COMPARE(ext_(v0, v1, 0, 32), + "7c62f800 ext v0, v1, 0, 32"); + + VERIFY_RUN(); +} diff --git a/deps/v8/test/cctest/test-disasm-x64.cc b/deps/v8/test/cctest/test-disasm-x64.cc index 3b1f8af826..4778b04bb7 100644 --- a/deps/v8/test/cctest/test-disasm-x64.cc +++ b/deps/v8/test/cctest/test-disasm-x64.cc @@ -27,15 +27,15 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "debug.h" -#include "disasm.h" -#include "disassembler.h" -#include "macro-assembler.h" -#include "serialize.h" -#include "stub-cache.h" -#include "cctest.h" +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -261,7 +261,7 @@ TEST(DisasmX64) { // TODO(mstarzinger): The following is protected. // __ jmp(Operand(rbx, rcx, times_4, 10000)); ExternalReference after_break_target = - ExternalReference(Debug_Address::AfterBreakTarget(), isolate); + ExternalReference::debug_after_break_target_address(isolate); USE(after_break_target); __ jmp(ic, RelocInfo::CODE_TARGET); __ nop(); @@ -420,6 +420,14 @@ TEST(DisasmX64) { } } + // xchg. + { + __ xchgq(rax, rax); + __ xchgq(rax, rbx); + __ xchgq(rbx, rbx); + __ xchgq(rbx, Operand(rsp, 12)); + } + // Nop instructions for (int i = 0; i < 16; i++) { __ Nop(i); @@ -433,7 +441,8 @@ TEST(DisasmX64) { desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); USE(code); #ifdef OBJECT_PRINT - code->Print(); + OFStream os(stdout); + code->Print(os); byte* begin = code->instruction_start(); byte* end = begin + code->instruction_size(); disasm::Disassembler::Disassemble(stdout, begin, end); diff --git a/deps/v8/test/cctest/test-disasm-x87.cc b/deps/v8/test/cctest/test-disasm-x87.cc new file mode 100644 index 0000000000..1515cc793b --- /dev/null +++ b/deps/v8/test/cctest/test-disasm-x87.cc @@ -0,0 +1,410 @@ +// Copyright 2011 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. + +#include <stdlib.h> + +#include "src/v8.h" + +#include "src/debug.h" +#include "src/disasm.h" +#include "src/disassembler.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +#define __ assm. + + +static void DummyStaticFunction(Object* result) { +} + + +TEST(DisasmIa320) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + v8::internal::byte buffer[2048]; + Assembler assm(isolate, buffer, sizeof buffer); + DummyStaticFunction(NULL); // just bloody use it (DELETE; debugging) + + // Short immediate instructions + __ adc(eax, 12345678); + __ add(eax, Immediate(12345678)); + __ or_(eax, 12345678); + __ sub(eax, Immediate(12345678)); + __ xor_(eax, 12345678); + __ and_(eax, 12345678); + Handle<FixedArray> foo = isolate->factory()->NewFixedArray(10, TENURED); + __ cmp(eax, foo); + + // ---- This one caused crash + __ mov(ebx, Operand(esp, ecx, times_2, 0)); // [esp+ecx*4] + + // ---- All instructions that I can think of + __ add(edx, ebx); + __ add(edx, Operand(12, RelocInfo::NONE32)); + __ add(edx, Operand(ebx, 0)); + __ add(edx, Operand(ebx, 16)); + __ add(edx, Operand(ebx, 1999)); + __ add(edx, Operand(ebx, -4)); + __ add(edx, Operand(ebx, -1999)); + __ add(edx, Operand(esp, 0)); + __ add(edx, Operand(esp, 16)); + __ add(edx, Operand(esp, 1999)); + __ add(edx, Operand(esp, -4)); + __ add(edx, Operand(esp, -1999)); + __ nop(); + __ add(esi, Operand(ecx, times_4, 0)); + __ add(esi, Operand(ecx, times_4, 24)); + __ add(esi, Operand(ecx, times_4, -4)); + __ add(esi, Operand(ecx, times_4, -1999)); + __ nop(); + __ add(edi, Operand(ebp, ecx, times_4, 0)); + __ add(edi, Operand(ebp, ecx, times_4, 12)); + __ add(edi, Operand(ebp, ecx, times_4, -8)); + __ add(edi, Operand(ebp, ecx, times_4, -3999)); + __ add(Operand(ebp, ecx, times_4, 12), Immediate(12)); + + __ nop(); + __ add(ebx, Immediate(12)); + __ nop(); + __ adc(ecx, 12); + __ adc(ecx, 1000); + __ nop(); + __ and_(edx, 3); + __ and_(edx, Operand(esp, 4)); + __ cmp(edx, 3); + __ cmp(edx, Operand(esp, 4)); + __ cmp(Operand(ebp, ecx, times_4, 0), Immediate(1000)); + Handle<FixedArray> foo2 = isolate->factory()->NewFixedArray(10, TENURED); + __ cmp(ebx, foo2); + __ cmpb(ebx, Operand(ebp, ecx, times_2, 0)); + __ cmpb(Operand(ebp, ecx, times_2, 0), ebx); + __ or_(edx, 3); + __ xor_(edx, 3); + __ nop(); + __ cpuid(); + __ movsx_b(edx, ecx); + __ movsx_w(edx, ecx); + __ movzx_b(edx, ecx); + __ movzx_w(edx, ecx); + + __ nop(); + __ imul(edx, ecx); + __ shld(edx, ecx); + __ shrd(edx, ecx); + __ bts(edx, ecx); + __ bts(Operand(ebx, ecx, times_4, 0), ecx); + __ nop(); + __ pushad(); + __ popad(); + __ pushfd(); + __ popfd(); + __ push(Immediate(12)); + __ push(Immediate(23456)); + __ push(ecx); + __ push(esi); + __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); + __ push(Operand(ebx, ecx, times_4, 0)); + __ push(Operand(ebx, ecx, times_4, 0)); + __ push(Operand(ebx, ecx, times_4, 10000)); + __ pop(edx); + __ pop(eax); + __ pop(Operand(ebx, ecx, times_4, 0)); + __ nop(); + + __ add(edx, Operand(esp, 16)); + __ add(edx, ecx); + __ mov_b(edx, ecx); + __ mov_b(ecx, 6); + __ mov_b(Operand(ebx, ecx, times_4, 10000), 6); + __ mov_b(Operand(esp, 16), edx); + __ mov_w(edx, Operand(esp, 16)); + __ mov_w(Operand(esp, 16), edx); + __ nop(); + __ movsx_w(edx, Operand(esp, 12)); + __ movsx_b(edx, Operand(esp, 12)); + __ movzx_w(edx, Operand(esp, 12)); + __ movzx_b(edx, Operand(esp, 12)); + __ nop(); + __ mov(edx, 1234567); + __ mov(edx, Operand(esp, 12)); + __ mov(Operand(ebx, ecx, times_4, 10000), Immediate(12345)); + __ mov(Operand(ebx, ecx, times_4, 10000), edx); + __ nop(); + __ dec_b(edx); + __ dec_b(Operand(eax, 10)); + __ dec_b(Operand(ebx, ecx, times_4, 10000)); + __ dec(edx); + __ cdq(); + + __ nop(); + __ idiv(edx); + __ idiv(Operand(edx, ecx, times_1, 1)); + __ idiv(Operand(esp, 12)); + __ div(edx); + __ div(Operand(edx, ecx, times_1, 1)); + __ div(Operand(esp, 12)); + __ mul(edx); + __ neg(edx); + __ not_(edx); + __ test(Operand(ebx, ecx, times_4, 10000), Immediate(123456)); + + __ imul(edx, Operand(ebx, ecx, times_4, 10000)); + __ imul(edx, ecx, 12); + __ imul(edx, Operand(edx, eax, times_2, 42), 8); + __ imul(edx, ecx, 1000); + __ imul(edx, Operand(ebx, ecx, times_4, 1), 9000); + + __ inc(edx); + __ inc(Operand(ebx, ecx, times_4, 10000)); + __ push(Operand(ebx, ecx, times_4, 10000)); + __ pop(Operand(ebx, ecx, times_4, 10000)); + __ call(Operand(ebx, ecx, times_4, 10000)); + __ jmp(Operand(ebx, ecx, times_4, 10000)); + + __ lea(edx, Operand(ebx, ecx, times_4, 10000)); + __ or_(edx, 12345); + __ or_(edx, Operand(ebx, ecx, times_4, 10000)); + + __ nop(); + + __ rcl(edx, 1); + __ rcl(edx, 7); + __ rcr(edx, 1); + __ rcr(edx, 7); + __ sar(edx, 1); + __ sar(edx, 6); + __ sar_cl(edx); + __ sar(Operand(ebx, ecx, times_4, 10000), 1); + __ sar(Operand(ebx, ecx, times_4, 10000), 6); + __ sar_cl(Operand(ebx, ecx, times_4, 10000)); + __ sbb(edx, Operand(ebx, ecx, times_4, 10000)); + __ shld(edx, Operand(ebx, ecx, times_4, 10000)); + __ shl(edx, 1); + __ shl(edx, 6); + __ shl_cl(edx); + __ shl(Operand(ebx, ecx, times_4, 10000), 1); + __ shl(Operand(ebx, ecx, times_4, 10000), 6); + __ shl_cl(Operand(ebx, ecx, times_4, 10000)); + __ shrd(edx, Operand(ebx, ecx, times_4, 10000)); + __ shr(edx, 1); + __ shr(edx, 7); + __ shr_cl(edx); + __ shr(Operand(ebx, ecx, times_4, 10000), 1); + __ shr(Operand(ebx, ecx, times_4, 10000), 6); + __ shr_cl(Operand(ebx, ecx, times_4, 10000)); + + + // Immediates + + __ adc(edx, 12345); + + __ add(ebx, Immediate(12)); + __ add(Operand(edx, ecx, times_4, 10000), Immediate(12)); + + __ and_(ebx, 12345); + + __ cmp(ebx, 12345); + __ cmp(ebx, Immediate(12)); + __ cmp(Operand(edx, ecx, times_4, 10000), Immediate(12)); + __ cmpb(eax, 100); + + __ or_(ebx, 12345); + + __ sub(ebx, Immediate(12)); + __ sub(Operand(edx, ecx, times_4, 10000), Immediate(12)); + + __ xor_(ebx, 12345); + + __ imul(edx, ecx, 12); + __ imul(edx, ecx, 1000); + + __ cld(); + __ rep_movs(); + __ rep_stos(); + __ stos(); + + __ sub(edx, Operand(ebx, ecx, times_4, 10000)); + __ sub(edx, ebx); + + __ test(edx, Immediate(12345)); + __ test(edx, Operand(ebx, ecx, times_8, 10000)); + __ test(Operand(esi, edi, times_1, -20000000), Immediate(300000000)); + __ test_b(edx, Operand(ecx, ebx, times_2, 1000)); + __ test_b(Operand(eax, -20), 0x9A); + __ nop(); + + __ xor_(edx, 12345); + __ xor_(edx, Operand(ebx, ecx, times_8, 10000)); + __ bts(Operand(ebx, ecx, times_8, 10000), edx); + __ hlt(); + __ int3(); + __ ret(0); + __ ret(8); + + // Calls + + Label L1, L2; + __ bind(&L1); + __ nop(); + __ call(&L1); + __ call(&L2); + __ nop(); + __ bind(&L2); + __ call(Operand(ebx, ecx, times_4, 10000)); + __ nop(); + Handle<Code> ic(LoadIC::initialize_stub(isolate, NOT_CONTEXTUAL)); + __ call(ic, RelocInfo::CODE_TARGET); + __ nop(); + __ call(FUNCTION_ADDR(DummyStaticFunction), RelocInfo::RUNTIME_ENTRY); + __ nop(); + + __ jmp(&L1); + __ jmp(Operand(ebx, ecx, times_4, 10000)); + ExternalReference after_break_target = + ExternalReference::debug_after_break_target_address(isolate); + __ jmp(Operand::StaticVariable(after_break_target)); + __ jmp(ic, RelocInfo::CODE_TARGET); + __ nop(); + + + Label Ljcc; + __ nop(); + // long jumps + __ j(overflow, &Ljcc); + __ j(no_overflow, &Ljcc); + __ j(below, &Ljcc); + __ j(above_equal, &Ljcc); + __ j(equal, &Ljcc); + __ j(not_equal, &Ljcc); + __ j(below_equal, &Ljcc); + __ j(above, &Ljcc); + __ j(sign, &Ljcc); + __ j(not_sign, &Ljcc); + __ j(parity_even, &Ljcc); + __ j(parity_odd, &Ljcc); + __ j(less, &Ljcc); + __ j(greater_equal, &Ljcc); + __ j(less_equal, &Ljcc); + __ j(greater, &Ljcc); + __ nop(); + __ bind(&Ljcc); + // short jumps + __ j(overflow, &Ljcc); + __ j(no_overflow, &Ljcc); + __ j(below, &Ljcc); + __ j(above_equal, &Ljcc); + __ j(equal, &Ljcc); + __ j(not_equal, &Ljcc); + __ j(below_equal, &Ljcc); + __ j(above, &Ljcc); + __ j(sign, &Ljcc); + __ j(not_sign, &Ljcc); + __ j(parity_even, &Ljcc); + __ j(parity_odd, &Ljcc); + __ j(less, &Ljcc); + __ j(greater_equal, &Ljcc); + __ j(less_equal, &Ljcc); + __ j(greater, &Ljcc); + + // 0xD9 instructions + __ nop(); + + __ fld(1); + __ fld1(); + __ fldz(); + __ fldpi(); + __ fabs(); + __ fchs(); + __ fprem(); + __ fprem1(); + __ fincstp(); + __ ftst(); + __ fxch(3); + __ fld_s(Operand(ebx, ecx, times_4, 10000)); + __ fstp_s(Operand(ebx, ecx, times_4, 10000)); + __ ffree(3); + __ fld_d(Operand(ebx, ecx, times_4, 10000)); + __ fstp_d(Operand(ebx, ecx, times_4, 10000)); + __ nop(); + + __ fild_s(Operand(ebx, ecx, times_4, 10000)); + __ fistp_s(Operand(ebx, ecx, times_4, 10000)); + __ fild_d(Operand(ebx, ecx, times_4, 10000)); + __ fistp_d(Operand(ebx, ecx, times_4, 10000)); + __ fnstsw_ax(); + __ nop(); + __ fadd(3); + __ fsub(3); + __ fmul(3); + __ fdiv(3); + + __ faddp(3); + __ fsubp(3); + __ fmulp(3); + __ fdivp(3); + __ fcompp(); + __ fwait(); + __ frndint(); + __ fninit(); + __ nop(); + + // xchg. + { + __ xchg(eax, eax); + __ xchg(eax, ebx); + __ xchg(ebx, ebx); + __ xchg(ebx, Operand(esp, 12)); + } + + // Nop instructions + for (int i = 0; i < 16; i++) { + __ Nop(i); + } + + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + USE(code); +#ifdef OBJECT_PRINT + OFStream os(stdout); + code->Print(os); + byte* begin = code->instruction_start(); + byte* end = begin + code->instruction_size(); + disasm::Disassembler::Disassemble(stdout, begin, end); +#endif +} + +#undef __ diff --git a/deps/v8/test/cctest/test-diy-fp.cc b/deps/v8/test/cctest/test-diy-fp.cc index 145e317ff8..255118e967 100644 --- a/deps/v8/test/cctest/test-diy-fp.cc +++ b/deps/v8/test/cctest/test-diy-fp.cc @@ -27,11 +27,11 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" -#include "diy-fp.h" +#include "src/base/platform/platform.h" +#include "src/diy-fp.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-double.cc b/deps/v8/test/cctest/test-double.cc index 2c9f0c21bb..16dcb37101 100644 --- a/deps/v8/test/cctest/test-double.cc +++ b/deps/v8/test/cctest/test-double.cc @@ -27,12 +27,12 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" -#include "diy-fp.h" -#include "double.h" +#include "src/base/platform/platform.h" +#include "src/diy-fp.h" +#include "src/double.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -105,7 +105,7 @@ TEST(IsDenormal) { TEST(IsSpecial) { CHECK(Double(V8_INFINITY).IsSpecial()); CHECK(Double(-V8_INFINITY).IsSpecial()); - CHECK(Double(OS::nan_value()).IsSpecial()); + CHECK(Double(v8::base::OS::nan_value()).IsSpecial()); uint64_t bits = V8_2PART_UINT64_C(0xFFF12345, 00000000); CHECK(Double(bits).IsSpecial()); // Denormals are not special: @@ -128,7 +128,7 @@ TEST(IsSpecial) { TEST(IsInfinite) { CHECK(Double(V8_INFINITY).IsInfinite()); CHECK(Double(-V8_INFINITY).IsInfinite()); - CHECK(!Double(OS::nan_value()).IsInfinite()); + CHECK(!Double(v8::base::OS::nan_value()).IsInfinite()); CHECK(!Double(0.0).IsInfinite()); CHECK(!Double(-0.0).IsInfinite()); CHECK(!Double(1.0).IsInfinite()); diff --git a/deps/v8/test/cctest/test-dtoa.cc b/deps/v8/test/cctest/test-dtoa.cc index 66c2aafc66..3f396a5d1b 100644 --- a/deps/v8/test/cctest/test-dtoa.cc +++ b/deps/v8/test/cctest/test-dtoa.cc @@ -27,16 +27,16 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "dtoa.h" +#include "src/dtoa.h" -#include "cctest.h" -#include "double.h" -#include "gay-fixed.h" -#include "gay-precision.h" -#include "gay-shortest.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "src/double.h" +#include "test/cctest/cctest.h" +#include "test/cctest/gay-fixed.h" +#include "test/cctest/gay-precision.h" +#include "test/cctest/gay-shortest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-fast-dtoa.cc b/deps/v8/test/cctest/test-fast-dtoa.cc index 46f975799f..52198a45f2 100644 --- a/deps/v8/test/cctest/test-fast-dtoa.cc +++ b/deps/v8/test/cctest/test-fast-dtoa.cc @@ -27,15 +27,15 @@ #include <stdlib.h> -#include "v8.h" - -#include "platform.h" -#include "cctest.h" -#include "diy-fp.h" -#include "double.h" -#include "fast-dtoa.h" -#include "gay-precision.h" -#include "gay-shortest.h" +#include "src/v8.h" + +#include "src/base/platform/platform.h" +#include "src/diy-fp.h" +#include "src/double.h" +#include "src/fast-dtoa.h" +#include "test/cctest/cctest.h" +#include "test/cctest/gay-precision.h" +#include "test/cctest/gay-shortest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-fixed-dtoa.cc b/deps/v8/test/cctest/test-fixed-dtoa.cc index 21926f1970..de40d09f1b 100644 --- a/deps/v8/test/cctest/test-fixed-dtoa.cc +++ b/deps/v8/test/cctest/test-fixed-dtoa.cc @@ -27,13 +27,13 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" -#include "double.h" -#include "fixed-dtoa.h" -#include "gay-fixed.h" +#include "src/base/platform/platform.h" +#include "src/double.h" +#include "src/fixed-dtoa.h" +#include "test/cctest/cctest.h" +#include "test/cctest/gay-fixed.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-flags.cc b/deps/v8/test/cctest/test-flags.cc index a1d2405ad5..862b73adba 100644 --- a/deps/v8/test/cctest/test-flags.cc +++ b/deps/v8/test/cctest/test-flags.cc @@ -27,8 +27,8 @@ #include <stdlib.h> -#include "v8.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-func-name-inference.cc b/deps/v8/test/cctest/test-func-name-inference.cc index f452b3ed3b..bc503b58c6 100644 --- a/deps/v8/test/cctest/test-func-name-inference.cc +++ b/deps/v8/test/cctest/test-func-name-inference.cc @@ -26,12 +26,12 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "api.h" -#include "debug.h" -#include "runtime.h" -#include "cctest.h" +#include "src/api.h" +#include "src/debug.h" +#include "src/runtime.h" +#include "test/cctest/cctest.h" using ::v8::internal::CStrVector; diff --git a/deps/v8/test/cctest/test-fuzz-arm64.cc b/deps/v8/test/cctest/test-fuzz-arm64.cc index 0ceb60f7b3..ada609fe78 100644 --- a/deps/v8/test/cctest/test-fuzz-arm64.cc +++ b/deps/v8/test/cctest/test-fuzz-arm64.cc @@ -23,11 +23,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> -#include "cctest.h" +#include "test/cctest/cctest.h" -#include "arm64/decoder-arm64.h" -#include "arm64/decoder-arm64-inl.h" -#include "arm64/disasm-arm64.h" +#include "src/arm64/decoder-arm64.h" +#include "src/arm64/decoder-arm64-inl.h" +#include "src/arm64/disasm-arm64.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-gc-tracer.cc b/deps/v8/test/cctest/test-gc-tracer.cc new file mode 100644 index 0000000000..190644dec1 --- /dev/null +++ b/deps/v8/test/cctest/test-gc-tracer.cc @@ -0,0 +1,125 @@ +// Copyright 2014 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. + +#include <stdlib.h> +#include <utility> + +#include "src/v8.h" + +#include "test/cctest/cctest.h" + +using namespace v8::internal; + +TEST(RingBufferPartialFill) { + const int max_size = 6; + typedef RingBuffer<int, max_size>::const_iterator Iter; + RingBuffer<int, max_size> ring_buffer; + CHECK(ring_buffer.empty()); + CHECK_EQ(static_cast<int>(ring_buffer.size()), 0); + CHECK(ring_buffer.begin() == ring_buffer.end()); + + // Fill ring_buffer partially: [0, 1, 2] + for (int i = 0; i < max_size / 2; i++) ring_buffer.push_back(i); + + CHECK(!ring_buffer.empty()); + CHECK(static_cast<int>(ring_buffer.size()) == max_size / 2); + CHECK(ring_buffer.begin() != ring_buffer.end()); + + // Test forward itartion + int i = 0; + for (Iter iter = ring_buffer.begin(); iter != ring_buffer.end(); ++iter) { + CHECK(*iter == i); + ++i; + } + CHECK_EQ(i, 3); // one past last element. + + // Test backward iteration + i = 2; + Iter iter = ring_buffer.back(); + while (true) { + CHECK(*iter == i); + if (iter == ring_buffer.begin()) break; + --iter; + --i; + } + CHECK_EQ(i, 0); +} + + +TEST(RingBufferWrapAround) { + const int max_size = 6; + typedef RingBuffer<int, max_size>::const_iterator Iter; + RingBuffer<int, max_size> ring_buffer; + + // Fill ring_buffer (wrap around): [9, 10, 11, 12, 13, 14] + for (int i = 0; i < 2 * max_size + 3; i++) ring_buffer.push_back(i); + + CHECK(!ring_buffer.empty()); + CHECK(static_cast<int>(ring_buffer.size()) == max_size); + CHECK(ring_buffer.begin() != ring_buffer.end()); + + // Test forward iteration + int i = 9; + for (Iter iter = ring_buffer.begin(); iter != ring_buffer.end(); ++iter) { + CHECK(*iter == i); + ++i; + } + CHECK_EQ(i, 15); // one past last element. + + // Test backward iteration + i = 14; + Iter iter = ring_buffer.back(); + while (true) { + CHECK(*iter == i); + if (iter == ring_buffer.begin()) break; + --iter; + --i; + } + CHECK_EQ(i, 9); +} + + +TEST(RingBufferPushFront) { + const int max_size = 6; + typedef RingBuffer<int, max_size>::const_iterator Iter; + RingBuffer<int, max_size> ring_buffer; + + // Fill ring_buffer (wrap around): [14, 13, 12, 11, 10, 9] + for (int i = 0; i < 2 * max_size + 3; i++) ring_buffer.push_front(i); + + CHECK(!ring_buffer.empty()); + CHECK(static_cast<int>(ring_buffer.size()) == max_size); + CHECK(ring_buffer.begin() != ring_buffer.end()); + + // Test forward iteration + int i = 14; + for (Iter iter = ring_buffer.begin(); iter != ring_buffer.end(); ++iter) { + CHECK(*iter == i); + --i; + } + CHECK_EQ(i, 8); // one past last element. +} diff --git a/deps/v8/test/cctest/test-global-handles.cc b/deps/v8/test/cctest/test-global-handles.cc index 1ab90ec5ec..ee295d6991 100644 --- a/deps/v8/test/cctest/test-global-handles.cc +++ b/deps/v8/test/cctest/test-global-handles.cc @@ -25,9 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "global-handles.h" +#include "src/global-handles.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8::internal; using v8::UniqueId; @@ -56,7 +56,7 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo { bool has_been_disposed() { return has_been_disposed_; } virtual void Dispose() { - ASSERT(!has_been_disposed_); + DCHECK(!has_been_disposed_); has_been_disposed_ = true; } @@ -121,16 +121,16 @@ TEST(IterateObjectGroupsOldApi) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 4); - ASSERT(can_skip_called_objects.Contains(*g1s1.location())); - ASSERT(can_skip_called_objects.Contains(*g1s2.location())); - ASSERT(can_skip_called_objects.Contains(*g2s1.location())); - ASSERT(can_skip_called_objects.Contains(*g2s2.location())); + DCHECK(can_skip_called_objects.length() == 4); + DCHECK(can_skip_called_objects.Contains(*g1s1.location())); + DCHECK(can_skip_called_objects.Contains(*g1s2.location())); + DCHECK(can_skip_called_objects.Contains(*g2s1.location())); + DCHECK(can_skip_called_objects.Contains(*g2s2.location())); // Nothing was visited. - ASSERT(visitor.visited.length() == 0); - ASSERT(!info1.has_been_disposed()); - ASSERT(!info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 0); + DCHECK(!info1.has_been_disposed()); + DCHECK(!info2.has_been_disposed()); } // Iterate again, now only skip the second object group. @@ -145,18 +145,18 @@ TEST(IterateObjectGroupsOldApi) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 3 || + DCHECK(can_skip_called_objects.length() == 3 || can_skip_called_objects.length() == 4); - ASSERT(can_skip_called_objects.Contains(*g1s2.location())); - ASSERT(can_skip_called_objects.Contains(*g2s1.location())); - ASSERT(can_skip_called_objects.Contains(*g2s2.location())); + DCHECK(can_skip_called_objects.Contains(*g1s2.location())); + DCHECK(can_skip_called_objects.Contains(*g2s1.location())); + DCHECK(can_skip_called_objects.Contains(*g2s2.location())); // The first group was visited. - ASSERT(visitor.visited.length() == 2); - ASSERT(visitor.visited.Contains(*g1s1.location())); - ASSERT(visitor.visited.Contains(*g1s2.location())); - ASSERT(info1.has_been_disposed()); - ASSERT(!info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 2); + DCHECK(visitor.visited.Contains(*g1s1.location())); + DCHECK(visitor.visited.Contains(*g1s2.location())); + DCHECK(info1.has_been_disposed()); + DCHECK(!info2.has_been_disposed()); } // Iterate again, don't skip anything. @@ -166,15 +166,15 @@ TEST(IterateObjectGroupsOldApi) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 1); - ASSERT(can_skip_called_objects.Contains(*g2s1.location()) || + DCHECK(can_skip_called_objects.length() == 1); + DCHECK(can_skip_called_objects.Contains(*g2s1.location()) || can_skip_called_objects.Contains(*g2s2.location())); // The second group was visited. - ASSERT(visitor.visited.length() == 2); - ASSERT(visitor.visited.Contains(*g2s1.location())); - ASSERT(visitor.visited.Contains(*g2s2.location())); - ASSERT(info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 2); + DCHECK(visitor.visited.Contains(*g2s1.location())); + DCHECK(visitor.visited.Contains(*g2s2.location())); + DCHECK(info2.has_been_disposed()); } } @@ -216,16 +216,16 @@ TEST(IterateObjectGroups) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 4); - ASSERT(can_skip_called_objects.Contains(*g1s1.location())); - ASSERT(can_skip_called_objects.Contains(*g1s2.location())); - ASSERT(can_skip_called_objects.Contains(*g2s1.location())); - ASSERT(can_skip_called_objects.Contains(*g2s2.location())); + DCHECK(can_skip_called_objects.length() == 4); + DCHECK(can_skip_called_objects.Contains(*g1s1.location())); + DCHECK(can_skip_called_objects.Contains(*g1s2.location())); + DCHECK(can_skip_called_objects.Contains(*g2s1.location())); + DCHECK(can_skip_called_objects.Contains(*g2s2.location())); // Nothing was visited. - ASSERT(visitor.visited.length() == 0); - ASSERT(!info1.has_been_disposed()); - ASSERT(!info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 0); + DCHECK(!info1.has_been_disposed()); + DCHECK(!info2.has_been_disposed()); } // Iterate again, now only skip the second object group. @@ -240,18 +240,18 @@ TEST(IterateObjectGroups) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 3 || + DCHECK(can_skip_called_objects.length() == 3 || can_skip_called_objects.length() == 4); - ASSERT(can_skip_called_objects.Contains(*g1s2.location())); - ASSERT(can_skip_called_objects.Contains(*g2s1.location())); - ASSERT(can_skip_called_objects.Contains(*g2s2.location())); + DCHECK(can_skip_called_objects.Contains(*g1s2.location())); + DCHECK(can_skip_called_objects.Contains(*g2s1.location())); + DCHECK(can_skip_called_objects.Contains(*g2s2.location())); // The first group was visited. - ASSERT(visitor.visited.length() == 2); - ASSERT(visitor.visited.Contains(*g1s1.location())); - ASSERT(visitor.visited.Contains(*g1s2.location())); - ASSERT(info1.has_been_disposed()); - ASSERT(!info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 2); + DCHECK(visitor.visited.Contains(*g1s1.location())); + DCHECK(visitor.visited.Contains(*g1s2.location())); + DCHECK(info1.has_been_disposed()); + DCHECK(!info2.has_been_disposed()); } // Iterate again, don't skip anything. @@ -261,15 +261,15 @@ TEST(IterateObjectGroups) { global_handles->IterateObjectGroups(&visitor, &CanSkipCallback); // CanSkipCallback was called for all objects. - ASSERT(can_skip_called_objects.length() == 1); - ASSERT(can_skip_called_objects.Contains(*g2s1.location()) || + DCHECK(can_skip_called_objects.length() == 1); + DCHECK(can_skip_called_objects.Contains(*g2s1.location()) || can_skip_called_objects.Contains(*g2s2.location())); // The second group was visited. - ASSERT(visitor.visited.length() == 2); - ASSERT(visitor.visited.Contains(*g2s1.location())); - ASSERT(visitor.visited.Contains(*g2s2.location())); - ASSERT(info2.has_been_disposed()); + DCHECK(visitor.visited.length() == 2); + DCHECK(visitor.visited.Contains(*g2s1.location())); + DCHECK(visitor.visited.Contains(*g2s2.location())); + DCHECK(info2.has_been_disposed()); } } @@ -306,16 +306,16 @@ TEST(ImplicitReferences) { List<ImplicitRefGroup*>* implicit_refs = global_handles->implicit_ref_groups(); USE(implicit_refs); - ASSERT(implicit_refs->length() == 2); - ASSERT(implicit_refs->at(0)->parent == + DCHECK(implicit_refs->length() == 2); + DCHECK(implicit_refs->at(0)->parent == reinterpret_cast<HeapObject**>(g1s1.location())); - ASSERT(implicit_refs->at(0)->length == 2); - ASSERT(implicit_refs->at(0)->children[0] == g1c1.location()); - ASSERT(implicit_refs->at(0)->children[1] == g1c2.location()); - ASSERT(implicit_refs->at(1)->parent == + DCHECK(implicit_refs->at(0)->length == 2); + DCHECK(implicit_refs->at(0)->children[0] == g1c1.location()); + DCHECK(implicit_refs->at(0)->children[1] == g1c2.location()); + DCHECK(implicit_refs->at(1)->parent == reinterpret_cast<HeapObject**>(g2s1.location())); - ASSERT(implicit_refs->at(1)->length == 1); - ASSERT(implicit_refs->at(1)->children[0] == g2c1.location()); + DCHECK(implicit_refs->at(1)->length == 1); + DCHECK(implicit_refs->at(1)->children[0] == g2c1.location()); global_handles->RemoveObjectGroups(); global_handles->RemoveImplicitRefGroups(); } diff --git a/deps/v8/test/cctest/test-global-object.cc b/deps/v8/test/cctest/test-global-object.cc index bbec9df775..0e2c9408c6 100644 --- a/deps/v8/test/cctest/test-global-object.cc +++ b/deps/v8/test/cctest/test-global-object.cc @@ -25,9 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8; diff --git a/deps/v8/test/cctest/test-hashing.cc b/deps/v8/test/cctest/test-hashing.cc index 9a7d61ddd8..9857f9d88a 100644 --- a/deps/v8/test/cctest/test-hashing.cc +++ b/deps/v8/test/cctest/test-hashing.cc @@ -27,16 +27,16 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "factory.h" -#include "macro-assembler.h" -#include "cctest.h" -#include "code-stubs.h" -#include "objects.h" +#include "src/code-stubs.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/objects.h" +#include "test/cctest/cctest.h" #ifdef USE_SIMULATOR -#include "simulator.h" +#include "src/simulator.h" #endif using namespace v8::internal; @@ -50,8 +50,8 @@ typedef uint32_t (*HASH_FUNCTION)(); void generate(MacroAssembler* masm, i::Vector<const uint8_t> string) { // GenerateHashInit takes the first character as an argument so it can't // handle the zero length string. - ASSERT(string.length() > 0); -#if V8_TARGET_ARCH_IA32 + DCHECK(string.length() > 0); +#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 __ push(ebx); __ push(ecx); __ mov(eax, Immediate(0)); @@ -114,11 +114,11 @@ void generate(MacroAssembler* masm, i::Vector<const uint8_t> string) { __ Pop(xzr, root); __ Ret(); __ SetStackPointer(old_stack_pointer); -#elif V8_TARGET_ARCH_MIPS +#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 __ push(kRootRegister); __ InitializeRootRegister(); - __ li(v0, Operand(0)); + __ mov(v0, zero_reg); __ li(t1, Operand(string.at(0))); StringHelper::GenerateHashInit(masm, v0, t1); for (int i = 1; i < string.length(); i++) { @@ -136,7 +136,7 @@ void generate(MacroAssembler* masm, i::Vector<const uint8_t> string) { void generate(MacroAssembler* masm, uint32_t key) { -#if V8_TARGET_ARCH_IA32 +#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 __ push(ebx); __ mov(eax, Immediate(key)); __ GetNumberHash(eax, ebx); @@ -170,7 +170,7 @@ void generate(MacroAssembler* masm, uint32_t key) { __ Pop(xzr, root); __ Ret(); __ SetStackPointer(old_stack_pointer); -#elif V8_TARGET_ARCH_MIPS +#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 __ push(kRootRegister); __ InitializeRootRegister(); __ li(v0, Operand(key)); diff --git a/deps/v8/test/cctest/test-hashmap.cc b/deps/v8/test/cctest/test-hashmap.cc index 70213c9aa8..1e94bed593 100644 --- a/deps/v8/test/cctest/test-hashmap.cc +++ b/deps/v8/test/cctest/test-hashmap.cc @@ -27,9 +27,10 @@ #include <stdlib.h> -#include "v8.h" -#include "hashmap.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/hashmap.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index eeafc7093c..e456323bae 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -29,16 +29,16 @@ #include <ctype.h> -#include "v8.h" +#include "src/v8.h" -#include "allocation-tracker.h" -#include "cctest.h" -#include "hashmap.h" -#include "heap-profiler.h" -#include "snapshot.h" -#include "debug.h" -#include "utils-inl.h" -#include "../include/v8-profiler.h" +#include "include/v8-profiler.h" +#include "src/allocation-tracker.h" +#include "src/debug.h" +#include "src/hashmap.h" +#include "src/heap-profiler.h" +#include "src/snapshot.h" +#include "src/utils-inl.h" +#include "test/cctest/cctest.h" using i::AllocationTraceNode; using i::AllocationTraceTree; @@ -471,6 +471,174 @@ TEST(HeapSnapshotConsString) { } +TEST(HeapSnapshotSymbol) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + CompileRun("a = Symbol('mySymbol');\n"); + const v8::HeapSnapshot* snapshot = + heap_profiler->TakeHeapSnapshot(v8_str("Symbol")); + CHECK(ValidateSnapshot(snapshot)); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* a = + GetProperty(global, v8::HeapGraphEdge::kProperty, "a"); + CHECK_NE(NULL, a); + CHECK_EQ(a->GetType(), v8::HeapGraphNode::kSymbol); + CHECK_EQ(v8_str("symbol"), a->GetName()); + const v8::HeapGraphNode* name = + GetProperty(a, v8::HeapGraphEdge::kInternal, "name"); + CHECK_NE(NULL, name); + CHECK_EQ(v8_str("mySymbol"), name->GetName()); +} + + +TEST(HeapSnapshotWeakCollection) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + CompileRun( + "k = {}; v = {}; s = 'str';\n" + "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n" + "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n"); + const v8::HeapSnapshot* snapshot = + heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections")); + CHECK(ValidateSnapshot(snapshot)); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* k = + GetProperty(global, v8::HeapGraphEdge::kProperty, "k"); + CHECK_NE(NULL, k); + const v8::HeapGraphNode* v = + GetProperty(global, v8::HeapGraphEdge::kProperty, "v"); + CHECK_NE(NULL, v); + const v8::HeapGraphNode* s = + GetProperty(global, v8::HeapGraphEdge::kProperty, "s"); + CHECK_NE(NULL, s); + + const v8::HeapGraphNode* ws = + GetProperty(global, v8::HeapGraphEdge::kProperty, "ws"); + CHECK_NE(NULL, ws); + CHECK_EQ(v8::HeapGraphNode::kObject, ws->GetType()); + CHECK_EQ(v8_str("WeakSet"), ws->GetName()); + + const v8::HeapGraphNode* ws_table = + GetProperty(ws, v8::HeapGraphEdge::kInternal, "table"); + CHECK_EQ(v8::HeapGraphNode::kArray, ws_table->GetType()); + CHECK_GT(ws_table->GetChildrenCount(), 0); + int weak_entries = 0; + for (int i = 0, count = ws_table->GetChildrenCount(); i < count; ++i) { + const v8::HeapGraphEdge* prop = ws_table->GetChild(i); + if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue; + if (k->GetId() == prop->GetToNode()->GetId()) { + ++weak_entries; + } + } + CHECK_EQ(1, weak_entries); + const v8::HeapGraphNode* ws_s = + GetProperty(ws, v8::HeapGraphEdge::kProperty, "str"); + CHECK_NE(NULL, ws_s); + CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(ws_s->GetId())); + + const v8::HeapGraphNode* wm = + GetProperty(global, v8::HeapGraphEdge::kProperty, "wm"); + CHECK_NE(NULL, wm); + CHECK_EQ(v8::HeapGraphNode::kObject, wm->GetType()); + CHECK_EQ(v8_str("WeakMap"), wm->GetName()); + + const v8::HeapGraphNode* wm_table = + GetProperty(wm, v8::HeapGraphEdge::kInternal, "table"); + CHECK_EQ(v8::HeapGraphNode::kArray, wm_table->GetType()); + CHECK_GT(wm_table->GetChildrenCount(), 0); + weak_entries = 0; + for (int i = 0, count = wm_table->GetChildrenCount(); i < count; ++i) { + const v8::HeapGraphEdge* prop = wm_table->GetChild(i); + if (prop->GetType() != v8::HeapGraphEdge::kWeak) continue; + const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId(); + if (to_node_id == k->GetId() || to_node_id == v->GetId()) { + ++weak_entries; + } + } + CHECK_EQ(2, weak_entries); + const v8::HeapGraphNode* wm_s = + GetProperty(wm, v8::HeapGraphEdge::kProperty, "str"); + CHECK_NE(NULL, wm_s); + CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(wm_s->GetId())); +} + + +TEST(HeapSnapshotCollection) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + CompileRun( + "k = {}; v = {}; s = 'str';\n" + "set = new Set(); set.add(k); set.add(v); set[s] = s;\n" + "map = new Map(); map.set(k, v); map[s] = s;\n"); + const v8::HeapSnapshot* snapshot = + heap_profiler->TakeHeapSnapshot(v8_str("Collections")); + CHECK(ValidateSnapshot(snapshot)); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* k = + GetProperty(global, v8::HeapGraphEdge::kProperty, "k"); + CHECK_NE(NULL, k); + const v8::HeapGraphNode* v = + GetProperty(global, v8::HeapGraphEdge::kProperty, "v"); + CHECK_NE(NULL, v); + const v8::HeapGraphNode* s = + GetProperty(global, v8::HeapGraphEdge::kProperty, "s"); + CHECK_NE(NULL, s); + + const v8::HeapGraphNode* set = + GetProperty(global, v8::HeapGraphEdge::kProperty, "set"); + CHECK_NE(NULL, set); + CHECK_EQ(v8::HeapGraphNode::kObject, set->GetType()); + CHECK_EQ(v8_str("Set"), set->GetName()); + + const v8::HeapGraphNode* set_table = + GetProperty(set, v8::HeapGraphEdge::kInternal, "table"); + CHECK_EQ(v8::HeapGraphNode::kArray, set_table->GetType()); + CHECK_GT(set_table->GetChildrenCount(), 0); + int entries = 0; + for (int i = 0, count = set_table->GetChildrenCount(); i < count; ++i) { + const v8::HeapGraphEdge* prop = set_table->GetChild(i); + const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId(); + if (to_node_id == k->GetId() || to_node_id == v->GetId()) { + ++entries; + } + } + CHECK_EQ(2, entries); + const v8::HeapGraphNode* set_s = + GetProperty(set, v8::HeapGraphEdge::kProperty, "str"); + CHECK_NE(NULL, set_s); + CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(set_s->GetId())); + + const v8::HeapGraphNode* map = + GetProperty(global, v8::HeapGraphEdge::kProperty, "map"); + CHECK_NE(NULL, map); + CHECK_EQ(v8::HeapGraphNode::kObject, map->GetType()); + CHECK_EQ(v8_str("Map"), map->GetName()); + + const v8::HeapGraphNode* map_table = + GetProperty(map, v8::HeapGraphEdge::kInternal, "table"); + CHECK_EQ(v8::HeapGraphNode::kArray, map_table->GetType()); + CHECK_GT(map_table->GetChildrenCount(), 0); + entries = 0; + for (int i = 0, count = map_table->GetChildrenCount(); i < count; ++i) { + const v8::HeapGraphEdge* prop = map_table->GetChild(i); + const v8::SnapshotObjectId to_node_id = prop->GetToNode()->GetId(); + if (to_node_id == k->GetId() || to_node_id == v->GetId()) { + ++entries; + } + } + CHECK_EQ(2, entries); + const v8::HeapGraphNode* map_s = + GetProperty(map, v8::HeapGraphEdge::kProperty, "str"); + CHECK_NE(NULL, map_s); + CHECK_EQ(static_cast<int>(s->GetId()), static_cast<int>(map_s->GetId())); +} + TEST(HeapSnapshotInternalReferences) { v8::Isolate* isolate = CcTest::isolate(); @@ -690,11 +858,11 @@ class TestJSONStream : public v8::OutputStream { if (abort_countdown_ == 0) return kAbort; CHECK_GT(chars_written, 0); i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0'); - i::OS::MemCopy(chunk.start(), buffer, chars_written); + i::MemCopy(chunk.start(), buffer, chars_written); return kContinue; } virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) { - ASSERT(false); + DCHECK(false); return kAbort; } void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } @@ -863,13 +1031,13 @@ class TestStatsStream : public v8::OutputStream { virtual ~TestStatsStream() {} virtual void EndOfStream() { ++eos_signaled_; } virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) { - ASSERT(false); + DCHECK(false); return kAbort; } virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer, int updates_written) { ++intervals_count_; - ASSERT(updates_written); + DCHECK(updates_written); updates_written_ += updates_written; entries_count_ = 0; if (first_interval_index_ == -1 && updates_written != 0) @@ -1554,9 +1722,9 @@ TEST(GlobalObjectFields) { const v8::HeapGraphNode* global_context = GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context"); CHECK_NE(NULL, global_context); - const v8::HeapGraphNode* global_receiver = - GetProperty(global, v8::HeapGraphEdge::kInternal, "global_receiver"); - CHECK_NE(NULL, global_receiver); + const v8::HeapGraphNode* global_proxy = + GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy"); + CHECK_NE(NULL, global_proxy); } @@ -1601,7 +1769,7 @@ TEST(GetHeapValueForNode) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };"); + CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };"); const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(v8_str("value")); CHECK(ValidateSnapshot(snapshot)); @@ -1622,10 +1790,9 @@ TEST(GetHeapValueForNode) { CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId())); const v8::HeapGraphNode* n_prop = GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop"); - v8::Local<v8::Number> js_n_prop = - js_obj->Get(v8_str("n_prop")).As<v8::Number>(); - CHECK(js_n_prop->NumberValue() == - heap_profiler->FindObjectById(n_prop->GetId())->NumberValue()); + v8::Local<v8::String> js_n_prop = + js_obj->Get(v8_str("n_prop")).As<v8::String>(); + CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId())); } @@ -1888,7 +2055,7 @@ TEST(NoDebugObjectInSnapshot) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - CcTest::i_isolate()->debug()->Load(); + CHECK(CcTest::i_isolate()->debug()->Load()); CompileRun("foo = {};"); const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); @@ -2017,7 +2184,7 @@ TEST(ManyLocalsInSharedContext) { // ... well check just every 15th because otherwise it's too slow in debug. for (int i = 0; i < num_objects - 1; i += 15) { i::EmbeddedVector<char, 100> var_name; - i::OS::SNPrintF(var_name, "f_%d", i); + i::SNPrintF(var_name, "f_%d", i); const v8::HeapGraphNode* f_object = GetProperty( context_object, v8::HeapGraphEdge::kContextVariable, var_name.start()); CHECK_NE(NULL, f_object); @@ -2112,7 +2279,7 @@ static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot, v8::String::Utf8Value edge_name(edge->GetName()); v8::String::Utf8Value node_name(to_node->GetName()); i::EmbeddedVector<char, 100> name; - i::OS::SNPrintF(name, "%s::%s", *edge_name, *node_name); + i::SNPrintF(name, "%s::%s", *edge_name, *node_name); if (strstr(name.start(), path[current_depth])) { node = to_node; break; @@ -2239,7 +2406,7 @@ TEST(ArrayGrowLeftTrim) { "for (var i = 0; i < 3; ++i)\n" " a.shift();\n"); - const char* names[] = { "(anonymous function)" }; + const char* names[] = {""}; AllocationTracker* tracker = reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker(); CHECK_NE(NULL, tracker); @@ -2274,8 +2441,7 @@ TEST(TrackHeapAllocations) { // Print for better diagnostics in case of failure. tracker->trace_tree()->Print(tracker); - const char* names[] = - { "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" }; + const char* names[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"}; AllocationTraceNode* node = FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); CHECK_NE(NULL, node); @@ -2310,7 +2476,7 @@ TEST(TrackBumpPointerAllocations) { LocalContext env; v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" }; + const char* names[] = {"", "start", "f_0", "f_1"}; // First check that normally all allocations are recorded. { heap_profiler->StartTrackingHeapObjects(true); @@ -2444,7 +2610,7 @@ TEST(ArrayBufferSharedBackingStore) { CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); void* data = ab_contents.Data(); - ASSERT(data != NULL); + DCHECK(data != NULL); v8::Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength()); CHECK(ab2->IsExternal()); diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 3cc61ed5fd..ab000dc6a6 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -28,37 +28,18 @@ #include <stdlib.h> #include <utility> -#include "v8.h" +#include "src/v8.h" -#include "compilation-cache.h" -#include "execution.h" -#include "factory.h" -#include "macro-assembler.h" -#include "global-handles.h" -#include "stub-cache.h" -#include "cctest.h" +#include "src/compilation-cache.h" +#include "src/execution.h" +#include "src/factory.h" +#include "src/global-handles.h" +#include "src/macro-assembler.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" using namespace v8::internal; -// Go through all incremental marking steps in one swoop. -static void SimulateIncrementalMarking() { - MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector(); - IncrementalMarking* marking = CcTest::heap()->incremental_marking(); - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); - } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - marking->Start(); - } - CHECK(marking->IsMarking()); - while (!marking->IsComplete()) { - marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - } - CHECK(marking->IsComplete()); -} - - static void CheckMap(Map* map, int type, int instance_size) { CHECK(map->IsHeapObject()); #ifdef DEBUG @@ -179,7 +160,8 @@ TEST(HeapObjects) { CHECK(value->IsNumber()); CHECK_EQ(Smi::kMaxValue, Handle<Smi>::cast(value)->value()); -#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64) +#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64) && \ + !defined(V8_TARGET_ARCH_MIPS64) // TODO(lrn): We need a NumberFromIntptr function in order to test this. value = factory->NewNumberFromInt(Smi::kMinValue - 1); CHECK(value->IsHeapNumber()); @@ -209,7 +191,9 @@ TEST(HeapObjects) { Handle<String> object_string = Handle<String>::cast(factory->Object_string()); Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object()); - CHECK(JSReceiver::HasLocalProperty(global, object_string)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, object_string); + CHECK(maybe.has_value); + CHECK(maybe.value); // Check ToString for oddballs CheckOddball(isolate, heap->true_value(), "true"); @@ -260,18 +244,12 @@ TEST(GarbageCollection) { { HandleScope inner_scope(isolate); // Allocate a function and keep it in global object's property. - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); - JSReceiver::SetProperty(global, name, function, NONE, SLOPPY).Check(); + Handle<JSFunction> function = factory->NewFunction(name); + JSReceiver::SetProperty(global, name, function, SLOPPY).Check(); // Allocate an object. Unrooted after leaving the scope. Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty( - obj, prop_name, twenty_three, NONE, SLOPPY).Check(); - JSReceiver::SetProperty( - obj, prop_namex, twenty_four, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_namex, twenty_four, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); @@ -282,7 +260,9 @@ TEST(GarbageCollection) { heap->CollectGarbage(NEW_SPACE); // Function should be alive. - CHECK(JSReceiver::HasLocalProperty(global, name)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, name); + CHECK(maybe.has_value); + CHECK(maybe.value); // Check function is retained. Handle<Object> func_value = Object::GetProperty(global, name).ToHandleChecked(); @@ -293,15 +273,16 @@ TEST(GarbageCollection) { HandleScope inner_scope(isolate); // Allocate another object, make it reachable from global. Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty(global, obj_name, obj, NONE, SLOPPY).Check(); - JSReceiver::SetProperty( - obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(global, obj_name, obj, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); } // After gc, it should survive. heap->CollectGarbage(NEW_SPACE); - CHECK(JSReceiver::HasLocalProperty(global, obj_name)); + maybe = JSReceiver::HasOwnProperty(global, obj_name); + CHECK(maybe.has_value); + CHECK(maybe.value); Handle<Object> obj = Object::GetProperty(global, obj_name).ToHandleChecked(); CHECK(obj->IsJSObject()); @@ -623,23 +604,18 @@ TEST(FunctionAllocation) { v8::HandleScope sc(CcTest::isolate()); Handle<String> name = factory->InternalizeUtf8String("theFunction"); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); + Handle<JSFunction> function = factory->NewFunction(name); Handle<Smi> twenty_three(Smi::FromInt(23), isolate); Handle<Smi> twenty_four(Smi::FromInt(24), isolate); Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); // Check that we can add properties to function objects. - JSReceiver::SetProperty( - function, prop_name, twenty_four, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(function, prop_name, twenty_four, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(24), *Object::GetProperty(function, prop_name).ToHandleChecked()); } @@ -663,55 +639,85 @@ TEST(ObjectProperties) { Handle<Smi> two(Smi::FromInt(2), isolate); // check for empty - CHECK(!JSReceiver::HasLocalProperty(obj, first)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete first JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first and then second - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete first and then second JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); - CHECK(!JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first and then second - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete second and then first JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); - CHECK(!JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(!maybe.value); // check string and internalized string match const char* string1 = "fisk"; Handle<String> s1 = factory->NewStringFromAsciiChecked(string1); - JSReceiver::SetProperty(obj, s1, one, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, s1, one, SLOPPY).Check(); Handle<String> s1_string = factory->InternalizeUtf8String(string1); - CHECK(JSReceiver::HasLocalProperty(obj, s1_string)); + maybe = JSReceiver::HasOwnProperty(obj, s1_string); + CHECK(maybe.has_value); + CHECK(maybe.value); // check internalized string and string match const char* string2 = "fugl"; Handle<String> s2_string = factory->InternalizeUtf8String(string2); - JSReceiver::SetProperty(obj, s2_string, one, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, s2_string, one, SLOPPY).Check(); Handle<String> s2 = factory->NewStringFromAsciiChecked(string2); - CHECK(JSReceiver::HasLocalProperty(obj, s2)); + maybe = JSReceiver::HasOwnProperty(obj, s2); + CHECK(maybe.has_value); + CHECK(maybe.value); } @@ -722,18 +728,15 @@ TEST(JSObjectMaps) { v8::HandleScope sc(CcTest::isolate()); Handle<String> name = factory->InternalizeUtf8String("theFunction"); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); + Handle<JSFunction> function = factory->NewFunction(name); Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); Handle<JSObject> obj = factory->NewJSObject(function); + Handle<Map> initial_map(function->initial_map()); // Set a propery Handle<Smi> twenty_three(Smi::FromInt(23), isolate); - JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); @@ -811,8 +814,8 @@ TEST(JSObjectCopy) { Handle<Smi> one(Smi::FromInt(1), isolate); Handle<Smi> two(Smi::FromInt(2), isolate); - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); + 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(); @@ -837,8 +840,8 @@ TEST(JSObjectCopy) { CHECK_EQ(*value1, *value2); // Flip the values. - JSReceiver::SetProperty(clone, first, two, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(clone, second, one, NONE, SLOPPY).Check(); + 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(); @@ -901,7 +904,6 @@ TEST(StringAllocation) { static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) { // Count the number of objects found in the heap. int found_count = 0; - heap->EnsureHeapIsIterable(); HeapIterator iterator(heap); for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { for (int i = 0; i < size; i++) { @@ -1030,7 +1032,9 @@ TEST(Regression39128) { CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length()); CHECK_EQ(0, jsobject->properties()->length()); // Create a reference to object in new space in jsobject. - jsobject->FastPropertyAtPut(-1, array); + FieldIndex index = FieldIndex::ForInObjectOffset( + JSObject::kHeaderSize - kPointerSize); + jsobject->FastPropertyAtPut(index, array); CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr)); @@ -1200,7 +1204,7 @@ TEST(TestCodeFlushingIncremental) { // Simulate several GCs that use incremental marking. const int kAgingThreshold = 6; for (int i = 0; i < kAgingThreshold; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); } CHECK(!function->shared()->is_compiled() || function->IsOptimized()); @@ -1214,7 +1218,7 @@ TEST(TestCodeFlushingIncremental) { // Simulate several GCs that use incremental marking but make sure // the loop breaks once the function is enqueued as a candidate. for (int i = 0; i < kAgingThreshold; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); if (!function->next_function_link()->IsUndefined()) break; CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); } @@ -1290,7 +1294,7 @@ TEST(TestCodeFlushingIncrementalScavenge) { // Simulate incremental marking so that the functions are enqueued as // code flushing candidates. Then kill one of the functions. Finally // perform a scavenge while incremental marking is still running. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); *function2.location() = NULL; CcTest::heap()->CollectGarbage(NEW_SPACE, "test scavenge while marking"); @@ -1344,7 +1348,7 @@ TEST(TestCodeFlushingIncrementalAbort) { // Simulate incremental marking so that the function is enqueued as // code flushing candidate. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Enable the debugger and add a breakpoint while incremental marking // is running so that incremental marking aborts and code flushing is @@ -1604,8 +1608,8 @@ TEST(TestSizeOfObjects) { CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector(); - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); } int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects()); @@ -1631,8 +1635,8 @@ TEST(TestSizeOfObjects) { CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects())); // Waiting for sweeper threads should not change heap size. - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); } CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects())); } @@ -1640,9 +1644,8 @@ TEST(TestSizeOfObjects) { TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { CcTest::InitializeVM(); - CcTest::heap()->EnsureHeapIsIterable(); - intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects(); HeapIterator iterator(CcTest::heap()); + intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects(); intptr_t size_of_objects_2 = 0; for (HeapObject* obj = iterator.next(); obj != NULL; @@ -1811,7 +1814,7 @@ TEST(LeakNativeContextViaMap) { ctx2->Exit(); v8::Local<v8::Context>::New(isolate, ctx1)->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1857,7 +1860,7 @@ TEST(LeakNativeContextViaFunction) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1901,7 +1904,7 @@ TEST(LeakNativeContextViaMapKeyed) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1949,7 +1952,7 @@ TEST(LeakNativeContextViaMapProto) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -2110,8 +2113,8 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { // The following two calls will increment CcTest::heap()->global_ic_age(). const int kLongIdlePauseInMs = 1000; - v8::V8::ContextDisposedNotification(); - v8::V8::IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->ContextDisposedNotification(); + CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); while (!marking->IsStopped() && !marking->IsComplete()) { marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); @@ -2166,8 +2169,8 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { // The following two calls will increment CcTest::heap()->global_ic_age(). // Since incremental marking is off, IdleNotification will do full GC. const int kLongIdlePauseInMs = 1000; - v8::V8::ContextDisposedNotification(); - v8::V8::IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->ContextDisposedNotification(); + CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age()); CHECK_EQ(0, f->shared()->opt_count()); @@ -2207,100 +2210,70 @@ TEST(OptimizedAllocationAlwaysInNewSpace) { TEST(OptimizedPretenuringAllocationFolding) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; - i::FLAG_allocation_site_pretenuring = false; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - v8::Local<v8::Value> res = CompileRun( - "function DataObject() {" - " this.a = 1.1;" - " this.b = [{}];" - " this.c = 1.2;" - " this.d = [{}];" - " this.e = 1.3;" - " this.f = [{}];" - "}" - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array();" "function f() {" " for (var i = 0; i < number_elements; i++) {" - " elements[i] = new DataObject();" + " elements[i] = [[{}], [1.1]];" " }" " return elements[number_elements-1]" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); - - Handle<JSObject> o = - v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(1))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(2))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(3))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(4))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(5))); -} + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + v8::Local<v8::Value> res = CompileRun(source.start()); -TEST(OptimizedPretenuringAllocationFoldingBlocks) { - i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; - i::FLAG_allocation_site_pretenuring = false; - CcTest::InitializeVM(); - if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; - if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; - v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" - "var elements = new Array(number_elements);" - "function DataObject() {" - " this.a = [{}];" - " this.b = [{}];" - " this.c = 1.1;" - " this.d = 1.2;" - " this.e = [{}];" - " this.f = 1.3;" - "}" - "function f() {" - " for (var i = 0; i < number_elements; i++) {" - " elements[i] = new DataObject();" - " }" - " return elements[number_elements - 1];" - "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0")); + Handle<JSObject> int_array_handle = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array)); + v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1")); + Handle<JSObject> double_array_handle = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array)); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(1))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(2))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(3))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(4))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(5))); + CHECK(CcTest::heap()->InOldPointerSpace(*o)); + CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle)); + CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements())); + CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle)); + CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements())); } TEST(OptimizedPretenuringObjectArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2308,9 +2281,13 @@ TEST(OptimizedPretenuringObjectArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2322,14 +2299,22 @@ TEST(OptimizedPretenuringObjectArrayLiterals) { TEST(OptimizedPretenuringMixedInObjectProperties) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2337,34 +2322,49 @@ TEST(OptimizedPretenuringMixedInObjectProperties) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); CHECK(CcTest::heap()->InOldPointerSpace(*o)); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(1))); + FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0); + FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1); + CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1))); + CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2))); - JSObject* inner_object = reinterpret_cast<JSObject*>(o->RawFastPropertyAt(0)); + JSObject* inner_object = + reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1)); CHECK(CcTest::heap()->InOldPointerSpace(inner_object)); - CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(inner_object->RawFastPropertyAt(1))); + CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1))); + CHECK(CcTest::heap()->InOldPointerSpace( + inner_object->RawFastPropertyAt(idx2))); } TEST(OptimizedPretenuringDoubleArrayProperties) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2372,9 +2372,13 @@ TEST(OptimizedPretenuringDoubleArrayProperties) { " }" " return elements[i - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2386,14 +2390,21 @@ TEST(OptimizedPretenuringDoubleArrayProperties) { TEST(OptimizedPretenuringdoubleArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2401,9 +2412,13 @@ TEST(OptimizedPretenuringdoubleArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2415,14 +2430,21 @@ TEST(OptimizedPretenuringdoubleArrayLiterals) { TEST(OptimizedPretenuringNestedMixedArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = 100;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2430,10 +2452,13 @@ TEST(OptimizedPretenuringNestedMixedArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" "f();"); + v8::Local<v8::Value> res = CompileRun(source.start()); + v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0")); Handle<JSObject> int_array_handle = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array)); @@ -2453,14 +2478,21 @@ TEST(OptimizedPretenuringNestedMixedArrayLiterals) { TEST(OptimizedPretenuringNestedObjectLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2468,9 +2500,13 @@ TEST(OptimizedPretenuringNestedObjectLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); v8::Local<v8::Value> int_array_1 = v8::Object::Cast(*res)->Get(v8_str("0")); Handle<JSObject> int_array_handle_1 = @@ -2491,14 +2527,21 @@ TEST(OptimizedPretenuringNestedObjectLiterals) { TEST(OptimizedPretenuringNestedDoubleLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2506,9 +2549,13 @@ TEST(OptimizedPretenuringNestedDoubleLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); v8::Local<v8::Value> double_array_1 = v8::Object::Cast(*res)->Get(v8_str("0")); @@ -2532,19 +2579,29 @@ TEST(OptimizedPretenuringNestedDoubleLiterals) { // Make sure pretenuring feedback is gathered for constructed objects as well // as for literals. TEST(OptimizedPretenuringConstructorCalls) { - if (!FLAG_allocation_site_pretenuring || !i::FLAG_pretenuring_call_new) { + if (!i::FLAG_pretenuring_call_new) { // FLAG_pretenuring_call_new needs to be synced with the snapshot. return; } i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + // Call new is doing slack tracking for the first + // JSFunction::kGenerousAllocationCount allocations, and we can't find + // mementos during that time. + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function foo() {" " this.a = 3;" @@ -2556,9 +2613,14 @@ TEST(OptimizedPretenuringConstructorCalls) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated + + JSFunction::kGenerousAllocationCount); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2567,57 +2629,77 @@ TEST(OptimizedPretenuringConstructorCalls) { } -// Test regular array literals allocation. -TEST(OptimizedAllocationArrayLiterals) { +TEST(OptimizedPretenuringCallNew) { + if (!i::FLAG_pretenuring_call_new) { + // FLAG_pretenuring_call_new needs to be synced with the snapshot. + return; + } i::FLAG_allow_natives_syntax = true; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + // Call new is doing slack tracking for the first + // JSFunction::kGenerousAllocationCount allocations, and we can't find + // mementos during that time. + i::SNPrintF( + source, + "var number_elements = %d;" + "var elements = new Array(number_elements);" + "function g() { this.a = 0; }" "function f() {" - " var numbers = new Array(1, 2, 3);" - " numbers[0] = 3.14;" - " return numbers;" + " for (var i = 0; i < number_elements; i++) {" + " elements[i] = new g();" + " }" + " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); - CHECK_EQ(static_cast<int>(3.14), - v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value()); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated + + JSFunction::kGenerousAllocationCount); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InNewSpace(o->elements())); + CHECK(CcTest::heap()->InOldPointerSpace(*o)); } -// Test global pretenuring call new. -TEST(OptimizedPretenuringCallNew) { +// Test regular array literals allocation. +TEST(OptimizedAllocationArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_allocation_site_pretenuring = false; - i::FLAG_pretenuring_call_new = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - AlwaysAllocateScope always_allocate(CcTest::i_isolate()); v8::Local<v8::Value> res = CompileRun( - "function g() { this.a = 0; }" "function f() {" - " return new g();" + " var numbers = new Array(1, 2, 3);" + " numbers[0] = 3.14;" + " return numbers;" "};" "f(); f(); f();" "%OptimizeFunctionOnNextCall(f);" "f();"); + CHECK_EQ(static_cast<int>(3.14), + v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - CHECK(CcTest::heap()->InOldPointerSpace(*o)); + + CHECK(CcTest::heap()->InNewSpace(o->elements())); } @@ -2641,7 +2723,7 @@ TEST(Regress1465) { AlwaysAllocateScope always_allocate(CcTest::i_isolate()); for (int i = 0; i < transitions_count; i++) { EmbeddedVector<char, 64> buffer; - OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); + SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); CompileRun(buffer.start()); } CompileRun("var root = new F;"); @@ -2657,7 +2739,7 @@ TEST(Regress1465) { CompileRun("%DebugPrint(root);"); CHECK_EQ(transitions_count, transitions_before); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); // Count number of live transitions after marking. Note that one transition @@ -2673,7 +2755,7 @@ static void AddTransitions(int transitions_count) { AlwaysAllocateScope always_allocate(CcTest::i_isolate()); for (int i = 0; i < transitions_count; i++) { EmbeddedVector<char, 64> buffer; - OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); + SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); CompileRun(buffer.start()); } } @@ -2695,8 +2777,7 @@ static void AddPropertyTo( i::FLAG_gc_interval = gc_count; i::FLAG_gc_global = true; CcTest::heap()->set_allocation_timeout(gc_count); - JSReceiver::SetProperty( - object, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check(); } @@ -2799,7 +2880,7 @@ TEST(TransitionArraySimpleToFull) { CompileRun("o = new F;" "root = new F"); root = GetByName("root"); - ASSERT(root->map()->transitions()->IsSimpleTransition()); + DCHECK(root->map()->transitions()->IsSimpleTransition()); AddPropertyTo(2, root, "happy"); // Count number of live transitions after marking. Note that one transition @@ -2823,7 +2904,7 @@ TEST(Regress2143a) { "root.foo = 0;" "root = new Object;"); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); // Compile a StoreIC that performs the prepared map transition. This // will restart incremental marking and should make sure the root is @@ -2864,7 +2945,7 @@ TEST(Regress2143b) { "root.foo = 0;" "root = new Object;"); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); // Compile an optimized LStoreNamedField that performs the prepared // map transition. This will restart incremental marking and should @@ -2920,7 +3001,8 @@ TEST(ReleaseOverReservedPages) { // Triggering one GC will cause a lot of garbage to be discovered but // even spread across all allocated pages. - heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation"); + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask, + "triggered for preparation"); CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); // Triggering subsequent GCs should cause at least half of the pages @@ -2986,8 +3068,9 @@ TEST(PrintSharedFunctionInfo) { *v8::Handle<v8::Function>::Cast( CcTest::global()->Get(v8_str("g")))); - DisallowHeapAllocation no_allocation; - g->shared()->PrintLn(); + OFStream os(stdout); + g->shared()->Print(os); + os << endl; } #endif // OBJECT_PRINT @@ -3018,9 +3101,9 @@ TEST(Regress2211) { CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string")))); // Check size. - DescriptorArray* descriptors = internal_obj->map()->instance_descriptors(); + FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0); ObjectHashTable* hashtable = ObjectHashTable::cast( - internal_obj->RawFastPropertyAt(descriptors->GetFieldIndex(0))); + internal_obj->RawFastPropertyAt(index)); // HashTable header (5) and 4 initial entries (8). CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize); } @@ -3058,18 +3141,22 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { Handle<FixedArray> feedback_vector(f->shared()->feedback_vector()); - CHECK_EQ(2, feedback_vector->length()); - CHECK(feedback_vector->get(0)->IsJSFunction()); - CHECK(feedback_vector->get(1)->IsJSFunction()); + int expected_length = FLAG_vector_ics ? 4 : 2; + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + if ((i % 2) == 1) { + CHECK(feedback_vector->get(i)->IsJSFunction()); + } + } - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); - CHECK_EQ(2, feedback_vector->length()); - CHECK_EQ(feedback_vector->get(0), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); - CHECK_EQ(feedback_vector->get(1), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + CHECK_EQ(feedback_vector->get(i), + *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + } } @@ -3105,7 +3192,7 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) { Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); CHECK(ic_before->ic_state() == MONOMORPHIC); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3138,8 +3225,8 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { CHECK(ic_before->ic_state() == MONOMORPHIC); // Fire context dispose notification. - v8::V8::ContextDisposedNotification(); - SimulateIncrementalMarking(); + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3179,8 +3266,8 @@ TEST(IncrementalMarkingClearsPolymorphicIC) { CHECK(ic_before->ic_state() == POLYMORPHIC); // Fire context dispose notification. - v8::V8::ContextDisposedNotification(); - SimulateIncrementalMarking(); + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3341,7 +3428,7 @@ TEST(Regress159140) { // Simulate incremental marking so that the functions are enqueued as // code flushing candidates. Then optimize one function. Finally // finish the GC to complete code flushing. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); CompileRun("%OptimizeFunctionOnNextCall(g); g(3);"); heap->CollectAllGarbage(Heap::kNoGCFlags); @@ -3388,7 +3475,7 @@ TEST(Regress165495) { // Simulate incremental marking so that unoptimized code is flushed // even though it still is cached in the optimized code map. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); heap->CollectAllGarbage(Heap::kNoGCFlags); // Make a new closure that will get code installed from the code map. @@ -3456,7 +3543,7 @@ TEST(Regress169209) { } // Simulate incremental marking and collect code flushing candidates. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); CHECK(shared1->code()->gc_metadata() != NULL); // Optimize function and make sure the unoptimized code is replaced. @@ -3602,7 +3689,7 @@ TEST(Regress168801) { // Simulate incremental marking so that unoptimized function is enqueued as a // candidate for code flushing. The shared function info however will not be // explicitly enqueued. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Now optimize the function so that it is taken off the candidate list. { @@ -3659,7 +3746,7 @@ TEST(Regress173458) { // Simulate incremental marking so that unoptimized function is enqueued as a // candidate for code flushing. The shared function info however will not be // explicitly enqueued. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Now enable the debugger which in turn will disable code flushing. CHECK(isolate->debug()->Load()); @@ -3688,7 +3775,7 @@ TEST(DeferredHandles) { } // An entire block of handles has been filled. // Next handle would require a new block. - ASSERT(data->next == data->limit); + DCHECK(data->next == data->limit); DeferredHandleScope deferred(isolate); DummyVisitor visitor; @@ -3709,7 +3796,7 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) { if (marking->IsStopped()) marking->Start(); // This big step should be sufficient to mark the whole array. marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - ASSERT(marking->IsComplete()); + DCHECK(marking->IsComplete()); } @@ -3736,10 +3823,6 @@ TEST(DisableInlineAllocation) { CcTest::heap()->DisableInlineAllocation(); CompileRun("run()"); - // Run test with inline allocation disabled and pretenuring. - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - CompileRun("run()"); - // Run test with inline allocation re-enabled. CcTest::heap()->EnableInlineAllocation(); CompileRun("run()"); @@ -3803,7 +3886,7 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) { // Now make sure that a gc should get rid of the function, even though we // still have the allocation site alive. for (int i = 0; i < 4; i++) { - heap->CollectAllGarbage(false); + heap->CollectAllGarbage(Heap::kNoGCFlags); } // The site still exists because of our global handle, but the code is no @@ -3853,7 +3936,7 @@ TEST(CellsInOptimizedCodeAreWeak) { heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } - ASSERT(code->marked_for_deoptimization()); + DCHECK(code->marked_for_deoptimization()); } @@ -3894,7 +3977,7 @@ TEST(ObjectsInOptimizedCodeAreWeak) { heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } - ASSERT(code->marked_for_deoptimization()); + DCHECK(code->marked_for_deoptimization()); } @@ -3911,37 +3994,41 @@ TEST(NoWeakHashTableLeakWithIncrementalMarking) { if (!isolate->use_crankshaft()) return; HandleScope outer_scope(heap->isolate()); for (int i = 0; i < 3; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); { LocalContext context; HandleScope scope(heap->isolate()); EmbeddedVector<char, 256> source; - OS::SNPrintF(source, - "function bar%d() {" - " return foo%d(1);" - "};" - "function foo%d(x) { with (x) { return 1 + x; } };" - "bar%d();" - "bar%d();" - "bar%d();" - "%OptimizeFunctionOnNextCall(bar%d);" - "bar%d();", i, i, i, i, i, i, i, i); + SNPrintF(source, + "function bar%d() {" + " return foo%d(1);" + "};" + "function foo%d(x) { with (x) { return 1 + x; } };" + "bar%d();" + "bar%d();" + "bar%d();" + "%%OptimizeFunctionOnNextCall(bar%d);" + "bar%d();", i, i, i, i, i, i, i, i); CompileRun(source.start()); } heap->CollectAllGarbage(i::Heap::kNoGCFlags); } - WeakHashTable* table = WeakHashTable::cast(heap->weak_object_to_code_table()); - CHECK_EQ(0, table->NumberOfElements()); + int elements = 0; + if (heap->weak_object_to_code_table()->IsHashTable()) { + WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table()); + elements = t->NumberOfElements(); + } + CHECK_EQ(0, elements); } static Handle<JSFunction> OptimizeDummyFunction(const char* name) { EmbeddedVector<char, 256> source; - OS::SNPrintF(source, - "function %s() { return 0; }" - "%s(); %s();" - "%%OptimizeFunctionOnNextCall(%s);" - "%s();", name, name, name, name, name); + SNPrintF(source, + "function %s() { return 0; }" + "%s(); %s();" + "%%OptimizeFunctionOnNextCall(%s);" + "%s();", name, name, name, name, name); CompileRun(source.start()); Handle<JSFunction> fun = v8::Utils::OpenHandle( @@ -3993,7 +4080,8 @@ static Handle<Code> DummyOptimizedCode(Isolate* isolate) { i::byte buffer[i::Assembler::kMinimalBufferSize]; MacroAssembler masm(isolate, buffer, sizeof(buffer)); CodeDesc desc; - masm.Prologue(BUILD_FUNCTION_FRAME); + masm.Push(isolate->factory()->undefined_value()); + masm.Drop(1); masm.GetCode(&desc); Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); Handle<Code> code = isolate->factory()->NewCode( @@ -4221,7 +4309,7 @@ TEST(Regress357137) { global->Set(v8::String::NewFromUtf8(isolate, "interrupt"), v8::FunctionTemplate::New(isolate, RequestInterrupt)); v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); - ASSERT(!context.IsEmpty()); + DCHECK(!context.IsEmpty()); v8::Context::Scope cscope(context); v8::Local<v8::Value> result = CompileRun( @@ -4246,6 +4334,7 @@ TEST(ArrayShiftSweeping) { "var tmp = new Array(100000);" "array[0] = 10;" "gc();" + "gc();" "array.shift();" "array;"); @@ -4254,6 +4343,145 @@ TEST(ArrayShiftSweeping) { CHECK(heap->InOldPointerSpace(o->elements())); CHECK(heap->InOldPointerSpace(*o)); Page* page = Page::FromAddress(o->elements()->address()); - CHECK(page->WasSwept() || + CHECK(page->parallel_sweeping() <= MemoryChunk::SWEEPING_FINALIZE || Marking::IsBlack(Marking::MarkBitFrom(o->elements()))); } + + +TEST(PromotionQueue) { + i::FLAG_expose_gc = true; + i::FLAG_max_semi_space_size = 2; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + NewSpace* new_space = heap->new_space(); + + // In this test we will try to overwrite the promotion queue which is at the + // end of to-space. To actually make that possible, we need at least two + // semi-space pages and take advantage of fragementation. + // (1) Grow semi-space to two pages. + // (2) Create a few small long living objects and call the scavenger to + // move them to the other semi-space. + // (3) Create a huge object, i.e., remainder of first semi-space page and + // create another huge object which should be of maximum allocatable memory + // size of the second semi-space page. + // (4) Call the scavenger again. + // What will happen is: the scavenger will promote the objects created in (2) + // and will create promotion queue entries at the end of the second + // semi-space page during the next scavenge when it promotes the objects to + // the old generation. The first allocation of (3) will fill up the first + // semi-space page. The second allocation in (3) will not fit into the first + // semi-space page, but it will overwrite the promotion queue which are in + // the second semi-space page. If the right guards are in place, the promotion + // queue will be evacuated in that case. + + // Grow the semi-space to two pages to make semi-space copy overwrite the + // promotion queue, which will be at the end of the second page. + intptr_t old_capacity = new_space->Capacity(); + new_space->Grow(); + CHECK(new_space->IsAtMaximumCapacity()); + CHECK(2 * old_capacity == new_space->Capacity()); + + // Call the scavenger two times to get an empty new space + heap->CollectGarbage(NEW_SPACE); + heap->CollectGarbage(NEW_SPACE); + + // First create a few objects which will survive a scavenge, and will get + // promoted to the old generation later on. These objects will create + // promotion queue entries at the end of the second semi-space page. + const int number_handles = 12; + Handle<FixedArray> handles[number_handles]; + for (int i = 0; i < number_handles; i++) { + handles[i] = isolate->factory()->NewFixedArray(1, NOT_TENURED); + } + heap->CollectGarbage(NEW_SPACE); + + // Create the first huge object which will exactly fit the first semi-space + // page. + int new_linear_size = static_cast<int>( + *heap->new_space()->allocation_limit_address() - + *heap->new_space()->allocation_top_address()); + int length = new_linear_size / kPointerSize - FixedArray::kHeaderSize; + Handle<FixedArray> first = + isolate->factory()->NewFixedArray(length, NOT_TENURED); + CHECK(heap->InNewSpace(*first)); + + // Create the second huge object of maximum allocatable second semi-space + // page size. + new_linear_size = static_cast<int>( + *heap->new_space()->allocation_limit_address() - + *heap->new_space()->allocation_top_address()); + length = Page::kMaxRegularHeapObjectSize / kPointerSize - + FixedArray::kHeaderSize; + Handle<FixedArray> second = + isolate->factory()->NewFixedArray(length, NOT_TENURED); + CHECK(heap->InNewSpace(*second)); + + // This scavenge will corrupt memory if the promotion queue is not evacuated. + heap->CollectGarbage(NEW_SPACE); +} + + +TEST(Regress388880) { + i::FLAG_expose_gc = true; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + + Handle<Map> map1 = Map::Create(isolate->object_function(), 1); + Handle<Map> map2 = + Map::CopyWithField(map1, factory->NewStringFromStaticAscii("foo"), + HeapType::Any(isolate), NONE, Representation::Tagged(), + OMIT_TRANSITION).ToHandleChecked(); + + int desired_offset = Page::kPageSize - map1->instance_size(); + + // Allocate fixed array in old pointer space so, that object allocated + // afterwards would end at the end of the page. + { + SimulateFullSpace(heap->old_pointer_space()); + int padding_size = desired_offset - Page::kObjectStartOffset; + int padding_array_length = + (padding_size - FixedArray::kHeaderSize) / kPointerSize; + + Handle<FixedArray> temp2 = + factory->NewFixedArray(padding_array_length, TENURED); + Page* page = Page::FromAddress(temp2->address()); + CHECK_EQ(Page::kObjectStartOffset, page->Offset(temp2->address())); + } + + Handle<JSObject> o = factory->NewJSObjectFromMap(map1, TENURED, false); + o->set_properties(*factory->empty_fixed_array()); + + // Ensure that the object allocated where we need it. + Page* page = Page::FromAddress(o->address()); + CHECK_EQ(desired_offset, page->Offset(o->address())); + + // Now we have an object right at the end of the page. + + // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes() + // that would cause crash. + IncrementalMarking* marking = CcTest::heap()->incremental_marking(); + marking->Abort(); + marking->Start(); + CHECK(marking->IsMarking()); + + // Now everything is set up for crashing in JSObject::MigrateFastToFast() + // when it calls heap->AdjustLiveBytes(...). + JSObject::MigrateToMap(o, map2); +} + + +#ifdef DEBUG +TEST(PathTracer) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + + v8::Local<v8::Value> result = CompileRun("'abc'"); + Handle<Object> o = v8::Utils::OpenHandle(*result); + CcTest::i_isolate()->heap()->TracePathToObject(*o); +} +#endif // DEBUG diff --git a/deps/v8/test/cctest/test-hydrogen-types.cc b/deps/v8/test/cctest/test-hydrogen-types.cc new file mode 100644 index 0000000000..0ac53bde09 --- /dev/null +++ b/deps/v8/test/cctest/test-hydrogen-types.cc @@ -0,0 +1,168 @@ +// 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/hydrogen-types.h" + +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +static const HType kTypes[] = { + #define DECLARE_TYPE(Name, mask) HType::Name(), + HTYPE_LIST(DECLARE_TYPE) + #undef DECLARE_TYPE +}; + +static const int kNumberOfTypes = sizeof(kTypes) / sizeof(kTypes[0]); + + +TEST(HTypeDistinct) { + for (int i = 0; i < kNumberOfTypes; ++i) { + for (int j = 0; j < kNumberOfTypes; ++j) { + CHECK(i == j || !kTypes[i].Equals(kTypes[j])); + } + } +} + + +TEST(HTypeReflexivity) { + // Reflexivity of = + for (int i = 0; i < kNumberOfTypes; ++i) { + CHECK(kTypes[i].Equals(kTypes[i])); + } + + // Reflexivity of < + for (int i = 0; i < kNumberOfTypes; ++i) { + CHECK(kTypes[i].IsSubtypeOf(kTypes[i])); + } +} + + +TEST(HTypeTransitivity) { + // Transitivity of = + for (int i = 0; i < kNumberOfTypes; ++i) { + for (int j = 0; j < kNumberOfTypes; ++j) { + for (int k = 0; k < kNumberOfTypes; ++k) { + HType ti = kTypes[i]; + HType tj = kTypes[j]; + HType tk = kTypes[k]; + CHECK(!ti.Equals(tj) || !tj.Equals(tk) || ti.Equals(tk)); + } + } + } + + // Transitivity of < + for (int i = 0; i < kNumberOfTypes; ++i) { + for (int j = 0; j < kNumberOfTypes; ++j) { + for (int k = 0; k < kNumberOfTypes; ++k) { + HType ti = kTypes[i]; + HType tj = kTypes[j]; + HType tk = kTypes[k]; + CHECK(!ti.IsSubtypeOf(tj) || !tj.IsSubtypeOf(tk) || ti.IsSubtypeOf(tk)); + } + } + } +} + + +TEST(HTypeCombine) { + // T < T /\ T' and T' < T /\ T' for all T,T' + for (int i = 0; i < kNumberOfTypes; ++i) { + for (int j = 0; j < kNumberOfTypes; ++j) { + HType ti = kTypes[i]; + HType tj = kTypes[j]; + CHECK(ti.IsSubtypeOf(ti.Combine(tj))); + CHECK(tj.IsSubtypeOf(ti.Combine(tj))); + } + } +} + + +TEST(HTypeAny) { + // T < Any for all T + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(ti.IsAny()); + } + + // Any < T implies T = Any for all T + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(!HType::Any().IsSubtypeOf(ti) || HType::Any().Equals(ti)); + } +} + + +TEST(HTypeTagged) { + // T < Tagged for all T \ {Any} + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(ti.IsTagged() || HType::Any().Equals(ti)); + } + + // Tagged < T implies T = Tagged or T = Any + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(!HType::Tagged().IsSubtypeOf(ti) || + HType::Tagged().Equals(ti) || + HType::Any().Equals(ti)); + } +} + + +TEST(HTypeSmi) { + // T < Smi implies T = None or T = Smi for all T + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(!ti.IsSmi() || + ti.Equals(HType::Smi()) || + ti.Equals(HType::None())); + } +} + + +TEST(HTypeHeapObject) { + CHECK(!HType::TaggedPrimitive().IsHeapObject()); + CHECK(!HType::TaggedNumber().IsHeapObject()); + CHECK(!HType::Smi().IsHeapObject()); + CHECK(HType::HeapObject().IsHeapObject()); + CHECK(HType::HeapPrimitive().IsHeapObject()); + CHECK(HType::Null().IsHeapObject()); + CHECK(HType::HeapNumber().IsHeapObject()); + CHECK(HType::String().IsHeapObject()); + CHECK(HType::Boolean().IsHeapObject()); + CHECK(HType::Undefined().IsHeapObject()); + CHECK(HType::JSObject().IsHeapObject()); + CHECK(HType::JSArray().IsHeapObject()); +} + + +TEST(HTypePrimitive) { + CHECK(HType::TaggedNumber().IsTaggedPrimitive()); + CHECK(HType::Smi().IsTaggedPrimitive()); + CHECK(!HType::HeapObject().IsTaggedPrimitive()); + CHECK(HType::HeapPrimitive().IsTaggedPrimitive()); + CHECK(HType::Null().IsHeapPrimitive()); + CHECK(HType::HeapNumber().IsHeapPrimitive()); + CHECK(HType::String().IsHeapPrimitive()); + CHECK(HType::Boolean().IsHeapPrimitive()); + CHECK(HType::Undefined().IsHeapPrimitive()); + CHECK(!HType::JSObject().IsTaggedPrimitive()); + CHECK(!HType::JSArray().IsTaggedPrimitive()); +} + + +TEST(HTypeJSObject) { + CHECK(HType::JSArray().IsJSObject()); +} + + +TEST(HTypeNone) { + // None < T for all T + for (int i = 0; i < kNumberOfTypes; ++i) { + HType ti = kTypes[i]; + CHECK(HType::None().IsSubtypeOf(ti)); + } +} diff --git a/deps/v8/test/cctest/test-javascript-arm64.cc b/deps/v8/test/cctest/test-javascript-arm64.cc index bd7a2b2851..5e4503478d 100644 --- a/deps/v8/test/cctest/test-javascript-arm64.cc +++ b/deps/v8/test/cctest/test-javascript-arm64.cc @@ -27,18 +27,18 @@ #include <limits.h> -#include "v8.h" - -#include "api.h" -#include "isolate.h" -#include "compilation-cache.h" -#include "execution.h" -#include "snapshot.h" -#include "platform.h" -#include "utils.h" -#include "cctest.h" -#include "parser.h" -#include "unicode-inl.h" +#include "src/v8.h" + +#include "src/api.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/execution.h" +#include "src/isolate.h" +#include "src/parser.h" +#include "src/snapshot.h" +#include "src/unicode-inl.h" +#include "src/utils.h" +#include "test/cctest/cctest.h" using ::v8::Context; using ::v8::Extension; diff --git a/deps/v8/test/cctest/test-js-arm64-variables.cc b/deps/v8/test/cctest/test-js-arm64-variables.cc index df3f4a8295..7f2771094c 100644 --- a/deps/v8/test/cctest/test-js-arm64-variables.cc +++ b/deps/v8/test/cctest/test-js-arm64-variables.cc @@ -29,18 +29,18 @@ #include <limits.h> -#include "v8.h" - -#include "api.h" -#include "isolate.h" -#include "compilation-cache.h" -#include "execution.h" -#include "snapshot.h" -#include "platform.h" -#include "utils.h" -#include "cctest.h" -#include "parser.h" -#include "unicode-inl.h" +#include "src/v8.h" + +#include "src/api.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/execution.h" +#include "src/isolate.h" +#include "src/parser.h" +#include "src/snapshot.h" +#include "src/unicode-inl.h" +#include "src/utils.h" +#include "test/cctest/cctest.h" using ::v8::Context; using ::v8::Extension; diff --git a/deps/v8/test/cctest/test-libplatform-default-platform.cc b/deps/v8/test/cctest/test-libplatform-default-platform.cc new file mode 100644 index 0000000000..dac6db2a00 --- /dev/null +++ b/deps/v8/test/cctest/test-libplatform-default-platform.cc @@ -0,0 +1,30 @@ +// 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 "src/libplatform/default-platform.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-libplatform.h" + +using namespace v8::internal; +using namespace v8::platform; + + +TEST(DefaultPlatformMessagePump) { + TaskCounter task_counter; + + DefaultPlatform platform; + + TestTask* task = new TestTask(&task_counter, true); + + CHECK(!platform.PumpMessageLoop(CcTest::isolate())); + + platform.CallOnForegroundThread(CcTest::isolate(), task); + + CHECK_EQ(1, task_counter.GetCount()); + CHECK(platform.PumpMessageLoop(CcTest::isolate())); + CHECK_EQ(0, task_counter.GetCount()); + CHECK(!platform.PumpMessageLoop(CcTest::isolate())); +} diff --git a/deps/v8/test/cctest/test-libplatform-task-queue.cc b/deps/v8/test/cctest/test-libplatform-task-queue.cc index 4765515763..630686b459 100644 --- a/deps/v8/test/cctest/test-libplatform-task-queue.cc +++ b/deps/v8/test/cctest/test-libplatform-task-queue.cc @@ -25,13 +25,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "libplatform/task-queue.h" -#include "test-libplatform.h" +#include "src/libplatform/task-queue.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-libplatform.h" using namespace v8::internal; +using namespace v8::platform; TEST(TaskQueueBasic) { diff --git a/deps/v8/test/cctest/test-libplatform-worker-thread.cc b/deps/v8/test/cctest/test-libplatform-worker-thread.cc index 090d6e1a18..ba6b51fd02 100644 --- a/deps/v8/test/cctest/test-libplatform-worker-thread.cc +++ b/deps/v8/test/cctest/test-libplatform-worker-thread.cc @@ -25,14 +25,15 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "libplatform/task-queue.h" -#include "libplatform/worker-thread.h" -#include "test-libplatform.h" +#include "src/libplatform/task-queue.h" +#include "src/libplatform/worker-thread.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-libplatform.h" using namespace v8::internal; +using namespace v8::platform; TEST(WorkerThread) { @@ -54,7 +55,7 @@ TEST(WorkerThread) { queue.Append(task3); queue.Append(task4); - // TaskQueue ASSERTs that it is empty in its destructor. + // TaskQueue DCHECKs that it is empty in its destructor. queue.Terminate(); delete thread1; diff --git a/deps/v8/test/cctest/test-libplatform.h b/deps/v8/test/cctest/test-libplatform.h index e32770eeda..67147f33e6 100644 --- a/deps/v8/test/cctest/test-libplatform.h +++ b/deps/v8/test/cctest/test-libplatform.h @@ -28,11 +28,12 @@ #ifndef TEST_LIBPLATFORM_H_ #define TEST_LIBPLATFORM_H_ -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8::internal; +using namespace v8::platform; class TaskCounter { public: @@ -40,22 +41,22 @@ class TaskCounter { ~TaskCounter() { CHECK_EQ(0, counter_); } int GetCount() const { - LockGuard<Mutex> guard(&lock_); + v8::base::LockGuard<v8::base::Mutex> guard(&lock_); return counter_; } void Inc() { - LockGuard<Mutex> guard(&lock_); + v8::base::LockGuard<v8::base::Mutex> guard(&lock_); ++counter_; } void Dec() { - LockGuard<Mutex> guard(&lock_); + v8::base::LockGuard<v8::base::Mutex> guard(&lock_); --counter_; } private: - mutable Mutex lock_; + mutable v8::base::Mutex lock_; int counter_; DISALLOW_COPY_AND_ASSIGN(TaskCounter); @@ -93,10 +94,12 @@ class TestTask : public v8::Task { }; -class TestWorkerThread : public Thread { +class TestWorkerThread : public v8::base::Thread { public: explicit TestWorkerThread(v8::Task* task) - : Thread("libplatform TestWorkerThread"), semaphore_(0), task_(task) {} + : Thread(Options("libplatform TestWorkerThread")), + semaphore_(0), + task_(task) {} virtual ~TestWorkerThread() {} void Signal() { semaphore_.Signal(); } @@ -111,7 +114,7 @@ class TestWorkerThread : public Thread { } private: - Semaphore semaphore_; + v8::base::Semaphore semaphore_; v8::Task* task_; DISALLOW_COPY_AND_ASSIGN(TestWorkerThread); diff --git a/deps/v8/test/cctest/test-list.cc b/deps/v8/test/cctest/test-list.cc index a29972b583..20c13f6e65 100644 --- a/deps/v8/test/cctest/test-list.cc +++ b/deps/v8/test/cctest/test-list.cc @@ -27,8 +27,8 @@ #include <stdlib.h> #include <string.h> -#include "v8.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-liveedit.cc b/deps/v8/test/cctest/test-liveedit.cc index 1c64108c8d..f5c22743bd 100644 --- a/deps/v8/test/cctest/test-liveedit.cc +++ b/deps/v8/test/cctest/test-liveedit.cc @@ -27,10 +27,10 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "liveedit.h" -#include "cctest.h" +#include "src/liveedit.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -117,12 +117,12 @@ void CompareStringsOneWay(const char* s1, const char* s2, int similar_part_length = diff_pos1 - pos1; int diff_pos2 = pos2 + similar_part_length; - ASSERT_EQ(diff_pos2, chunk->pos2); + DCHECK_EQ(diff_pos2, chunk->pos2); for (int j = 0; j < similar_part_length; j++) { - ASSERT(pos1 + j < len1); - ASSERT(pos2 + j < len2); - ASSERT_EQ(s1[pos1 + j], s2[pos2 + j]); + DCHECK(pos1 + j < len1); + DCHECK(pos2 + j < len2); + DCHECK_EQ(s1[pos1 + j], s2[pos2 + j]); } diff_parameter += chunk->len1 + chunk->len2; pos1 = diff_pos1 + chunk->len1; @@ -131,17 +131,17 @@ void CompareStringsOneWay(const char* s1, const char* s2, { // After last chunk. int similar_part_length = len1 - pos1; - ASSERT_EQ(similar_part_length, len2 - pos2); + DCHECK_EQ(similar_part_length, len2 - pos2); USE(len2); for (int j = 0; j < similar_part_length; j++) { - ASSERT(pos1 + j < len1); - ASSERT(pos2 + j < len2); - ASSERT_EQ(s1[pos1 + j], s2[pos2 + j]); + DCHECK(pos1 + j < len1); + DCHECK(pos2 + j < len2); + DCHECK_EQ(s1[pos1 + j], s2[pos2 + j]); } } if (expected_diff_parameter != -1) { - ASSERT_EQ(expected_diff_parameter, diff_parameter); + DCHECK_EQ(expected_diff_parameter, diff_parameter); } } diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc index 12b35a5c4d..ed315cea3d 100644 --- a/deps/v8/test/cctest/test-lockers.cc +++ b/deps/v8/test/cctest/test-lockers.cc @@ -27,19 +27,19 @@ #include <limits.h> -#include "v8.h" - -#include "api.h" -#include "isolate.h" -#include "compilation-cache.h" -#include "execution.h" -#include "smart-pointers.h" -#include "snapshot.h" -#include "platform.h" -#include "utils.h" -#include "cctest.h" -#include "parser.h" -#include "unicode-inl.h" +#include "src/v8.h" + +#include "src/api.h" +#include "src/base/platform/platform.h" +#include "src/compilation-cache.h" +#include "src/execution.h" +#include "src/isolate.h" +#include "src/parser.h" +#include "src/smart-pointers.h" +#include "src/snapshot.h" +#include "src/unicode-inl.h" +#include "src/utils.h" +#include "test/cctest/cctest.h" using ::v8::Context; using ::v8::Extension; @@ -56,10 +56,10 @@ using ::v8::V8; // Migrating an isolate -class KangarooThread : public v8::internal::Thread { +class KangarooThread : public v8::base::Thread { public: KangarooThread(v8::Isolate* isolate, v8::Handle<v8::Context> context) - : Thread("KangarooThread"), + : Thread(Options("KangarooThread")), isolate_(isolate), context_(isolate, context) {} @@ -146,12 +146,11 @@ class JoinableThread { virtual void Run() = 0; private: - class ThreadWithSemaphore : public i::Thread { + class ThreadWithSemaphore : public v8::base::Thread { public: explicit ThreadWithSemaphore(JoinableThread* joinable_thread) - : Thread(joinable_thread->name_), - joinable_thread_(joinable_thread) { - } + : Thread(Options(joinable_thread->name_)), + joinable_thread_(joinable_thread) {} virtual void Run() { joinable_thread_->Run(); @@ -163,7 +162,7 @@ class JoinableThread { }; const char* name_; - i::Semaphore semaphore_; + v8::base::Semaphore semaphore_; ThreadWithSemaphore thread_; friend class ThreadWithSemaphore; @@ -223,9 +222,7 @@ TEST(IsolateLockingStress) { class IsolateNonlockingThread : public JoinableThread { public: - explicit IsolateNonlockingThread() - : JoinableThread("IsolateNonlockingThread") { - } + IsolateNonlockingThread() : JoinableThread("IsolateNonlockingThread") {} virtual void Run() { v8::Isolate* isolate = v8::Isolate::New(); @@ -247,6 +244,8 @@ class IsolateNonlockingThread : public JoinableThread { TEST(MultithreadedParallelIsolates) { #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS const int kNThreads = 10; +#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT + const int kNThreads = 4; #else const int kNThreads = 50; #endif @@ -713,6 +712,8 @@ class IsolateGenesisThread : public JoinableThread { TEST(ExtensionsRegistration) { #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS const int kNThreads = 10; +#elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT + const int kNThreads = 4; #else const int kNThreads = 40; #endif diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc index 5b6858e553..334a201053 100644 --- a/deps/v8/test/cctest/test-log-stack-tracer.cc +++ b/deps/v8/test/cctest/test-log-stack-tracer.cc @@ -29,17 +29,17 @@ #include <stdlib.h> -#include "v8.h" - -#include "api.h" -#include "cctest.h" -#include "codegen.h" -#include "disassembler.h" -#include "isolate.h" -#include "log.h" -#include "sampler.h" -#include "trace-extension.h" -#include "vm-state-inl.h" +#include "src/v8.h" + +#include "src/api.h" +#include "src/codegen.h" +#include "src/disassembler.h" +#include "src/isolate.h" +#include "src/log.h" +#include "src/sampler.h" +#include "src/vm-state-inl.h" +#include "test/cctest/cctest.h" +#include "test/cctest/trace-extension.h" using v8::Function; using v8::Local; @@ -119,12 +119,12 @@ static void CreateTraceCallerFunction(v8::Local<v8::Context> context, const char* func_name, const char* trace_func_name) { i::EmbeddedVector<char, 256> trace_call_buf; - i::OS::SNPrintF(trace_call_buf, - "function %s() {" - " fp = new FPGrabber();" - " %s(fp.low_bits, fp.high_bits);" - "}", - func_name, trace_func_name); + i::SNPrintF(trace_call_buf, + "function %s() {" + " fp = new FPGrabber();" + " %s(fp.low_bits, fp.high_bits);" + "}", + func_name, trace_func_name); // Create the FPGrabber function, which grabs the caller's frame pointer // when called as a constructor. @@ -172,7 +172,7 @@ TEST(CFromJSStackTrace) { CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), sample.external_callback); // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" - int base = 0; + unsigned base = 0; CHECK_GT(sample.frames_count, base + 1); CHECK(IsAddressWithinFuncCode( @@ -225,7 +225,7 @@ TEST(PureJSStackTrace) { CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), sample.external_callback); // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" - int base = 0; + unsigned base = 0; CHECK_GT(sample.frames_count, base + 1); CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0])); CHECK(IsAddressWithinFuncCode( diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index e6ed75e64d..d72e6f0e1e 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -34,15 +34,16 @@ #include <cmath> #endif // __linux__ -#include "v8.h" -#include "log.h" -#include "log-utils.h" -#include "cpu-profiler.h" -#include "natives.h" -#include "utils.h" -#include "v8threads.h" -#include "cctest.h" -#include "vm-state-inl.h" +#include "src/v8.h" + +#include "src/cpu-profiler.h" +#include "src/log.h" +#include "src/log-utils.h" +#include "src/natives.h" +#include "src/utils.h" +#include "src/v8threads.h" +#include "src/vm-state-inl.h" +#include "test/cctest/cctest.h" using v8::internal::Address; using v8::internal::EmbeddedVector; @@ -112,7 +113,7 @@ class ScopedLoggerInitializer { static const char* StrNStr(const char* s1, const char* s2, int n) { if (s1[n] == '\0') return strstr(s1, s2); i::ScopedVector<char> str(n + 1); - i::OS::StrNCpy(str, s1, static_cast<size_t>(n)); + i::StrNCpy(str, s1, static_cast<size_t>(n)); str[n] = '\0'; char* found = strstr(str.start(), s2); return found != NULL ? s1 + (found - str.start()) : NULL; @@ -358,9 +359,9 @@ TEST(LogCallbacks) { CHECK(exists); i::EmbeddedVector<char, 100> ref_data; - i::OS::SNPrintF(ref_data, - "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"method1\"\0", - ObjMethod1); + i::SNPrintF(ref_data, + "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"method1\"", + reinterpret_cast<intptr_t>(ObjMethod1)); CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length())); log.Dispose(); @@ -402,23 +403,23 @@ TEST(LogAccessorCallbacks) { CHECK(exists); EmbeddedVector<char, 100> prop1_getter_record; - i::OS::SNPrintF(prop1_getter_record, - "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop1\"", - Prop1Getter); + i::SNPrintF(prop1_getter_record, + "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop1\"", + reinterpret_cast<intptr_t>(Prop1Getter)); CHECK_NE(NULL, StrNStr(log.start(), prop1_getter_record.start(), log.length())); EmbeddedVector<char, 100> prop1_setter_record; - i::OS::SNPrintF(prop1_setter_record, - "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"set prop1\"", - Prop1Setter); + i::SNPrintF(prop1_setter_record, + "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"set prop1\"", + reinterpret_cast<intptr_t>(Prop1Setter)); CHECK_NE(NULL, StrNStr(log.start(), prop1_setter_record.start(), log.length())); EmbeddedVector<char, 100> prop2_getter_record; - i::OS::SNPrintF(prop2_getter_record, - "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop2\"", - Prop2Getter); + i::SNPrintF(prop2_getter_record, + "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop2\"", + reinterpret_cast<intptr_t>(Prop2Getter)); CHECK_NE(NULL, StrNStr(log.start(), prop2_getter_record.start(), log.length())); log.Dispose(); diff --git a/deps/v8/test/cctest/test-macro-assembler-arm.cc b/deps/v8/test/cctest/test-macro-assembler-arm.cc index 8aed4c27b5..2cfad0df83 100644 --- a/deps/v8/test/cctest/test-macro-assembler-arm.cc +++ b/deps/v8/test/cctest/test-macro-assembler-arm.cc @@ -27,11 +27,13 @@ #include <stdlib.h> -#include "v8.h" -#include "macro-assembler.h" -#include "arm/macro-assembler-arm.h" -#include "arm/simulator-arm.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/macro-assembler.h" + +#include "src/arm/macro-assembler-arm.h" +#include "src/arm/simulator-arm.h" using namespace v8::internal; @@ -66,10 +68,12 @@ TEST(CopyBytes) { size_t act_size; // Allocate two blocks to copy data between. - byte* src_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0)); + byte* src_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); CHECK(src_buffer); CHECK(act_size >= static_cast<size_t>(data_size)); - byte* dest_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0)); + byte* dest_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); CHECK(dest_buffer); CHECK(act_size >= static_cast<size_t>(data_size)); @@ -137,9 +141,8 @@ TEST(LoadAndStoreWithRepresentation) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); diff --git a/deps/v8/test/cctest/test-macro-assembler-ia32.cc b/deps/v8/test/cctest/test-macro-assembler-ia32.cc index 3ad52712c4..4d37579918 100644 --- a/deps/v8/test/cctest/test-macro-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-macro-assembler-ia32.cc @@ -27,13 +27,13 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "macro-assembler.h" -#include "factory.h" -#include "platform.h" -#include "serialize.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" using namespace v8::internal; @@ -54,9 +54,8 @@ TEST(LoadAndStoreWithRepresentation) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -123,20 +122,17 @@ TEST(LoadAndStoreWithRepresentation) { __ j(not_equal, &exit); // Test 5. - if (CpuFeatures::IsSupported(SSE2)) { - CpuFeatureScope scope(masm, SSE2); - __ mov(eax, Immediate(5)); // Test XMM move immediate. - __ Move(xmm0, 0.0); - __ Move(xmm1, 0.0); - __ ucomisd(xmm0, xmm1); - __ j(not_equal, &exit); - __ Move(xmm2, 991.01); - __ ucomisd(xmm0, xmm2); - __ j(equal, &exit); - __ Move(xmm0, 991.01); - __ ucomisd(xmm0, xmm2); - __ j(not_equal, &exit); - } + __ mov(eax, Immediate(5)); // Test XMM move immediate. + __ Move(xmm0, 0.0); + __ Move(xmm1, 0.0); + __ ucomisd(xmm0, xmm1); + __ j(not_equal, &exit); + __ Move(xmm2, 991.01); + __ ucomisd(xmm0, xmm2); + __ j(equal, &exit); + __ Move(xmm0, 991.01); + __ ucomisd(xmm0, xmm2); + __ j(not_equal, &exit); // Test 6. __ mov(eax, Immediate(6)); diff --git a/deps/v8/test/cctest/test-macro-assembler-mips.cc b/deps/v8/test/cctest/test-macro-assembler-mips.cc index a5045a8f01..33a4611540 100644 --- a/deps/v8/test/cctest/test-macro-assembler-mips.cc +++ b/deps/v8/test/cctest/test-macro-assembler-mips.cc @@ -27,11 +27,12 @@ #include <stdlib.h> -#include "v8.h" -#include "macro-assembler.h" -#include "mips/macro-assembler-mips.h" -#include "mips/simulator-mips.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/macro-assembler.h" +#include "src/mips/macro-assembler-mips.h" +#include "src/mips/simulator-mips.h" using namespace v8::internal; @@ -66,10 +67,12 @@ TEST(CopyBytes) { size_t act_size; // Allocate two blocks to copy data between. - byte* src_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0)); + byte* src_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); CHECK(src_buffer); CHECK(act_size >= static_cast<size_t>(data_size)); - byte* dest_buffer = static_cast<byte*>(OS::Allocate(data_size, &act_size, 0)); + byte* dest_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); CHECK(dest_buffer); CHECK(act_size >= static_cast<size_t>(data_size)); diff --git a/deps/v8/test/cctest/test-macro-assembler-mips64.cc b/deps/v8/test/cctest/test-macro-assembler-mips64.cc new file mode 100644 index 0000000000..eef658de67 --- /dev/null +++ b/deps/v8/test/cctest/test-macro-assembler-mips64.cc @@ -0,0 +1,217 @@ +// 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. + +#include <stdlib.h> + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/macro-assembler.h" +#include "src/mips64/macro-assembler-mips64.h" +#include "src/mips64/simulator-mips64.h" + + +using namespace v8::internal; + +typedef void* (*F)(int64_t x, int64_t y, int p2, int p3, int p4); + +#define __ masm-> + + +static byte to_non_zero(int n) { + return static_cast<unsigned>(n) % 255 + 1; +} + + +static bool all_zeroes(const byte* beg, const byte* end) { + CHECK(beg); + CHECK(beg <= end); + while (beg < end) { + if (*beg++ != 0) + return false; + } + return true; +} + + +TEST(CopyBytes) { + CcTest::InitializeVM(); + Isolate* isolate = Isolate::Current(); + HandleScope handles(isolate); + + const int data_size = 1 * KB; + size_t act_size; + + // Allocate two blocks to copy data between. + byte* src_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); + CHECK(src_buffer); + CHECK(act_size >= static_cast<size_t>(data_size)); + byte* dest_buffer = + static_cast<byte*>(v8::base::OS::Allocate(data_size, &act_size, 0)); + CHECK(dest_buffer); + CHECK(act_size >= static_cast<size_t>(data_size)); + + // Storage for a0 and a1. + byte* a0_; + byte* a1_; + + MacroAssembler assembler(isolate, NULL, 0); + MacroAssembler* masm = &assembler; + + // Code to be generated: The stuff in CopyBytes followed by a store of a0 and + // a1, respectively. + __ CopyBytes(a0, a1, a2, a3); + __ li(a2, Operand(reinterpret_cast<int64_t>(&a0_))); + __ li(a3, Operand(reinterpret_cast<int64_t>(&a1_))); + __ sd(a0, MemOperand(a2)); + __ jr(ra); + __ sd(a1, MemOperand(a3)); + + CodeDesc desc; + masm->GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + ::F f = FUNCTION_CAST< ::F>(code->entry()); + + // Initialise source data with non-zero bytes. + for (int i = 0; i < data_size; i++) { + src_buffer[i] = to_non_zero(i); + } + + const int fuzz = 11; + + for (int size = 0; size < 600; size++) { + for (const byte* src = src_buffer; src < src_buffer + fuzz; src++) { + for (byte* dest = dest_buffer; dest < dest_buffer + fuzz; dest++) { + memset(dest_buffer, 0, data_size); + CHECK(dest + size < dest_buffer + data_size); + (void) CALL_GENERATED_CODE(f, reinterpret_cast<int64_t>(src), + reinterpret_cast<int64_t>(dest), + size, 0, 0); + // a0 and a1 should point at the first byte after the copied data. + CHECK_EQ(src + size, a0_); + CHECK_EQ(dest + size, a1_); + // Check that we haven't written outside the target area. + CHECK(all_zeroes(dest_buffer, dest)); + CHECK(all_zeroes(dest + size, dest_buffer + data_size)); + // Check the target area. + CHECK_EQ(0, memcmp(src, dest, size)); + } + } + } + + // Check that the source data hasn't been clobbered. + for (int i = 0; i < data_size; i++) { + CHECK(src_buffer[i] == to_non_zero(i)); + } +} + + +TEST(LoadConstants) { + CcTest::InitializeVM(); + Isolate* isolate = Isolate::Current(); + HandleScope handles(isolate); + + int64_t refConstants[64]; + int64_t result[64]; + + int64_t mask = 1; + for (int i = 0; i < 64; i++) { + refConstants[i] = ~(mask << i); + } + + MacroAssembler assembler(isolate, NULL, 0); + MacroAssembler* masm = &assembler; + + __ mov(a4, a0); + for (int i = 0; i < 64; i++) { + // Load constant. + __ li(a5, Operand(refConstants[i])); + __ sd(a5, MemOperand(a4)); + __ Daddu(a4, a4, Operand(kPointerSize)); + } + + __ jr(ra); + __ nop(); + + CodeDesc desc; + masm->GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + ::F f = FUNCTION_CAST< ::F>(code->entry()); + (void) CALL_GENERATED_CODE(f, reinterpret_cast<int64_t>(result), + 0, 0, 0, 0); + // Check results. + for (int i = 0; i < 64; i++) { + CHECK(refConstants[i] == result[i]); + } +} + + +TEST(LoadAddress) { + CcTest::InitializeVM(); + Isolate* isolate = Isolate::Current(); + HandleScope handles(isolate); + + MacroAssembler assembler(isolate, NULL, 0); + MacroAssembler* masm = &assembler; + Label to_jump, skip; + __ mov(a4, a0); + + __ Branch(&skip); + __ bind(&to_jump); + __ nop(); + __ nop(); + __ jr(ra); + __ nop(); + __ bind(&skip); + __ li(a4, Operand(masm->jump_address(&to_jump)), ADDRESS_LOAD); + int check_size = masm->InstructionsGeneratedSince(&skip); + CHECK_EQ(check_size, 4); + __ jr(a4); + __ nop(); + __ stop("invalid"); + __ stop("invalid"); + __ stop("invalid"); + __ stop("invalid"); + __ stop("invalid"); + + + CodeDesc desc; + masm->GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + ::F f = FUNCTION_CAST< ::F>(code->entry()); + (void) CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0); + // Check results. +} + +#undef __ diff --git a/deps/v8/test/cctest/test-macro-assembler-x64.cc b/deps/v8/test/cctest/test-macro-assembler-x64.cc index 609bc69956..2c0e918057 100644 --- a/deps/v8/test/cctest/test-macro-assembler-x64.cc +++ b/deps/v8/test/cctest/test-macro-assembler-x64.cc @@ -27,13 +27,13 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "macro-assembler.h" -#include "factory.h" -#include "platform.h" -#include "serialize.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" +#include "test/cctest/cctest.h" namespace i = v8::internal; using i::Address; @@ -46,7 +46,6 @@ using i::Immediate; using i::Isolate; using i::Label; using i::MacroAssembler; -using i::OS; using i::Operand; using i::RelocInfo; using i::Representation; @@ -157,9 +156,8 @@ TEST(SmiMove) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -207,7 +205,7 @@ void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) { __ movl(rax, Immediate(id + 2)); __ j(less_equal, exit); } else { - ASSERT_EQ(x, y); + DCHECK_EQ(x, y); __ movl(rax, Immediate(id + 3)); __ j(not_equal, exit); } @@ -224,7 +222,7 @@ void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) { __ movl(rax, Immediate(id + 9)); __ j(greater_equal, exit); } else { - ASSERT(y > x); + DCHECK(y > x); __ movl(rax, Immediate(id + 10)); __ j(less_equal, exit); } @@ -244,10 +242,8 @@ TEST(SmiCompare) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -295,9 +291,8 @@ TEST(Integer32ToSmi) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -399,7 +394,7 @@ void TestI64PlusConstantToSmi(MacroAssembler* masm, int64_t x, int y) { int64_t result = x + y; - ASSERT(Smi::IsValid(result)); + DCHECK(Smi::IsValid(result)); __ movl(rax, Immediate(id)); __ Move(r8, Smi::FromInt(static_cast<int>(result))); __ movq(rcx, x); @@ -423,9 +418,8 @@ TEST(Integer64PlusConstantToSmi) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -467,9 +461,8 @@ TEST(SmiCheck) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -714,10 +707,8 @@ TEST(SmiNeg) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -820,7 +811,7 @@ static void SmiAddOverflowTest(MacroAssembler* masm, int id, int x) { // Adds a Smi to x so that the addition overflows. - ASSERT(x != 0); // Can't overflow by adding a Smi. + DCHECK(x != 0); // Can't overflow by adding a Smi. int y_max = (x > 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue - x - 1); int y_min = (x > 0) ? (Smi::kMaxValue - x + 1) : (Smi::kMinValue + 0); @@ -930,10 +921,8 @@ TEST(SmiAdd) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 3, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1039,7 +1028,7 @@ static void SmiSubOverflowTest(MacroAssembler* masm, int id, int x) { // Subtracts a Smi from x so that the subtraction overflows. - ASSERT(x != -1); // Can't overflow by subtracting a Smi. + DCHECK(x != -1); // Can't overflow by subtracting a Smi. int y_max = (x < 0) ? (Smi::kMaxValue + 0) : (Smi::kMinValue + 0); int y_min = (x < 0) ? (Smi::kMaxValue + x + 2) : (Smi::kMinValue + x); @@ -1151,10 +1140,8 @@ TEST(SmiSub) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 4, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1242,9 +1229,8 @@ TEST(SmiMul) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1347,10 +1333,8 @@ TEST(SmiDiv) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1457,10 +1441,8 @@ TEST(SmiMod) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1515,7 +1497,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { for (int i = 0; i < 8; i++) { __ Move(rcx, Smi::FromInt(x)); SmiIndex index = masm->SmiToIndex(rdx, rcx, i); - ASSERT(index.reg.is(rcx) || index.reg.is(rdx)); + DCHECK(index.reg.is(rcx) || index.reg.is(rdx)); __ shlq(index.reg, Immediate(index.scale)); __ Set(r8, static_cast<intptr_t>(x) << i); __ cmpq(index.reg, r8); @@ -1523,7 +1505,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { __ incq(rax); __ Move(rcx, Smi::FromInt(x)); index = masm->SmiToIndex(rcx, rcx, i); - ASSERT(index.reg.is(rcx)); + DCHECK(index.reg.is(rcx)); __ shlq(rcx, Immediate(index.scale)); __ Set(r8, static_cast<intptr_t>(x) << i); __ cmpq(rcx, r8); @@ -1532,7 +1514,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { __ Move(rcx, Smi::FromInt(x)); index = masm->SmiToNegativeIndex(rdx, rcx, i); - ASSERT(index.reg.is(rcx) || index.reg.is(rdx)); + DCHECK(index.reg.is(rcx) || index.reg.is(rdx)); __ shlq(index.reg, Immediate(index.scale)); __ Set(r8, static_cast<intptr_t>(-x) << i); __ cmpq(index.reg, r8); @@ -1540,7 +1522,7 @@ void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { __ incq(rax); __ Move(rcx, Smi::FromInt(x)); index = masm->SmiToNegativeIndex(rcx, rcx, i); - ASSERT(index.reg.is(rcx)); + DCHECK(index.reg.is(rcx)); __ shlq(rcx, Immediate(index.scale)); __ Set(r8, static_cast<intptr_t>(-x) << i); __ cmpq(rcx, r8); @@ -1554,10 +1536,8 @@ TEST(SmiIndex) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 5, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 5, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1623,10 +1603,8 @@ TEST(SmiSelectNonSmi) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1702,10 +1680,8 @@ TEST(SmiAnd) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1783,10 +1759,8 @@ TEST(SmiOr) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1866,10 +1840,8 @@ TEST(SmiXor) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -1933,10 +1905,8 @@ TEST(SmiNot) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2029,10 +1999,8 @@ TEST(SmiShiftLeft) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 7, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 7, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2135,10 +2103,8 @@ TEST(SmiShiftLogicalRight) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 5, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 5, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2204,10 +2170,8 @@ TEST(SmiShiftArithmeticRight) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 3, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2239,7 +2203,7 @@ TEST(SmiShiftArithmeticRight) { void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) { - ASSERT(x >= 0); + DCHECK(x >= 0); int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 }; int power_count = 8; __ movl(rax, Immediate(id)); @@ -2268,10 +2232,8 @@ TEST(PositiveSmiTimesPowerOfTwoToInteger64) { i::V8::Initialize(NULL); // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 4, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 4, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2311,10 +2273,8 @@ TEST(OperandOffset) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = - static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize * 2, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); @@ -2665,9 +2625,8 @@ TEST(LoadAndStoreWithRepresentation) { // Allocate an executable page of memory. size_t actual_size; - byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, - &actual_size, - true)); + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); CHECK(buffer); Isolate* isolate = CcTest::i_isolate(); HandleScope handles(isolate); diff --git a/deps/v8/test/cctest/test-macro-assembler-x87.cc b/deps/v8/test/cctest/test-macro-assembler-x87.cc new file mode 100644 index 0000000000..9aa40c0b10 --- /dev/null +++ b/deps/v8/test/cctest/test-macro-assembler-x87.cc @@ -0,0 +1,150 @@ +// 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. + +#include <stdlib.h> + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/base/platform/platform.h" +#include "src/factory.h" +#include "src/macro-assembler.h" +#include "src/serialize.h" + +using namespace v8::internal; + +#if __GNUC__ +#define STDCALL __attribute__((stdcall)) +#else +#define STDCALL __stdcall +#endif + +typedef int STDCALL F0Type(); +typedef F0Type* F0; + +#define __ masm-> + + +TEST(LoadAndStoreWithRepresentation) { + v8::internal::V8::Initialize(NULL); + + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(v8::base::OS::Allocate( + Assembler::kMinimalBufferSize, &actual_size, true)); + CHECK(buffer); + Isolate* isolate = CcTest::i_isolate(); + HandleScope handles(isolate); + MacroAssembler assembler(isolate, buffer, static_cast<int>(actual_size)); + MacroAssembler* masm = &assembler; // Create a pointer for the __ macro. + __ push(ebx); + __ push(edx); + __ sub(esp, Immediate(1 * kPointerSize)); + Label exit; + + // Test 1. + __ mov(eax, Immediate(1)); // Test number. + __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); + __ mov(ebx, Immediate(-1)); + __ Store(ebx, Operand(esp, 0 * kPointerSize), Representation::UInteger8()); + __ mov(ebx, Operand(esp, 0 * kPointerSize)); + __ mov(edx, Immediate(255)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + __ Load(ebx, Operand(esp, 0 * kPointerSize), Representation::UInteger8()); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + + + // Test 2. + __ mov(eax, Immediate(2)); // Test number. + __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); + __ mov(ebx, Immediate(-1)); + __ Store(ebx, Operand(esp, 0 * kPointerSize), Representation::Integer8()); + __ mov(ebx, Operand(esp, 0 * kPointerSize)); + __ mov(edx, Immediate(255)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + __ Load(ebx, Operand(esp, 0 * kPointerSize), Representation::Integer8()); + __ mov(edx, Immediate(-1)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + + // Test 3. + __ mov(eax, Immediate(3)); // Test number. + __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); + __ mov(ebx, Immediate(-1)); + __ Store(ebx, Operand(esp, 0 * kPointerSize), Representation::Integer16()); + __ mov(ebx, Operand(esp, 0 * kPointerSize)); + __ mov(edx, Immediate(65535)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + __ Load(edx, Operand(esp, 0 * kPointerSize), Representation::Integer16()); + __ mov(ebx, Immediate(-1)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + + // Test 4. + __ mov(eax, Immediate(4)); // Test number. + __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); + __ mov(ebx, Immediate(-1)); + __ Store(ebx, Operand(esp, 0 * kPointerSize), Representation::UInteger16()); + __ mov(ebx, Operand(esp, 0 * kPointerSize)); + __ mov(edx, Immediate(65535)); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + __ Load(edx, Operand(esp, 0 * kPointerSize), Representation::UInteger16()); + __ cmp(ebx, edx); + __ j(not_equal, &exit); + + // Test 5. + __ mov(eax, Immediate(5)); + __ Move(edx, Immediate(0)); // Test Move() + __ cmp(edx, Immediate(0)); + __ j(not_equal, &exit); + __ Move(ecx, Immediate(-1)); + __ cmp(ecx, Immediate(-1)); + __ j(not_equal, &exit); + __ Move(ebx, Immediate(0x77)); + __ cmp(ebx, Immediate(0x77)); + __ j(not_equal, &exit); + + __ xor_(eax, eax); // Success. + __ bind(&exit); + __ add(esp, Immediate(1 * kPointerSize)); + __ pop(edx); + __ pop(ebx); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + +#undef __ diff --git a/deps/v8/test/cctest/test-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc index 5f13bd25ab..1d4b0d8e7d 100644 --- a/deps/v8/test/cctest/test-mark-compact.cc +++ b/deps/v8/test/cctest/test-mark-compact.cc @@ -28,21 +28,21 @@ #include <stdlib.h> #ifdef __linux__ -#include <sys/types.h> -#include <sys/stat.h> +#include <errno.h> #include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> -#include <errno.h> #endif #include <utility> -#include "v8.h" +#include "src/v8.h" -#include "full-codegen.h" -#include "global-handles.h" -#include "snapshot.h" -#include "cctest.h" +#include "src/full-codegen.h" +#include "src/global-handles.h" +#include "src/snapshot.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -77,7 +77,7 @@ TEST(MarkingDeque) { TEST(Promotion) { CcTest::InitializeVM(); TestHeap* heap = CcTest::test_heap(); - heap->ConfigureHeap(2*256*KB, 1*MB, 1*MB, 0); + heap->ConfigureHeap(1, 1, 1, 0); v8::HandleScope sc(CcTest::isolate()); @@ -92,7 +92,8 @@ TEST(Promotion) { CHECK(heap->InSpace(*array, NEW_SPACE)); // Call mark compact GC, so array becomes an old object. - heap->CollectGarbage(OLD_POINTER_SPACE); + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); // Array now sits in the old space CHECK(heap->InSpace(*array, OLD_POINTER_SPACE)); @@ -102,7 +103,7 @@ TEST(Promotion) { TEST(NoPromotion) { CcTest::InitializeVM(); TestHeap* heap = CcTest::test_heap(); - heap->ConfigureHeap(2*256*KB, 1*MB, 1*MB, 0); + heap->ConfigureHeap(1, 1, 1, 0); v8::HandleScope sc(CcTest::isolate()); @@ -156,12 +157,8 @@ TEST(MarkCompactCollector) { { HandleScope scope(isolate); // allocate a garbage Handle<String> func_name = factory->InternalizeUtf8String("theFunction"); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - func_name, factory->undefined_value()); - Handle<Map> initial_map = factory->NewMap( - JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); - JSReceiver::SetProperty(global, func_name, function, NONE, SLOPPY).Check(); + Handle<JSFunction> function = factory->NewFunction(func_name); + JSReceiver::SetProperty(global, func_name, function, SLOPPY).Check(); factory->NewJSObject(function); } @@ -170,7 +167,9 @@ TEST(MarkCompactCollector) { { HandleScope scope(isolate); Handle<String> func_name = factory->InternalizeUtf8String("theFunction"); - CHECK(JSReceiver::HasLocalProperty(global, func_name)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, func_name); + CHECK(maybe.has_value); + CHECK(maybe.value); Handle<Object> func_value = Object::GetProperty(global, func_name).ToHandleChecked(); CHECK(func_value->IsJSFunction()); @@ -178,17 +177,19 @@ TEST(MarkCompactCollector) { Handle<JSObject> obj = factory->NewJSObject(function); Handle<String> obj_name = factory->InternalizeUtf8String("theObject"); - JSReceiver::SetProperty(global, obj_name, obj, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(global, obj_name, obj, SLOPPY).Check(); Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); Handle<Smi> twenty_three(Smi::FromInt(23), isolate); - JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); } heap->CollectGarbage(OLD_POINTER_SPACE, "trigger 5"); { HandleScope scope(isolate); Handle<String> obj_name = factory->InternalizeUtf8String("theObject"); - CHECK(JSReceiver::HasLocalProperty(global, obj_name)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, obj_name); + CHECK(maybe.has_value); + CHECK(maybe.value); Handle<Object> object = Object::GetProperty(global, obj_name).ToHandleChecked(); CHECK(object->IsJSObject()); @@ -240,7 +241,7 @@ static void WeakPointerCallback( std::pair<v8::Persistent<v8::Value>*, int>* p = reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>( data.GetParameter()); - ASSERT_EQ(1234, p->second); + DCHECK_EQ(1234, p->second); NumberOfWeakCalls++; p->first->Reset(); } @@ -365,7 +366,7 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo { bool has_been_disposed() { return has_been_disposed_; } virtual void Dispose() { - ASSERT(!has_been_disposed_); + DCHECK(!has_been_disposed_); has_been_disposed_ = true; } @@ -393,7 +394,7 @@ TEST(EmptyObjectGroups) { TestRetainedObjectInfo info; global_handles->AddObjectGroup(NULL, 0, &info); - ASSERT(info.has_been_disposed()); + DCHECK(info.has_been_disposed()); global_handles->AddImplicitReferences( Handle<HeapObject>::cast(object).location(), NULL, 0); diff --git a/deps/v8/test/cctest/test-mementos.cc b/deps/v8/test/cctest/test-mementos.cc index a377b4a4c6..4c85151b88 100644 --- a/deps/v8/test/cctest/test-mementos.cc +++ b/deps/v8/test/cctest/test-mementos.cc @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -89,10 +89,7 @@ TEST(PretenuringCallNew) { Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); - // We need to create several instances to get past the slack-tracking - // phase, where mementos aren't emitted. int call_count = 10; - CHECK_GE(call_count, SharedFunctionInfo::kGenerousAllocationCount); i::ScopedVector<char> test_buf(1024); const char* program = "function f() {" @@ -105,7 +102,7 @@ TEST(PretenuringCallNew) { " a = new f();" "}" "a;"; - i::OS::SNPrintF(test_buf, program, call_count); + i::SNPrintF(test_buf, program, call_count); v8::Local<v8::Value> res = CompileRun(test_buf.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -117,8 +114,8 @@ TEST(PretenuringCallNew) { CHECK_EQ(memento->map(), heap->allocation_memento_map()); // Furthermore, how many mementos did we create? The count should match - // call_count - SharedFunctionInfo::kGenerousAllocationCount. + // call_count. Note, that mementos are allocated during the inobject slack + // tracking phase. AllocationSite* site = memento->GetAllocationSite(); - CHECK_EQ(call_count - SharedFunctionInfo::kGenerousAllocationCount, - site->pretenure_create_count()->value()); + CHECK_EQ(call_count, site->pretenure_create_count()->value()); } diff --git a/deps/v8/test/cctest/test-microtask-delivery.cc b/deps/v8/test/cctest/test-microtask-delivery.cc index e6f38b79bc..082bc1a3ed 100644 --- a/deps/v8/test/cctest/test-microtask-delivery.cc +++ b/deps/v8/test/cctest/test-microtask-delivery.cc @@ -25,9 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8; namespace i = v8::internal; diff --git a/deps/v8/test/cctest/test-mutex.cc b/deps/v8/test/cctest/test-mutex.cc deleted file mode 100644 index cdc829f156..0000000000 --- a/deps/v8/test/cctest/test-mutex.cc +++ /dev/null @@ -1,118 +0,0 @@ -// 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. - -#include <cstdlib> - -#include "v8.h" - -#include "cctest.h" -#include "platform/mutex.h" - -using namespace ::v8::internal; - - -TEST(LockGuardMutex) { - Mutex mutex; - { LockGuard<Mutex> lock_guard(&mutex); - } - { LockGuard<Mutex> lock_guard(&mutex); - } -} - - -TEST(LockGuardRecursiveMutex) { - RecursiveMutex recursive_mutex; - { LockGuard<RecursiveMutex> lock_guard(&recursive_mutex); - } - { LockGuard<RecursiveMutex> lock_guard1(&recursive_mutex); - LockGuard<RecursiveMutex> lock_guard2(&recursive_mutex); - } -} - - -TEST(LockGuardLazyMutex) { - LazyMutex lazy_mutex = LAZY_MUTEX_INITIALIZER; - { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); - } - { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer()); - } -} - - -TEST(LockGuardLazyRecursiveMutex) { - LazyRecursiveMutex lazy_recursive_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER; - { LockGuard<RecursiveMutex> lock_guard(lazy_recursive_mutex.Pointer()); - } - { LockGuard<RecursiveMutex> lock_guard1(lazy_recursive_mutex.Pointer()); - LockGuard<RecursiveMutex> lock_guard2(lazy_recursive_mutex.Pointer()); - } -} - - -TEST(MultipleMutexes) { - Mutex mutex1; - Mutex mutex2; - Mutex mutex3; - // Order 1 - mutex1.Lock(); - mutex2.Lock(); - mutex3.Lock(); - mutex1.Unlock(); - mutex2.Unlock(); - mutex3.Unlock(); - // Order 2 - mutex1.Lock(); - mutex2.Lock(); - mutex3.Lock(); - mutex3.Unlock(); - mutex2.Unlock(); - mutex1.Unlock(); -} - - -TEST(MultipleRecursiveMutexes) { - RecursiveMutex recursive_mutex1; - RecursiveMutex recursive_mutex2; - // Order 1 - recursive_mutex1.Lock(); - recursive_mutex2.Lock(); - CHECK(recursive_mutex1.TryLock()); - CHECK(recursive_mutex2.TryLock()); - recursive_mutex1.Unlock(); - recursive_mutex1.Unlock(); - recursive_mutex2.Unlock(); - recursive_mutex2.Unlock(); - // Order 2 - recursive_mutex1.Lock(); - CHECK(recursive_mutex1.TryLock()); - recursive_mutex2.Lock(); - CHECK(recursive_mutex2.TryLock()); - recursive_mutex2.Unlock(); - recursive_mutex1.Unlock(); - recursive_mutex2.Unlock(); - recursive_mutex1.Unlock(); -} diff --git a/deps/v8/test/cctest/test-object-observe.cc b/deps/v8/test/cctest/test-object-observe.cc index a7b346fc6f..679569e27c 100644 --- a/deps/v8/test/cctest/test-object-observe.cc +++ b/deps/v8/test/cctest/test-object-observe.cc @@ -25,9 +25,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" +#include "test/cctest/cctest.h" using namespace v8; namespace i = v8::internal; @@ -275,8 +275,8 @@ TEST(APITestBasicMutation) { // Setting an indexed element via the property setting method obj->Set(Number::New(v8_isolate, 1), Number::New(v8_isolate, 5)); // Setting with a non-String, non-uint32 key - obj->Set(Number::New(v8_isolate, 1.1), - Number::New(v8_isolate, 6), DontDelete); + obj->ForceSet(Number::New(v8_isolate, 1.1), Number::New(v8_isolate, 6), + DontDelete); obj->Delete(String::NewFromUtf8(v8_isolate, "foo")); obj->Delete(1); obj->ForceDelete(Number::New(v8_isolate, 1.1)); @@ -616,7 +616,6 @@ TEST(GetNotifierFromSameOrigin) { static int GetGlobalObjectsCount() { - CcTest::heap()->EnsureHeapIsIterable(); int count = 0; i::HeapIterator it(CcTest::heap()); for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) @@ -659,7 +658,7 @@ TEST(DontLeakContextOnObserve) { "Object.unobserve(obj, observer);"); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(1); } @@ -680,7 +679,7 @@ TEST(DontLeakContextOnGetNotifier) { CompileRun("Object.getNotifier(obj);"); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(1); } @@ -707,6 +706,6 @@ TEST(DontLeakContextOnNotifierPerformChange) { "notifier, 'foo', function(){})"); } - v8::V8::ContextDisposedNotification(); + CcTest::isolate()->ContextDisposedNotification(); CheckSurvivingGlobalObjectsCount(1); } diff --git a/deps/v8/test/cctest/test-ordered-hash-table.cc b/deps/v8/test/cctest/test-ordered-hash-table.cc index 48a457f5ee..bb1e0145b5 100644 --- a/deps/v8/test/cctest/test-ordered-hash-table.cc +++ b/deps/v8/test/cctest/test-ordered-hash-table.cc @@ -27,34 +27,17 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "factory.h" +#include "src/factory.h" +#include "test/cctest/cctest.h" namespace { using namespace v8::internal; -void CheckIterResultObject(Isolate* isolate, - Handle<JSObject> result, - Handle<Object> value, - bool done) { - Handle<Object> value_object = - Object::GetProperty(isolate, result, "value").ToHandleChecked(); - Handle<Object> done_object = - Object::GetProperty(isolate, result, "done").ToHandleChecked(); - - CHECK_EQ(*value_object, *value); - CHECK(done_object->IsBoolean()); - CHECK_EQ(done_object->BooleanValue(), done); -} - - TEST(Set) { - i::FLAG_harmony_collections = true; - LocalContext context; Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); @@ -64,21 +47,22 @@ TEST(Set) { CHECK_EQ(0, ordered_set->NumberOfElements()); CHECK_EQ(0, ordered_set->NumberOfDeletedElements()); - Handle<JSSetIterator> value_iterator = - JSSetIterator::Create(ordered_set, JSSetIterator::kKindValues); - Handle<JSSetIterator> value_iterator_2 = - JSSetIterator::Create(ordered_set, JSSetIterator::kKindValues); - Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); Handle<JSObject> obj = factory->NewJSObjectFromMap(map); CHECK(!ordered_set->Contains(obj)); ordered_set = OrderedHashSet::Add(ordered_set, obj); CHECK_EQ(1, ordered_set->NumberOfElements()); CHECK(ordered_set->Contains(obj)); - ordered_set = OrderedHashSet::Remove(ordered_set, obj); + bool was_present = false; + ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present); + CHECK(was_present); CHECK_EQ(0, ordered_set->NumberOfElements()); CHECK(!ordered_set->Contains(obj)); + // Removing a not-present object should set was_present to false. + ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present); + CHECK(!was_present); + // Test for collisions/chaining Handle<JSObject> obj1 = factory->NewJSObjectFromMap(map); ordered_set = OrderedHashSet::Add(ordered_set, obj1); @@ -91,18 +75,6 @@ TEST(Set) { CHECK(ordered_set->Contains(obj2)); CHECK(ordered_set->Contains(obj3)); - // Test iteration - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator), obj1, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator), obj2, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator), obj3, false); - CheckIterResultObject(isolate, - JSSetIterator::Next(value_iterator), - factory->undefined_value(), - true); - // Test growth ordered_set = OrderedHashSet::Add(ordered_set, obj); Handle<JSObject> obj4 = factory->NewJSObjectFromMap(map); @@ -116,35 +88,21 @@ TEST(Set) { CHECK_EQ(0, ordered_set->NumberOfDeletedElements()); CHECK_EQ(4, ordered_set->NumberOfBuckets()); - // Test iteration after growth - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator_2), obj1, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator_2), obj2, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator_2), obj3, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator_2), obj, false); - CheckIterResultObject( - isolate, JSSetIterator::Next(value_iterator_2), obj4, false); - CheckIterResultObject(isolate, - JSSetIterator::Next(value_iterator_2), - factory->undefined_value(), - true); - // Test shrinking - ordered_set = OrderedHashSet::Remove(ordered_set, obj); - ordered_set = OrderedHashSet::Remove(ordered_set, obj1); - ordered_set = OrderedHashSet::Remove(ordered_set, obj2); - ordered_set = OrderedHashSet::Remove(ordered_set, obj3); + ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present); + CHECK(was_present); + ordered_set = OrderedHashSet::Remove(ordered_set, obj1, &was_present); + CHECK(was_present); + ordered_set = OrderedHashSet::Remove(ordered_set, obj2, &was_present); + CHECK(was_present); + ordered_set = OrderedHashSet::Remove(ordered_set, obj3, &was_present); + CHECK(was_present); CHECK_EQ(1, ordered_set->NumberOfElements()); CHECK_EQ(2, ordered_set->NumberOfBuckets()); } TEST(Map) { - i::FLAG_harmony_collections = true; - LocalContext context; Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); @@ -154,11 +112,6 @@ TEST(Map) { CHECK_EQ(0, ordered_map->NumberOfElements()); CHECK_EQ(0, ordered_map->NumberOfDeletedElements()); - Handle<JSMapIterator> value_iterator = - JSMapIterator::Create(ordered_map, JSMapIterator::kKindValues); - Handle<JSMapIterator> key_iterator = - JSMapIterator::Create(ordered_map, JSMapIterator::kKindKeys); - Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); Handle<JSObject> obj = factory->NewJSObjectFromMap(map); Handle<JSObject> val = factory->NewJSObjectFromMap(map); @@ -166,8 +119,9 @@ TEST(Map) { ordered_map = OrderedHashMap::Put(ordered_map, obj, val); CHECK_EQ(1, ordered_map->NumberOfElements()); CHECK(ordered_map->Lookup(obj)->SameValue(*val)); - ordered_map = OrderedHashMap::Put( - ordered_map, obj, factory->the_hole_value()); + bool was_present = false; + ordered_map = OrderedHashMap::Remove(ordered_map, obj, &was_present); + CHECK(was_present); CHECK_EQ(0, ordered_map->NumberOfElements()); CHECK(ordered_map->Lookup(obj)->IsTheHole()); @@ -186,18 +140,6 @@ TEST(Map) { CHECK(ordered_map->Lookup(obj2)->SameValue(*val2)); CHECK(ordered_map->Lookup(obj3)->SameValue(*val3)); - // Test iteration - CheckIterResultObject( - isolate, JSMapIterator::Next(value_iterator), val1, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(value_iterator), val2, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(value_iterator), val3, false); - CheckIterResultObject(isolate, - JSMapIterator::Next(value_iterator), - factory->undefined_value(), - true); - // Test growth ordered_map = OrderedHashMap::Put(ordered_map, obj, val); Handle<JSObject> obj4 = factory->NewJSObjectFromMap(map); @@ -211,31 +153,15 @@ TEST(Map) { CHECK_EQ(5, ordered_map->NumberOfElements()); CHECK_EQ(4, ordered_map->NumberOfBuckets()); - // Test iteration after growth - CheckIterResultObject( - isolate, JSMapIterator::Next(key_iterator), obj1, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(key_iterator), obj2, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(key_iterator), obj3, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(key_iterator), obj, false); - CheckIterResultObject( - isolate, JSMapIterator::Next(key_iterator), obj4, false); - CheckIterResultObject(isolate, - JSMapIterator::Next(key_iterator), - factory->undefined_value(), - true); - // Test shrinking - ordered_map = OrderedHashMap::Put( - ordered_map, obj, factory->the_hole_value()); - ordered_map = OrderedHashMap::Put( - ordered_map, obj1, factory->the_hole_value()); - ordered_map = OrderedHashMap::Put( - ordered_map, obj2, factory->the_hole_value()); - ordered_map = OrderedHashMap::Put( - ordered_map, obj3, factory->the_hole_value()); + ordered_map = OrderedHashMap::Remove(ordered_map, obj, &was_present); + CHECK(was_present); + ordered_map = OrderedHashMap::Remove(ordered_map, obj1, &was_present); + CHECK(was_present); + ordered_map = OrderedHashMap::Remove(ordered_map, obj2, &was_present); + CHECK(was_present); + ordered_map = OrderedHashMap::Remove(ordered_map, obj3, &was_present); + CHECK(was_present); CHECK_EQ(1, ordered_map->NumberOfElements()); CHECK_EQ(2, ordered_map->NumberOfBuckets()); } diff --git a/deps/v8/test/cctest/test-ostreams.cc b/deps/v8/test/cctest/test-ostreams.cc new file mode 100644 index 0000000000..c83f96d466 --- /dev/null +++ b/deps/v8/test/cctest/test-ostreams.cc @@ -0,0 +1,148 @@ +// 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 <string.h> +#include <limits> + +#include "include/v8stdint.h" +#include "src/ostreams.h" +#include "test/cctest/cctest.h" + +using namespace v8::internal; + + +TEST(OStringStreamConstructor) { + OStringStream oss; + const size_t expected_size = 0; + CHECK(expected_size == oss.size()); + CHECK_GT(oss.capacity(), 0); + CHECK_NE(NULL, oss.data()); + CHECK_EQ("", oss.c_str()); +} + + +#define TEST_STRING \ + "Ash nazg durbatuluk, " \ + "ash nazg gimbatul, " \ + "ash nazg thrakatuluk, " \ + "agh burzum-ishi krimpatul." + +TEST(OStringStreamGrow) { + OStringStream oss; + const int repeat = 30; + size_t len = strlen(TEST_STRING); + for (int i = 0; i < repeat; ++i) { + oss.write(TEST_STRING, len); + } + const char* expected = + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING + TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING; + const size_t expected_len = len * repeat; + CHECK(expected_len == oss.size()); + CHECK_GT(oss.capacity(), 0); + CHECK_EQ(0, strncmp(expected, oss.data(), expected_len)); + CHECK_EQ(expected, oss.c_str()); +} + + +template <class T> +static void check(const char* expected, T value) { + OStringStream oss; + oss << value << " " << hex << value; + CHECK_EQ(expected, oss.c_str()); +} + + +TEST(NumericFormatting) { + check<bool>("0 0", false); + check<bool>("1 1", true); + + check<int16_t>("-12345 cfc7", -12345); + check<int16_t>("-32768 8000", std::numeric_limits<int16_t>::min()); + check<int16_t>("32767 7fff", std::numeric_limits<int16_t>::max()); + + check<uint16_t>("34567 8707", 34567); + check<uint16_t>("0 0", std::numeric_limits<uint16_t>::min()); + check<uint16_t>("65535 ffff", std::numeric_limits<uint16_t>::max()); + + check<int32_t>("-1234567 ffed2979", -1234567); + check<int32_t>("-2147483648 80000000", std::numeric_limits<int32_t>::min()); + check<int32_t>("2147483647 7fffffff", std::numeric_limits<int32_t>::max()); + + check<uint32_t>("3456789 34bf15", 3456789); + check<uint32_t>("0 0", std::numeric_limits<uint32_t>::min()); + check<uint32_t>("4294967295 ffffffff", std::numeric_limits<uint32_t>::max()); + + check<int64_t>("-1234567 ffffffffffed2979", -1234567); + check<int64_t>("-9223372036854775808 8000000000000000", + std::numeric_limits<int64_t>::min()); + check<int64_t>("9223372036854775807 7fffffffffffffff", + std::numeric_limits<int64_t>::max()); + + check<uint64_t>("3456789 34bf15", 3456789); + check<uint64_t>("0 0", std::numeric_limits<uint64_t>::min()); + check<uint64_t>("18446744073709551615 ffffffffffffffff", + std::numeric_limits<uint64_t>::max()); + + check<float>("0 0", 0.0f); + check<float>("123 123", 123.0f); + check<float>("-0.5 -0.5", -0.5f); + check<float>("1.25 1.25", 1.25f); + check<float>("0.0625 0.0625", 6.25e-2f); + + check<double>("0 0", 0.0); + check<double>("123 123", 123.0); + check<double>("-0.5 -0.5", -0.5); + check<double>("1.25 1.25", 1.25); + check<double>("0.0625 0.0625", 6.25e-2); +} + + +TEST(CharacterOutput) { + check<char>("a a", 'a'); + check<signed char>("B B", 'B'); + check<unsigned char>("9 9", '9'); + check<const char*>("bye bye", "bye"); + + OStringStream os; + os.put('H').write("ello", 4); + CHECK_EQ("Hello", os.c_str()); +} + + +TEST(Manipulators) { + OStringStream os; + os << 123 << hex << 123 << endl << 123 << dec << 123 << 123; + CHECK_EQ("1237b\n7b123123", os.c_str()); +} + + +class MiscStuff { + public: + MiscStuff(int i, double d, const char* s) : i_(i), d_(d), s_(s) { } + + private: + friend OStream& operator<<(OStream& os, const MiscStuff& m); + + int i_; + double d_; + const char* s_; +}; + + +OStream& operator<<(OStream& os, const MiscStuff& m) { + return os << "{i:" << m.i_ << ", d:" << m.d_ << ", s:'" << m.s_ << "'}"; +} + + +TEST(CustomOutput) { + OStringStream os; + MiscStuff m(123, 4.5, "Hurz!"); + os << m; + CHECK_EQ("{i:123, d:4.5, s:'Hurz!'}", os.c_str()); +} diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc index 58734d054e..9cb5d69e6c 100644 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -25,22 +25,25 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include "v8.h" +#include "src/v8.h" + +#include "src/ast-value-factory.h" +#include "src/compiler.h" +#include "src/execution.h" +#include "src/isolate.h" +#include "src/objects.h" +#include "src/parser.h" +#include "src/preparser.h" +#include "src/rewriter.h" +#include "src/scanner-character-streams.h" +#include "src/token.h" +#include "src/utils.h" -#include "cctest.h" -#include "compiler.h" -#include "execution.h" -#include "isolate.h" -#include "objects.h" -#include "parser.h" -#include "preparser.h" -#include "scanner-character-streams.h" -#include "token.h" -#include "utils.h" +#include "test/cctest/cctest.h" TEST(ScanKeywords) { struct KeywordToken { @@ -84,7 +87,7 @@ TEST(ScanKeywords) { // Adding characters will make keyword matching fail. static const char chars_to_append[] = { 'z', '0', '_' }; for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) { - i::OS::MemMove(buffer, keyword, length); + i::MemMove(buffer, keyword, length); buffer[length] = chars_to_append[j]; i::Utf8ToUtf16CharacterStream stream(buffer, length + 1); i::Scanner scanner(&unicode_cache); @@ -94,7 +97,7 @@ TEST(ScanKeywords) { } // Replacing characters will make keyword matching fail. { - i::OS::MemMove(buffer, keyword, length); + i::MemMove(buffer, keyword, length); buffer[length - 1] = '_'; i::Utf8ToUtf16CharacterStream stream(buffer, length); i::Scanner scanner(&unicode_cache); @@ -141,9 +144,8 @@ TEST(ScanHTMLEndComments) { }; // Parser/Scanner needs a stack limit. - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit(); for (int i = 0; tests[i]; i++) { const i::byte* source = @@ -156,8 +158,7 @@ TEST(ScanHTMLEndComments) { preparser.set_allow_lazy(true); i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - CHECK(!data.has_error()); + CHECK(!log.HasError()); } for (int i = 0; fail_tests[i]; i++) { @@ -172,8 +173,7 @@ TEST(ScanHTMLEndComments) { i::PreParser::PreParseResult result = preparser.PreParseProgram(); // Even in the case of a syntax error, kPreParseSuccess is returned. CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - CHECK(data.has_error()); + CHECK(log.HasError()); } } @@ -197,9 +197,8 @@ TEST(UsingCachedData) { v8::HandleScope handles(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); // Source containing functions that might be lazily compiled and all types // of symbols (string, propertyName, regexp). @@ -213,23 +212,28 @@ TEST(UsingCachedData) { "var v = /RegExp Literal/;" "var w = /RegExp Literal\\u0020With Escape/gin;" "var y = { get getter() { return 42; }, " - " set setter(v) { this.value = v; }};"; + " set setter(v) { this.value = v; }};" + "var f = a => function (b) { return a + b; };" + "var g = a => b => a + b;"; int source_length = i::StrLength(source); // ScriptResource will be deleted when the corresponding String is GCd. v8::ScriptCompiler::Source script_source(v8::String::NewExternal( isolate, new ScriptResource(source, source_length))); + i::FLAG_harmony_arrow_functions = true; i::FLAG_min_preparse_length = 0; v8::ScriptCompiler::Compile(isolate, &script_source, - v8::ScriptCompiler::kProduceDataToCache); + v8::ScriptCompiler::kProduceParserCache); CHECK(script_source.GetCachedData()); // Compile the script again, using the cached data. bool lazy_flag = i::FLAG_lazy; i::FLAG_lazy = true; - v8::ScriptCompiler::Compile(isolate, &script_source); + v8::ScriptCompiler::Compile(isolate, &script_source, + v8::ScriptCompiler::kConsumeParserCache); i::FLAG_lazy = false; - v8::ScriptCompiler::CompileUnbound(isolate, &script_source); + v8::ScriptCompiler::CompileUnbound(isolate, &script_source, + v8::ScriptCompiler::kConsumeParserCache); i::FLAG_lazy = lazy_flag; } @@ -240,49 +244,55 @@ TEST(PreparseFunctionDataIsUsed) { // Make preparsing work for short scripts. i::FLAG_min_preparse_length = 0; + i::FLAG_harmony_arrow_functions = true; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handles(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); - const char* good_code = - "function this_is_lazy() { var a; } function foo() { return 25; } foo();"; + const char* good_code[] = { + "function this_is_lazy() { var a; } function foo() { return 25; } foo();", + "var this_is_lazy = () => { var a; }; var foo = () => 25; foo();", + }; // Insert a syntax error inside the lazy function. - const char* bad_code = - "function this_is_lazy() { if ( } function foo() { return 25; } foo();"; - - v8::ScriptCompiler::Source good_source(v8_str(good_code)); - v8::ScriptCompiler::Compile(isolate, &good_source, - v8::ScriptCompiler::kProduceDataToCache); - - const v8::ScriptCompiler::CachedData* cached_data = - good_source.GetCachedData(); - CHECK(cached_data->data != NULL); - CHECK_GT(cached_data->length, 0); - - // Now compile the erroneous code with the good preparse data. If the preparse - // data is used, the lazy function is skipped and it should compile fine. - v8::ScriptCompiler::Source bad_source( - v8_str(bad_code), new v8::ScriptCompiler::CachedData( - cached_data->data, cached_data->length)); - v8::Local<v8::Value> result = - v8::ScriptCompiler::Compile(isolate, &bad_source)->Run(); - CHECK(result->IsInt32()); - CHECK_EQ(25, result->Int32Value()); + const char* bad_code[] = { + "function this_is_lazy() { if ( } function foo() { return 25; } foo();", + "var this_is_lazy = () => { if ( }; var foo = () => 25; foo();", + }; + + for (unsigned i = 0; i < ARRAY_SIZE(good_code); i++) { + v8::ScriptCompiler::Source good_source(v8_str(good_code[i])); + v8::ScriptCompiler::Compile(isolate, &good_source, + v8::ScriptCompiler::kProduceDataToCache); + + const v8::ScriptCompiler::CachedData* cached_data = + good_source.GetCachedData(); + CHECK(cached_data->data != NULL); + CHECK_GT(cached_data->length, 0); + + // Now compile the erroneous code with the good preparse data. If the + // preparse data is used, the lazy function is skipped and it should + // compile fine. + v8::ScriptCompiler::Source bad_source( + 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(); + CHECK(result->IsInt32()); + CHECK_EQ(25, result->Int32Value()); + } } TEST(StandAlonePreParser) { v8::V8::Initialize(); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); const char* programs[] = { "{label: 42}", @@ -290,6 +300,7 @@ TEST(StandAlonePreParser) { "function foo(x, y) { return x + y; }", "%ArgleBargle(glop);", "var x = new new Function('this.x = 42');", + "var f = (x, y) => x + y;", NULL }; @@ -306,10 +317,10 @@ TEST(StandAlonePreParser) { i::PreParser preparser(&scanner, &log, stack_limit); preparser.set_allow_lazy(true); preparser.set_allow_natives_syntax(true); + preparser.set_allow_arrow_functions(true); i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - CHECK(!data.has_error()); + CHECK(!log.HasError()); } } @@ -317,9 +328,8 @@ TEST(StandAlonePreParser) { TEST(StandAlonePreParserNoNatives) { v8::V8::Initialize(); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); const char* programs[] = { "%ArgleBargle(glop);", @@ -342,9 +352,7 @@ TEST(StandAlonePreParserNoNatives) { preparser.set_allow_lazy(true); i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - // Data contains syntax error. - CHECK(data.has_error()); + CHECK(log.HasError()); } } @@ -356,13 +364,12 @@ TEST(PreparsingObjectLiterals) { v8::HandleScope handles(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); { const char* source = "var myo = {if: \"foo\"}; myo.if;"; - v8::Local<v8::Value> result = PreCompileCompileRun(source); + v8::Local<v8::Value> result = ParserCacheCompileRun(source); CHECK(result->IsString()); v8::String::Utf8Value utf8(result); CHECK_EQ("foo", *utf8); @@ -370,7 +377,7 @@ TEST(PreparsingObjectLiterals) { { const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];"; - v8::Local<v8::Value> result = PreCompileCompileRun(source); + v8::Local<v8::Value> result = ParserCacheCompileRun(source); CHECK(result->IsString()); v8::String::Utf8Value utf8(result); CHECK_EQ("foo", *utf8); @@ -378,7 +385,7 @@ TEST(PreparsingObjectLiterals) { { const char* source = "var myo = {1: \"foo\"}; myo[1];"; - v8::Local<v8::Value> result = PreCompileCompileRun(source); + v8::Local<v8::Value> result = ParserCacheCompileRun(source); CHECK(result->IsString()); v8::String::Utf8Value utf8(result); CHECK_EQ("foo", *utf8); @@ -390,9 +397,7 @@ TEST(RegressChromium62639) { v8::V8::Initialize(); i::Isolate* isolate = CcTest::i_isolate(); - int marker; - isolate->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + isolate->stack_guard()->SetStackLimit(GetCurrentStackPosition() - 128 * 1024); const char* program = "var x = 'something';\n" "escape: function() {}"; @@ -413,8 +418,7 @@ TEST(RegressChromium62639) { i::PreParser::PreParseResult result = preparser.PreParseProgram(); // Even in the case of a syntax error, kPreParseSuccess is returned. CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - CHECK(data.has_error()); + CHECK(log.HasError()); } @@ -427,9 +431,7 @@ TEST(Regress928) { // as with-content, which made it assume that a function inside // the block could be lazily compiled, and an extra, unexpected, // entry was added to the data. - int marker; - isolate->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + isolate->stack_guard()->SetStackLimit(GetCurrentStackPosition() - 128 * 1024); const char* program = "try { } catch (e) { var foo = function () { /* first */ } }" @@ -446,15 +448,15 @@ TEST(Regress928) { preparser.set_allow_lazy(true); i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseSuccess, result); - i::ScriptData data(log.ExtractData()); - CHECK(!data.has_error()); - data.Initialize(); + i::ScriptData* sd = log.GetScriptData(); + i::ParseData pd(sd); + pd.Initialize(); int first_function = static_cast<int>(strstr(program, "function") - program); int first_lbrace = first_function + i::StrLength("function () "); CHECK_EQ('{', program[first_lbrace]); - i::FunctionEntry entry1 = data.GetFunctionEntry(first_lbrace); + i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace); CHECK(!entry1.is_valid()); int second_function = @@ -462,18 +464,18 @@ TEST(Regress928) { int second_lbrace = second_function + i::StrLength("function () "); CHECK_EQ('{', program[second_lbrace]); - i::FunctionEntry entry2 = data.GetFunctionEntry(second_lbrace); + i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace); CHECK(entry2.is_valid()); CHECK_EQ('}', program[entry2.end_pos() - 1]); + delete sd; } TEST(PreParseOverflow) { v8::V8::Initialize(); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); size_t kProgramSize = 1024 * 1024; i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1)); @@ -491,6 +493,7 @@ TEST(PreParseOverflow) { i::PreParser preparser(&scanner, &log, stack_limit); preparser.set_allow_lazy(true); + preparser.set_allow_arrow_functions(true); i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseStackOverflow, result); } @@ -669,7 +672,7 @@ TEST(Utf8CharacterStream) { i, unibrow::Utf16::kNoPreviousCharacter); } - ASSERT(cursor == kAllUtf8CharsSizeU); + DCHECK(cursor == kAllUtf8CharsSizeU); i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer), kAllUtf8CharsSizeU); @@ -758,8 +761,8 @@ TEST(StreamScanner) { i::Token::EOS, i::Token::ILLEGAL }; - ASSERT_EQ('{', str2[19]); - ASSERT_EQ('}', str2[37]); + DCHECK_EQ('{', str2[19]); + DCHECK_EQ('}', str2[37]); TestStreamScanner(&stream2, expectations2, 20, 37); const char* str3 = "{}}}}"; @@ -796,8 +799,12 @@ void TestScanRegExp(const char* re_source, const char* expected) { CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV); CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV)); scanner.Next(); // Current token is now the regexp literal. + i::Zone zone(CcTest::i_isolate()); + i::AstValueFactory ast_value_factory(&zone, + CcTest::i_isolate()->heap()->HashSeed()); + ast_value_factory.Internalize(CcTest::i_isolate()); i::Handle<i::String> val = - scanner.AllocateInternalizedString(CcTest::i_isolate()); + scanner.CurrentSymbol(&ast_value_factory)->string(); i::DisallowHeapAllocation no_alloc; i::String::FlatContent content = val->GetFlatContent(); CHECK(content.IsAscii()); @@ -964,7 +971,13 @@ TEST(ScopePositions) { " infunction;\n" " }", "\n" " more;", i::FUNCTION_SCOPE, i::SLOPPY }, - { " (function fun", "(a,b) { infunction; }", ")();", + // TODO(aperez): Change to use i::ARROW_SCOPE when implemented + { " start;\n", "(a,b) => a + b", "; more;", + i::FUNCTION_SCOPE, i::SLOPPY }, + { " start;\n", "(a,b) => { return a+b; }", "\nmore;", + i::FUNCTION_SCOPE, i::SLOPPY }, + { " start;\n" + " (function fun", "(a,b) { infunction; }", ")();", i::FUNCTION_SCOPE, i::SLOPPY }, { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;", i::BLOCK_SCOPE, i::STRICT }, @@ -1091,9 +1104,7 @@ TEST(ScopePositions) { v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); v8::Context::Scope context_scope(context); - int marker; - isolate->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + isolate->stack_guard()->SetStackLimit(GetCurrentStackPosition() - 128 * 1024); for (int i = 0; source_data[i].outer_prefix; i++) { int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix); @@ -1105,10 +1116,10 @@ TEST(ScopePositions) { int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; i::ScopedVector<char> program(kProgramByteSize + 1); - i::OS::SNPrintF(program, "%s%s%s", - source_data[i].outer_prefix, - source_data[i].inner_source, - source_data[i].outer_suffix); + i::SNPrintF(program, "%s%s%s", + source_data[i].outer_prefix, + source_data[i].inner_source, + source_data[i].outer_suffix); // Parse program source. i::Handle<i::String> source = factory->NewStringFromUtf8( @@ -1119,6 +1130,7 @@ TEST(ScopePositions) { i::Parser parser(&info); parser.set_allow_lazy(true); parser.set_allow_harmony_scoping(true); + parser.set_allow_arrow_functions(true); info.MarkAsGlobal(); info.SetStrictMode(source_data[i].strict_mode); parser.Parse(); @@ -1141,20 +1153,41 @@ TEST(ScopePositions) { } -i::Handle<i::String> FormatMessage(i::ScriptData* data) { +const char* ReadString(unsigned* start) { + int length = start[0]; + char* result = i::NewArray<char>(length + 1); + for (int i = 0; i < length; i++) { + result[i] = start[i + 1]; + } + result[length] = '\0'; + return result; +} + + +i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) { i::Isolate* isolate = CcTest::i_isolate(); i::Factory* factory = isolate->factory(); - const char* message = data->BuildMessage(); + const char* message = + ReadString(&data[i::PreparseDataConstants::kMessageTextPos]); i::Handle<i::String> format = v8::Utils::OpenHandle( *v8::String::NewFromUtf8(CcTest::isolate(), message)); - i::Vector<const char*> args = data->BuildArgs(); - i::Handle<i::JSArray> args_array = factory->NewJSArray(args.length()); - for (int i = 0; i < args.length(); i++) { - i::JSArray::SetElement( - args_array, i, v8::Utils::OpenHandle(*v8::String::NewFromUtf8( - CcTest::isolate(), args[i])), - NONE, i::SLOPPY).Check(); + int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos]; + const char* arg = NULL; + i::Handle<i::JSArray> args_array; + 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(); + } else { + CHECK_EQ(0, arg_count); + args_array = factory->NewJSArray(0); } + i::Handle<i::JSObject> builtins(isolate->js_builtins_object()); i::Handle<i::Object> format_fun = i::Object::GetProperty( isolate, builtins, "FormatMessage").ToHandleChecked(); @@ -1162,11 +1195,9 @@ i::Handle<i::String> FormatMessage(i::ScriptData* data) { i::Handle<i::Object> result = i::Execution::Call( isolate, format_fun, builtins, 2, arg_handles).ToHandleChecked(); CHECK(result->IsString()); - for (int i = 0; i < args.length(); i++) { - i::DeleteArray(args[i]); - } - i::DeleteArray(args.start()); i::DeleteArray(message); + i::DeleteArray(arg); + data.Dispose(); return i::Handle<i::String>::cast(result); } @@ -1177,8 +1208,8 @@ enum ParserFlag { kAllowHarmonyScoping, kAllowModules, kAllowGenerators, - kAllowForOf, - kAllowHarmonyNumericLiterals + kAllowHarmonyNumericLiterals, + kAllowArrowFunctions }; @@ -1196,9 +1227,9 @@ void SetParserFlags(i::ParserBase<Traits>* parser, parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping)); parser->set_allow_modules(flags.Contains(kAllowModules)); parser->set_allow_generators(flags.Contains(kAllowGenerators)); - parser->set_allow_for_of(flags.Contains(kAllowForOf)); parser->set_allow_harmony_numeric_literals( flags.Contains(kAllowHarmonyNumericLiterals)); + parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions)); } @@ -1221,7 +1252,8 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, i::PreParser::PreParseResult result = preparser.PreParseProgram(); CHECK_EQ(i::PreParser::kPreParseSuccess, result); } - i::ScriptData data(log.ExtractData()); + + bool preparse_error = log.HasError(); // Parse the data i::FunctionLiteral* function; @@ -1246,7 +1278,7 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, isolate, exception_handle, "message").ToHandleChecked()); if (result == kSuccess) { - i::OS::Print( + v8::base::OS::Print( "Parser failed on:\n" "\t%s\n" "with error:\n" @@ -1256,8 +1288,8 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, CHECK(false); } - if (!data.has_error()) { - i::OS::Print( + if (!preparse_error) { + v8::base::OS::Print( "Parser failed on:\n" "\t%s\n" "with error:\n" @@ -1267,9 +1299,10 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, CHECK(false); } // Check that preparser and parser produce the same error. - i::Handle<i::String> preparser_message = FormatMessage(&data); + i::Handle<i::String> preparser_message = + FormatMessage(log.ErrorMessageData()); if (!i::String::Equals(message_string, preparser_message)) { - i::OS::Print( + v8::base::OS::Print( "Expected parser and preparser to produce the same error on:\n" "\t%s\n" "However, found the following error messages\n" @@ -1280,17 +1313,18 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, preparser_message->ToCString().get()); CHECK(false); } - } else if (data.has_error()) { - i::OS::Print( + } else if (preparse_error) { + v8::base::OS::Print( "Preparser failed on:\n" "\t%s\n" "with error:\n" "\t%s\n" "However, the parser succeeded", - source->ToCString().get(), FormatMessage(&data)->ToCString().get()); + source->ToCString().get(), + FormatMessage(log.ErrorMessageData())->ToCString().get()); CHECK(false); } else if (result == kError) { - i::OS::Print( + v8::base::OS::Print( "Expected error on:\n" "\t%s\n" "However, parser and preparser succeeded", @@ -1301,15 +1335,22 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, void TestParserSync(const char* source, - const ParserFlag* flag_list, - size_t flag_list_length, - ParserSyncTestResult result = kSuccessOrError) { + const ParserFlag* varying_flags, + size_t varying_flags_length, + ParserSyncTestResult result = kSuccessOrError, + const ParserFlag* always_true_flags = NULL, + size_t always_true_flags_length = 0) { i::Handle<i::String> str = CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source); - for (int bits = 0; bits < (1 << flag_list_length); bits++) { + for (int bits = 0; bits < (1 << varying_flags_length); bits++) { i::EnumSet<ParserFlag> flags; - for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) { - if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]); + for (size_t flag_index = 0; flag_index < varying_flags_length; + ++flag_index) { + if ((bits & (1 << flag_index)) != 0) flags.Add(varying_flags[flag_index]); + } + for (size_t flag_index = 0; flag_index < always_true_flags_length; + ++flag_index) { + flags.Add(always_true_flags[flag_index]); } TestParserSyncWithFlags(str, flags, result); } @@ -1390,14 +1431,12 @@ TEST(ParserSync) { v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); v8::Context::Scope context_scope(context); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); - static const ParserFlag flags1[] = { - kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, - kAllowForOf - }; + static const ParserFlag flags1[] = {kAllowLazy, kAllowHarmonyScoping, + kAllowModules, kAllowGenerators, + kAllowArrowFunctions}; for (int i = 0; context_data[i][0] != NULL; ++i) { for (int j = 0; statement_data[j] != NULL; ++j) { for (int k = 0; termination_data[k] != NULL; ++k) { @@ -1410,7 +1449,7 @@ TEST(ParserSync) { // Plug the source code pieces together. i::ScopedVector<char> program(kProgramSize + 1); - int length = i::OS::SNPrintF(program, + int length = i::SNPrintF(program, "label: for (;;) { %s%s%s%s }", context_data[i][0], statement_data[j], @@ -1461,22 +1500,42 @@ void RunParserSyncTest(const char* context_data[][2], const char* statement_data[], ParserSyncTestResult result, const ParserFlag* flags = NULL, - int flags_len = 0) { + int flags_len = 0, + const ParserFlag* always_true_flags = NULL, + int always_true_flags_len = 0) { v8::HandleScope handles(CcTest::isolate()); v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); v8::Context::Scope context_scope(context); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); static const ParserFlag default_flags[] = { - kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, - kAllowForOf, kAllowNativesSyntax - }; - if (!flags) { + kAllowLazy, kAllowHarmonyScoping, kAllowModules, + kAllowGenerators, kAllowNativesSyntax, kAllowArrowFunctions}; + ParserFlag* generated_flags = NULL; + if (flags == NULL) { flags = default_flags; flags_len = ARRAY_SIZE(default_flags); + if (always_true_flags != NULL) { + // Remove always_true_flags from default_flags. + CHECK(always_true_flags_len < flags_len); + generated_flags = new ParserFlag[flags_len - always_true_flags_len]; + int flag_index = 0; + for (int i = 0; i < flags_len; ++i) { + bool use_flag = true; + for (int j = 0; j < always_true_flags_len; ++j) { + if (flags[i] == always_true_flags[j]) { + use_flag = false; + break; + } + } + if (use_flag) generated_flags[flag_index++] = flags[i]; + } + CHECK(flag_index == flags_len - always_true_flags_len); + flags_len = flag_index; + flags = generated_flags; + } } for (int i = 0; context_data[i][0] != NULL; ++i) { for (int j = 0; statement_data[j] != NULL; ++j) { @@ -1487,18 +1546,21 @@ void RunParserSyncTest(const char* context_data[][2], // Plug the source code pieces together. i::ScopedVector<char> program(kProgramSize + 1); - int length = i::OS::SNPrintF(program, - "%s%s%s", - context_data[i][0], - statement_data[j], - context_data[i][1]); + int length = i::SNPrintF(program, + "%s%s%s", + context_data[i][0], + statement_data[j], + context_data[i][1]); CHECK(length == kProgramSize); TestParserSync(program.start(), flags, flags_len, - result); + result, + always_true_flags, + always_true_flags_len); } } + delete[] generated_flags; } @@ -1526,6 +1588,10 @@ TEST(ErrorsEvalAndArguments) { "function foo(arguments) { }", "function foo(bar, eval) { }", "function foo(bar, arguments) { }", + "(eval) => { }", + "(arguments) => { }", + "(foo, eval) => { }", + "(foo, arguments) => { }", "eval = 1;", "arguments = 1;", "var foo = eval = 1;", @@ -1582,6 +1648,7 @@ TEST(NoErrorsEvalAndArgumentsStrict) { const char* context_data[][2] = { { "\"use strict\";", "" }, { "function test_func() { \"use strict\";", "}" }, + { "() => { \"use strict\"; ", "}" }, { NULL, NULL } }; @@ -1597,7 +1664,9 @@ TEST(NoErrorsEvalAndArgumentsStrict) { NULL }; - RunParserSyncTest(context_data, statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowArrowFunctions}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); } @@ -1609,6 +1678,7 @@ TEST(ErrorsFutureStrictReservedWords) { const char* context_data[][2] = { { "\"use strict\";", "" }, { "function test_func() {\"use strict\"; ", "}"}, + { "() => { \"use strict\"; ", "}" }, { NULL, NULL } }; @@ -1623,10 +1693,13 @@ TEST(ErrorsFutureStrictReservedWords) { "var foo = interface = 1;", "++interface;", "interface++;", + "var yield = 13;", NULL }; - RunParserSyncTest(context_data, statement_data, kError); + static const ParserFlag always_flags[] = {kAllowArrowFunctions}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, + ARRAY_SIZE(always_flags)); } @@ -1634,6 +1707,7 @@ TEST(NoErrorsFutureStrictReservedWords) { const char* context_data[][2] = { { "", "" }, { "function test_func() {", "}"}, + { "() => {", "}" }, { NULL, NULL } }; @@ -1648,10 +1722,13 @@ TEST(NoErrorsFutureStrictReservedWords) { "var foo = interface = 1;", "++interface;", "interface++;", + "var yield = 13;", NULL }; - RunParserSyncTest(context_data, statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowArrowFunctions}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); } @@ -1664,6 +1741,8 @@ TEST(ErrorsReservedWords) { { "\"use strict\";", "" }, { "var eval; function test_func() {", "}"}, { "var eval; function test_func() {\"use strict\"; ", "}"}, + { "var eval; () => {", "}"}, + { "var eval; () => {\"use strict\"; ", "}"}, { NULL, NULL } }; @@ -1674,6 +1753,8 @@ TEST(ErrorsReservedWords) { "function super() { }", "function foo(super) { }", "function foo(bar, super) { }", + "(super) => { }", + "(bar, super) => { }", "super = 1;", "var foo = super = 1;", "++super;", @@ -1686,12 +1767,47 @@ TEST(ErrorsReservedWords) { } -TEST(NoErrorsYieldSloppy) { +TEST(NoErrorsLetSloppyAllModes) { + // In sloppy mode, it's okay to use "let" as identifier. + const char* context_data[][2] = { + { "", "" }, + { "function f() {", "}" }, + { "(function f() {", "})" }, + { NULL, NULL } + }; + + const char* statement_data[] = { + "var let;", + "var foo, let;", + "try { } catch (let) { }", + "function let() { }", + "(function let() { })", + "function foo(let) { }", + "function foo(bar, let) { }", + "let = 1;", + "var foo = let = 1;", + "let * 2;", + "++let;", + "let++;", + "let: 34", + "function let(let) { let: let(let + let(0)); }", + "({ let: 1 })", + "({ get let() { 1 } })", + "let(100)", + NULL + }; + + RunParserSyncTest(context_data, statement_data, kSuccess); +} + + +TEST(NoErrorsYieldSloppyAllModes) { // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a - // generator (see next test). + // generator (see other test). const char* context_data[][2] = { { "", "" }, - { "function is_not_gen() {", "}" }, + { "function not_gen() {", "}" }, + { "(function not_gen() {", "})" }, { NULL, NULL } }; @@ -1700,12 +1816,20 @@ TEST(NoErrorsYieldSloppy) { "var foo, yield;", "try { } catch (yield) { }", "function yield() { }", + "(function yield() { })", "function foo(yield) { }", "function foo(bar, yield) { }", "yield = 1;", "var foo = yield = 1;", + "yield * 2;", "++yield;", "yield++;", + "yield: 34", + "function yield(yield) { yield: yield (yield + yield(0)); }", + "({ yield: 1 })", + "({ get yield() { 1 } })", + "yield(100)", + "yield[100]", NULL }; @@ -1713,9 +1837,15 @@ TEST(NoErrorsYieldSloppy) { } -TEST(ErrorsYieldSloppyGenerator) { +TEST(NoErrorsYieldSloppyGeneratorsEnabled) { + // In sloppy mode, it's okay to use "yield" as identifier, *except* inside a + // generator (see next test). const char* context_data[][2] = { - { "function * is_gen() {", "}" }, + { "", "" }, + { "function not_gen() {", "}" }, + { "function * gen() { function not_gen() {", "} }" }, + { "(function not_gen() {", "})" }, + { "(function * gen() { (function not_gen() {", "}) })" }, { NULL, NULL } }; @@ -1724,28 +1854,41 @@ TEST(ErrorsYieldSloppyGenerator) { "var foo, yield;", "try { } catch (yield) { }", "function yield() { }", - // BUG: These should not be allowed, but they are (if kAllowGenerators is - // set) - // "function foo(yield) { }", - // "function foo(bar, yield) { }", + "(function yield() { })", + "function foo(yield) { }", + "function foo(bar, yield) { }", + "function * yield() { }", + "(function * yield() { })", "yield = 1;", "var foo = yield = 1;", + "yield * 2;", "++yield;", "yield++;", + "yield: 34", + "function yield(yield) { yield: yield (yield + yield(0)); }", + "({ yield: 1 })", + "({ get yield() { 1 } })", + "yield(100)", + "yield[100]", NULL }; - // If generators are not allowed, the error will be produced at the '*' token, - // so this test works both with and without the kAllowGenerators flag. - RunParserSyncTest(context_data, statement_data, kError); + // This test requires kAllowGenerators to succeed. + static const ParserFlag always_true_flags[] = { kAllowGenerators }; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_true_flags, 1); } TEST(ErrorsYieldStrict) { const char* context_data[][2] = { { "\"use strict\";", "" }, - { "\"use strict\"; function is_not_gen() {", "}" }, + { "\"use strict\"; function not_gen() {", "}" }, { "function test_func() {\"use strict\"; ", "}"}, + { "\"use strict\"; function * gen() { function not_gen() {", "} }" }, + { "\"use strict\"; (function not_gen() {", "})" }, + { "\"use strict\"; (function * gen() { (function not_gen() {", "}) })" }, + { "() => {\"use strict\"; ", "}" }, { NULL, NULL } }; @@ -1754,12 +1897,16 @@ TEST(ErrorsYieldStrict) { "var foo, yield;", "try { } catch (yield) { }", "function yield() { }", + "(function yield() { })", "function foo(yield) { }", "function foo(bar, yield) { }", + "function * yield() { }", + "(function * yield() { })", "yield = 1;", "var foo = yield = 1;", "++yield;", "yield++;", + "yield: 34;", NULL }; @@ -1767,22 +1914,116 @@ TEST(ErrorsYieldStrict) { } -TEST(ErrorsYield) { +TEST(NoErrorsGenerator) { const char* context_data[][2] = { - { "function * is_gen() {", "}" }, + { "function * gen() {", "}" }, + { "(function * gen() {", "})" }, + { "(function * () {", "})" }, { NULL, NULL } }; const char* statement_data[] = { - "yield 2;", // this is legal inside generator - "yield * 2;", // this is legal inside generator + // A generator without a body is valid. + "" + // Valid yield expressions inside generators. + "yield 2;", + "yield * 2;", + "yield * \n 2;", + "yield yield 1;", + "yield * yield * 1;", + "yield 3 + (yield 4);", + "yield * 3 + (yield * 4);", + "(yield * 3) + (yield * 4);", + "yield 3; yield 4;", + "yield * 3; yield * 4;", + "(function (yield) { })", + "yield { yield: 12 }", + "yield /* comment */ { yield: 12 }", + "yield * \n { yield: 12 }", + "yield /* comment */ * \n { yield: 12 }", + // You can return in a generator. + "yield 1; return", + "yield * 1; return", + "yield 1; return 37", + "yield * 1; return 37", + "yield 1; return 37; yield 'dead';", + "yield * 1; return 37; yield * 'dead';", + // Yield is still a valid key in object literals. + "({ yield: 1 })", + "({ get yield() { } })", + // Yield without RHS. + "yield;", + "yield", + "yield\n", + "yield /* comment */" + "yield // comment\n" + "(yield)", + "[yield]", + "{yield}", + "yield, yield", + "yield; yield", + "(yield) ? yield : yield", + "(yield) \n ? yield : yield", + // If there is a newline before the next token, we don't look for RHS. + "yield\nfor (;;) {}", + NULL + }; + + // This test requires kAllowGenerators to succeed. + static const ParserFlag always_true_flags[] = { + kAllowGenerators + }; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_true_flags, 1); +} + + +TEST(ErrorsYieldGenerator) { + const char* context_data[][2] = { + { "function * gen() {", "}" }, + { "\"use strict\"; function * gen() {", "}" }, + { NULL, NULL } + }; + + const char* statement_data[] = { + // Invalid yield expressions inside generators. + "var yield;", + "var foo, yield;", + "try { } catch (yield) { }", + "function yield() { }", + // The name of the NFE is let-bound in the generator, which does not permit + // yield to be an identifier. + "(function yield() { })", + "(function * yield() { })", + // Yield isn't valid as a formal parameter for generators. + "function * foo(yield) { }", + "(function * foo(yield) { })", + "yield = 1;", + "var foo = yield = 1;", + "++yield;", + "yield++;", + "yield *", + "(yield *)", + // Yield binds very loosely, so this parses as "yield (3 + yield 4)", which + // is invalid. + "yield 3 + yield 4;", + "yield: 34", + "yield ? 1 : 2", + // Parses as yield (/ yield): invalid. + "yield / yield", + "+ yield", + "+ yield 3", + // Invalid (no newline allowed between yield and *). + "yield\n*3", + // Invalid (we see a newline, so we parse {yield:42} as a statement, not an + // object literal, and yield is not a valid label). + "yield\n{yield: 42}", + "yield /* comment */\n {yield: 42}", + "yield //comment\n {yield: 42}", NULL }; - // Here we cannot assert that there is no error, since there will be without - // the kAllowGenerators flag. However, we test that Parser and PreParser - // produce the same errors. - RunParserSyncTest(context_data, statement_data, kSuccessOrError); + RunParserSyncTest(context_data, statement_data, kError); } @@ -1790,16 +2031,18 @@ TEST(ErrorsNameOfStrictFunction) { // Tests that illegal tokens as names of a strict function produce the correct // errors. const char* context_data[][2] = { - { "", ""}, - { "\"use strict\";", ""}, + { "function ", ""}, + { "\"use strict\"; function", ""}, + { "function * ", ""}, + { "\"use strict\"; function * ", ""}, { NULL, NULL } }; const char* statement_data[] = { - "function eval() {\"use strict\";}", - "function arguments() {\"use strict\";}", - "function interface() {\"use strict\";}", - "function yield() {\"use strict\";}", + "eval() {\"use strict\";}", + "arguments() {\"use strict\";}", + "interface() {\"use strict\";}", + "yield() {\"use strict\";}", // Future reserved words are always illegal "function super() { }", "function super() {\"use strict\";}", @@ -1812,15 +2055,15 @@ TEST(ErrorsNameOfStrictFunction) { TEST(NoErrorsNameOfStrictFunction) { const char* context_data[][2] = { - { "", ""}, + { "function ", ""}, { NULL, NULL } }; const char* statement_data[] = { - "function eval() { }", - "function arguments() { }", - "function interface() { }", - "function yield() { }", + "eval() { }", + "arguments() { }", + "interface() { }", + "yield() { }", NULL }; @@ -1828,12 +2071,35 @@ TEST(NoErrorsNameOfStrictFunction) { } +TEST(NoErrorsNameOfStrictGenerator) { + const char* context_data[][2] = { + { "function * ", ""}, + { NULL, NULL } + }; + + const char* statement_data[] = { + "eval() { }", + "arguments() { }", + "interface() { }", + "yield() { }", + NULL + }; + + // This test requires kAllowGenerators to succeed. + static const ParserFlag always_true_flags[] = { + kAllowGenerators + }; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_true_flags, 1); +} + TEST(ErrorsIllegalWordsAsLabelsSloppy) { // Using future reserved words as labels is always an error. const char* context_data[][2] = { { "", ""}, { "function test_func() {", "}" }, + { "() => {", "}" }, { NULL, NULL } }; @@ -1851,6 +2117,7 @@ TEST(ErrorsIllegalWordsAsLabelsStrict) { const char* context_data[][2] = { { "\"use strict\";", "" }, { "function test_func() {\"use strict\"; ", "}"}, + { "() => {\"use strict\"; ", "}" }, { NULL, NULL } }; @@ -1870,8 +2137,10 @@ TEST(NoErrorsIllegalWordsAsLabels) { const char* context_data[][2] = { { "", ""}, { "function test_func() {", "}" }, + { "() => {", "}" }, { "\"use strict\";", "" }, { "\"use strict\"; function test_func() {", "}" }, + { "\"use strict\"; () => {", "}" }, { NULL, NULL } }; @@ -1882,7 +2151,9 @@ TEST(NoErrorsIllegalWordsAsLabels) { NULL }; - RunParserSyncTest(context_data, statement_data, kSuccess); + static const ParserFlag always_flags[] = {kAllowArrowFunctions}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); } @@ -1891,6 +2162,7 @@ TEST(ErrorsParenthesizedLabels) { const char* context_data[][2] = { { "", ""}, { "function test_func() {", "}" }, + { "() => {", "}" }, { NULL, NULL } }; @@ -1969,9 +2241,8 @@ TEST(DontRegressPreParserDataSizes) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handles(isolate); - int marker; - CcTest::i_isolate()->stack_guard()->SetStackLimit( - reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); + CcTest::i_isolate()->stack_guard()->SetStackLimit(GetCurrentStackPosition() - + 128 * 1024); struct TestCase { const char* program; @@ -1997,21 +2268,20 @@ TEST(DontRegressPreParserDataSizes) { factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source); i::CompilationInfoWithZone info(script); - i::ScriptData* data = NULL; - info.SetCachedData(&data, i::PRODUCE_CACHED_DATA); + i::ScriptData* sd = NULL; + info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache); i::Parser::Parse(&info, true); - CHECK(data); - CHECK(!data->HasError()); + i::ParseData pd(sd); - if (data->function_count() != test_cases[i].functions) { - i::OS::Print( + if (pd.FunctionCount() != test_cases[i].functions) { + v8::base::OS::Print( "Expected preparse data for program:\n" "\t%s\n" "to contain %d functions, however, received %d functions.\n", - program, test_cases[i].functions, - data->function_count()); + program, test_cases[i].functions, pd.FunctionCount()); CHECK(false); } + delete sd; } } @@ -2132,9 +2402,13 @@ TEST(Intrinsics) { NULL }; - // Parsing will fail or succeed depending on whether we allow natives syntax - // or not. - RunParserSyncTest(context_data, statement_data, kSuccessOrError); + // This test requires kAllowNativesSyntax to succeed. + static const ParserFlag always_true_flags[] = { + kAllowNativesSyntax + }; + + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_true_flags, 1); } @@ -2199,10 +2473,12 @@ TEST(ErrorsNewExpression) { TEST(StrictObjectLiteralChecking) { const char* strict_context_data[][2] = { {"\"use strict\"; var myobject = {", "};"}, + {"\"use strict\"; var myobject = {", ",};"}, { NULL, NULL } }; const char* non_strict_context_data[][2] = { {"var myobject = {", "};"}, + {"var myobject = {", ",};"}, { NULL, NULL } }; @@ -2231,23 +2507,29 @@ TEST(ErrorsObjectLiteralChecking) { }; const char* statement_data[] = { + ",", "foo: 1, get foo() {}", - "foo: 1, set foo() {}", + "foo: 1, set foo(v) {}", "\"foo\": 1, get \"foo\"() {}", - "\"foo\": 1, set \"foo\"() {}", + "\"foo\": 1, set \"foo\"(v) {}", "1: 1, get 1() {}", "1: 1, set 1() {}", // It's counter-intuitive, but these collide too (even in classic // mode). Note that we can have "foo" and foo as properties in classic mode, // but we cannot have "foo" and get foo, or foo and get "foo". "foo: 1, get \"foo\"() {}", - "foo: 1, set \"foo\"() {}", + "foo: 1, set \"foo\"(v) {}", "\"foo\": 1, get foo() {}", - "\"foo\": 1, set foo() {}", + "\"foo\": 1, set foo(v) {}", "1: 1, get \"1\"() {}", "1: 1, set \"1\"() {}", "\"1\": 1, get 1() {}" - "\"1\": 1, set 1() {}" + "\"1\": 1, set 1(v) {}" + // Wrong number of parameters + "get bar(x) {}", + "get bar(x, y) {}", + "set bar() {}", + "set bar(x, y) {}", // Parsing FunctionLiteral for getter or setter fails "get foo( +", "get foo() \"error\"", @@ -2261,7 +2543,9 @@ TEST(ErrorsObjectLiteralChecking) { TEST(NoErrorsObjectLiteralChecking) { const char* context_data[][2] = { {"var myobject = {", "};"}, + {"var myobject = {", ",};"}, {"\"use strict\"; var myobject = {", "};"}, + {"\"use strict\"; var myobject = {", ",};"}, { NULL, NULL } }; @@ -2271,25 +2555,22 @@ TEST(NoErrorsObjectLiteralChecking) { "1: 1, 2: 2", // Syntax: IdentifierName ':' AssignmentExpression "foo: bar = 5 + baz", - // Syntax: 'get' (IdentifierName | String | Number) FunctionLiteral + // Syntax: 'get' PropertyName '(' ')' '{' FunctionBody '}' "get foo() {}", "get \"foo\"() {}", "get 1() {}", - // Syntax: 'set' (IdentifierName | String | Number) FunctionLiteral - "set foo() {}", - "set \"foo\"() {}", - "set 1() {}", + // Syntax: 'set' PropertyName '(' PropertySetParameterList ')' + // '{' FunctionBody '}' + "set foo(v) {}", + "set \"foo\"(v) {}", + "set 1(v) {}", // Non-colliding getters and setters -> no errors "foo: 1, get bar() {}", - "foo: 1, set bar(b) {}", + "foo: 1, set bar(v) {}", "\"foo\": 1, get \"bar\"() {}", - "\"foo\": 1, set \"bar\"() {}", + "\"foo\": 1, set \"bar\"(v) {}", "1: 1, get 2() {}", - "1: 1, set 2() {}", - // Weird number of parameters -> no errors - "get bar() {}, set bar() {}", - "get bar(x) {}, set bar(x) {}", - "get bar(x, y) {}, set bar(x, y) {}", + "1: 1, set 2(v) {}", // Keywords, future reserved and strict future reserved are also allowed as // property names. "if: 4", @@ -2459,3 +2740,606 @@ TEST(InvalidLeftHandSide) { RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess); RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError); } + + +TEST(FuncNameInferrerBasic) { + // Tests that function names are inferred properly. + i::FLAG_allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + CompileRun("var foo1 = function() {}; " + "var foo2 = function foo3() {}; " + "function not_ctor() { " + " var foo4 = function() {}; " + " return %FunctionGetInferredName(foo4); " + "} " + "function Ctor() { " + " var foo5 = function() {}; " + " return %FunctionGetInferredName(foo5); " + "} " + "var obj1 = { foo6: function() {} }; " + "var obj2 = { 'foo7': function() {} }; " + "var obj3 = {}; " + "obj3[1] = function() {}; " + "var obj4 = {}; " + "obj4[1] = function foo8() {}; " + "var obj5 = {}; " + "obj5['foo9'] = function() {}; " + "var obj6 = { obj7 : { foo10: function() {} } };"); + ExpectString("%FunctionGetInferredName(foo1)", "foo1"); + // foo2 is not unnamed -> its name is not inferred. + ExpectString("%FunctionGetInferredName(foo2)", ""); + ExpectString("not_ctor()", "foo4"); + ExpectString("Ctor()", "Ctor.foo5"); + ExpectString("%FunctionGetInferredName(obj1.foo6)", "obj1.foo6"); + ExpectString("%FunctionGetInferredName(obj2.foo7)", "obj2.foo7"); + ExpectString("%FunctionGetInferredName(obj3[1])", + "obj3.(anonymous function)"); + ExpectString("%FunctionGetInferredName(obj4[1])", ""); + ExpectString("%FunctionGetInferredName(obj5['foo9'])", "obj5.foo9"); + ExpectString("%FunctionGetInferredName(obj6.obj7.foo10)", "obj6.obj7.foo10"); +} + + +TEST(FuncNameInferrerTwoByte) { + // Tests function name inferring in cases where some parts of the inferred + // function name are two-byte strings. + i::FLAG_allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + uint16_t* two_byte_source = AsciiToTwoByteString( + "var obj1 = { oXj2 : { foo1: function() {} } }; " + "%FunctionGetInferredName(obj1.oXj2.foo1)"); + uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); + // Make it really non-ASCII (replace the Xs with a non-ASCII character). + two_byte_source[14] = two_byte_source[78] = two_byte_name[6] = 0x010d; + v8::Local<v8::String> source = + v8::String::NewFromTwoByte(isolate, two_byte_source); + v8::Local<v8::Value> result = CompileRun(source); + CHECK(result->IsString()); + v8::Local<v8::String> expected_name = + v8::String::NewFromTwoByte(isolate, two_byte_name); + CHECK(result->Equals(expected_name)); + i::DeleteArray(two_byte_source); + i::DeleteArray(two_byte_name); +} + + +TEST(FuncNameInferrerEscaped) { + // The same as FuncNameInferrerTwoByte, except that we express the two-byte + // character as a unicode escape. + i::FLAG_allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + uint16_t* two_byte_source = AsciiToTwoByteString( + "var obj1 = { o\\u010dj2 : { foo1: function() {} } }; " + "%FunctionGetInferredName(obj1.o\\u010dj2.foo1)"); + uint16_t* two_byte_name = AsciiToTwoByteString("obj1.oXj2.foo1"); + // Fix to correspond to the non-ASCII name in two_byte_source. + two_byte_name[6] = 0x010d; + v8::Local<v8::String> source = + v8::String::NewFromTwoByte(isolate, two_byte_source); + v8::Local<v8::Value> result = CompileRun(source); + CHECK(result->IsString()); + v8::Local<v8::String> expected_name = + v8::String::NewFromTwoByte(isolate, two_byte_name); + CHECK(result->Equals(expected_name)); + i::DeleteArray(two_byte_source); + i::DeleteArray(two_byte_name); +} + + +TEST(RegressionLazyFunctionWithErrorWithArg) { + // The bug occurred when a lazy function had an error which requires a + // parameter (such as "unknown label" here). The error message was processed + // before the AstValueFactory containing the error message string was + // internalized. + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + i::FLAG_lazy = true; + i::FLAG_min_preparse_length = 0; + CompileRun("function this_is_lazy() {\n" + " break p;\n" + "}\n" + "this_is_lazy();\n"); +} + + +TEST(SerializationOfMaybeAssignmentFlag) { + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + i::HandleScope scope(isolate); + LocalContext env; + + const char* src = + "function h() {" + " var result = [];" + " function f() {" + " result.push(2);" + " }" + " function assertResult(r) {" + " f();" + " result = [];" + " }" + " assertResult([2]);" + " assertResult([2]);" + " return f;" + "};" + "h();"; + + i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); + i::SNPrintF(program, "%s", src); + i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); + source->PrintOn(stdout); + printf("\n"); + i::Zone zone(isolate); + v8::Local<v8::Value> v = CompileRun(src); + i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); + i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); + i::Context* context = f->context(); + i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); + avf.Internalize(isolate); + const i::AstRawString* name = avf.GetOneByteString("result"); + i::Handle<i::String> str = name->string(); + CHECK(str->IsInternalizedString()); + i::Scope* global_scope = + new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); + global_scope->Initialize(); + i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); + DCHECK(s != global_scope); + DCHECK(name != NULL); + + // Get result from h's function context (that is f's context) + i::Variable* var = s->Lookup(name); + + CHECK(var != NULL); + // Maybe assigned should survive deserialization + CHECK(var->maybe_assigned() == i::kMaybeAssigned); + // TODO(sigurds) Figure out if is_used should survive context serialization. +} + + +TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) { + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + i::HandleScope scope(isolate); + LocalContext env; + + + const char* src = + "function f(x) {" + " var a = arguments;" + " function g(i) {" + " ++a[0];" + " };" + " return g;" + " }" + "f(0);"; + + i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); + i::SNPrintF(program, "%s", src); + i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); + source->PrintOn(stdout); + printf("\n"); + i::Zone zone(isolate); + v8::Local<v8::Value> v = CompileRun(src); + i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); + i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); + i::Context* context = f->context(); + i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); + avf.Internalize(isolate); + + i::Scope* global_scope = + new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); + global_scope->Initialize(); + i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); + DCHECK(s != global_scope); + const i::AstRawString* name_x = avf.GetOneByteString("x"); + + // Get result from f's function context (that is g's outer context) + i::Variable* var_x = s->Lookup(name_x); + CHECK(var_x != NULL); + CHECK(var_x->maybe_assigned() == i::kMaybeAssigned); +} + + +TEST(ExportsMaybeAssigned) { + i::FLAG_use_strict = true; + i::FLAG_harmony_scoping = true; + i::FLAG_harmony_modules = true; + + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + i::HandleScope scope(isolate); + LocalContext env; + + const char* src = + "module A {" + " export var x = 1;" + " export function f() { return x };" + " export const y = 2;" + " module B {}" + " export module C {}" + "};" + "A.f"; + + i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); + i::SNPrintF(program, "%s", src); + i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); + source->PrintOn(stdout); + printf("\n"); + i::Zone zone(isolate); + v8::Local<v8::Value> v = CompileRun(src); + i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); + i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); + i::Context* context = f->context(); + i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); + avf.Internalize(isolate); + + i::Scope* global_scope = + new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone); + global_scope->Initialize(); + i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone); + DCHECK(s != global_scope); + const i::AstRawString* name_x = avf.GetOneByteString("x"); + const i::AstRawString* name_f = avf.GetOneByteString("f"); + const i::AstRawString* name_y = avf.GetOneByteString("y"); + const i::AstRawString* name_B = avf.GetOneByteString("B"); + const i::AstRawString* name_C = avf.GetOneByteString("C"); + + // Get result from h's function context (that is f's context) + i::Variable* var_x = s->Lookup(name_x); + CHECK(var_x != NULL); + CHECK(var_x->maybe_assigned() == i::kMaybeAssigned); + i::Variable* var_f = s->Lookup(name_f); + CHECK(var_f != NULL); + CHECK(var_f->maybe_assigned() == i::kMaybeAssigned); + i::Variable* var_y = s->Lookup(name_y); + CHECK(var_y != NULL); + CHECK(var_y->maybe_assigned() == i::kNotAssigned); + i::Variable* var_B = s->Lookup(name_B); + CHECK(var_B != NULL); + CHECK(var_B->maybe_assigned() == i::kNotAssigned); + i::Variable* var_C = s->Lookup(name_C); + CHECK(var_C != NULL); + CHECK(var_C->maybe_assigned() == i::kNotAssigned); +} + + +TEST(InnerAssignment) { + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + i::HandleScope scope(isolate); + LocalContext env; + + const char* prefix = "function f() {"; + const char* midfix = " function g() {"; + const char* suffix = "}}"; + struct { const char* source; bool assigned; bool strict; } outers[] = { + // Actual assignments. + { "var x; var x = 5;", true, false }, + { "var x; { var x = 5; }", true, false }, + { "'use strict'; let x; x = 6;", true, true }, + { "var x = 5; function x() {}", true, false }, + // Actual non-assignments. + { "var x;", false, false }, + { "var x = 5;", false, false }, + { "'use strict'; let x;", false, true }, + { "'use strict'; let x = 6;", false, true }, + { "'use strict'; var x = 0; { let x = 6; }", false, true }, + { "'use strict'; var x = 0; { let x; x = 6; }", false, true }, + { "'use strict'; let x = 0; { let x = 6; }", false, true }, + { "'use strict'; let x = 0; { let x; x = 6; }", false, true }, + { "var x; try {} catch (x) { x = 5; }", false, false }, + { "function x() {}", false, false }, + // Eval approximation. + { "var x; eval('');", true, false }, + { "eval(''); var x;", true, false }, + { "'use strict'; let x; eval('');", true, true }, + { "'use strict'; eval(''); let x;", true, true }, + // Non-assignments not recognized, because the analysis is approximative. + { "var x; var x;", true, false }, + { "var x = 5; var x;", true, false }, + { "var x; { var x; }", true, false }, + { "var x; function x() {}", true, false }, + { "function x() {}; var x;", true, false }, + { "var x; try {} catch (x) { var x = 5; }", true, false }, + }; + struct { const char* source; bool assigned; bool with; } inners[] = { + // Actual assignments. + { "x = 1;", true, false }, + { "x++;", true, false }, + { "++x;", true, false }, + { "x--;", true, false }, + { "--x;", true, false }, + { "{ x = 1; }", true, false }, + { "'use strict'; { let x; }; x = 0;", true, false }, + { "'use strict'; { const x = 1; }; x = 0;", true, false }, + { "'use strict'; { function x() {} }; x = 0;", true, false }, + { "with ({}) { x = 1; }", true, true }, + { "eval('');", true, false }, + { "'use strict'; { let y; eval('') }", true, false }, + { "function h() { x = 0; }", true, false }, + { "(function() { x = 0; })", true, false }, + { "(function() { x = 0; })", true, false }, + { "with ({}) (function() { x = 0; })", true, true }, + // Actual non-assignments. + { "", false, false }, + { "x;", false, false }, + { "var x;", false, false }, + { "var x = 8;", false, false }, + { "var x; x = 8;", false, false }, + { "'use strict'; let x;", false, false }, + { "'use strict'; let x = 8;", false, false }, + { "'use strict'; let x; x = 8;", false, false }, + { "'use strict'; const x = 8;", false, false }, + { "function x() {}", false, false }, + { "function x() { x = 0; }", false, false }, + { "function h(x) { x = 0; }", false, false }, + { "'use strict'; { let x; x = 0; }", false, false }, + { "{ var x; }; x = 0;", false, false }, + { "with ({}) {}", false, true }, + { "var x; { with ({}) { x = 1; } }", false, true }, + { "try {} catch(x) { x = 0; }", false, false }, + { "try {} catch(x) { with ({}) { x = 1; } }", false, true }, + // Eval approximation. + { "eval('');", true, false }, + { "function h() { eval(''); }", true, false }, + { "(function() { eval(''); })", true, false }, + // Shadowing not recognized because of eval approximation. + { "var x; eval('');", true, false }, + { "'use strict'; let x; eval('');", true, false }, + { "try {} catch(x) { eval(''); }", true, false }, + { "function x() { eval(''); }", true, false }, + { "(function(x) { eval(''); })", true, false }, + }; + + // Used to trigger lazy compilation of function + int comment_len = 2048; + i::ScopedVector<char> comment(comment_len + 1); + i::SNPrintF(comment, "/*%0*d*/", comment_len - 4, 0); + int prefix_len = Utf8LengthHelper(prefix); + int midfix_len = Utf8LengthHelper(midfix); + int suffix_len = Utf8LengthHelper(suffix); + for (unsigned i = 0; i < ARRAY_SIZE(outers); ++i) { + const char* outer = outers[i].source; + int outer_len = Utf8LengthHelper(outer); + for (unsigned j = 0; j < ARRAY_SIZE(inners); ++j) { + for (unsigned outer_lazy = 0; outer_lazy < 2; ++outer_lazy) { + for (unsigned inner_lazy = 0; inner_lazy < 2; ++inner_lazy) { + if (outers[i].strict && inners[j].with) continue; + const char* inner = inners[j].source; + int inner_len = Utf8LengthHelper(inner); + + int outer_comment_len = outer_lazy ? comment_len : 0; + int inner_comment_len = inner_lazy ? comment_len : 0; + const char* outer_comment = outer_lazy ? comment.start() : ""; + const char* inner_comment = inner_lazy ? comment.start() : ""; + int len = prefix_len + outer_comment_len + outer_len + midfix_len + + inner_comment_len + inner_len + suffix_len; + i::ScopedVector<char> program(len + 1); + + i::SNPrintF(program, "%s%s%s%s%s%s%s", prefix, outer_comment, outer, + midfix, inner_comment, inner, suffix); + i::Handle<i::String> source = + factory->InternalizeUtf8String(program.start()); + source->PrintOn(stdout); + printf("\n"); + + i::Handle<i::Script> script = factory->NewScript(source); + i::CompilationInfoWithZone info(script); + i::Parser parser(&info); + parser.set_allow_harmony_scoping(true); + CHECK(parser.Parse()); + CHECK(i::Rewriter::Rewrite(&info)); + CHECK(i::Scope::Analyze(&info)); + CHECK(info.function() != NULL); + + i::Scope* scope = info.function()->scope(); + CHECK_EQ(scope->inner_scopes()->length(), 1); + i::Scope* inner_scope = scope->inner_scopes()->at(0); + const i::AstRawString* var_name = + info.ast_value_factory()->GetOneByteString("x"); + i::Variable* var = inner_scope->Lookup(var_name); + bool expected = outers[i].assigned || inners[j].assigned; + CHECK(var != NULL); + CHECK(var->is_used() || !expected); + CHECK((var->maybe_assigned() == i::kMaybeAssigned) == expected); + } + } + } + } +} + +namespace { + +int* global_use_counts = NULL; + +void MockUseCounterCallback(v8::Isolate* isolate, + v8::Isolate::UseCounterFeature feature) { + ++global_use_counts[feature]; +} + +} + + +TEST(UseAsmUseCount) { + i::Isolate* isolate = CcTest::i_isolate(); + i::HandleScope scope(isolate); + LocalContext env; + int use_counts[v8::Isolate::kUseCounterFeatureCount] = {}; + global_use_counts = use_counts; + CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback); + CompileRun("\"use asm\";\n" + "var foo = 1;\n" + "\"use asm\";\n" // Only the first one counts. + "function bar() { \"use asm\"; var baz = 1; }"); + CHECK_EQ(2, use_counts[v8::Isolate::kUseAsm]); +} + + +TEST(ErrorsArrowFunctions) { + // Tests that parser and preparser generate the same kind of errors + // on invalid arrow function syntax. + const char* context_data[][2] = { + {"", ";"}, + {"v = ", ";"}, + {"bar ? (", ") : baz;"}, + {"bar ? baz : (", ");"}, + {"bar[", "];"}, + {"bar, ", ";"}, + {"", ", bar;"}, + {NULL, NULL} + }; + + const char* statement_data[] = { + "=> 0", + "=>", + "() =>", + "=> {}", + ") => {}", + ", => {}", + "(,) => {}", + "return => {}", + "() => {'value': 42}", + + // Check that the early return introduced in ParsePrimaryExpression + // does not accept stray closing parentheses. + ")", + ") => 0", + "foo[()]", + "()", + + // Parameter lists with extra parens should be recognized as errors. + "(()) => 0", + "((x)) => 0", + "((x, y)) => 0", + "(x, (y)) => 0", + "((x, y, z)) => 0", + "(x, (y, z)) => 0", + "((x, y), z) => 0", + + // Parameter lists are always validated as strict, so those are errors. + "eval => {}", + "arguments => {}", + "yield => {}", + "interface => {}", + "(eval) => {}", + "(arguments) => {}", + "(yield) => {}", + "(interface) => {}", + "(eval, bar) => {}", + "(bar, eval) => {}", + "(bar, arguments) => {}", + "(bar, yield) => {}", + "(bar, interface) => {}", + // TODO(aperez): Detecting duplicates does not work in PreParser. + // "(bar, bar) => {}", + + // The parameter list is parsed as an expression, but only + // a comma-separated list of identifier is valid. + "32 => {}", + "(32) => {}", + "(a, 32) => {}", + "if => {}", + "(if) => {}", + "(a, if) => {}", + "a + b => {}", + "(a + b) => {}", + "(a + b, c) => {}", + "(a, b - c) => {}", + "\"a\" => {}", + "(\"a\") => {}", + "(\"a\", b) => {}", + "(a, \"b\") => {}", + "-a => {}", + "(-a) => {}", + "(-a, b) => {}", + "(a, -b) => {}", + "{} => {}", + "({}) => {}", + "(a, {}) => {}", + "({}, a) => {}", + "a++ => {}", + "(a++) => {}", + "(a++, b) => {}", + "(a, b++) => {}", + "[] => {}", + "([]) => {}", + "(a, []) => {}", + "([], a) => {}", + "(a = b) => {}", + "(a = b, c) => {}", + "(a, b = c) => {}", + "(foo ? bar : baz) => {}", + "(a, foo ? bar : baz) => {}", + "(foo ? bar : baz, a) => {}", + NULL + }; + + // The test is quite slow, so run it with a reduced set of flags. + static const ParserFlag flags[] = { + kAllowLazy, kAllowHarmonyScoping, kAllowGenerators + }; + static const ParserFlag always_flags[] = { kAllowArrowFunctions }; + RunParserSyncTest(context_data, statement_data, kError, flags, + ARRAY_SIZE(flags), always_flags, ARRAY_SIZE(always_flags)); +} + + +TEST(NoErrorsArrowFunctions) { + // Tests that parser and preparser accept valid arrow functions syntax. + const char* context_data[][2] = { + {"", ";"}, + {"bar ? (", ") : baz;"}, + {"bar ? baz : (", ");"}, + {"bar, ", ";"}, + {"", ", bar;"}, + {NULL, NULL} + }; + + const char* statement_data[] = { + "() => {}", + "() => { return 42 }", + "x => { return x; }", + "(x) => { return x; }", + "(x, y) => { return x + y; }", + "(x, y, z) => { return x + y + z; }", + "(x, y) => { x.a = y; }", + "() => 42", + "x => x", + "x => x * x", + "(x) => x", + "(x) => x * x", + "(x, y) => x + y", + "(x, y, z) => x, y, z", + "(x, y) => x.a = y", + "() => ({'value': 42})", + "x => y => x + y", + "(x, y) => (u, v) => x*u + y*v", + "(x, y) => z => z * (x + y)", + "x => (y, z) => z * (x + y)", + + // Those are comma-separated expressions, with arrow functions as items. + // They stress the code for validating arrow function parameter lists. + "a, b => 0", + "a, b, (c, d) => 0", + "(a, b, (c, d) => 0)", + "(a, b) => 0, (c, d) => 1", + "(a, b => {}, a => a + 1)", + "((a, b) => {}, (a => a + 1))", + "(a, (a, (b, c) => 0))", + + // Arrow has more precedence, this is the same as: foo ? bar : (baz = {}) + "foo ? bar : baz => {}", + NULL + }; + + static const ParserFlag always_flags[] = {kAllowArrowFunctions}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); +} diff --git a/deps/v8/test/cctest/test-platform-linux.cc b/deps/v8/test/cctest/test-platform-linux.cc index f289e94828..613638e78a 100644 --- a/deps/v8/test/cctest/test-platform-linux.cc +++ b/deps/v8/test/cctest/test-platform-linux.cc @@ -31,16 +31,16 @@ #include <stdlib.h> #include <unistd.h> // for usleep() -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "test/cctest/cctest.h" using namespace ::v8::internal; TEST(VirtualMemory) { - VirtualMemory* vm = new VirtualMemory(1 * MB); + v8::base::VirtualMemory* vm = new v8::base::VirtualMemory(1 * MB); CHECK(vm->IsReserved()); void* block_addr = vm->address(); size_t block_size = 4 * KB; @@ -51,8 +51,3 @@ TEST(VirtualMemory) { CHECK(vm->Uncommit(block_addr, block_size)); delete vm; } - - -TEST(GetCurrentProcessId) { - CHECK_EQ(static_cast<int>(getpid()), OS::GetCurrentProcessId()); -} diff --git a/deps/v8/test/cctest/test-platform-macos.cc b/deps/v8/test/cctest/test-platform-macos.cc deleted file mode 100644 index 5bc5f97849..0000000000 --- a/deps/v8/test/cctest/test-platform-macos.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2006-2008 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. -// -// Tests of the TokenLock class from lock.h - -#include <stdlib.h> - -#include "v8.h" -#include "cctest.h" - -using namespace ::v8::internal; diff --git a/deps/v8/test/cctest/test-platform-tls.cc b/deps/v8/test/cctest/test-platform-tls.cc deleted file mode 100644 index 31501d9ef7..0000000000 --- a/deps/v8/test/cctest/test-platform-tls.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2011 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. -// -// Tests of fast TLS support. - -#include "v8.h" - -#include "cctest.h" -#include "checks.h" -#include "platform.h" - -using v8::internal::Thread; - -static const int kValueCount = 128; - -static Thread::LocalStorageKey keys[kValueCount]; - -static void* GetValue(int num) { - return reinterpret_cast<void*>(static_cast<intptr_t>(num + 1)); -} - - -static void DoTest() { - for (int i = 0; i < kValueCount; i++) { - CHECK(!Thread::HasThreadLocal(keys[i])); - } - for (int i = 0; i < kValueCount; i++) { - Thread::SetThreadLocal(keys[i], GetValue(i)); - } - for (int i = 0; i < kValueCount; i++) { - CHECK(Thread::HasThreadLocal(keys[i])); - } - for (int i = 0; i < kValueCount; i++) { - CHECK_EQ(GetValue(i), Thread::GetThreadLocal(keys[i])); - CHECK_EQ(GetValue(i), Thread::GetExistingThreadLocal(keys[i])); - } - for (int i = 0; i < kValueCount; i++) { - Thread::SetThreadLocal(keys[i], GetValue(kValueCount - i - 1)); - } - for (int i = 0; i < kValueCount; i++) { - CHECK(Thread::HasThreadLocal(keys[i])); - } - for (int i = 0; i < kValueCount; i++) { - CHECK_EQ(GetValue(kValueCount - i - 1), - Thread::GetThreadLocal(keys[i])); - CHECK_EQ(GetValue(kValueCount - i - 1), - Thread::GetExistingThreadLocal(keys[i])); - } -} - -class TestThread : public Thread { - public: - TestThread() : Thread("TestThread") {} - - virtual void Run() { - DoTest(); - } -}; - - -TEST(FastTLS) { - for (int i = 0; i < kValueCount; i++) { - keys[i] = Thread::CreateThreadLocalKey(); - } - DoTest(); - TestThread thread; - thread.Start(); - thread.Join(); -} diff --git a/deps/v8/test/cctest/test-platform-win32.cc b/deps/v8/test/cctest/test-platform-win32.cc index d7fdab11ed..cecde74120 100644 --- a/deps/v8/test/cctest/test-platform-win32.cc +++ b/deps/v8/test/cctest/test-platform-win32.cc @@ -29,17 +29,17 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" -#include "win32-headers.h" +#include "src/base/platform/platform.h" +#include "src/base/win32-headers.h" +#include "test/cctest/cctest.h" using namespace ::v8::internal; TEST(VirtualMemory) { - VirtualMemory* vm = new VirtualMemory(1 * MB); + v8::base::VirtualMemory* vm = new v8::base::VirtualMemory(1 * MB); CHECK(vm->IsReserved()); void* block_addr = vm->address(); size_t block_size = 4 * KB; @@ -50,9 +50,3 @@ TEST(VirtualMemory) { CHECK(vm->Uncommit(block_addr, block_size)); delete vm; } - - -TEST(GetCurrentProcessId) { - CHECK_EQ(static_cast<int>(::GetCurrentProcessId()), - OS::GetCurrentProcessId()); -} diff --git a/deps/v8/test/cctest/test-platform.cc b/deps/v8/test/cctest/test-platform.cc index 6b28b18953..3beaccea8e 100644 --- a/deps/v8/test/cctest/test-platform.cc +++ b/deps/v8/test/cctest/test-platform.cc @@ -27,8 +27,8 @@ #include <stdlib.h> -#include "cctest.h" -#include "platform.h" +#include "src/base/platform/platform.h" +#include "test/cctest/cctest.h" using namespace ::v8::internal; @@ -94,7 +94,7 @@ TEST(StackAlignment) { v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo"))); v8::Local<v8::Value> result = foo->Call(global_object, 0, NULL); - CHECK_EQ(0, result->Int32Value() % OS::ActivationFrameAlignment()); + CHECK_EQ(0, result->Int32Value() % v8::base::OS::ActivationFrameAlignment()); } #undef GET_STACK_POINTERS diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index c3198b1512..7578b35fbd 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -27,12 +27,13 @@ // // Tests of profiles generator and utilities. -#include "v8.h" -#include "profile-generator-inl.h" -#include "profiler-extension.h" -#include "cctest.h" -#include "cpu-profiler.h" -#include "../include/v8-profiler.h" +#include "src/v8.h" + +#include "include/v8-profiler.h" +#include "src/cpu-profiler.h" +#include "src/profile-generator-inl.h" +#include "test/cctest/cctest.h" +#include "test/cctest/profiler-extension.h" using i::CodeEntry; using i::CodeMap; @@ -571,14 +572,14 @@ TEST(RecordStackTraceAtStartProfiling) { const_cast<ProfileNode*>(current)->Print(0); // The tree should look like this: // (root) - // (anonymous function) + // "" // a // b // c // There can also be: // startProfiling // if the sampler managed to get a tick. - current = PickChild(current, "(anonymous function)"); + current = PickChild(current, ""); CHECK_NE(NULL, const_cast<ProfileNode*>(current)); current = PickChild(current, "a"); CHECK_NE(NULL, const_cast<ProfileNode*>(current)); @@ -601,7 +602,7 @@ TEST(Issue51919) { CpuProfilesCollection::kMaxSimultaneousProfiles> titles; for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) { i::Vector<char> title = i::Vector<char>::New(16); - i::OS::SNPrintF(title, "%d", i); + i::SNPrintF(title, "%d", i); CHECK(collection.StartProfiling(title.start(), false)); titles[i] = title.start(); } @@ -650,22 +651,22 @@ TEST(ProfileNodeScriptId) { const_cast<v8::CpuProfileNode*>(current))->Print(0); // The tree should look like this: // (root) - // (anonymous function) + // "" // b // a // There can also be: // startProfiling // if the sampler managed to get a tick. - current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName); + current = PickChild(current, ""); CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current)); current = PickChild(current, "b"); CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current)); - CHECK_EQ(script_b->GetId(), current->GetScriptId()); + CHECK_EQ(script_b->GetUnboundScript()->GetId(), current->GetScriptId()); current = PickChild(current, "a"); CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current)); - CHECK_EQ(script_a->GetId(), current->GetScriptId()); + CHECK_EQ(script_a->GetUnboundScript()->GetId(), current->GetScriptId()); } @@ -759,10 +760,10 @@ TEST(BailoutReason) { const_cast<v8::CpuProfileNode*>(current))->Print(0); // The tree should look like this: // (root) - // (anonymous function) + // "" // kTryFinally // kTryCatch - current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName); + current = PickChild(current, ""); CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current)); current = PickChild(current, "TryFinally"); diff --git a/deps/v8/test/cctest/test-random-number-generator.cc b/deps/v8/test/cctest/test-random-number-generator.cc index 93f3257003..a53205c9c8 100644 --- a/deps/v8/test/cctest/test-random-number-generator.cc +++ b/deps/v8/test/cctest/test-random-number-generator.cc @@ -25,10 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "cctest.h" -#include "utils/random-number-generator.h" +#include "src/base/utils/random-number-generator.h" +#include "src/isolate-inl.h" using namespace v8::internal; @@ -39,46 +40,13 @@ static const int kRandomSeeds[] = { }; -TEST(NextIntWithMaxValue) { - for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) { - RandomNumberGenerator rng(kRandomSeeds[n]); - for (int max = 1; max <= kMaxRuns; ++max) { - int n = rng.NextInt(max); - CHECK_LE(0, n); - CHECK_LT(n, max); - } - } -} - - -TEST(NextBoolReturnsBooleanValue) { - for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) { - RandomNumberGenerator rng(kRandomSeeds[n]); - for (int k = 0; k < kMaxRuns; ++k) { - bool b = rng.NextBool(); - CHECK(b == false || b == true); - } - } -} - - -TEST(NextDoubleRange) { - for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) { - RandomNumberGenerator rng(kRandomSeeds[n]); - for (int k = 0; k < kMaxRuns; ++k) { - double d = rng.NextDouble(); - CHECK_LE(0.0, d); - CHECK_LT(d, 1.0); - } - } -} - - TEST(RandomSeedFlagIsUsed) { for (unsigned n = 0; n < ARRAY_SIZE(kRandomSeeds); ++n) { FLAG_random_seed = kRandomSeeds[n]; - RandomNumberGenerator rng1; - RandomNumberGenerator rng2(kRandomSeeds[n]); + v8::Isolate* i = v8::Isolate::New(); + v8::base::RandomNumberGenerator& rng1 = + *reinterpret_cast<Isolate*>(i)->random_number_generator(); + v8::base::RandomNumberGenerator rng2(kRandomSeeds[n]); for (int k = 1; k <= kMaxRuns; ++k) { int64_t i1, i2; rng1.NextBytes(&i1, sizeof(i1)); @@ -88,5 +56,6 @@ TEST(RandomSeedFlagIsUsed) { CHECK_EQ(rng2.NextInt(k), rng1.NextInt(k)); CHECK_EQ(rng2.NextDouble(), rng1.NextDouble()); } + i->Dispose(); } } diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index 10b227c8e9..5c1764eacf 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -28,48 +28,58 @@ #include <stdlib.h> -#include "v8.h" - -#include "ast.h" -#include "char-predicates-inl.h" -#include "cctest.h" -#include "jsregexp.h" -#include "parser.h" -#include "regexp-macro-assembler.h" -#include "regexp-macro-assembler-irregexp.h" -#include "string-stream.h" -#include "zone-inl.h" +#include "src/v8.h" + +#include "src/ast.h" +#include "src/char-predicates-inl.h" +#include "src/jsregexp.h" +#include "src/ostreams.h" +#include "src/parser.h" +#include "src/regexp-macro-assembler.h" +#include "src/regexp-macro-assembler-irregexp.h" +#include "src/string-stream.h" +#include "src/zone-inl.h" #ifdef V8_INTERPRETED_REGEXP -#include "interpreter-irregexp.h" +#include "src/interpreter-irregexp.h" #else // V8_INTERPRETED_REGEXP -#include "macro-assembler.h" -#include "code.h" +#include "src/macro-assembler.h" #if V8_TARGET_ARCH_ARM -#include "arm/assembler-arm.h" -#include "arm/macro-assembler-arm.h" -#include "arm/regexp-macro-assembler-arm.h" +#include "src/arm/assembler-arm.h" // NOLINT +#include "src/arm/macro-assembler-arm.h" +#include "src/arm/regexp-macro-assembler-arm.h" #endif #if V8_TARGET_ARCH_ARM64 -#include "arm64/assembler-arm64.h" -#include "arm64/macro-assembler-arm64.h" -#include "arm64/regexp-macro-assembler-arm64.h" +#include "src/arm64/assembler-arm64.h" +#include "src/arm64/macro-assembler-arm64.h" +#include "src/arm64/regexp-macro-assembler-arm64.h" #endif #if V8_TARGET_ARCH_MIPS -#include "mips/assembler-mips.h" -#include "mips/macro-assembler-mips.h" -#include "mips/regexp-macro-assembler-mips.h" +#include "src/mips/assembler-mips.h" +#include "src/mips/macro-assembler-mips.h" +#include "src/mips/regexp-macro-assembler-mips.h" +#endif +#if V8_TARGET_ARCH_MIPS64 +#include "src/mips64/assembler-mips64.h" +#include "src/mips64/macro-assembler-mips64.h" +#include "src/mips64/regexp-macro-assembler-mips64.h" #endif #if V8_TARGET_ARCH_X64 -#include "x64/assembler-x64.h" -#include "x64/macro-assembler-x64.h" -#include "x64/regexp-macro-assembler-x64.h" +#include "src/x64/assembler-x64.h" +#include "src/x64/macro-assembler-x64.h" +#include "src/x64/regexp-macro-assembler-x64.h" #endif #if V8_TARGET_ARCH_IA32 -#include "ia32/assembler-ia32.h" -#include "ia32/macro-assembler-ia32.h" -#include "ia32/regexp-macro-assembler-ia32.h" +#include "src/ia32/assembler-ia32.h" +#include "src/ia32/macro-assembler-ia32.h" +#include "src/ia32/regexp-macro-assembler-ia32.h" +#endif +#if V8_TARGET_ARCH_X87 +#include "src/x87/assembler-x87.h" +#include "src/x87/macro-assembler-x87.h" +#include "src/x87/regexp-macro-assembler-x87.h" #endif #endif // V8_INTERPRETED_REGEXP +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -85,7 +95,7 @@ static bool CheckParse(const char* input) { } -static SmartArrayPointer<const char> Parse(const char* input) { +static void CheckParseEq(const char* input, const char* expected) { V8::Initialize(NULL); v8::HandleScope scope(CcTest::isolate()); Zone zone(CcTest::i_isolate()); @@ -95,8 +105,9 @@ static SmartArrayPointer<const char> Parse(const char* input) { &reader, false, &result, &zone)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); - SmartArrayPointer<const char> output = result.tree->ToString(&zone); - return output; + OStringStream os; + result.tree->Print(os, &zone); + CHECK_EQ(expected, os.c_str()); } @@ -137,7 +148,6 @@ static MinMaxPair CheckMinMaxMatch(const char* input) { #define CHECK_PARSE_ERROR(input) CHECK(!CheckParse(input)) -#define CHECK_PARSE_EQ(input, expected) CHECK_EQ(expected, Parse(input).get()) #define CHECK_SIMPLE(input, simple) CHECK_EQ(simple, CheckSimple(input)); #define CHECK_MIN_MAX(input, min, max) \ { MinMaxPair min_max = CheckMinMaxMatch(input); \ @@ -150,126 +160,129 @@ TEST(Parser) { CHECK_PARSE_ERROR("?"); - CHECK_PARSE_EQ("abc", "'abc'"); - CHECK_PARSE_EQ("", "%"); - CHECK_PARSE_EQ("abc|def", "(| 'abc' 'def')"); - CHECK_PARSE_EQ("abc|def|ghi", "(| 'abc' 'def' 'ghi')"); - CHECK_PARSE_EQ("^xxx$", "(: @^i 'xxx' @$i)"); - CHECK_PARSE_EQ("ab\\b\\d\\bcd", "(: 'ab' @b [0-9] @b 'cd')"); - CHECK_PARSE_EQ("\\w|\\d", "(| [0-9 A-Z _ a-z] [0-9])"); - CHECK_PARSE_EQ("a*", "(# 0 - g 'a')"); - CHECK_PARSE_EQ("a*?", "(# 0 - n 'a')"); - CHECK_PARSE_EQ("abc+", "(: 'ab' (# 1 - g 'c'))"); - CHECK_PARSE_EQ("abc+?", "(: 'ab' (# 1 - n 'c'))"); - CHECK_PARSE_EQ("xyz?", "(: 'xy' (# 0 1 g 'z'))"); - CHECK_PARSE_EQ("xyz??", "(: 'xy' (# 0 1 n 'z'))"); - CHECK_PARSE_EQ("xyz{0,1}", "(: 'xy' (# 0 1 g 'z'))"); - CHECK_PARSE_EQ("xyz{0,1}?", "(: 'xy' (# 0 1 n 'z'))"); - CHECK_PARSE_EQ("xyz{93}", "(: 'xy' (# 93 93 g 'z'))"); - CHECK_PARSE_EQ("xyz{93}?", "(: 'xy' (# 93 93 n 'z'))"); - CHECK_PARSE_EQ("xyz{1,32}", "(: 'xy' (# 1 32 g 'z'))"); - CHECK_PARSE_EQ("xyz{1,32}?", "(: 'xy' (# 1 32 n 'z'))"); - CHECK_PARSE_EQ("xyz{1,}", "(: 'xy' (# 1 - g 'z'))"); - CHECK_PARSE_EQ("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))"); - CHECK_PARSE_EQ("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'"); - CHECK_PARSE_EQ("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')"); - CHECK_PARSE_EQ("(?:foo)", "'foo'"); - CHECK_PARSE_EQ("(?: foo )", "' foo '"); - CHECK_PARSE_EQ("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))"); - CHECK_PARSE_EQ("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')"); - CHECK_PARSE_EQ("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')"); - CHECK_PARSE_EQ("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')"); - CHECK_PARSE_EQ("()", "(^ %)"); - CHECK_PARSE_EQ("(?=)", "(-> + %)"); - CHECK_PARSE_EQ("[]", "^[\\x00-\\uffff]"); // Doesn't compile on windows - CHECK_PARSE_EQ("[^]", "[\\x00-\\uffff]"); // \uffff isn't in codepage 1252 - CHECK_PARSE_EQ("[x]", "[x]"); - CHECK_PARSE_EQ("[xyz]", "[x y z]"); - CHECK_PARSE_EQ("[a-zA-Z0-9]", "[a-z A-Z 0-9]"); - CHECK_PARSE_EQ("[-123]", "[- 1 2 3]"); - CHECK_PARSE_EQ("[^123]", "^[1 2 3]"); - CHECK_PARSE_EQ("]", "']'"); - CHECK_PARSE_EQ("}", "'}'"); - CHECK_PARSE_EQ("[a-b-c]", "[a-b - c]"); - CHECK_PARSE_EQ("[\\d]", "[0-9]"); - CHECK_PARSE_EQ("[x\\dz]", "[x 0-9 z]"); - CHECK_PARSE_EQ("[\\d-z]", "[0-9 - z]"); - CHECK_PARSE_EQ("[\\d-\\d]", "[0-9 - 0-9]"); - CHECK_PARSE_EQ("[z-\\d]", "[z - 0-9]"); + CheckParseEq("abc", "'abc'"); + CheckParseEq("", "%"); + CheckParseEq("abc|def", "(| 'abc' 'def')"); + CheckParseEq("abc|def|ghi", "(| 'abc' 'def' 'ghi')"); + CheckParseEq("^xxx$", "(: @^i 'xxx' @$i)"); + CheckParseEq("ab\\b\\d\\bcd", "(: 'ab' @b [0-9] @b 'cd')"); + CheckParseEq("\\w|\\d", "(| [0-9 A-Z _ a-z] [0-9])"); + CheckParseEq("a*", "(# 0 - g 'a')"); + CheckParseEq("a*?", "(# 0 - n 'a')"); + CheckParseEq("abc+", "(: 'ab' (# 1 - g 'c'))"); + CheckParseEq("abc+?", "(: 'ab' (# 1 - n 'c'))"); + CheckParseEq("xyz?", "(: 'xy' (# 0 1 g 'z'))"); + CheckParseEq("xyz??", "(: 'xy' (# 0 1 n 'z'))"); + CheckParseEq("xyz{0,1}", "(: 'xy' (# 0 1 g 'z'))"); + CheckParseEq("xyz{0,1}?", "(: 'xy' (# 0 1 n 'z'))"); + CheckParseEq("xyz{93}", "(: 'xy' (# 93 93 g 'z'))"); + CheckParseEq("xyz{93}?", "(: 'xy' (# 93 93 n 'z'))"); + CheckParseEq("xyz{1,32}", "(: 'xy' (# 1 32 g 'z'))"); + CheckParseEq("xyz{1,32}?", "(: 'xy' (# 1 32 n 'z'))"); + CheckParseEq("xyz{1,}", "(: 'xy' (# 1 - g 'z'))"); + CheckParseEq("xyz{1,}?", "(: 'xy' (# 1 - n 'z'))"); + CheckParseEq("a\\fb\\nc\\rd\\te\\vf", "'a\\x0cb\\x0ac\\x0dd\\x09e\\x0bf'"); + CheckParseEq("a\\nb\\bc", "(: 'a\\x0ab' @b 'c')"); + CheckParseEq("(?:foo)", "'foo'"); + CheckParseEq("(?: foo )", "' foo '"); + CheckParseEq("(foo|bar|baz)", "(^ (| 'foo' 'bar' 'baz'))"); + CheckParseEq("foo|(bar|baz)|quux", "(| 'foo' (^ (| 'bar' 'baz')) 'quux')"); + CheckParseEq("foo(?=bar)baz", "(: 'foo' (-> + 'bar') 'baz')"); + CheckParseEq("foo(?!bar)baz", "(: 'foo' (-> - 'bar') 'baz')"); + CheckParseEq("()", "(^ %)"); + CheckParseEq("(?=)", "(-> + %)"); + CheckParseEq("[]", "^[\\x00-\\uffff]"); // Doesn't compile on windows + CheckParseEq("[^]", "[\\x00-\\uffff]"); // \uffff isn't in codepage 1252 + CheckParseEq("[x]", "[x]"); + CheckParseEq("[xyz]", "[x y z]"); + CheckParseEq("[a-zA-Z0-9]", "[a-z A-Z 0-9]"); + CheckParseEq("[-123]", "[- 1 2 3]"); + CheckParseEq("[^123]", "^[1 2 3]"); + CheckParseEq("]", "']'"); + CheckParseEq("}", "'}'"); + CheckParseEq("[a-b-c]", "[a-b - c]"); + CheckParseEq("[\\d]", "[0-9]"); + CheckParseEq("[x\\dz]", "[x 0-9 z]"); + CheckParseEq("[\\d-z]", "[0-9 - z]"); + CheckParseEq("[\\d-\\d]", "[0-9 - 0-9]"); + CheckParseEq("[z-\\d]", "[z - 0-9]"); // Control character outside character class. - CHECK_PARSE_EQ("\\cj\\cJ\\ci\\cI\\ck\\cK", - "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'"); - CHECK_PARSE_EQ("\\c!", "'\\c!'"); - CHECK_PARSE_EQ("\\c_", "'\\c_'"); - CHECK_PARSE_EQ("\\c~", "'\\c~'"); - CHECK_PARSE_EQ("\\c1", "'\\c1'"); + CheckParseEq("\\cj\\cJ\\ci\\cI\\ck\\cK", "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'"); + CheckParseEq("\\c!", "'\\c!'"); + CheckParseEq("\\c_", "'\\c_'"); + CheckParseEq("\\c~", "'\\c~'"); + CheckParseEq("\\c1", "'\\c1'"); // Control character inside character class. - CHECK_PARSE_EQ("[\\c!]", "[\\ c !]"); - CHECK_PARSE_EQ("[\\c_]", "[\\x1f]"); - CHECK_PARSE_EQ("[\\c~]", "[\\ c ~]"); - CHECK_PARSE_EQ("[\\ca]", "[\\x01]"); - CHECK_PARSE_EQ("[\\cz]", "[\\x1a]"); - CHECK_PARSE_EQ("[\\cA]", "[\\x01]"); - CHECK_PARSE_EQ("[\\cZ]", "[\\x1a]"); - CHECK_PARSE_EQ("[\\c1]", "[\\x11]"); - - CHECK_PARSE_EQ("[a\\]c]", "[a ] c]"); - CHECK_PARSE_EQ("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '"); - CHECK_PARSE_EQ("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ # ]"); - CHECK_PARSE_EQ("\\0", "'\\x00'"); - CHECK_PARSE_EQ("\\8", "'8'"); - CHECK_PARSE_EQ("\\9", "'9'"); - CHECK_PARSE_EQ("\\11", "'\\x09'"); - CHECK_PARSE_EQ("\\11a", "'\\x09a'"); - CHECK_PARSE_EQ("\\011", "'\\x09'"); - CHECK_PARSE_EQ("\\00011", "'\\x0011'"); - CHECK_PARSE_EQ("\\118", "'\\x098'"); - CHECK_PARSE_EQ("\\111", "'I'"); - CHECK_PARSE_EQ("\\1111", "'I1'"); - CHECK_PARSE_EQ("(x)(x)(x)\\1", "(: (^ 'x') (^ 'x') (^ 'x') (<- 1))"); - CHECK_PARSE_EQ("(x)(x)(x)\\2", "(: (^ 'x') (^ 'x') (^ 'x') (<- 2))"); - CHECK_PARSE_EQ("(x)(x)(x)\\3", "(: (^ 'x') (^ 'x') (^ 'x') (<- 3))"); - CHECK_PARSE_EQ("(x)(x)(x)\\4", "(: (^ 'x') (^ 'x') (^ 'x') '\\x04')"); - CHECK_PARSE_EQ("(x)(x)(x)\\1*", "(: (^ 'x') (^ 'x') (^ 'x')" - " (# 0 - g (<- 1)))"); - CHECK_PARSE_EQ("(x)(x)(x)\\2*", "(: (^ 'x') (^ 'x') (^ 'x')" - " (# 0 - g (<- 2)))"); - CHECK_PARSE_EQ("(x)(x)(x)\\3*", "(: (^ 'x') (^ 'x') (^ 'x')" - " (# 0 - g (<- 3)))"); - CHECK_PARSE_EQ("(x)(x)(x)\\4*", "(: (^ 'x') (^ 'x') (^ 'x')" - " (# 0 - g '\\x04'))"); - CHECK_PARSE_EQ("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10", - "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')" - " (^ 'x') (^ 'x') (^ 'x') (^ 'x') (<- 10))"); - CHECK_PARSE_EQ("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11", - "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')" - " (^ 'x') (^ 'x') (^ 'x') (^ 'x') '\\x09')"); - CHECK_PARSE_EQ("(a)\\1", "(: (^ 'a') (<- 1))"); - CHECK_PARSE_EQ("(a\\1)", "(^ 'a')"); - CHECK_PARSE_EQ("(\\1a)", "(^ 'a')"); - CHECK_PARSE_EQ("(?=a)?a", "'a'"); - CHECK_PARSE_EQ("(?=a){0,10}a", "'a'"); - CHECK_PARSE_EQ("(?=a){1,10}a", "(: (-> + 'a') 'a')"); - CHECK_PARSE_EQ("(?=a){9,10}a", "(: (-> + 'a') 'a')"); - CHECK_PARSE_EQ("(?!a)?a", "'a'"); - CHECK_PARSE_EQ("\\1(a)", "(^ 'a')"); - CHECK_PARSE_EQ("(?!(a))\\1", "(: (-> - (^ 'a')) (<- 1))"); - CHECK_PARSE_EQ("(?!\\1(a\\1)\\1)\\1", "(: (-> - (: (^ 'a') (<- 1))) (<- 1))"); - CHECK_PARSE_EQ("[\\0]", "[\\x00]"); - CHECK_PARSE_EQ("[\\11]", "[\\x09]"); - CHECK_PARSE_EQ("[\\11a]", "[\\x09 a]"); - CHECK_PARSE_EQ("[\\011]", "[\\x09]"); - CHECK_PARSE_EQ("[\\00011]", "[\\x00 1 1]"); - CHECK_PARSE_EQ("[\\118]", "[\\x09 8]"); - CHECK_PARSE_EQ("[\\111]", "[I]"); - CHECK_PARSE_EQ("[\\1111]", "[I 1]"); - CHECK_PARSE_EQ("\\x34", "'\x34'"); - CHECK_PARSE_EQ("\\x60", "'\x60'"); - CHECK_PARSE_EQ("\\x3z", "'x3z'"); - CHECK_PARSE_EQ("\\c", "'\\c'"); - CHECK_PARSE_EQ("\\u0034", "'\x34'"); - CHECK_PARSE_EQ("\\u003z", "'u003z'"); - CHECK_PARSE_EQ("foo[z]*", "(: 'foo' (# 0 - g [z]))"); + CheckParseEq("[\\c!]", "[\\ c !]"); + CheckParseEq("[\\c_]", "[\\x1f]"); + CheckParseEq("[\\c~]", "[\\ c ~]"); + CheckParseEq("[\\ca]", "[\\x01]"); + CheckParseEq("[\\cz]", "[\\x1a]"); + CheckParseEq("[\\cA]", "[\\x01]"); + CheckParseEq("[\\cZ]", "[\\x1a]"); + CheckParseEq("[\\c1]", "[\\x11]"); + + CheckParseEq("[a\\]c]", "[a ] c]"); + CheckParseEq("\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ", "'[]{}()%^# '"); + CheckParseEq("[\\[\\]\\{\\}\\(\\)\\%\\^\\#\\ ]", "[[ ] { } ( ) % ^ # ]"); + CheckParseEq("\\0", "'\\x00'"); + CheckParseEq("\\8", "'8'"); + CheckParseEq("\\9", "'9'"); + CheckParseEq("\\11", "'\\x09'"); + CheckParseEq("\\11a", "'\\x09a'"); + CheckParseEq("\\011", "'\\x09'"); + CheckParseEq("\\00011", "'\\x0011'"); + CheckParseEq("\\118", "'\\x098'"); + CheckParseEq("\\111", "'I'"); + CheckParseEq("\\1111", "'I1'"); + CheckParseEq("(x)(x)(x)\\1", "(: (^ 'x') (^ 'x') (^ 'x') (<- 1))"); + CheckParseEq("(x)(x)(x)\\2", "(: (^ 'x') (^ 'x') (^ 'x') (<- 2))"); + CheckParseEq("(x)(x)(x)\\3", "(: (^ 'x') (^ 'x') (^ 'x') (<- 3))"); + CheckParseEq("(x)(x)(x)\\4", "(: (^ 'x') (^ 'x') (^ 'x') '\\x04')"); + CheckParseEq("(x)(x)(x)\\1*", + "(: (^ 'x') (^ 'x') (^ 'x')" + " (# 0 - g (<- 1)))"); + CheckParseEq("(x)(x)(x)\\2*", + "(: (^ 'x') (^ 'x') (^ 'x')" + " (# 0 - g (<- 2)))"); + CheckParseEq("(x)(x)(x)\\3*", + "(: (^ 'x') (^ 'x') (^ 'x')" + " (# 0 - g (<- 3)))"); + CheckParseEq("(x)(x)(x)\\4*", + "(: (^ 'x') (^ 'x') (^ 'x')" + " (# 0 - g '\\x04'))"); + CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\10", + "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')" + " (^ 'x') (^ 'x') (^ 'x') (^ 'x') (<- 10))"); + CheckParseEq("(x)(x)(x)(x)(x)(x)(x)(x)(x)(x)\\11", + "(: (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x') (^ 'x')" + " (^ 'x') (^ 'x') (^ 'x') (^ 'x') '\\x09')"); + CheckParseEq("(a)\\1", "(: (^ 'a') (<- 1))"); + CheckParseEq("(a\\1)", "(^ 'a')"); + CheckParseEq("(\\1a)", "(^ 'a')"); + CheckParseEq("(?=a)?a", "'a'"); + CheckParseEq("(?=a){0,10}a", "'a'"); + CheckParseEq("(?=a){1,10}a", "(: (-> + 'a') 'a')"); + CheckParseEq("(?=a){9,10}a", "(: (-> + 'a') 'a')"); + CheckParseEq("(?!a)?a", "'a'"); + CheckParseEq("\\1(a)", "(^ 'a')"); + CheckParseEq("(?!(a))\\1", "(: (-> - (^ 'a')) (<- 1))"); + CheckParseEq("(?!\\1(a\\1)\\1)\\1", "(: (-> - (: (^ 'a') (<- 1))) (<- 1))"); + CheckParseEq("[\\0]", "[\\x00]"); + CheckParseEq("[\\11]", "[\\x09]"); + CheckParseEq("[\\11a]", "[\\x09 a]"); + CheckParseEq("[\\011]", "[\\x09]"); + CheckParseEq("[\\00011]", "[\\x00 1 1]"); + CheckParseEq("[\\118]", "[\\x09 8]"); + CheckParseEq("[\\111]", "[I]"); + CheckParseEq("[\\1111]", "[I 1]"); + CheckParseEq("\\x34", "'\x34'"); + CheckParseEq("\\x60", "'\x60'"); + CheckParseEq("\\x3z", "'x3z'"); + CheckParseEq("\\c", "'\\c'"); + CheckParseEq("\\u0034", "'\x34'"); + CheckParseEq("\\u003z", "'u003z'"); + CheckParseEq("foo[z]*", "(: 'foo' (# 0 - g [z]))"); CHECK_SIMPLE("", false); CHECK_SIMPLE("a", true); @@ -317,22 +330,22 @@ TEST(Parser) { CHECK_SIMPLE("(?!a)?a\\1", false); CHECK_SIMPLE("(?:(?=a))a\\1", false); - CHECK_PARSE_EQ("a{}", "'a{}'"); - CHECK_PARSE_EQ("a{,}", "'a{,}'"); - CHECK_PARSE_EQ("a{", "'a{'"); - CHECK_PARSE_EQ("a{z}", "'a{z}'"); - CHECK_PARSE_EQ("a{1z}", "'a{1z}'"); - CHECK_PARSE_EQ("a{12z}", "'a{12z}'"); - CHECK_PARSE_EQ("a{12,", "'a{12,'"); - CHECK_PARSE_EQ("a{12,3b", "'a{12,3b'"); - CHECK_PARSE_EQ("{}", "'{}'"); - CHECK_PARSE_EQ("{,}", "'{,}'"); - CHECK_PARSE_EQ("{", "'{'"); - CHECK_PARSE_EQ("{z}", "'{z}'"); - CHECK_PARSE_EQ("{1z}", "'{1z}'"); - CHECK_PARSE_EQ("{12z}", "'{12z}'"); - CHECK_PARSE_EQ("{12,", "'{12,'"); - CHECK_PARSE_EQ("{12,3b", "'{12,3b'"); + CheckParseEq("a{}", "'a{}'"); + CheckParseEq("a{,}", "'a{,}'"); + CheckParseEq("a{", "'a{'"); + CheckParseEq("a{z}", "'a{z}'"); + CheckParseEq("a{1z}", "'a{1z}'"); + CheckParseEq("a{12z}", "'a{12z}'"); + CheckParseEq("a{12,", "'a{12,'"); + CheckParseEq("a{12,3b", "'a{12,3b'"); + CheckParseEq("{}", "'{}'"); + CheckParseEq("{,}", "'{,}'"); + CheckParseEq("{", "'{'"); + CheckParseEq("{z}", "'{z}'"); + CheckParseEq("{1z}", "'{1z}'"); + CheckParseEq("{12z}", "'{12z}'"); + CheckParseEq("{12,", "'{12,'"); + CheckParseEq("{12,3b", "'{12,3b'"); CHECK_MIN_MAX("a", 1, 1); CHECK_MIN_MAX("abc", 3, 3); @@ -386,10 +399,10 @@ TEST(Parser) { TEST(ParserRegression) { - CHECK_PARSE_EQ("[A-Z$-][x]", "(! [A-Z $ -] [x])"); - CHECK_PARSE_EQ("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')"); - CHECK_PARSE_EQ("{", "'{'"); - CHECK_PARSE_EQ("a|", "(| 'a' %)"); + CheckParseEq("[A-Z$-][x]", "(! [A-Z $ -] [x])"); + CheckParseEq("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')"); + CheckParseEq("{", "'{'"); + CheckParseEq("a|", "(| 'a' %)"); } static void ExpectError(const char* input, @@ -429,13 +442,11 @@ TEST(Errors) { // Check that we don't allow more than kMaxCapture captures const int kMaxCaptures = 1 << 16; // Must match RegExpParser::kMaxCaptures. const char* kTooManyCaptures = "Too many captures"; - HeapStringAllocator allocator; - StringStream accumulator(&allocator); + OStringStream os; for (int i = 0; i <= kMaxCaptures; i++) { - accumulator.Add("()"); + os << "()"; } - SmartArrayPointer<const char> many_captures(accumulator.ToCString()); - ExpectError(many_captures.get(), kTooManyCaptures); + ExpectError(os.c_str(), kTooManyCaptures); } @@ -663,11 +674,11 @@ TEST(ParsePossessiveRepetition) { // Enable possessive quantifier syntax. FLAG_regexp_possessive_quantifier = true; - CHECK_PARSE_EQ("a*+", "(# 0 - p 'a')"); - CHECK_PARSE_EQ("a++", "(# 1 - p 'a')"); - CHECK_PARSE_EQ("a?+", "(# 0 1 p 'a')"); - CHECK_PARSE_EQ("a{10,20}+", "(# 10 20 p 'a')"); - CHECK_PARSE_EQ("za{10,20}+b", "(: 'z' (# 10 20 p 'a') 'b')"); + CheckParseEq("a*+", "(# 0 - p 'a')"); + CheckParseEq("a++", "(# 1 - p 'a')"); + CheckParseEq("a?+", "(# 0 1 p 'a')"); + CheckParseEq("a{10,20}+", "(# 10 20 p 'a')"); + CheckParseEq("za{10,20}+b", "(: 'z' (# 10 20 p 'a') 'b')"); // Disable possessive quantifier syntax. FLAG_regexp_possessive_quantifier = false; @@ -698,6 +709,10 @@ typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler; typedef RegExpMacroAssemblerARM64 ArchRegExpMacroAssembler; #elif V8_TARGET_ARCH_MIPS typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler; +#elif V8_TARGET_ARCH_MIPS64 +typedef RegExpMacroAssemblerMIPS ArchRegExpMacroAssembler; +#elif V8_TARGET_ARCH_X87 +typedef RegExpMacroAssemblerX87 ArchRegExpMacroAssembler; #endif class ContextInitializer { @@ -1668,26 +1683,26 @@ TEST(CanonicalizeCharacterSets) { list->Add(CharacterRange(30, 40), &zone); list->Add(CharacterRange(50, 60), &zone); set.Canonicalize(); - ASSERT_EQ(3, list->length()); - ASSERT_EQ(10, list->at(0).from()); - ASSERT_EQ(20, list->at(0).to()); - ASSERT_EQ(30, list->at(1).from()); - ASSERT_EQ(40, list->at(1).to()); - ASSERT_EQ(50, list->at(2).from()); - ASSERT_EQ(60, list->at(2).to()); + DCHECK_EQ(3, list->length()); + DCHECK_EQ(10, list->at(0).from()); + DCHECK_EQ(20, list->at(0).to()); + DCHECK_EQ(30, list->at(1).from()); + DCHECK_EQ(40, list->at(1).to()); + DCHECK_EQ(50, list->at(2).from()); + DCHECK_EQ(60, list->at(2).to()); list->Rewind(0); list->Add(CharacterRange(10, 20), &zone); list->Add(CharacterRange(50, 60), &zone); list->Add(CharacterRange(30, 40), &zone); set.Canonicalize(); - ASSERT_EQ(3, list->length()); - ASSERT_EQ(10, list->at(0).from()); - ASSERT_EQ(20, list->at(0).to()); - ASSERT_EQ(30, list->at(1).from()); - ASSERT_EQ(40, list->at(1).to()); - ASSERT_EQ(50, list->at(2).from()); - ASSERT_EQ(60, list->at(2).to()); + DCHECK_EQ(3, list->length()); + DCHECK_EQ(10, list->at(0).from()); + DCHECK_EQ(20, list->at(0).to()); + DCHECK_EQ(30, list->at(1).from()); + DCHECK_EQ(40, list->at(1).to()); + DCHECK_EQ(50, list->at(2).from()); + DCHECK_EQ(60, list->at(2).to()); list->Rewind(0); list->Add(CharacterRange(30, 40), &zone); @@ -1696,26 +1711,26 @@ TEST(CanonicalizeCharacterSets) { list->Add(CharacterRange(100, 100), &zone); list->Add(CharacterRange(1, 1), &zone); set.Canonicalize(); - ASSERT_EQ(5, list->length()); - ASSERT_EQ(1, list->at(0).from()); - ASSERT_EQ(1, list->at(0).to()); - ASSERT_EQ(10, list->at(1).from()); - ASSERT_EQ(20, list->at(1).to()); - ASSERT_EQ(25, list->at(2).from()); - ASSERT_EQ(25, list->at(2).to()); - ASSERT_EQ(30, list->at(3).from()); - ASSERT_EQ(40, list->at(3).to()); - ASSERT_EQ(100, list->at(4).from()); - ASSERT_EQ(100, list->at(4).to()); + DCHECK_EQ(5, list->length()); + DCHECK_EQ(1, list->at(0).from()); + DCHECK_EQ(1, list->at(0).to()); + DCHECK_EQ(10, list->at(1).from()); + DCHECK_EQ(20, list->at(1).to()); + DCHECK_EQ(25, list->at(2).from()); + DCHECK_EQ(25, list->at(2).to()); + DCHECK_EQ(30, list->at(3).from()); + DCHECK_EQ(40, list->at(3).to()); + DCHECK_EQ(100, list->at(4).from()); + DCHECK_EQ(100, list->at(4).to()); list->Rewind(0); list->Add(CharacterRange(10, 19), &zone); list->Add(CharacterRange(21, 30), &zone); list->Add(CharacterRange(20, 20), &zone); set.Canonicalize(); - ASSERT_EQ(1, list->length()); - ASSERT_EQ(10, list->at(0).from()); - ASSERT_EQ(30, list->at(0).to()); + DCHECK_EQ(1, list->length()); + DCHECK_EQ(10, list->at(0).from()); + DCHECK_EQ(30, list->at(0).to()); } @@ -1798,8 +1813,8 @@ TEST(CharacterRangeMerge) { offset += 9; } - ASSERT(CharacterRange::IsCanonical(&l1)); - ASSERT(CharacterRange::IsCanonical(&l2)); + DCHECK(CharacterRange::IsCanonical(&l1)); + DCHECK(CharacterRange::IsCanonical(&l2)); ZoneList<CharacterRange> first_only(4, &zone); ZoneList<CharacterRange> second_only(4, &zone); diff --git a/deps/v8/test/cctest/test-reloc-info.cc b/deps/v8/test/cctest/test-reloc-info.cc index 5ab9e803c2..94ed287c44 100644 --- a/deps/v8/test/cctest/test-reloc-info.cc +++ b/deps/v8/test/cctest/test-reloc-info.cc @@ -26,8 +26,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "cctest.h" -#include "assembler.h" +#include "src/assembler.h" +#include "test/cctest/cctest.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/test-representation.cc b/deps/v8/test/cctest/test-representation.cc index 95a65cbbf7..fc1f531331 100644 --- a/deps/v8/test/cctest/test-representation.cc +++ b/deps/v8/test/cctest/test-representation.cc @@ -25,9 +25,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "cctest.h" -#include "types.h" -#include "property-details.h" +#include "test/cctest/cctest.h" + +#include "src/property-details.h" +#include "src/types.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-semaphore.cc b/deps/v8/test/cctest/test-semaphore.cc index 895303f4f8..c7fca519dc 100644 --- a/deps/v8/test/cctest/test-semaphore.cc +++ b/deps/v8/test/cctest/test-semaphore.cc @@ -27,38 +27,39 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "platform.h" -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "test/cctest/cctest.h" using namespace ::v8::internal; -class WaitAndSignalThread V8_FINAL : public Thread { - public: - explicit WaitAndSignalThread(Semaphore* semaphore) - : Thread("WaitAndSignalThread"), semaphore_(semaphore) {} +class WaitAndSignalThread V8_FINAL : public v8::base::Thread { + public: + explicit WaitAndSignalThread(v8::base::Semaphore* semaphore) + : Thread(Options("WaitAndSignalThread")), semaphore_(semaphore) {} virtual ~WaitAndSignalThread() {} virtual void Run() V8_OVERRIDE { for (int n = 0; n < 1000; ++n) { semaphore_->Wait(); - bool result = semaphore_->WaitFor(TimeDelta::FromMicroseconds(1)); - ASSERT(!result); + bool result = + semaphore_->WaitFor(v8::base::TimeDelta::FromMicroseconds(1)); + DCHECK(!result); USE(result); semaphore_->Signal(); } } - private: - Semaphore* semaphore_; + private: + v8::base::Semaphore* semaphore_; }; TEST(WaitAndSignal) { - Semaphore semaphore(0); + v8::base::Semaphore semaphore(0); WaitAndSignalThread t1(&semaphore); WaitAndSignalThread t2(&semaphore); @@ -73,33 +74,33 @@ TEST(WaitAndSignal) { semaphore.Wait(); - bool result = semaphore.WaitFor(TimeDelta::FromMicroseconds(1)); - ASSERT(!result); + bool result = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(1)); + DCHECK(!result); USE(result); } TEST(WaitFor) { bool ok; - Semaphore semaphore(0); + v8::base::Semaphore semaphore(0); // Semaphore not signalled - timeout. - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(0)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(0)); CHECK(!ok); - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(100)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(100)); CHECK(!ok); - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(1000)); CHECK(!ok); // Semaphore signalled - no timeout. semaphore.Signal(); - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(0)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(0)); CHECK(ok); semaphore.Signal(); - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(100)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(100)); CHECK(ok); semaphore.Signal(); - ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(1000)); + ok = semaphore.WaitFor(v8::base::TimeDelta::FromMicroseconds(1000)); CHECK(ok); } @@ -110,13 +111,13 @@ static const int kBufferSize = 4096; // GCD(buffer size, alphabet size) = 1 static char buffer[kBufferSize]; static const int kDataSize = kBufferSize * kAlphabetSize * 10; -static Semaphore free_space(kBufferSize); -static Semaphore used_space(0); +static v8::base::Semaphore free_space(kBufferSize); +static v8::base::Semaphore used_space(0); -class ProducerThread V8_FINAL : public Thread { - public: - ProducerThread() : Thread("ProducerThread") {} +class ProducerThread V8_FINAL : public v8::base::Thread { + public: + ProducerThread() : Thread(Options("ProducerThread")) {} virtual ~ProducerThread() {} virtual void Run() V8_OVERRIDE { @@ -129,15 +130,15 @@ class ProducerThread V8_FINAL : public Thread { }; -class ConsumerThread V8_FINAL : public Thread { - public: - ConsumerThread() : Thread("ConsumerThread") {} +class ConsumerThread V8_FINAL : public v8::base::Thread { + public: + ConsumerThread() : Thread(Options("ConsumerThread")) {} virtual ~ConsumerThread() {} virtual void Run() V8_OVERRIDE { for (int n = 0; n < kDataSize; ++n) { used_space.Wait(); - ASSERT_EQ(static_cast<int>(alphabet[n % kAlphabetSize]), + DCHECK_EQ(static_cast<int>(alphabet[n % kAlphabetSize]), static_cast<int>(buffer[n % kBufferSize])); free_space.Signal(); } diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 10c35c1c4d..9ae90c4776 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -27,21 +27,22 @@ #include <signal.h> -#include "sys/stat.h" - -#include "v8.h" - -#include "debug.h" -#include "ic-inl.h" -#include "runtime.h" -#include "serialize.h" -#include "scopeinfo.h" -#include "snapshot.h" -#include "cctest.h" -#include "spaces.h" -#include "objects.h" -#include "natives.h" -#include "bootstrapper.h" +#include <sys/stat.h> + +#include "src/v8.h" + +#include "src/bootstrapper.h" +#include "src/compilation-cache.h" +#include "src/debug.h" +#include "src/heap/spaces.h" +#include "src/ic-inl.h" +#include "src/natives.h" +#include "src/objects.h" +#include "src/runtime.h" +#include "src/scopeinfo.h" +#include "src/serialize.h" +#include "src/snapshot.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -77,7 +78,7 @@ static int* counter_function(const char* name) { return &local_counters[hash]; } hash = (hash + 1) % kCounters; - ASSERT(hash != original_hash); // Hash table has been filled up. + DCHECK(hash != original_hash); // Hash table has been filled up. } } @@ -115,21 +116,21 @@ TEST(ExternalReferenceEncoder) { encoder.Encode(total_compile_size.address())); ExternalReference stack_limit_address = ExternalReference::address_of_stack_limit(isolate); - CHECK_EQ(make_code(UNCLASSIFIED, 4), + CHECK_EQ(make_code(UNCLASSIFIED, 2), encoder.Encode(stack_limit_address.address())); ExternalReference real_stack_limit_address = ExternalReference::address_of_real_stack_limit(isolate); - CHECK_EQ(make_code(UNCLASSIFIED, 5), + CHECK_EQ(make_code(UNCLASSIFIED, 3), encoder.Encode(real_stack_limit_address.address())); - CHECK_EQ(make_code(UNCLASSIFIED, 16), + CHECK_EQ(make_code(UNCLASSIFIED, 8), encoder.Encode(ExternalReference::debug_break(isolate).address())); - CHECK_EQ(make_code(UNCLASSIFIED, 10), - encoder.Encode( - ExternalReference::new_space_start(isolate).address())); - CHECK_EQ(make_code(UNCLASSIFIED, 3), - encoder.Encode( - ExternalReference::roots_array_start(isolate).address())); - CHECK_EQ(make_code(UNCLASSIFIED, 52), + CHECK_EQ( + make_code(UNCLASSIFIED, 4), + encoder.Encode(ExternalReference::new_space_start(isolate).address())); + CHECK_EQ( + make_code(UNCLASSIFIED, 1), + encoder.Encode(ExternalReference::roots_array_start(isolate).address())); + CHECK_EQ(make_code(UNCLASSIFIED, 34), encoder.Encode(ExternalReference::cpu_features().address())); } @@ -152,20 +153,20 @@ TEST(ExternalReferenceDecoder) { make_code(STATS_COUNTER, Counters::k_total_compile_size))); CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 4))); + decoder.Decode(make_code(UNCLASSIFIED, 2))); CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 5))); + decoder.Decode(make_code(UNCLASSIFIED, 3))); CHECK_EQ(ExternalReference::debug_break(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 16))); + decoder.Decode(make_code(UNCLASSIFIED, 8))); CHECK_EQ(ExternalReference::new_space_start(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 10))); + decoder.Decode(make_code(UNCLASSIFIED, 4))); } class FileByteSink : public SnapshotByteSink { public: explicit FileByteSink(const char* snapshot_file) { - fp_ = OS::FOpen(snapshot_file, "wb"); + fp_ = v8::base::OS::FOpen(snapshot_file, "wb"); file_name_ = snapshot_file; if (fp_ == NULL) { PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file); @@ -177,9 +178,9 @@ class FileByteSink : public SnapshotByteSink { fclose(fp_); } } - virtual void Put(int byte, const char* description) { + virtual void Put(byte b, const char* description) { if (fp_ != NULL) { - fputc(byte, fp_); + fputc(b, fp_); } } virtual int Position() { @@ -210,8 +211,8 @@ void FileByteSink::WriteSpaceUsed( int property_cell_space_used) { int file_name_length = StrLength(file_name_) + 10; Vector<char> name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(name, "%s.size", file_name_); - FILE* fp = OS::FOpen(name.start(), "w"); + SNPrintF(name, "%s.size", file_name_); + FILE* fp = v8::base::OS::FOpen(name.start(), "w"); name.Dispose(); fprintf(fp, "new %d\n", new_space_used); fprintf(fp, "pointer %d\n", pointer_space_used); @@ -262,7 +263,7 @@ static void Serialize() { // Test that the whole heap can be serialized. TEST(Serialize) { if (!Snapshot::HaveASnapshotToStartFrom()) { - Serializer::RequestEnable(CcTest::i_isolate()); + CcTest::i_isolate()->enable_serializer(); v8::V8::Initialize(); Serialize(); } @@ -272,7 +273,7 @@ TEST(Serialize) { // Test that heap serialization is non-destructive. TEST(SerializeTwice) { if (!Snapshot::HaveASnapshotToStartFrom()) { - Serializer::RequestEnable(CcTest::i_isolate()); + CcTest::i_isolate()->enable_serializer(); v8::V8::Initialize(); Serialize(); Serialize(); @@ -283,8 +284,60 @@ TEST(SerializeTwice) { //---------------------------------------------------------------------------- // Tests that the heap can be deserialized. + +static void ReserveSpaceForSnapshot(Deserializer* deserializer, + const char* file_name) { + int file_name_length = StrLength(file_name) + 10; + Vector<char> name = Vector<char>::New(file_name_length + 1); + SNPrintF(name, "%s.size", file_name); + FILE* fp = v8::base::OS::FOpen(name.start(), "r"); + name.Dispose(); + int new_size, pointer_size, data_size, code_size, map_size, cell_size, + property_cell_size; +#ifdef _MSC_VER + // Avoid warning about unsafe fscanf from MSVC. + // Please note that this is only fine if %c and %s are not being used. +#define fscanf fscanf_s +#endif + CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size)); + CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size)); + CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size)); + CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size)); + CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size)); + CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size)); + CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size)); +#ifdef _MSC_VER +#undef fscanf +#endif + fclose(fp); + deserializer->set_reservation(NEW_SPACE, new_size); + deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size); + deserializer->set_reservation(OLD_DATA_SPACE, data_size); + deserializer->set_reservation(CODE_SPACE, code_size); + deserializer->set_reservation(MAP_SPACE, map_size); + deserializer->set_reservation(CELL_SPACE, cell_size); + deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size); +} + + +bool InitializeFromFile(const char* snapshot_file) { + int len; + byte* str = ReadBytes(snapshot_file, &len); + if (!str) return false; + bool success; + { + SnapshotByteSource source(str, len); + Deserializer deserializer(&source); + ReserveSpaceForSnapshot(&deserializer, snapshot_file); + success = V8::Initialize(&deserializer); + } + DeleteArray(str); + return success; +} + + static void Deserialize() { - CHECK(Snapshot::Initialize(FLAG_testing_serialization_file)); + CHECK(InitializeFromFile(FLAG_testing_serialization_file)); } @@ -370,7 +423,7 @@ DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2, TEST(PartialSerialization) { if (!Snapshot::HaveASnapshotToStartFrom()) { Isolate* isolate = CcTest::i_isolate(); - Serializer::RequestEnable(isolate); + CcTest::i_isolate()->enable_serializer(); v8::V8::Initialize(); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); Heap* heap = isolate->heap(); @@ -380,7 +433,7 @@ TEST(PartialSerialization) { HandleScope scope(isolate); env.Reset(v8_isolate, v8::Context::New(v8_isolate)); } - ASSERT(!env.IsEmpty()); + DCHECK(!env.IsEmpty()); { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); @@ -398,13 +451,13 @@ TEST(PartialSerialization) { { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo"); - ASSERT(!foo.IsEmpty()); + DCHECK(!foo.IsEmpty()); raw_foo = *(v8::Utils::OpenHandle(*foo)); } int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); { v8::HandleScope handle_scope(v8_isolate); @@ -443,48 +496,13 @@ TEST(PartialSerialization) { } -static void ReserveSpaceForSnapshot(Deserializer* deserializer, - const char* file_name) { - int file_name_length = StrLength(file_name) + 10; - Vector<char> name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(name, "%s.size", file_name); - FILE* fp = OS::FOpen(name.start(), "r"); - name.Dispose(); - int new_size, pointer_size, data_size, code_size, map_size, cell_size, - property_cell_size; -#ifdef _MSC_VER - // Avoid warning about unsafe fscanf from MSVC. - // Please note that this is only fine if %c and %s are not being used. -#define fscanf fscanf_s -#endif - CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size)); - CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size)); - CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size)); - CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size)); - CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size)); - CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size)); - CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size)); -#ifdef _MSC_VER -#undef fscanf -#endif - fclose(fp); - deserializer->set_reservation(NEW_SPACE, new_size); - deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size); - deserializer->set_reservation(OLD_DATA_SPACE, data_size); - deserializer->set_reservation(CODE_SPACE, code_size); - deserializer->set_reservation(MAP_SPACE, map_size); - deserializer->set_reservation(CELL_SPACE, cell_size); - deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size); -} - - DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { - if (!Snapshot::IsEnabled()) { + if (!Snapshot::HaveASnapshotToStartFrom()) { int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - CHECK(Snapshot::Initialize(startup_name.start())); + CHECK(InitializeFromFile(startup_name.start())); startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; @@ -521,7 +539,7 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { TEST(ContextSerialization) { if (!Snapshot::HaveASnapshotToStartFrom()) { Isolate* isolate = CcTest::i_isolate(); - Serializer::RequestEnable(isolate); + CcTest::i_isolate()->enable_serializer(); v8::V8::Initialize(); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); Heap* heap = isolate->heap(); @@ -531,7 +549,7 @@ TEST(ContextSerialization) { HandleScope scope(isolate); env.Reset(v8_isolate, v8::Context::New(v8_isolate)); } - ASSERT(!env.IsEmpty()); + DCHECK(!env.IsEmpty()); { v8::HandleScope handle_scope(v8_isolate); v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); @@ -548,7 +566,7 @@ TEST(ContextSerialization) { int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); { v8::HandleScope handle_scope(v8_isolate); @@ -594,9 +612,9 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { if (!Snapshot::HaveASnapshotToStartFrom()) { int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - CHECK(Snapshot::Initialize(startup_name.start())); + CHECK(InitializeFromFile(startup_name.start())); startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; @@ -644,3 +662,185 @@ DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) { bool ArtificialFailure2 = false; CHECK(ArtificialFailure2); } + + +int CountBuiltins() { + // Check that we have not deserialized any additional builtin. + HeapIterator iterator(CcTest::heap()); + DisallowHeapAllocation no_allocation; + int counter = 0; + for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { + if (obj->IsCode() && Code::cast(obj)->kind() == Code::BUILTIN) counter++; + } + return counter; +} + + +TEST(SerializeToplevelOnePlusOne) { + FLAG_serialize_toplevel = true; + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. + + v8::HandleScope scope(CcTest::isolate()); + + const char* source = "1 + 1"; + + Handle<String> orig_source = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + Handle<String> copy_source = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + CHECK(!orig_source.is_identical_to(copy_source)); + CHECK(orig_source->Equals(*copy_source)); + + ScriptData* cache = NULL; + + Handle<SharedFunctionInfo> orig = Compiler::CompileScript( + orig_source, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE); + + int builtins_count = CountBuiltins(); + + Handle<SharedFunctionInfo> copy; + { + DisallowCompilation no_compile_expected(isolate); + copy = Compiler::CompileScript( + copy_source, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE); + } + + CHECK_NE(*orig, *copy); + CHECK(Script::cast(copy->script())->source() == *copy_source); + + Handle<JSFunction> copy_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + copy, isolate->native_context()); + Handle<JSObject> global(isolate->context()->global_object()); + Handle<Object> copy_result = + Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); + CHECK_EQ(2, Handle<Smi>::cast(copy_result)->value()); + + CHECK_EQ(builtins_count, CountBuiltins()); + + delete cache; +} + + +TEST(SerializeToplevelInternalizedString) { + FLAG_serialize_toplevel = true; + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + isolate->compilation_cache()->Disable(); // Disable same-isolate code cache. + + v8::HandleScope scope(CcTest::isolate()); + + const char* source = "'string1'"; + + Handle<String> orig_source = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + Handle<String> copy_source = isolate->factory() + ->NewStringFromUtf8(CStrVector(source)) + .ToHandleChecked(); + CHECK(!orig_source.is_identical_to(copy_source)); + CHECK(orig_source->Equals(*copy_source)); + + Handle<JSObject> global(isolate->context()->global_object()); + ScriptData* cache = NULL; + + Handle<SharedFunctionInfo> orig = Compiler::CompileScript( + orig_source, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE); + Handle<JSFunction> orig_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + orig, isolate->native_context()); + Handle<Object> orig_result = + Execution::Call(isolate, orig_fun, global, 0, NULL).ToHandleChecked(); + CHECK(orig_result->IsInternalizedString()); + + int builtins_count = CountBuiltins(); + + Handle<SharedFunctionInfo> copy; + { + DisallowCompilation no_compile_expected(isolate); + copy = Compiler::CompileScript( + copy_source, Handle<String>(), 0, 0, false, + Handle<Context>(isolate->native_context()), NULL, &cache, + v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE); + } + CHECK_NE(*orig, *copy); + CHECK(Script::cast(copy->script())->source() == *copy_source); + + Handle<JSFunction> copy_fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + copy, isolate->native_context()); + CHECK_NE(*orig_fun, *copy_fun); + Handle<Object> copy_result = + Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked(); + CHECK(orig_result.is_identical_to(copy_result)); + Handle<String> expected = + isolate->factory()->NewStringFromAsciiChecked("string1"); + + CHECK(Handle<String>::cast(copy_result)->Equals(*expected)); + CHECK_EQ(builtins_count, CountBuiltins()); + + delete cache; +} + + +TEST(SerializeToplevelIsolates) { + FLAG_serialize_toplevel = true; + + const char* source = "function f() { return 'abc'; }; f() + 'def'"; + v8::ScriptCompiler::CachedData* cache; + + v8::Isolate* isolate1 = v8::Isolate::New(); + v8::Isolate* isolate2 = v8::Isolate::New(); + { + v8::Isolate::Scope iscope(isolate1); + v8::HandleScope scope(isolate1); + v8::Local<v8::Context> context = v8::Context::New(isolate1); + v8::Context::Scope context_scope(context); + + v8::Local<v8::String> source_str = v8_str(source); + v8::ScriptOrigin origin(v8_str("test")); + v8::ScriptCompiler::Source source(source_str, origin); + v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound( + isolate1, &source, v8::ScriptCompiler::kProduceCodeCache); + const v8::ScriptCompiler::CachedData* data = source.GetCachedData(); + // Persist cached data. + uint8_t* buffer = NewArray<uint8_t>(data->length); + MemCopy(buffer, data->data, data->length); + cache = new v8::ScriptCompiler::CachedData( + buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned); + + v8::Local<v8::Value> result = script->BindToCurrentContext()->Run(); + CHECK(result->ToString()->Equals(v8_str("abcdef"))); + } + isolate1->Dispose(); + + { + v8::Isolate::Scope iscope(isolate2); + v8::HandleScope scope(isolate2); + v8::Local<v8::Context> context = v8::Context::New(isolate2); + v8::Context::Scope context_scope(context); + + v8::Local<v8::String> source_str = v8_str(source); + v8::ScriptOrigin origin(v8_str("test")); + v8::ScriptCompiler::Source source(source_str, origin, cache); + v8::Local<v8::UnboundScript> script; + { + DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2)); + script = v8::ScriptCompiler::CompileUnbound( + isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache); + } + v8::Local<v8::Value> result = script->BindToCurrentContext()->Run(); + CHECK(result->ToString()->Equals(v8_str("abcdef"))); + } + isolate2->Dispose(); +} diff --git a/deps/v8/test/cctest/test-socket.cc b/deps/v8/test/cctest/test-socket.cc deleted file mode 100644 index 47d8b17831..0000000000 --- a/deps/v8/test/cctest/test-socket.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2009 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. - -#include "v8.h" -#include "platform.h" -#include "platform/socket.h" -#include "cctest.h" - - -using namespace ::v8::internal; - - -class SocketListenerThread : public Thread { - public: - SocketListenerThread(int port, int data_size) - : Thread("SocketListenerThread"), - port_(port), - data_size_(data_size), - server_(NULL), - client_(NULL), - listening_(0) { - data_ = new char[data_size_]; - } - ~SocketListenerThread() { - // Close both sockets. - delete client_; - delete server_; - delete[] data_; - } - - void Run(); - void WaitForListening() { listening_.Wait(); } - char* data() { return data_; } - - private: - int port_; - char* data_; - int data_size_; - Socket* server_; // Server socket used for bind/accept. - Socket* client_; // Single client connection used by the test. - Semaphore listening_; // Signalled when the server socket is in listen mode. -}; - - -void SocketListenerThread::Run() { - bool ok; - - // Create the server socket and bind it to the requested port. - server_ = new Socket; - server_->SetReuseAddress(true); - CHECK(server_ != NULL); - ok = server_->Bind(port_); - CHECK(ok); - - // Listen for new connections. - ok = server_->Listen(1); - CHECK(ok); - listening_.Signal(); - - // Accept a connection. - client_ = server_->Accept(); - CHECK(client_ != NULL); - - // Read the expected niumber of bytes of data. - int bytes_read = 0; - while (bytes_read < data_size_) { - bytes_read += client_->Receive(data_ + bytes_read, data_size_ - bytes_read); - } -} - - -static bool SendAll(Socket* socket, const char* data, int len) { - int sent_len = 0; - while (sent_len < len) { - int status = socket->Send(data, len); - if (status <= 0) { - return false; - } - sent_len += status; - } - return true; -} - - -static void SendAndReceive(int port, char *data, int len) { - static const char* kLocalhost = "localhost"; - - bool ok; - - // Make a string with the port number. - const int kPortBuferLen = 6; - char port_str[kPortBuferLen]; - OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port); - - // Create a socket listener. - SocketListenerThread* listener = new SocketListenerThread(port, len); - listener->Start(); - listener->WaitForListening(); - - // Connect and write some data. - Socket* client = new Socket; - CHECK(client != NULL); - ok = client->Connect(kLocalhost, port_str); - CHECK(ok); - - // Send all the data. - ok = SendAll(client, data, len); - CHECK(ok); - - // Wait until data is received. - listener->Join(); - - // Check that data received is the same as data send. - for (int i = 0; i < len; i++) { - CHECK(data[i] == listener->data()[i]); - } - - // Close the client before the listener to avoid TIME_WAIT issues. - client->Shutdown(); - delete client; - delete listener; -} - - -TEST(Socket) { - // Make sure this port is not used by other tests to allow tests to run in - // parallel. - static const int kPort = 5859 + FlagDependentPortOffset(); - - // Send and receive some data. - static const int kBufferSizeSmall = 20; - char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij"; - SendAndReceive(kPort, small_data, kBufferSizeSmall); - - // Send and receive some more data. - static const int kBufferSizeMedium = 10000; - char* medium_data = new char[kBufferSizeMedium]; - for (int i = 0; i < kBufferSizeMedium; i++) { - medium_data[i] = i % 256; - } - SendAndReceive(kPort, medium_data, kBufferSizeMedium); - delete[] medium_data; - - // Send and receive even more data. - static const int kBufferSizeLarge = 1000000; - char* large_data = new char[kBufferSizeLarge]; - for (int i = 0; i < kBufferSizeLarge; i++) { - large_data[i] = i % 256; - } - SendAndReceive(kPort, large_data, kBufferSizeLarge); - delete[] large_data; -} diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc index 47e2536fc9..0062094400 100644 --- a/deps/v8/test/cctest/test-spaces.cc +++ b/deps/v8/test/cctest/test-spaces.cc @@ -27,8 +27,10 @@ #include <stdlib.h> -#include "v8.h" -#include "cctest.h" +#include "src/snapshot.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" + using namespace v8::internal; @@ -169,12 +171,14 @@ static void VerifyMemoryChunk(Isolate* isolate, commit_area_size, executable, NULL); - size_t alignment = code_range->exists() ? - MemoryChunk::kAlignment : OS::CommitPageSize(); - size_t reserved_size = ((executable == EXECUTABLE)) - ? RoundUp(header_size + guard_size + reserve_area_size + guard_size, - alignment) - : RoundUp(header_size + reserve_area_size, OS::CommitPageSize()); + size_t alignment = code_range != NULL && code_range->valid() ? + MemoryChunk::kAlignment : v8::base::OS::CommitPageSize(); + size_t reserved_size = + ((executable == EXECUTABLE)) + ? RoundUp(header_size + guard_size + reserve_area_size + guard_size, + alignment) + : RoundUp(header_size + reserve_area_size, + v8::base::OS::CommitPageSize()); CHECK(memory_chunk->size() == reserved_size); CHECK(memory_chunk->area_start() < memory_chunk->address() + memory_chunk->size()); @@ -221,7 +225,7 @@ TEST(MemoryChunk) { // With CodeRange. CodeRange* code_range = new CodeRange(isolate); - const int code_range_size = 32 * MB; + const size_t code_range_size = 32 * MB; if (!code_range->SetUp(code_range_size)) return; VerifyMemoryChunk(isolate, @@ -393,7 +397,7 @@ TEST(LargeObjectSpace) { if (allocation.IsRetry()) break; } CHECK(lo->Available() < available); - }; + } CHECK(!lo->IsEmpty()); @@ -403,11 +407,15 @@ TEST(LargeObjectSpace) { TEST(SizeOfFirstPageIsLargeEnough) { if (i::FLAG_always_opt) return; + // Bootstrapping without a snapshot causes more allocations. + if (!i::Snapshot::HaveASnapshotToStartFrom()) return; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); // 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. + if (i == CODE_SPACE && i::FLAG_debug_code) continue; CHECK_EQ(1, isolate->heap()->paged_space(i)->CountTotalPages()); } @@ -415,6 +423,8 @@ TEST(SizeOfFirstPageIsLargeEnough) { HandleScope scope(isolate); CompileRun("/*empty*/"); 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. + if (i == CODE_SPACE && i::FLAG_debug_code) continue; CHECK_EQ(1, isolate->heap()->paged_space(i)->CountTotalPages()); } diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 706836c1c9..b55780182b 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -32,12 +32,12 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "api.h" -#include "factory.h" -#include "objects.h" -#include "cctest.h" +#include "src/api.h" +#include "src/factory.h" +#include "src/objects.h" +#include "test/cctest/cctest.h" // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry class MyRandomNumberGenerator { @@ -77,7 +77,7 @@ class MyRandomNumberGenerator { } bool next(double threshold) { - ASSERT(threshold >= 0.0 && threshold <= 1.0); + DCHECK(threshold >= 0.0 && threshold <= 1.0); if (threshold == 1.0) return true; if (threshold == 0.0) return false; uint32_t value = next() % 100000; @@ -1201,10 +1201,9 @@ TEST(SliceFromSlice) { TEST(AsciiArrayJoin) { // Set heap limits. - static const int K = 1024; v8::ResourceConstraints constraints; - constraints.set_max_new_space_size(2 * K * K); - constraints.set_max_old_space_size(4 * K * K); + constraints.set_max_semi_space_size(1); + constraints.set_max_old_space_size(4); v8::SetResourceConstraints(CcTest::isolate(), &constraints); // String s is made of 2^17 = 131072 'c' characters and a is an array diff --git a/deps/v8/test/cctest/test-strtod.cc b/deps/v8/test/cctest/test-strtod.cc index bebf4d14b0..7c1118603e 100644 --- a/deps/v8/test/cctest/test-strtod.cc +++ b/deps/v8/test/cctest/test-strtod.cc @@ -27,14 +27,14 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "bignum.h" -#include "cctest.h" -#include "diy-fp.h" -#include "double.h" -#include "strtod.h" -#include "utils/random-number-generator.h" +#include "src/base/utils/random-number-generator.h" +#include "src/bignum.h" +#include "src/diy-fp.h" +#include "src/double.h" +#include "src/strtod.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -449,7 +449,7 @@ static const int kShortStrtodRandomCount = 2; static const int kLargeStrtodRandomCount = 2; TEST(RandomStrtod) { - RandomNumberGenerator rng; + v8::base::RandomNumberGenerator rng; char buffer[kBufferSize]; for (int length = 1; length < 15; length++) { for (int i = 0; i < kShortStrtodRandomCount; ++i) { diff --git a/deps/v8/test/cctest/test-symbols.cc b/deps/v8/test/cctest/test-symbols.cc index f0d0ed1606..066c997037 100644 --- a/deps/v8/test/cctest/test-symbols.cc +++ b/deps/v8/test/cctest/test-symbols.cc @@ -5,10 +5,11 @@ // of ConsStrings. These operations may not be very fast, but they // should be possible without getting errors due to too deep recursion. -#include "v8.h" +#include "src/v8.h" -#include "cctest.h" -#include "objects.h" +#include "src/objects.h" +#include "src/ostreams.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -21,16 +22,16 @@ TEST(Create) { const int kNumSymbols = 30; Handle<Symbol> symbols[kNumSymbols]; + OFStream os(stdout); for (int i = 0; i < kNumSymbols; ++i) { symbols[i] = isolate->factory()->NewSymbol(); CHECK(symbols[i]->IsName()); CHECK(symbols[i]->IsSymbol()); CHECK(symbols[i]->HasHashCode()); CHECK_GT(symbols[i]->Hash(), 0); - symbols[i]->ShortPrint(); - PrintF("\n"); + os << Brief(*symbols[i]) << "\n"; #if OBJECT_PRINT - symbols[i]->Print(); + symbols[i]->Print(os); #endif #if VERIFY_HEAP symbols[i]->ObjectVerify(); diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc index 569ee95c64..a5ed7ab9bf 100644 --- a/deps/v8/test/cctest/test-thread-termination.cc +++ b/deps/v8/test/cctest/test-thread-termination.cc @@ -25,12 +25,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" -#include "platform.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" +#include "src/base/platform/platform.h" -v8::internal::Semaphore* semaphore = NULL; + +v8::base::Semaphore* semaphore = NULL; void Signal(const v8::FunctionCallbackInfo<v8::Value>& args) { @@ -158,11 +159,11 @@ TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) { } -class TerminatorThread : public v8::internal::Thread { +class TerminatorThread : public v8::base::Thread { public: explicit TerminatorThread(i::Isolate* isolate) - : Thread("TerminatorThread"), - isolate_(reinterpret_cast<v8::Isolate*>(isolate)) { } + : Thread(Options("TerminatorThread")), + isolate_(reinterpret_cast<v8::Isolate*>(isolate)) {} void Run() { semaphore->Wait(); CHECK(!v8::V8::IsExecutionTerminating(isolate_)); @@ -177,7 +178,7 @@ class TerminatorThread : public v8::internal::Thread { // Test that a single thread of JavaScript execution can be terminated // from the side by another thread. TEST(TerminateOnlyV8ThreadFromOtherThread) { - semaphore = new v8::internal::Semaphore(0); + semaphore = new v8::base::Semaphore(0); TerminatorThread thread(CcTest::i_isolate()); thread.Start(); @@ -358,3 +359,103 @@ TEST(TerminateCancelTerminateFromThreadItself) { // Check that execution completed with correct return value. CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed"))); } + + +void MicrotaskShouldNotRun(const v8::FunctionCallbackInfo<v8::Value>& info) { + CHECK(false); +} + + +void MicrotaskLoopForever(const v8::FunctionCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::HandleScope scope(isolate); + // Enqueue another should-not-run task to ensure we clean out the queue + // when we terminate. + isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun)); + CompileRun("terminate(); while (true) { }"); + CHECK(v8::V8::IsExecutionTerminating()); +} + + +TEST(TerminateFromOtherThreadWhileMicrotaskRunning) { + semaphore = new v8::base::Semaphore(0); + TerminatorThread thread(CcTest::i_isolate()); + thread.Start(); + + v8::Isolate* isolate = CcTest::isolate(); + isolate->SetAutorunMicrotasks(false); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global = + CreateGlobalTemplate(CcTest::isolate(), Signal, DoLoop); + v8::Handle<v8::Context> context = + v8::Context::New(CcTest::isolate(), NULL, global); + v8::Context::Scope context_scope(context); + isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskLoopForever)); + // The second task should never be run because we bail out if we're + // terminating. + isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun)); + isolate->RunMicrotasks(); + + v8::V8::CancelTerminateExecution(isolate); + isolate->RunMicrotasks(); // should not run MicrotaskShouldNotRun + + thread.Join(); + delete semaphore; + semaphore = NULL; +} + + +static int callback_counter = 0; + + +static void CounterCallback(v8::Isolate* isolate, void* data) { + callback_counter++; +} + + +TEST(PostponeTerminateException) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global = + CreateGlobalTemplate(CcTest::isolate(), TerminateCurrentThread, DoLoop); + v8::Handle<v8::Context> context = + v8::Context::New(CcTest::isolate(), NULL, global); + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch; + static const char* terminate_and_loop = + "terminate(); for (var i = 0; i < 10000; i++);"; + + { // Postpone terminate execution interrupts. + i::PostponeInterruptsScope p1(CcTest::i_isolate(), + i::StackGuard::TERMINATE_EXECUTION) ; + + // API interrupts should still be triggered. + CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL); + CHECK_EQ(0, callback_counter); + CompileRun(terminate_and_loop); + CHECK(!try_catch.HasTerminated()); + CHECK_EQ(1, callback_counter); + + { // Postpone API interrupts as well. + i::PostponeInterruptsScope p2(CcTest::i_isolate(), + i::StackGuard::API_INTERRUPT); + + // None of the two interrupts should trigger. + CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL); + CompileRun(terminate_and_loop); + CHECK(!try_catch.HasTerminated()); + CHECK_EQ(1, callback_counter); + } + + // Now the previously requested API interrupt should trigger. + CompileRun(terminate_and_loop); + CHECK(!try_catch.HasTerminated()); + CHECK_EQ(2, callback_counter); + } + + // Now the previously requested terminate execution interrupt should trigger. + CompileRun("for (var i = 0; i < 10000; i++);"); + CHECK(try_catch.HasTerminated()); + CHECK_EQ(2, callback_counter); +} diff --git a/deps/v8/test/cctest/test-threads.cc b/deps/v8/test/cctest/test-threads.cc index 24fb1d1d75..12042261f4 100644 --- a/deps/v8/test/cctest/test-threads.cc +++ b/deps/v8/test/cctest/test-threads.cc @@ -25,12 +25,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "platform.h" -#include "isolate.h" - -#include "cctest.h" +#include "src/base/platform/platform.h" +#include "src/isolate.h" enum Turn { @@ -43,9 +42,9 @@ enum Turn { static Turn turn = FILL_CACHE; -class ThreadA : public v8::internal::Thread { +class ThreadA : public v8::base::Thread { public: - ThreadA() : Thread("ThreadA") { } + ThreadA() : Thread(Options("ThreadA")) {} void Run() { v8::Isolate* isolate = CcTest::isolate(); v8::Locker locker(isolate); @@ -83,9 +82,9 @@ class ThreadA : public v8::internal::Thread { }; -class ThreadB : public v8::internal::Thread { +class ThreadB : public v8::base::Thread { public: - ThreadB() : Thread("ThreadB") { } + ThreadB() : Thread(Options("ThreadB")) {} void Run() { do { { @@ -123,16 +122,16 @@ TEST(JSFunctionResultCachesInTwoThreads) { CHECK_EQ(DONE, turn); } -class ThreadIdValidationThread : public v8::internal::Thread { +class ThreadIdValidationThread : public v8::base::Thread { public: - ThreadIdValidationThread(i::Thread* thread_to_start, - i::List<i::ThreadId>* refs, - unsigned int thread_no, - i::Semaphore* semaphore) - : Thread("ThreadRefValidationThread"), - refs_(refs), thread_no_(thread_no), thread_to_start_(thread_to_start), - semaphore_(semaphore) { - } + ThreadIdValidationThread(v8::base::Thread* thread_to_start, + i::List<i::ThreadId>* refs, unsigned int thread_no, + v8::base::Semaphore* semaphore) + : Thread(Options("ThreadRefValidationThread")), + refs_(refs), + thread_no_(thread_no), + thread_to_start_(thread_to_start), + semaphore_(semaphore) {} void Run() { i::ThreadId thread_id = i::ThreadId::Current(); @@ -150,8 +149,8 @@ class ThreadIdValidationThread : public v8::internal::Thread { private: i::List<i::ThreadId>* refs_; int thread_no_; - i::Thread* thread_to_start_; - i::Semaphore* semaphore_; + v8::base::Thread* thread_to_start_; + v8::base::Semaphore* semaphore_; }; @@ -159,7 +158,7 @@ TEST(ThreadIdValidation) { const int kNThreads = 100; i::List<ThreadIdValidationThread*> threads(kNThreads); i::List<i::ThreadId> refs(kNThreads); - i::Semaphore semaphore(0); + v8::base::Semaphore semaphore(0); ThreadIdValidationThread* prev = NULL; for (int i = kNThreads - 1; i >= 0; i--) { ThreadIdValidationThread* newThread = @@ -176,19 +175,3 @@ TEST(ThreadIdValidation) { delete threads[i]; } } - - -class ThreadC : public v8::internal::Thread { - public: - ThreadC() : Thread("ThreadC") { } - void Run() { - Join(); - } -}; - - -TEST(ThreadJoinSelf) { - ThreadC thread; - thread.Start(); - thread.Join(); -} diff --git a/deps/v8/test/cctest/test-time.cc b/deps/v8/test/cctest/test-time.cc deleted file mode 100644 index 1ef9e08f65..0000000000 --- a/deps/v8/test/cctest/test-time.cc +++ /dev/null @@ -1,197 +0,0 @@ -// 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. - -#include "v8.h" - -#if V8_OS_POSIX -#include <sys/time.h> // NOLINT -#endif - -#include "cctest.h" -#if V8_OS_WIN -#include "win32-headers.h" -#endif - -using namespace v8::internal; - - -TEST(TimeDeltaFromAndIn) { - CHECK(TimeDelta::FromDays(2) == TimeDelta::FromHours(48)); - CHECK(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180)); - CHECK(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120)); - CHECK(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000)); - CHECK(TimeDelta::FromMilliseconds(2) == TimeDelta::FromMicroseconds(2000)); - CHECK_EQ(static_cast<int>(13), TimeDelta::FromDays(13).InDays()); - CHECK_EQ(static_cast<int>(13), TimeDelta::FromHours(13).InHours()); - CHECK_EQ(static_cast<int>(13), TimeDelta::FromMinutes(13).InMinutes()); - CHECK_EQ(static_cast<int64_t>(13), TimeDelta::FromSeconds(13).InSeconds()); - CHECK_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF()); - CHECK_EQ(static_cast<int64_t>(13), - TimeDelta::FromMilliseconds(13).InMilliseconds()); - CHECK_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF()); - CHECK_EQ(static_cast<int64_t>(13), - TimeDelta::FromMicroseconds(13).InMicroseconds()); -} - - -#if V8_OS_MACOSX -TEST(TimeDeltaFromMachTimespec) { - TimeDelta null = TimeDelta(); - CHECK(null == TimeDelta::FromMachTimespec(null.ToMachTimespec())); - TimeDelta delta1 = TimeDelta::FromMilliseconds(42); - CHECK(delta1 == TimeDelta::FromMachTimespec(delta1.ToMachTimespec())); - TimeDelta delta2 = TimeDelta::FromDays(42); - CHECK(delta2 == TimeDelta::FromMachTimespec(delta2.ToMachTimespec())); -} -#endif - - -TEST(TimeJsTime) { - Time t = Time::FromJsTime(700000.3); - CHECK_EQ(700000.3, t.ToJsTime()); -} - - -#if V8_OS_POSIX -TEST(TimeFromTimespec) { - Time null; - CHECK(null.IsNull()); - CHECK(null == Time::FromTimespec(null.ToTimespec())); - Time now = Time::Now(); - CHECK(now == Time::FromTimespec(now.ToTimespec())); - Time now_sys = Time::NowFromSystemTime(); - CHECK(now_sys == Time::FromTimespec(now_sys.ToTimespec())); - Time unix_epoch = Time::UnixEpoch(); - CHECK(unix_epoch == Time::FromTimespec(unix_epoch.ToTimespec())); - Time max = Time::Max(); - CHECK(max.IsMax()); - CHECK(max == Time::FromTimespec(max.ToTimespec())); -} - - -TEST(TimeFromTimeval) { - Time null; - CHECK(null.IsNull()); - CHECK(null == Time::FromTimeval(null.ToTimeval())); - Time now = Time::Now(); - CHECK(now == Time::FromTimeval(now.ToTimeval())); - Time now_sys = Time::NowFromSystemTime(); - CHECK(now_sys == Time::FromTimeval(now_sys.ToTimeval())); - Time unix_epoch = Time::UnixEpoch(); - CHECK(unix_epoch == Time::FromTimeval(unix_epoch.ToTimeval())); - Time max = Time::Max(); - CHECK(max.IsMax()); - CHECK(max == Time::FromTimeval(max.ToTimeval())); -} -#endif - - -#if V8_OS_WIN -TEST(TimeFromFiletime) { - Time null; - CHECK(null.IsNull()); - CHECK(null == Time::FromFiletime(null.ToFiletime())); - Time now = Time::Now(); - CHECK(now == Time::FromFiletime(now.ToFiletime())); - Time now_sys = Time::NowFromSystemTime(); - CHECK(now_sys == Time::FromFiletime(now_sys.ToFiletime())); - Time unix_epoch = Time::UnixEpoch(); - CHECK(unix_epoch == Time::FromFiletime(unix_epoch.ToFiletime())); - Time max = Time::Max(); - CHECK(max.IsMax()); - CHECK(max == Time::FromFiletime(max.ToFiletime())); -} -#endif - - -TEST(TimeTicksIsMonotonic) { - TimeTicks previous_normal_ticks; - TimeTicks previous_highres_ticks; - ElapsedTimer timer; - timer.Start(); - while (!timer.HasExpired(TimeDelta::FromMilliseconds(100))) { - TimeTicks normal_ticks = TimeTicks::Now(); - TimeTicks highres_ticks = TimeTicks::HighResolutionNow(); - CHECK_GE(normal_ticks, previous_normal_ticks); - CHECK_GE((normal_ticks - previous_normal_ticks).InMicroseconds(), 0); - CHECK_GE(highres_ticks, previous_highres_ticks); - CHECK_GE((highres_ticks - previous_highres_ticks).InMicroseconds(), 0); - previous_normal_ticks = normal_ticks; - previous_highres_ticks = highres_ticks; - } -} - - -template <typename T> -static void ResolutionTest(T (*Now)(), TimeDelta target_granularity) { - // We're trying to measure that intervals increment in a VERY small amount - // of time -- according to the specified target granularity. Unfortunately, - // if we happen to have a context switch in the middle of our test, the - // context switch could easily exceed our limit. So, we iterate on this - // several times. As long as we're able to detect the fine-granularity - // timers at least once, then the test has succeeded. - static const TimeDelta kExpirationTimeout = TimeDelta::FromSeconds(1); - ElapsedTimer timer; - timer.Start(); - TimeDelta delta; - do { - T start = Now(); - T now = start; - // Loop until we can detect that the clock has changed. Non-HighRes timers - // will increment in chunks, i.e. 15ms. By spinning until we see a clock - // change, we detect the minimum time between measurements. - do { - now = Now(); - delta = now - start; - } while (now <= start); - CHECK_NE(static_cast<int64_t>(0), delta.InMicroseconds()); - } while (delta > target_granularity && !timer.HasExpired(kExpirationTimeout)); - CHECK_LE(delta, target_granularity); -} - - -TEST(TimeNowResolution) { - // We assume that Time::Now() has at least 16ms resolution. - static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(16); - ResolutionTest<Time>(&Time::Now, kTargetGranularity); -} - - -TEST(TimeTicksNowResolution) { - // We assume that TimeTicks::Now() has at least 16ms resolution. - static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(16); - ResolutionTest<TimeTicks>(&TimeTicks::Now, kTargetGranularity); -} - - -TEST(TimeTicksHighResolutionNowResolution) { - if (!TimeTicks::IsHighResolutionClockWorking()) return; - - // We assume that TimeTicks::HighResolutionNow() has sub-ms resolution. - static const TimeDelta kTargetGranularity = TimeDelta::FromMilliseconds(1); - ResolutionTest<TimeTicks>(&TimeTicks::HighResolutionNow, kTargetGranularity); -} diff --git a/deps/v8/test/cctest/test-types.cc b/deps/v8/test/cctest/test-types.cc index 47868f6484..8c5e41ca10 100644 --- a/deps/v8/test/cctest/test-types.cc +++ b/deps/v8/test/cctest/test-types.cc @@ -1,35 +1,13 @@ // 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include <vector> -#include "cctest.h" -#include "types.h" -#include "utils/random-number-generator.h" +#include "src/hydrogen-types.h" +#include "src/isolate-inl.h" +#include "src/types.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -41,11 +19,7 @@ struct ZoneRep { return !IsBitset(t) && reinterpret_cast<intptr_t>(AsStruct(t)[0]) == tag; } static bool IsBitset(Type* t) { return reinterpret_cast<intptr_t>(t) & 1; } - static bool IsClass(Type* t) { return IsStruct(t, 0); } - static bool IsConstant(Type* t) { return IsStruct(t, 1); } - static bool IsArray(Type* t) { return IsStruct(t, 2); } - static bool IsFunction(Type* t) { return IsStruct(t, 3); } - static bool IsUnion(Type* t) { return IsStruct(t, 4); } + static bool IsUnion(Type* t) { return IsStruct(t, 6); } static Struct* AsStruct(Type* t) { return reinterpret_cast<Struct*>(t); @@ -53,12 +27,6 @@ struct ZoneRep { static int AsBitset(Type* t) { return static_cast<int>(reinterpret_cast<intptr_t>(t) >> 1); } - static Map* AsClass(Type* t) { - return *static_cast<Map**>(AsStruct(t)[3]); - } - static Object* AsConstant(Type* t) { - return *static_cast<Object**>(AsStruct(t)[3]); - } static Struct* AsUnion(Type* t) { return AsStruct(t); } @@ -67,6 +35,13 @@ struct ZoneRep { } static Zone* ToRegion(Zone* zone, Isolate* isolate) { return zone; } + + struct BitsetType : Type::BitsetType { + using Type::BitsetType::New; + using Type::BitsetType::Glb; + using Type::BitsetType::Lub; + using Type::BitsetType::InherentLub; + }; }; @@ -77,29 +52,32 @@ struct HeapRep { return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag; } static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); } - static bool IsClass(Handle<HeapType> t) { return t->IsMap(); } - static bool IsConstant(Handle<HeapType> t) { return t->IsBox(); } - static bool IsArray(Handle<HeapType> t) { return IsStruct(t, 2); } - static bool IsFunction(Handle<HeapType> t) { return IsStruct(t, 3); } - static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 4); } + static bool IsUnion(Handle<HeapType> t) { return IsStruct(t, 6); } static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); } static int AsBitset(Handle<HeapType> t) { return Smi::cast(*t)->value(); } - static Map* AsClass(Handle<HeapType> t) { return Map::cast(*t); } - static Object* AsConstant(Handle<HeapType> t) { - return Box::cast(*t)->value(); - } static Struct* AsUnion(Handle<HeapType> t) { return AsStruct(t); } static int Length(Struct* structured) { return structured->length() - 1; } static Isolate* ToRegion(Zone* zone, Isolate* isolate) { return isolate; } + + struct BitsetType : HeapType::BitsetType { + using HeapType::BitsetType::New; + using HeapType::BitsetType::Glb; + using HeapType::BitsetType::Lub; + using HeapType::BitsetType::InherentLub; + static int Glb(Handle<HeapType> type) { return Glb(*type); } + static int Lub(Handle<HeapType> type) { return Lub(*type); } + static int InherentLub(Handle<HeapType> type) { return InherentLub(*type); } + }; }; template<class Type, class TypeHandle, class Region> class Types { public: - Types(Region* region, Isolate* isolate) : region_(region) { + Types(Region* region, Isolate* isolate) + : region_(region), rng_(isolate->random_number_generator()) { #define DECLARE_TYPE(name, value) \ name = Type::name(region); \ types.push_back(name); @@ -143,7 +121,16 @@ class Types { types.push_back(Type::Constant(*it, region)); } - FloatArray = Type::Array(Float, region); + doubles.push_back(-0.0); + doubles.push_back(+0.0); + doubles.push_back(-std::numeric_limits<double>::infinity()); + doubles.push_back(+std::numeric_limits<double>::infinity()); + for (int i = 0; i < 10; ++i) { + doubles.push_back(rng_->NextInt()); + doubles.push_back(rng_->NextDouble() * rng_->NextInt()); + } + + NumberArray = Type::Array(Number, region); StringArray = Type::Array(String, region); AnyArray = Type::Array(Any, region); @@ -152,7 +139,7 @@ class Types { NumberFunction2 = Type::Function(Number, Number, Number, region); MethodFunction = Type::Function(String, Object, 0, region); - for (int i = 0; i < 50; ++i) { + for (int i = 0; i < 30; ++i) { types.push_back(Fuzz()); } } @@ -183,7 +170,7 @@ class Types { TypeHandle ArrayConstant; TypeHandle UninitializedConstant; - TypeHandle FloatArray; + TypeHandle NumberArray; TypeHandle StringArray; TypeHandle AnyArray; @@ -195,9 +182,27 @@ class Types { typedef std::vector<TypeHandle> TypeVector; typedef std::vector<Handle<i::Map> > MapVector; typedef std::vector<Handle<i::Object> > ValueVector; + typedef std::vector<double> DoubleVector; + TypeVector types; MapVector maps; ValueVector values; + DoubleVector doubles; // Some floating-point values, excluding NaN. + + // Range type helper functions, partially copied from types.cc. + // Note: dle(dmin(x,y), dmax(x,y)) holds iff neither x nor y is NaN. + bool dle(double x, double y) { + return x <= y && (x != 0 || IsMinusZero(x) || !IsMinusZero(y)); + } + bool deq(double x, double y) { + return dle(x, y) && dle(y, x); + } + double dmin(double x, double y) { + return dle(x, y) ? x : y; + } + double dmax(double x, double y) { + return dle(x, y) ? y : x; + } TypeHandle Of(Handle<i::Object> value) { return Type::Of(value, region_); @@ -211,6 +216,10 @@ class Types { return Type::Constant(value, region_); } + TypeHandle Range(double min, double max) { + return Type::Range(min, max, region_); + } + TypeHandle Class(Handle<i::Map> map) { return Type::Class(map, region_); } @@ -246,18 +255,18 @@ class Types { } TypeHandle Random() { - return types[rng_.NextInt(static_cast<int>(types.size()))]; + return types[rng_->NextInt(static_cast<int>(types.size()))]; } TypeHandle Fuzz(int depth = 5) { - switch (rng_.NextInt(depth == 0 ? 3 : 20)) { + switch (rng_->NextInt(depth == 0 ? 3 : 20)) { case 0: { // bitset int n = 0 #define COUNT_BITSET_TYPES(type, value) + 1 BITSET_TYPE_LIST(COUNT_BITSET_TYPES) #undef COUNT_BITSET_TYPES ; - int i = rng_.NextInt(n); + int i = rng_->NextInt(n); #define PICK_BITSET_TYPE(type, value) \ if (i-- == 0) return Type::type(region_); BITSET_TYPE_LIST(PICK_BITSET_TYPE) @@ -265,31 +274,37 @@ class Types { UNREACHABLE(); } case 1: { // class - int i = rng_.NextInt(static_cast<int>(maps.size())); + int i = rng_->NextInt(static_cast<int>(maps.size())); return Type::Class(maps[i], region_); } case 2: { // constant - int i = rng_.NextInt(static_cast<int>(values.size())); + int i = rng_->NextInt(static_cast<int>(values.size())); return Type::Constant(values[i], region_); } - case 3: { // array + case 3: { // context + int depth = rng_->NextInt(3); + TypeHandle type = Type::Internal(region_); + for (int i = 0; i < depth; ++i) type = Type::Context(type, region_); + return type; + } + case 4: { // array TypeHandle element = Fuzz(depth / 2); return Type::Array(element, region_); } - case 4: case 5: case 6: { // function TypeHandle result = Fuzz(depth / 2); TypeHandle receiver = Fuzz(depth / 2); - int arity = rng_.NextInt(3); + int arity = rng_->NextInt(3); TypeHandle type = Type::Function(result, receiver, arity, region_); for (int i = 0; i < type->AsFunction()->Arity(); ++i) { - TypeHandle parameter = Fuzz(depth - 1); + TypeHandle parameter = Fuzz(depth / 2); type->AsFunction()->InitParameter(i, parameter); } + return type; } default: { // union - int n = rng_.NextInt(10); + int n = rng_->NextInt(10); TypeHandle type = None; for (int i = 0; i < n; ++i) { TypeHandle operand = Fuzz(depth - 1); @@ -301,9 +316,11 @@ class Types { UNREACHABLE(); } + Region* region() { return region_; } + private: Region* region_; - RandomNumberGenerator rng_; + v8::base::RandomNumberGenerator* rng_; }; @@ -313,6 +330,7 @@ struct Tests : Rep { typedef typename TypesInstance::TypeVector::iterator TypeIterator; typedef typename TypesInstance::MapVector::iterator MapIterator; typedef typename TypesInstance::ValueVector::iterator ValueIterator; + typedef typename TypesInstance::DoubleVector::iterator DoubleIterator; Isolate* isolate; HandleScope scope; @@ -328,19 +346,13 @@ struct Tests : Rep { bool Equal(TypeHandle type1, TypeHandle type2) { return - type1->Is(type2) && type2->Is(type1) && + type1->Equals(type2) && Rep::IsBitset(type1) == Rep::IsBitset(type2) && - Rep::IsClass(type1) == Rep::IsClass(type2) && - Rep::IsConstant(type1) == Rep::IsConstant(type2) && Rep::IsUnion(type1) == Rep::IsUnion(type2) && type1->NumClasses() == type2->NumClasses() && type1->NumConstants() == type2->NumConstants() && (!Rep::IsBitset(type1) || Rep::AsBitset(type1) == Rep::AsBitset(type2)) && - (!Rep::IsClass(type1) || - Rep::AsClass(type1) == Rep::AsClass(type2)) && - (!Rep::IsConstant(type1) || - Rep::AsConstant(type1) == Rep::AsConstant(type2)) && (!Rep::IsUnion(type1) || Rep::Length(Rep::AsUnion(type1)) == Rep::Length(Rep::AsUnion(type2))); } @@ -460,7 +472,7 @@ struct Tests : Rep { for (MapIterator mt = T.maps.begin(); mt != T.maps.end(); ++mt) { Handle<i::Map> map = *mt; TypeHandle type = T.Class(map); - CHECK(this->IsClass(type)); + CHECK(type->IsClass()); } // Map attribute @@ -487,7 +499,7 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; TypeHandle type = T.Constant(value); - CHECK(this->IsConstant(type)); + CHECK(type->IsConstant()); } // Value attribute @@ -507,6 +519,93 @@ struct Tests : Rep { CHECK(Equal(type1, type2) == (*value1 == *value2)); } } + + // Typing of numbers + Factory* fac = isolate->factory(); + CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall)); + CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall)); + CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall)); + CHECK(T.Constant(fac->NewNumber(-1))->Is(T.OtherSignedSmall)); + CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.OtherSignedSmall)); + CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.OtherSignedSmall)); + if (SmiValuesAre31Bits()) { + CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31)); + CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31)); + CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32)); + CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32)); + CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32)); + } else { + CHECK(SmiValuesAre32Bits()); + CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall)); + CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall)); + CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31)); + CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31)); + CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSignedSmall)); + CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSignedSmall)); + CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSignedSmall)); + CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32)); + CHECK(!T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32)); + CHECK(!T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32)); + } + CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.OtherUnsigned32)); + CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.OtherUnsigned32)); + CHECK(T.Constant(fac->NewNumber(0xffffffffu+1.0))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero)); + CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN)); + CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber)); + CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber)); + } + + void Range() { + // Constructor + for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) { + for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) { + double min = T.dmin(*i, *j); + double max = T.dmax(*i, *j); + TypeHandle type = T.Range(min, max); + CHECK(type->IsRange()); + } + } + + // Range attributes + for (DoubleIterator i = T.doubles.begin(); i != T.doubles.end(); ++i) { + for (DoubleIterator j = T.doubles.begin(); j != T.doubles.end(); ++j) { + double min = T.dmin(*i, *j); + double max = T.dmax(*i, *j); + printf("RangeType: min, max = %f, %f\n", min, max); + TypeHandle type = T.Range(min, max); + printf("RangeType: Min, Max = %f, %f\n", + type->AsRange()->Min(), type->AsRange()->Max()); + CHECK(min == type->AsRange()->Min()); + CHECK(max == type->AsRange()->Max()); + } + } + +// TODO(neis): enable once subtyping is updated. +// // Functionality & Injectivity: Range(min1, max1) = Range(min2, max2) <=> +// // min1 = min2 /\ max1 = max2 +// for (DoubleIterator i1 = T.doubles.begin(); i1 != T.doubles.end(); ++i1) { +// for (DoubleIterator j1 = T.doubles.begin(); j1 != T.doubles.end(); ++j1) { +// for (DoubleIterator i2 = T.doubles.begin(); +// i2 != T.doubles.end(); ++i2) { +// for (DoubleIterator j2 = T.doubles.begin(); +// j2 != T.doubles.end(); ++j2) { +// double min1 = T.dmin(*i1, *j1); +// double max1 = T.dmax(*i1, *j1); +// double min2 = T.dmin(*i2, *j2); +// double max2 = T.dmax(*i2, *j2); +// TypeHandle type1 = T.Range(min1, max1); +// TypeHandle type2 = T.Range(min2, max2); +// CHECK(Equal(type1, type2) == +// (T.deq(min1, min2) && T.deq(max1, max2))); +// } +// } +// } +// } } void Array() { @@ -514,7 +613,7 @@ struct Tests : Rep { for (int i = 0; i < 20; ++i) { TypeHandle type = T.Random(); TypeHandle array = T.Array1(type); - CHECK(this->IsArray(array)); + CHECK(array->IsArray()); } // Attributes @@ -669,6 +768,44 @@ struct Tests : Rep { } } + void Bounds() { + // Ordering: (T->BitsetGlb())->Is(T->BitsetLub()) + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + TypeHandle glb = + Rep::BitsetType::New(Rep::BitsetType::Glb(type), T.region()); + TypeHandle lub = + Rep::BitsetType::New(Rep::BitsetType::Lub(type), T.region()); + CHECK(glb->Is(lub)); + } + + // Lower bound: (T->BitsetGlb())->Is(T) + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + TypeHandle glb = + Rep::BitsetType::New(Rep::BitsetType::Glb(type), T.region()); + CHECK(glb->Is(type)); + } + + // Upper bound: T->Is(T->BitsetLub()) + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + TypeHandle lub = + Rep::BitsetType::New(Rep::BitsetType::Lub(type), T.region()); + CHECK(type->Is(lub)); + } + + // Inherent bound: (T->BitsetLub())->Is(T->InherentBitsetLub()) + for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { + TypeHandle type = *it; + TypeHandle lub = + Rep::BitsetType::New(Rep::BitsetType::Lub(type), T.region()); + TypeHandle inherent = + Rep::BitsetType::New(Rep::BitsetType::InherentLub(type), T.region()); + CHECK(lub->Is(inherent)); + } + } + void Is() { // Least Element (Bottom): None->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { @@ -772,10 +909,9 @@ struct Tests : Rep { CheckSub(T.SignedSmall, T.Number); CheckSub(T.Signed32, T.Number); - CheckSub(T.Float, T.Number); CheckSub(T.SignedSmall, T.Signed32); - CheckUnordered(T.SignedSmall, T.Float); - CheckUnordered(T.Signed32, T.Float); + CheckUnordered(T.SignedSmall, T.MinusZero); + CheckUnordered(T.Signed32, T.Unsigned32); CheckSub(T.UniqueName, T.Name); CheckSub(T.String, T.Name); @@ -823,8 +959,8 @@ struct Tests : Rep { CheckUnordered(T.ObjectConstant2, T.ArrayClass); CheckUnordered(T.ArrayConstant, T.ObjectClass); - CheckSub(T.FloatArray, T.Array); - CheckSub(T.FloatArray, T.Object); + CheckSub(T.NumberArray, T.Array); + CheckSub(T.NumberArray, T.Object); CheckUnordered(T.StringArray, T.AnyArray); CheckSub(T.MethodFunction, T.Function); @@ -1044,13 +1180,13 @@ struct Tests : Rep { } } - // T1->Maybe(T2) iff Intersect(T1, T2) inhabited + // T1->Maybe(T2) implies Intersect(T1, T2) inhabited for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { TypeHandle type1 = *it1; TypeHandle type2 = *it2; TypeHandle intersect12 = T.Intersect(type1, type2); - CHECK(type1->Maybe(type2) == intersect12->IsInhabited()); + CHECK(!type1->Maybe(type2) || intersect12->IsInhabited()); } } @@ -1114,8 +1250,8 @@ struct Tests : Rep { CheckDisjoint(T.Boolean, T.Undefined, T.Semantic); CheckOverlap(T.SignedSmall, T.Number, T.Semantic); - CheckOverlap(T.Float, T.Number, T.Semantic); - CheckDisjoint(T.Signed32, T.Float, T.Semantic); + CheckOverlap(T.NaN, T.Number, T.Semantic); + CheckDisjoint(T.Signed32, T.NaN, T.Semantic); CheckOverlap(T.UniqueName, T.Name, T.Semantic); CheckOverlap(T.String, T.Name, T.Semantic); @@ -1145,7 +1281,6 @@ struct Tests : Rep { CheckOverlap(T.SmiConstant, T.SignedSmall, T.Semantic); CheckOverlap(T.SmiConstant, T.Signed32, T.Semantic); CheckOverlap(T.SmiConstant, T.Number, T.Semantic); - CheckDisjoint(T.SmiConstant, T.Float, T.Semantic); CheckOverlap(T.ObjectConstant1, T.Object, T.Semantic); CheckOverlap(T.ObjectConstant2, T.Object, T.Semantic); CheckOverlap(T.ArrayConstant, T.Object, T.Semantic); @@ -1160,9 +1295,9 @@ struct Tests : Rep { CheckDisjoint(T.ObjectConstant2, T.ArrayClass, T.Semantic); CheckDisjoint(T.ArrayConstant, T.ObjectClass, T.Semantic); - CheckOverlap(T.FloatArray, T.Array, T.Semantic); - CheckDisjoint(T.FloatArray, T.AnyArray, T.Semantic); - CheckDisjoint(T.FloatArray, T.StringArray, T.Semantic); + CheckOverlap(T.NumberArray, T.Array, T.Semantic); + CheckDisjoint(T.NumberArray, T.AnyArray, T.Semantic); + CheckDisjoint(T.NumberArray, T.StringArray, T.Semantic); CheckOverlap(T.MethodFunction, T.Function, T.Semantic); CheckDisjoint(T.SignedFunction1, T.NumberFunction1, T.Semantic); @@ -1303,22 +1438,18 @@ struct Tests : Rep { // Bitset-array CHECK(this->IsBitset(T.Union(T.AnyArray, T.Array))); - CHECK(this->IsUnion(T.Union(T.FloatArray, T.Number))); + CHECK(this->IsUnion(T.Union(T.NumberArray, T.Number))); CheckEqual(T.Union(T.AnyArray, T.Array), T.Array); - CheckSub(T.None, T.Union(T.FloatArray, T.Number)); - CheckSub(T.Union(T.FloatArray, T.Number), T.Any); CheckUnordered(T.Union(T.AnyArray, T.String), T.Array); - CheckOverlap(T.Union(T.FloatArray, T.String), T.Object, T.Semantic); - CheckDisjoint(T.Union(T.FloatArray, T.String), T.Number, T.Semantic); + CheckOverlap(T.Union(T.NumberArray, T.String), T.Object, T.Semantic); + CheckDisjoint(T.Union(T.NumberArray, T.String), T.Number, T.Semantic); // Bitset-function CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Function))); CHECK(this->IsUnion(T.Union(T.NumberFunction1, T.Number))); CheckEqual(T.Union(T.MethodFunction, T.Function), T.Function); - CheckSub(T.None, T.Union(T.MethodFunction, T.Number)); - CheckSub(T.Union(T.MethodFunction, T.Number), T.Any); CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Function); CheckOverlap(T.Union(T.NumberFunction2, T.String), T.Object, T.Semantic); CheckDisjoint(T.Union(T.NumberFunction1, T.String), T.Number, T.Semantic); @@ -1353,10 +1484,10 @@ struct Tests : Rep { // Bitset-union CheckSub( - T.Float, + T.NaN, T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number)); CheckSub( - T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Float), + T.Union(T.Union(T.ArrayClass, T.ObjectConstant1), T.Signed32), T.Union(T.ObjectConstant1, T.Union(T.Number, T.ArrayClass))); // Class-union @@ -1380,9 +1511,9 @@ struct Tests : Rep { // Array-union CheckEqual( - T.Union(T.AnyArray, T.Union(T.FloatArray, T.AnyArray)), - T.Union(T.AnyArray, T.FloatArray)); - CheckSub(T.Union(T.AnyArray, T.FloatArray), T.Array); + T.Union(T.AnyArray, T.Union(T.NumberArray, T.AnyArray)), + T.Union(T.AnyArray, T.NumberArray)); + CheckSub(T.Union(T.AnyArray, T.NumberArray), T.Array); // Function-union CheckEqual( @@ -1524,7 +1655,7 @@ struct Tests : Rep { CheckSub(T.Intersect(T.ObjectClass, T.Number), T.Representation); // Bitset-array - CheckEqual(T.Intersect(T.FloatArray, T.Object), T.FloatArray); + CheckEqual(T.Intersect(T.NumberArray, T.Object), T.NumberArray); CheckSub(T.Intersect(T.AnyArray, T.Function), T.Representation); // Bitset-function @@ -1535,24 +1666,24 @@ struct Tests : Rep { CheckEqual( T.Intersect(T.Object, T.Union(T.ObjectConstant1, T.ObjectClass)), T.Union(T.ObjectConstant1, T.ObjectClass)); - CheckEqual( - T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number), - T.None); + CHECK( + !T.Intersect(T.Union(T.ArrayClass, T.ObjectConstant1), T.Number) + ->IsInhabited()); // Class-constant - CheckEqual(T.Intersect(T.ObjectConstant1, T.ObjectClass), T.None); - CheckEqual(T.Intersect(T.ArrayClass, T.ObjectConstant2), T.None); + CHECK(!T.Intersect(T.ObjectConstant1, T.ObjectClass)->IsInhabited()); + CHECK(!T.Intersect(T.ArrayClass, T.ObjectConstant2)->IsInhabited()); // Array-union CheckEqual( - T.Intersect(T.FloatArray, T.Union(T.FloatArray, T.ArrayClass)), - T.FloatArray); + T.Intersect(T.NumberArray, T.Union(T.NumberArray, T.ArrayClass)), + T.NumberArray); CheckEqual( T.Intersect(T.AnyArray, T.Union(T.Object, T.SmiConstant)), T.AnyArray); - CheckEqual( - T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.FloatArray), - T.None); + CHECK( + !T.Intersect(T.Union(T.AnyArray, T.ArrayConstant), T.NumberArray) + ->IsInhabited()); // Function-union CheckEqual( @@ -1561,9 +1692,9 @@ struct Tests : Rep { CheckEqual( T.Intersect(T.NumberFunction1, T.Union(T.Object, T.SmiConstant)), T.NumberFunction1); - CheckEqual( - T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2), - T.None); + CHECK( + !T.Intersect(T.Union(T.MethodFunction, T.Name), T.NumberFunction2) + ->IsInhabited()); // Class-union CheckEqual( @@ -1572,9 +1703,9 @@ struct Tests : Rep { CheckEqual( T.Intersect(T.ArrayClass, T.Union(T.Object, T.SmiConstant)), T.ArrayClass); - CheckEqual( - T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass), - T.None); + CHECK( + !T.Intersect(T.Union(T.ObjectClass, T.ArrayConstant), T.ArrayClass) + ->IsInhabited()); // Constant-union CheckEqual( @@ -1584,10 +1715,10 @@ struct Tests : Rep { CheckEqual( T.Intersect(T.SmiConstant, T.Union(T.Number, T.ObjectConstant2)), T.SmiConstant); - CheckEqual( - T.Intersect( - T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1), - T.None); + CHECK( + !T.Intersect( + T.Union(T.ArrayConstant, T.ObjectClass), T.ObjectConstant1) + ->IsInhabited()); // Union-union CheckEqual( @@ -1615,6 +1746,46 @@ struct Tests : Rep { T.Union(T.ObjectConstant2, T.ObjectConstant1)); } + void Distributivity1() { + // Distributivity: + // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3)) + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + 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; + TypeHandle type2 = *it2; + TypeHandle type3 = *it3; + TypeHandle union12 = T.Union(type1, type2); + TypeHandle union13 = T.Union(type1, type3); + TypeHandle intersect23 = T.Intersect(type2, type3); + TypeHandle union1_23 = T.Union(type1, intersect23); + TypeHandle intersect12_13 = T.Intersect(union12, union13); + CHECK(Equal(union1_23, intersect12_13)); + } + } + } + } + + void Distributivity2() { + // Distributivity: + // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3)) + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + 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; + TypeHandle type2 = *it2; + TypeHandle type3 = *it3; + TypeHandle intersect12 = T.Intersect(type1, type2); + TypeHandle intersect13 = T.Intersect(type1, type3); + TypeHandle union23 = T.Union(type2, type3); + TypeHandle intersect1_23 = T.Intersect(type1, union23); + TypeHandle union12_13 = T.Union(intersect12, intersect13); + CHECK(Equal(intersect1_23, union12_13)); + } + } + } + } + template<class Type2, class TypeHandle2, class Region2, class Rep2> void Convert() { Types<Type2, TypeHandle2, Region2> T2( @@ -1626,6 +1797,18 @@ struct Tests : Rep { CheckEqual(type1, type3); } } + + void HTypeFromType() { + for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { + for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { + TypeHandle type1 = *it1; + TypeHandle type2 = *it2; + HType htype1 = HType::FromType<Type>(type1); + HType htype2 = HType::FromType<Type>(type2); + CHECK(!type1->Is(type2) || htype1.IsSubtypeOf(htype2)); + } + } + } }; typedef Tests<Type, Type*, Zone, ZoneRep> ZoneTests; @@ -1653,6 +1836,13 @@ TEST(ConstantType) { } +TEST(RangeType) { + CcTest::InitializeVM(); + ZoneTests().Range(); + HeapTests().Range(); +} + + TEST(ArrayType) { CcTest::InitializeVM(); ZoneTests().Array(); @@ -1681,6 +1871,13 @@ TEST(NowOf) { } +TEST(Bounds) { + CcTest::InitializeVM(); + ZoneTests().Bounds(); + HeapTests().Bounds(); +} + + TEST(Is) { CcTest::InitializeVM(); ZoneTests().Is(); @@ -1744,8 +1941,29 @@ TEST(Intersect2) { } +TEST(Distributivity1) { + CcTest::InitializeVM(); + ZoneTests().Distributivity1(); + HeapTests().Distributivity1(); +} + + +TEST(Distributivity2) { + CcTest::InitializeVM(); + ZoneTests().Distributivity2(); + HeapTests().Distributivity2(); +} + + TEST(Convert) { CcTest::InitializeVM(); ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>(); HeapTests().Convert<Type, Type*, Zone, ZoneRep>(); } + + +TEST(HTypeFromType) { + CcTest::InitializeVM(); + ZoneTests().HTypeFromType(); + HeapTests().HTypeFromType(); +} diff --git a/deps/v8/test/cctest/test-unbound-queue.cc b/deps/v8/test/cctest/test-unbound-queue.cc index dd9b9c142b..6da91e6943 100644 --- a/deps/v8/test/cctest/test-unbound-queue.cc +++ b/deps/v8/test/cctest/test-unbound-queue.cc @@ -27,9 +27,10 @@ // // Tests of the unbound queue. -#include "v8.h" -#include "unbound-queue-inl.h" -#include "cctest.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/unbound-queue-inl.h" using i::UnboundQueue; diff --git a/deps/v8/test/cctest/test-unique.cc b/deps/v8/test/cctest/test-unique.cc index ad14ff1334..302539a96d 100644 --- a/deps/v8/test/cctest/test-unique.cc +++ b/deps/v8/test/cctest/test-unique.cc @@ -27,12 +27,12 @@ #include <stdlib.h> -#include "v8.h" +#include "src/v8.h" -#include "factory.h" -#include "global-handles.h" -#include "unique.h" -#include "cctest.h" +#include "src/factory.h" +#include "src/global-handles.h" +#include "src/unique.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-unscopables-hidden-prototype.cc b/deps/v8/test/cctest/test-unscopables-hidden-prototype.cc new file mode 100644 index 0000000000..aef2ccf288 --- /dev/null +++ b/deps/v8/test/cctest/test-unscopables-hidden-prototype.cc @@ -0,0 +1,103 @@ +// 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 <stdlib.h> + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +namespace { + + +static void Cleanup() { + CompileRun( + "delete object.x;" + "delete hidden_prototype.x;" + "delete object[Symbol.unscopables];" + "delete hidden_prototype[Symbol.unscopables];"); +} + + +TEST(Unscopables) { + LocalContext context; + v8::Isolate* isolate = context->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); + v8::Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); + + t1->SetHiddenPrototype(true); + + v8::Local<v8::Object> object = t0->GetFunction()->NewInstance(); + v8::Local<v8::Object> hidden_prototype = t1->GetFunction()->NewInstance(); + + object->SetPrototype(hidden_prototype); + + context->Global()->Set(v8_str("object"), object); + context->Global()->Set(v8_str("hidden_prototype"), hidden_prototype); + + CHECK_EQ(1, CompileRun( + "var result;" + "var x = 0;" + "object.x = 1;" + "with (object) {" + " result = x;" + "}" + "result")->Int32Value()); + + Cleanup(); + CHECK_EQ(2, CompileRun( + "var result;" + "var x = 0;" + "hidden_prototype.x = 2;" + "with (object) {" + " result = x;" + "}" + "result")->Int32Value()); + + Cleanup(); + CHECK_EQ(0, CompileRun( + "var result;" + "var x = 0;" + "object.x = 3;" + "object[Symbol.unscopables] = {x: true};" + "with (object) {" + " result = x;" + "}" + "result")->Int32Value()); + + Cleanup(); + CHECK_EQ(0, CompileRun( + "var result;" + "var x = 0;" + "hidden_prototype.x = 4;" + "hidden_prototype[Symbol.unscopables] = {x: true};" + "with (object) {" + " result = x;" + "}" + "result")->Int32Value()); + + Cleanup(); + CHECK_EQ(0, CompileRun( + "var result;" + "var x = 0;" + "object.x = 5;" + "hidden_prototype[Symbol.unscopables] = {x: true};" + "with (object) {" + " result = x;" + "}" + "result;")->Int32Value()); + + Cleanup(); + CHECK_EQ(0, CompileRun( + "var result;" + "var x = 0;" + "hidden_prototype.x = 6;" + "object[Symbol.unscopables] = {x: true};" + "with (object) {" + " result = x;" + "}" + "result")->Int32Value()); +} +} diff --git a/deps/v8/test/cctest/test-utils-arm64.cc b/deps/v8/test/cctest/test-utils-arm64.cc index 9eb32b002e..b0b77bc97d 100644 --- a/deps/v8/test/cctest/test-utils-arm64.cc +++ b/deps/v8/test/cctest/test-utils-arm64.cc @@ -25,12 +25,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "macro-assembler.h" -#include "arm64/utils-arm64.h" -#include "cctest.h" -#include "test-utils-arm64.h" +#include "src/arm64/utils-arm64.h" +#include "src/macro-assembler.h" +#include "test/cctest/cctest.h" +#include "test/cctest/test-utils-arm64.h" using namespace v8::internal; @@ -95,7 +95,7 @@ bool EqualFP64(double expected, const RegisterDump*, double result) { bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) { - ASSERT(reg.Is32Bits()); + DCHECK(reg.Is32Bits()); // Retrieve the corresponding X register so we can check that the upper part // was properly cleared. int64_t result_x = core->xreg(reg.code()); @@ -112,7 +112,7 @@ bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) { bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg) { - ASSERT(reg.Is64Bits()); + DCHECK(reg.Is64Bits()); uint64_t result = core->xreg(reg.code()); return Equal64(expected, core, result); } @@ -121,7 +121,7 @@ bool Equal64(uint64_t expected, bool EqualFP32(float expected, const RegisterDump* core, const FPRegister& fpreg) { - ASSERT(fpreg.Is32Bits()); + DCHECK(fpreg.Is32Bits()); // Retrieve the corresponding D register so we can check that the upper part // was properly cleared. uint64_t result_64 = core->dreg_bits(fpreg.code()); @@ -138,7 +138,7 @@ bool EqualFP32(float expected, bool EqualFP64(double expected, const RegisterDump* core, const FPRegister& fpreg) { - ASSERT(fpreg.Is64Bits()); + DCHECK(fpreg.Is64Bits()); return EqualFP64(expected, core, core->dreg(fpreg.code())); } @@ -146,7 +146,7 @@ bool EqualFP64(double expected, bool Equal64(const Register& reg0, const RegisterDump* core, const Register& reg1) { - ASSERT(reg0.Is64Bits() && reg1.Is64Bits()); + DCHECK(reg0.Is64Bits() && reg1.Is64Bits()); int64_t expected = core->xreg(reg0.code()); int64_t result = core->xreg(reg1.code()); return Equal64(expected, core, result); @@ -174,8 +174,8 @@ static char FlagV(uint32_t flags) { bool EqualNzcv(uint32_t expected, uint32_t result) { - ASSERT((expected & ~NZCVFlag) == 0); - ASSERT((result & ~NZCVFlag) == 0); + DCHECK((expected & ~NZCVFlag) == 0); + DCHECK((result & ~NZCVFlag) == 0); if (result != expected) { printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n", FlagN(expected), FlagZ(expected), FlagC(expected), FlagV(expected), @@ -231,7 +231,7 @@ RegList PopulateRegisterArray(Register* w, Register* x, Register* r, } } // Check that we got enough registers. - ASSERT(CountSetBits(list, kNumberOfRegisters) == reg_count); + DCHECK(CountSetBits(list, kNumberOfRegisters) == reg_count); return list; } @@ -258,7 +258,7 @@ RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v, } } // Check that we got enough registers. - ASSERT(CountSetBits(list, kNumberOfFPRegisters) == reg_count); + DCHECK(CountSetBits(list, kNumberOfFPRegisters) == reg_count); return list; } @@ -270,7 +270,7 @@ void Clobber(MacroAssembler* masm, RegList reg_list, uint64_t const value) { if (reg_list & (1UL << i)) { Register xn = Register::Create(i, kXRegSizeInBits); // We should never write into csp here. - ASSERT(!xn.Is(csp)); + DCHECK(!xn.Is(csp)); if (!xn.IsZero()) { if (!first.IsValid()) { // This is the first register we've hit, so construct the literal. @@ -320,7 +320,7 @@ void Clobber(MacroAssembler* masm, CPURegList reg_list) { void RegisterDump::Dump(MacroAssembler* masm) { - ASSERT(__ StackPointer().Is(csp)); + DCHECK(__ StackPointer().Is(csp)); // Ensure that we don't unintentionally clobber any registers. RegList old_tmp_list = masm->TmpList()->list(); @@ -396,7 +396,7 @@ void RegisterDump::Dump(MacroAssembler* masm) { // easily restore them. Register dump2_base = x10; Register dump2 = x11; - ASSERT(!AreAliased(dump_base, dump, tmp, dump2_base, dump2)); + DCHECK(!AreAliased(dump_base, dump, tmp, dump2_base, dump2)); // Don't lose the dump_ address. __ Mov(dump2_base, dump_base); diff --git a/deps/v8/test/cctest/test-utils-arm64.h b/deps/v8/test/cctest/test-utils-arm64.h index 2ff26e49cc..d00ad5e78c 100644 --- a/deps/v8/test/cctest/test-utils-arm64.h +++ b/deps/v8/test/cctest/test-utils-arm64.h @@ -28,12 +28,12 @@ #ifndef V8_ARM64_TEST_UTILS_ARM64_H_ #define V8_ARM64_TEST_UTILS_ARM64_H_ -#include "v8.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "macro-assembler.h" -#include "arm64/macro-assembler-arm64.h" -#include "arm64/utils-arm64.h" -#include "cctest.h" +#include "src/arm64/macro-assembler-arm64.h" +#include "src/arm64/utils-arm64.h" +#include "src/macro-assembler.h" using namespace v8::internal; @@ -59,7 +59,7 @@ class RegisterDump { if (code == kSPRegInternalCode) { return wspreg(); } - ASSERT(RegAliasesMatch(code)); + DCHECK(RegAliasesMatch(code)); return dump_.w_[code]; } @@ -67,13 +67,13 @@ class RegisterDump { if (code == kSPRegInternalCode) { return spreg(); } - ASSERT(RegAliasesMatch(code)); + DCHECK(RegAliasesMatch(code)); return dump_.x_[code]; } // FPRegister accessors. inline uint32_t sreg_bits(unsigned code) const { - ASSERT(FPRegAliasesMatch(code)); + DCHECK(FPRegAliasesMatch(code)); return dump_.s_[code]; } @@ -82,7 +82,7 @@ class RegisterDump { } inline uint64_t dreg_bits(unsigned code) const { - ASSERT(FPRegAliasesMatch(code)); + DCHECK(FPRegAliasesMatch(code)); return dump_.d_[code]; } @@ -92,19 +92,19 @@ class RegisterDump { // Stack pointer accessors. inline int64_t spreg() const { - ASSERT(SPRegAliasesMatch()); + DCHECK(SPRegAliasesMatch()); return dump_.sp_; } inline int64_t wspreg() const { - ASSERT(SPRegAliasesMatch()); + DCHECK(SPRegAliasesMatch()); return dump_.wsp_; } // Flags accessors. inline uint64_t flags_nzcv() const { - ASSERT(IsComplete()); - ASSERT((dump_.flags_ & ~Flags_mask) == 0); + DCHECK(IsComplete()); + DCHECK((dump_.flags_ & ~Flags_mask) == 0); return dump_.flags_ & Flags_mask; } @@ -120,21 +120,21 @@ class RegisterDump { // w<code>. A failure of this test most likely represents a failure in the // ::Dump method, or a failure in the simulator. bool RegAliasesMatch(unsigned code) const { - ASSERT(IsComplete()); - ASSERT(code < kNumberOfRegisters); + DCHECK(IsComplete()); + DCHECK(code < kNumberOfRegisters); return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]); } // As RegAliasesMatch, but for the stack pointer. bool SPRegAliasesMatch() const { - ASSERT(IsComplete()); + DCHECK(IsComplete()); return ((dump_.sp_ & kWRegMask) == dump_.wsp_); } // As RegAliasesMatch, but for floating-point registers. bool FPRegAliasesMatch(unsigned code) const { - ASSERT(IsComplete()); - ASSERT(code < kNumberOfFPRegisters); + DCHECK(IsComplete()); + DCHECK(code < kNumberOfFPRegisters); return (dump_.d_[code] & kSRegMask) == dump_.s_[code]; } diff --git a/deps/v8/test/cctest/test-utils.cc b/deps/v8/test/cctest/test-utils.cc index 86d52fa82b..cf539305b3 100644 --- a/deps/v8/test/cctest/test-utils.cc +++ b/deps/v8/test/cctest/test-utils.cc @@ -27,11 +27,13 @@ #include <stdlib.h> -#include "v8.h" +#include <vector> -#include "cctest.h" -#include "platform.h" -#include "utils-inl.h" +#include "src/v8.h" + +#include "src/base/platform/platform.h" +#include "src/utils-inl.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -70,7 +72,7 @@ TEST(Utils1) { CHECK_EQ(INT_MAX, FastD2IChecked(1.0e100)); CHECK_EQ(INT_MIN, FastD2IChecked(-1.0e100)); - CHECK_EQ(INT_MIN, FastD2IChecked(OS::nan_value())); + CHECK_EQ(INT_MIN, FastD2IChecked(v8::base::OS::nan_value())); } @@ -83,7 +85,7 @@ TEST(SNPrintF) { static const char kMarker = static_cast<char>(42); Vector<char> buffer = Vector<char>::New(i + 1); buffer[i] = kMarker; - int n = OS::SNPrintF(Vector<char>(buffer.start(), i), "%s", s); + int n = SNPrintF(Vector<char>(buffer.start(), i), "%s", s); CHECK(n <= i); CHECK(n == length || n == -1); CHECK_EQ(0, strncmp(buffer.start(), s, i - 1)); @@ -110,15 +112,15 @@ void TestMemMove(byte* area1, area1[i] = i & 0xFF; area2[i] = i & 0xFF; } - OS::MemMove(area1 + dest_offset, area1 + src_offset, length); + MemMove(area1 + dest_offset, area1 + src_offset, length); memmove(area2 + dest_offset, area2 + src_offset, length); if (memcmp(area1, area2, kAreaSize) != 0) { - printf("OS::MemMove(): src_offset: %d, dest_offset: %d, length: %d\n", + printf("MemMove(): src_offset: %d, dest_offset: %d, length: %d\n", src_offset, dest_offset, length); for (int i = 0; i < kAreaSize; i++) { if (area1[i] == area2[i]) continue; - printf("diff at offset %d (%p): is %d, should be %d\n", - i, reinterpret_cast<void*>(area1 + i), area1[i], area2[i]); + printf("diff at offset %d (%p): is %d, should be %d\n", i, + reinterpret_cast<void*>(area1 + i), area1[i], area2[i]); } CHECK(false); } @@ -218,3 +220,40 @@ TEST(SequenceCollectorRegression) { CHECK_EQ(0, strncmp("0123456789012345678901234567890123", seq.start(), seq.length())); } + + +// TODO(svenpanne) Unconditionally test this when our infrastructure is fixed. +#if !V8_CC_MSVC && !V8_OS_NACL +TEST(CPlusPlus11Features) { + struct S { + bool x; + struct T { + double y; + int z[3]; + } t; + }; + S s{true, {3.1415, {1, 2, 3}}}; + CHECK_EQ(2, s.t.z[1]); + +// TODO(svenpanne) Remove the old-skool code when we ship the new C++ headers. +#if 0 + std::vector<int> vec{11, 22, 33, 44}; +#else + std::vector<int> vec; + vec.push_back(11); + vec.push_back(22); + vec.push_back(33); + vec.push_back(44); +#endif + vec.push_back(55); + vec.push_back(66); + for (auto& i : vec) { + ++i; + } + int j = 12; + for (auto i : vec) { + CHECK_EQ(j, i); + j += 11; + } +} +#endif diff --git a/deps/v8/test/cctest/test-version.cc b/deps/v8/test/cctest/test-version.cc index 6bec4b75ee..231451d11a 100644 --- a/deps/v8/test/cctest/test-version.cc +++ b/deps/v8/test/cctest/test-version.cc @@ -25,10 +25,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" +#include "src/v8.h" -#include "version.h" -#include "cctest.h" +#include "src/version.h" +#include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 14a5e020a1..bb412a82aa 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -27,11 +27,11 @@ #include <utility> -#include "v8.h" +#include "src/v8.h" -#include "global-handles.h" -#include "snapshot.h" -#include "cctest.h" +#include "src/global-handles.h" +#include "src/snapshot.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -46,10 +46,12 @@ static Handle<JSWeakMap> AllocateJSWeakMap(Isolate* isolate) { Handle<Map> map = factory->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); Handle<JSObject> weakmap_obj = factory->NewJSObjectFromMap(map); Handle<JSWeakMap> weakmap(JSWeakMap::cast(*weakmap_obj)); - // Do not use handles for the hash table, it would make entries strong. - Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 1); - weakmap->set_table(*table); - weakmap->set_next(Smi::FromInt(0)); + // Do not leak handles for the hash table, it would make entries strong. + { + HandleScope scope(isolate); + Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 1); + weakmap->set_table(*table); + } return weakmap; } @@ -69,7 +71,7 @@ static void WeakPointerCallback( std::pair<v8::Persistent<v8::Value>*, int>* p = reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>( data.GetParameter()); - ASSERT_EQ(1234, p->second); + DCHECK_EQ(1234, p->second); NumberOfWeakCalls++; p->first->Reset(); } @@ -185,8 +187,8 @@ TEST(Regress2060a) { Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); HandleScope scope(isolate); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - factory->function_string(), factory->null_value()); + Handle<JSFunction> function = factory->NewFunction( + factory->function_string()); Handle<JSObject> key = factory->NewJSObject(function); Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate); @@ -225,8 +227,8 @@ TEST(Regress2060b) { Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); HandleScope scope(isolate); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - factory->function_string(), factory->null_value()); + Handle<JSFunction> function = factory->NewFunction( + factory->function_string()); // Start second old-space page so that keys land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); @@ -253,3 +255,20 @@ TEST(Regress2060b) { heap->CollectAllGarbage(Heap::kNoGCFlags); heap->CollectAllGarbage(Heap::kNoGCFlags); } + + +TEST(Regress399527) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + { + HandleScope scope(isolate); + AllocateJSWeakMap(isolate); + SimulateIncrementalMarking(heap); + } + // The weak map is marked black here but leaving the handle scope will make + // the object unreachable. Aborting incremental marking will clear all the + // marking bits which makes the weak map garbage. + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); +} diff --git a/deps/v8/test/cctest/test-weaksets.cc b/deps/v8/test/cctest/test-weaksets.cc index a3a9478973..299cc92e9b 100644 --- a/deps/v8/test/cctest/test-weaksets.cc +++ b/deps/v8/test/cctest/test-weaksets.cc @@ -27,11 +27,11 @@ #include <utility> -#include "v8.h" +#include "src/v8.h" -#include "global-handles.h" -#include "snapshot.h" -#include "cctest.h" +#include "src/global-handles.h" +#include "src/snapshot.h" +#include "test/cctest/cctest.h" using namespace v8::internal; @@ -46,10 +46,12 @@ static Handle<JSWeakSet> AllocateJSWeakSet(Isolate* isolate) { Handle<Map> map = factory->NewMap(JS_WEAK_SET_TYPE, JSWeakSet::kSize); Handle<JSObject> weakset_obj = factory->NewJSObjectFromMap(map); Handle<JSWeakSet> weakset(JSWeakSet::cast(*weakset_obj)); - // Do not use handles for the hash table, it would make entries strong. - Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 1); - weakset->set_table(*table); - weakset->set_next(Smi::FromInt(0)); + // Do not leak handles for the hash table, it would make entries strong. + { + HandleScope scope(isolate); + Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 1); + weakset->set_table(*table); + } return weakset; } @@ -69,7 +71,7 @@ static void WeakPointerCallback( std::pair<v8::Persistent<v8::Value>*, int>* p = reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>( data.GetParameter()); - ASSERT_EQ(1234, p->second); + DCHECK_EQ(1234, p->second); NumberOfWeakCalls++; p->first->Reset(); } @@ -185,8 +187,8 @@ TEST(WeakSet_Regress2060a) { Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); HandleScope scope(isolate); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - factory->function_string(), factory->null_value()); + Handle<JSFunction> function = factory->NewFunction( + factory->function_string()); Handle<JSObject> key = factory->NewJSObject(function); Handle<JSWeakSet> weakset = AllocateJSWeakSet(isolate); @@ -225,8 +227,8 @@ TEST(WeakSet_Regress2060b) { Factory* factory = isolate->factory(); Heap* heap = isolate->heap(); HandleScope scope(isolate); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - factory->function_string(), factory->null_value()); + Handle<JSFunction> function = factory->NewFunction( + factory->function_string()); // Start second old-space page so that keys land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); diff --git a/deps/v8/test/cctest/test-weaktypedarrays.cc b/deps/v8/test/cctest/test-weaktypedarrays.cc index daf07eed02..d40b7e95a9 100644 --- a/deps/v8/test/cctest/test-weaktypedarrays.cc +++ b/deps/v8/test/cctest/test-weaktypedarrays.cc @@ -27,12 +27,12 @@ #include <stdlib.h> -#include "v8.h" -#include "api.h" -#include "heap.h" -#include "objects.h" +#include "src/v8.h" +#include "test/cctest/cctest.h" -#include "cctest.h" +#include "src/api.h" +#include "src/heap/heap.h" +#include "src/objects.h" using namespace v8::internal; @@ -155,7 +155,7 @@ TEST(WeakArrayBuffersFromScript) { } i::ScopedVector<char> source(1024); - i::OS::SNPrintF(source, "ab%d = null;", i); + i::SNPrintF(source, "ab%d = null;", i); CompileRun(source.start()); isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); @@ -165,7 +165,7 @@ TEST(WeakArrayBuffersFromScript) { v8::HandleScope s2(context->GetIsolate()); for (int j = 1; j <= 3; j++) { if (j == i) continue; - i::OS::SNPrintF(source, "ab%d", j); + i::SNPrintF(source, "ab%d", j); v8::Handle<v8::ArrayBuffer> ab = v8::Handle<v8::ArrayBuffer>::Cast(CompileRun(source.start())); CHECK(HasArrayBufferInWeakList(isolate->heap(), @@ -282,11 +282,11 @@ static void TestTypedArrayFromScript(const char* constructor) { { v8::HandleScope s1(context->GetIsolate()); - i::OS::SNPrintF(source, - "var ta1 = new %s(ab);" - "var ta2 = new %s(ab);" - "var ta3 = new %s(ab)", - constructor, constructor, constructor); + i::SNPrintF(source, + "var ta1 = new %s(ab);" + "var ta2 = new %s(ab);" + "var ta3 = new %s(ab)", + constructor, constructor, constructor); CompileRun(source.start()); v8::Handle<v8::ArrayBuffer> ab = @@ -305,7 +305,7 @@ static void TestTypedArrayFromScript(const char* constructor) { CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta3))); } - i::OS::SNPrintF(source, "ta%d = null;", i); + i::SNPrintF(source, "ta%d = null;", i); CompileRun(source.start()); isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); @@ -319,7 +319,7 @@ static void TestTypedArrayFromScript(const char* constructor) { CHECK_EQ(2, CountViews(*iab)); for (int j = 1; j <= 3; j++) { if (j == i) continue; - i::OS::SNPrintF(source, "ta%d", j); + i::SNPrintF(source, "ta%d", j); v8::Handle<TypedArray> ta = v8::Handle<TypedArray>::Cast(CompileRun(source.start())); CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta))); diff --git a/deps/v8/test/cctest/trace-extension.cc b/deps/v8/test/cctest/trace-extension.cc index 2da6813166..8f390e4bc5 100644 --- a/deps/v8/test/cctest/trace-extension.cc +++ b/deps/v8/test/cctest/trace-extension.cc @@ -25,10 +25,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "trace-extension.h" +#include "test/cctest/trace-extension.h" -#include "cctest.h" -#include "sampler.h" +#include "src/sampler.h" +#include "test/cctest/cctest.h" namespace v8 { namespace internal { diff --git a/deps/v8/test/cctest/trace-extension.h b/deps/v8/test/cctest/trace-extension.h index b80b3d45dc..919eda5bb5 100644 --- a/deps/v8/test/cctest/trace-extension.h +++ b/deps/v8/test/cctest/trace-extension.h @@ -28,7 +28,7 @@ #ifndef V8_TEST_CCTEST_TRACE_EXTENSION_H_ #define V8_TEST_CCTEST_TRACE_EXTENSION_H_ -#include "v8.h" +#include "src/v8.h" namespace v8 { namespace internal { |