Update V8 to r4730 as required by WebKit r60469
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index 2cf0b12..876c104 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -71,6 +71,7 @@
'test-strings.cc',
'test-threads.cc',
'test-thread-termination.cc',
+ 'test-unbound-queue.cc',
'test-utils.cc',
'test-version.cc'
],
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index ea9e6e1..46eaccd 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -76,6 +76,11 @@
}
+static void ExpectTrue(const char* code) {
+ ExpectBoolean(code, true);
+}
+
+
static void ExpectObject(const char* code, Local<Value> expected) {
Local<Value> result = CompileRun(code);
CHECK(result->Equals(expected));
@@ -2506,7 +2511,7 @@
// Uses getOwnPropertyDescriptor to check the configurable status
Local<Script> script_desc
- = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
+ = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
"obj, 'x');"
"prop.configurable;"));
Local<Value> result = script_desc->Run();
@@ -2592,8 +2597,167 @@
}
+static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
+ char const* name) {
+ return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
+}
+THREADED_TEST(DefineAPIAccessorOnObject) {
+ v8::HandleScope scope;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ LocalContext context;
+
+ context->Global()->Set(v8_str("obj1"), templ->NewInstance());
+ CompileRun("var obj2 = {};");
+
+ CHECK(CompileRun("obj1.x")->IsUndefined());
+ CHECK(CompileRun("obj2.x")->IsUndefined());
+
+ CHECK(GetGlobalProperty(&context, "obj1")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+
+ ExpectString("obj1.x", "x");
+ CHECK(CompileRun("obj2.x")->IsUndefined());
+
+ CHECK(GetGlobalProperty(&context, "obj2")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+
+ ExpectString("obj1.x", "x");
+ ExpectString("obj2.x", "x");
+
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
+
+ CompileRun("Object.defineProperty(obj1, 'x',"
+ "{ get: function() { return 'y'; }, configurable: true })");
+
+ ExpectString("obj1.x", "y");
+ ExpectString("obj2.x", "x");
+
+ CompileRun("Object.defineProperty(obj2, 'x',"
+ "{ get: function() { return 'y'; }, configurable: true })");
+
+ ExpectString("obj1.x", "y");
+ ExpectString("obj2.x", "y");
+
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
+
+ CHECK(GetGlobalProperty(&context, "obj1")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+ CHECK(GetGlobalProperty(&context, "obj2")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+
+ ExpectString("obj1.x", "x");
+ ExpectString("obj2.x", "x");
+
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
+ ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
+
+ // Define getters/setters, but now make them not configurable.
+ CompileRun("Object.defineProperty(obj1, 'x',"
+ "{ get: function() { return 'z'; }, configurable: false })");
+ CompileRun("Object.defineProperty(obj2, 'x',"
+ "{ get: function() { return 'z'; }, configurable: false })");
+
+ ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
+ ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
+
+ ExpectString("obj1.x", "z");
+ ExpectString("obj2.x", "z");
+
+ CHECK(!GetGlobalProperty(&context, "obj1")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+ CHECK(!GetGlobalProperty(&context, "obj2")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+
+ ExpectString("obj1.x", "z");
+ ExpectString("obj2.x", "z");
+}
+
+
+THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
+ v8::HandleScope scope;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ LocalContext context;
+
+ context->Global()->Set(v8_str("obj1"), templ->NewInstance());
+ CompileRun("var obj2 = {};");
+
+ CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
+ v8_str("x"),
+ GetXValue, NULL,
+ v8_str("donut"), v8::DEFAULT, v8::DontDelete));
+ CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
+ v8_str("x"),
+ GetXValue, NULL,
+ v8_str("donut"), v8::DEFAULT, v8::DontDelete));
+
+ ExpectString("obj1.x", "x");
+ ExpectString("obj2.x", "x");
+
+ ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
+ ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
+
+ CHECK(!GetGlobalProperty(&context, "obj1")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+ CHECK(!GetGlobalProperty(&context, "obj2")->
+ SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
+
+ {
+ v8::TryCatch try_catch;
+ CompileRun("Object.defineProperty(obj1, 'x',"
+ "{get: function() { return 'func'; }})");
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value(try_catch.Exception());
+ CHECK_EQ(*exception_value,
+ "TypeError: Cannot redefine property: defineProperty");
+ }
+ {
+ v8::TryCatch try_catch;
+ CompileRun("Object.defineProperty(obj2, 'x',"
+ "{get: function() { return 'func'; }})");
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value(try_catch.Exception());
+ CHECK_EQ(*exception_value,
+ "TypeError: Cannot redefine property: defineProperty");
+ }
+}
+
+
+static v8::Handle<Value> Get239Value(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ CHECK_EQ(info.Data(), v8_str("donut"));
+ CHECK_EQ(name, v8_str("239"));
+ return name;
+}
+
+
+THREADED_TEST(ElementAPIAccessor) {
+ v8::HandleScope scope;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ LocalContext context;
+
+ context->Global()->Set(v8_str("obj1"), templ->NewInstance());
+ CompileRun("var obj2 = {};");
+
+ CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
+ v8_str("239"),
+ Get239Value, NULL,
+ v8_str("donut")));
+ CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
+ v8_str("239"),
+ Get239Value, NULL,
+ v8_str("donut")));
+
+ ExpectString("obj1[239]", "239");
+ ExpectString("obj2[239]", "239");
+ ExpectString("obj1['239']", "239");
+ ExpectString("obj2['239']", "239");
+}
+
v8::Persistent<Value> xValue;
@@ -8003,8 +8167,8 @@
// TODO(155): This test would break without the initialization of V8. This is
// a workaround for now to make this test not fail.
v8::V8::Initialize();
- const char *script = "function foo(a) { return a+1; }";
- v8::ScriptData *sd =
+ const char* script = "function foo(a) { return a+1; }";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK_NE(sd->Length(), 0);
CHECK_NE(sd->Data(), NULL);
@@ -8015,8 +8179,8 @@
TEST(PreCompileWithError) {
v8::V8::Initialize();
- const char *script = "function foo(a) { return 1 * * 2; }";
- v8::ScriptData *sd =
+ const char* script = "function foo(a) { return 1 * * 2; }";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(sd->HasError());
delete sd;
@@ -8025,14 +8189,53 @@
TEST(Regress31661) {
v8::V8::Initialize();
- const char *script = " The Definintive Guide";
- v8::ScriptData *sd =
+ const char* script = " The Definintive Guide";
+ v8::ScriptData* sd =
v8::ScriptData::PreCompile(script, i::StrLength(script));
CHECK(sd->HasError());
delete sd;
}
+// Tests that ScriptData can be serialized and deserialized.
+TEST(PreCompileSerialization) {
+ v8::V8::Initialize();
+ const char* script = "function foo(a) { return a+1; }";
+ v8::ScriptData* sd =
+ v8::ScriptData::PreCompile(script, i::StrLength(script));
+
+ // Serialize.
+ int serialized_data_length = sd->Length();
+ char* serialized_data = i::NewArray<char>(serialized_data_length);
+ memcpy(serialized_data, sd->Data(), serialized_data_length);
+
+ // Deserialize.
+ v8::ScriptData* deserialized_sd =
+ v8::ScriptData::New(serialized_data, serialized_data_length);
+
+ // Verify that the original is the same as the deserialized.
+ CHECK_EQ(sd->Length(), deserialized_sd->Length());
+ CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
+ CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
+
+ delete sd;
+ delete deserialized_sd;
+}
+
+
+// Attempts to deserialize bad data.
+TEST(PreCompileDeserializationError) {
+ v8::V8::Initialize();
+ const char* data = "DONT CARE";
+ int invalid_size = 3;
+ v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
+
+ CHECK_EQ(0, sd->Length());
+
+ delete sd;
+}
+
+
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can
diff --git a/test/cctest/test-circular-queue.cc b/test/cctest/test-circular-queue.cc
index 3fa49bf..ce9a42e 100644
--- a/test/cctest/test-circular-queue.cc
+++ b/test/cctest/test-circular-queue.cc
@@ -1,6 +1,6 @@
// Copyright 2010 the V8 project authors. All rights reserved.
//
-// Tests of circular queues.
+// Tests of the circular queue.
#include "v8.h"
#include "circular-queue-inl.h"
@@ -8,53 +8,9 @@
namespace i = v8::internal;
-using i::CircularQueue;
using i::SamplingCircularQueue;
-TEST(SingleRecordCircularQueue) {
- typedef int Record;
- CircularQueue<Record> cq(sizeof(Record) * 2);
- CHECK(cq.IsEmpty());
- cq.Enqueue(1);
- CHECK(!cq.IsEmpty());
- Record rec = 0;
- cq.Dequeue(&rec);
- CHECK_EQ(1, rec);
- CHECK(cq.IsEmpty());
-}
-
-
-TEST(MultipleRecordsCircularQueue) {
- typedef int Record;
- const int kQueueSize = 10;
- CircularQueue<Record> cq(sizeof(Record) * (kQueueSize + 1));
- CHECK(cq.IsEmpty());
- cq.Enqueue(1);
- CHECK(!cq.IsEmpty());
- for (int i = 2; i <= 5; ++i) {
- cq.Enqueue(i);
- CHECK(!cq.IsEmpty());
- }
- Record rec = 0;
- for (int i = 1; i <= 4; ++i) {
- CHECK(!cq.IsEmpty());
- cq.Dequeue(&rec);
- CHECK_EQ(i, rec);
- }
- for (int i = 6; i <= 12; ++i) {
- cq.Enqueue(i);
- CHECK(!cq.IsEmpty());
- }
- for (int i = 5; i <= 12; ++i) {
- CHECK(!cq.IsEmpty());
- cq.Dequeue(&rec);
- CHECK_EQ(i, rec);
- }
- CHECK(cq.IsEmpty());
-}
-
-
TEST(SamplingCircularQueue) {
typedef SamplingCircularQueue::Cell Record;
const int kRecordsPerChunk = 4;
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 6133cdb..f587fc8 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -114,7 +114,8 @@
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
processor.CodeDeleteEvent(ToAddress(0x1600));
- processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000));
+ processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
+ CodeEntry::kNoSecurityToken);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
@@ -176,7 +177,8 @@
processor.Stop();
processor.Join();
- CpuProfile* profile = profiles.StopProfiling("", 1);
+ CpuProfile* profile =
+ profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
// Check call trees.
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index d90be8e..4b4c950 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -6196,7 +6196,28 @@
v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
CHECK_EQ(*context1, *context2);
- // Make sure debugger is unloaded before running other tests.
- v8::internal::ForceUnloadDebugger();
+}
+
+
+static v8::Handle<v8::Value> expected_callback_data;
+static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
+ CHECK(details.GetEventContext() == expected_context);
+ CHECK_EQ(expected_callback_data, details.GetCallbackData());
+}
+
+// Check that event details contain context where debug event occured.
+TEST(DebugEventContext) {
+ v8::HandleScope scope;
+ expected_callback_data = v8::Int32::New(2010);
+ v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
+ expected_callback_data);
+ expected_context = v8::Context::New();
+ v8::Context::Scope context_scope(expected_context);
+ v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
+ expected_context.Dispose();
+ expected_context.Clear();
+ v8::Debug::SetDebugEventListener(NULL);
+ expected_context_data = v8::Handle<v8::Value>();
CheckDebuggerUnloaded();
}
+
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index 02e64b4..f94cd45 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -237,6 +237,7 @@
__ cld();
__ rep_movs();
__ rep_stos();
+ __ stos();
__ sub(edx, Operand(ebx, ecx, times_4, 10000));
__ sub(edx, Operand(ebx));
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 4d9d759..6da1a75 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -66,28 +66,6 @@
}
-static void CheckRetAddrIsInFunction(const char* func_name,
- Address ret_addr,
- Address func_start_addr,
- unsigned int func_len) {
- printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n",
- func_name, func_start_addr, ret_addr, func_start_addr + func_len);
- CHECK_GE(ret_addr, func_start_addr);
- CHECK_GE(func_start_addr + func_len, ret_addr);
-}
-
-
-static void CheckRetAddrIsInJSFunction(const char* func_name,
- Address ret_addr,
- Handle<JSFunction> func) {
- v8::internal::Code* func_code = func->code();
- CheckRetAddrIsInFunction(
- func_name, ret_addr,
- func_code->instruction_start(),
- func_code->ExecutableSize());
-}
-
-
// --- T r a c e E x t e n s i o n ---
class TraceExtension : public v8::Extension {
@@ -209,11 +187,16 @@
}
-static void CheckRetAddrIsInJSFunction(const char* func_name,
- Address ret_addr) {
- CheckRetAddrIsInJSFunction(func_name,
- ret_addr,
- GetGlobalJSFunction(func_name));
+static void CheckObjectIsJSFunction(const char* func_name,
+ Address addr) {
+ i::Object* obj = reinterpret_cast<i::Object*>(addr);
+ CHECK(obj->IsJSFunction());
+ CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
+ i::SmartPointer<char> found_name =
+ i::String::cast(
+ JSFunction::cast(
+ obj)->shared()->name())->ToCString();
+ CHECK_EQ(func_name, *found_name);
}
@@ -272,6 +255,7 @@
Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
CHECK(!func.is_null());
i::FLAG_allow_natives_syntax = allow_natives_syntax;
+ func->shared()->set_name(*NewString(func_name));
#ifdef DEBUG
v8::internal::Code* func_code = func->code();
@@ -289,6 +273,11 @@
// StackTracer uses Top::c_entry_fp as a starting point for stack
// walking.
TEST(CFromJSStackTrace) {
+ // TODO(711) The hack of replacing the inline runtime function
+ // RandomHeapNumber with GetFrameNumber does not work with the way the full
+ // compiler generates inline runtime calls.
+ i::FLAG_always_full_compiler = false;
+
TickSample sample;
InitTraceEnv(&sample);
@@ -313,10 +302,8 @@
// StackTracer::Trace
CHECK_GT(sample.frames_count, 1);
// Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
- CheckRetAddrIsInJSFunction("JSFuncDoTrace",
- sample.stack[0]);
- CheckRetAddrIsInJSFunction("JSTrace",
- sample.stack[1]);
+ CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]);
+ CheckObjectIsJSFunction("JSTrace", sample.stack[1]);
}
@@ -326,6 +313,11 @@
// Top::c_entry_fp value. In this case, StackTracer uses passed frame
// pointer value as a starting point for stack walking.
TEST(PureJSStackTrace) {
+ // TODO(711) The hack of replacing the inline runtime function
+ // RandomHeapNumber with GetFrameNumber does not work with the way the full
+ // compiler generates inline runtime calls.
+ i::FLAG_always_full_compiler = false;
+
TickSample sample;
InitTraceEnv(&sample);
@@ -359,10 +351,8 @@
sample.function);
CHECK_GT(sample.frames_count, 1);
// Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
- CheckRetAddrIsInJSFunction("JSTrace",
- sample.stack[0]);
- CheckRetAddrIsInJSFunction("OuterJSTrace",
- sample.stack[1]);
+ CheckObjectIsJSFunction("JSTrace", sample.stack[0]);
+ CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]);
}
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
index 8924ba7..dd97498 100755
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -61,6 +61,7 @@
using v8::internal::r13;
using v8::internal::r14;
using v8::internal::r15;
+using v8::internal::times_pointer_size;
using v8::internal::FUNCTION_CAST;
using v8::internal::CodeDesc;
using v8::internal::less_equal;
@@ -75,6 +76,8 @@
using v8::internal::Smi;
using v8::internal::kSmiTagMask;
using v8::internal::kSmiValueSize;
+using v8::internal::kPointerSize;
+using v8::internal::kIntSize;
// Test the x64 assembler by compiling some simple functions into
// a buffer and executing them. These tests do not initialize the
@@ -2053,4 +2056,358 @@
}
+TEST(OperandOffset) {
+ int data[256];
+ for (int i = 0; i < 256; i++) { data[i] = i * 0x01010101; }
+
+ // 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, static_cast<int>(actual_size));
+
+ MacroAssembler* masm = &assembler;
+ masm->set_allow_stub_calls(false);
+ Label exit;
+
+ __ push(r12);
+ __ push(r13);
+ __ push(rbx);
+ __ push(rbp);
+ __ push(Immediate(0x100)); // <-- rbp
+ __ movq(rbp, rsp);
+ __ push(Immediate(0x101));
+ __ push(Immediate(0x102));
+ __ push(Immediate(0x103));
+ __ push(Immediate(0x104));
+ __ push(Immediate(0x105)); // <-- rbx
+ __ push(Immediate(0x106));
+ __ push(Immediate(0x107));
+ __ push(Immediate(0x108));
+ __ push(Immediate(0x109)); // <-- rsp
+ // rbp = rsp[9]
+ // r12 = rsp[3]
+ // rbx = rsp[5]
+ // r13 = rsp[7]
+ __ lea(r12, Operand(rsp, 3 * kPointerSize));
+ __ lea(r13, Operand(rbp, -3 * kPointerSize));
+ __ lea(rbx, Operand(rbp, -5 * kPointerSize));
+ __ movl(rcx, Immediate(2));
+ __ movq(r8, reinterpret_cast<uintptr_t>(&data[128]), RelocInfo::NONE);
+ __ movl(rax, Immediate(1));
+
+ Operand sp0 = Operand(rsp, 0);
+
+ // Test 1.
+ __ movl(rdx, sp0); // Sanity check.
+ __ cmpl(rdx, Immediate(0x109));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Test 2.
+ // Zero to non-zero displacement.
+ __ movl(rdx, Operand(sp0, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x107));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand sp2 = Operand(rsp, 2 * kPointerSize);
+
+ // Test 3.
+ __ movl(rdx, sp2); // Sanity check.
+ __ cmpl(rdx, Immediate(0x107));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(sp2, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x105));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Non-zero to zero displacement.
+ __ movl(rdx, Operand(sp2, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x109));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand sp2c2 = Operand(rsp, rcx, times_pointer_size, 2 * kPointerSize);
+
+ // Test 6.
+ __ movl(rdx, sp2c2); // Sanity check.
+ __ cmpl(rdx, Immediate(0x105));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(sp2c2, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x103));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Non-zero to zero displacement.
+ __ movl(rdx, Operand(sp2c2, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x107));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+
+ Operand bp0 = Operand(rbp, 0);
+
+ // Test 9.
+ __ movl(rdx, bp0); // Sanity check.
+ __ cmpl(rdx, Immediate(0x100));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Zero to non-zero displacement.
+ __ movl(rdx, Operand(bp0, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x102));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand bp2 = Operand(rbp, -2 * kPointerSize);
+
+ // Test 11.
+ __ movl(rdx, bp2); // Sanity check.
+ __ cmpl(rdx, Immediate(0x102));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Non-zero to zero displacement.
+ __ movl(rdx, Operand(bp2, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x100));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bp2, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x104));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand bp2c4 = Operand(rbp, rcx, times_pointer_size, -4 * kPointerSize);
+
+ // Test 14:
+ __ movl(rdx, bp2c4); // Sanity check.
+ __ cmpl(rdx, Immediate(0x102));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bp2c4, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x100));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bp2c4, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x104));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand bx0 = Operand(rbx, 0);
+
+ // Test 17.
+ __ movl(rdx, bx0); // Sanity check.
+ __ cmpl(rdx, Immediate(0x105));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bx0, 5 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x100));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bx0, -4 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x109));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand bx2 = Operand(rbx, 2 * kPointerSize);
+
+ // Test 20.
+ __ movl(rdx, bx2); // Sanity check.
+ __ cmpl(rdx, Immediate(0x103));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bx2, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x101));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Non-zero to zero displacement.
+ __ movl(rdx, Operand(bx2, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x105));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand bx2c2 = Operand(rbx, rcx, times_pointer_size, -2 * kPointerSize);
+
+ // Test 23.
+ __ movl(rdx, bx2c2); // Sanity check.
+ __ cmpl(rdx, Immediate(0x105));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bx2c2, 2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x103));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(bx2c2, -2 * kPointerSize));
+ __ cmpl(rdx, Immediate(0x107));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand r80 = Operand(r8, 0);
+
+ // Test 26.
+ __ movl(rdx, r80); // Sanity check.
+ __ cmpl(rdx, Immediate(0x80808080));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, -8 * kIntSize));
+ __ cmpl(rdx, Immediate(0x78787878));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, 8 * kIntSize));
+ __ cmpl(rdx, Immediate(0x88888888));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, -64 * kIntSize));
+ __ cmpl(rdx, Immediate(0x40404040));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, 64 * kIntSize));
+ __ cmpl(rdx, Immediate(0xC0C0C0C0));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ Operand r88 = Operand(r8, 8 * kIntSize);
+
+ // Test 31.
+ __ movl(rdx, r88); // Sanity check.
+ __ cmpl(rdx, Immediate(0x88888888));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r88, -8 * kIntSize));
+ __ cmpl(rdx, Immediate(0x80808080));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r88, 8 * kIntSize));
+ __ cmpl(rdx, Immediate(0x90909090));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r88, -64 * kIntSize));
+ __ cmpl(rdx, Immediate(0x48484848));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r88, 64 * kIntSize));
+ __ cmpl(rdx, Immediate(0xC8C8C8C8));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+
+ Operand r864 = Operand(r8, 64 * kIntSize);
+
+ // Test 36.
+ __ movl(rdx, r864); // Sanity check.
+ __ cmpl(rdx, Immediate(0xC0C0C0C0));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r864, -8 * kIntSize));
+ __ cmpl(rdx, Immediate(0xB8B8B8B8));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r864, 8 * kIntSize));
+ __ cmpl(rdx, Immediate(0xC8C8C8C8));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r864, -64 * kIntSize));
+ __ cmpl(rdx, Immediate(0x80808080));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r864, 32 * kIntSize));
+ __ cmpl(rdx, Immediate(0xE0E0E0E0));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // 32-bit offset to 8-bit offset.
+ __ movl(rdx, Operand(r864, -60 * kIntSize));
+ __ cmpl(rdx, Immediate(0x84848484));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r864, 60 * kIntSize));
+ __ cmpl(rdx, Immediate(0xFCFCFCFC));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Test unaligned offsets.
+
+ // Test 43.
+ __ movl(rdx, Operand(r80, 2));
+ __ cmpl(rdx, Immediate(0x81818080));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, -2));
+ __ cmpl(rdx, Immediate(0x80807F7F));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, 126));
+ __ cmpl(rdx, Immediate(0xA0A09F9F));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, -126));
+ __ cmpl(rdx, Immediate(0x61616060));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, 254));
+ __ cmpl(rdx, Immediate(0xC0C0BFBF));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ __ movl(rdx, Operand(r80, -254));
+ __ cmpl(rdx, Immediate(0x41414040));
+ __ j(not_equal, &exit);
+ __ incq(rax);
+
+ // Success.
+
+ __ movl(rax, Immediate(0));
+ __ bind(&exit);
+ __ lea(rsp, Operand(rbp, kPointerSize));
+ __ pop(rbp);
+ __ pop(rbx);
+ __ pop(r13);
+ __ pop(r12);
+ __ 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/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index e5850c9..b438d25 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -19,22 +19,64 @@
using i::ProfileGenerator;
using i::SampleRateCalculator;
using i::TickSample;
+using i::TokenEnumerator;
using i::Vector;
+namespace v8 {
+namespace internal {
+
+class TokenEnumeratorTester {
+ public:
+ static i::List<bool>* token_removed(TokenEnumerator* te) {
+ return &te->token_removed_;
+ }
+};
+
+} } // namespace v8::internal
+
+TEST(TokenEnumerator) {
+ TokenEnumerator te;
+ CHECK_EQ(CodeEntry::kNoSecurityToken, te.GetTokenId(NULL));
+ v8::HandleScope hs;
+ v8::Local<v8::String> token1(v8::String::New("1"));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ v8::Local<v8::String> token2(v8::String::New("2"));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ {
+ v8::HandleScope hs;
+ v8::Local<v8::String> token3(v8::String::New("3"));
+ CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+ }
+ CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
+ i::Heap::CollectAllGarbage(false);
+ CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
+ CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
+ CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
+}
+
+
TEST(ProfileNodeFindOrAddChild) {
ProfileNode node(NULL, NULL);
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
CHECK_NE(NULL, childNode1);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
CHECK_NE(NULL, childNode2);
CHECK_NE(childNode1, childNode2);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
CHECK_NE(NULL, childNode3);
CHECK_NE(childNode1, childNode3);
@@ -75,9 +117,12 @@
} // namespace
TEST(ProfileTreeAddPathFromStart) {
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@@ -142,9 +187,12 @@
TEST(ProfileTreeAddPathFromEnd) {
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@@ -222,11 +270,30 @@
CHECK_EQ(1, empty_tree.root()->total_ticks());
CHECK_EQ(1, empty_tree.root()->self_ticks());
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry* e1_path[] = {&entry1};
Vector<CodeEntry*> e1_path_vec(
e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
+
+ ProfileTree single_child_tree;
+ single_child_tree.AddPathFromStart(e1_path_vec);
+ single_child_tree.root()->IncrementSelfTicks();
+ CHECK_EQ(0, single_child_tree.root()->total_ticks());
+ CHECK_EQ(1, single_child_tree.root()->self_ticks());
+ ProfileTreeTestHelper single_child_helper(&single_child_tree);
+ ProfileNode* node1 = single_child_helper.Walk(&entry1);
+ CHECK_NE(NULL, node1);
+ CHECK_EQ(0, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+ single_child_tree.CalculateTotalTicks();
+ CHECK_EQ(2, single_child_tree.root()->total_ticks());
+ CHECK_EQ(1, single_child_tree.root()->self_ticks());
+ CHECK_EQ(1, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry* e1_e2_path[] = {&entry1, &entry2};
Vector<CodeEntry*> e1_e2_path_vec(
e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
@@ -241,7 +308,7 @@
// Results in {root,0,0} -> {entry1,0,2} -> {entry2,0,3}
CHECK_EQ(0, flat_tree.root()->total_ticks());
CHECK_EQ(0, flat_tree.root()->self_ticks());
- ProfileNode* node1 = flat_helper.Walk(&entry1);
+ node1 = flat_helper.Walk(&entry1);
CHECK_NE(NULL, node1);
CHECK_EQ(0, node1->total_ticks());
CHECK_EQ(2, node1->self_ticks());
@@ -261,7 +328,8 @@
CodeEntry* e2_path[] = {&entry2};
Vector<CodeEntry*> e2_path_vec(
e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry* e3_path[] = {&entry3};
Vector<CodeEntry*> e3_path_vec(
e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
@@ -316,16 +384,119 @@
}
+TEST(ProfileTreeFilteredClone) {
+ ProfileTree source_tree;
+ const int token0 = 0, token1 = 1, token2 = 2;
+ CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0, token0);
+ CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0, token1);
+ CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
+ CodeEntry entry4(
+ i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
+ CodeEntry::kInheritsSecurityToken);
+
+ {
+ CodeEntry* e1_e2_path[] = {&entry1, &entry2};
+ Vector<CodeEntry*> e1_e2_path_vec(
+ e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
+ source_tree.AddPathFromStart(e1_e2_path_vec);
+ CodeEntry* e2_e4_path[] = {&entry2, &entry4};
+ Vector<CodeEntry*> e2_e4_path_vec(
+ e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
+ source_tree.AddPathFromStart(e2_e4_path_vec);
+ CodeEntry* e3_e1_path[] = {&entry3, &entry1};
+ Vector<CodeEntry*> e3_e1_path_vec(
+ e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
+ source_tree.AddPathFromStart(e3_e1_path_vec);
+ CodeEntry* e3_e2_path[] = {&entry3, &entry2};
+ Vector<CodeEntry*> e3_e2_path_vec(
+ e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
+ source_tree.AddPathFromStart(e3_e2_path_vec);
+ source_tree.CalculateTotalTicks();
+ // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
+ // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
+ // -> {entry3,0,2,0} -> {entry1,1,1,0}
+ // -> {entry2,1,1,1}
+ CHECK_EQ(4, source_tree.root()->total_ticks());
+ CHECK_EQ(0, source_tree.root()->self_ticks());
+ }
+
+ {
+ ProfileTree token0_tree;
+ token0_tree.FilteredClone(&source_tree, token0);
+ // Should be -> {entry1,1,1,0}
+ // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
+ // [self ticks from filtered nodes are attributed to their parents]
+ CHECK_EQ(4, token0_tree.root()->total_ticks());
+ CHECK_EQ(1, token0_tree.root()->self_ticks());
+ ProfileTreeTestHelper token0_helper(&token0_tree);
+ ProfileNode* node1 = token0_helper.Walk(&entry1);
+ CHECK_NE(NULL, node1);
+ CHECK_EQ(1, node1->total_ticks());
+ CHECK_EQ(1, node1->self_ticks());
+ CHECK_EQ(NULL, token0_helper.Walk(&entry2));
+ ProfileNode* node3 = token0_helper.Walk(&entry3);
+ CHECK_NE(NULL, node3);
+ CHECK_EQ(2, node3->total_ticks());
+ CHECK_EQ(1, node3->self_ticks());
+ ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
+ CHECK_NE(NULL, node3_1);
+ CHECK_EQ(1, node3_1->total_ticks());
+ CHECK_EQ(1, node3_1->self_ticks());
+ CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
+ }
+
+ {
+ ProfileTree token1_tree;
+ token1_tree.FilteredClone(&source_tree, token1);
+ // Should be
+ // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
+ // [child nodes referring to the same entry get merged and
+ // their self times summed up]
+ CHECK_EQ(4, token1_tree.root()->total_ticks());
+ CHECK_EQ(1, token1_tree.root()->self_ticks());
+ ProfileTreeTestHelper token1_helper(&token1_tree);
+ CHECK_EQ(NULL, token1_helper.Walk(&entry1));
+ CHECK_EQ(NULL, token1_helper.Walk(&entry3));
+ ProfileNode* node2 = token1_helper.Walk(&entry2);
+ CHECK_NE(NULL, node2);
+ CHECK_EQ(3, node2->total_ticks());
+ CHECK_EQ(2, node2->self_ticks());
+ ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
+ CHECK_NE(NULL, node2_4);
+ CHECK_EQ(1, node2_4->total_ticks());
+ CHECK_EQ(1, node2_4->self_ticks());
+ }
+
+ {
+ ProfileTree token2_tree;
+ token2_tree.FilteredClone(&source_tree, token2);
+ // Should be
+ // {root,4,4,-1}
+ // [no nodes, all ticks get migrated into root node]
+ CHECK_EQ(4, token2_tree.root()->total_ticks());
+ CHECK_EQ(4, token2_tree.root()->self_ticks());
+ ProfileTreeTestHelper token2_helper(&token2_tree);
+ CHECK_EQ(NULL, token2_helper.Walk(&entry1));
+ CHECK_EQ(NULL, token2_helper.Walk(&entry2));
+ CHECK_EQ(NULL, token2_helper.Walk(&entry3));
+ }
+}
+
+
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}
TEST(CodeMapAddCode) {
CodeMap code_map;
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0);
- CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry3(
+ i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry4(
+ i::Logger::FUNCTION_TAG, "", "ddd", "", 0, CodeEntry::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
@@ -352,8 +523,10 @@
TEST(CodeMapMoveAndDeleteCode) {
CodeMap code_map;
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0);
+ CodeEntry entry1(
+ i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
+ CodeEntry entry2(
+ i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
@@ -425,7 +598,8 @@
sample3.frames_count = 2;
generator.RecordTickSample(sample3);
- CpuProfile* profile = profiles.StopProfiling("", 1);
+ CpuProfile* profile =
+ profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
ProfileTreeTestHelper top_down_test_helper(profile->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 83a1e19..aed7466 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -308,3 +308,48 @@
v8::Script::Compile(source)->Run();
context.Dispose();
}
+
+v8::Handle<v8::Value> ReenterAfterTermination(const v8::Arguments& args) {
+ v8::TryCatch try_catch;
+ CHECK(!v8::V8::IsExecutionTerminating());
+ v8::Script::Compile(v8::String::New("function f() {"
+ " var term = true;"
+ " try {"
+ " while(true) {"
+ " if (term) terminate();"
+ " term = false;"
+ " }"
+ " fail();"
+ " } catch(e) {"
+ " fail();"
+ " }"
+ "}"
+ "f()"))->Run();
+ CHECK(try_catch.HasCaught());
+ CHECK(try_catch.Exception()->IsNull());
+ CHECK(try_catch.Message().IsEmpty());
+ CHECK(!try_catch.CanContinue());
+ CHECK(v8::V8::IsExecutionTerminating());
+ v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run();
+ return v8::Undefined();
+}
+
+// Test that reentry into V8 while the termination exception is still pending
+// (has not yet unwound the 0-level JS frame) does not crash.
+TEST(TerminateAndReenterFromThreadItself) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global =
+ CreateGlobalTemplate(TerminateCurrentThread, ReenterAfterTermination);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ CHECK(!v8::V8::IsExecutionTerminating());
+ v8::Handle<v8::String> source =
+ v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+ CHECK(!v8::V8::IsExecutionTerminating());
+ // Check we can run JS again after termination.
+ CHECK(v8::Script::Compile(v8::String::New("function f() { return true; }"
+ "f()"))->Run()->IsTrue());
+ context.Dispose();
+}
+
diff --git a/test/cctest/test-unbound-queue.cc b/test/cctest/test-unbound-queue.cc
new file mode 100644
index 0000000..df5509e
--- /dev/null
+++ b/test/cctest/test-unbound-queue.cc
@@ -0,0 +1,54 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+//
+// Tests of the unbound queue.
+
+#include "v8.h"
+#include "unbound-queue-inl.h"
+#include "cctest.h"
+
+namespace i = v8::internal;
+
+using i::UnboundQueue;
+
+
+TEST(SingleRecord) {
+ typedef int Record;
+ UnboundQueue<Record> cq;
+ CHECK(cq.IsEmpty());
+ cq.Enqueue(1);
+ CHECK(!cq.IsEmpty());
+ Record rec = 0;
+ cq.Dequeue(&rec);
+ CHECK_EQ(1, rec);
+ CHECK(cq.IsEmpty());
+}
+
+
+TEST(MultipleRecords) {
+ typedef int Record;
+ UnboundQueue<Record> cq;
+ CHECK(cq.IsEmpty());
+ cq.Enqueue(1);
+ CHECK(!cq.IsEmpty());
+ for (int i = 2; i <= 5; ++i) {
+ cq.Enqueue(i);
+ CHECK(!cq.IsEmpty());
+ }
+ Record rec = 0;
+ for (int i = 1; i <= 4; ++i) {
+ CHECK(!cq.IsEmpty());
+ cq.Dequeue(&rec);
+ CHECK_EQ(i, rec);
+ }
+ for (int i = 6; i <= 12; ++i) {
+ cq.Enqueue(i);
+ CHECK(!cq.IsEmpty());
+ }
+ for (int i = 5; i <= 12; ++i) {
+ CHECK(!cq.IsEmpty());
+ cq.Dequeue(&rec);
+ CHECK_EQ(i, rec);
+ }
+ CHECK(cq.IsEmpty());
+}
+
diff --git a/test/mjsunit/compiler/assignment.js b/test/mjsunit/compiler/assignment.js
index ee2d323..6aded4e 100644
--- a/test/mjsunit/compiler/assignment.js
+++ b/test/mjsunit/compiler/assignment.js
@@ -262,3 +262,15 @@
}
bar_loop();
+
+
+// Test for assignment using a keyed store ic:
+function store_i_in_element_i_of_object_i() {
+ var i = new Object();
+ i[i] = i;
+}
+
+// Run three times to exercise caches.
+store_i_in_element_i_of_object_i();
+store_i_in_element_i_of_object_i();
+store_i_in_element_i_of_object_i();
diff --git a/test/mjsunit/object-define-property.js b/test/mjsunit/object-define-property.js
index 43b1c7f..46bfb34 100644
--- a/test/mjsunit/object-define-property.js
+++ b/test/mjsunit/object-define-property.js
@@ -53,36 +53,46 @@
assertTrue(/called on non-object/.test(e));
}
-// Object
+// Object.
var obj1 = {};
-// Values
+// Values.
var val1 = 0;
var val2 = 0;
var val3 = 0;
-// Descriptors
+function setter1() {val1++; }
+function getter1() {return val1; }
+
+function setter2() {val2++; }
+function getter2() {return val2; }
+
+function setter3() {val3++; }
+function getter3() {return val3; }
+
+
+// Descriptors.
var emptyDesc = {};
var accessorConfigurable = {
- set: function() { val1++; },
- get: function() { return val1; },
+ set: setter1,
+ get: getter1,
configurable: true
};
var accessorNoConfigurable = {
- set: function() { val2++; },
- get: function() { return val2; },
+ set: setter2,
+ get: getter2,
configurable: false
};
var accessorOnlySet = {
- set: function() { val3++; },
+ set: setter3,
configurable: true
};
var accessorOnlyGet = {
- get: function() { return val3; },
+ get: getter3,
configurable: true
};
@@ -200,7 +210,7 @@
assertEquals(4, val2);
assertEquals(4, obj1.bar);
-// Define an accessor that has only a setter
+// Define an accessor that has only a setter.
Object.defineProperty(obj1, "setOnly", accessorOnlySet);
desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
assertTrue(desc.configurable);
@@ -212,7 +222,7 @@
assertEquals(1, obj1.setOnly = 1);
assertEquals(1, val3);
-// Add a getter - should not touch the setter
+// Add a getter - should not touch the setter.
Object.defineProperty(obj1, "setOnly", accessorOnlyGet);
desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
assertTrue(desc.configurable);
@@ -256,7 +266,7 @@
assertEquals(obj1.foobar, 1000);
-// Redefine to writable descriptor - now writing to foobar should be allowed
+// Redefine to writable descriptor - now writing to foobar should be allowed.
Object.defineProperty(obj1, "foobar", dataWritable);
desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
assertEquals(obj1.foobar, 3000);
@@ -279,7 +289,7 @@
assertEquals(obj1.foobar, 2000);
assertEquals(desc.value, 2000);
assertFalse(desc.configurable);
-assertFalse(desc.writable);
+assertTrue(desc.writable);
assertFalse(desc.enumerable);
assertEquals(desc.get, undefined);
assertEquals(desc.set, undefined);
@@ -307,7 +317,7 @@
assertEquals(obj1.foobar, 2000);
assertEquals(desc.value, 2000);
assertFalse(desc.configurable);
-assertFalse(desc.writable);
+assertTrue(desc.writable);
assertFalse(desc.enumerable);
assertEquals(desc.get, undefined);
assertEquals(desc.set, undefined);
@@ -375,7 +385,7 @@
// Redefinition of an accessor defined using __defineGetter__ and
-// __defineSetter__
+// __defineSetter__.
function get(){return this.x}
function set(x){this.x=x};
@@ -442,7 +452,7 @@
assertEquals(5, val1);
assertEquals(5, obj4.bar);
-// Make sure an error is thrown when trying to access to redefined function
+// Make sure an error is thrown when trying to access to redefined function.
try {
obj4.bar();
assertTrue(false);
@@ -453,7 +463,7 @@
// Test runtime calls to DefineOrRedefineDataProperty and
// DefineOrRedefineAccessorProperty - make sure we don't
-// crash
+// crash.
try {
%DefineOrRedefineAccessorProperty(0, 0, 0, 0, 0);
} catch (e) {
@@ -497,3 +507,210 @@
} catch (e) {
assertTrue(/illegal access/.test(e));
}
+
+// Test that all possible differences in step 6 in DefineOwnProperty are
+// exercised, i.e., any difference in the given property descriptor and the
+// existing properties should not return true, but throw an error if the
+// existing configurable property is false.
+
+var obj5 = {};
+// Enumerable will default to false.
+Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
+// First, test that we are actually allowed to set the accessor if all
+// values are of the descriptor are the same as the existing one.
+Object.defineProperty(obj5, 'foo', accessorNoConfigurable);
+
+// Different setter.
+var descDifferent = {
+ configurable:false,
+ enumerable:false,
+ set: setter1,
+ get: getter2
+};
+
+try {
+ Object.defineProperty(obj5, 'foo', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Different getter.
+descDifferent = {
+ configurable:false,
+ enumerable:false,
+ set: setter2,
+ get: getter1
+};
+
+try {
+ Object.defineProperty(obj5, 'foo', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Different enumerable.
+descDifferent = {
+ configurable:false,
+ enumerable:true,
+ set: setter2,
+ get: getter2
+};
+
+try {
+ Object.defineProperty(obj5, 'foo', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Different configurable.
+descDifferent = {
+ configurable:false,
+ enumerable:true,
+ set: setter2,
+ get: getter2
+};
+
+try {
+ Object.defineProperty(obj5, 'foo', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// No difference.
+descDifferent = {
+ configurable:false,
+ enumerable:false,
+ set: setter2,
+ get: getter2
+};
+// Make sure we can still redefine if all properties are the same.
+Object.defineProperty(obj5, 'foo', descDifferent);
+
+// Make sure that obj5 still holds the original values.
+desc = Object.getOwnPropertyDescriptor(obj5, 'foo');
+assertEquals(desc.get, getter2);
+assertEquals(desc.set, setter2);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+
+// Also exercise step 6 on data property, writable and enumerable
+// defaults to false.
+Object.defineProperty(obj5, 'bar', dataNoConfigurable);
+
+// Test that redefinition with the same property descriptor is possible
+Object.defineProperty(obj5, 'bar', dataNoConfigurable);
+
+// Different value.
+descDifferent = {
+ configurable:false,
+ enumerable:false,
+ writable: false,
+ value: 1999
+};
+
+try {
+ Object.defineProperty(obj5, 'bar', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Different writable.
+descDifferent = {
+ configurable:false,
+ enumerable:false,
+ writable: true,
+ value: 2000
+};
+
+try {
+ Object.defineProperty(obj5, 'bar', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+
+// Different enumerable.
+descDifferent = {
+ configurable:false,
+ enumerable:true ,
+ writable:false,
+ value: 2000
+};
+
+try {
+ Object.defineProperty(obj5, 'bar', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+
+// Different configurable.
+descDifferent = {
+ configurable:true,
+ enumerable:false,
+ writable:false,
+ value: 2000
+};
+
+try {
+ Object.defineProperty(obj5, 'bar', descDifferent);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// No difference.
+descDifferent = {
+ configurable:false,
+ enumerable:false,
+ writable:false,
+ value:2000
+};
+// Make sure we can still redefine if all properties are the same.
+Object.defineProperty(obj5, 'bar', descDifferent);
+
+// Make sure that obj5 still holds the original values.
+desc = Object.getOwnPropertyDescriptor(obj5, 'bar');
+assertEquals(desc.value, 2000);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertFalse(desc.configurable);
+
+
+// Make sure that we can't overwrite +0 with -0 and vice versa.
+var descMinusZero = {value: -0, configurable: false};
+var descPlusZero = {value: +0, configurable: false};
+
+Object.defineProperty(obj5, 'minuszero', descMinusZero);
+
+// Make sure we can redefine with -0.
+Object.defineProperty(obj5, 'minuszero', descMinusZero);
+
+try {
+ Object.defineProperty(obj5, 'minuszero', descPlusZero);
+ assertUnreachable();
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+
+Object.defineProperty(obj5, 'pluszero', descPlusZero);
+
+// Make sure we can redefine with +0.
+Object.defineProperty(obj5, 'pluszero', descPlusZero);
+
+try {
+ Object.defineProperty(obj5, 'pluszero', descMinusZero);
+ assertUnreachable();
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
diff --git a/test/mjsunit/regress/regress-712.js b/test/mjsunit/regress/regress-712.js
new file mode 100644
index 0000000..b26b94a
--- /dev/null
+++ b/test/mjsunit/regress/regress-712.js
@@ -0,0 +1,38 @@
+// Copyright 2010 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.
+
+// This regression test is used to ensure that Object.defineProperty
+// can't be called with an empty property descriptor on a non-configurable
+// existing property and override the existing property.
+// See: http://code.google.com/p/v8/issues/detail?id=712
+
+var obj = {};
+Object.defineProperty(obj, "x", { get: function() { return "42"; },
+ configurable: false });
+assertEquals(obj.x, "42");
+Object.defineProperty(obj, 'x', {});
+assertEquals(obj.x, "42");
diff --git a/test/mjsunit/regress/regress-720.js b/test/mjsunit/regress/regress-720.js
new file mode 100644
index 0000000..97e1284
--- /dev/null
+++ b/test/mjsunit/regress/regress-720.js
@@ -0,0 +1,36 @@
+// Copyright 2010 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.
+
+// This regression test is used to ensure that Object.defineProperty
+// keeps the existing value of the writable flag if none is given
+// in the provided descriptor.
+// See: http://code.google.com/p/v8/issues/detail?id=720
+
+var o = {x: 10};
+Object.defineProperty(o, "x", {value: 5});
+var desc = Object.getOwnPropertyDescriptor(o, "x");
+assertTrue(desc["writable"]);
diff --git a/test/mjsunit/samevalue.js b/test/mjsunit/samevalue.js
new file mode 100644
index 0000000..6cb35e6
--- /dev/null
+++ b/test/mjsunit/samevalue.js
@@ -0,0 +1,102 @@
+// Copyright 2010 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-natives_as natives
+// Test the SameValue internal method.
+
+var obj1 = {x: 10, y: 11, z: "test"};
+var obj2 = {x: 10, y: 11, z: "test"};
+
+assertTrue(natives.SameValue(0, 0));
+assertTrue(natives.SameValue(+0, +0));
+assertTrue(natives.SameValue(-0, -0));
+assertTrue(natives.SameValue(1, 1));
+assertTrue(natives.SameValue(2, 2));
+assertTrue(natives.SameValue(-1, -1));
+assertTrue(natives.SameValue(0.5, 0.5));
+assertTrue(natives.SameValue(true, true));
+assertTrue(natives.SameValue(false, false));
+assertTrue(natives.SameValue(NaN, NaN));
+assertTrue(natives.SameValue(null, null));
+assertTrue(natives.SameValue("foo", "foo"));
+assertTrue(natives.SameValue(obj1, obj1));
+// Undefined values.
+assertTrue(natives.SameValue());
+assertTrue(natives.SameValue(undefined, undefined));
+
+assertFalse(natives.SameValue(0,1));
+assertFalse(natives.SameValue("foo", "bar"));
+assertFalse(natives.SameValue(obj1, obj2));
+assertFalse(natives.SameValue(true, false));
+
+assertFalse(natives.SameValue(obj1, true));
+assertFalse(natives.SameValue(obj1, "foo"));
+assertFalse(natives.SameValue(obj1, 1));
+assertFalse(natives.SameValue(obj1, undefined));
+assertFalse(natives.SameValue(obj1, NaN));
+
+assertFalse(natives.SameValue(undefined, true));
+assertFalse(natives.SameValue(undefined, "foo"));
+assertFalse(natives.SameValue(undefined, 1));
+assertFalse(natives.SameValue(undefined, obj1));
+assertFalse(natives.SameValue(undefined, NaN));
+
+assertFalse(natives.SameValue(NaN, true));
+assertFalse(natives.SameValue(NaN, "foo"));
+assertFalse(natives.SameValue(NaN, 1));
+assertFalse(natives.SameValue(NaN, obj1));
+assertFalse(natives.SameValue(NaN, undefined));
+
+assertFalse(natives.SameValue("foo", true));
+assertFalse(natives.SameValue("foo", 1));
+assertFalse(natives.SameValue("foo", obj1));
+assertFalse(natives.SameValue("foo", undefined));
+assertFalse(natives.SameValue("foo", NaN));
+
+assertFalse(natives.SameValue(true, 1));
+assertFalse(natives.SameValue(true, obj1));
+assertFalse(natives.SameValue(true, undefined));
+assertFalse(natives.SameValue(true, NaN));
+assertFalse(natives.SameValue(true, "foo"));
+
+assertFalse(natives.SameValue(1, true));
+assertFalse(natives.SameValue(1, obj1));
+assertFalse(natives.SameValue(1, undefined));
+assertFalse(natives.SameValue(1, NaN));
+assertFalse(natives.SameValue(1, "foo"));
+
+// Special string cases.
+assertFalse(natives.SameValue("1", 1));
+assertFalse(natives.SameValue("true", true));
+assertFalse(natives.SameValue("false", false));
+assertFalse(natives.SameValue("undefined", undefined));
+assertFalse(natives.SameValue("NaN", NaN));
+
+// -0 and +0 are should be different
+assertFalse(natives.SameValue(+0, -0));
+assertFalse(natives.SameValue(-0, +0));
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
index c92bfa6..b4ec444 100644
--- a/test/mozilla/mozilla.status
+++ b/test/mozilla/mozilla.status
@@ -161,6 +161,7 @@
# In Denmark the adjustment starts one week earlier!.
# Tests based on shell that use dates in this gap are flaky.
ecma/Date/15.9.5.10-1: PASS || FAIL
+ecma/Date/15.9.5.10-2: PASS || TIMEOUT if ($arch == arm && $mode == debug)
ecma/Date/15.9.5.12-1: PASS || FAIL
ecma/Date/15.9.5.14: PASS || FAIL
ecma/Date/15.9.5.34-1: PASS || FAIL