diff options
Diffstat (limited to 'deps/v8/test')
31 files changed, 3076 insertions, 230 deletions
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 91034034a1..f041041c11 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -67,7 +67,9 @@ SOURCES = { 'test-disasm-ia32.cc', 'test-log-stack-tracer.cc' ], - 'arch:x64': ['test-assembler-x64.cc', 'test-log-stack-tracer.cc'], + 'arch:x64': ['test-assembler-x64.cc', + 'test-macro-assembler-x64.cc', + 'test-log-stack-tracer.cc'], 'os:linux': ['test-platform-linux.cc'], 'os:macos': ['test-platform-macos.cc'], 'os:nullos': ['test-platform-nullos.cc'], diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 2282c2d9b9..c63ba31652 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -25,8 +25,6 @@ // (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 "v8.h" #include "api.h" @@ -574,6 +572,44 @@ THREADED_TEST(UsingExternalAsciiString) { } +THREADED_TEST(StringConcat) { + { + v8::HandleScope scope; + LocalContext env; + const char* one_byte_string_1 = "function a_times_t"; + const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; + const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; + const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; + const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; + const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; + const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; + Local<String> left = v8_str(one_byte_string_1); + Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1)); + Local<String> source = String::Concat(left, right); + right = String::NewExternal( + new TestAsciiResource(i::StrDup(one_byte_extern_1))); + source = String::Concat(source, right); + right = String::NewExternal( + new TestResource(AsciiToTwoByteString(two_byte_extern_1))); + source = String::Concat(source, right); + right = v8_str(one_byte_string_2); + source = String::Concat(source, right); + right = String::New(AsciiToTwoByteString(two_byte_string_2)); + source = String::Concat(source, right); + right = String::NewExternal( + new TestResource(AsciiToTwoByteString(two_byte_extern_2))); + source = String::Concat(source, right); + Local<Script> script = Script::Compile(source); + Local<Value> value = script->Run(); + CHECK(value->IsNumber()); + CHECK_EQ(68, value->Int32Value()); + } + v8::internal::CompilationCache::Clear(); + i::Heap::CollectAllGarbage(false); + i::Heap::CollectAllGarbage(false); +} + + THREADED_TEST(GlobalProperties) { v8::HandleScope scope; LocalContext env; @@ -702,6 +738,88 @@ THREADED_TEST(PropertyHandler) { } +THREADED_TEST(TinyInteger) { + v8::HandleScope scope; + LocalContext env; + int32_t value = 239; + Local<v8::Integer> value_obj = v8::Integer::New(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); +} + + +THREADED_TEST(BigSmiInteger) { + v8::HandleScope scope; + LocalContext env; + int32_t value = i::Smi::kMaxValue; + // We cannot add one to a Smi::kMaxValue without wrapping. + if (i::kSmiValueSize < 32) { + CHECK(i::Smi::IsValid(value)); + CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::New(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + } +} + + +THREADED_TEST(BigInteger) { + v8::HandleScope scope; + LocalContext env; + // We cannot add one to a Smi::kMaxValue without wrapping. + if (i::kSmiValueSize < 32) { + // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. + // The code will not be run in that case, due to the "if" guard. + int32_t value = + static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); + CHECK(value > i::Smi::kMaxValue); + CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::New(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); + } +} + + +THREADED_TEST(TinyUnsignedInteger) { + v8::HandleScope scope; + LocalContext env; + uint32_t value = 239; + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); +} + + +THREADED_TEST(BigUnsignedSmiInteger) { + v8::HandleScope scope; + LocalContext env; + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); + CHECK(i::Smi::IsValid(value)); + CHECK(!i::Smi::IsValid(value + 1)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); +} + + +THREADED_TEST(BigUnsignedInteger) { + v8::HandleScope scope; + LocalContext env; + uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; + CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); + CHECK(!i::Smi::IsValid(value)); + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); +} + + +THREADED_TEST(OutOfSignedRangeUnsignedInteger) { + v8::HandleScope scope; + LocalContext env; + uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; + uint32_t value = INT32_MAX_AS_UINT + 1; + CHECK(value > INT32_MAX_AS_UINT); // No overflow. + Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); + CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); +} + + THREADED_TEST(Number) { v8::HandleScope scope; LocalContext env; @@ -1346,6 +1464,44 @@ THREADED_TEST(InternalFieldsNativePointers) { } +THREADED_TEST(InternalFieldsNativePointersAndExternal) { + v8::HandleScope scope; + LocalContext env; + + Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); + Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); + instance_templ->SetInternalFieldCount(1); + Local<v8::Object> obj = templ->GetFunction()->NewInstance(); + CHECK_EQ(1, obj->InternalFieldCount()); + CHECK(obj->GetPointerFromInternalField(0) == NULL); + + char* data = new char[100]; + + void* aligned = data; + CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1); + void* unaligned = data + 1; + CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1); + + obj->SetPointerInInternalField(0, aligned); + i::Heap::CollectAllGarbage(false); + CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0))); + + obj->SetPointerInInternalField(0, unaligned); + i::Heap::CollectAllGarbage(false); + CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0))); + + obj->SetInternalField(0, v8::External::Wrap(aligned)); + i::Heap::CollectAllGarbage(false); + CHECK_EQ(aligned, obj->GetPointerFromInternalField(0)); + + obj->SetInternalField(0, v8::External::Wrap(unaligned)); + i::Heap::CollectAllGarbage(false); + CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0)); + + delete[] data; +} + + THREADED_TEST(IdentityHash) { v8::HandleScope scope; LocalContext env; @@ -1810,7 +1966,7 @@ TEST(HugeConsStringOutOfMemory) { // Build huge string. This should fail with out of memory exception. Local<Value> result = CompileRun( "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();" - "for (var i = 0; i < 21; i++) { str = str + str; }"); + "for (var i = 0; i < 22; i++) { str = str + str; }"); // Check for out of memory state. CHECK(result.IsEmpty()); diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc index cd750c5dfa..81aa973db4 100644 --- a/deps/v8/test/cctest/test-assembler-x64.cc +++ b/deps/v8/test/cctest/test-assembler-x64.cc @@ -44,6 +44,7 @@ using v8::internal::Label; using v8::internal::rax; using v8::internal::rsi; using v8::internal::rdi; +using v8::internal::rcx; using v8::internal::rdx; using v8::internal::rbp; using v8::internal::rsp; @@ -53,20 +54,28 @@ using v8::internal::less_equal; using v8::internal::not_equal; using v8::internal::greater; - // Test the x64 assembler by compiling some simple functions into // a buffer and executing them. These tests do not initialize the // V8 library, create a context, or use any V8 objects. -// The AMD64 calling convention is used, with the first five arguments -// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in +// The AMD64 calling convention is used, with the first six arguments +// in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in // the XMM registers. The return value is in RAX. // This calling convention is used on Linux, with GCC, and on Mac OS, -// with GCC. A different convention is used on 64-bit windows. +// with GCC. A different convention is used on 64-bit windows, +// where the first four integer arguments are passed in RCX, RDX, R8 and R9. typedef int (*F0)(); typedef int (*F1)(int64_t x); typedef int (*F2)(int64_t x, int64_t y); +#ifdef _WIN64 +static const v8::internal::Register arg1 = rcx; +static const v8::internal::Register arg2 = rdx; +#else +static const v8::internal::Register arg1 = rdi; +static const v8::internal::Register arg2 = rsi; +#endif + #define __ assm. @@ -80,7 +89,7 @@ TEST(AssemblerX64ReturnOperation) { Assembler assm(buffer, actual_size); // Assemble a simple function that copies argument 2 and returns it. - __ movq(rax, rsi); + __ movq(rax, arg2); __ nop(); __ ret(0); @@ -105,9 +114,9 @@ TEST(AssemblerX64StackOperations) { // incorrect stack frames when debugging this function (which has them). __ push(rbp); __ movq(rbp, rsp); - __ push(rsi); // Value at (rbp - 8) - __ push(rsi); // Value at (rbp - 16) - __ push(rdi); // Value at (rbp - 24) + __ push(arg2); // Value at (rbp - 8) + __ push(arg2); // Value at (rbp - 16) + __ push(arg1); // Value at (rbp - 24) __ pop(rax); __ pop(rax); __ pop(rax); @@ -132,8 +141,8 @@ TEST(AssemblerX64ArithmeticOperations) { Assembler assm(buffer, actual_size); // Assemble a simple function that adds arguments returning the sum. - __ movq(rax, rsi); - __ addq(rax, rdi); + __ movq(rax, arg2); + __ addq(rax, arg1); __ ret(0); CodeDesc desc; @@ -154,8 +163,8 @@ TEST(AssemblerX64ImulOperation) { // Assemble a simple function that multiplies arguments returning the high // word. - __ movq(rax, rsi); - __ imul(rdi); + __ movq(rax, arg2); + __ imul(arg1); __ movq(rax, rdx); __ ret(0); @@ -182,14 +191,16 @@ TEST(AssemblerX64MemoryOperands) { // Assemble a simple function that copies argument 2 and returns it. __ push(rbp); __ movq(rbp, rsp); - __ push(rsi); // Value at (rbp - 8) - __ push(rsi); // Value at (rbp - 16) - __ push(rdi); // Value at (rbp - 24) + + __ push(arg2); // Value at (rbp - 8) + __ push(arg2); // Value at (rbp - 16) + __ push(arg1); // Value at (rbp - 24) + const int kStackElementSize = 8; __ movq(rax, Operand(rbp, -3 * kStackElementSize)); - __ pop(rsi); - __ pop(rsi); - __ pop(rsi); + __ pop(arg2); + __ pop(arg2); + __ pop(arg2); __ pop(rbp); __ nop(); __ ret(0); @@ -210,13 +221,14 @@ TEST(AssemblerX64ControlFlow) { CHECK(buffer); Assembler assm(buffer, actual_size); - // Assemble a simple function that copies argument 2 and returns it. + // Assemble a simple function that copies argument 1 and returns it. __ push(rbp); + __ movq(rbp, rsp); - __ movq(rax, rdi); + __ movq(rax, arg1); Label target; __ jmp(&target); - __ movq(rax, rsi); + __ movq(rax, arg2); __ bind(&target); __ pop(rbp); __ ret(0); diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 1da363c2ae..4ffcee3dbf 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -3539,6 +3539,52 @@ bool IsBreakEventMessage(char *message) { } +// We match parts of the message to decide if it is a exception message. +bool IsExceptionEventMessage(char *message) { + const char* type_event = "\"type\":\"event\""; + const char* event_exception = "\"event\":\"exception\""; + // Does the message contain both type:event and event:exception? + return strstr(message, type_event) != NULL && + strstr(message, event_exception) != NULL; +} + + +// We match the message wether it is an evaluate response message. +bool IsEvaluateResponseMessage(char* message) { + const char* type_response = "\"type\":\"response\""; + const char* command_evaluate = "\"command\":\"evaluate\""; + // Does the message contain both type:response and command:evaluate? + return strstr(message, type_response) != NULL && + strstr(message, command_evaluate) != NULL; +} + + +// We match parts of the message to get evaluate result int value. +int GetEvaluateIntResult(char *message) { + const char* value = "\"value\":"; + char* pos = strstr(message, value); + if (pos == NULL) { + return -1; + } + int res = -1; + res = atoi(pos + strlen(value)); + return res; +} + + +// We match parts of the message to get hit breakpoint id. +int GetBreakpointIdFromBreakEventMessage(char *message) { + const char* breakpoints = "\"breakpoints\":["; + char* pos = strstr(message, breakpoints); + if (pos == NULL) { + return -1; + } + int res = -1; + res = atoi(pos + strlen(breakpoints)); + return res; +} + + /* Test MessageQueues */ /* Tests the message queues that hold debugger commands and * response messages to the debugger. Fills queues and makes @@ -3566,8 +3612,6 @@ static void MessageHandler(const uint16_t* message, int length, // Allow message handler to block on a semaphore, to test queueing of // messages while blocked. message_queue_barriers.semaphore_1->Wait(); - printf("%s\n", print_buffer); - fflush(stdout); } void MessageQueueDebuggerThread::Run() { @@ -3822,8 +3866,6 @@ static void ThreadedMessageHandler(const v8::Debug::Message& message) { if (IsBreakEventMessage(print_buffer)) { threaded_debugging_barriers.barrier_2.Wait(); } - printf("%s\n", print_buffer); - fflush(stdout); } @@ -3911,16 +3953,20 @@ class BreakpointsDebuggerThread : public v8::internal::Thread { Barriers* breakpoints_barriers; +int break_event_breakpoint_id; +int evaluate_int_result; static void BreakpointsMessageHandler(const v8::Debug::Message& message) { static char print_buffer[1000]; v8::String::Value json(message.GetJSON()); Utf16ToAscii(*json, json.length(), print_buffer); - printf("%s\n", print_buffer); - fflush(stdout); - // Is break_template a prefix of the message? if (IsBreakEventMessage(print_buffer)) { + break_event_breakpoint_id = + GetBreakpointIdFromBreakEventMessage(print_buffer); + breakpoints_barriers->semaphore_1->Signal(); + } else if (IsEvaluateResponseMessage(print_buffer)) { + evaluate_int_result = GetEvaluateIntResult(print_buffer); breakpoints_barriers->semaphore_1->Signal(); } } @@ -3930,9 +3976,9 @@ void BreakpointsV8Thread::Run() { const char* source_1 = "var y_global = 3;\n" "function cat( new_value ) {\n" " var x = new_value;\n" - " y_global = 4;\n" + " y_global = y_global + 4;\n" " x = 3 * x + 1;\n" - " y_global = 5;\n" + " y_global = y_global + 5;\n" " return x;\n" "}\n" "\n" @@ -3970,59 +4016,76 @@ void BreakpointsDebuggerThread::Run() { "\"type\":\"request\"," "\"command\":\"setbreakpoint\"," "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}"; - const char* command_3 = "{\"seq\":104," + const char* command_3 = "{\"seq\":103," "\"type\":\"request\"," "\"command\":\"evaluate\"," "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}"; - const char* command_4 = "{\"seq\":105," + const char* command_4 = "{\"seq\":104," "\"type\":\"request\"," "\"command\":\"evaluate\"," - "\"arguments\":{\"expression\":\"x\",\"disable_break\":true}}"; - const char* command_5 = "{\"seq\":106," + "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}"; + const char* command_5 = "{\"seq\":105," "\"type\":\"request\"," "\"command\":\"continue\"}"; - const char* command_6 = "{\"seq\":107," + const char* command_6 = "{\"seq\":106," "\"type\":\"request\"," "\"command\":\"continue\"}"; - const char* command_7 = "{\"seq\":108," + const char* command_7 = "{\"seq\":107," "\"type\":\"request\"," "\"command\":\"evaluate\"," "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}"; - const char* command_8 = "{\"seq\":109," + const char* command_8 = "{\"seq\":108," "\"type\":\"request\"," "\"command\":\"continue\"}"; // v8 thread initializes, runs source_1 breakpoints_barriers->barrier_1.Wait(); - // 1:Set breakpoint in cat(). + // 1:Set breakpoint in cat() (will get id 1). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer)); - // 2:Set breakpoint in dog() + // 2:Set breakpoint in dog() (will get id 2). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer)); breakpoints_barriers->barrier_2.Wait(); - // v8 thread starts compiling source_2. + // V8 thread starts compiling source_2. // Automatic break happens, to run queued commands // breakpoints_barriers->semaphore_1->Wait(); // Commands 1 through 3 run, thread continues. // v8 thread runs source_2 to breakpoint in cat(). // message callback receives break event. breakpoints_barriers->semaphore_1->Wait(); + // Must have hit breakpoint #1. + CHECK_EQ(1, break_event_breakpoint_id); // 4:Evaluate dog() (which has a breakpoint). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer)); - // v8 thread hits breakpoint in dog() + // V8 thread hits breakpoint in dog(). breakpoints_barriers->semaphore_1->Wait(); // wait for break event - // 5:Evaluate x + // Must have hit breakpoint #2. + CHECK_EQ(2, break_event_breakpoint_id); + // 5:Evaluate (x + 1). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer)); - // 6:Continue evaluation of dog() + // Evaluate (x + 1) finishes. + breakpoints_barriers->semaphore_1->Wait(); + // Must have result 108. + CHECK_EQ(108, evaluate_int_result); + // 6:Continue evaluation of dog(). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer)); - // dog() finishes. + // Evaluate dog() finishes. + breakpoints_barriers->semaphore_1->Wait(); + // Must have result 107. + CHECK_EQ(107, evaluate_int_result); // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint // in cat(19). v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer)); - // message callback gets break event + // Message callback gets break event. breakpoints_barriers->semaphore_1->Wait(); // wait for break event - // 8: Evaluate dog() with breaks disabled + // Must have hit breakpoint #1. + CHECK_EQ(1, break_event_breakpoint_id); + // 8: Evaluate dog() with breaks disabled. v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer)); + // Evaluate dog() finishes. + breakpoints_barriers->semaphore_1->Wait(); + // Must have result 116. + CHECK_EQ(116, evaluate_int_result); // 9: Continue evaluation of source2, reach end. v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer)); } @@ -4325,7 +4388,13 @@ static int message_handler_hit_count = 0; static void MessageHandlerHitCount(const v8::Debug::Message& message) { message_handler_hit_count++; - SendContinueCommand(); + static char print_buffer[1000]; + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); + if (IsExceptionEventMessage(print_buffer)) { + // Send a continue command for exception events. + SendContinueCommand(); + } } @@ -4415,8 +4484,6 @@ 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); - printf("%s\n", print_buffer); - fflush(stdout); } @@ -4776,8 +4843,12 @@ static void ContextCheckMessageHandler(const v8::Debug::Message& message) { expected_context_data)); message_handler_hit_count++; + static char print_buffer[1000]; + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); + // Send a continue command for break events. - if (message.GetEvent() == v8::Break) { + if (IsBreakEventMessage(print_buffer)) { SendContinueCommand(); } } @@ -5016,7 +5087,11 @@ static void DebugEvalContextCheckMessageHandler( expected_context_data)); message_handler_hit_count++; - if (message.IsEvent() && message.GetEvent() == v8::Break) { + static char print_buffer[1000]; + v8::String::Value json(message.GetJSON()); + Utf16ToAscii(*json, json.length(), print_buffer); + + if (IsBreakEventMessage(print_buffer)) { break_count++; if (!sent_eval) { sent_eval = true; @@ -5038,7 +5113,8 @@ static void DebugEvalContextCheckMessageHandler( SendContinueCommand(); continue_command_send_count++; } - } else if (message.IsResponse() && continue_command_send_count < 2) { + } else if (IsEvaluateResponseMessage(print_buffer) && + continue_command_send_count < 2) { // Response to the evaluation request. We're still on the breakpoint so // send continue. SendContinueCommand(); diff --git a/deps/v8/test/cctest/test-disasm-ia32.cc b/deps/v8/test/cctest/test-disasm-ia32.cc index af9fb97e5b..74db23463a 100644 --- a/deps/v8/test/cctest/test-disasm-ia32.cc +++ b/deps/v8/test/cctest/test-disasm-ia32.cc @@ -363,7 +363,31 @@ TEST(DisasmIa320) { __ divsd(xmm1, xmm0); __ movdbl(xmm1, Operand(ebx, ecx, times_4, 10000)); __ movdbl(Operand(ebx, ecx, times_4, 10000), xmm1); + __ comisd(xmm0, xmm1); } + + // cmov. + { + CHECK(CpuFeatures::IsSupported(CpuFeatures::CMOV)); + CpuFeatures::Scope use_cmov(CpuFeatures::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)); + } + __ ret(0); CodeDesc desc; diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index eb32b6539e..9911ce42bc 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -132,15 +132,19 @@ TEST(HeapObjects) { CHECK(value->IsNumber()); CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value()); +#ifndef V8_TARGET_ARCH_X64 + // TODO(lrn): We need a NumberFromIntptr function in order to test this. value = Heap::NumberFromInt32(Smi::kMinValue - 1); CHECK(value->IsHeapNumber()); CHECK(value->IsNumber()); CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number()); +#endif - value = Heap::NumberFromInt32(Smi::kMaxValue + 1); + value = Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1); CHECK(value->IsHeapNumber()); CHECK(value->IsNumber()); - CHECK_EQ(static_cast<double>(Smi::kMaxValue + 1), value->Number()); + CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1), + value->Number()); // nan oddball checks CHECK(Heap::nan_value()->IsNumber()); @@ -640,8 +644,9 @@ TEST(JSArray) { CHECK_EQ(Smi::FromInt(1), array->length()); CHECK_EQ(array->GetElement(0), name); - // Set array length with larger than smi value. - Object* length = Heap::NumberFromInt32(Smi::kMaxValue + 1); +// Set array length with larger than smi value. + Object* length = + Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1); array->SetElementsLength(length); uint32_t int_length = 0; diff --git a/deps/v8/test/cctest/test-macro-assembler-x64.cc b/deps/v8/test/cctest/test-macro-assembler-x64.cc new file mode 100755 index 0000000000..9c1197ffd8 --- /dev/null +++ b/deps/v8/test/cctest/test-macro-assembler-x64.cc @@ -0,0 +1,2096 @@ +// 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 <stdlib.h> + +#include "v8.h" + +#include "macro-assembler.h" +#include "factory.h" +#include "platform.h" +#include "serialize.h" +#include "cctest.h" + +using v8::internal::byte; +using v8::internal::OS; +using v8::internal::Assembler; +using v8::internal::Condition; +using v8::internal::MacroAssembler; +using v8::internal::HandleScope; +using v8::internal::Operand; +using v8::internal::Immediate; +using v8::internal::SmiIndex; +using v8::internal::Label; +using v8::internal::RelocInfo; +using v8::internal::rax; +using v8::internal::rbx; +using v8::internal::rsi; +using v8::internal::rdi; +using v8::internal::rcx; +using v8::internal::rdx; +using v8::internal::rbp; +using v8::internal::rsp; +using v8::internal::r8; +using v8::internal::r9; +using v8::internal::r11; +using v8::internal::r12; +using v8::internal::r13; +using v8::internal::r14; +using v8::internal::r15; +using v8::internal::FUNCTION_CAST; +using v8::internal::CodeDesc; +using v8::internal::less_equal; +using v8::internal::not_equal; +using v8::internal::not_zero; +using v8::internal::greater; +using v8::internal::greater_equal; +using v8::internal::carry; +using v8::internal::not_carry; +using v8::internal::negative; +using v8::internal::positive; +using v8::internal::Smi; +using v8::internal::kSmiTagMask; +using v8::internal::kSmiValueSize; + +// Test the x64 assembler by compiling some simple functions into +// a buffer and executing them. These tests do not initialize the +// V8 library, create a context, or use any V8 objects. +// The AMD64 calling convention is used, with the first five arguments +// in RSI, RDI, RDX, RCX, R8, and R9, and floating point arguments in +// the XMM registers. The return value is in RAX. +// This calling convention is used on Linux, with GCC, and on Mac OS, +// with GCC. A different convention is used on 64-bit windows. + +typedef int (*F0)(); + +#define __ masm-> + +TEST(Smi) { + // Check that C++ Smi operations work as expected. + intptr_t test_numbers[] = { + 0, 1, -1, 127, 128, -128, -129, 255, 256, -256, -257, + Smi::kMaxValue, static_cast<intptr_t>(Smi::kMaxValue) + 1, + Smi::kMinValue, static_cast<intptr_t>(Smi::kMinValue) - 1 + }; + int test_number_count = 15; + for (int i = 0; i < test_number_count; i++) { + intptr_t number = test_numbers[i]; + bool is_valid = Smi::IsValid(number); + bool is_in_range = number >= Smi::kMinValue && number <= Smi::kMaxValue; + CHECK_EQ(is_in_range, is_valid); + if (is_valid) { + Smi* smi_from_intptr = Smi::FromIntptr(number); + if (static_cast<int>(number) == number) { // Is a 32-bit int. + Smi* smi_from_int = Smi::FromInt(static_cast<int32_t>(number)); + CHECK_EQ(smi_from_int, smi_from_intptr); + } + int smi_value = smi_from_intptr->value(); + CHECK_EQ(number, static_cast<intptr_t>(smi_value)); + } + } +} + + +static void TestMoveSmi(MacroAssembler* masm, Label* exit, int id, Smi* value) { + __ movl(rax, Immediate(id)); + __ Move(rcx, Smi::FromInt(0)); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0))); + __ cmpq(rcx, rdx); + __ j(not_equal, exit); +} + + +// Test that we can move a Smi value literally into a register. +TEST(SmiMove) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + MacroAssembler* masm = &assembler; // Create a pointer for the __ macro. + masm->set_allow_stub_calls(false); + Label exit; + + TestMoveSmi(masm, &exit, 1, Smi::FromInt(0)); + TestMoveSmi(masm, &exit, 2, Smi::FromInt(127)); + TestMoveSmi(masm, &exit, 3, Smi::FromInt(128)); + TestMoveSmi(masm, &exit, 4, Smi::FromInt(255)); + TestMoveSmi(masm, &exit, 5, Smi::FromInt(256)); + TestMoveSmi(masm, &exit, 6, Smi::FromInt(Smi::kMaxValue)); + TestMoveSmi(masm, &exit, 7, Smi::FromInt(-1)); + TestMoveSmi(masm, &exit, 8, Smi::FromInt(-128)); + TestMoveSmi(masm, &exit, 9, Smi::FromInt(-129)); + TestMoveSmi(masm, &exit, 10, Smi::FromInt(-256)); + TestMoveSmi(masm, &exit, 11, Smi::FromInt(-257)); + TestMoveSmi(masm, &exit, 12, Smi::FromInt(Smi::kMinValue)); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiCompare(MacroAssembler* masm, Label* exit, int id, int x, int y) { + __ Move(rcx, Smi::FromInt(x)); + __ movq(r8, rcx); + __ Move(rdx, Smi::FromInt(y)); + __ movq(r9, rdx); + __ SmiCompare(rcx, rdx); + if (x < y) { + __ movl(rax, Immediate(id + 1)); + __ j(greater_equal, exit); + } else if (x > y) { + __ movl(rax, Immediate(id + 2)); + __ j(less_equal, exit); + } else { + ASSERT_EQ(x, y); + __ movl(rax, Immediate(id + 3)); + __ j(not_equal, exit); + } + __ movl(rax, Immediate(id + 4)); + __ cmpq(rcx, r8); + __ j(not_equal, exit); + __ incq(rax); + __ cmpq(rdx, r9); + __ j(not_equal, exit); + + if (x != y) { + __ SmiCompare(rdx, rcx); + if (y < x) { + __ movl(rax, Immediate(id + 9)); + __ j(greater_equal, exit); + } else { + ASSERT(y > x); + __ movl(rax, Immediate(id + 10)); + __ j(less_equal, exit); + } + } else { + __ SmiCompare(rcx, rcx); + __ movl(rax, Immediate(id + 11)); + __ j(not_equal, exit); + __ incq(rax); + __ cmpq(rcx, r8); + __ j(not_equal, exit); + } +} + + +// Test that we can compare smis for equality (and more). +TEST(SmiCompare) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiCompare(masm, &exit, 0x10, 0, 0); + TestSmiCompare(masm, &exit, 0x20, 0, 1); + TestSmiCompare(masm, &exit, 0x30, 1, 0); + TestSmiCompare(masm, &exit, 0x40, 1, 1); + TestSmiCompare(masm, &exit, 0x50, 0, -1); + TestSmiCompare(masm, &exit, 0x60, -1, 0); + TestSmiCompare(masm, &exit, 0x70, -1, -1); + TestSmiCompare(masm, &exit, 0x80, 0, Smi::kMinValue); + TestSmiCompare(masm, &exit, 0x90, Smi::kMinValue, 0); + TestSmiCompare(masm, &exit, 0xA0, 0, Smi::kMaxValue); + TestSmiCompare(masm, &exit, 0xB0, Smi::kMaxValue, 0); + TestSmiCompare(masm, &exit, 0xC0, -1, Smi::kMinValue); + TestSmiCompare(masm, &exit, 0xD0, Smi::kMinValue, -1); + TestSmiCompare(masm, &exit, 0xE0, -1, Smi::kMaxValue); + TestSmiCompare(masm, &exit, 0xF0, Smi::kMaxValue, -1); + TestSmiCompare(masm, &exit, 0x100, Smi::kMinValue, Smi::kMinValue); + TestSmiCompare(masm, &exit, 0x110, Smi::kMinValue, Smi::kMaxValue); + TestSmiCompare(masm, &exit, 0x120, Smi::kMaxValue, Smi::kMinValue); + TestSmiCompare(masm, &exit, 0x130, Smi::kMaxValue, Smi::kMaxValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + + +TEST(Integer32ToSmi) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + __ movq(rax, Immediate(1)); // Test number. + __ movl(rcx, Immediate(0)); + __ Integer32ToSmi(rcx, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0))); + __ SmiCompare(rcx, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(2)); // Test number. + __ movl(rcx, Immediate(1024)); + __ Integer32ToSmi(rcx, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024))); + __ SmiCompare(rcx, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(3)); // Test number. + __ movl(rcx, Immediate(-1)); + __ Integer32ToSmi(rcx, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1))); + __ SmiCompare(rcx, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(4)); // Test number. + __ movl(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(rcx, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue))); + __ SmiCompare(rcx, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(5)); // Test number. + __ movl(rcx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(rcx, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue))); + __ SmiCompare(rcx, rdx); + __ j(not_equal, &exit); + + // Different target register. + + __ movq(rax, Immediate(6)); // Test number. + __ movl(rcx, Immediate(0)); + __ Integer32ToSmi(r8, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(0))); + __ SmiCompare(r8, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(7)); // Test number. + __ movl(rcx, Immediate(1024)); + __ Integer32ToSmi(r8, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(1024))); + __ SmiCompare(r8, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(8)); // Test number. + __ movl(rcx, Immediate(-1)); + __ Integer32ToSmi(r8, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(-1))); + __ SmiCompare(r8, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(9)); // Test number. + __ movl(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(r8, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMaxValue))); + __ SmiCompare(r8, rdx); + __ j(not_equal, &exit); + + __ movq(rax, Immediate(10)); // Test number. + __ movl(rcx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(r8, rcx); + __ Set(rdx, reinterpret_cast<intptr_t>(Smi::FromInt(Smi::kMinValue))); + __ SmiCompare(r8, rdx); + __ j(not_equal, &exit); + + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestI64PlusConstantToSmi(MacroAssembler* masm, + Label* exit, + int id, + int64_t x, + int y) { + int64_t result = x + y; + ASSERT(Smi::IsValid(result)); + __ movl(rax, Immediate(id)); + __ Move(r8, Smi::FromInt(result)); + __ movq(rcx, x, RelocInfo::NONE); + __ movq(r11, rcx); + __ Integer64PlusConstantToSmi(rdx, rcx, y); + __ SmiCompare(rdx, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ Integer64PlusConstantToSmi(rcx, rcx, y); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); +} + + +TEST(Integer64PlusConstantToSmi) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + int64_t twice_max = static_cast<int64_t>(Smi::kMaxValue) * 2; + + TestI64PlusConstantToSmi(masm, &exit, 0x10, 0, 0); + TestI64PlusConstantToSmi(masm, &exit, 0x20, 0, 1); + TestI64PlusConstantToSmi(masm, &exit, 0x30, 1, 0); + TestI64PlusConstantToSmi(masm, &exit, 0x40, Smi::kMaxValue - 5, 5); + TestI64PlusConstantToSmi(masm, &exit, 0x50, Smi::kMinValue + 5, 5); + TestI64PlusConstantToSmi(masm, &exit, 0x60, twice_max, -Smi::kMaxValue); + TestI64PlusConstantToSmi(masm, &exit, 0x70, -twice_max, Smi::kMaxValue); + TestI64PlusConstantToSmi(masm, &exit, 0x80, 0, Smi::kMinValue); + TestI64PlusConstantToSmi(masm, &exit, 0x90, 0, Smi::kMaxValue); + TestI64PlusConstantToSmi(masm, &exit, 0xA0, Smi::kMinValue, 0); + TestI64PlusConstantToSmi(masm, &exit, 0xB0, Smi::kMaxValue, 0); + TestI64PlusConstantToSmi(masm, &exit, 0xC0, twice_max, Smi::kMinValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +TEST(SmiCheck) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + Condition cond; + + __ movl(rax, Immediate(1)); // Test number. + + // CheckSmi + + __ movl(rcx, Immediate(0)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckSmi(rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckSmi(rcx); + __ j(cond, &exit); + + __ incq(rax); + __ movl(rcx, Immediate(-1)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckSmi(rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckSmi(rcx); + __ j(cond, &exit); + + __ incq(rax); + __ movl(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckSmi(rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckSmi(rcx); + __ j(cond, &exit); + + __ incq(rax); + __ movl(rcx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckSmi(rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckSmi(rcx); + __ j(cond, &exit); + + // CheckPositiveSmi + + __ incq(rax); + __ movl(rcx, Immediate(0)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckPositiveSmi(rcx); // Zero counts as positive. + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckPositiveSmi(rcx); // "zero" non-smi. + __ j(cond, &exit); + + __ incq(rax); + __ movq(rcx, Immediate(-1)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckPositiveSmi(rcx); // Negative smis are not positive. + __ j(cond, &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckPositiveSmi(rcx); // Most negative smi is not positive. + __ j(cond, &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckPositiveSmi(rcx); // "Negative" non-smi. + __ j(cond, &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckPositiveSmi(rcx); // Most positive smi is positive. + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckPositiveSmi(rcx); // "Positive" non-smi. + __ j(cond, &exit); + + // CheckIsMinSmi + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckIsMinSmi(rcx); + __ j(cond, &exit); + + __ incq(rax); + __ movq(rcx, Immediate(0)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckIsMinSmi(rcx); + __ j(cond, &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckIsMinSmi(rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMinValue + 1)); + __ Integer32ToSmi(rcx, rcx); + cond = masm->CheckIsMinSmi(rcx); + __ j(cond, &exit); + + // CheckBothSmi + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMaxValue)); + __ Integer32ToSmi(rcx, rcx); + __ movq(rdx, Immediate(Smi::kMinValue)); + __ Integer32ToSmi(rdx, rdx); + cond = masm->CheckBothSmi(rcx, rdx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckBothSmi(rcx, rdx); + __ j(cond, &exit); + + __ incq(rax); + __ xor_(rdx, Immediate(kSmiTagMask)); + cond = masm->CheckBothSmi(rcx, rdx); + __ j(cond, &exit); + + __ incq(rax); + __ xor_(rcx, Immediate(kSmiTagMask)); + cond = masm->CheckBothSmi(rcx, rdx); + __ j(cond, &exit); + + __ incq(rax); + cond = masm->CheckBothSmi(rcx, rcx); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + cond = masm->CheckBothSmi(rdx, rdx); + __ j(cond, &exit); + + // CheckInteger32ValidSmiValue + __ incq(rax); + __ movq(rcx, Immediate(0)); + cond = masm->CheckInteger32ValidSmiValue(rax); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ movq(rcx, Immediate(-1)); + cond = masm->CheckInteger32ValidSmiValue(rax); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMaxValue)); + cond = masm->CheckInteger32ValidSmiValue(rax); + __ j(NegateCondition(cond), &exit); + + __ incq(rax); + __ movq(rcx, Immediate(Smi::kMinValue)); + cond = masm->CheckInteger32ValidSmiValue(rax); + __ j(NegateCondition(cond), &exit); + + // Success + __ xor_(rax, rax); + + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + + +void TestSmiNeg(MacroAssembler* masm, Label* exit, int id, int x) { + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + if (x == Smi::kMinValue || x == 0) { + // Negation fails. + __ movl(rax, Immediate(id + 8)); + __ SmiNeg(r9, rcx, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiNeg(rcx, rcx, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + } else { + Label smi_ok, smi_ok2; + int result = -x; + __ movl(rax, Immediate(id)); + __ Move(r8, Smi::FromInt(result)); + + __ SmiNeg(r9, rcx, &smi_ok); + __ jmp(exit); + __ bind(&smi_ok); + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiNeg(rcx, rcx, &smi_ok2); + __ jmp(exit); + __ bind(&smi_ok2); + __ incq(rax); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + } +} + + +TEST(SmiNeg) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiNeg(masm, &exit, 0x10, 0); + TestSmiNeg(masm, &exit, 0x20, 1); + TestSmiNeg(masm, &exit, 0x30, -1); + TestSmiNeg(masm, &exit, 0x40, 127); + TestSmiNeg(masm, &exit, 0x50, 65535); + TestSmiNeg(masm, &exit, 0x60, Smi::kMinValue); + TestSmiNeg(masm, &exit, 0x70, Smi::kMaxValue); + TestSmiNeg(masm, &exit, 0x80, -Smi::kMaxValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + + + +static void SmiAddTest(MacroAssembler* masm, + Label* exit, + int id, + int first, + int second) { + __ movl(rcx, Immediate(first)); + __ Integer32ToSmi(rcx, rcx); + __ movl(rdx, Immediate(second)); + __ Integer32ToSmi(rdx, rdx); + __ movl(r8, Immediate(first + second)); + __ Integer32ToSmi(r8, r8); + + __ movl(rax, Immediate(id)); // Test number. + __ SmiAdd(r9, rcx, rdx, exit); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiAdd(rcx, rcx, rdx, exit); \ + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ movl(rcx, Immediate(first)); + __ Integer32ToSmi(rcx, rcx); + + __ incq(rax); + __ SmiAddConstant(r9, rcx, Smi::FromInt(second)); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ SmiAddConstant(rcx, rcx, Smi::FromInt(second)); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ movl(rcx, Immediate(first)); + __ Integer32ToSmi(rcx, rcx); + + __ incq(rax); + __ SmiAddConstant(r9, rcx, Smi::FromInt(second), exit); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiAddConstant(rcx, rcx, Smi::FromInt(second), exit); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); +} + +TEST(SmiAdd) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + // No-overflow tests. + SmiAddTest(masm, &exit, 0x10, 1, 2); + SmiAddTest(masm, &exit, 0x20, 1, -2); + SmiAddTest(masm, &exit, 0x30, -1, 2); + SmiAddTest(masm, &exit, 0x40, -1, -2); + SmiAddTest(masm, &exit, 0x50, 0x1000, 0x2000); + SmiAddTest(masm, &exit, 0x60, Smi::kMinValue, 5); + SmiAddTest(masm, &exit, 0x70, Smi::kMaxValue, -5); + SmiAddTest(masm, &exit, 0x80, Smi::kMaxValue, Smi::kMinValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +static void SmiSubTest(MacroAssembler* masm, + Label* exit, + int id, + int first, + int second) { + __ Move(rcx, Smi::FromInt(first)); + __ Move(rdx, Smi::FromInt(second)); + __ Move(r8, Smi::FromInt(first - second)); + + __ movl(rax, Immediate(id)); // Test 0. + __ SmiSub(r9, rcx, rdx, exit); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); // Test 1. + __ SmiSub(rcx, rcx, rdx, exit); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ Move(rcx, Smi::FromInt(first)); + + __ incq(rax); // Test 2. + __ SmiSubConstant(r9, rcx, Smi::FromInt(second)); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); // Test 3. + __ SmiSubConstant(rcx, rcx, Smi::FromInt(second)); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ Move(rcx, Smi::FromInt(first)); + + __ incq(rax); // Test 4. + __ SmiSubConstant(r9, rcx, Smi::FromInt(second), exit); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); // Test 5. + __ SmiSubConstant(rcx, rcx, Smi::FromInt(second), exit); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); +} + +static void SmiSubOverflowTest(MacroAssembler* masm, + Label* exit, + int id, + int x) { + // Subtracts a Smi from x so that the subtraction overflows. + ASSERT(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); + + __ movl(rax, Immediate(id)); + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); // Store original Smi value of x in r11. + __ Move(rdx, Smi::FromInt(y_min)); + { + Label overflow_ok; + __ SmiSub(r9, rcx, rdx, &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + { + Label overflow_ok; + __ incq(rax); + __ SmiSub(rcx, rcx, rdx, &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + __ movq(rcx, r11); + { + Label overflow_ok; + __ incq(rax); + __ SmiSubConstant(r9, rcx, Smi::FromInt(y_min), &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + { + Label overflow_ok; + __ incq(rax); + __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_min), &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + __ Move(rdx, Smi::FromInt(y_max)); + + { + Label overflow_ok; + __ incq(rax); + __ SmiSub(r9, rcx, rdx, &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + { + Label overflow_ok; + __ incq(rax); + __ SmiSub(rcx, rcx, rdx, &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + __ movq(rcx, r11); + { + Label overflow_ok; + __ incq(rax); + __ SmiSubConstant(r9, rcx, Smi::FromInt(y_max), &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } + + { + Label overflow_ok; + __ incq(rax); + __ SmiSubConstant(rcx, rcx, Smi::FromInt(y_max), &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } +} + + +TEST(SmiSub) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + SmiSubTest(masm, &exit, 0x10, 1, 2); + SmiSubTest(masm, &exit, 0x20, 1, -2); + SmiSubTest(masm, &exit, 0x30, -1, 2); + SmiSubTest(masm, &exit, 0x40, -1, -2); + SmiSubTest(masm, &exit, 0x50, 0x1000, 0x2000); + SmiSubTest(masm, &exit, 0x60, Smi::kMinValue, -5); + SmiSubTest(masm, &exit, 0x70, Smi::kMaxValue, 5); + SmiSubTest(masm, &exit, 0x80, -Smi::kMaxValue, Smi::kMinValue); + SmiSubTest(masm, &exit, 0x90, 0, Smi::kMaxValue); + + SmiSubOverflowTest(masm, &exit, 0xA0, 1); + SmiSubOverflowTest(masm, &exit, 0xB0, 1024); + SmiSubOverflowTest(masm, &exit, 0xC0, Smi::kMaxValue); + SmiSubOverflowTest(masm, &exit, 0xD0, -2); + SmiSubOverflowTest(masm, &exit, 0xE0, -42000); + SmiSubOverflowTest(masm, &exit, 0xF0, Smi::kMinValue); + SmiSubOverflowTest(masm, &exit, 0x100, 0); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + + +void TestSmiMul(MacroAssembler* masm, Label* exit, int id, int x, int y) { + int64_t result = static_cast<int64_t>(x) * static_cast<int64_t>(y); + bool negative_zero = (result == 0) && (x < 0 || y < 0); + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ Move(rdx, Smi::FromInt(y)); + if (Smi::IsValid(result) && !negative_zero) { + __ movl(rax, Immediate(id)); + __ Move(r8, Smi::FromIntptr(result)); + __ SmiMul(r9, rcx, rdx, exit); + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiMul(rcx, rcx, rdx, exit); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + } else { + __ movl(rax, Immediate(id + 8)); + Label overflow_ok, overflow_ok2; + __ SmiMul(r9, rcx, rdx, &overflow_ok); + __ jmp(exit); + __ bind(&overflow_ok); + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + __ incq(rax); + __ SmiMul(rcx, rcx, rdx, &overflow_ok2); + __ jmp(exit); + __ bind(&overflow_ok2); + // 31-bit version doesn't preserve rcx on failure. + // __ incq(rax); + // __ SmiCompare(r11, rcx); + // __ j(not_equal, exit); + } +} + + +TEST(SmiMul) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiMul(masm, &exit, 0x10, 0, 0); + TestSmiMul(masm, &exit, 0x20, -1, 0); + TestSmiMul(masm, &exit, 0x30, 0, -1); + TestSmiMul(masm, &exit, 0x40, -1, -1); + TestSmiMul(masm, &exit, 0x50, 0x10000, 0x10000); + TestSmiMul(masm, &exit, 0x60, 0x10000, 0xffff); + TestSmiMul(masm, &exit, 0x70, 0x10000, 0xffff); + TestSmiMul(masm, &exit, 0x80, Smi::kMaxValue, -1); + TestSmiMul(masm, &exit, 0x90, Smi::kMaxValue, -2); + TestSmiMul(masm, &exit, 0xa0, Smi::kMaxValue, 2); + TestSmiMul(masm, &exit, 0xb0, (Smi::kMaxValue / 2), 2); + TestSmiMul(masm, &exit, 0xc0, (Smi::kMaxValue / 2) + 1, 2); + TestSmiMul(masm, &exit, 0xd0, (Smi::kMinValue / 2), 2); + TestSmiMul(masm, &exit, 0xe0, (Smi::kMinValue / 2) - 1, 2); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiDiv(MacroAssembler* masm, Label* exit, int id, int x, int y) { + bool division_by_zero = (y == 0); + bool negative_zero = (x == 0 && y < 0); +#ifdef V8_TARGET_ARCH_X64 + bool overflow = (x == Smi::kMinValue && y < 0); // Safe approx. used. +#else + bool overflow = (x == Smi::kMinValue && y == -1); +#endif + bool fraction = !division_by_zero && !overflow && (x % y != 0); + __ Move(r11, Smi::FromInt(x)); + __ Move(r12, Smi::FromInt(y)); + if (!fraction && !overflow && !negative_zero && !division_by_zero) { + // Division succeeds + __ movq(rcx, r11); + __ movq(r15, Immediate(id)); + int result = x / y; + __ Move(r8, Smi::FromInt(result)); + __ SmiDiv(r9, rcx, r12, exit); + // Might have destroyed rcx and r12. + __ incq(r15); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(r15); + __ movq(rcx, r11); + __ Move(r12, Smi::FromInt(y)); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(r15); + __ SmiDiv(rcx, rcx, r12, exit); + + __ incq(r15); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + } else { + // Division fails. + __ movq(r15, Immediate(id + 8)); + + Label fail_ok, fail_ok2; + __ movq(rcx, r11); + __ SmiDiv(r9, rcx, r12, &fail_ok); + __ jmp(exit); + __ bind(&fail_ok); + + __ incq(r15); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(r15); + __ SmiDiv(rcx, rcx, r12, &fail_ok2); + __ jmp(exit); + __ bind(&fail_ok2); + + __ incq(r15); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } +} + + +TEST(SmiDiv) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiDiv(masm, &exit, 0x10, 1, 1); + TestSmiDiv(masm, &exit, 0x20, 1, 0); + TestSmiDiv(masm, &exit, 0x30, -1, 0); + TestSmiDiv(masm, &exit, 0x40, 0, 1); + TestSmiDiv(masm, &exit, 0x50, 0, -1); + TestSmiDiv(masm, &exit, 0x60, 4, 2); + TestSmiDiv(masm, &exit, 0x70, -4, 2); + TestSmiDiv(masm, &exit, 0x80, 4, -2); + TestSmiDiv(masm, &exit, 0x90, -4, -2); + TestSmiDiv(masm, &exit, 0xa0, 3, 2); + TestSmiDiv(masm, &exit, 0xb0, 3, 4); + TestSmiDiv(masm, &exit, 0xc0, 1, Smi::kMaxValue); + TestSmiDiv(masm, &exit, 0xd0, -1, Smi::kMaxValue); + TestSmiDiv(masm, &exit, 0xe0, Smi::kMaxValue, 1); + TestSmiDiv(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue); + TestSmiDiv(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue); + TestSmiDiv(masm, &exit, 0x110, Smi::kMaxValue, -1); + TestSmiDiv(masm, &exit, 0x120, Smi::kMinValue, 1); + TestSmiDiv(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue); + TestSmiDiv(masm, &exit, 0x140, Smi::kMinValue, -1); + + __ xor_(r15, r15); // Success. + __ bind(&exit); + __ movq(rax, r15); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiMod(MacroAssembler* masm, Label* exit, int id, int x, int y) { + bool division_by_zero = (y == 0); + bool division_overflow = (x == Smi::kMinValue) && (y == -1); + bool fraction = !division_by_zero && !division_overflow && ((x % y) != 0); + bool negative_zero = (!fraction && x < 0); + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ Move(r12, Smi::FromInt(y)); + if (!division_overflow && !negative_zero && !division_by_zero) { + // Modulo succeeds + __ movq(r15, Immediate(id)); + int result = x % y; + __ Move(r8, Smi::FromInt(result)); + __ SmiMod(r9, rcx, r12, exit); + + __ incq(r15); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(r15); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(r15); + __ SmiMod(rcx, rcx, r12, exit); + + __ incq(r15); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + } else { + // Modulo fails. + __ movq(r15, Immediate(id + 8)); + + Label fail_ok, fail_ok2; + __ SmiMod(r9, rcx, r12, &fail_ok); + __ jmp(exit); + __ bind(&fail_ok); + + __ incq(r15); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(r15); + __ SmiMod(rcx, rcx, r12, &fail_ok2); + __ jmp(exit); + __ bind(&fail_ok2); + + __ incq(r15); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + } +} + + +TEST(SmiMod) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiMod(masm, &exit, 0x10, 1, 1); + TestSmiMod(masm, &exit, 0x20, 1, 0); + TestSmiMod(masm, &exit, 0x30, -1, 0); + TestSmiMod(masm, &exit, 0x40, 0, 1); + TestSmiMod(masm, &exit, 0x50, 0, -1); + TestSmiMod(masm, &exit, 0x60, 4, 2); + TestSmiMod(masm, &exit, 0x70, -4, 2); + TestSmiMod(masm, &exit, 0x80, 4, -2); + TestSmiMod(masm, &exit, 0x90, -4, -2); + TestSmiMod(masm, &exit, 0xa0, 3, 2); + TestSmiMod(masm, &exit, 0xb0, 3, 4); + TestSmiMod(masm, &exit, 0xc0, 1, Smi::kMaxValue); + TestSmiMod(masm, &exit, 0xd0, -1, Smi::kMaxValue); + TestSmiMod(masm, &exit, 0xe0, Smi::kMaxValue, 1); + TestSmiMod(masm, &exit, 0xf0, Smi::kMaxValue, Smi::kMaxValue); + TestSmiMod(masm, &exit, 0x100, Smi::kMaxValue, -Smi::kMaxValue); + TestSmiMod(masm, &exit, 0x110, Smi::kMaxValue, -1); + TestSmiMod(masm, &exit, 0x120, Smi::kMinValue, 1); + TestSmiMod(masm, &exit, 0x130, Smi::kMinValue, Smi::kMinValue); + TestSmiMod(masm, &exit, 0x140, Smi::kMinValue, -1); + + __ xor_(r15, r15); // Success. + __ bind(&exit); + __ movq(rax, r15); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiIndex(MacroAssembler* masm, Label* exit, int id, int x) { + __ movl(rax, Immediate(id)); + + 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)); + __ shl(index.reg, Immediate(index.scale)); + __ Set(r8, static_cast<intptr_t>(x) << i); + __ SmiCompare(index.reg, r8); + __ j(not_equal, exit); + __ incq(rax); + __ Move(rcx, Smi::FromInt(x)); + index = masm->SmiToIndex(rcx, rcx, i); + ASSERT(index.reg.is(rcx)); + __ shl(rcx, Immediate(index.scale)); + __ Set(r8, static_cast<intptr_t>(x) << i); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + __ incq(rax); + + __ Move(rcx, Smi::FromInt(x)); + index = masm->SmiToNegativeIndex(rdx, rcx, i); + ASSERT(index.reg.is(rcx) || index.reg.is(rdx)); + __ shl(index.reg, Immediate(index.scale)); + __ Set(r8, static_cast<intptr_t>(-x) << i); + __ SmiCompare(index.reg, r8); + __ j(not_equal, exit); + __ incq(rax); + __ Move(rcx, Smi::FromInt(x)); + index = masm->SmiToNegativeIndex(rcx, rcx, i); + ASSERT(index.reg.is(rcx)); + __ shl(rcx, Immediate(index.scale)); + __ Set(r8, static_cast<intptr_t>(-x) << i); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + __ incq(rax); + } +} + +TEST(SmiIndex) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiIndex(masm, &exit, 0x10, 0); + TestSmiIndex(masm, &exit, 0x20, 1); + TestSmiIndex(masm, &exit, 0x30, 100); + TestSmiIndex(masm, &exit, 0x40, 1000); + TestSmiIndex(masm, &exit, 0x50, Smi::kMaxValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSelectNonSmi(MacroAssembler* masm, Label* exit, int id, int x, int y) { + __ movl(rax, Immediate(id)); + __ Move(rcx, Smi::FromInt(x)); + __ Move(rdx, Smi::FromInt(y)); + __ xor_(rdx, Immediate(kSmiTagMask)); + __ SelectNonSmi(r9, rcx, rdx, exit); + + __ incq(rax); + __ SmiCompare(r9, rdx); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rcx, Smi::FromInt(x)); + __ Move(rdx, Smi::FromInt(y)); + __ xor_(rcx, Immediate(kSmiTagMask)); + __ SelectNonSmi(r9, rcx, rdx, exit); + + __ incq(rax); + __ SmiCompare(r9, rcx); + __ j(not_equal, exit); + + __ incq(rax); + Label fail_ok; + __ Move(rcx, Smi::FromInt(x)); + __ Move(rdx, Smi::FromInt(y)); + __ xor_(rcx, Immediate(kSmiTagMask)); + __ xor_(rdx, Immediate(kSmiTagMask)); + __ SelectNonSmi(r9, rcx, rdx, &fail_ok); + __ jmp(exit); + __ bind(&fail_ok); +} + + +TEST(SmiSelectNonSmi) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); // Avoid inline checks. + Label exit; + + TestSelectNonSmi(masm, &exit, 0x10, 0, 0); + TestSelectNonSmi(masm, &exit, 0x20, 0, 1); + TestSelectNonSmi(masm, &exit, 0x30, 1, 0); + TestSelectNonSmi(masm, &exit, 0x40, 0, -1); + TestSelectNonSmi(masm, &exit, 0x50, -1, 0); + TestSelectNonSmi(masm, &exit, 0x60, -1, -1); + TestSelectNonSmi(masm, &exit, 0x70, 1, 1); + TestSelectNonSmi(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); + TestSelectNonSmi(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiAnd(MacroAssembler* masm, Label* exit, int id, int x, int y) { + int result = x & y; + + __ movl(rax, Immediate(id)); + + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ Move(rdx, Smi::FromInt(y)); + __ Move(r8, Smi::FromInt(result)); + __ SmiAnd(r9, rcx, rdx); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiAnd(rcx, rcx, rdx); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); + + __ movq(rcx, r11); + __ incq(rax); + __ SmiAndConstant(r9, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiAndConstant(rcx, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); +} + + +TEST(SmiAnd) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiAnd(masm, &exit, 0x10, 0, 0); + TestSmiAnd(masm, &exit, 0x20, 0, 1); + TestSmiAnd(masm, &exit, 0x30, 1, 0); + TestSmiAnd(masm, &exit, 0x40, 0, -1); + TestSmiAnd(masm, &exit, 0x50, -1, 0); + TestSmiAnd(masm, &exit, 0x60, -1, -1); + TestSmiAnd(masm, &exit, 0x70, 1, 1); + TestSmiAnd(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); + TestSmiAnd(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); + TestSmiAnd(masm, &exit, 0xA0, Smi::kMinValue, -1); + TestSmiAnd(masm, &exit, 0xB0, Smi::kMinValue, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiOr(MacroAssembler* masm, Label* exit, int id, int x, int y) { + int result = x | y; + + __ movl(rax, Immediate(id)); + + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ Move(rdx, Smi::FromInt(y)); + __ Move(r8, Smi::FromInt(result)); + __ SmiOr(r9, rcx, rdx); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiOr(rcx, rcx, rdx); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); + + __ movq(rcx, r11); + __ incq(rax); + __ SmiOrConstant(r9, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiOrConstant(rcx, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); +} + + +TEST(SmiOr) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiOr(masm, &exit, 0x10, 0, 0); + TestSmiOr(masm, &exit, 0x20, 0, 1); + TestSmiOr(masm, &exit, 0x30, 1, 0); + TestSmiOr(masm, &exit, 0x40, 0, -1); + TestSmiOr(masm, &exit, 0x50, -1, 0); + TestSmiOr(masm, &exit, 0x60, -1, -1); + TestSmiOr(masm, &exit, 0x70, 1, 1); + TestSmiOr(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); + TestSmiOr(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); + TestSmiOr(masm, &exit, 0xA0, Smi::kMinValue, -1); + TestSmiOr(masm, &exit, 0xB0, 0x05555555, 0x01234567); + TestSmiOr(masm, &exit, 0xC0, 0x05555555, 0x0fedcba9); + TestSmiOr(masm, &exit, 0xD0, Smi::kMinValue, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiXor(MacroAssembler* masm, Label* exit, int id, int x, int y) { + int result = x ^ y; + + __ movl(rax, Immediate(id)); + + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ Move(rdx, Smi::FromInt(y)); + __ Move(r8, Smi::FromInt(result)); + __ SmiXor(r9, rcx, rdx); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiXor(rcx, rcx, rdx); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); + + __ movq(rcx, r11); + __ incq(rax); + __ SmiXorConstant(r9, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, r9); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiXorConstant(rcx, rcx, Smi::FromInt(y)); + __ SmiCompare(r8, rcx); + __ j(not_equal, exit); +} + + +TEST(SmiXor) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiXor(masm, &exit, 0x10, 0, 0); + TestSmiXor(masm, &exit, 0x20, 0, 1); + TestSmiXor(masm, &exit, 0x30, 1, 0); + TestSmiXor(masm, &exit, 0x40, 0, -1); + TestSmiXor(masm, &exit, 0x50, -1, 0); + TestSmiXor(masm, &exit, 0x60, -1, -1); + TestSmiXor(masm, &exit, 0x70, 1, 1); + TestSmiXor(masm, &exit, 0x80, Smi::kMinValue, Smi::kMaxValue); + TestSmiXor(masm, &exit, 0x90, Smi::kMinValue, Smi::kMinValue); + TestSmiXor(masm, &exit, 0xA0, Smi::kMinValue, -1); + TestSmiXor(masm, &exit, 0xB0, 0x5555555, 0x01234567); + TestSmiXor(masm, &exit, 0xC0, 0x5555555, 0x0fedcba9); + TestSmiXor(masm, &exit, 0xD0, Smi::kMinValue, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiNot(MacroAssembler* masm, Label* exit, int id, int x) { + int result = ~x; + __ movl(rax, Immediate(id)); + + __ Move(r8, Smi::FromInt(result)); + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + + __ SmiNot(r9, rcx); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiCompare(r11, rcx); + __ j(not_equal, exit); + + __ incq(rax); + __ SmiNot(rcx, rcx); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); +} + + +TEST(SmiNot) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiNot(masm, &exit, 0x10, 0); + TestSmiNot(masm, &exit, 0x20, 1); + TestSmiNot(masm, &exit, 0x30, -1); + TestSmiNot(masm, &exit, 0x40, 127); + TestSmiNot(masm, &exit, 0x50, 65535); + TestSmiNot(masm, &exit, 0x60, Smi::kMinValue); + TestSmiNot(masm, &exit, 0x70, Smi::kMaxValue); + TestSmiNot(masm, &exit, 0x80, 0x05555555); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiShiftLeft(MacroAssembler* masm, Label* exit, int id, int x) { + const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; + const int kNumShifts = 5; + __ movl(rax, Immediate(id)); + for (int i = 0; i < kNumShifts; i++) { + // rax == id + i * 10. + int shift = shifts[i]; + int result = x << shift; + if (Smi::IsValid(result)) { + __ Move(r8, Smi::FromInt(result)); + __ Move(rcx, Smi::FromInt(x)); + __ SmiShiftLeftConstant(r9, rcx, shift, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rcx, Smi::FromInt(x)); + __ SmiShiftLeftConstant(rcx, rcx, shift, exit); + + __ incq(rax); + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(rcx, Smi::FromInt(shift)); + __ SmiShiftLeft(r9, rdx, rcx, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(r11, Smi::FromInt(shift)); + __ SmiShiftLeft(r9, rdx, r11, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(r11, Smi::FromInt(shift)); + __ SmiShiftLeft(rdx, rdx, r11, exit); + + __ incq(rax); + __ SmiCompare(rdx, r8); + __ j(not_equal, exit); + + __ incq(rax); + } else { + // Cannot happen with long smis. + Label fail_ok; + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ SmiShiftLeftConstant(r9, rcx, shift, &fail_ok); + __ jmp(exit); + __ bind(&fail_ok); + + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(rax); + Label fail_ok2; + __ SmiShiftLeftConstant(rcx, rcx, shift, &fail_ok2); + __ jmp(exit); + __ bind(&fail_ok2); + + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(r8, Smi::FromInt(shift)); + Label fail_ok3; + __ SmiShiftLeft(r9, rcx, r8, &fail_ok3); + __ jmp(exit); + __ bind(&fail_ok3); + + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(r8, Smi::FromInt(shift)); + __ movq(rdx, r11); + Label fail_ok4; + __ SmiShiftLeft(rdx, rdx, r8, &fail_ok4); + __ jmp(exit); + __ bind(&fail_ok4); + + __ incq(rax); + __ SmiCompare(rdx, r11); + __ j(not_equal, exit); + + __ addq(rax, Immediate(3)); + } + } +} + + +TEST(SmiShiftLeft) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 3, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiShiftLeft(masm, &exit, 0x10, 0); + TestSmiShiftLeft(masm, &exit, 0x50, 1); + TestSmiShiftLeft(masm, &exit, 0x90, 127); + TestSmiShiftLeft(masm, &exit, 0xD0, 65535); + TestSmiShiftLeft(masm, &exit, 0x110, Smi::kMaxValue); + TestSmiShiftLeft(masm, &exit, 0x150, Smi::kMinValue); + TestSmiShiftLeft(masm, &exit, 0x190, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiShiftLogicalRight(MacroAssembler* masm, + Label* exit, + int id, + int x) { + const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; + const int kNumShifts = 5; + __ movl(rax, Immediate(id)); + for (int i = 0; i < kNumShifts; i++) { + int shift = shifts[i]; + intptr_t result = static_cast<unsigned int>(x) >> shift; + if (Smi::IsValid(result)) { + __ Move(r8, Smi::FromInt(result)); + __ Move(rcx, Smi::FromInt(x)); + __ SmiShiftLogicalRightConstant(r9, rcx, shift, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(rcx, Smi::FromInt(shift)); + __ SmiShiftLogicalRight(r9, rdx, rcx, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(r11, Smi::FromInt(shift)); + __ SmiShiftLogicalRight(r9, rdx, r11, exit); + + __ incq(rax); + __ SmiCompare(r9, r8); + __ j(not_equal, exit); + + __ incq(rax); + } else { + // Cannot happen with long smis. + Label fail_ok; + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ SmiShiftLogicalRightConstant(r9, rcx, shift, &fail_ok); + __ jmp(exit); + __ bind(&fail_ok); + + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(r8, Smi::FromInt(shift)); + Label fail_ok3; + __ SmiShiftLogicalRight(r9, rcx, r8, &fail_ok3); + __ jmp(exit); + __ bind(&fail_ok3); + + __ incq(rax); + __ SmiCompare(rcx, r11); + __ j(not_equal, exit); + + __ addq(rax, Immediate(3)); + } + } +} + + +TEST(SmiShiftLogicalRight) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiShiftLogicalRight(masm, &exit, 0x10, 0); + TestSmiShiftLogicalRight(masm, &exit, 0x30, 1); + TestSmiShiftLogicalRight(masm, &exit, 0x50, 127); + TestSmiShiftLogicalRight(masm, &exit, 0x70, 65535); + TestSmiShiftLogicalRight(masm, &exit, 0x90, Smi::kMaxValue); + TestSmiShiftLogicalRight(masm, &exit, 0xB0, Smi::kMinValue); + TestSmiShiftLogicalRight(masm, &exit, 0xD0, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestSmiShiftArithmeticRight(MacroAssembler* masm, + Label* exit, + int id, + int x) { + const int shifts[] = { 0, 1, 7, 24, kSmiValueSize - 1}; + const int kNumShifts = 5; + __ movl(rax, Immediate(id)); + for (int i = 0; i < kNumShifts; i++) { + int shift = shifts[i]; + // Guaranteed arithmetic shift. + int result = (x < 0) ? ~((~x) >> shift) : (x >> shift); + __ Move(r8, Smi::FromInt(result)); + __ Move(rcx, Smi::FromInt(x)); + __ SmiShiftArithmeticRightConstant(rcx, rcx, shift); + + __ SmiCompare(rcx, r8); + __ j(not_equal, exit); + + __ incq(rax); + __ Move(rdx, Smi::FromInt(x)); + __ Move(r11, Smi::FromInt(shift)); + __ SmiShiftArithmeticRight(rdx, rdx, r11); + + __ SmiCompare(rdx, r8); + __ j(not_equal, exit); + + __ incq(rax); + } +} + + +TEST(SmiShiftArithmeticRight) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestSmiShiftArithmeticRight(masm, &exit, 0x10, 0); + TestSmiShiftArithmeticRight(masm, &exit, 0x20, 1); + TestSmiShiftArithmeticRight(masm, &exit, 0x30, 127); + TestSmiShiftArithmeticRight(masm, &exit, 0x40, 65535); + TestSmiShiftArithmeticRight(masm, &exit, 0x50, Smi::kMaxValue); + TestSmiShiftArithmeticRight(masm, &exit, 0x60, Smi::kMinValue); + TestSmiShiftArithmeticRight(masm, &exit, 0x70, -1); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ ret(0); + + CodeDesc desc; + masm->GetCode(&desc); + // Call the function from C++. + int result = FUNCTION_CAST<F0>(buffer)(); + CHECK_EQ(0, result); +} + + +void TestPositiveSmiPowerUp(MacroAssembler* masm, Label* exit, int id, int x) { + ASSERT(x >= 0); + int powers[] = { 0, 1, 2, 3, 8, 16, 24, 31 }; + int power_count = 8; + __ movl(rax, Immediate(id)); + for (int i = 0; i < power_count; i++) { + int power = powers[i]; + intptr_t result = static_cast<intptr_t>(x) << power; + __ Set(r8, result); + __ Move(rcx, Smi::FromInt(x)); + __ movq(r11, rcx); + __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rcx, power); + __ SmiCompare(rdx, r8); + __ j(not_equal, exit); + __ incq(rax); + __ SmiCompare(r11, rcx); // rcx unchanged. + __ j(not_equal, exit); + __ incq(rax); + __ PositiveSmiTimesPowerOfTwoToInteger64(rcx, rcx, power); + __ SmiCompare(rdx, r8); + __ j(not_equal, exit); + __ incq(rax); + } +} + + +TEST(PositiveSmiTimesPowerOfTwoToInteger64) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = + static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize * 2, + &actual_size, + true)); + CHECK(buffer); + HandleScope handles; + MacroAssembler assembler(buffer, actual_size); + + MacroAssembler* masm = &assembler; + masm->set_allow_stub_calls(false); + Label exit; + + TestPositiveSmiPowerUp(masm, &exit, 0x20, 0); + TestPositiveSmiPowerUp(masm, &exit, 0x40, 1); + TestPositiveSmiPowerUp(masm, &exit, 0x60, 127); + TestPositiveSmiPowerUp(masm, &exit, 0x80, 128); + TestPositiveSmiPowerUp(masm, &exit, 0xA0, 255); + TestPositiveSmiPowerUp(masm, &exit, 0xC0, 256); + TestPositiveSmiPowerUp(masm, &exit, 0x100, 65535); + TestPositiveSmiPowerUp(masm, &exit, 0x120, 65536); + TestPositiveSmiPowerUp(masm, &exit, 0x140, Smi::kMaxValue); + + __ xor_(rax, rax); // Success. + __ bind(&exit); + __ 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/mjsunit/compiler/literals-assignment.js b/deps/v8/test/mjsunit/compiler/literals-assignment.js new file mode 100644 index 0000000000..932bfa7f10 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/literals-assignment.js @@ -0,0 +1,71 @@ +// 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. + +// Tests for simple assignments and literals inside an anonymous function + +// Test simple return statement. +assertEquals(8, eval("(function() { return 8; })()")); + +// Test simple assignment +var code = "(function() {\ + var a;\ + a = 8;\ + return a;\ + })()"; +assertEquals(8, eval(code)); + +code = "(function() {\ + var x;\ + x = 'abc';\ + return x;\ + })()"; +assertEquals("abc", eval(code)); + +// Test assignment as an RHS expression + +code = "(function() {\ + var x, y;\ + x = y = 8;\ + return x;\ + })()"; +assertEquals(8, eval(code)); + + +code = "(function() {\ + var x, y;\ + x = y = 8;\ + return y;\ + })()"; +assertEquals(8, eval(code)); + + +code = "(function() {\ + var x,y,z;\ + return x = y = z = 8;\ + })()"; +assertEquals(8, eval(code)); + diff --git a/deps/v8/test/mjsunit/compiler/literals.js b/deps/v8/test/mjsunit/compiler/literals.js new file mode 100644 index 0000000000..e0e532fa2a --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/literals.js @@ -0,0 +1,35 @@ +// 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. + +// Test simple literals. +assertEquals(8, eval("8")); + +assertEquals(null, eval("null")); + +assertEquals("abc", eval("'abc'")); + +assertEquals(8, eval("6;'abc';8")); diff --git a/deps/v8/test/mjsunit/debug-backtrace.js b/deps/v8/test/mjsunit/debug-backtrace.js index 0c200aee3e..d15b2d2619 100644 --- a/deps/v8/test/mjsunit/debug-backtrace.js +++ b/deps/v8/test/mjsunit/debug-backtrace.js @@ -69,6 +69,11 @@ ParsedResponse.prototype.body = function() { } +ParsedResponse.prototype.running = function() { + return this.response_.running; +} + + ParsedResponse.prototype.lookup = function(handle) { return this.refs_[handle]; } @@ -88,8 +93,9 @@ function listener(event, exec_state, event_data, data) { var frame; var source; - // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp; + // New copy of debug command processor paused state. + dcp = exec_state.debugCommandProcessor(false); // Get the backtrace. var json; @@ -114,6 +120,7 @@ function listener(event, exec_state, event_data, data) { assertEquals("g", response.lookup(frames[2].func.ref).name); assertEquals(3, frames[3].index); assertEquals("", response.lookup(frames[3].func.ref).name); + assertFalse(response.running(), "expected not running"); // Get backtrace with two frames. json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}' @@ -234,6 +241,17 @@ function listener(event, exec_state, event_data, data) { source = response.body(); assertEquals(Debug.findScript(f).source, source.source); + // New copy of debug command processor in running state. + dcp = exec_state.debugCommandProcessor(true); + // Get the backtrace. + json = '{"seq":0,"type":"request","command":"backtrace"}' + resp = dcp.processDebugJSONRequest(json); + response = new ParsedResponse(resp); + // It might be argueable, but we expect response to have body when + // not suspended + assertTrue(!!response.body(), "response should be null"); + assertTrue(response.running(), "expected running"); + listenerCalled = true; } } catch (e) { diff --git a/deps/v8/test/mjsunit/debug-changebreakpoint.js b/deps/v8/test/mjsunit/debug-changebreakpoint.js index 477c908136..936523a0e7 100644 --- a/deps/v8/test/mjsunit/debug-changebreakpoint.js +++ b/deps/v8/test/mjsunit/debug-changebreakpoint.js @@ -59,7 +59,7 @@ function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Test some illegal clearbreakpoint requests. var request = '{' + base_request + '}' diff --git a/deps/v8/test/mjsunit/debug-clearbreakpoint.js b/deps/v8/test/mjsunit/debug-clearbreakpoint.js index 28920c53a5..59479f2daa 100644 --- a/deps/v8/test/mjsunit/debug-clearbreakpoint.js +++ b/deps/v8/test/mjsunit/debug-clearbreakpoint.js @@ -59,7 +59,7 @@ function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Test some illegal clearbreakpoint requests. var request = '{' + base_request + '}' diff --git a/deps/v8/test/mjsunit/debug-clearbreakpointgroup.js b/deps/v8/test/mjsunit/debug-clearbreakpointgroup.js index eca9378759..aad6c3aff7 100644 --- a/deps/v8/test/mjsunit/debug-clearbreakpointgroup.js +++ b/deps/v8/test/mjsunit/debug-clearbreakpointgroup.js @@ -60,7 +60,7 @@ function listener(event, exec_state, event_data, data) { try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Clear breakpoint group 1.
testArguments(dcp, '{"groupId":1}', true);
diff --git a/deps/v8/test/mjsunit/debug-continue.js b/deps/v8/test/mjsunit/debug-continue.js index 0c11abc56e..a501aa925c 100644 --- a/deps/v8/test/mjsunit/debug-continue.js +++ b/deps/v8/test/mjsunit/debug-continue.js @@ -44,7 +44,10 @@ function safeEval(code) { } } -function testArguments(dcp, arguments, success) { +function testArguments(exec_state, arguments, success) { + // Get the debug command processor in paused state. + var dcp = exec_state.debugCommandProcessor(false); + // Generate request with the supplied arguments var request; if (arguments) { @@ -65,25 +68,23 @@ function testArguments(dcp, arguments, success) { function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { - // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); // Test simple continue request. - testArguments(dcp, void 0, true); + testArguments(exec_state, void 0, true); // Test some illegal continue requests. - testArguments(dcp, '{"stepaction":"maybe"}', false); - testArguments(dcp, '{"stepcount":-1}', false); + testArguments(exec_state, '{"stepaction":"maybe"}', false); + testArguments(exec_state, '{"stepcount":-1}', false); // Test some legal continue requests. - testArguments(dcp, '{"stepaction":"in"}', true); - testArguments(dcp, '{"stepaction":"min"}', true); - testArguments(dcp, '{"stepaction":"next"}', true); - testArguments(dcp, '{"stepaction":"out"}', true); - testArguments(dcp, '{"stepcount":1}', true); - testArguments(dcp, '{"stepcount":10}', true); - testArguments(dcp, '{"stepcount":"10"}', true); - testArguments(dcp, '{"stepaction":"next","stepcount":10}', true); + testArguments(exec_state, '{"stepaction":"in"}', true); + testArguments(exec_state, '{"stepaction":"min"}', true); + testArguments(exec_state, '{"stepaction":"next"}', true); + testArguments(exec_state, '{"stepaction":"out"}', true); + testArguments(exec_state, '{"stepcount":1}', true); + testArguments(exec_state, '{"stepcount":10}', true); + testArguments(exec_state, '{"stepcount":"10"}', true); + testArguments(exec_state, '{"stepaction":"next","stepcount":10}', true); // Indicate that all was processed. listenerComplete = true; @@ -108,6 +109,6 @@ function g() { Debug.setBreakPoint(g, 0, 0); g(); +assertFalse(exception, "exception in listener") // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete, "listener did not run to completion"); -assertFalse(exception, "exception in listener") diff --git a/deps/v8/test/mjsunit/debug-evaluate-bool-constructor.js b/deps/v8/test/mjsunit/debug-evaluate-bool-constructor.js new file mode 100644 index 0000000000..809a5ccc69 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-evaluate-bool-constructor.js @@ -0,0 +1,80 @@ +// 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.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var listenerComplete = false;
+var exception = false;
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor();
+
+ var request = {
+ seq: 0,
+ type: 'request',
+ command: 'evaluate',
+ arguments: {
+ expression: 'a',
+ frame: 0
+ }
+ };
+ request = JSON.stringify(request);
+
+ var resp = dcp.processDebugJSONRequest(request);
+ var response = JSON.parse(resp);
+ assertTrue(response.success, 'Command failed: ' + resp);
+ assertEquals('object', response.body.type);
+ assertEquals('Object', response.body.className);
+
+ // Indicate that all was processed.
+ listenerComplete = true;
+ }
+ } catch (e) {
+ exception = e
+ };
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+function callDebugger() {
+ // Add set constructor field to a non-function value.
+ var a = {constructor:true};
+ debugger;
+}
+
+callDebugger();
+
+
+// Make sure that the debug event listener vas invoked.
+assertFalse(exception, "exception in listener")
+assertTrue(listenerComplete, "listener did not run to completion");
diff --git a/deps/v8/test/mjsunit/debug-evaluate-recursive.js b/deps/v8/test/mjsunit/debug-evaluate-recursive.js index 9f037e5783..6ee391b63b 100644 --- a/deps/v8/test/mjsunit/debug-evaluate-recursive.js +++ b/deps/v8/test/mjsunit/debug-evaluate-recursive.js @@ -44,7 +44,10 @@ function safeEval(code) { } } -function testRequest(dcp, arguments, success, result) { +function testRequest(exec_state, arguments, success, result) { + // Get the debug command processor in paused state. + var dcp = exec_state.debugCommandProcessor(false); + // Generate request with the supplied arguments. var request; if (arguments) { @@ -74,23 +77,20 @@ function listener(event, exec_state, event_data, data) { assertEquals(1, exec_state.frame(0).evaluate('f()', true).value()); assertEquals(2, exec_state.frame(0).evaluate('g()', true).value()); - // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); - // Call functions with break using the JSON protocol. Tests that argument // disable_break is default true. - testRequest(dcp, '{"expression":"f()"}', true, 1); - testRequest(dcp, '{"expression":"f()","frame":0}', true, 1); - testRequest(dcp, '{"expression":"g()"}', true, 2); - testRequest(dcp, '{"expression":"g()","frame":0}', true, 2); + testRequest(exec_state, '{"expression":"f()"}', true, 1); + testRequest(exec_state, '{"expression":"f()","frame":0}', true, 1); + testRequest(exec_state, '{"expression":"g()"}', true, 2); + testRequest(exec_state, '{"expression":"g()","frame":0}', true, 2); // Call functions with break using the JSON protocol. Tests passing // argument disable_break is default true. - testRequest(dcp, '{"expression":"f()","disable_break":true}', true, 1); - testRequest(dcp, '{"expression":"f()","frame":0,"disable_break":true}', + testRequest(exec_state, '{"expression":"f()","disable_break":true}', true, 1); + testRequest(exec_state, '{"expression":"f()","frame":0,"disable_break":true}', true, 1); - testRequest(dcp, '{"expression":"g()","disable_break":true}', true, 2); - testRequest(dcp, '{"expression":"g()","frame":0,"disable_break":true}', + testRequest(exec_state, '{"expression":"g()","disable_break":true}', true, 2); + testRequest(exec_state, '{"expression":"g()","frame":0,"disable_break":true}', true, 2); // Indicate that all was processed. @@ -146,9 +146,9 @@ Debug.setBreakPoint(f, 2, 0); // Cause a debug break event. debugger; +assertFalse(exception, "exception in listener") // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete); -assertFalse(exception, "exception in listener") // Remove the debug event listener. Debug.setListener(null); @@ -161,7 +161,7 @@ Debug.setBreakPoint(f, 2, 0); debugger; +assertFalse(exception, "exception in listener") // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete); -assertFalse(exception, "exception in listener") assertEquals(2, break_count); diff --git a/deps/v8/test/mjsunit/debug-evaluate.js b/deps/v8/test/mjsunit/debug-evaluate.js index 5c5734f877..c4779072ac 100644 --- a/deps/v8/test/mjsunit/debug-evaluate.js +++ b/deps/v8/test/mjsunit/debug-evaluate.js @@ -59,14 +59,15 @@ function testRequest(dcp, arguments, success, result) { } else { assertFalse(response.success, request + ' -> ' + response.message); } - assertFalse(response.running, request + ' -> expected not running'); + assertEquals(response.running, "unspecified_running_state", + request + ' -> expected not running'); } function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Test some illegal evaluate requests. testRequest(dcp, void 0, false); @@ -112,6 +113,6 @@ a = 1; Debug.setBreakPoint(f, 2, 0); g(); +assertFalse(exception, "exception in listener") // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete, "listener did not run to completion"); -assertFalse(exception, "exception in listener") diff --git a/deps/v8/test/mjsunit/debug-handle.js b/deps/v8/test/mjsunit/debug-handle.js index c7ab76af44..98875ceb41 100644 --- a/deps/v8/test/mjsunit/debug-handle.js +++ b/deps/v8/test/mjsunit/debug-handle.js @@ -43,7 +43,10 @@ function safeEval(code) { // Send an evaluation request and return the handle of the result. -function evaluateRequest(dcp, arguments) { +function evaluateRequest(exec_state, arguments) { + // Get the debug command processor. + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); + // The base part of all evaluate requests. var base_request = '"seq":0,"type":"request","command":"evaluate"' @@ -63,7 +66,10 @@ function evaluateRequest(dcp, arguments) { // Send a lookup request and return the evaluated JSON response. -function lookupRequest(dcp, arguments, success) { +function lookupRequest(exec_state, arguments, success) { + // Get the debug command processor. + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); + // The base part of all lookup requests. var base_request = '"seq":0,"type":"request","command":"lookup"' @@ -81,7 +87,7 @@ function lookupRequest(dcp, arguments, success) { } else { assertFalse(response.success, request + ' -> ' + response.message); } - assertFalse(response.running, request + ' -> expected not running'); + assertEquals(response.running, dcp.isRunning(), request + ' -> expected not running'); return response; } @@ -90,26 +96,23 @@ function lookupRequest(dcp, arguments, success) { function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { - // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); - // Test some illegal lookup requests. - lookupRequest(dcp, void 0, false); - lookupRequest(dcp, '{"handles":["a"]}', false); - lookupRequest(dcp, '{"handles":[-1]}', false); + lookupRequest(exec_state, void 0, false); + lookupRequest(exec_state, '{"handles":["a"]}', false); + lookupRequest(exec_state, '{"handles":[-1]}', false); // Evaluate and get some handles. - var handle_o = evaluateRequest(dcp, '{"expression":"o"}'); - var handle_p = evaluateRequest(dcp, '{"expression":"p"}'); - var handle_b = evaluateRequest(dcp, '{"expression":"a"}'); - var handle_a = evaluateRequest(dcp, '{"expression":"b","frame":1}'); + var handle_o = evaluateRequest(exec_state, '{"expression":"o"}'); + var handle_p = evaluateRequest(exec_state, '{"expression":"p"}'); + var handle_b = evaluateRequest(exec_state, '{"expression":"a"}'); + var handle_a = evaluateRequest(exec_state, '{"expression":"b","frame":1}'); assertEquals(handle_o, handle_a); assertEquals(handle_a, handle_b); assertFalse(handle_o == handle_p, "o and p have he same handle"); var response; var count; - response = lookupRequest(dcp, '{"handles":[' + handle_o + ']}', true); + response = lookupRequest(exec_state, '{"handles":[' + handle_o + ']}', true); var obj = response.body[handle_o]; assertTrue(!!obj, 'Object not found: ' + handle_o); assertEquals(handle_o, obj.handle); @@ -127,20 +130,20 @@ function listener(event, exec_state, event_data, data) { } } assertEquals(2, count, 'Either "o" or "p" not found'); - response = lookupRequest(dcp, '{"handles":[' + handle_p + ']}', true); + response = lookupRequest(exec_state, '{"handles":[' + handle_p + ']}', true); obj = response.body[handle_p]; assertTrue(!!obj, 'Object not found: ' + handle_p); assertEquals(handle_p, obj.handle); // Check handles for functions on the stack. - var handle_f = evaluateRequest(dcp, '{"expression":"f"}'); - var handle_g = evaluateRequest(dcp, '{"expression":"g"}'); - var handle_caller = evaluateRequest(dcp, '{"expression":"f.caller"}'); + var handle_f = evaluateRequest(exec_state, '{"expression":"f"}'); + var handle_g = evaluateRequest(exec_state, '{"expression":"g"}'); + var handle_caller = evaluateRequest(exec_state, '{"expression":"f.caller"}'); assertFalse(handle_f == handle_g, "f and g have he same handle"); assertEquals(handle_g, handle_caller, "caller for f should be g"); - response = lookupRequest(dcp, '{"handles":[' + handle_f + ']}', true); + response = lookupRequest(exec_state, '{"handles":[' + handle_f + ']}', true); obj = response.body[handle_f]; assertEquals(handle_f, obj.handle); @@ -151,14 +154,14 @@ function listener(event, exec_state, event_data, data) { switch (obj.properties[i].name) { case 'name': var response_name; - response_name = lookupRequest(dcp, arguments, true); + response_name = lookupRequest(exec_state, arguments, true); assertEquals('string', response_name.body[ref].type); assertEquals("f", response_name.body[ref].value); count++; break; case 'length': var response_length; - response_length = lookupRequest(dcp, arguments, true); + response_length = lookupRequest(exec_state, arguments, true); assertEquals('number', response_length.body[ref].type); assertEquals(1, response_length.body[ref].value); count++; @@ -179,7 +182,7 @@ function listener(event, exec_state, event_data, data) { } var arguments = '{"handles":[' + refs.join(',') + ']}'; - response = lookupRequest(dcp, arguments, true); + response = lookupRequest(exec_state, arguments, true); count = 0; for (i in obj.properties) { var ref = obj.properties[i].ref; @@ -244,6 +247,6 @@ p.o = o; p.p = p; g(o); +assertFalse(exception, "exception in listener") // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete, "listener did not run to completion: " + exception); -assertFalse(exception, "exception in listener") diff --git a/deps/v8/test/mjsunit/debug-mirror-cache.js b/deps/v8/test/mjsunit/debug-mirror-cache.js index d15146faef..5b85306a18 100644 --- a/deps/v8/test/mjsunit/debug-mirror-cache.js +++ b/deps/v8/test/mjsunit/debug-mirror-cache.js @@ -41,7 +41,7 @@ function g() { Debug = debug.Debug listenerCallCount = 0; -listenerExceptionCount = 0; +listenerExceptions = []; function listener(event, exec_state, event_data, data) { @@ -54,8 +54,8 @@ function listener(event, exec_state, event_data, data) { assertEquals(0, debug.next_handle_, "Mirror cache not cleared"); assertEquals(0, debug.mirror_cache_.length, "Mirror cache not cleared"); - // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + // Get the debug command processor in paused state. + var dcp = exec_state.debugCommandProcessor(false); // Make a backtrace request to create some mirrors. var json; @@ -68,7 +68,7 @@ function listener(event, exec_state, event_data, data) { } } catch (e) { print(e); - listenerExceptionCount++; + listenerExceptions.push(e); }; }; @@ -79,7 +79,7 @@ Debug.setListener(listener); debugger; debugger; +assertEquals([], listenerExceptions, "Exception in listener"); // Make sure that the debug event listener vas invoked. assertEquals(2, listenerCallCount, "Listener not called"); -assertEquals(0, listenerExceptionCount, "Exception in listener"); diff --git a/deps/v8/test/mjsunit/debug-references.js b/deps/v8/test/mjsunit/debug-references.js index 1fde1ac74f..452761cf1c 100644 --- a/deps/v8/test/mjsunit/debug-references.js +++ b/deps/v8/test/mjsunit/debug-references.js @@ -66,14 +66,14 @@ function testRequest(dcp, arguments, success, count) { } else {
assertFalse(response.success, request + ' -> ' + response.message);
}
- assertFalse(response.running, request + ' -> expected not running');
+ assertEquals(response.running, dcp.isRunning(), request + ' -> expected not running');
}
function listener(event, exec_state, event_data, data) {
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test some illegal references requests.
testRequest(dcp, void 0, false);
diff --git a/deps/v8/test/mjsunit/debug-scopes.js b/deps/v8/test/mjsunit/debug-scopes.js index e87cbb7c22..af29df98cc 100644 --- a/deps/v8/test/mjsunit/debug-scopes.js +++ b/deps/v8/test/mjsunit/debug-scopes.js @@ -92,7 +92,7 @@ function CheckScopeChain(scopes, exec_state) { } // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Send a scopes request and check the result. var json; @@ -155,7 +155,7 @@ function CheckScopeContent(content, number, exec_state) { assertEquals(count, scope_size); // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Send a scope request for information on a single scope and check the // result. diff --git a/deps/v8/test/mjsunit/debug-scripts-request.js b/deps/v8/test/mjsunit/debug-scripts-request.js index 80b3bce597..41bff0e805 100644 --- a/deps/v8/test/mjsunit/debug-scripts-request.js +++ b/deps/v8/test/mjsunit/debug-scripts-request.js @@ -60,7 +60,7 @@ function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Test illegal scripts requests. testArguments(dcp, '{"types":"xx"}', false); diff --git a/deps/v8/test/mjsunit/debug-setbreakpoint.js b/deps/v8/test/mjsunit/debug-setbreakpoint.js index f8d9b157b2..08492b4ecc 100644 --- a/deps/v8/test/mjsunit/debug-setbreakpoint.js +++ b/deps/v8/test/mjsunit/debug-setbreakpoint.js @@ -69,7 +69,7 @@ function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Break) { // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor("unspecified_running_state"); // Test some illegal setbreakpoint requests. var request = '{' + base_request + '}' diff --git a/deps/v8/test/mjsunit/debug-suspend.js b/deps/v8/test/mjsunit/debug-suspend.js new file mode 100644 index 0000000000..73a2e8c24b --- /dev/null +++ b/deps/v8/test/mjsunit/debug-suspend.js @@ -0,0 +1,96 @@ +// Copyright 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. + +// Flags: --expose-debug-as debug +// Get the Debug object exposed from the debug context global object. +Debug = debug.Debug + +// Simple function which stores the last debug event. +listenerComplete = false; +exception = false; + +var base_backtrace_request = '"seq":0,"type":"request","command":"backtrace"' +var base_suspend_request = '"seq":0,"type":"request","command":"suspend"' + +function safeEval(code) { + try { + return eval('(' + code + ')'); + } catch (e) { + assertEquals(void 0, e); + return undefined; + } +} + +function testArguments(exec_state) { + // Get the debug command processor in running state. + var dcp = exec_state.debugCommandProcessor(true); + + assertTrue(dcp.isRunning()); + + var backtrace_request = '{' + base_backtrace_request + '}' + var backtrace_response = safeEval(dcp.processDebugJSONRequest(backtrace_request)); + + assertTrue(backtrace_response.success); + + assertTrue(backtrace_response.running, backtrace_request + ' -> expected running'); + + assertTrue(dcp.isRunning()); + + var suspend_request = '{' + base_suspend_request + '}' + var suspend_response = safeEval(dcp.processDebugJSONRequest(suspend_request)); + + assertTrue(suspend_response.success); + + assertFalse(suspend_response.running, suspend_request + ' -> expected not running'); + + assertFalse(dcp.isRunning()); +} + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + + // Test simple suspend request. + testArguments(exec_state); + + // Indicate that all was processed. + listenerComplete = true; + } + } catch (e) { + exception = e + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +// Stop debugger and check that suspend command changes running flag. +debugger; + +assertFalse(exception, "exception in listener") +// Make sure that the debug event listener vas invoked. +assertTrue(listenerComplete, "listener did not run to completion"); diff --git a/deps/v8/test/mjsunit/for-in.js b/deps/v8/test/mjsunit/for-in.js index dfe721dbee..e3436ff3be 100644 --- a/deps/v8/test/mjsunit/for-in.js +++ b/deps/v8/test/mjsunit/for-in.js @@ -31,21 +31,21 @@ function props(x) { return array.sort(); } -assertEquals(0, props({}).length); -assertEquals(1, props({x:1}).length); -assertEquals(2, props({x:1, y:2}).length); +assertEquals(0, props({}).length, "olen0"); +assertEquals(1, props({x:1}).length, "olen1"); +assertEquals(2, props({x:1, y:2}).length, "olen2"); -assertArrayEquals(["x"], props({x:1})); -assertArrayEquals(["x", "y"], props({x:1, y:2})); -assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3})); +assertArrayEquals(["x"], props({x:1}), "x"); +assertArrayEquals(["x", "y"], props({x:1, y:2}), "xy"); +assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3}), "xyzoom"); -assertEquals(0, props([]).length); -assertEquals(1, props([1]).length); -assertEquals(2, props([1,2]).length); +assertEquals(0, props([]).length, "alen0"); +assertEquals(1, props([1]).length, "alen1"); +assertEquals(2, props([1,2]).length, "alen2"); -assertArrayEquals(["0"], props([1])); -assertArrayEquals(["0", "1"], props([1,2])); -assertArrayEquals(["0", "1", "2"], props([1,2,3])); +assertArrayEquals(["0"], props([1]), "0"); +assertArrayEquals(["0", "1"], props([1,2]), "01"); +assertArrayEquals(["0", "1", "2"], props([1,2,3]), "012"); var o = {}; var a = []; @@ -54,33 +54,33 @@ for (var i = 0x0020; i < 0x01ff; i+=2) { a.push(s); o[s] = i; } -assertArrayEquals(a, props(o)); +assertArrayEquals(a, props(o), "charcodes"); var a = []; -assertEquals(0, props(a).length); +assertEquals(0, props(a).length, "proplen0"); a[Math.pow(2,30)-1] = 0; -assertEquals(1, props(a).length); +assertEquals(1, props(a).length, "proplen1"); a[Math.pow(2,31)-1] = 0; -assertEquals(2, props(a).length); +assertEquals(2, props(a).length, "proplen2"); a[1] = 0; -assertEquals(3, props(a).length); +assertEquals(3, props(a).length, "proplen3"); for (var hest = 'hest' in {}) { } -assertEquals('hest', hest); +assertEquals('hest', hest, "empty-no-override"); var result = ''; for (var p in {a : [0], b : 1}) { result += p; } -assertEquals('ab', result); +assertEquals('ab', result, "ab"); var result = ''; for (var p in {a : {v:1}, b : 1}) { result += p; } -assertEquals('ab', result); +assertEquals('ab', result, "ab-nodeep"); var result = ''; for (var p in { get a() {}, b : 1}) { result += p; } -assertEquals('ab', result); +assertEquals('ab', result, "abget"); var result = ''; for (var p in { get a() {}, set a(x) {}, b : 1}) { result += p; } -assertEquals('ab', result); +assertEquals('ab', result, "abgetset"); diff --git a/deps/v8/test/mjsunit/regress/regress-1081309.js b/deps/v8/test/mjsunit/regress/regress-1081309.js index a771ac0448..009ede1516 100644 --- a/deps/v8/test/mjsunit/regress/regress-1081309.js +++ b/deps/v8/test/mjsunit/regress/regress-1081309.js @@ -69,7 +69,7 @@ function listener(event, exec_state, event_data, data) { // 0: [anonymous] // Get the debug command processor. - var dcp = exec_state.debugCommandProcessor(); + var dcp = exec_state.debugCommandProcessor(false); // Get the backtrace. var json; @@ -105,6 +105,6 @@ try { // Ignore the exception "Cannot call method 'x' of undefined" } +assertFalse(exception, "exception in listener", exception) // Make sure that the debug event listener vas invoked. assertTrue(listenerCalled, "listener not called"); -assertFalse(exception, "exception in listener", exception) diff --git a/deps/v8/test/mjsunit/regress/regress-1199401.js b/deps/v8/test/mjsunit/regress/regress-1199401.js index 792faea982..cc7985d820 100644 --- a/deps/v8/test/mjsunit/regress/regress-1199401.js +++ b/deps/v8/test/mjsunit/regress/regress-1199401.js @@ -27,35 +27,49 @@ // Ensure that we can correctly change the sign of the most negative smi. -assertEquals(1073741824, -1073741824 * -1); -assertEquals(1073741824, -1073741824 / -1); -assertEquals(1073741824, -(-1073741824)); -assertEquals(1073741824, 0 - (-1073741824)); - -var min_smi = -1073741824; - -assertEquals(1073741824, min_smi * -1); -assertEquals(1073741824, min_smi / -1); -assertEquals(1073741824, -min_smi); -assertEquals(1073741824, 0 - min_smi); - -var zero = 0; -var minus_one = -1; - -assertEquals(1073741824, min_smi * minus_one); -assertEquals(1073741824, min_smi / minus_one); -assertEquals(1073741824, -min_smi); -assertEquals(1073741824, zero - min_smi); - -assertEquals(1073741824, -1073741824 * minus_one); -assertEquals(1073741824, -1073741824 / minus_one); -assertEquals(1073741824, -(-1073741824)); -assertEquals(1073741824, zero - (-1073741824)); - -var half_min_smi = -(1<<15); -var half_max_smi = (1<<15); - -assertEquals(1073741824, -half_min_smi * half_max_smi); -assertEquals(1073741824, half_min_smi * -half_max_smi); -assertEquals(1073741824, half_max_smi * -half_min_smi); -assertEquals(1073741824, -half_max_smi * half_min_smi); +// Possible Smi ranges. +var ranges = [{min: -1073741824, max: 1073741823, bits: 31}, + {min: -2147483648, max: 2147483647, bits: 32}]; + +for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + var min_smi = range.min; + var max_smi = range.max; + var bits = range.bits; + var name = bits + "-bit"; + + var result = max_smi + 1; + + // Min smi as literal + assertEquals(result, eval(min_smi + " * -1"), name + "-litconmult"); + assertEquals(result, eval(min_smi + " / -1"), name + "-litcondiv"); + assertEquals(result, eval("-(" + min_smi + ")"), name + "-litneg"); + assertEquals(result, eval("0 - (" + min_smi + ")")), name + "-conlitsub"; + + // As variable: + assertEquals(result, min_smi * -1, name + "-varconmult"); + assertEquals(result, min_smi / -1, name + "-varcondiv"); + assertEquals(result, -min_smi, name + "-varneg"); + assertEquals(result, 0 - min_smi, name + "-convarsub"); + + // Only variables: + var zero = 0; + var minus_one = -1; + + assertEquals(result, min_smi * minus_one, name + "-varvarmult"); + assertEquals(result, min_smi / minus_one, name + "-varvardiv"); + assertEquals(result, zero - min_smi, name + "-varvarsub"); + + // Constants as variables + assertEquals(result, eval(min_smi + " * minus_one"), name + "-litvarmult"); + assertEquals(result, eval(min_smi + " / minus_one"), name + "-litvarmdiv"); + assertEquals(result, eval("0 - (" + min_smi + ")"), name + "-varlitsub"); + + var half_min_smi = -(1 << (bits >> 1)); + var half_max_smi = 1 << ((bits - 1) >> 1); + + assertEquals(max_smi + 1, -half_min_smi * half_max_smi, name + "-half1"); + assertEquals(max_smi + 1, half_min_smi * -half_max_smi, name + "-half2"); + assertEquals(max_smi + 1, half_max_smi * -half_min_smi, name + "-half3"); + assertEquals(max_smi + 1, -half_max_smi * half_min_smi, name + "-half4"); +} diff --git a/deps/v8/test/mjsunit/smi-negative-zero.js b/deps/v8/test/mjsunit/smi-negative-zero.js index 719ee49f01..690644317e 100644 --- a/deps/v8/test/mjsunit/smi-negative-zero.js +++ b/deps/v8/test/mjsunit/smi-negative-zero.js @@ -37,64 +37,64 @@ var minus_four = -4; // variable op variable -assertEquals(one / (-zero), -Infinity, "one / -0 I"); +assertEquals(-Infinity, one / (-zero), "one / -0 I"); -assertEquals(one / (zero * minus_one), -Infinity, "one / -1"); -assertEquals(one / (minus_one * zero), -Infinity, "one / -0 II"); -assertEquals(one / (zero * zero), Infinity, "one / 0 I"); -assertEquals(one / (minus_one * minus_one), 1, "one / 1"); +assertEquals(-Infinity, one / (zero * minus_one), "one / -1"); +assertEquals(-Infinity, one / (minus_one * zero), "one / -0 II"); +assertEquals(Infinity, one / (zero * zero), "one / 0 I"); +assertEquals(1, one / (minus_one * minus_one), "one / 1"); -assertEquals(one / (zero / minus_one), -Infinity, "one / -0 III"); -assertEquals(one / (zero / one), Infinity, "one / 0 II"); +assertEquals(-Infinity, one / (zero / minus_one), "one / -0 III"); +assertEquals(Infinity, one / (zero / one), "one / 0 II"); -assertEquals(one / (minus_four % two), -Infinity, "foo1"); -assertEquals(one / (minus_four % minus_two), -Infinity, "foo2"); -assertEquals(one / (four % two), Infinity, "foo3"); -assertEquals(one / (four % minus_two), Infinity, "foo4"); +assertEquals(-Infinity, one / (minus_four % two), "foo1"); +assertEquals(-Infinity, one / (minus_four % minus_two), "foo2"); +assertEquals(Infinity, one / (four % two), "foo3"); +assertEquals(Infinity, one / (four % minus_two), "foo4"); // literal op variable -assertEquals(one / (0 * minus_one), -Infinity, "bar1"); -assertEquals(one / (-1 * zero), -Infinity, "bar2"); -assertEquals(one / (0 * zero), Infinity, "bar3"); -assertEquals(one / (-1 * minus_one), 1, "bar4"); +assertEquals(-Infinity, one / (0 * minus_one), "bar1"); +assertEquals(-Infinity, one / (-1 * zero), "bar2"); +assertEquals(Infinity, one / (0 * zero), "bar3"); +assertEquals(1, one / (-1 * minus_one), "bar4"); -assertEquals(one / (0 / minus_one), -Infinity, "baz1"); -assertEquals(one / (0 / one), Infinity, "baz2"); +assertEquals(-Infinity, one / (0 / minus_one), "baz1"); +assertEquals(Infinity, one / (0 / one), "baz2"); -assertEquals(one / (-4 % two), -Infinity, "baz3"); -assertEquals(one / (-4 % minus_two), -Infinity, "baz4"); -assertEquals(one / (4 % two), Infinity, "baz5"); -assertEquals(one / (4 % minus_two), Infinity, "baz6"); +assertEquals(-Infinity, one / (-4 % two), "baz3"); +assertEquals(-Infinity, one / (-4 % minus_two), "baz4"); +assertEquals(Infinity, one / (4 % two), "baz5"); +assertEquals(Infinity, one / (4 % minus_two), "baz6"); // variable op literal -assertEquals(one / (zero * -1), -Infinity, "fizz1"); -assertEquals(one / (minus_one * 0), -Infinity, "fizz2"); -assertEquals(one / (zero * 0), Infinity, "fizz3"); -assertEquals(one / (minus_one * -1), 1, "fizz4"); +assertEquals(-Infinity, one / (zero * -1), "fizz1"); +assertEquals(-Infinity, one / (minus_one * 0), "fizz2"); +assertEquals(Infinity, one / (zero * 0), "fizz3"); +assertEquals(1, one / (minus_one * -1), "fizz4"); -assertEquals(one / (zero / -1), -Infinity, "buzz1"); -assertEquals(one / (zero / 1), Infinity, "buzz2"); +assertEquals(-Infinity, one / (zero / -1), "buzz1"); +assertEquals(Infinity, one / (zero / 1), "buzz2"); -assertEquals(one / (minus_four % 2), -Infinity, "buzz3"); -assertEquals(one / (minus_four % -2), -Infinity, "buzz4"); -assertEquals(one / (four % 2), Infinity, "buzz5"); -assertEquals(one / (four % -2), Infinity, "buzz6"); +assertEquals(-Infinity, one / (minus_four % 2), "buzz3"); +assertEquals(-Infinity, one / (minus_four % -2), "buzz4"); +assertEquals(Infinity, one / (four % 2), "buzz5"); +assertEquals(Infinity, one / (four % -2), "buzz6"); // literal op literal -assertEquals(one / (-0), -Infinity, "fisk1"); +assertEquals(-Infinity, one / (-0), "fisk1"); -assertEquals(one / (0 * -1), -Infinity, "fisk2"); -assertEquals(one / (-1 * 0), -Infinity, "fisk3"); -assertEquals(one / (0 * 0), Infinity, "fisk4"); -assertEquals(one / (-1 * -1), 1, "fisk5"); +assertEquals(-Infinity, one / (0 * -1), "fisk2"); +assertEquals(-Infinity, one / (-1 * 0), "fisk3"); +assertEquals(Infinity, one / (0 * 0), "fisk4"); +assertEquals(1, one / (-1 * -1), "fisk5"); -assertEquals(one / (0 / -1), -Infinity, "hest1"); -assertEquals(one / (0 / 1), Infinity, "hest2"); +assertEquals(-Infinity, one / (0 / -1), "hest1"); +assertEquals(Infinity, one / (0 / 1), "hest2"); -assertEquals(one / (-4 % 2), -Infinity, "fiskhest1"); -assertEquals(one / (-4 % -2), -Infinity, "fiskhest2"); -assertEquals(one / (4 % 2), Infinity, "fiskhest3"); -assertEquals(one / (4 % -2), Infinity, "fiskhest4"); +assertEquals(-Infinity, one / (-4 % 2), "fiskhest1"); +assertEquals(-Infinity, one / (-4 % -2), "fiskhest2"); +assertEquals(Infinity, one / (4 % 2), "fiskhest3"); +assertEquals(Infinity, one / (4 % -2), "fiskhest4"); diff --git a/deps/v8/test/mjsunit/testcfg.py b/deps/v8/test/mjsunit/testcfg.py index e3f3fcd940..49064b12fe 100644 --- a/deps/v8/test/mjsunit/testcfg.py +++ b/deps/v8/test/mjsunit/testcfg.py @@ -114,7 +114,8 @@ class MjsunitTestConfiguration(test.TestConfiguration): bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))] third_party = [current_path + ['third_party', t] for t in self.Ls(join(self.root, 'third_party'))] tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))] - all_tests = mjsunit + regress + bugs + third_party + tools + compiler = [current_path + ['compiler', t] for t in self.Ls(join(self.root, 'compiler'))] + all_tests = mjsunit + regress + bugs + third_party + tools + compiler result = [] for test in all_tests: if self.Contains(path, test): diff --git a/deps/v8/test/mjsunit/third_party/array-isarray.js b/deps/v8/test/mjsunit/third_party/array-isarray.js new file mode 100644 index 0000000000..0fc42a3f27 --- /dev/null +++ b/deps/v8/test/mjsunit/third_party/array-isarray.js @@ -0,0 +1,48 @@ +// Copyright (c) 2009 Apple Computer, Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. 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. +// +// 3. Neither the name of the copyright holder(s) nor the names of any +// 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. + +// Based on LayoutTests/fast/js/resources/Array-isArray.js + +assertTrue(Array.isArray([])); +assertTrue(Array.isArray(new Array)); +assertTrue(Array.isArray(Array())); +assertTrue(Array.isArray('abc'.match(/(a)*/g))); +assertFalse((function(){ return Array.isArray(arguments); })()); +assertFalse(Array.isArray()); +assertFalse(Array.isArray(null)); +assertFalse(Array.isArray(undefined)); +assertFalse(Array.isArray(true)); +assertFalse(Array.isArray(false)); +assertFalse(Array.isArray('a string')); +assertFalse(Array.isArray({})); +assertFalse(Array.isArray({length: 5})); +assertFalse(Array.isArray({__proto__: Array.prototype, length:1, 0:1, 1:2})); + diff --git a/deps/v8/test/mjsunit/third_party/string-trim.js b/deps/v8/test/mjsunit/third_party/string-trim.js new file mode 100644 index 0000000000..234dff6dcd --- /dev/null +++ b/deps/v8/test/mjsunit/third_party/string-trim.js @@ -0,0 +1,107 @@ +// Copyright (c) 2009 Apple Computer, Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. 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. +// +// 3. Neither the name of the copyright holder(s) nor the names of any +// 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. + +// Based on LayoutTests/fast/js/script-tests/string-trim.js + +// References to trim(), trimLeft() and trimRight() functions for +// testing Function's *.call() and *.apply() methods. + +var trim = String.prototype.trim; +var trimLeft = String.prototype.trimLeft; +var trimRight = String.prototype.trimRight; + +var testString = 'foo bar'; +var trimString = ''; +var leftTrimString = ''; +var rightTrimString = ''; +var wsString = ''; + +var whitespace = [ + {s : '\u0009', t : 'HORIZONTAL TAB'}, + {s : '\u000A', t : 'LINE FEED OR NEW LINE'}, + {s : '\u000B', t : 'VERTICAL TAB'}, + {s : '\u000C', t : 'FORMFEED'}, + {s : '\u000D', t : 'CARRIAGE RETURN'}, + {s : '\u0020', t : 'SPACE'}, + {s : '\u00A0', t : 'NO-BREAK SPACE'}, + {s : '\u2000', t : 'EN QUAD'}, + {s : '\u2001', t : 'EM QUAD'}, + {s : '\u2002', t : 'EN SPACE'}, + {s : '\u2003', t : 'EM SPACE'}, + {s : '\u2004', t : 'THREE-PER-EM SPACE'}, + {s : '\u2005', t : 'FOUR-PER-EM SPACE'}, + {s : '\u2006', t : 'SIX-PER-EM SPACE'}, + {s : '\u2007', t : 'FIGURE SPACE'}, + {s : '\u2008', t : 'PUNCTUATION SPACE'}, + {s : '\u2009', t : 'THIN SPACE'}, + {s : '\u200A', t : 'HAIR SPACE'}, + {s : '\u3000', t : 'IDEOGRAPHIC SPACE'}, + {s : '\u2028', t : 'LINE SEPARATOR'}, + {s : '\u2029', t : 'PARAGRAPH SEPARATOR'}, + {s : '\u200B', t : 'ZERO WIDTH SPACE (category Cf)'} +]; + +for (var i = 0; i < whitespace.length; i++) { + assertEquals(whitespace[i].s.trim(), ''); + assertEquals(whitespace[i].s.trimLeft(), ''); + assertEquals(whitespace[i].s.trimRight(), ''); + wsString += whitespace[i].s; +} + +trimString = wsString + testString + wsString; +leftTrimString = testString + wsString; // Trimmed from the left. +rightTrimString = wsString + testString; // Trimmed from the right. + +assertEquals(wsString.trim(), ''); +assertEquals(wsString.trimLeft(), ''); +assertEquals(wsString.trimRight(), ''); + +assertEquals(trimString.trim(), testString); +assertEquals(trimString.trimLeft(), leftTrimString); +assertEquals(trimString.trimRight(), rightTrimString); + +assertEquals(leftTrimString.trim(), testString); +assertEquals(leftTrimString.trimLeft(), leftTrimString); +assertEquals(leftTrimString.trimRight(), testString); + +assertEquals(rightTrimString.trim(), testString); +assertEquals(rightTrimString.trimLeft(), testString); +assertEquals(rightTrimString.trimRight(), rightTrimString); + +var testValues = [0, Infinity, NaN, true, false, ({}), ['an','array'], + ({toString:function(){return 'wibble'}}) +]; + +for (var i = 0; i < testValues.length; i++) { + assertEquals(trim.call(testValues[i]), String(testValues[i])); + assertEquals(trimLeft.call(testValues[i]), String(testValues[i])); + assertEquals(trimRight.call(testValues[i]), String(testValues[i])); +} |