summaryrefslogtreecommitdiff
path: root/deps/v8/test
diff options
context:
space:
mode:
authorRyan <ry@tinyclouds.org>2009-06-08 18:34:06 +0200
committerRyan <ry@tinyclouds.org>2009-06-08 18:34:06 +0200
commit696f02455792b368249bf9b013dde637b5ec31fd (patch)
tree95b2dbd6c2537df9df52f6627aac36fcf05f6a7a /deps/v8/test
parentf6a7fe26574defaa807a13248102ebe0f23270af (diff)
downloadnode-696f02455792b368249bf9b013dde637b5ec31fd.tar.gz
Upgrade to v8 1.2.7
Diffstat (limited to 'deps/v8/test')
-rw-r--r--deps/v8/test/cctest/SConscript2
-rw-r--r--deps/v8/test/cctest/cctest.status9
-rw-r--r--deps/v8/test/cctest/test-api.cc386
-rw-r--r--deps/v8/test/cctest/test-assembler-x64.cc251
-rw-r--r--deps/v8/test/cctest/test-debug.cc541
-rw-r--r--deps/v8/test/cctest/test-func-name-inference.cc17
-rw-r--r--deps/v8/test/cctest/test-hashmap.cc73
-rw-r--r--deps/v8/test/cctest/test-heap.cc39
-rw-r--r--deps/v8/test/cctest/test-list.cc34
-rw-r--r--deps/v8/test/cctest/test-log-ia32.cc77
-rw-r--r--deps/v8/test/cctest/test-log-utils.cc132
-rw-r--r--deps/v8/test/cctest/test-log.cc621
-rw-r--r--deps/v8/test/cctest/test-utils.cc7
-rw-r--r--deps/v8/test/cctest/test-version.cc3
-rw-r--r--deps/v8/test/mjsunit/codegen-coverage.js (renamed from deps/v8/test/mjsunit/codegen_coverage.js)0
-rw-r--r--deps/v8/test/mjsunit/debug-backtrace.js24
-rw-r--r--deps/v8/test/mjsunit/debug-compile-event.js39
-rw-r--r--deps/v8/test/mjsunit/debug-references.js2
-rw-r--r--deps/v8/test/mjsunit/debug-scripts-request.js21
-rw-r--r--deps/v8/test/mjsunit/mirror-array.js5
-rw-r--r--deps/v8/test/mjsunit/mirror-boolean.js2
-rw-r--r--deps/v8/test/mjsunit/mirror-date.js18
-rw-r--r--deps/v8/test/mjsunit/mirror-error.js5
-rw-r--r--deps/v8/test/mjsunit/mirror-function.js5
-rw-r--r--deps/v8/test/mjsunit/mirror-null.js2
-rw-r--r--deps/v8/test/mjsunit/mirror-number.js2
-rw-r--r--deps/v8/test/mjsunit/mirror-object.js8
-rw-r--r--deps/v8/test/mjsunit/mirror-regexp.js5
-rw-r--r--deps/v8/test/mjsunit/mirror-script.js32
-rw-r--r--deps/v8/test/mjsunit/mirror-string.js2
-rw-r--r--deps/v8/test/mjsunit/mirror-undefined.js2
-rw-r--r--deps/v8/test/mjsunit/mirror-unresolved-function.js5
-rw-r--r--deps/v8/test/mjsunit/regexp.js13
-rw-r--r--deps/v8/test/mjsunit/regress/regress-334.js (renamed from deps/v8/test/mjsunit/bugs/bug-334.js)0
-rw-r--r--deps/v8/test/mjsunit/regress/regress-341.js36
-rw-r--r--deps/v8/test/mjsunit/regress/regress-349.js32
-rw-r--r--deps/v8/test/mjsunit/regress/regress-351.js31
-rw-r--r--deps/v8/test/mjsunit/string-lastindexof.js63
38 files changed, 2365 insertions, 181 deletions
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript
index 740acbaa6..7506d2921 100644
--- a/deps/v8/test/cctest/SConscript
+++ b/deps/v8/test/cctest/SConscript
@@ -48,6 +48,7 @@ SOURCES = {
'test-list.cc',
'test-lock.cc',
'test-log.cc',
+ 'test-log-utils.cc',
'test-mark-compact.cc',
'test-regexp.cc',
'test-serialize.cc',
@@ -64,6 +65,7 @@ SOURCES = {
'test-disasm-ia32.cc',
'test-log-ia32.cc'
],
+ 'arch:x64': ['test-assembler-x64.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/cctest.status b/deps/v8/test/cctest/cctest.status
index 7b43c8de9..a8c218016 100644
--- a/deps/v8/test/cctest/cctest.status
+++ b/deps/v8/test/cctest/cctest.status
@@ -40,6 +40,15 @@ test-spaces/LargeObjectSpace: PASS || FAIL
# BUG(240): Test seems flaky on ARM.
test-api/RegExpInterruption: SKIP
+# We cannot assume that we can throw OutOfMemory exceptions in all situations.
+# Apparently our ARM box is in such a state. Skip the test as it also runs for
+# a long time.
+test-api/OutOfMemory: SKIP
+test-api/OutOfMemoryNested: SKIP
+
+# BUG(355): Test crashes on ARM.
+test-log/ProfLazyMode: SKIP
+
[ $simulator == arm ]
# BUG(271): During exception propagation, we compare pointers into the
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 4b55b6be0..48157d80b 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -30,6 +30,7 @@
#include "v8.h"
#include "api.h"
+#include "compilation-cache.h"
#include "snapshot.h"
#include "platform.h"
#include "top.h"
@@ -464,6 +465,7 @@ THREADED_TEST(ScriptUsingStringResource) {
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(0, TestResource::dispose_count);
}
+ v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(1, TestResource::dispose_count);
}
@@ -484,6 +486,7 @@ THREADED_TEST(ScriptUsingAsciiStringResource) {
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
+ v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@@ -505,6 +508,7 @@ THREADED_TEST(ScriptMakingExternalString) {
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(0, TestResource::dispose_count);
}
+ v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(1, TestResource::dispose_count);
}
@@ -527,35 +531,43 @@ THREADED_TEST(ScriptMakingExternalAsciiString) {
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(0, TestAsciiResource::dispose_count);
}
+ v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage();
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
THREADED_TEST(UsingExternalString) {
- v8::HandleScope scope;
- uint16_t* two_byte_string = AsciiToTwoByteString("test string");
- Local<String> string = String::NewExternal(new TestResource(two_byte_string));
- i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
- // Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
- CHECK(isymbol->IsSymbol());
+ {
+ v8::HandleScope scope;
+ uint16_t* two_byte_string = AsciiToTwoByteString("test string");
+ Local<String> string =
+ String::NewExternal(new TestResource(two_byte_string));
+ i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
+ // Trigger GCs so that the newly allocated string moves to old gen.
+ i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
+ i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
+ i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
+ CHECK(isymbol->IsSymbol());
+ }
+ i::Heap::CollectAllGarbage();
}
THREADED_TEST(UsingExternalAsciiString) {
- v8::HandleScope scope;
- const char* one_byte_string = "test string";
- Local<String> string = String::NewExternal(
- new TestAsciiResource(i::StrDup(one_byte_string)));
- i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
- // Trigger GCs so that the newly allocated string moves to old gen.
- i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
- i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
- i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
- CHECK(isymbol->IsSymbol());
+ {
+ v8::HandleScope scope;
+ const char* one_byte_string = "test string";
+ Local<String> string = String::NewExternal(
+ new TestAsciiResource(i::StrDup(one_byte_string)));
+ i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
+ // Trigger GCs so that the newly allocated string moves to old gen.
+ i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
+ i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
+ i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
+ CHECK(isymbol->IsSymbol());
+ }
+ i::Heap::CollectAllGarbage();
}
@@ -1327,6 +1339,38 @@ THREADED_TEST(HiddenProperties) {
}
+static v8::Handle<Value> InterceptorForHiddenProperties(
+ Local<String> name, const AccessorInfo& info) {
+ // Make sure objects move.
+ bool saved_always_compact = i::FLAG_always_compact;
+ if (!i::FLAG_never_compact) {
+ i::FLAG_always_compact = true;
+ }
+ // The whole goal of this interceptor is to cause a GC during local property
+ // lookup.
+ i::Heap::CollectAllGarbage();
+ i::FLAG_always_compact = saved_always_compact;
+ return v8::Handle<Value>();
+}
+
+
+THREADED_TEST(HiddenPropertiesWithInterceptors) {
+ v8::HandleScope scope;
+ LocalContext context;
+
+ v8::Local<v8::String> key = v8_str("api-test::hidden-key");
+
+ // Associate an interceptor with an object and start setting hidden values.
+ Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+ Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
+ instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
+ Local<v8::Function> function = fun_templ->GetFunction();
+ Local<v8::Object> obj = function->NewInstance();
+ CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
+ CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
+}
+
+
THREADED_TEST(External) {
v8::HandleScope scope;
int x = 3;
@@ -4471,10 +4515,6 @@ THREADED_TEST(EvalAliasedDynamic) {
v8::HandleScope scope;
LocalContext current;
- // This sets 'global' to the real global object (as opposed to the
- // proxy). It is highly implementation dependent, so take care.
- current->Global()->Set(v8_str("global"), current->Global()->GetPrototype());
-
// Tests where aliased eval can only be resolved dynamically.
Local<Script> script =
Script::Compile(v8_str("function f(x) { "
@@ -4483,7 +4523,7 @@ THREADED_TEST(EvalAliasedDynamic) {
"}"
"foo = 0;"
"result1 = f(new Object());"
- "result2 = f(global);"
+ "result2 = f(this);"
"var x = new Object();"
"x.eval = function(x) { return 1; };"
"result3 = f(x);"));
@@ -4498,7 +4538,7 @@ THREADED_TEST(EvalAliasedDynamic) {
" var bar = 2;"
" with (x) { return eval('bar'); }"
"}"
- "f(global)"));
+ "f(this)"));
script->Run();
CHECK(try_catch.HasCaught());
try_catch.Reset();
@@ -4585,6 +4625,44 @@ THREADED_TEST(CrossEval) {
}
+// Test that calling eval in a context which has been detached from
+// its global throws an exception. This behavior is consistent with
+// other JavaScript implementations.
+THREADED_TEST(EvalInDetachedGlobal) {
+ v8::HandleScope scope;
+
+ v8::Persistent<Context> context0 = Context::New();
+ v8::Persistent<Context> context1 = Context::New();
+
+ // Setup function in context0 that uses eval from context0.
+ context0->Enter();
+ v8::Handle<v8::Value> fun =
+ CompileRun("var x = 42;"
+ "(function() {"
+ " var e = eval;"
+ " return function(s) { return e(s); }"
+ "})()");
+ context0->Exit();
+
+ // Put the function into context1 and call it before and after
+ // detaching the global. Before detaching, the call succeeds and
+ // after detaching and exception is thrown.
+ context1->Enter();
+ context1->Global()->Set(v8_str("fun"), fun);
+ v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
+ CHECK_EQ(42, x_value->Int32Value());
+ context0->DetachGlobal();
+ v8::TryCatch catcher;
+ x_value = CompileRun("fun('x')");
+ CHECK(x_value.IsEmpty());
+ CHECK(catcher.HasCaught());
+ context1->Exit();
+
+ context1.Dispose();
+ context0.Dispose();
+}
+
+
THREADED_TEST(CrossLazyLoad) {
v8::HandleScope scope;
LocalContext other;
@@ -4607,6 +4685,12 @@ THREADED_TEST(CrossLazyLoad) {
static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
+ if (args.IsConstructCall()) {
+ if (args[0]->IsInt32()) {
+ return v8_num(-args[0]->Int32Value());
+ }
+ }
+
return args[0];
}
@@ -4660,9 +4744,9 @@ THREADED_TEST(CallAsFunction) {
// Check that the call-as-function handler can be called through
// new. Currently, there is no way to check in the call-as-function
// handler if it has been called through new or not.
- value = CompileRun("new obj(42)");
+ value = CompileRun("new obj(43)");
CHECK(!try_catch.HasCaught());
- CHECK_EQ(42, value->Int32Value());
+ CHECK_EQ(-43, value->Int32Value());
}
@@ -4777,6 +4861,23 @@ THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
}
+typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
+ const AccessorInfo& info);
+
+
+static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
+ const char* source,
+ int expected) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(getter);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(source);
+ CHECK_EQ(expected, value->Int32Value());
+}
+
+
static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
@@ -4787,17 +4888,100 @@ static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
// This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC) {
- v8::HandleScope scope;
- v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
- templ->SetNamedPropertyHandler(InterceptorLoadICGetter);
- LocalContext context;
- context->Global()->Set(v8_str("o"), templ->NewInstance());
- v8::Handle<Value> value = CompileRun(
+ CheckInterceptorLoadIC(InterceptorLoadICGetter,
"var result = 0;"
"for (var i = 0; i < 1000; i++) {"
" result = o.x;"
- "}");
- CHECK_EQ(42, value->Int32Value());
+ "}",
+ 42);
+}
+
+
+// Below go several tests which verify that JITing for various
+// configurations of interceptor and explicit fields works fine
+// (those cases are special cased to get better performance).
+
+static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ return v8_str("x")->Equals(name)
+ ? v8::Integer::New(42) : v8::Handle<v8::Value>();
+}
+
+
+THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "var result = 0;"
+ "o.y = 239;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.y;"
+ "}",
+ 239);
+}
+
+
+THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "var result = 0;"
+ "o.__proto__ = { 'y': 239 };"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.y + o.x;"
+ "}",
+ 239 + 42);
+}
+
+
+THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "var result = 0;"
+ "o.__proto__.y = 239;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.y + o.x;"
+ "}",
+ 239 + 42);
+}
+
+
+THREADED_TEST(InterceptorLoadICUndefined) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = (o.y == undefined) ? 239 : 42;"
+ "}",
+ 239);
+}
+
+
+THREADED_TEST(InterceptorLoadICWithOverride) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "fst = new Object(); fst.__proto__ = o;"
+ "snd = new Object(); snd.__proto__ = fst;"
+ "var result1 = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result1 = snd.x;"
+ "}"
+ "fst.x = 239;"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = snd.x;"
+ "}"
+ "result + result1",
+ 239 + 42);
+}
+
+
+static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ CHECK(v8_str("x")->Equals(name));
+ return v8::Integer::New(0);
+}
+
+
+THREADED_TEST(InterceptorReturningZero) {
+ CheckInterceptorLoadIC(InterceptorLoadICGetter0,
+ "o.x == undefined ? 1 : 0",
+ 0);
}
@@ -6571,3 +6755,135 @@ TEST(ForceSetWithInterceptor) {
CHECK_EQ(1, force_set_set_count);
CHECK_EQ(6, force_set_get_count);
}
+
+
+THREADED_TEST(ForceDelete) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
+ LocalContext context(NULL, templ);
+ v8::Handle<v8::Object> global = context->Global();
+
+ // Ordinary properties
+ v8::Handle<v8::String> simple_property = v8::String::New("p");
+ global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
+ CHECK_EQ(4, global->Get(simple_property)->Int32Value());
+ // This should fail because the property is dont-delete.
+ CHECK(!global->Delete(simple_property));
+ CHECK_EQ(4, global->Get(simple_property)->Int32Value());
+ // This should succeed even though the property is dont-delete.
+ CHECK(global->ForceDelete(simple_property));
+ CHECK(global->Get(simple_property)->IsUndefined());
+}
+
+
+static int force_delete_interceptor_count = 0;
+static bool pass_on_delete = false;
+
+
+static v8::Handle<v8::Boolean> ForceDeleteDeleter(
+ v8::Local<v8::String> name,
+ const v8::AccessorInfo& info) {
+ force_delete_interceptor_count++;
+ if (pass_on_delete) {
+ return v8::Handle<v8::Boolean>();
+ } else {
+ return v8::True();
+ }
+}
+
+
+THREADED_TEST(ForceDeleteWithInterceptor) {
+ force_delete_interceptor_count = 0;
+ pass_on_delete = false;
+
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
+ LocalContext context(NULL, templ);
+ v8::Handle<v8::Object> global = context->Global();
+
+ v8::Handle<v8::String> some_property = v8::String::New("a");
+ global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
+
+ // Deleting a property should get intercepted and nothing should
+ // happen.
+ CHECK_EQ(0, force_delete_interceptor_count);
+ CHECK(global->Delete(some_property));
+ CHECK_EQ(1, force_delete_interceptor_count);
+ CHECK_EQ(42, global->Get(some_property)->Int32Value());
+ // Deleting the property when the interceptor returns an empty
+ // handle should not delete the property since it is DontDelete.
+ pass_on_delete = true;
+ CHECK(!global->Delete(some_property));
+ CHECK_EQ(2, force_delete_interceptor_count);
+ CHECK_EQ(42, global->Get(some_property)->Int32Value());
+ // Forcing the property to be deleted should delete the value
+ // without calling the interceptor.
+ CHECK(global->ForceDelete(some_property));
+ CHECK(global->Get(some_property)->IsUndefined());
+ CHECK_EQ(2, force_delete_interceptor_count);
+}
+
+
+v8::Persistent<Context> calling_context0;
+v8::Persistent<Context> calling_context1;
+v8::Persistent<Context> calling_context2;
+
+
+// Check that the call to the callback is initiated in
+// calling_context2, the directly calling context is calling_context1
+// and the callback itself is in calling_context0.
+static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
+ ApiTestFuzzer::Fuzz();
+ CHECK(Context::GetCurrent() == calling_context0);
+ CHECK(Context::GetCalling() == calling_context1);
+ CHECK(Context::GetEntered() == calling_context2);
+ return v8::Integer::New(42);
+}
+
+
+THREADED_TEST(GetCallingContext) {
+ v8::HandleScope scope;
+
+ calling_context0 = Context::New();
+ calling_context1 = Context::New();
+ calling_context2 = Context::New();
+
+ // Allow cross-domain access.
+ Local<String> token = v8_str("<security token>");
+ calling_context0->SetSecurityToken(token);
+ calling_context1->SetSecurityToken(token);
+ calling_context2->SetSecurityToken(token);
+
+ // Create an object with a C++ callback in context0.
+ calling_context0->Enter();
+ Local<v8::FunctionTemplate> callback_templ =
+ v8::FunctionTemplate::New(GetCallingContextCallback);
+ calling_context0->Global()->Set(v8_str("callback"),
+ callback_templ->GetFunction());
+ calling_context0->Exit();
+
+ // Expose context0 in context1 and setup a function that calls the
+ // callback function.
+ calling_context1->Enter();
+ calling_context1->Global()->Set(v8_str("context0"),
+ calling_context0->Global());
+ CompileRun("function f() { context0.callback() }");
+ calling_context1->Exit();
+
+ // Expose context1 in context2 and call the callback function in
+ // context0 indirectly through f in context1.
+ calling_context2->Enter();
+ calling_context2->Global()->Set(v8_str("context1"),
+ calling_context1->Global());
+ CompileRun("context1.f()");
+ calling_context2->Exit();
+
+ // Dispose the contexts to allow them to be garbage collected.
+ calling_context0.Dispose();
+ calling_context1.Dispose();
+ calling_context2.Dispose();
+ calling_context0.Clear();
+ calling_context1.Clear();
+ calling_context2.Clear();
+}
diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc
new file mode 100644
index 000000000..43ba4e913
--- /dev/null
+++ b/deps/v8/test/cctest/test-assembler-x64.cc
@@ -0,0 +1,251 @@
+// 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::Operand;
+using v8::internal::Immediate;
+using v8::internal::Label;
+using v8::internal::rax;
+using v8::internal::rsi;
+using v8::internal::rdi;
+using v8::internal::rbp;
+using v8::internal::rsp;
+using v8::internal::FUNCTION_CAST;
+using v8::internal::CodeDesc;
+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 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)();
+typedef int (*F1)(int x);
+typedef int (*F2)(int x, int y);
+
+#define __ assm.
+
+
+TEST(AssemblerX64ReturnOperation) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+
+ // Assemble a simple function that copies argument 2 and returns it.
+ __ movq(rax, rsi);
+ __ nop();
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F2>(buffer)(3, 2);
+ CHECK_EQ(2, result);
+}
+
+TEST(AssemblerX64StackOperations) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+
+ // Assemble a simple function that copies argument 2 and returns it.
+ // We compile without stack frame pointers, so the gdb debugger shows
+ // 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)
+ __ pop(rax);
+ __ pop(rax);
+ __ pop(rax);
+ __ pop(rbp);
+ __ nop();
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F2>(buffer)(3, 2);
+ CHECK_EQ(2, result);
+}
+
+TEST(AssemblerX64ArithmeticOperations) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+
+ // Assemble a simple function that copies argument 2 and returns it.
+ __ movq(rax, rsi);
+ __ add(rax, rdi);
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F2>(buffer)(3, 2);
+ CHECK_EQ(5, result);
+}
+
+TEST(AssemblerX64MemoryOperands) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+
+ // 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)
+ const int kStackElementSize = 8;
+ __ movq(rax, Operand(rbp, -3 * kStackElementSize));
+ __ pop(rsi);
+ __ pop(rsi);
+ __ pop(rsi);
+ __ pop(rbp);
+ __ nop();
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F2>(buffer)(3, 2);
+ CHECK_EQ(3, result);
+}
+
+TEST(AssemblerX64ControlFlow) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+
+ // Assemble a simple function that copies argument 2 and returns it.
+ __ push(rbp);
+ __ movq(rbp, rsp);
+ __ movq(rax, rdi);
+ Label target;
+ __ jmp(&target);
+ __ movq(rax, rsi);
+ __ bind(&target);
+ __ pop(rbp);
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F2>(buffer)(3, 2);
+ CHECK_EQ(3, result);
+}
+
+TEST(AssemblerX64LoopImmediates) {
+ // Allocate an executable page of memory.
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
+ &actual_size,
+ true));
+ CHECK(buffer);
+ Assembler assm(buffer, actual_size);
+ // Assemble two loops using rax as counter, and verify the ending counts.
+ Label Fail;
+ __ movq(rax, Immediate(-3));
+ Label Loop1_test;
+ Label Loop1_body;
+ __ jmp(&Loop1_test);
+ __ bind(&Loop1_body);
+ __ add(rax, Immediate(7));
+ __ bind(&Loop1_test);
+ __ cmp(rax, Immediate(20));
+ __ j(less_equal, &Loop1_body);
+ // Did the loop terminate with the expected value?
+ __ cmp(rax, Immediate(25));
+ __ j(not_equal, &Fail);
+
+ Label Loop2_test;
+ Label Loop2_body;
+ __ movq(rax, Immediate(0x11FEED00));
+ __ jmp(&Loop2_test);
+ __ bind(&Loop2_body);
+ __ add(rax, Immediate(-0x1100));
+ __ bind(&Loop2_test);
+ __ cmp(rax, Immediate(0x11FE8000));
+ __ j(greater, &Loop2_body);
+ // Did the loop terminate with the expected value?
+ __ cmp(rax, Immediate(0x11FE7600));
+ __ j(not_equal, &Fail);
+
+ __ movq(rax, Immediate(1));
+ __ ret(0);
+ __ bind(&Fail);
+ __ movq(rax, Immediate(0));
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ // Call the function from C++.
+ int result = FUNCTION_CAST<F0>(buffer)();
+ CHECK_EQ(1, result);
+}
+#undef __
diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc
index 288efbaed..92f48e1cf 100644
--- a/deps/v8/test/cctest/test-debug.cc
+++ b/deps/v8/test/cctest/test-debug.cc
@@ -30,6 +30,7 @@
#include "v8.h"
#include "api.h"
+#include "compilation-cache.h"
#include "debug.h"
#include "platform.h"
#include "stub-cache.h"
@@ -370,7 +371,8 @@ static void PrepareStep(StepAction step_action) {
// This function is in namespace v8::internal to be friend with class
// v8::internal::Debug.
-namespace v8 { namespace internal { // NOLINT
+namespace v8 {
+namespace internal {
// Collect the currently debugged functions.
Handle<FixedArray> GetDebuggedFunctions() {
@@ -3311,6 +3313,82 @@ TEST(HiddenPrototypePropertyMirror) {
}
+static v8::Handle<v8::Value> ProtperyXNativeGetter(
+ v8::Local<v8::String> property, const v8::AccessorInfo& info) {
+ return v8::Integer::New(10);
+}
+
+
+TEST(NativeGetterPropertyMirror) {
+ // Create a V8 environment with debug access.
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ env.ExposeDebug();
+
+ v8::Handle<v8::String> name = v8::String::New("x");
+ // Create object with named accessor.
+ v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
+ named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
+ v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
+
+ // Create object with named property getter.
+ env->Global()->Set(v8::String::New("instance"), named->NewInstance());
+ CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
+
+ // Get mirror for the object with property getter.
+ CompileRun("instance_mirror = debug.MakeMirror(instance);");
+ CHECK(CompileRun(
+ "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
+
+ CompileRun("named_names = instance_mirror.propertyNames();");
+ CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
+ CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
+ CHECK(CompileRun(
+ "instance_mirror.property('x').value().isNumber()")->BooleanValue());
+ CHECK(CompileRun(
+ "instance_mirror.property('x').value().value() == 10")->BooleanValue());
+}
+
+
+static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
+ v8::Local<v8::String> property, const v8::AccessorInfo& info) {
+ return CompileRun("throw new Error('Error message');");
+}
+
+
+TEST(NativeGetterThrowingErrorPropertyMirror) {
+ // Create a V8 environment with debug access.
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ env.ExposeDebug();
+
+ v8::Handle<v8::String> name = v8::String::New("x");
+ // Create object with named accessor.
+ v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
+ named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
+ v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
+
+ // Create object with named property getter.
+ env->Global()->Set(v8::String::New("instance"), named->NewInstance());
+
+ // Get mirror for the object with property getter.
+ CompileRun("instance_mirror = debug.MakeMirror(instance);");
+ CHECK(CompileRun(
+ "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
+ CompileRun("named_names = instance_mirror.propertyNames();");
+ CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
+ CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
+ CHECK(CompileRun(
+ "instance_mirror.property('x').value().isError()")->BooleanValue());
+
+ // Check that the message is that passed to the Error constructor.
+ CHECK(CompileRun(
+ "instance_mirror.property('x').value().message() == 'Error message'")->
+ BooleanValue());
+}
+
+
+
// Multithreaded tests of JSON debugger protocol
// Support classes
@@ -4166,11 +4244,8 @@ TEST(DebuggerUnload) {
}
-// Debugger message handler which counts the number of times it is called.
-static int message_handler_hit_count = 0;
-static void MessageHandlerHitCount(const v8::Debug::Message& message) {
- message_handler_hit_count++;
-
+// Sends continue command to the debugger.
+static void SendContinueCommand() {
const int kBufferSize = 1000;
uint16_t buffer[kBufferSize];
const char* command_continue =
@@ -4182,6 +4257,15 @@ static void MessageHandlerHitCount(const v8::Debug::Message& message) {
}
+// Debugger message handler which counts the number of times it is called.
+static int message_handler_hit_count = 0;
+static void MessageHandlerHitCount(const v8::Debug::Message& message) {
+ message_handler_hit_count++;
+
+ SendContinueCommand();
+}
+
+
// Test clearing the debug message handler.
TEST(DebuggerClearMessageHandler) {
v8::HandleScope scope;
@@ -4525,6 +4609,8 @@ class EmptyExternalStringResource : public v8::String::ExternalStringResource {
TEST(DebugGetLoadedScripts) {
v8::HandleScope scope;
DebugLocalContext env;
+ env.ExposeDebug();
+
EmptyExternalStringResource source_ext_str;
v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
@@ -4538,11 +4624,15 @@ TEST(DebugGetLoadedScripts) {
i::FLAG_allow_natives_syntax = true;
CompileRun(
"var scripts = %DebugGetLoadedScripts();"
- "for (var i = 0; i < scripts.length; ++i) {"
- " scripts[i].line_ends;"
+ "var count = scripts.length;"
+ "for (var i = 0; i < count; ++i) {"
+ " scripts[i].line_ends;"
"}");
// Must not crash while accessing line_ends.
i::FLAG_allow_natives_syntax = allow_natives_syntax;
+
+ // Some scripts are retrieved - at least the number of native scripts.
+ CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
}
@@ -4574,7 +4664,6 @@ TEST(ScriptNameAndData) {
v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
script1->SetData(v8::String::New("data"));
script1->Run();
- v8::Script::Compile(script, &origin1)->Run();
v8::Local<v8::Function> f;
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
@@ -4583,6 +4672,15 @@ TEST(ScriptNameAndData) {
CHECK_EQ("name", last_script_name_hit);
CHECK_EQ("data", last_script_data_hit);
+ // Compile the same script again without setting data. As the compilation
+ // cache is disabled when debugging expect the data to be missing.
+ v8::Script::Compile(script, &origin1)->Run();
+ f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+ f->Call(env->Global(), 0, NULL);
+ CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ("name", last_script_name_hit);
+ CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
+
v8::Local<v8::String> data_obj_source = v8::String::New(
"({ a: 'abc',\n"
" b: 123,\n"
@@ -4595,7 +4693,7 @@ TEST(ScriptNameAndData) {
script2->SetData(data_obj);
f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
f->Call(env->Global(), 0, NULL);
- CHECK_EQ(2, break_point_hit_count);
+ CHECK_EQ(3, break_point_hit_count);
CHECK_EQ("new name", last_script_name_hit);
CHECK_EQ("abc 123", last_script_data_hit);
}
@@ -4612,16 +4710,9 @@ static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
expected_context_data));
message_handler_hit_count++;
- const int kBufferSize = 1000;
- uint16_t buffer[kBufferSize];
- const char* command_continue =
- "{\"seq\":0,"
- "\"type\":\"request\","
- "\"command\":\"continue\"}";
-
// Send a continue command for break events.
if (message.GetEvent() == v8::Break) {
- v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
+ SendContinueCommand();
}
}
@@ -4679,4 +4770,418 @@ TEST(ContextData) {
// Two times compile event and two times break event.
CHECK_GT(message_handler_hit_count, 4);
+
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
+// Debug message handler which issues a debug break when it hits a break event.
+static int message_handler_break_hit_count = 0;
+static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
+ // Schedule a debug break for break events.
+ if (message.IsEvent() && message.GetEvent() == v8::Break) {
+ message_handler_break_hit_count++;
+ if (message_handler_break_hit_count == 1) {
+ v8::Debug::DebugBreak();
+ }
+ }
+
+ // Issue a continue command if this event will not cause the VM to start
+ // running.
+ if (!message.WillStartRunning()) {
+ SendContinueCommand();
+ }
+}
+
+
+// Test that a debug break can be scheduled while in a message handler.
+TEST(DebugBreakInMessageHandler) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
+
+ // Test functions.
+ const char* script = "function f() { debugger; } function g() { }";
+ CompileRun(script);
+ v8::Local<v8::Function> f =
+ v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+ v8::Local<v8::Function> g =
+ v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
+
+ // Call f then g. The debugger statement in f will casue a break which will
+ // cause another break.
+ f->Call(env->Global(), 0, NULL);
+ CHECK_EQ(2, message_handler_break_hit_count);
+ // Calling g will not cause any additional breaks.
+ g->Call(env->Global(), 0, NULL);
+ CHECK_EQ(2, message_handler_break_hit_count);
+}
+
+
+// Debug event handler which gets the function on the top frame and schedules a
+// break a number of times.
+static void DebugEventDebugBreak(
+ v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+
+ if (event == v8::Break) {
+ break_point_hit_count++;
+
+ // Get the name of the top frame function.
+ if (!frame_function_name.IsEmpty()) {
+ // Get the name of the function.
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { exec_state };
+ v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
+ argc, argv);
+ if (result->IsUndefined()) {
+ last_function_hit[0] = '\0';
+ } else {
+ CHECK(result->IsString());
+ v8::Handle<v8::String> function_name(result->ToString());
+ function_name->WriteAscii(last_function_hit);
+ }
+ }
+
+ // Keep forcing breaks.
+ if (break_point_hit_count < 20) {
+ v8::Debug::DebugBreak();
+ }
+ }
+}
+
+
+TEST(RegExpDebugBreak) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ i::FLAG_regexp_native = true;
+
+ // Create a function for checking the function when hitting a break point.
+ frame_function_name = CompileFunction(&env,
+ frame_function_name_source,
+ "frame_function_name");
+
+ // Test RegExp which matches white spaces and comments at the begining of a
+ // source line.
+ const char* script =
+ "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
+ "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
+
+ v8::Local<v8::Function> f = CompileFunction(script, "f");
+ const int argc = 1;
+ v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
+ v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
+ CHECK_EQ(12, result->Int32Value());
+
+ v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
+ v8::Debug::DebugBreak();
+ result = f->Call(env->Global(), argc, argv);
+
+ CHECK_EQ(20, break_point_hit_count);
+ CHECK_EQ("exec", last_function_hit);
+}
+
+
+// Common part of EvalContextData and NestedBreakEventContextData tests.
+static void ExecuteScriptForContextCheck() {
+ // Create a context.
+ v8::Persistent<v8::Context> context_1;
+ v8::Handle<v8::ObjectTemplate> global_template =
+ v8::Handle<v8::ObjectTemplate>();
+ v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
+ context_1 = v8::Context::New(NULL, global_template, global_object);
+
+ // Default data value is undefined.
+ CHECK(context_1->GetData()->IsUndefined());
+
+ // Set and check a data value.
+ v8::Handle<v8::Value> data_1 = v8::Number::New(1);
+ context_1->SetData(data_1);
+ CHECK(context_1->GetData()->StrictEquals(data_1));
+
+ // Simple test function with eval that causes a break.
+ const char* source = "function f() { eval('debugger;'); }";
+
+ // Enter and run function in the context.
+ {
+ v8::Context::Scope context_scope(context_1);
+ expected_context = context_1;
+ expected_context_data = data_1;
+ v8::Local<v8::Function> f = CompileFunction(source, "f");
+ f->Call(context_1->Global(), 0, NULL);
+ }
+}
+
+
+// Test which creates a context and sets embedder data on it. Checks that this
+// data is set correctly and that when the debug message handler is called for
+// break event in an eval statement the expected context is the one returned by
+// Message.GetEventContext.
+TEST(EvalContextData) {
+ v8::HandleScope scope;
+ v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
+
+ ExecuteScriptForContextCheck();
+
+ // One time compile event and one time break event.
+ CHECK_GT(message_handler_hit_count, 2);
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
+static bool sent_eval = false;
+static int break_count = 0;
+static int continue_command_send_count = 0;
+// Check that the expected context is the one generating the debug event
+// including the case of nested break event.
+static void DebugEvalContextCheckMessageHandler(
+ const v8::Debug::Message& message) {
+ CHECK(message.GetEventContext() == expected_context);
+ CHECK(message.GetEventContext()->GetData()->StrictEquals(
+ expected_context_data));
+ message_handler_hit_count++;
+
+ if (message.IsEvent() && message.GetEvent() == v8::Break) {
+ break_count++;
+ if (!sent_eval) {
+ sent_eval = true;
+
+ const int kBufferSize = 1000;
+ uint16_t buffer[kBufferSize];
+ const char* eval_command =
+ "{\"seq\":0,"
+ "\"type\":\"request\","
+ "\"command\":\"evaluate\","
+ "arguments:{\"expression\":\"debugger;\","
+ "\"global\":true,\"disable_break\":false}}";
+
+ // Send evaluate command.
+ v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
+ return;
+ } else {
+ // It's a break event caused by the evaluation request above.
+ SendContinueCommand();
+ continue_command_send_count++;
+ }
+ } else if (message.IsResponse() && continue_command_send_count < 2) {
+ // Response to the evaluation request. We're still on the breakpoint so
+ // send continue.
+ SendContinueCommand();
+ continue_command_send_count++;
+ }
+}
+
+
+// Tests that context returned for break event is correct when the event occurs
+// in 'evaluate' debugger request.
+TEST(NestedBreakEventContextData) {
+ v8::HandleScope scope;
+ break_count = 0;
+ message_handler_hit_count = 0;
+ v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
+
+ ExecuteScriptForContextCheck();
+
+ // One time compile event and two times break event.
+ CHECK_GT(message_handler_hit_count, 3);
+
+ // One break from the source and another from the evaluate request.
+ CHECK_EQ(break_count, 2);
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
+// Debug event listener which counts the script collected events.
+int script_collected_count = 0;
+static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ // Count the number of breaks.
+ if (event == v8::ScriptCollected) {
+ script_collected_count++;
+ }
+}
+
+
+// Test that scripts collected are reported through the debug event listener.
+TEST(ScriptCollectedEvent) {
+ break_point_hit_count = 0;
+ script_collected_count = 0;
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Request the loaded scripts to initialize the debugger script cache.
+ Debug::GetLoadedScripts();
+
+ // Do garbage collection to ensure that only the script in this test will be
+ // collected afterwards.
+ Heap::CollectAllGarbage();
+
+ script_collected_count = 0;
+ v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
+ v8::Undefined());
+ {
+ v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
+ v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
+ }
+
+ // Do garbage collection to collect the script above which is no longer
+ // referenced.
+ Heap::CollectAllGarbage();
+
+ CHECK_EQ(2, script_collected_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
+// Debug event listener which counts the script collected events.
+int script_collected_message_count = 0;
+static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
+ // Count the number of scripts collected.
+ if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
+ script_collected_message_count++;
+ v8::Handle<v8::Context> context = message.GetEventContext();
+ CHECK(context.IsEmpty());
+ }
+}
+
+
+// Test that GetEventContext doesn't fail and return empty handle for
+// ScriptCollected events.
+TEST(ScriptCollectedEventContext) {
+ script_collected_message_count = 0;
+ v8::HandleScope scope;
+
+ { // Scope for the DebugLocalContext.
+ DebugLocalContext env;
+
+ // Request the loaded scripts to initialize the debugger script cache.
+ Debug::GetLoadedScripts();
+
+ // Do garbage collection to ensure that only the script in this test will be
+ // collected afterwards.
+ Heap::CollectAllGarbage();
+
+ v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
+ {
+ v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
+ v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
+ }
+ }
+
+ // Do garbage collection to collect the script above which is no longer
+ // referenced.
+ Heap::CollectAllGarbage();
+
+ CHECK_EQ(2, script_collected_message_count);
+
+ v8::Debug::SetMessageHandler2(NULL);
+}
+
+
+// Debug event listener which counts the after compile events.
+int after_compile_message_count = 0;
+static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
+ // Count the number of scripts collected.
+ if (message.IsEvent()) {
+ if (message.GetEvent() == v8::AfterCompile) {
+ after_compile_message_count++;
+ } else if (message.GetEvent() == v8::Break) {
+ SendContinueCommand();
+ }
+ }
+}
+
+
+// Tests that after compile event is sent as many times as there are scripts
+// compiled.
+TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ after_compile_message_count = 0;
+ const char* script = "var a=1";
+
+ v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
+ v8::Script::Compile(v8::String::New(script))->Run();
+ v8::Debug::SetMessageHandler2(NULL);
+
+ v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
+ v8::Debug::DebugBreak();
+ v8::Script::Compile(v8::String::New(script))->Run();
+
+ // Setting listener to NULL should cause debugger unload.
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+
+ // Compilation cache should be disabled when debugger is active.
+ CHECK_EQ(2, after_compile_message_count);
+}
+
+
+// Tests that break event is sent when message handler is reset.
+TEST(BreakMessageWhenMessageHandlerIsReset) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ after_compile_message_count = 0;
+ const char* script = "function f() {};";
+
+ v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
+ v8::Script::Compile(v8::String::New(script))->Run();
+ v8::Debug::SetMessageHandler2(NULL);
+
+ v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
+ v8::Debug::DebugBreak();
+ v8::Local<v8::Function> f =
+ v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+ f->Call(env->Global(), 0, NULL);
+
+ // Setting message handler to NULL should cause debugger unload.
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+
+ // Compilation cache should be disabled when debugger is active.
+ CHECK_EQ(1, after_compile_message_count);
+}
+
+
+static int exception_event_count = 0;
+static void ExceptionMessageHandler(const v8::Debug::Message& message) {
+ if (message.IsEvent() && message.GetEvent() == v8::Exception) {
+ exception_event_count++;
+ SendContinueCommand();
+ }
+}
+
+
+// Tests that exception event is sent when message handler is reset.
+TEST(ExceptionMessageWhenMessageHandlerIsReset) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ exception_event_count = 0;
+ const char* script = "function f() {throw new Error()};";
+
+ v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
+ v8::Script::Compile(v8::String::New(script))->Run();
+ v8::Debug::SetMessageHandler2(NULL);
+
+ v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
+ v8::Local<v8::Function> f =
+ v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+ f->Call(env->Global(), 0, NULL);
+
+ // Setting message handler to NULL should cause debugger unload.
+ v8::Debug::SetMessageHandler2(NULL);
+ CheckDebuggerUnloaded();
+
+ CHECK_EQ(1, exception_event_count);
}
diff --git a/deps/v8/test/cctest/test-func-name-inference.cc b/deps/v8/test/cctest/test-func-name-inference.cc
index d91f75fa0..1bfc8834a 100644
--- a/deps/v8/test/cctest/test-func-name-inference.cc
+++ b/deps/v8/test/cctest/test-func-name-inference.cc
@@ -32,15 +32,18 @@
#include "cctest.h"
+using ::v8::internal::CStrVector;
+using ::v8::internal::Factory;
using ::v8::internal::Handle;
+using ::v8::internal::Heap;
using ::v8::internal::JSFunction;
using ::v8::internal::Object;
+using ::v8::internal::Runtime;
using ::v8::internal::Script;
+using ::v8::internal::SmartPointer;
using ::v8::internal::SharedFunctionInfo;
using ::v8::internal::String;
-namespace i = ::v8::internal;
-
static v8::Persistent<v8::Context> env;
@@ -66,19 +69,19 @@ static void CheckFunctionName(v8::Handle<v8::Script> script,
// Find the position of a given func source substring in the source.
Handle<String> func_pos_str =
- i::Factory::NewStringFromAscii(i::CStrVector(func_pos_src));
- int func_pos = i::Runtime::StringMatch(script_src, func_pos_str, 0);
+ Factory::NewStringFromAscii(CStrVector(func_pos_src));
+ int func_pos = Runtime::StringMatch(script_src, func_pos_str, 0);
CHECK_NE(0, func_pos);
// Obtain SharedFunctionInfo for the function.
Object* shared_func_info_ptr =
- i::Runtime::FindSharedFunctionInfoInScript(i_script, func_pos);
- CHECK(shared_func_info_ptr != i::Heap::undefined_value());
+ Runtime::FindSharedFunctionInfoInScript(i_script, func_pos);
+ CHECK(shared_func_info_ptr != Heap::undefined_value());
Handle<SharedFunctionInfo> shared_func_info(
SharedFunctionInfo::cast(shared_func_info_ptr));
// Verify inferred function name.
- i::SmartPointer<char> inferred_name =
+ SmartPointer<char> inferred_name =
shared_func_info->inferred_name()->ToCString();
CHECK_EQ(ref_inferred_name, *inferred_name);
}
diff --git a/deps/v8/test/cctest/test-hashmap.cc b/deps/v8/test/cctest/test-hashmap.cc
index 954dbe103..70213c9aa 100644
--- a/deps/v8/test/cctest/test-hashmap.cc
+++ b/deps/v8/test/cctest/test-hashmap.cc
@@ -38,20 +38,29 @@ static bool DefaultMatchFun(void* a, void* b) {
}
+typedef uint32_t (*IntKeyHash)(uint32_t key);
+
+
class IntSet {
public:
- IntSet() : map_(DefaultMatchFun) {}
+ explicit IntSet(IntKeyHash hash) : hash_(hash), map_(DefaultMatchFun) {}
void Insert(int x) {
CHECK_NE(0, x); // 0 corresponds to (void*)NULL - illegal key value
- HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), Hash(x), true);
+ HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), hash_(x), true);
CHECK(p != NULL); // insert is set!
CHECK_EQ(reinterpret_cast<void*>(x), p->key);
// we don't care about p->value
}
+ void Remove(int x) {
+ CHECK_NE(0, x); // 0 corresponds to (void*)NULL - illegal key value
+ map_.Remove(reinterpret_cast<void*>(x), hash_(x));
+ }
+
bool Present(int x) {
- HashMap::Entry* p = map_.Lookup(reinterpret_cast<void*>(x), Hash(x), false);
+ HashMap::Entry* p =
+ map_.Lookup(reinterpret_cast<void*>(x), hash_(x), false);
if (p != NULL) {
CHECK_EQ(reinterpret_cast<void*>(x), p->key);
}
@@ -72,13 +81,17 @@ class IntSet {
}
private:
+ IntKeyHash hash_;
HashMap map_;
- static uint32_t Hash(uint32_t key) { return key * 23; }
};
-TEST(Set) {
- IntSet set;
+static uint32_t Hash(uint32_t key) { return 23; }
+static uint32_t CollisionHash(uint32_t key) { return key & 0x3; }
+
+
+void TestSet(IntKeyHash hash, int size) {
+ IntSet set(hash);
CHECK_EQ(0, set.occupancy());
set.Insert(1);
@@ -96,6 +109,18 @@ TEST(Set) {
CHECK(!set.Present(4));
CHECK_EQ(3, set.occupancy());
+ set.Remove(1);
+ CHECK(!set.Present(1));
+ CHECK(set.Present(2));
+ CHECK(set.Present(3));
+ CHECK_EQ(2, set.occupancy());
+
+ set.Remove(3);
+ CHECK(!set.Present(1));
+ CHECK(set.Present(2));
+ CHECK(!set.Present(3));
+ CHECK_EQ(1, set.occupancy());
+
set.Clear();
CHECK_EQ(0, set.occupancy());
@@ -103,21 +128,49 @@ TEST(Set) {
const int start = 453;
const int factor = 13;
const int offset = 7;
- const uint32_t n = 1000;
+ const uint32_t n = size;
int x = start;
for (uint32_t i = 0; i < n; i++) {
CHECK_EQ(i, static_cast<double>(set.occupancy()));
set.Insert(x);
- x = x*factor + offset;
+ x = x * factor + offset;
}
+ CHECK_EQ(n, static_cast<double>(set.occupancy()));
// Verify the same sequence of values.
x = start;
for (uint32_t i = 0; i < n; i++) {
CHECK(set.Present(x));
- x = x*factor + offset;
+ x = x * factor + offset;
}
-
CHECK_EQ(n, static_cast<double>(set.occupancy()));
+
+ // Remove all these values.
+ x = start;
+ for (uint32_t i = 0; i < n; i++) {
+ CHECK_EQ(n - i, static_cast<double>(set.occupancy()));
+ CHECK(set.Present(x));
+ set.Remove(x);
+ CHECK(!set.Present(x));
+ x = x * factor + offset;
+
+ // Verify the the expected values are still there.
+ int y = start;
+ for (uint32_t j = 0; j < n; j++) {
+ if (j <= i) {
+ CHECK(!set.Present(y));
+ } else {
+ CHECK(set.Present(y));
+ }
+ y = y * factor + offset;
+ }
+ }
+ CHECK_EQ(0, set.occupancy());
+}
+
+
+TEST(Set) {
+ TestSet(Hash, 100);
+ TestSet(CollisionHash, 50);
}
diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc
index e35ac5fba..515657f71 100644
--- a/deps/v8/test/cctest/test-heap.cc
+++ b/deps/v8/test/cctest/test-heap.cc
@@ -36,34 +36,43 @@ TEST(HeapMaps) {
InitializeVM();
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
- CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kHeaderSize);
+ CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kAlignedSize);
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
- SeqTwoByteString::kHeaderSize);
+ SeqTwoByteString::kAlignedSize);
}
static void CheckOddball(Object* obj, const char* string) {
CHECK(obj->IsOddball());
+#ifndef V8_HOST_ARCH_64_BIT
+// TODO(X64): Reenable when native builtins work.
bool exc;
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+#endif // V8_HOST_ARCH_64_BIT
}
static void CheckSmi(int value, const char* string) {
+#ifndef V8_HOST_ARCH_64_BIT
+// TODO(X64): Reenable when native builtins work.
bool exc;
Object* print_string =
*Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+#endif // V8_HOST_ARCH_64_BIT
}
static void CheckNumber(double value, const char* string) {
Object* obj = Heap::NumberFromDouble(value);
CHECK(obj->IsNumber());
+#ifndef V8_HOST_ARCH_64_BIT
+// TODO(X64): Reenable when native builtins work.
bool exc;
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
+#endif // V8_HOST_ARCH_64_BIT
}
@@ -178,12 +187,16 @@ TEST(HeapObjects) {
TEST(Tagging) {
InitializeVM();
+ int request = 24;
+ ASSERT_EQ(request, OBJECT_SIZE_ALIGN(request));
CHECK(Smi::FromInt(42)->IsSmi());
- CHECK(Failure::RetryAfterGC(12, NEW_SPACE)->IsFailure());
- CHECK_EQ(12, Failure::RetryAfterGC(12, NEW_SPACE)->requested());
- CHECK_EQ(NEW_SPACE, Failure::RetryAfterGC(12, NEW_SPACE)->allocation_space());
+ CHECK(Failure::RetryAfterGC(request, NEW_SPACE)->IsFailure());
+ CHECK_EQ(request, Failure::RetryAfterGC(request, NEW_SPACE)->requested());
+ CHECK_EQ(NEW_SPACE,
+ Failure::RetryAfterGC(request, NEW_SPACE)->allocation_space());
CHECK_EQ(OLD_POINTER_SPACE,
- Failure::RetryAfterGC(12, OLD_POINTER_SPACE)->allocation_space());
+ Failure::RetryAfterGC(request,
+ OLD_POINTER_SPACE)->allocation_space());
CHECK(Failure::Exception()->IsFailure());
CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
@@ -315,7 +328,7 @@ static bool WeakPointerCleared = false;
static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
void* id) {
USE(handle);
- if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true;
+ if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
}
@@ -385,7 +398,7 @@ TEST(WeakGlobalHandlesMark) {
static void TestDeleteWeakGlobalHandleCallback(
v8::Persistent<v8::Value> handle,
void* id) {
- if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true;
+ if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
handle.Dispose();
}
@@ -540,7 +553,7 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(first));
// delete first
- CHECK(obj->DeleteProperty(first));
+ CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
// add first and then second
@@ -550,9 +563,9 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(second));
// delete first and then second
- CHECK(obj->DeleteProperty(first));
+ CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(second));
- CHECK(obj->DeleteProperty(second));
+ CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second));
@@ -563,9 +576,9 @@ TEST(ObjectProperties) {
CHECK(obj->HasLocalProperty(second));
// delete second and then first
- CHECK(obj->DeleteProperty(second));
+ CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(first));
- CHECK(obj->DeleteProperty(first));
+ CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second));
diff --git a/deps/v8/test/cctest/test-list.cc b/deps/v8/test/cctest/test-list.cc
index 838a45d0d..624b6e939 100644
--- a/deps/v8/test/cctest/test-list.cc
+++ b/deps/v8/test/cctest/test-list.cc
@@ -65,3 +65,37 @@ TEST(ListAdd) {
list.Add(list[0]);
CHECK_EQ(1, list[4]);
}
+
+// Test that we can add all elements from a list to another list.
+TEST(ListAddAll) {
+ List<int, ZeroingAllocationPolicy> list(4);
+ list.Add(0);
+ list.Add(1);
+ list.Add(2);
+
+ CHECK_EQ(3, list.length());
+ for (int i = 0; i < 3; i++) {
+ CHECK_EQ(i, list[i]);
+ }
+
+ List<int, ZeroingAllocationPolicy> other_list(4);
+
+ // Add no elements to list since other_list is empty.
+ list.AddAll(other_list);
+ CHECK_EQ(3, list.length());
+ for (int i = 0; i < 3; i++) {
+ CHECK_EQ(i, list[i]);
+ }
+
+ // Add three elements to other_list.
+ other_list.Add(0);
+ other_list.Add(1);
+ other_list.Add(2);
+
+ // Copy the three elements from other_list to list.
+ list.AddAll(other_list);
+ CHECK_EQ(6, list.length());
+ for (int i = 0; i < 6; i++) {
+ CHECK_EQ(i % 3, list[i]);
+ }
+}
diff --git a/deps/v8/test/cctest/test-log-ia32.cc b/deps/v8/test/cctest/test-log-ia32.cc
index 43cb294b1..a40a800ee 100644
--- a/deps/v8/test/cctest/test-log-ia32.cc
+++ b/deps/v8/test/cctest/test-log-ia32.cc
@@ -13,6 +13,7 @@
#include "top.h"
#include "cctest.h"
#include "disassembler.h"
+#include "register-allocator-inl.h"
using v8::Function;
using v8::Local;
@@ -36,13 +37,11 @@ static v8::Persistent<v8::Context> env;
static struct {
- StackTracer* tracer;
TickSample* sample;
-} trace_env = { NULL, NULL };
+} trace_env = { NULL };
-static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
- trace_env.tracer = tracer;
+static void InitTraceEnv(TickSample* sample) {
trace_env.sample = sample;
}
@@ -52,7 +51,7 @@ static void DoTrace(Address fp) {
// sp is only used to define stack high bound
trace_env.sample->sp =
reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
- trace_env.tracer->Trace(trace_env.sample);
+ StackTracer::Trace(trace_env.sample);
}
@@ -98,6 +97,8 @@ class TraceExtension : public v8::Extension {
v8::Handle<String> name);
static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
+ static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
+ static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
private:
static Address GetFP(const v8::Arguments& args);
static const char* kSource;
@@ -106,8 +107,9 @@ class TraceExtension : public v8::Extension {
const char* TraceExtension::kSource =
"native function trace();"
- "native function js_trace();";
-
+ "native function js_trace();"
+ "native function js_entry_sp();"
+ "native function js_entry_sp_level2();";
v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
v8::Handle<String> name) {
@@ -115,6 +117,10 @@ v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
return v8::FunctionTemplate::New(TraceExtension::Trace);
} else if (name->Equals(String::New("js_trace"))) {
return v8::FunctionTemplate::New(TraceExtension::JSTrace);
+ } else if (name->Equals(String::New("js_entry_sp"))) {
+ return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
+ } else if (name->Equals(String::New("js_entry_sp_level2"))) {
+ return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
} else {
CHECK(false);
return v8::Handle<v8::FunctionTemplate>();
@@ -142,6 +148,34 @@ v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
}
+static Address GetJsEntrySp() {
+ CHECK_NE(NULL, Top::GetCurrentThread());
+ return Top::js_entry_sp(Top::GetCurrentThread());
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) {
+ CHECK_NE(0, GetJsEntrySp());
+ return v8::Undefined();
+}
+
+
+static void CompileRun(const char* source) {
+ Script::Compile(String::New(source))->Run();
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
+ const v8::Arguments& args) {
+ v8::HandleScope scope;
+ const Address js_entry_sp = GetJsEntrySp();
+ CHECK_NE(0, js_entry_sp);
+ CompileRun("js_entry_sp();");
+ CHECK_EQ(js_entry_sp, GetJsEntrySp());
+ return v8::Undefined();
+}
+
+
static TraceExtension kTraceExtension;
v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
@@ -163,11 +197,6 @@ static Handle<JSFunction> CompileFunction(const char* source) {
}
-static void CompileRun(const char* source) {
- Script::Compile(String::New(source))->Run();
-}
-
-
static Local<Value> GetGlobalProperty(const char* name) {
return env->Global()->Get(String::New(name));
}
@@ -198,7 +227,8 @@ static Handle<v8::internal::String> NewString(const char* s) {
}
-namespace v8 { namespace internal {
+namespace v8 {
+namespace internal {
class CodeGeneratorPatcher {
public:
@@ -253,8 +283,7 @@ static void CreateTraceCallerFunction(const char* func_name,
TEST(CFromJSStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
InitializeVM();
v8::HandleScope scope;
@@ -275,8 +304,7 @@ TEST(CFromJSStackTrace) {
TEST(PureJSStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
InitializeVM();
v8::HandleScope scope;
@@ -321,11 +349,22 @@ static int CFunc(int depth) {
TEST(PureCStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
// Check that sampler doesn't crash
CHECK_EQ(10, CFunc(10));
}
+TEST(JsEntrySp) {
+ InitializeVM();
+ v8::HandleScope scope;
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("a = 1; b = a + 1;");
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("js_entry_sp();");
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("js_entry_sp_level2();");
+ CHECK_EQ(0, GetJsEntrySp());
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/test/cctest/test-log-utils.cc b/deps/v8/test/cctest/test-log-utils.cc
new file mode 100644
index 000000000..64e590099
--- /dev/null
+++ b/deps/v8/test/cctest/test-log-utils.cc
@@ -0,0 +1,132 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+//
+// Tests of logging utilities from log-utils.h
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+#include "v8.h"
+
+#include "log-utils.h"
+#include "cctest.h"
+
+using v8::internal::EmbeddedVector;
+using v8::internal::LogDynamicBuffer;
+using v8::internal::Vector;
+
+// Fills 'ref_buffer' with test data: a sequence of two-digit
+// hex numbers: '0001020304...'. Then writes 'ref_buffer' contents to 'dynabuf'.
+static void WriteData(LogDynamicBuffer* dynabuf, Vector<char>* ref_buffer) {
+ static const char kHex[] = "0123456789ABCDEF";
+ CHECK_GT(ref_buffer->length(), 0);
+ CHECK_GT(513, ref_buffer->length());
+ for (int i = 0, half_len = ref_buffer->length() >> 1; i < half_len; ++i) {
+ (*ref_buffer)[i << 1] = kHex[i >> 4];
+ (*ref_buffer)[(i << 1) + 1] = kHex[i & 15];
+ }
+ if (ref_buffer->length() & 1) {
+ ref_buffer->last() = kHex[ref_buffer->length() >> 5];
+ }
+ CHECK_EQ(ref_buffer->length(),
+ dynabuf->Write(ref_buffer->start(), ref_buffer->length()));
+}
+
+
+static int ReadData(
+ LogDynamicBuffer* dynabuf, int start_pos, i::Vector<char>* buffer) {
+ return dynabuf->Read(start_pos, buffer->start(), buffer->length());
+}
+
+
+// Helper function used by CHECK_EQ to compare Vectors. Templatized to
+// accept both "char" and "const char" vector contents.
+template <typename E, typename V>
+static inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const Vector<E>& expected,
+ const char* value_source,
+ const Vector<V>& value) {
+ if (expected.length() != value.length()) {
+ V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n"
+ "# Vectors lengths differ: %d expected, %d found",
+ expected_source, value_source,
+ expected.length(), value.length());
+ }
+ if (strncmp(expected.start(), value.start(), expected.length()) != 0) {
+ V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n"
+ "# Vectors contents differ:\n"
+ "# Expected: %.*s\n"
+ "# Found: %.*s",
+ expected_source, value_source,
+ expected.length(), expected.start(),
+ value.length(), value.start());
+ }
+}
+
+
+TEST(DynaBufSingleBlock) {
+ LogDynamicBuffer dynabuf(32, 32, "", 0);
+ EmbeddedVector<char, 32> ref_buf;
+ WriteData(&dynabuf, &ref_buf);
+ EmbeddedVector<char, 32> buf;
+ CHECK_EQ(32, dynabuf.Read(0, buf.start(), buf.length()));
+ CHECK_EQ(32, ReadData(&dynabuf, 0, &buf));
+ CHECK_EQ(ref_buf, buf);
+
+ // Verify that we can't read and write past the end.
+ CHECK_EQ(0, dynabuf.Read(32, buf.start(), buf.length()));
+ CHECK_EQ(0, dynabuf.Write(buf.start(), buf.length()));
+}
+
+
+TEST(DynaBufCrossBlocks) {
+ LogDynamicBuffer dynabuf(32, 128, "", 0);
+ EmbeddedVector<char, 48> ref_buf;
+ WriteData(&dynabuf, &ref_buf);
+ CHECK_EQ(48, dynabuf.Write(ref_buf.start(), ref_buf.length()));
+ // Verify that we can't write data when remaining buffer space isn't enough.
+ CHECK_EQ(0, dynabuf.Write(ref_buf.start(), ref_buf.length()));
+ EmbeddedVector<char, 48> buf;
+ CHECK_EQ(48, ReadData(&dynabuf, 0, &buf));
+ CHECK_EQ(ref_buf, buf);
+ CHECK_EQ(48, ReadData(&dynabuf, 48, &buf));
+ CHECK_EQ(ref_buf, buf);
+ CHECK_EQ(0, ReadData(&dynabuf, 48 * 2, &buf));
+}
+
+
+TEST(DynaBufReadTruncation) {
+ LogDynamicBuffer dynabuf(32, 128, "", 0);
+ EmbeddedVector<char, 128> ref_buf;
+ WriteData(&dynabuf, &ref_buf);
+ EmbeddedVector<char, 128> buf;
+ CHECK_EQ(128, ReadData(&dynabuf, 0, &buf));
+ CHECK_EQ(ref_buf, buf);
+ // Try to read near the end with a buffer larger than remaining data size.
+ EmbeddedVector<char, 48> tail_buf;
+ CHECK_EQ(32, ReadData(&dynabuf, 128 - 32, &tail_buf));
+ CHECK_EQ(ref_buf.SubVector(128 - 32, 128), tail_buf.SubVector(0, 32));
+}
+
+
+TEST(DynaBufSealing) {
+ const char* seal = "Sealed";
+ const int seal_size = strlen(seal);
+ LogDynamicBuffer dynabuf(32, 128, seal, seal_size);
+ EmbeddedVector<char, 100> ref_buf;
+ WriteData(&dynabuf, &ref_buf);
+ // Try to write data that will not fit in the buffer.
+ CHECK_EQ(0, dynabuf.Write(ref_buf.start(), 128 - 100 - seal_size + 1));
+ // Now the buffer is sealed, writing of any amount of data is forbidden.
+ CHECK_EQ(0, dynabuf.Write(ref_buf.start(), 1));
+ EmbeddedVector<char, 100> buf;
+ CHECK_EQ(100, ReadData(&dynabuf, 0, &buf));
+ CHECK_EQ(ref_buf, buf);
+ // Check the seal.
+ EmbeddedVector<char, 50> seal_buf;
+ CHECK_EQ(seal_size, ReadData(&dynabuf, 100, &seal_buf));
+ CHECK_EQ(v8::internal::CStrVector(seal), seal_buf.SubVector(0, seal_size));
+ // Verify that there's no data beyond the seal.
+ CHECK_EQ(0, ReadData(&dynabuf, 100 + seal_size, &buf));
+}
+
+#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc
index 6a7e54f1d..f3f7efc71 100644
--- a/deps/v8/test/cctest/test-log.cc
+++ b/deps/v8/test/cctest/test-log.cc
@@ -7,15 +7,18 @@
#include "v8.h"
#include "log.h"
-
#include "cctest.h"
+using v8::internal::Address;
+using v8::internal::EmbeddedVector;
using v8::internal::Logger;
+namespace i = v8::internal;
+
static void SetUp() {
// Log to memory buffer.
- v8::internal::FLAG_logfile = "*";
- v8::internal::FLAG_log = true;
+ i::FLAG_logfile = "*";
+ i::FLAG_log = true;
Logger::Setup();
}
@@ -54,6 +57,7 @@ TEST(GetMessages) {
memset(log_lines, 0, sizeof(log_lines));
// A bit more than the first line length.
CHECK_EQ(line_1_len, Logger::GetLogLines(0, log_lines, line_1_len + 3));
+ log_lines[line_1_len] = '\0';
CHECK_EQ(line_1, log_lines);
memset(log_lines, 0, sizeof(log_lines));
const char* line_2 = "cccc,\"dddd\"\n";
@@ -82,6 +86,11 @@ TEST(GetMessages) {
}
+static int GetLogLines(int start_pos, i::Vector<char>* buffer) {
+ return Logger::GetLogLines(start_pos, buffer->start(), buffer->length());
+}
+
+
TEST(BeyondWritePosition) {
SetUp();
Logger::StringEvent("aaa", "bbb");
@@ -89,22 +98,24 @@ TEST(BeyondWritePosition) {
// See Logger::StringEvent.
const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n";
const int all_lines_len = strlen(all_lines);
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 1));
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len, NULL, 100));
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 1));
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 1, NULL, 100));
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 1));
- CHECK_EQ(0, Logger::GetLogLines(all_lines_len + 100, NULL, 100));
- CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 1));
- CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, NULL, 100));
+ EmbeddedVector<char, 100> buffer;
+ const int beyond_write_pos = all_lines_len;
+ CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos, buffer.start(), 1));
+ CHECK_EQ(0, GetLogLines(beyond_write_pos, &buffer));
+ CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos + 1, buffer.start(), 1));
+ CHECK_EQ(0, GetLogLines(beyond_write_pos + 1, &buffer));
+ CHECK_EQ(0, Logger::GetLogLines(beyond_write_pos + 100, buffer.start(), 1));
+ CHECK_EQ(0, GetLogLines(beyond_write_pos + 100, &buffer));
+ CHECK_EQ(0, Logger::GetLogLines(10 * 1024 * 1024, buffer.start(), 1));
+ CHECK_EQ(0, GetLogLines(10 * 1024 * 1024, &buffer));
TearDown();
}
TEST(MemoryLoggingTurnedOff) {
// Log to stdout
- v8::internal::FLAG_logfile = "-";
- v8::internal::FLAG_log = true;
+ i::FLAG_logfile = "-";
+ i::FLAG_log = true;
Logger::Setup();
CHECK_EQ(0, Logger::GetLogLines(0, NULL, 0));
CHECK_EQ(0, Logger::GetLogLines(100, NULL, 0));
@@ -114,4 +125,588 @@ TEST(MemoryLoggingTurnedOff) {
}
+static void CompileAndRunScript(const char *src) {
+ v8::Script::Compile(v8::String::New(src))->Run();
+}
+
+
+namespace v8 {
+namespace internal {
+
+class LoggerTestHelper : public AllStatic {
+ public:
+ static bool IsSamplerActive() { return Logger::IsProfilerSamplerActive(); }
+};
+
+} // namespace v8::internal
+} // namespace v8
+
+using v8::internal::LoggerTestHelper;
+
+
+static int CheckThatProfilerWorks(int log_pos) {
+ Logger::ResumeProfiler();
+ CHECK(LoggerTestHelper::IsSamplerActive());
+
+ // Verify that the current map of compiled functions has been logged.
+ EmbeddedVector<char, 102400> buffer;
+ int map_log_size = GetLogLines(log_pos, &buffer);
+ printf("map_log_size: %d\n", map_log_size);
+ CHECK_GT(map_log_size, 0);
+ CHECK_GT(buffer.length(), map_log_size);
+ log_pos += map_log_size;
+ // Check buffer contents.
+ buffer[map_log_size] = '\0';
+ const char* code_creation = "\ncode-creation,"; // eq. to /^code-creation,/
+ CHECK_NE(NULL, strstr(buffer.start(), code_creation));
+
+ // Force compiler to generate new code by parametrizing source.
+ EmbeddedVector<char, 100> script_src;
+ i::OS::SNPrintF(script_src,
+ "for (var i = 0; i < 1000; ++i) { "
+ "(function(x) { return %d * x; })(i); }",
+ log_pos);
+ // Run code for 200 msecs to get some ticks.
+ const double end_time = i::OS::TimeCurrentMillis() + 200;
+ while (i::OS::TimeCurrentMillis() < end_time) {
+ CompileAndRunScript(script_src.start());
+ }
+
+ Logger::PauseProfiler();
+ CHECK(!LoggerTestHelper::IsSamplerActive());
+
+ // Wait 50 msecs to allow Profiler thread to process the last
+ // tick sample it has got.
+ i::OS::Sleep(50);
+
+ // Now we must have compiler and tick records.
+ int log_size = GetLogLines(log_pos, &buffer);
+ printf("log_size: %d\n", log_size);
+ CHECK_GT(log_size, 0);
+ CHECK_GT(buffer.length(), log_size);
+ log_pos += log_size;
+ // Check buffer contents.
+ buffer[log_size] = '\0';
+ const char* tick = "\ntick,";
+ CHECK_NE(NULL, strstr(buffer.start(), code_creation));
+ CHECK_NE(NULL, strstr(buffer.start(), tick));
+
+ return log_pos;
+}
+
+
+TEST(ProfLazyMode) {
+ const bool saved_prof_lazy = i::FLAG_prof_lazy;
+ const bool saved_prof = i::FLAG_prof;
+ const bool saved_prof_auto = i::FLAG_prof_auto;
+ i::FLAG_prof = true;
+ i::FLAG_prof_lazy = true;
+ i::FLAG_prof_auto = false;
+ i::FLAG_logfile = "*";
+
+ // If tests are being run manually, V8 will be already initialized
+ // by the test below.
+ const bool need_to_set_up_logger = i::V8::IsRunning();
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ if (need_to_set_up_logger) Logger::Setup();
+ env->Enter();
+
+ // No sampling should happen prior to resuming profiler.
+ CHECK(!LoggerTestHelper::IsSamplerActive());
+
+ // Read initial logged data (static libs map).
+ EmbeddedVector<char, 102400> buffer;
+ int log_pos = GetLogLines(0, &buffer);
+ CHECK_GT(log_pos, 0);
+ CHECK_GT(buffer.length(), log_pos);
+
+ CompileAndRunScript("var a = (function(x) { return x + 1; })(10);");
+
+ // Nothing must be logged while profiling is suspended.
+ CHECK_EQ(0, GetLogLines(log_pos, &buffer));
+
+ log_pos = CheckThatProfilerWorks(log_pos);
+
+ CompileAndRunScript("var a = (function(x) { return x + 1; })(10);");
+
+ // No new data beyond last retrieved position.
+ CHECK_EQ(0, GetLogLines(log_pos, &buffer));
+
+ // Check that profiling can be resumed again.
+ CheckThatProfilerWorks(log_pos);
+
+ env->Exit();
+ Logger::TearDown();
+ i::FLAG_prof_lazy = saved_prof_lazy;
+ i::FLAG_prof = saved_prof;
+ i::FLAG_prof_auto = saved_prof_auto;
+}
+
+
+static inline bool IsStringEqualTo(const char* r, const char* s) {
+ return strncmp(r, s, strlen(r)) == 0;
+}
+
+
+static bool Consume(const char* str, char** buf) {
+ if (IsStringEqualTo(str, *buf)) {
+ *buf += strlen(str);
+ return true;
+ }
+ return false;
+}
+
+
+namespace {
+
+// A code entity is a pointer to a position of code-creation event in buffer log
+// offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes
+// comparing code entities pretty easy.
+typedef char* CodeEntityInfo;
+
+class Interval {
+ public:
+ Interval()
+ : min_addr_(reinterpret_cast<Address>(-1)),
+ max_addr_(reinterpret_cast<Address>(0)), next_(NULL) {}
+
+ ~Interval() { delete next_; }
+
+ size_t Length() {
+ size_t result = max_addr_ - min_addr_ + 1;
+ if (next_ != NULL) result += next_->Length();
+ return result;
+ }
+
+ void CloneFrom(Interval* src) {
+ while (src != NULL) {
+ RegisterAddress(src->min_addr_);
+ RegisterAddress(src->max_addr_);
+ src = src->next_;
+ }
+ }
+
+ bool Contains(Address addr) {
+ if (min_addr_ <= addr && addr <= max_addr_) {
+ return true;
+ }
+ if (next_ != NULL) {
+ return next_->Contains(addr);
+ } else {
+ return false;
+ }
+ }
+
+ size_t GetIndex(Address addr) {
+ if (min_addr_ <= addr && addr <= max_addr_) {
+ return addr - min_addr_;
+ }
+ CHECK_NE(NULL, next_);
+ return (max_addr_ - min_addr_ + 1) + next_->GetIndex(addr);
+ }
+
+ Address GetMinAddr() {
+ return next_ == NULL ? min_addr_ : i::Min(min_addr_, next_->GetMinAddr());
+ }
+
+ Address GetMaxAddr() {
+ return next_ == NULL ? max_addr_ : i::Max(max_addr_, next_->GetMaxAddr());
+ }
+
+ void RegisterAddress(Address addr) {
+ if (min_addr_ == reinterpret_cast<Address>(-1)
+ || (size_t)(addr > min_addr_ ?
+ addr - min_addr_ : min_addr_ - addr) < MAX_DELTA) {
+ if (addr < min_addr_) min_addr_ = addr;
+ if (addr > max_addr_) max_addr_ = addr;
+ } else {
+ if (next_ == NULL) next_ = new Interval();
+ next_->RegisterAddress(addr);
+ }
+ }
+
+ Address raw_min_addr() { return min_addr_; }
+
+ Address raw_max_addr() { return max_addr_; }
+
+ Interval* get_next() { return next_; }
+
+ private:
+ static const size_t MAX_DELTA = 0x100000;
+ Address min_addr_;
+ Address max_addr_;
+ Interval* next_;
+};
+
+
+// A structure used to return log parsing results.
+class ParseLogResult {
+ public:
+ ParseLogResult()
+ : entities_map(NULL), entities(NULL),
+ max_entities(0) {}
+
+ ~ParseLogResult() {
+ i::DeleteArray(entities_map);
+ i::DeleteArray(entities);
+ }
+
+ void AllocateEntities() {
+ // Make sure that the test doesn't operate on a bogus log.
+ CHECK_GT(max_entities, 0);
+ CHECK_GT(bounds.GetMinAddr(), 0);
+ CHECK_GT(bounds.GetMaxAddr(), bounds.GetMinAddr());
+
+ entities = i::NewArray<CodeEntityInfo>(max_entities);
+ for (int i = 0; i < max_entities; ++i) {
+ entities[i] = NULL;
+ }
+ const size_t map_length = bounds.Length();
+ entities_map = i::NewArray<int>(map_length);
+ for (size_t i = 0; i < map_length; ++i) {
+ entities_map[i] = -1;
+ }
+ }
+
+ bool HasIndexForAddress(Address addr) {
+ return bounds.Contains(addr);
+ }
+
+ size_t GetIndexForAddress(Address addr) {
+ CHECK(HasIndexForAddress(addr));
+ return bounds.GetIndex(addr);
+ }
+
+ CodeEntityInfo GetEntity(Address addr) {
+ if (HasIndexForAddress(addr)) {
+ size_t idx = GetIndexForAddress(addr);
+ int item = entities_map[idx];
+ return item != -1 ? entities[item] : NULL;
+ }
+ return NULL;
+ }
+
+ void ParseAddress(char* start) {
+ Address addr =
+ reinterpret_cast<Address>(strtoul(start, NULL, 16)); // NOLINT
+ bounds.RegisterAddress(addr);
+ }
+
+ Address ConsumeAddress(char** start) {
+ char* end_ptr;
+ Address addr =
+ reinterpret_cast<Address>(strtoul(*start, &end_ptr, 16)); // NOLINT
+ CHECK(HasIndexForAddress(addr));
+ *start = end_ptr;
+ return addr;
+ }
+
+ Interval bounds;
+ // Memory map of entities start addresses.
+ int* entities_map;
+ // An array of code entities.
+ CodeEntityInfo* entities;
+ // Maximal entities count. Actual entities count can be lower,
+ // empty entity slots are pointing to NULL.
+ int max_entities;
+};
+
+} // namespace
+
+
+typedef void (*ParserBlock)(char* start, char* end, ParseLogResult* result);
+
+static void ParserCycle(
+ char* start, char* end, ParseLogResult* result,
+ ParserBlock block_creation, ParserBlock block_delete,
+ ParserBlock block_move) {
+
+ const char* code_creation = "code-creation,";
+ const char* code_delete = "code-delete,";
+ const char* code_move = "code-move,";
+
+ const char* lazy_compile = "LazyCompile,";
+ const char* script = "Script,";
+ const char* function = "Function,";
+
+ while (start < end) {
+ if (Consume(code_creation, &start)) {
+ if (Consume(lazy_compile, &start)
+ || Consume(script, &start)
+ || Consume(function, &start)) {
+ block_creation(start, end, result);
+ }
+ } else if (Consume(code_delete, &start)) {
+ block_delete(start, end, result);
+ } else if (Consume(code_move, &start)) {
+ block_move(start, end, result);
+ }
+ while (start < end && *start != '\n') ++start;
+ ++start;
+ }
+}
+
+
+static void Pass1CodeCreation(char* start, char* end, ParseLogResult* result) {
+ result->ParseAddress(start);
+ ++result->max_entities;
+}
+
+
+static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) {
+ result->ParseAddress(start);
+}
+
+
+static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) {
+ result->ParseAddress(start);
+ // Skip old address.
+ while (start < end && *start != ',') ++start;
+ CHECK_GT(end, start);
+ ++start; // Skip ','.
+ result->ParseAddress(start);
+}
+
+
+static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) {
+ Address addr = result->ConsumeAddress(&start);
+ CHECK_GT(end, start);
+ ++start; // Skip ','.
+
+ size_t idx = result->GetIndexForAddress(addr);
+ result->entities_map[idx] = -1;
+ for (int i = 0; i < result->max_entities; ++i) {
+ // Find an empty slot and fill it.
+ if (result->entities[i] == NULL) {
+ result->entities[i] = start;
+ result->entities_map[idx] = i;
+ break;
+ }
+ }
+ // Make sure that a slot was found.
+ CHECK_GE(result->entities_map[idx], 0);
+}
+
+
+static void Pass2CodeDelete(char* start, char* end, ParseLogResult* result) {
+ Address addr = result->ConsumeAddress(&start);
+ size_t idx = result->GetIndexForAddress(addr);
+ // There can be code deletes that are not related to JS code.
+ if (result->entities_map[idx] >= 0) {
+ result->entities[result->entities_map[idx]] = NULL;
+ result->entities_map[idx] = -1;
+ }
+}
+
+
+static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) {
+ Address from_addr = result->ConsumeAddress(&start);
+ CHECK_GT(end, start);
+ ++start; // Skip ','.
+ Address to_addr = result->ConsumeAddress(&start);
+ CHECK_GT(end, start);
+
+ size_t from_idx = result->GetIndexForAddress(from_addr);
+ size_t to_idx = result->GetIndexForAddress(to_addr);
+ // There can be code moves that are not related to JS code.
+ if (from_idx != to_idx && result->entities_map[from_idx] >= 0) {
+ CHECK_EQ(-1, result->entities_map[to_idx]);
+ result->entities_map[to_idx] = result->entities_map[from_idx];
+ result->entities_map[from_idx] = -1;
+ };
+}
+
+
+static void ParseLog(char* start, char* end, ParseLogResult* result) {
+ // Pass 1: Calculate boundaries of addresses and entities count.
+ ParserCycle(start, end, result,
+ Pass1CodeCreation, Pass1CodeDelete, Pass1CodeMove);
+
+ printf("min_addr: %p, max_addr: %p, entities: %d\n",
+ result->bounds.GetMinAddr(), result->bounds.GetMaxAddr(),
+ result->max_entities);
+
+ result->AllocateEntities();
+
+ // Pass 2: Fill in code entries data.
+ ParserCycle(start, end, result,
+ Pass2CodeCreation, Pass2CodeDelete, Pass2CodeMove);
+}
+
+
+static inline void PrintCodeEntityInfo(CodeEntityInfo entity) {
+ const int max_len = 50;
+ if (entity != NULL) {
+ char* eol = strchr(entity, '\n');
+ int len = eol - entity;
+ len = len <= max_len ? len : max_len;
+ printf("%-*.*s ", max_len, len, entity);
+ } else {
+ printf("%*s", max_len + 1, "");
+ }
+}
+
+
+static void PrintCodeEntitiesInfo(
+ bool is_equal, Address addr,
+ CodeEntityInfo l_entity, CodeEntityInfo r_entity) {
+ printf("%c %p ", is_equal ? ' ' : '*', addr);
+ PrintCodeEntityInfo(l_entity);
+ PrintCodeEntityInfo(r_entity);
+ printf("\n");
+}
+
+
+static inline int StrChrLen(const char* s, char c) {
+ return strchr(s, c) - s;
+}
+
+
+static bool AreFuncSizesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
+ int ref_len = StrChrLen(ref_s, ',');
+ int new_len = StrChrLen(new_s, ',');
+ return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0;
+}
+
+
+static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) {
+ // Skip size.
+ ref_s = strchr(ref_s, ',') + 1;
+ new_s = strchr(new_s, ',') + 1;
+ int ref_len = StrChrLen(ref_s, '\n');
+ int new_len = StrChrLen(new_s, '\n');
+ // If reference is anonymous (""), it's OK to have anything in new.
+ if (ref_len == 2) return true;
+ // A special case for ErrorPrototype. Haven't yet figured out why they
+ // are different.
+ const char* error_prototype = "\"ErrorPrototype";
+ if (IsStringEqualTo(error_prototype, ref_s)
+ && IsStringEqualTo(error_prototype, new_s)) {
+ return true;
+ }
+ // Built-in objects have problems too.
+ const char* built_ins[] = {
+ "\"Boolean\"", "\"Function\"", "\"Number\"",
+ "\"Object\"", "\"Script\"", "\"String\""
+ };
+ for (size_t i = 0; i < sizeof(built_ins) / sizeof(*built_ins); ++i) {
+ if (IsStringEqualTo(built_ins[i], new_s)) {
+ return true;
+ }
+ }
+ return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0;
+}
+
+
+static bool AreEntitiesEqual(CodeEntityInfo ref_e, CodeEntityInfo new_e) {
+ if (ref_e == NULL && new_e != NULL) return true;
+ if (ref_e != NULL && new_e != NULL) {
+ return AreFuncSizesEqual(ref_e, new_e) && AreFuncNamesEqual(ref_e, new_e);
+ }
+ if (ref_e != NULL && new_e == NULL) {
+ // args_count entities (argument adapters) are not found by heap traversal,
+ // but they are not needed because they doesn't contain any code.
+ ref_e = strchr(ref_e, ',') + 1;
+ const char* args_count = "\"args_count:";
+ return IsStringEqualTo(args_count, ref_e);
+ }
+ return false;
+}
+
+
+// Test that logging of code create / move / delete events
+// is equivalent to traversal of a resulting heap.
+TEST(EquivalenceOfLoggingAndTraversal) {
+ // This test needs to be run on a "clean" V8 to ensure that snapshot log
+ // is loaded. This is always true when running using tools/test.py because
+ // it launches a new cctest instance for every test. To be sure that launching
+ // cctest manually also works, please be sure that no tests below
+ // are using V8.
+ //
+ // P.S. No, V8 can't be re-initialized after disposal, see include/v8.h.
+ CHECK(!i::V8::IsRunning());
+
+ i::FLAG_logfile = "*";
+ i::FLAG_log = true;
+ i::FLAG_log_code = true;
+
+ // Make sure objects move.
+ bool saved_always_compact = i::FLAG_always_compact;
+ if (!i::FLAG_never_compact) {
+ i::FLAG_always_compact = true;
+ }
+
+ v8::HandleScope scope;
+ v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
+ v8::Handle<v8::Context> env = v8::Context::New(
+ 0, v8::Handle<v8::ObjectTemplate>(), global_object);
+ env->Enter();
+
+ // Compile and run a function that creates other functions.
+ CompileAndRunScript(
+ "(function f(obj) {\n"
+ " obj.test =\n"
+ " (function a(j) { return function b() { return j; } })(100);\n"
+ "})(this);");
+ i::Heap::CollectAllGarbage();
+
+ EmbeddedVector<char, 204800> buffer;
+ int log_size;
+ ParseLogResult ref_result;
+
+ // Retrieve the log.
+ {
+ // Make sure that no GCs occur prior to LogCompiledFunctions call.
+ i::AssertNoAllocation no_alloc;
+
+ log_size = GetLogLines(0, &buffer);
+ CHECK_GT(log_size, 0);
+ CHECK_GT(buffer.length(), log_size);
+
+ // Fill a map of compiled code objects.
+ ParseLog(buffer.start(), buffer.start() + log_size, &ref_result);
+ }
+
+ // Iterate heap to find compiled functions, will write to log.
+ i::Logger::LogCompiledFunctions();
+ char* new_log_start = buffer.start() + log_size;
+ const int new_log_size = Logger::GetLogLines(
+ log_size, new_log_start, buffer.length() - log_size);
+ CHECK_GT(new_log_size, 0);
+ CHECK_GT(buffer.length(), log_size + new_log_size);
+
+ // Fill an equivalent map of compiled code objects.
+ ParseLogResult new_result;
+ ParseLog(new_log_start, new_log_start + new_log_size, &new_result);
+
+ // Test their actual equivalence.
+ Interval combined;
+ combined.CloneFrom(&ref_result.bounds);
+ combined.CloneFrom(&new_result.bounds);
+ Interval* iter = &combined;
+ bool results_equal = true;
+
+ while (iter != NULL) {
+ for (Address addr = iter->raw_min_addr();
+ addr <= iter->raw_max_addr(); ++addr) {
+ CodeEntityInfo ref_entity = ref_result.GetEntity(addr);
+ CodeEntityInfo new_entity = new_result.GetEntity(addr);
+ if (ref_entity != NULL || new_entity != NULL) {
+ const bool equal = AreEntitiesEqual(ref_entity, new_entity);
+ if (!equal) results_equal = false;
+ PrintCodeEntitiesInfo(equal, addr, ref_entity, new_entity);
+ }
+ }
+ iter = iter->get_next();
+ }
+ // Make sure that all log data is written prior crash due to CHECK failure.
+ fflush(stdout);
+ CHECK(results_equal);
+
+ env->Exit();
+ Logger::TearDown();
+ i::FLAG_always_compact = saved_always_compact;
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/test/cctest/test-utils.cc b/deps/v8/test/cctest/test-utils.cc
index acb5d3ca6..23b3254c2 100644
--- a/deps/v8/test/cctest/test-utils.cc
+++ b/deps/v8/test/cctest/test-utils.cc
@@ -152,6 +152,13 @@ TEST(Utils1) {
CHECK_EQ(0, FastD2I(0.345));
CHECK_EQ(1, FastD2I(1.234));
CHECK_EQ(1000000, FastD2I(1000000.123));
+ // Check that >> is implemented as arithmetic shift right.
+ // If this is not true, then ArithmeticShiftRight() must be changed,
+ // There are also documented right shifts in assembler.cc of
+ // int8_t and intptr_t signed integers.
+ CHECK_EQ(-2, -8 >> 2);
+ CHECK_EQ(-2, static_cast<int8_t>(-8) >> 2);
+ CHECK_EQ(-2, static_cast<intptr_t>(-8) >> 2);
}
diff --git a/deps/v8/test/cctest/test-version.cc b/deps/v8/test/cctest/test-version.cc
index 0b93fbf8c..6d2685596 100644
--- a/deps/v8/test/cctest/test-version.cc
+++ b/deps/v8/test/cctest/test-version.cc
@@ -33,7 +33,8 @@
using namespace v8::internal;
-namespace v8 { namespace internal {
+namespace v8 {
+namespace internal {
void SetVersion(int major, int minor, int build, int patch,
bool candidate, const char* soname) {
diff --git a/deps/v8/test/mjsunit/codegen_coverage.js b/deps/v8/test/mjsunit/codegen-coverage.js
index d5e7769d7..d5e7769d7 100644
--- a/deps/v8/test/mjsunit/codegen_coverage.js
+++ b/deps/v8/test/mjsunit/codegen-coverage.js
diff --git a/deps/v8/test/mjsunit/debug-backtrace.js b/deps/v8/test/mjsunit/debug-backtrace.js
index f08f6390e..1d2bb9af9 100644
--- a/deps/v8/test/mjsunit/debug-backtrace.js
+++ b/deps/v8/test/mjsunit/debug-backtrace.js
@@ -37,7 +37,7 @@ var m = function() {
};
function g() {
- m();
+ m();
};
@@ -80,8 +80,9 @@ function listener(event, exec_state, event_data, data) {
{
// The expected backtrace is
// 0: f
- // 1: g
- // 2: [anonymous]
+ // 1: m
+ // 2: g
+ // 3: [anonymous]
var response;
var backtrace;
@@ -133,6 +134,23 @@ function listener(event, exec_state, event_data, data) {
assertEquals(2, frames[1].index);
assertEquals("g", response.lookup(frames[1].func.ref).name);
+ // Get backtrace with bottom two frames.
+ json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":0,"toFrame":2, "bottom":true}}'
+ response = new ParsedResponse(dcp.processDebugJSONRequest(json));
+ backtrace = response.body();
+ assertEquals(2, backtrace.fromFrame);
+ assertEquals(4, backtrace.toFrame);
+ assertEquals(4, backtrace.totalFrames);
+ var frames = backtrace.frames;
+ assertEquals(2, frames.length);
+ for (var i = 0; i < frames.length; i++) {
+ assertEquals('frame', frames[i].type);
+ }
+ assertEquals(2, frames[0].index);
+ assertEquals("g", response.lookup(frames[0].func.ref).name);
+ assertEquals(3, frames[1].index);
+ assertEquals("", response.lookup(frames[1].func.ref).name);
+
// Get the individual frames.
json = '{"seq":0,"type":"request","command":"frame"}'
response = new ParsedResponse(dcp.processDebugJSONRequest(json));
diff --git a/deps/v8/test/mjsunit/debug-compile-event.js b/deps/v8/test/mjsunit/debug-compile-event.js
index 035e36c30..c346f76e8 100644
--- a/deps/v8/test/mjsunit/debug-compile-event.js
+++ b/deps/v8/test/mjsunit/debug-compile-event.js
@@ -32,8 +32,11 @@ Debug = debug.Debug
var exception = false; // Exception in debug event listener.
var before_compile_count = 0;
var after_compile_count = 0;
-var current_source = ''; // Current source compiled.
-var source_count = 0; // Total number of scource sompiled.
+var current_source = ''; // Current source being compiled.
+var source_count = 0; // Total number of scources compiled.
+var host_compilations = 0; // Number of scources compiled through the API.
+var eval_compilations = 0; // Number of scources compiled through eval.
+var json_compilations = 0; // Number of scources compiled through JSON.parse.
function compileSource(source) {
@@ -52,19 +55,41 @@ function listener(event, exec_state, event_data, data) {
before_compile_count++;
} else {
after_compile_count++;
+ switch (event_data.script().compilationType()) {
+ case Debug.ScriptCompilationType.Host:
+ host_compilations++;
+ break;
+ case Debug.ScriptCompilationType.Eval:
+ eval_compilations++;
+ break;
+ case Debug.ScriptCompilationType.JSON:
+ json_compilations++;
+ break;
+ }
}
-
+
// If the compiled source contains 'eval' there will be additional compile
// events for the source inside eval.
if (current_source.indexOf('eval') == 0) {
// For source with 'eval' there will be compile events with substrings
// as well as with with the exact source.
assertTrue(current_source.indexOf(event_data.script().source()) >= 0);
+ } else if (current_source.indexOf('JSON.parse') == 0) {
+ // For JSON the JSON source will be in parentheses.
+ var s = event_data.script().source();
+ if (s[0] == '(') {
+ s = s.substring(1, s.length - 2);
+ }
+ assertTrue(current_source.indexOf(s) >= 0);
} else {
// For source without 'eval' there will be a compile events with the
// exact source.
assertEquals(current_source, event_data.script().source());
}
+ // Check that script context is included into the event message.
+ var json = event_data.toJSONProtocol();
+ var msg = eval('(' + json + ')');
+ assertTrue('context' in msg.body.script);
}
} catch (e) {
exception = e
@@ -82,6 +107,8 @@ compileSource('eval("a=2")');
source_count++; // Using eval causes additional compilation event.
compileSource('eval("eval(\'function(){return a;}\')")');
source_count += 2; // Using eval causes additional compilation event.
+compileSource('JSON.parse("{a:1,b:2}")');
+source_count++; // Using JSON.parse causes additional compilation event.
// Make sure that the debug event listener was invoked.
assertFalse(exception, "exception in listener")
@@ -89,7 +116,11 @@ assertFalse(exception, "exception in listener")
// Number of before and after compile events should be the same.
assertEquals(before_compile_count, after_compile_count);
-// Check the actual number of events.
+// Check the actual number of events (no compilation through the API as all
+// source compiled through eval except for one JSON.parse call).
assertEquals(source_count, after_compile_count);
+assertEquals(0, host_compilations);
+assertEquals(source_count - 1, eval_compilations);
+assertEquals(1, json_compilations);
Debug.setListener(null);
diff --git a/deps/v8/test/mjsunit/debug-references.js b/deps/v8/test/mjsunit/debug-references.js
index dedc3eff4..1fde1ac74 100644
--- a/deps/v8/test/mjsunit/debug-references.js
+++ b/deps/v8/test/mjsunit/debug-references.js
@@ -113,6 +113,6 @@ q = new Point(1,2);
// Enter debugger causing the event listener to be called.
debugger;
-// Make sure that the debug event listener vas invoked.
+// Make sure that the debug event listener was invoked.
assertFalse(exception, "exception in listener")
assertTrue(listenerComplete, "listener did not run to completion");
diff --git a/deps/v8/test/mjsunit/debug-scripts-request.js b/deps/v8/test/mjsunit/debug-scripts-request.js
index cf1615bb7..80b3bce59 100644
--- a/deps/v8/test/mjsunit/debug-scripts-request.js
+++ b/deps/v8/test/mjsunit/debug-scripts-request.js
@@ -66,9 +66,6 @@ function listener(event, exec_state, event_data, data) {
testArguments(dcp, '{"types":"xx"}', false);
// Test legal scripts requests.
- var request = '{' + base_request + '}'
- var response = safeEval(dcp.processDebugJSONRequest(request));
- assertTrue(response.success);
testArguments(dcp, '{}', true);
testArguments(dcp, '{"types":1}', true);
testArguments(dcp, '{"types":2}', true);
@@ -76,6 +73,21 @@ function listener(event, exec_state, event_data, data) {
testArguments(dcp, '{"types":7}', true);
testArguments(dcp, '{"types":0xFF}', true);
+ // Test request for all scripts.
+ var request = '{' + base_request + '}'
+ var response = safeEval(dcp.processDebugJSONRequest(request));
+ assertTrue(response.success);
+
+ // Test filtering by id.
+ assertEquals(2, response.body.length);
+ var script = response.body[0];
+ var request = '{' + base_request + ',"arguments":{"ids":[' +
+ script.id + ']}}';
+ var response = safeEval(dcp.processDebugJSONRequest(request));
+ assertTrue(response.success);
+ assertEquals(1, response.body.length);
+ assertEquals(script.id, response.body[0].id);
+
// Indicate that all was processed.
listenerComplete = true;
}
@@ -91,5 +103,6 @@ Debug.setListener(listener);
debugger;
// Make sure that the debug event listener vas invoked with no exceptions.
-assertTrue(listenerComplete, "listener did not run to completion");
+assertTrue(listenerComplete,
+ "listener did not run to completion, exception: " + exception);
assertFalse(exception, "exception in listener")
diff --git a/deps/v8/test/mjsunit/mirror-array.js b/deps/v8/test/mjsunit/mirror-array.js
index 1873d1eb6..eb8f72a8c 100644
--- a/deps/v8/test/mjsunit/mirror-array.js
+++ b/deps/v8/test/mjsunit/mirror-array.js
@@ -44,8 +44,9 @@ function testArrayMirror(a, names) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(a);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
- var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+ var json = JSON.stringify(serializer.serializeValue(mirror));
+ var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror, 'Unexpected mirror hierachy');
diff --git a/deps/v8/test/mjsunit/mirror-boolean.js b/deps/v8/test/mjsunit/mirror-boolean.js
index 4f9308924..311c78176 100644
--- a/deps/v8/test/mjsunit/mirror-boolean.js
+++ b/deps/v8/test/mjsunit/mirror-boolean.js
@@ -32,7 +32,7 @@ function testBooleanMirror(b) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(b);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
+ var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-date.js b/deps/v8/test/mjsunit/mirror-date.js
index a6334d0f1..6b6a3ad40 100644
--- a/deps/v8/test/mjsunit/mirror-date.js
+++ b/deps/v8/test/mjsunit/mirror-date.js
@@ -32,7 +32,7 @@ function testDateMirror(d, iso8601) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(d);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
+ var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
@@ -55,9 +55,9 @@ function testDateMirror(d, iso8601) {
assertEquals(iso8601, fromJSON.value);
}
-
// Test Date values.
-testDateMirror(new Date(Date.parse("Dec 25, 1995 1:30 UTC")), "1995-12-25T01:30:00.000Z");
+testDateMirror(new Date(Date.parse("Dec 25, 1995 1:30 UTC")),
+ "1995-12-25T01:30:00Z");
d = new Date();
d.setUTCFullYear(1967);
d.setUTCMonth(0); // January.
@@ -66,10 +66,10 @@ d.setUTCHours(9);
d.setUTCMinutes(22);
d.setUTCSeconds(59);
d.setUTCMilliseconds(0);
-testDateMirror(d, "1967-01-17T09:22:59.000Z");
+testDateMirror(d, "1967-01-17T09:22:59Z");
d.setUTCMilliseconds(1);
-testDateMirror(d, "1967-01-17T09:22:59.001Z");
-d.setUTCMilliseconds(12);
-testDateMirror(d, "1967-01-17T09:22:59.012Z");
-d.setUTCMilliseconds(123);
-testDateMirror(d, "1967-01-17T09:22:59.123Z");
+testDateMirror(d, "1967-01-17T09:22:59Z");
+d.setUTCSeconds(12);
+testDateMirror(d, "1967-01-17T09:22:12Z");
+d.setUTCSeconds(36);
+testDateMirror(d, "1967-01-17T09:22:36Z");
diff --git a/deps/v8/test/mjsunit/mirror-error.js b/deps/v8/test/mjsunit/mirror-error.js
index 37ec46c86..4ed8c1b42 100644
--- a/deps/v8/test/mjsunit/mirror-error.js
+++ b/deps/v8/test/mjsunit/mirror-error.js
@@ -44,8 +44,9 @@ function testErrorMirror(e) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(e);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
- var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+ var json = JSON.stringify(serializer.serializeValue(mirror));
+ var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-function.js b/deps/v8/test/mjsunit/mirror-function.js
index 59d9e7862..58aee3dae 100644
--- a/deps/v8/test/mjsunit/mirror-function.js
+++ b/deps/v8/test/mjsunit/mirror-function.js
@@ -44,8 +44,9 @@ function testFunctionMirror(f) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(f);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
- var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+ var json = JSON.stringify(serializer.serializeValue(mirror));
+ var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-null.js b/deps/v8/test/mjsunit/mirror-null.js
index db68966a4..1ee555b7b 100644
--- a/deps/v8/test/mjsunit/mirror-null.js
+++ b/deps/v8/test/mjsunit/mirror-null.js
@@ -31,7 +31,7 @@
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(null);
var serializer = debug.MakeMirrorSerializer();
-var json = serializer.serializeValue(mirror);
+var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-number.js b/deps/v8/test/mjsunit/mirror-number.js
index 68eb0d7e7..2db5df439 100644
--- a/deps/v8/test/mjsunit/mirror-number.js
+++ b/deps/v8/test/mjsunit/mirror-number.js
@@ -32,7 +32,7 @@ function testNumberMirror(n) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(n);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
+ var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-object.js b/deps/v8/test/mjsunit/mirror-object.js
index e829a0e22..ad7add8ae 100644
--- a/deps/v8/test/mjsunit/mirror-object.js
+++ b/deps/v8/test/mjsunit/mirror-object.js
@@ -44,8 +44,9 @@ function testObjectMirror(obj, cls_name, ctor_name, hasSpecialProperties) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(obj);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
- var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+ var json = JSON.stringify(serializer.serializeValue(mirror));
+ var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror, 'Unexpected mirror hierachy');
@@ -105,7 +106,7 @@ function testObjectMirror(obj, cls_name, ctor_name, hasSpecialProperties) {
assertEquals(names.length, fromJSON.properties.length, 'Some properties missing in JSON');
for (var i = 0; i < fromJSON.properties.length; i++) {
var name = fromJSON.properties[i].name;
- if (!name) name = fromJSON.properties[i].index;
+ if (typeof name == 'undefined') name = fromJSON.properties[i].index;
var found = false;
for (var j = 0; j < names.length; j++) {
if (names[j] == name) {
@@ -157,7 +158,6 @@ function Point(x,y) {
this.y_ = y;
}
-
// Test a number of different objects.
testObjectMirror({}, 'Object', 'Object');
testObjectMirror({'a':1,'b':2}, 'Object', 'Object');
diff --git a/deps/v8/test/mjsunit/mirror-regexp.js b/deps/v8/test/mjsunit/mirror-regexp.js
index 0490b17f0..8c834bf38 100644
--- a/deps/v8/test/mjsunit/mirror-regexp.js
+++ b/deps/v8/test/mjsunit/mirror-regexp.js
@@ -55,8 +55,9 @@ function testRegExpMirror(r) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(r);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
- var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+ var json = JSON.stringify(serializer.serializeValue(mirror));
+ var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-script.js b/deps/v8/test/mjsunit/mirror-script.js
index 61f0f3aa6..9b67b9ba0 100644
--- a/deps/v8/test/mjsunit/mirror-script.js
+++ b/deps/v8/test/mjsunit/mirror-script.js
@@ -25,14 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --allow-natives-syntax
// Test the mirror object for scripts.
-function testScriptMirror(f, file_name, file_lines, script_type, script_source) {
+function testScriptMirror(f, file_name, file_lines, type, compilation_type,
+ source, eval_from_line) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(f).script();
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
+ var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
@@ -53,13 +54,17 @@ function testScriptMirror(f, file_name, file_lines, script_type, script_source)
if (file_lines > 0) {
assertEquals(file_lines, mirror.lineCount());
}
- assertEquals(script_type, mirror.scriptType());
- if (script_source) {
- assertEquals(script_source, mirror.source());
+ assertEquals(type, mirror.scriptType());
+ assertEquals(compilation_type, mirror.compilationType(), "compilation type");
+ if (source) {
+ assertEquals(source, mirror.source());
+ }
+ if (eval_from_line) {
+ assertEquals(eval_from_line, mirror.evalFromLocation().line);
}
// Parse JSON representation and check.
- var fromJSON = eval('(' + json + ')');
+ var fromJSON = JSON.parse(json);
assertEquals('script', fromJSON.type);
name = fromJSON.name;
if (name) {
@@ -72,15 +77,18 @@ function testScriptMirror(f, file_name, file_lines, script_type, script_source)
if (file_lines > 0) {
assertEquals(file_lines, fromJSON.lineCount);
}
- assertEquals(script_type, fromJSON.scriptType);
+ assertEquals(type, fromJSON.scriptType);
+ assertEquals(compilation_type, fromJSON.compilationType);
}
// Test the script mirror for different functions.
-testScriptMirror(function(){}, 'mirror-script.js', 92, 2);
-testScriptMirror(Math.sin, 'native math.js', -1, 0);
-testScriptMirror(eval('function(){}'), null, 1, 2, 'function(){}');
-testScriptMirror(eval('function(){\n }'), null, 2, 2, 'function(){\n }');
+testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0);
+testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
+testScriptMirror(eval('function(){}'), null, 1, 2, 1, 'function(){}', 87);
+testScriptMirror(eval('function(){\n }'), null, 2, 2, 1, 'function(){\n }', 88);
+testScriptMirror(%CompileString("({a:1,b:2})", true), null, 1, 2, 2, '({a:1,b:2})');
+testScriptMirror(%CompileString("({a:1,\n b:2})", true), null, 2, 2, 2, '({a:1,\n b:2})');
// Test taking slices of source.
var mirror = debug.MakeMirror(eval('function(){\n 1;\n}')).script();
diff --git a/deps/v8/test/mjsunit/mirror-string.js b/deps/v8/test/mjsunit/mirror-string.js
index eeabc5fe2..c241849d8 100644
--- a/deps/v8/test/mjsunit/mirror-string.js
+++ b/deps/v8/test/mjsunit/mirror-string.js
@@ -34,7 +34,7 @@ function testStringMirror(s) {
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(s);
var serializer = debug.MakeMirrorSerializer();
- var json = serializer.serializeValue(mirror);
+ var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-undefined.js b/deps/v8/test/mjsunit/mirror-undefined.js
index 2b5b84c6a..7f63239e5 100644
--- a/deps/v8/test/mjsunit/mirror-undefined.js
+++ b/deps/v8/test/mjsunit/mirror-undefined.js
@@ -31,7 +31,7 @@
// Create mirror and JSON representation.
var mirror = debug.MakeMirror(void 0);
var serializer = debug.MakeMirrorSerializer();
-var json = serializer.serializeValue(mirror);
+var json = JSON.stringify(serializer.serializeValue(mirror));
// Check the mirror hierachy.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/mirror-unresolved-function.js b/deps/v8/test/mjsunit/mirror-unresolved-function.js
index 8d8ca37f8..c1fe4a3ef 100644
--- a/deps/v8/test/mjsunit/mirror-unresolved-function.js
+++ b/deps/v8/test/mjsunit/mirror-unresolved-function.js
@@ -42,8 +42,9 @@ MirrorRefCache.prototype.lookup = function(handle) {
var mirror = new debug.UnresolvedFunctionMirror("f");
var serializer = debug.MakeMirrorSerializer();
-var json = serializer.serializeValue(mirror);
-var refs = new MirrorRefCache(serializer.serializeReferencedObjects());
+var json = JSON.stringify(serializer.serializeValue(mirror));
+var refs = new MirrorRefCache(
+ JSON.stringify(serializer.serializeReferencedObjects()));
// Check the mirror hierachy for unresolved functions.
assertTrue(mirror instanceof debug.Mirror);
diff --git a/deps/v8/test/mjsunit/regexp.js b/deps/v8/test/mjsunit/regexp.js
index e562df090..0a23d00ac 100644
--- a/deps/v8/test/mjsunit/regexp.js
+++ b/deps/v8/test/mjsunit/regexp.js
@@ -375,3 +375,16 @@ assertFalse(/x([0-7]%%%x|[0-6]%%%y)/.test('x7%%%y'), 'qt8');
// Don't hang on this one.
/[^\xfe-\xff]*/.test("");
+
+
+var long = "a";
+for (var i = 0; i < 100000; i++) {
+ long = "a?" + long;
+}
+// Don't crash on this one, but maybe throw an exception.
+try {
+ RegExp(long).exec("a");
+} catch (e) {
+ assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow");
+}
+
diff --git a/deps/v8/test/mjsunit/bugs/bug-334.js b/deps/v8/test/mjsunit/regress/regress-334.js
index 024fc9e85..024fc9e85 100644
--- a/deps/v8/test/mjsunit/bugs/bug-334.js
+++ b/deps/v8/test/mjsunit/regress/regress-334.js
diff --git a/deps/v8/test/mjsunit/regress/regress-341.js b/deps/v8/test/mjsunit/regress/regress-341.js
new file mode 100644
index 000000000..4db6bc696
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-341.js
@@ -0,0 +1,36 @@
+// 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.
+
+// Should not crash.
+// See http://code.google.com/p/v8/issues/detail?id=341
+
+function F() {}
+
+F.prototype = 1;
+var o = {};
+
+assertThrows("o instanceof F");
diff --git a/deps/v8/test/mjsunit/regress/regress-349.js b/deps/v8/test/mjsunit/regress/regress-349.js
new file mode 100644
index 000000000..1a60e3e12
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-349.js
@@ -0,0 +1,32 @@
+// 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.
+
+// Should not crash.
+// See http://code.google.com/p/v8/issues/detail?id=349
+
+var str = "bbaabbbbbbbbabbaaaabbaaabbbaaaabbaaabbabaaabb";
+assertEquals(str, str.replace(/aabab/g, "foo"));
diff --git a/deps/v8/test/mjsunit/regress/regress-351.js b/deps/v8/test/mjsunit/regress/regress-351.js
new file mode 100644
index 000000000..44470db32
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-351.js
@@ -0,0 +1,31 @@
+// 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.
+
+// Should use index of 0 if provided index is negative.
+// See http://code.google.com/p/v8/issues/detail?id=351
+
+assertEquals(0, "test".lastIndexOf("test", -1));
diff --git a/deps/v8/test/mjsunit/string-lastindexof.js b/deps/v8/test/mjsunit/string-lastindexof.js
index bf46666ee..27378f789 100644
--- a/deps/v8/test/mjsunit/string-lastindexof.js
+++ b/deps/v8/test/mjsunit/string-lastindexof.js
@@ -27,25 +27,62 @@
var s = "test test test";
-assertEquals(5, s.lastIndexOf("test", 5));
-assertEquals(5, s.lastIndexOf("test", 6));
-assertEquals(0, s.lastIndexOf("test", 4));
-assertEquals(0, s.lastIndexOf("test", 0));
-assertEquals(-1, s.lastIndexOf("test", -1));
-assertEquals(10, s.lastIndexOf("test"));
-assertEquals(-1, s.lastIndexOf("notpresent"));
-assertEquals(-1, s.lastIndexOf());
-assertEquals(10, s.lastIndexOf("test", "not a number"));
+var MAX_DOUBLE = 1.7976931348623157e+308;
+var MIN_DOUBLE = -MAX_DOUBLE;
+var MAX_SMI = Math.pow(2,30)-1;
+var MIN_SMI = -Math.pow(2,30);
+
+assertEquals(10, s.lastIndexOf("test", Infinity), "tinf");
+assertEquals(10, s.lastIndexOf("test", MAX_DOUBLE), "tmaxdouble");
+assertEquals(10, s.lastIndexOf("test", MAX_SMI), "tmaxsmi");
+assertEquals(10, s.lastIndexOf("test", s.length * 2), "t2length");
+assertEquals(10, s.lastIndexOf("test", 15), "t15");
+assertEquals(10, s.lastIndexOf("test", 14), "t14");
+assertEquals(10, s.lastIndexOf("test", 10), "t10");
+assertEquals(5, s.lastIndexOf("test", 9), "t9");
+assertEquals(5, s.lastIndexOf("test", 6), "t6");
+assertEquals(5, s.lastIndexOf("test", 5), "t5");
+assertEquals(0, s.lastIndexOf("test", 4), "t4");
+assertEquals(0, s.lastIndexOf("test", 0), "t0");
+assertEquals(0, s.lastIndexOf("test", -1), "t-1");
+assertEquals(0, s.lastIndexOf("test", -s.length), "t-len");
+assertEquals(0, s.lastIndexOf("test", MIN_SMI), "tminsmi");
+assertEquals(0, s.lastIndexOf("test", MIN_DOUBLE), "tmindouble");
+assertEquals(0, s.lastIndexOf("test", -Infinity), "tneginf");
+assertEquals(10, s.lastIndexOf("test"), "t");
+assertEquals(-1, s.lastIndexOf("notpresent"), "n");
+assertEquals(-1, s.lastIndexOf(), "none");
+assertEquals(10, s.lastIndexOf("test", "not a number"), "nan");
+
+var longNonMatch = "overlong string that doesn't match";
+var longAlmostMatch = "test test test!";
+var longAlmostMatch2 = "!test test test";
+
+
+assertEquals(-1, s.lastIndexOf(longNonMatch), "long");
+assertEquals(-1, s.lastIndexOf(longNonMatch, 10), "longpos");
+assertEquals(-1, s.lastIndexOf(longNonMatch, NaN), "longnan");
+assertEquals(-1, s.lastIndexOf(longAlmostMatch), "tlong");
+assertEquals(-1, s.lastIndexOf(longAlmostMatch, 10), "tlongpos");
+assertEquals(-1, s.lastIndexOf(longAlmostMatch), "tlongnan");
+
+var nonInitialMatch = "est";
+
+assertEquals(-1, s.lastIndexOf(nonInitialMatch, 0), "noninit");
+assertEquals(-1, s.lastIndexOf(nonInitialMatch, -1), "noninitneg");
+assertEquals(-1, s.lastIndexOf(nonInitialMatch, MIN_SMI), "noninitminsmi");
+assertEquals(-1, s.lastIndexOf(nonInitialMatch, MIN_DOUBLE), "noninitmindbl");
+assertEquals(-1, s.lastIndexOf(nonInitialMatch, -Infinity), "noninitneginf");
for (var i = s.length + 10; i >= 0; i--) {
var expected = i < s.length ? i : s.length;
- assertEquals(expected, s.lastIndexOf("", i));
+ assertEquals(expected, s.lastIndexOf("", i), "empty" + i);
}
var reString = "asdf[a-z]+(asdf)?";
-assertEquals(4, reString.lastIndexOf("[a-z]+"));
-assertEquals(10, reString.lastIndexOf("(asdf)?"));
+assertEquals(4, reString.lastIndexOf("[a-z]+"), "r4");
+assertEquals(10, reString.lastIndexOf("(asdf)?"), "r10");
-assertEquals(1, String.prototype.lastIndexOf.length);
+assertEquals(1, String.prototype.lastIndexOf.length, "length");