Update V8 to r6101 as required by WebKit r74534
Change-Id: I7f84af8dd732f11898fd644b2c2b1538914cb78d
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index ba3466d..7038137 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -50,6 +50,7 @@
'test-dataflow.cc',
'test-debug.cc',
'test-decls.cc',
+ 'test-deoptimization.cc',
'test-diy-fp.cc',
'test-double.cc',
'test-dtoa.cc',
@@ -69,6 +70,7 @@
'test-parsing.cc',
'test-profile-generator.cc',
'test-regexp.cc',
+ 'test-reloc-info.cc',
'test-serialize.cc',
'test-sockets.cc',
'test-spaces.cc',
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
new file mode 100644
index 0000000..aa2b355
--- /dev/null
+++ b/test/cctest/cctest.gyp
@@ -0,0 +1,160 @@
+# Copyright 2010 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS!="mac"', {
+ # TODO(sgjesse): This is currently copied from v8.gyp, should probably
+ # be refactored.
+ 'conditions': [
+ ['v8_target_arch=="arm"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_ARM',
+ ],
+ }],
+ ['v8_target_arch=="ia32"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_IA32',
+ ],
+ }],
+ ['v8_target_arch=="x64"', {
+ 'defines': [
+ 'V8_TARGET_ARCH_X64',
+ ],
+ }],
+ ],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'cctest',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../tools/gyp/v8.gyp:v8',
+ ],
+ 'include_dirs': [
+ '../../src',
+ ],
+ 'sources': [
+ 'cctest.cc',
+ 'gay-fixed.cc',
+ 'gay-precision.cc',
+ 'gay-shortest.cc',
+ 'test-accessors.cc',
+ 'test-alloc.cc',
+ 'test-api.cc',
+ 'test-ast.cc',
+ 'test-bignum.cc',
+ 'test-bignum-dtoa.cc',
+ 'test-circular-queue.cc',
+ 'test-compiler.cc',
+ 'test-conversions.cc',
+ 'test-cpu-profiler.cc',
+ 'test-dataflow.cc',
+ 'test-debug.cc',
+ 'test-decls.cc',
+ 'test-deoptimization.cc',
+ 'test-diy-fp.cc',
+ 'test-double.cc',
+ 'test-dtoa.cc',
+ 'test-fast-dtoa.cc',
+ 'test-fixed-dtoa.cc',
+ 'test-flags.cc',
+ 'test-func-name-inference.cc',
+ 'test-hashmap.cc',
+ 'test-heap.cc',
+ 'test-heap-profiler.cc',
+ 'test-list.cc',
+ 'test-liveedit.cc',
+ 'test-lock.cc',
+ 'test-log.cc',
+ 'test-log-utils.cc',
+ 'test-mark-compact.cc',
+ 'test-parsing.cc',
+ 'test-profile-generator.cc',
+ 'test-regexp.cc',
+ 'test-reloc-info.cc',
+ 'test-serialize.cc',
+ 'test-sockets.cc',
+ 'test-spaces.cc',
+ 'test-strings.cc',
+ 'test-strtod.cc',
+ 'test-thread-termination.cc',
+ 'test-threads.cc',
+ 'test-type-info.cc',
+ 'test-unbound-queue.cc',
+ 'test-utils.cc',
+ 'test-version.cc'
+ ],
+ 'conditions': [
+ ['v8_target_arch=="ia32"', {
+ 'sources': [
+ 'test-assembler-ia32.cc',
+ 'test-disasm-ia32.cc',
+ 'test-log-stack-tracer.cc'
+ ],
+ }],
+ ['v8_target_arch=="x64"', {
+ 'sources': [
+ 'test-assembler-x64.cc',
+ 'test-macro-assembler-x64.cc',
+ 'test-log-stack-tracer.cc'
+ ],
+ }],
+ ['v8_target_arch=="arm"', {
+ 'sources': [
+ 'test-assembler-arm.cc',
+ 'test-disasm-arm.cc'
+ ],
+ }],
+ ['v8_target_arch=="mips"', {
+ 'sources': [
+ 'test-assembler-mips.cc',
+ 'test-mips.cc',
+ ],
+ }],
+ [ 'OS=="linux"', {
+ 'sources': [
+ 'test-platform-linux.cc',
+ ],
+ }],
+ [ 'OS=="mac"', {
+ 'sources': [
+ 'test-platform-macos.cc',
+ ],
+ }],
+ [ 'OS=="win"', {
+ 'sources': [
+ 'test-platform-win32.cc',
+ ],
+ }],
+ ],
+ },
+ ],
+}
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 895e245..4dfe51a 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -29,19 +29,40 @@
test-api/Bug*: FAIL
+
+##############################################################################
# BUG(281): This test fails on some Linuxes.
test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux
# BUG(382): Weird test. Can't guarantee that it never times out.
test-api/ApplyInterruption: PASS || TIMEOUT
+# BUG(484): This test which we thought was originally corrected in r5236
+# is re-appearing. Disabled until bug in test is fixed. This only fails
+# when snapshot is on, so I am marking it PASS || FAIL
+test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
+
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
test-serialize/TestThatAlwaysFails: FAIL
test-serialize/DependentTestThatAlwaysFails: FAIL
+
+##############################################################################
+[ $arch == x64 ]
+
+# Optimization is currently not working on crankshaft x64 and ARM.
+test-heap/TestInternalWeakLists: PASS || FAIL
+test-heap/TestInternalWeakListsTraverseWithGC: PASS || FAIL
+
+
+##############################################################################
[ $arch == arm ]
+# Optimization is currently not working on crankshaft x64 and ARM.
+test-heap/TestInternalWeakLists: PASS || FAIL
+test-heap/TestInternalWeakListsTraverseWithGC: PASS || FAIL
+
# 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.
@@ -51,6 +72,23 @@
# BUG(355): Test crashes on ARM.
test-log/ProfLazyMode: SKIP
+# BUG(945): Socket connect fails on ARM
+test-debug/DebuggerAgentProtocolOverflowHeader: SKIP
+test-sockets/Socket: SKIP
+
+
+##############################################################################
+[ $arch == arm && $crankshaft ]
+
+# Tests that fail with crankshaft.
+test-deoptimization/DeoptimizeBinaryOperationMOD: FAIL
+
+# Tests that time out with crankshaft.
+test-debug/ThreadedDebugging: SKIP
+test-debug/DebugBreakLoop: SKIP
+
+
+##############################################################################
[ $arch == mips ]
test-accessors: SKIP
test-alloc: SKIP
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index fcf2ce4..d2a28d7 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -133,7 +133,7 @@
// Force the creation of an initial map and set the code to
// something empty.
Factory::NewJSObject(function);
- function->set_code(Builtins::builtin(Builtins::EmptyFunction));
+ function->ReplaceCode(Builtins::builtin(Builtins::EmptyFunction));
// Patch the map to have an accessor for "get".
Handle<Map> map(function->initial_map());
Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 4af0c52..9539973 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -814,79 +814,6 @@
}
-static void* expected_ptr;
-static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
- void* ptr = v8::External::Unwrap(args.Data());
- CHECK_EQ(expected_ptr, ptr);
- return v8::Boolean::New(true);
-}
-
-
-static void TestExternalPointerWrapping() {
- v8::HandleScope scope;
- LocalContext env;
-
- v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
-
- v8::Handle<v8::Object> obj = v8::Object::New();
- obj->Set(v8_str("func"),
- v8::FunctionTemplate::New(callback, data)->GetFunction());
- env->Global()->Set(v8_str("obj"), obj);
-
- CHECK(CompileRun(
- "function foo() {\n"
- " for (var i = 0; i < 13; i++) obj.func();\n"
- "}\n"
- "foo(), true")->BooleanValue());
-}
-
-
-THREADED_TEST(ExternalWrap) {
- // Check heap allocated object.
- int* ptr = new int;
- expected_ptr = ptr;
- TestExternalPointerWrapping();
- delete ptr;
-
- // Check stack allocated object.
- int foo;
- expected_ptr = &foo;
- TestExternalPointerWrapping();
-
- // Check not aligned addresses.
- const int n = 100;
- char* s = new char[n];
- for (int i = 0; i < n; i++) {
- expected_ptr = s + i;
- TestExternalPointerWrapping();
- }
-
- delete[] s;
-
- // Check several invalid addresses.
- expected_ptr = reinterpret_cast<void*>(1);
- TestExternalPointerWrapping();
-
- expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
- TestExternalPointerWrapping();
-
- expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
- TestExternalPointerWrapping();
-
-#if defined(V8_HOST_ARCH_X64)
- // Check a value with a leading 1 bit in x64 Smi encoding.
- expected_ptr = reinterpret_cast<void*>(0x400000000);
- TestExternalPointerWrapping();
-
- expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
- TestExternalPointerWrapping();
-
- expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
- TestExternalPointerWrapping();
-#endif
-}
-
-
THREADED_TEST(FindInstanceInPrototypeChain) {
v8::HandleScope scope;
LocalContext env;
@@ -4417,47 +4344,167 @@
}
+static int StrCmp16(uint16_t* a, uint16_t* b) {
+ while (true) {
+ if (*a == 0 && *b == 0) return 0;
+ if (*a != *b) return 0 + *a - *b;
+ a++;
+ b++;
+ }
+}
+
+
+static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
+ while (true) {
+ if (n-- == 0) return 0;
+ if (*a == 0 && *b == 0) return 0;
+ if (*a != *b) return 0 + *a - *b;
+ a++;
+ b++;
+ }
+}
+
+
THREADED_TEST(StringWrite) {
v8::HandleScope scope;
v8::Handle<String> str = v8_str("abcde");
+ // abc<Icelandic eth><Unicode snowman>.
+ v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
+
+ CHECK_EQ(5, str2->Length());
char buf[100];
+ char utf8buf[100];
+ uint16_t wbuf[100];
int len;
+ int charlen;
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
+ CHECK_EQ(len, 9);
+ CHECK_EQ(charlen, 5);
+ CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 8, &charlen);
+ CHECK_EQ(len, 8);
+ CHECK_EQ(charlen, 5);
+ CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 7, &charlen);
+ CHECK_EQ(len, 5);
+ CHECK_EQ(charlen, 4);
+ CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 6, &charlen);
+ CHECK_EQ(len, 5);
+ CHECK_EQ(charlen, 4);
+ CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 5, &charlen);
+ CHECK_EQ(len, 5);
+ CHECK_EQ(charlen, 4);
+ CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 4, &charlen);
+ CHECK_EQ(len, 3);
+ CHECK_EQ(charlen, 3);
+ CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 3, &charlen);
+ CHECK_EQ(len, 3);
+ CHECK_EQ(charlen, 3);
+ CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
+
+ memset(utf8buf, 0x1, sizeof(utf8buf));
+ len = str2->WriteUtf8(utf8buf, 2, &charlen);
+ CHECK_EQ(len, 2);
+ CHECK_EQ(charlen, 2);
+ CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf);
CHECK_EQ(len, 5);
- CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
+ len = str->Write(wbuf);
+ CHECK_EQ(len, 5);
+ CHECK_EQ(strcmp("abcde", buf), 0);
+ uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
+ CHECK_EQ(StrCmp16(answer1, wbuf), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 4);
CHECK_EQ(len, 4);
+ len = str->Write(wbuf, 0, 4);
+ CHECK_EQ(len, 4);
CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
+ uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
+ CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 5);
CHECK_EQ(len, 5);
+ len = str->Write(wbuf, 0, 5);
+ CHECK_EQ(len, 5);
CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
+ uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
+ CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 0, 6);
CHECK_EQ(len, 5);
- CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
+ len = str->Write(wbuf, 0, 6);
+ CHECK_EQ(len, 5);
+ CHECK_EQ(strcmp("abcde", buf), 0);
+ uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
+ CHECK_EQ(StrCmp16(answer4, wbuf), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, -1);
CHECK_EQ(len, 1);
- CHECK_EQ(strncmp("e\0", buf, 2), 0);
+ len = str->Write(wbuf, 4, -1);
+ CHECK_EQ(len, 1);
+ CHECK_EQ(strcmp("e", buf), 0);
+ uint16_t answer5[] = {'e', '\0'};
+ CHECK_EQ(StrCmp16(answer5, wbuf), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, 6);
CHECK_EQ(len, 1);
- CHECK_EQ(strncmp("e\0", buf, 2), 0);
+ len = str->Write(wbuf, 4, 6);
+ CHECK_EQ(len, 1);
+ CHECK_EQ(strcmp("e", buf), 0);
+ CHECK_EQ(StrCmp16(answer5, wbuf), 0);
memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
len = str->WriteAscii(buf, 4, 1);
CHECK_EQ(len, 1);
+ len = str->Write(wbuf, 4, 1);
+ CHECK_EQ(len, 1);
CHECK_EQ(strncmp("e\1", buf, 2), 0);
+ uint16_t answer6[] = {'e', 0x101};
+ CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
+
+ memset(buf, 0x1, sizeof(buf));
+ memset(wbuf, 0x1, sizeof(wbuf));
+ len = str->WriteAscii(buf, 3, 1);
+ CHECK_EQ(len, 1);
+ len = str->Write(wbuf, 3, 1);
+ CHECK_EQ(len, 1);
+ CHECK_EQ(strncmp("d\1", buf, 2), 0);
+ uint16_t answer7[] = {'d', 0x101};
+ CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
}
@@ -5133,13 +5180,11 @@
}
-static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
static bool NamedAccessBlocker(Local<v8::Object> global,
Local<Value> name,
v8::AccessType type,
Local<Value> data) {
- return Context::GetCurrent()->Global()->Equals(global) ||
- allowed_access_type[type];
+ return Context::GetCurrent()->Global()->Equals(global);
}
@@ -5147,8 +5192,7 @@
uint32_t key,
v8::AccessType type,
Local<Value> data) {
- return Context::GetCurrent()->Global()->Equals(global) ||
- allowed_access_type[type];
+ return Context::GetCurrent()->Global()->Equals(global);
}
@@ -5180,7 +5224,7 @@
}
-TEST(AccessControl) {
+THREADED_TEST(AccessControl) {
v8::HandleScope handle_scope;
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
@@ -5206,27 +5250,6 @@
v8::Handle<v8::Object> global0 = context0->Global();
- // Define a property with JS getter and setter.
- CompileRun(
- "function getter() { return 'getter'; };\n"
- "function setter() { return 'setter'; }\n"
- "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
-
- Local<Value> getter = global0->Get(v8_str("getter"));
- Local<Value> setter = global0->Get(v8_str("setter"));
-
- // And define normal element.
- global0->Set(239, v8_str("239"));
-
- // Define an element with JS getter and setter.
- CompileRun(
- "function el_getter() { return 'el_getter'; };\n"
- "function el_setter() { return 'el_setter'; };\n"
- "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
-
- Local<Value> el_getter = global0->Get(v8_str("el_getter"));
- Local<Value> el_setter = global0->Get(v8_str("el_setter"));
-
v8::HandleScope scope1;
v8::Persistent<Context> context1 = Context::New();
@@ -5235,187 +5258,40 @@
v8::Handle<v8::Object> global1 = context1->Global();
global1->Set(v8_str("other"), global0);
- // Access blocked property.
- CompileRun("other.blocked_prop = 1");
-
- ExpectUndefined("other.blocked_prop");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
- ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
-
- // Enable ACCESS_HAS
- allowed_access_type[v8::ACCESS_HAS] = true;
- ExpectUndefined("other.blocked_prop");
- // ... and now we can get the descriptor...
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
- // ... and enumerate the property.
- ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Access blocked element.
- CompileRun("other[239] = 1");
-
- ExpectUndefined("other[239]");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
- ExpectFalse("propertyIsEnumerable.call(other, '239')");
-
- // Enable ACCESS_HAS
- allowed_access_type[v8::ACCESS_HAS] = true;
- ExpectUndefined("other[239]");
- // ... and now we can get the descriptor...
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
- // ... and enumerate the property.
- ExpectTrue("propertyIsEnumerable.call(other, '239')");
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Access a property with JS accessor.
- CompileRun("other.js_accessor_p = 2");
-
- ExpectUndefined("other.js_accessor_p");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
-
- // Enable ACCESS_HAS.
- allowed_access_type[v8::ACCESS_HAS] = true;
- ExpectUndefined("other.js_accessor_p");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS and ACCESS_GET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
-
- ExpectString("other.js_accessor_p", "getter");
- ExpectObject(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
-
- allowed_access_type[v8::ACCESS_GET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS and ACCESS_SET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_SET] = true;
-
- ExpectUndefined("other.js_accessor_p");
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
- ExpectObject(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
-
- allowed_access_type[v8::ACCESS_SET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
- allowed_access_type[v8::ACCESS_SET] = true;
-
- ExpectString("other.js_accessor_p", "getter");
- ExpectObject(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
- ExpectObject(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
- ExpectUndefined(
- "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
-
- allowed_access_type[v8::ACCESS_SET] = false;
- allowed_access_type[v8::ACCESS_GET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Access an element with JS accessor.
- CompileRun("other[42] = 2");
-
- ExpectUndefined("other[42]");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
-
- // Enable ACCESS_HAS.
- allowed_access_type[v8::ACCESS_HAS] = true;
- ExpectUndefined("other[42]");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS and ACCESS_GET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
-
- ExpectString("other[42]", "el_getter");
- ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
-
- allowed_access_type[v8::ACCESS_GET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS and ACCESS_SET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_SET] = true;
-
- ExpectUndefined("other[42]");
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
- ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
-
- allowed_access_type[v8::ACCESS_SET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
- // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
- allowed_access_type[v8::ACCESS_HAS] = true;
- allowed_access_type[v8::ACCESS_GET] = true;
- allowed_access_type[v8::ACCESS_SET] = true;
-
- ExpectString("other[42]", "el_getter");
- ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
- ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
- ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
-
- allowed_access_type[v8::ACCESS_SET] = false;
- allowed_access_type[v8::ACCESS_GET] = false;
- allowed_access_type[v8::ACCESS_HAS] = false;
-
v8::Handle<Value> value;
+ // Access blocked property
+ value = v8_compile("other.blocked_prop = 1")->Run();
+ value = v8_compile("other.blocked_prop")->Run();
+ CHECK(value->IsUndefined());
+
+ value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
+ CHECK(value->IsFalse());
+
// Access accessible property
- value = CompileRun("other.accessible_prop = 3");
+ value = v8_compile("other.accessible_prop = 3")->Run();
CHECK(value->IsNumber());
CHECK_EQ(3, value->Int32Value());
CHECK_EQ(3, g_echo_value);
- value = CompileRun("other.accessible_prop");
+ value = v8_compile("other.accessible_prop")->Run();
CHECK(value->IsNumber());
CHECK_EQ(3, value->Int32Value());
- value = CompileRun(
- "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
- CHECK(value->IsNumber());
- CHECK_EQ(3, value->Int32Value());
-
- value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
+ value =
+ v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
CHECK(value->IsTrue());
// Enumeration doesn't enumerate accessors from inaccessible objects in
// the prototype chain even if the accessors are in themselves accessible.
- value =
+ Local<Value> result =
CompileRun("(function(){var obj = {'__proto__':other};"
"for (var p in obj)"
" if (p == 'accessible_prop' || p == 'blocked_prop') {"
" return false;"
" }"
"return true;})()");
- CHECK(value->IsTrue());
+ CHECK(result->IsTrue());
context1->Exit();
context0->Exit();
@@ -5922,6 +5798,22 @@
instance_template->Set(v8_str("f"),
v8::FunctionTemplate::New(InstanceFunctionCallback));
+ // The script to check how Crankshaft compiles missing global function
+ // invocations. function g is not defined and should throw on call.
+ const char* script =
+ "function wrapper(call) {"
+ " var x = 0, y = 1;"
+ " for (var i = 0; i < 1000; i++) {"
+ " x += i * 100;"
+ " y += i * 100;"
+ " }"
+ " if (call) g();"
+ "}"
+ "for (var i = 0; i < 17; i++) wrapper(false);"
+ "var thrown = 0;"
+ "try { wrapper(true); } catch (e) { thrown = 1; };"
+ "thrown";
+
{
LocalContext env(NULL, instance_template);
// Hold on to the global object so it can be used again in another
@@ -5932,6 +5824,8 @@
CHECK_EQ(42, value->Int32Value());
value = Script::Compile(v8_str("f()"))->Run();
CHECK_EQ(12, value->Int32Value());
+ value = Script::Compile(v8_str(script))->Run();
+ CHECK_EQ(1, value->Int32Value());
}
{
@@ -5941,6 +5835,48 @@
CHECK_EQ(42, value->Int32Value());
value = Script::Compile(v8_str("f()"))->Run();
CHECK_EQ(12, value->Int32Value());
+ value = Script::Compile(v8_str(script))->Run();
+ CHECK_EQ(1, value->Int32Value());
+ }
+}
+
+
+THREADED_TEST(CallKnownGlobalReceiver) {
+ v8::HandleScope handle_scope;
+
+ Local<Value> global_object;
+
+ Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+
+ // The script to check that we leave global object not
+ // global object proxy on stack when we deoptimize from inside
+ // arguments evaluation.
+ // To provoke error we need to both force deoptimization
+ // from arguments evaluation and to force CallIC to take
+ // CallIC_Miss code path that can't cope with global proxy.
+ const char* script =
+ "function bar(x, y) { try { } finally { } }"
+ "function baz(x) { try { } finally { } }"
+ "function bom(x) { try { } finally { } }"
+ "function foo(x) { bar([x], bom(2)); }"
+ "for (var i = 0; i < 10000; i++) foo(1);"
+ "foo";
+
+ Local<Value> foo;
+ {
+ LocalContext env(NULL, instance_template);
+ // Hold on to the global object so it can be used again in another
+ // environment initialization.
+ global_object = env->Global();
+ foo = Script::Compile(v8_str(script))->Run();
+ }
+
+ {
+ // Create new environment reusing the global object.
+ LocalContext env(NULL, instance_template, global_object);
+ env->Global()->Set(v8_str("foo"), foo);
+ Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
}
}
@@ -8915,6 +8851,105 @@
}
+v8::Handle<v8::String> a;
+v8::Handle<v8::String> h;
+
+static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
+ Local<Value> name,
+ v8::AccessType type,
+ Local<Value> data) {
+ return !(name->Equals(a) || name->Equals(h));
+}
+
+
+THREADED_TEST(TurnOnAccessCheckAndRecompile) {
+ v8::HandleScope handle_scope;
+
+ // Create an environment with access check to the global object disabled by
+ // default. When the registered access checker will block access to properties
+ // a and h
+ a = v8_str("a");
+ h = v8_str("h");
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
+ IndexedGetAccessBlocker,
+ v8::Handle<v8::Value>(),
+ false);
+ v8::Persistent<Context> context = Context::New(NULL, global_template);
+ Context::Scope context_scope(context);
+
+ // Set up a property and a number of functions.
+ context->Global()->Set(v8_str("a"), v8_num(1));
+ static const char* source = "function f1() {return a;}"
+ "function f2() {return a;}"
+ "function g1() {return h();}"
+ "function g2() {return h();}"
+ "function h() {return 1;}";
+
+ CompileRun(source);
+ Local<Function> f1;
+ Local<Function> f2;
+ Local<Function> g1;
+ Local<Function> g2;
+ Local<Function> h;
+ f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
+ f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
+ g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
+ g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
+ h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
+
+ // Get the global object.
+ v8::Handle<v8::Object> global = context->Global();
+
+ // Call f1 one time and f2 a number of times. This will ensure that f1 still
+ // uses the runtime system to retreive property a whereas f2 uses global load
+ // inline cache.
+ CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
+ for (int i = 0; i < 4; i++) {
+ CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
+ }
+
+ // Same for g1 and g2.
+ CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
+ for (int i = 0; i < 4; i++) {
+ CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
+ }
+
+ // Detach the global and turn on access check now blocking access to property
+ // a and function h.
+ context->DetachGlobal();
+ context->Global()->TurnOnAccessCheck();
+
+ // Failing access check to property get results in undefined.
+ CHECK(f1->Call(global, 0, NULL)->IsUndefined());
+ CHECK(f2->Call(global, 0, NULL)->IsUndefined());
+
+ // Failing access check to function call results in exception.
+ CHECK(g1->Call(global, 0, NULL).IsEmpty());
+ CHECK(g2->Call(global, 0, NULL).IsEmpty());
+
+ // No failing access check when just returning a constant.
+ CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
+
+ // Now compile the source again. And get the newly compiled functions, except
+ // for h for which access is blocked.
+ CompileRun(source);
+ f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
+ f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
+ g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
+ g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
+ CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
+
+ // Failing access check to property get results in undefined.
+ CHECK(f1->Call(global, 0, NULL)->IsUndefined());
+ CHECK(f2->Call(global, 0, NULL)->IsUndefined());
+
+ // Failing access check to function call results in exception.
+ CHECK(g1->Call(global, 0, NULL).IsEmpty());
+ CHECK(g2->Call(global, 0, NULL).IsEmpty());
+}
+
+
// This test verifies that pre-compilation (aka preparsing) can be called
// without initializing the whole VM. Thus we cannot run this test in a
// multi-threaded setup.
@@ -10766,7 +10801,9 @@
// Tests the C++ StackTrace API.
-THREADED_TEST(CaptureStackTrace) {
+// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
+// THREADED_TEST(CaptureStackTrace) {
+TEST(CaptureStackTrace) {
v8::HandleScope scope;
v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
Local<ObjectTemplate> templ = ObjectTemplate::New();
diff --git a/test/cctest/test-dataflow.cc b/test/cctest/test-dataflow.cc
index 003ac66..5894de2 100644
--- a/test/cctest/test-dataflow.cc
+++ b/test/cctest/test-dataflow.cc
@@ -52,6 +52,24 @@
}
{
+ BitVector v(64);
+ v.Add(27);
+ v.Add(30);
+ v.Add(31);
+ v.Add(33);
+ BitVector::Iterator iter(&v);
+ CHECK_EQ(27, iter.Current());
+ iter.Advance();
+ CHECK_EQ(30, iter.Current());
+ iter.Advance();
+ CHECK_EQ(31, iter.Current());
+ iter.Advance();
+ CHECK_EQ(33, iter.Current());
+ iter.Advance();
+ CHECK(iter.Done());
+ }
+
+ {
BitVector v(15);
v.Add(0);
BitVector w(15);
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 7791185..87f9cab 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -1,4 +1,4 @@
-// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -32,11 +32,13 @@
#include "v8.h"
#include "api.h"
+#include "cctest.h"
#include "compilation-cache.h"
#include "debug.h"
+#include "deoptimizer.h"
#include "platform.h"
#include "stub-cache.h"
-#include "cctest.h"
+#include "utils.h"
using ::v8::internal::EmbeddedVector;
@@ -515,16 +517,52 @@
// ---
-// Source for The JavaScript function which picks out the function name of the
-// top frame.
+// Source for the JavaScript function which picks out the function
+// name of a frame.
const char* frame_function_name_source =
- "function frame_function_name(exec_state) {"
- " return exec_state.frame(0).func().name();"
+ "function frame_function_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).func().name();"
"}";
v8::Local<v8::Function> frame_function_name;
-// Source for The JavaScript function which picks out the source line for the
+// Source for the JavaScript function which pick out the name of the
+// first argument of a frame.
+const char* frame_argument_name_source =
+ "function frame_argument_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).argumentName(0);"
+ "}";
+v8::Local<v8::Function> frame_argument_name;
+
+
+// Source for the JavaScript function which pick out the value of the
+// first argument of a frame.
+const char* frame_argument_value_source =
+ "function frame_argument_value(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).argumentValue(0).value_;"
+ "}";
+v8::Local<v8::Function> frame_argument_value;
+
+
+// Source for the JavaScript function which pick out the name of the
+// first argument of a frame.
+const char* frame_local_name_source =
+ "function frame_local_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).localName(0);"
+ "}";
+v8::Local<v8::Function> frame_local_name;
+
+
+// Source for the JavaScript function which pick out the value of the
+// first argument of a frame.
+const char* frame_local_value_source =
+ "function frame_local_value(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).localValue(0).value_;"
+ "}";
+v8::Local<v8::Function> frame_local_value;
+
+
+// Source for the JavaScript function which picks out the source line for the
// top frame.
const char* frame_source_line_source =
"function frame_source_line(exec_state) {"
@@ -533,7 +571,7 @@
v8::Local<v8::Function> frame_source_line;
-// Source for The JavaScript function which picks out the source column for the
+// Source for the JavaScript function which picks out the source column for the
// top frame.
const char* frame_source_column_source =
"function frame_source_column(exec_state) {"
@@ -542,7 +580,7 @@
v8::Local<v8::Function> frame_source_column;
-// Source for The JavaScript function which picks out the script name for the
+// Source for the JavaScript function which picks out the script name for the
// top frame.
const char* frame_script_name_source =
"function frame_script_name(exec_state) {"
@@ -551,7 +589,7 @@
v8::Local<v8::Function> frame_script_name;
-// Source for The JavaScript function which picks out the script data for the
+// Source for the JavaScript function which picks out the script data for the
// top frame.
const char* frame_script_data_source =
"function frame_script_data(exec_state) {"
@@ -560,7 +598,7 @@
v8::Local<v8::Function> frame_script_data;
-// Source for The JavaScript function which picks out the script data from
+// Source for the JavaScript function which picks out the script data from
// AfterCompile event
const char* compiled_script_data_source =
"function compiled_script_data(event_data) {"
@@ -569,7 +607,7 @@
v8::Local<v8::Function> compiled_script_data;
-// Source for The JavaScript function which returns the number of frames.
+// Source for the JavaScript function which returns the number of frames.
static const char* frame_count_source =
"function frame_count(exec_state) {"
" return exec_state.frameCount();"
@@ -603,8 +641,8 @@
break_point_hit_count++;
if (!frame_function_name.IsEmpty()) {
// Get the name of the function.
- const int argc = 1;
- v8::Handle<v8::Value> argv[argc] = { exec_state };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
@@ -834,8 +872,8 @@
// Check that the current function is the expected.
CHECK(break_point_hit_count <
StrLength(expected_step_sequence));
- const int argc = 1;
- v8::Handle<v8::Value> argv[argc] = { exec_state };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
CHECK(result->IsString());
@@ -2586,6 +2624,10 @@
v8::Local<v8::Function> foo = CompileFunction(&env,
"function foo(){a=1;b=1;c=1;}",
"foo");
+
+ // Run foo to allow it to get optimized.
+ CompileRun("a=0; b=0; c=0; foo();");
+
SetBreakPoint(foo, 3);
// Register a debug event listener which steps and counts.
@@ -2635,7 +2677,8 @@
" y = 1;\n"
" x = a[i];\n"
" }\n"
- "}\n",
+ "}\n"
+ "y=0\n",
"foo");
// Create array [0,1,2,3,4,5,6,7,8,9]
@@ -2681,7 +2724,8 @@
" y = 1;\n"
" a[i] = 42;\n"
" }\n"
- "}\n",
+ "}\n"
+ "y=0\n",
"foo");
// Create array [0,1,2,3,4,5,6,7,8,9]
@@ -2753,15 +2797,12 @@
}
-static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
+static void DoDebugStepNamedStoreLoop(int expected) {
v8::HandleScope scope;
DebugLocalContext env;
- // Register a debug event listener which steps and counts before compiling the
- // function to ensure the full compiler is used.
- if (full_compiler) {
- v8::Debug::SetDebugEventListener(DebugEventStep);
- }
+ // Register a debug event listener which steps and counts.
+ v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping of named store.
v8::Local<v8::Function> foo = CompileFunction(
@@ -2777,12 +2818,6 @@
// Call function without any break points to ensure inlining is in place.
foo->Call(env->Global(), 0, NULL);
- // Register a debug event listener which steps and counts after compiling the
- // function to ensure the optimizing compiler is used.
- if (!full_compiler) {
- v8::Debug::SetDebugEventListener(DebugEventStep);
- }
-
// Setup break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
@@ -2798,20 +2833,11 @@
// Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoopFull) {
- // With the full compiler it is possible to break on the for statement.
+TEST(DebugStepNamedStoreLoop) {
DoDebugStepNamedStoreLoop(22);
}
-// Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoopOptimizing) {
- // With the optimizing compiler it is not possible to break on the for
- // statement as it uses a local variable thus no IC's.
- DoDebugStepNamedStoreLoop(11, false);
-}
-
-
// Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs) {
v8::HandleScope scope;
@@ -2828,6 +2854,10 @@
" var index='name';"
" var y = {};"
" a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
+
+ // Run functions to allow them to get optimized.
+ CompileRun("a=0; b=0; bar(); foo();");
+
SetBreakPoint(foo, 0);
step_action = StepIn;
@@ -2862,15 +2892,18 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo() { "
" var a;"
" var b = 1;"
" var c = foo;"
" var d = Math.floor;"
" var e = b + d(1.2);"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 0);
// Stepping through the declarations.
@@ -2892,15 +2925,18 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo() { "
" var a,b;"
" a = 1;"
" b = a + 2;"
" b = 1 + 2 + 3;"
" a = Math.floor(b);"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 0);
// Stepping through the declarations.
@@ -2922,7 +2958,8 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
@@ -2932,7 +2969,8 @@
" c = 1;"
" d = 1;"
" }"
- "}";
+ "}"
+ "a=0; b=0; c=0; d=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
@@ -2963,7 +3001,8 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
@@ -2979,7 +3018,8 @@
" f = 1;"
" break;"
" }"
- "}";
+ "}"
+ "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
@@ -3017,14 +3057,16 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" while (a < x) {"
" a++;"
" }"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3033,14 +3075,14 @@
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
foo->Call(env->Global(), argc, argv_10);
- CHECK_EQ(23, break_point_hit_count);
+ CHECK_EQ(22, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
foo->Call(env->Global(), argc, argv_100);
- CHECK_EQ(203, break_point_hit_count);
+ CHECK_EQ(202, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
@@ -3055,14 +3097,16 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" do {"
" a++;"
" } while (a < x)"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3093,15 +3137,18 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
" for (i = 0; i < x; i++) {"
" b = 1;"
" }"
- "}";
+ "}"
+ "a=0; b=0; i=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 8); // "a = 1;"
// Looping 10 times.
@@ -3131,7 +3178,8 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
@@ -3144,7 +3192,8 @@
" c++;"
" }"
" return b;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3180,7 +3229,8 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
@@ -3193,7 +3243,8 @@
" c++;"
" }"
" return b;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3230,13 +3281,16 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
v8::Local<v8::Function> foo;
const char* src_1 = "function foo() { "
" var a = [1, 2];"
" for (x in a) {"
" b = 0;"
" }"
- "}";
+ "}"
+ "foo()";
foo = CompileFunction(&env, src_1, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
@@ -3245,12 +3299,15 @@
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(6, break_point_hit_count);
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src_2 = "function foo() { "
" var a = {a:[1, 2, 3]};"
" for (x in a.a) {"
" b = 0;"
" }"
- "}";
+ "}"
+ "foo()";
foo = CompileFunction(&env, src_2, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
@@ -3272,12 +3329,14 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo(x) { "
" var a = {};"
" with (a) {}"
" with (b) {}"
- "}";
+ "}"
+ "foo()";
env->Global()->Set(v8::String::New("b"), v8::Object::New());
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
@@ -3301,12 +3360,14 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo(x) { "
" var a;"
" a = x ? 1 : 2;"
" return a;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0); // "var a;"
@@ -3340,10 +3401,12 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b();c();}; "
"function b() {c();}; "
- "function c() {}; ";
+ "function c() {}; "
+ "a(); b(); c()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -3389,11 +3452,13 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b(c(d()),d());c(d());d()}; "
"function b(x,y) {c();}; "
"function c(x) {}; "
- "function d() {}; ";
+ "function d() {}; "
+ "a(); b(); c(); d()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -3439,10 +3504,12 @@
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b(false);c();}; "
"function b(x) {if(x){c();};}; "
- "function c() {}; ";
+ "function c() {}; "
+ "a(); b(); c()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -6116,8 +6183,8 @@
// 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 };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
@@ -6846,6 +6913,7 @@
}
}
+
// Check that event details contain context where debug event occured.
TEST(DebugEventBreakData) {
v8::HandleScope scope;
@@ -6898,6 +6966,156 @@
CheckDebuggerUnloaded();
}
+static bool debug_event_break_deoptimize_done = false;
+
+static void DebugEventBreakDeoptimize(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ if (event == v8::Break) {
+ if (!frame_function_name.IsEmpty()) {
+ // Get the name of the function.
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
+ v8::Handle<v8::Value> result =
+ frame_function_name->Call(exec_state, argc, argv);
+ if (!result->IsUndefined()) {
+ char fn[80];
+ CHECK(result->IsString());
+ v8::Handle<v8::String> function_name(result->ToString());
+ function_name->WriteAscii(fn);
+ if (strcmp(fn, "bar") == 0) {
+ i::Deoptimizer::DeoptimizeAll();
+ debug_event_break_deoptimize_done = true;
+ }
+ }
+ }
+
+ v8::Debug::DebugBreak();
+ }
+}
+
+
+// Test deoptimization when execution is broken using the debug break stack
+// check interrupt.
+TEST(DeoptimizeDuringDebugBreak) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ env.ExposeDebug();
+
+ // Create a function for checking the function when hitting a break point.
+ frame_function_name = CompileFunction(&env,
+ frame_function_name_source,
+ "frame_function_name");
+
+
+ // Set a debug event listener which will keep interrupting execution until
+ // debug break. When inside function bar it will deoptimize all functions.
+ // This tests lazy deoptimization bailout for the stack check, as the first
+ // time in function bar when using debug break and no break points will be at
+ // the initial stack check.
+ v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize,
+ v8::Undefined());
+
+ // Compile and run function bar which will optimize it for some flag settings.
+ v8::Script::Compile(v8::String::New("function bar(){}; bar()"))->Run();
+
+ // Set debug break and call bar again.
+ v8::Debug::DebugBreak();
+ v8::Script::Compile(v8::String::New("bar()"))->Run();
+
+ CHECK(debug_event_break_deoptimize_done);
+
+ v8::Debug::SetDebugEventListener(NULL);
+}
+
+
+static void DebugEventBreakWithOptimizedStack(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ if (event == v8::Break) {
+ if (!frame_function_name.IsEmpty()) {
+ for (int i = 0; i < 2; i++) {
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(i) };
+ // Get the name of the function in frame i.
+ v8::Handle<v8::Value> result =
+ frame_function_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> function_name(result->ToString());
+ CHECK(function_name->Equals(v8::String::New("loop")));
+ // Get the name of the first argument in frame i.
+ result = frame_argument_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> argument_name(result->ToString());
+ CHECK(argument_name->Equals(v8::String::New("count")));
+ // Get the value of the first argument in frame i. If the
+ // funtion is optimized the value will be undefined, otherwise
+ // the value will be '1 - i'.
+ //
+ // TODO(3141533): We should be able to get the real value for
+ // optimized frames.
+ result = frame_argument_value->Call(exec_state, argc, argv);
+ CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
+ // Get the name of the first local variable.
+ result = frame_local_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> local_name(result->ToString());
+ CHECK(local_name->Equals(v8::String::New("local")));
+ // Get the value of the first local variable. If the function
+ // is optimized the value will be undefined, otherwise it will
+ // be 42.
+ //
+ // TODO(3141533): We should be able to get the real value for
+ // optimized frames.
+ result = frame_local_value->Call(exec_state, argc, argv);
+ CHECK(result->IsUndefined() || (result->Int32Value() == 42));
+ }
+ }
+ }
+}
+
+
+static v8::Handle<v8::Value> ScheduleBreak(const v8::Arguments& args) {
+ v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack,
+ v8::Undefined());
+ v8::Debug::DebugBreak();
+ return v8::Undefined();
+}
+
+
+TEST(DebugBreakStackInspection) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ frame_function_name =
+ CompileFunction(&env, frame_function_name_source, "frame_function_name");
+ frame_argument_name =
+ CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
+ frame_argument_value = CompileFunction(&env,
+ frame_argument_value_source,
+ "frame_argument_value");
+ frame_local_name =
+ CompileFunction(&env, frame_local_name_source, "frame_local_name");
+ frame_local_value =
+ CompileFunction(&env, frame_local_value_source, "frame_local_value");
+
+ v8::Handle<v8::FunctionTemplate> schedule_break_template =
+ v8::FunctionTemplate::New(ScheduleBreak);
+ v8::Handle<v8::Function> schedule_break =
+ schedule_break_template->GetFunction();
+ env->Global()->Set(v8_str("scheduleBreak"), schedule_break);
+
+ const char* src =
+ "function loop(count) {"
+ " var local = 42;"
+ " if (count < 1) { scheduleBreak(); loop(count + 1); }"
+ "}"
+ "loop(0);";
+ v8::Script::Compile(v8::String::New(src))->Run();
+}
+
// Test that setting the terminate execution flag during debug break processing.
static void TestDebugBreakInLoop(const char* loop_head,
diff --git a/test/cctest/test-deoptimization.cc b/test/cctest/test-deoptimization.cc
new file mode 100644
index 0000000..1745355
--- /dev/null
+++ b/test/cctest/test-deoptimization.cc
@@ -0,0 +1,714 @@
+// Copyright 2007-2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "api.h"
+#include "compilation-cache.h"
+#include "debug.h"
+#include "deoptimizer.h"
+#include "platform.h"
+#include "stub-cache.h"
+#include "cctest.h"
+
+
+using ::v8::internal::Handle;
+using ::v8::internal::Object;
+using ::v8::internal::JSFunction;
+using ::v8::internal::Deoptimizer;
+using ::v8::internal::EmbeddedVector;
+using ::v8::internal::OS;
+
+// Size of temp buffer for formatting small strings.
+#define SMALL_STRING_BUFFER_SIZE 80
+
+// Utility class to set --allow-natives-syntax --always-opt and --nouse-inlining
+// when constructed and return to their default state when destroyed.
+class AlwaysOptimizeAllowNativesSyntaxNoInlining {
+ public:
+ AlwaysOptimizeAllowNativesSyntaxNoInlining()
+ : always_opt_(i::FLAG_always_opt),
+ allow_natives_syntax_(i::FLAG_allow_natives_syntax),
+ use_inlining_(i::FLAG_use_inlining) {
+ i::FLAG_always_opt = true;
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_use_inlining = false;
+ }
+
+ ~AlwaysOptimizeAllowNativesSyntaxNoInlining() {
+ i::FLAG_allow_natives_syntax = allow_natives_syntax_;
+ i::FLAG_always_opt = always_opt_;
+ i::FLAG_use_inlining = use_inlining_;
+ }
+
+ private:
+ bool always_opt_;
+ bool allow_natives_syntax_;
+ bool use_inlining_;
+};
+
+
+// Utility class to set --allow-natives-syntax and --nouse-inlining when
+// constructed and return to their default state when destroyed.
+class AllowNativesSyntaxNoInlining {
+ public:
+ AllowNativesSyntaxNoInlining()
+ : allow_natives_syntax_(i::FLAG_allow_natives_syntax),
+ use_inlining_(i::FLAG_use_inlining) {
+ i::FLAG_allow_natives_syntax = true;
+ i::FLAG_use_inlining = false;
+ }
+
+ ~AllowNativesSyntaxNoInlining() {
+ i::FLAG_allow_natives_syntax = allow_natives_syntax_;
+ i::FLAG_use_inlining = use_inlining_;
+ }
+
+ private:
+ bool allow_natives_syntax_;
+ bool use_inlining_;
+};
+
+
+Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
+ const char* property_name) {
+ v8::Local<v8::Function> fun =
+ v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
+ return v8::Utils::OpenHandle(*fun);
+}
+
+
+TEST(DeoptimizeSimple) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ // Test lazy deoptimization of a simple function.
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "function h() { %DeoptimizeFunction(f); }"
+ "function g() { count++; h(); }"
+ "function f() { g(); };"
+ "f();"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+
+ // Test lazy deoptimization of a simple function. Call the function after the
+ // deoptimization while it is still activated further down the stack.
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "function g() { count++; %DeoptimizeFunction(f); f(false); }"
+ "function f(x) { if (x) { g(); } else { return } };"
+ "f(true);"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeSimpleWithArguments) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ // Test lazy deoptimization of a simple function with some arguments.
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "function h(x) { %DeoptimizeFunction(f); }"
+ "function g(x, y) { count++; h(x); }"
+ "function f(x, y, z) { g(1,x); y+z; };"
+ "f(1, \"2\", false);"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+
+ // Test lazy deoptimization of a simple function with some arguments. Call the
+ // function after the deoptimization while it is still activated further down
+ // the stack.
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "function g(x, y) { count++; %DeoptimizeFunction(f); f(false, 1, y); }"
+ "function f(x, y, z) { if (x) { g(x, y); } else { return y + z; } };"
+ "f(true, 1, \"2\");"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeSimpleNested) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ // Test lazy deoptimization of a simple function. Have a nested function call
+ // do the deoptimization.
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "var result = 0;"
+ "function h(x, y, z) { return x + y + z; }"
+ "function g(z) { count++; %DeoptimizeFunction(f); return z;}"
+ "function f(x,y,z) { return h(x, y, g(z)); };"
+ "result = f(1, 2, 3);"
+ "gc(); gc()");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(6, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+ }
+}
+
+
+TEST(DeoptimizeRecursive) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ {
+ // Test lazy deoptimization of a simple function called recursively. Call
+ // the function recursively a number of times before deoptimizing it.
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "var calls = 0;"
+ "function g() { count++; %DeoptimizeFunction(f); }"
+ "function f(x) { calls++; if (x > 0) { f(x - 1); } else { g(); } };"
+ "f(10); gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(11, env->Global()->Get(v8_str("calls"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+
+ v8::Local<v8::Function> fun =
+ v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
+ Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
+}
+
+
+TEST(DeoptimizeMultiple) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "var result = 0;"
+ "function g() { count++;"
+ " %DeoptimizeFunction(f1);"
+ " %DeoptimizeFunction(f2);"
+ " %DeoptimizeFunction(f3);"
+ " %DeoptimizeFunction(f4);}"
+ "function f4(x) { g(); };"
+ "function f3(x, y, z) { f4(); return x + y + z; };"
+ "function f2(x, y) { return x + f3(y + 1, y + 1, y + 1) + y; };"
+ "function f1(x) { return f2(x + 1, x + 1) + x; };"
+ "result = f1(1);"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeConstructor) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "function g() { count++;"
+ " %DeoptimizeFunction(f); }"
+ "function f() { g(); };"
+ "result = new f() instanceof f;"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK(env->Global()->Get(v8_str("result"))->IsTrue());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "var result = 0;"
+ "function g() { count++;"
+ " %DeoptimizeFunction(f); }"
+ "function f(x, y) { this.x = x; g(); this.y = y; };"
+ "result = new f(1, 2);"
+ "result = result.x + result.y;"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(3, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeConstructorMultiple) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ {
+ AlwaysOptimizeAllowNativesSyntaxNoInlining options;
+ CompileRun(
+ "var count = 0;"
+ "var result = 0;"
+ "function g() { count++;"
+ " %DeoptimizeFunction(f1);"
+ " %DeoptimizeFunction(f2);"
+ " %DeoptimizeFunction(f3);"
+ " %DeoptimizeFunction(f4);}"
+ "function f4(x) { this.result = x; g(); };"
+ "function f3(x, y, z) { this.result = new f4(x + y + z).result; };"
+ "function f2(x, y) {"
+ " this.result = x + new f3(y + 1, y + 1, y + 1).result + y; };"
+ "function f1(x) { this.result = new f2(x + 1, x + 1).result + x; };"
+ "result = new f1(1).result;"
+ "gc(); gc()");
+ }
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(14, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeBinaryOperationADDString) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ const char* f_source = "function f(x, y) { return x + y; };";
+
+ {
+ AllowNativesSyntaxNoInlining options;
+ // Compile function f and collect to type feedback to insert binary op stub
+ // call in the optimized code.
+ i::FLAG_prepare_always_opt = true;
+ CompileRun("var count = 0;"
+ "var result = 0;"
+ "var deopt = false;"
+ "function X() { };"
+ "X.prototype.toString = function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(f); } return 'an X'"
+ "};");
+ CompileRun(f_source);
+ CompileRun("for (var i = 0; i < 5; i++) {"
+ " f('a+', new X());"
+ "};");
+
+ // Compile an optimized version of f.
+ i::FLAG_always_opt = true;
+ CompileRun(f_source);
+ CompileRun("f('a+', new X());");
+ CHECK(!i::V8::UseCrankshaft() ||
+ GetJSFunction(env->Global(), "f")->IsOptimized());
+
+ // Call f and force deoptimization while processing the binary operation.
+ CompileRun("deopt = true;"
+ "var result = f('a+', new X());"
+ "gc(); gc();");
+ }
+
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ v8::Handle<v8::Value> result = env->Global()->Get(v8_str("result"));
+ CHECK(result->IsString());
+ v8::String::AsciiValue ascii(result);
+ CHECK_EQ("a+an X", *ascii);
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+static void CompileConstructorWithDeoptimizingValueOf() {
+ CompileRun("var count = 0;"
+ "var result = 0;"
+ "var deopt = false;"
+ "function X() { };"
+ "X.prototype.valueOf = function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(f); } return 8"
+ "};");
+}
+
+
+static void TestDeoptimizeBinaryOpHelper(LocalContext* env,
+ const char* binary_op) {
+ EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer;
+ OS::SNPrintF(f_source_buffer,
+ "function f(x, y) { return x %s y; };",
+ binary_op);
+ char* f_source = f_source_buffer.start();
+
+ AllowNativesSyntaxNoInlining options;
+ // Compile function f and collect to type feedback to insert binary op stub
+ // call in the optimized code.
+ i::FLAG_prepare_always_opt = true;
+ CompileConstructorWithDeoptimizingValueOf();
+ CompileRun(f_source);
+ CompileRun("for (var i = 0; i < 5; i++) {"
+ " f(8, new X());"
+ "};");
+
+ // Compile an optimized version of f.
+ i::FLAG_always_opt = true;
+ CompileRun(f_source);
+ CompileRun("f(7, new X());");
+ CHECK(!i::V8::UseCrankshaft() ||
+ GetJSFunction((*env)->Global(), "f")->IsOptimized());
+
+ // Call f and force deoptimization while processing the binary operation.
+ CompileRun("deopt = true;"
+ "var result = f(7, new X());"
+ "gc(); gc();");
+
+ CHECK(!GetJSFunction((*env)->Global(), "f")->IsOptimized());
+}
+
+
+TEST(DeoptimizeBinaryOperationADD) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ TestDeoptimizeBinaryOpHelper(&env, "+");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(15, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeBinaryOperationSUB) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ TestDeoptimizeBinaryOpHelper(&env, "-");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(-1, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeBinaryOperationMUL) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ TestDeoptimizeBinaryOpHelper(&env, "*");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(56, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeBinaryOperationDIV) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ TestDeoptimizeBinaryOpHelper(&env, "/");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(0, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeBinaryOperationMOD) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ TestDeoptimizeBinaryOpHelper(&env, "%");
+
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(7, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeCompare) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ const char* f_source = "function f(x, y) { return x < y; };";
+
+ {
+ AllowNativesSyntaxNoInlining options;
+ // Compile function f and collect to type feedback to insert compare ic
+ // call in the optimized code.
+ i::FLAG_prepare_always_opt = true;
+ CompileRun("var count = 0;"
+ "var result = 0;"
+ "var deopt = false;"
+ "function X() { };"
+ "X.prototype.toString = function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(f); } return 'b'"
+ "};");
+ CompileRun(f_source);
+ CompileRun("for (var i = 0; i < 5; i++) {"
+ " f('a', new X());"
+ "};");
+
+ // Compile an optimized version of f.
+ i::FLAG_always_opt = true;
+ CompileRun(f_source);
+ CompileRun("f('a', new X());");
+ CHECK(!i::V8::UseCrankshaft() ||
+ GetJSFunction(env->Global(), "f")->IsOptimized());
+
+ // Call f and force deoptimization while processing the comparison.
+ CompileRun("deopt = true;"
+ "var result = f('a', new X());"
+ "gc(); gc();");
+ }
+
+ CHECK(!GetJSFunction(env->Global(), "f")->IsOptimized());
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(true, env->Global()->Get(v8_str("result"))->BooleanValue());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeLoadICStoreIC) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ // Functions to generate load/store/keyed load/keyed store IC calls.
+ const char* f1_source = "function f1(x) { return x.y; };";
+ const char* g1_source = "function g1(x) { x.y = 1; };";
+ const char* f2_source = "function f2(x, y) { return x[y]; };";
+ const char* g2_source = "function g2(x, y) { x[y] = 1; };";
+
+ {
+ AllowNativesSyntaxNoInlining options;
+ // Compile functions and collect to type feedback to insert ic
+ // calls in the optimized code.
+ i::FLAG_prepare_always_opt = true;
+ CompileRun("var count = 0;"
+ "var result = 0;"
+ "var deopt = false;"
+ "function X() { };"
+ "X.prototype.__defineGetter__('y', function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(f1); };"
+ " return 13;"
+ "});"
+ "X.prototype.__defineSetter__('y', function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(g1); };"
+ "});"
+ "X.prototype.__defineGetter__('z', function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(f2); };"
+ " return 13;"
+ "});"
+ "X.prototype.__defineSetter__('z', function () {"
+ " if (deopt) { count++; %DeoptimizeFunction(g2); };"
+ "});");
+ CompileRun(f1_source);
+ CompileRun(g1_source);
+ CompileRun(f2_source);
+ CompileRun(g2_source);
+ CompileRun("for (var i = 0; i < 5; i++) {"
+ " f1(new X());"
+ " g1(new X());"
+ " f2(new X(), 'z');"
+ " g2(new X(), 'z');"
+ "};");
+
+ // Compile an optimized version of the functions.
+ i::FLAG_always_opt = true;
+ CompileRun(f1_source);
+ CompileRun(g1_source);
+ CompileRun(f2_source);
+ CompileRun(g2_source);
+ CompileRun("f1(new X());");
+ CompileRun("g1(new X());");
+ CompileRun("f2(new X(), 'z');");
+ CompileRun("g2(new X(), 'z');");
+ if (i::V8::UseCrankshaft()) {
+ CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
+ }
+
+ // Call functions and force deoptimization while processing the ics.
+ CompileRun("deopt = true;"
+ "var result = f1(new X());"
+ "g1(new X());"
+ "f2(new X(), 'z');"
+ "g2(new X(), 'z');"
+ "gc(); gc();");
+ }
+
+ CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
+ CHECK_EQ(4, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
+
+
+TEST(DeoptimizeLoadICStoreICNested) {
+ v8::HandleScope scope;
+ const char* extension_list[] = { "v8/gc" };
+ v8::ExtensionConfiguration extensions(1, extension_list);
+ LocalContext env(&extensions);
+
+ // Functions to generate load/store/keyed load/keyed store IC calls.
+ const char* f1_source = "function f1(x) { return x.y; };";
+ const char* g1_source = "function g1(x) { x.y = 1; };";
+ const char* f2_source = "function f2(x, y) { return x[y]; };";
+ const char* g2_source = "function g2(x, y) { x[y] = 1; };";
+
+ {
+ AllowNativesSyntaxNoInlining options;
+ // Compile functions and collect to type feedback to insert ic
+ // calls in the optimized code.
+ i::FLAG_prepare_always_opt = true;
+ CompileRun("var count = 0;"
+ "var result = 0;"
+ "var deopt = false;"
+ "function X() { };"
+ "X.prototype.__defineGetter__('y', function () {"
+ " g1(this);"
+ " return 13;"
+ "});"
+ "X.prototype.__defineSetter__('y', function () {"
+ " f2(this, 'z');"
+ "});"
+ "X.prototype.__defineGetter__('z', function () {"
+ " g2(this, 'z');"
+ "});"
+ "X.prototype.__defineSetter__('z', function () {"
+ " if (deopt) {"
+ " count++;"
+ " %DeoptimizeFunction(f1);"
+ " %DeoptimizeFunction(g1);"
+ " %DeoptimizeFunction(f2);"
+ " %DeoptimizeFunction(g2); };"
+ "});");
+ CompileRun(f1_source);
+ CompileRun(g1_source);
+ CompileRun(f2_source);
+ CompileRun(g2_source);
+ CompileRun("for (var i = 0; i < 5; i++) {"
+ " f1(new X());"
+ " g1(new X());"
+ " f2(new X(), 'z');"
+ " g2(new X(), 'z');"
+ "};");
+
+ // Compile an optimized version of the functions.
+ i::FLAG_always_opt = true;
+ CompileRun(f1_source);
+ CompileRun(g1_source);
+ CompileRun(f2_source);
+ CompileRun(g2_source);
+ CompileRun("f1(new X());");
+ CompileRun("g1(new X());");
+ CompileRun("f2(new X(), 'z');");
+ CompileRun("g2(new X(), 'z');");
+ if (i::V8::UseCrankshaft()) {
+ CHECK(GetJSFunction(env->Global(), "f1")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "g1")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "f2")->IsOptimized());
+ CHECK(GetJSFunction(env->Global(), "g2")->IsOptimized());
+ }
+
+ // Call functions and force deoptimization while processing the ics.
+ CompileRun("deopt = true;"
+ "var result = f1(new X());"
+ "gc(); gc();");
+ }
+
+ CHECK(!GetJSFunction(env->Global(), "f1")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "g1")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "f2")->IsOptimized());
+ CHECK(!GetJSFunction(env->Global(), "g2")->IsOptimized());
+ CHECK_EQ(1, env->Global()->Get(v8_str("count"))->Int32Value());
+ CHECK_EQ(13, env->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(0, Deoptimizer::GetDeoptimizedCodeCount());
+}
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 95314d7..ad242fe 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -1193,4 +1193,69 @@
CHECK_EQ(1, stream.eos_signaled());
}
+
+TEST(HeapSnapshotGetNodeById) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("id"));
+ const v8::HeapGraphNode* root = snapshot->GetRoot();
+ CHECK_EQ(root, snapshot->GetNodeById(root->GetId()));
+ for (int i = 0, count = root->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = root->GetChild(i);
+ CHECK_EQ(
+ prop->GetToNode(), snapshot->GetNodeById(prop->GetToNode()->GetId()));
+ }
+ // Check a big id, which should not exist yet.
+ CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
+}
+
+
+namespace {
+
+class TestActivityControl : public v8::ActivityControl {
+ public:
+ explicit TestActivityControl(int abort_count)
+ : done_(0), total_(0), abort_count_(abort_count) {}
+ ControlOption ReportProgressValue(int done, int total) {
+ done_ = done;
+ total_ = total;
+ return --abort_count_ != 0 ? kContinue : kAbort;
+ }
+ int done() { return done_; }
+ int total() { return total_; }
+
+ private:
+ int done_;
+ int total_;
+ int abort_count_;
+};
+}
+
+TEST(TakeHeapSnapshotAborting) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
+ TestActivityControl aborting_control(3);
+ const v8::HeapSnapshot* no_snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"),
+ v8::HeapSnapshot::kFull,
+ &aborting_control);
+ CHECK_EQ(NULL, no_snapshot);
+ CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_GT(aborting_control.total(), aborting_control.done());
+
+ TestActivityControl control(-1); // Don't abort.
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("full"),
+ v8::HeapSnapshot::kFull,
+ &control);
+ CHECK_NE(NULL, snapshot);
+ CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
+ CHECK_EQ(control.total(), control.done());
+ CHECK_GT(control.total(), 0);
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index fbe66ec..a23ee17 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -511,7 +511,7 @@
if (!maybe_a->ToObject(&a)) continue;
CHECK(a->IsSymbol());
Object* b;
- MaybeObject* maybe_b = Heap::LookupAsciiSymbol(string);
+ MaybeObject *maybe_b = Heap::LookupAsciiSymbol(string);
if (!maybe_b->ToObject(&b)) continue;
CHECK_EQ(b, a);
CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
@@ -978,7 +978,9 @@
Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
// This compile will add the code to the compilation cache.
- CompileRun(source);
+ { v8::HandleScope scope;
+ CompileRun(source);
+ }
// Check function is compiled.
Object* func_value =
@@ -1000,8 +1002,8 @@
Heap::CollectAllGarbage(true);
// foo should no longer be in the compilation cache
- CHECK(!function->shared()->is_compiled());
- CHECK(!function->is_compiled());
+ CHECK(!function->shared()->is_compiled() || function->IsOptimized());
+ CHECK(!function->is_compiled() || function->IsOptimized());
// Call foo to get it recompiled.
CompileRun("foo()");
CHECK(function->shared()->is_compiled());
@@ -1021,6 +1023,20 @@
}
+// Count the number of user functions in the weak list of optimized
+// functions attached to a global context.
+static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
+ int count = 0;
+ Handle<Context> icontext = v8::Utils::OpenHandle(*context);
+ Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
+ while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
+ count++;
+ object = JSFunction::cast(object)->next_function_link();
+ }
+ return count;
+}
+
+
TEST(TestInternalWeakLists) {
static const int kNumTestContexts = 10;
@@ -1032,9 +1048,63 @@
// Create a number of global contests which gets linked together.
for (int i = 0; i < kNumTestContexts; i++) {
ctx[i] = v8::Context::New();
+
+ bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
+
CHECK_EQ(i + 1, CountGlobalContexts());
ctx[i]->Enter();
+
+ // Create a handle scope so no function objects get stuch in the outer
+ // handle scope
+ v8::HandleScope scope;
+ const char* source = "function f1() { };"
+ "function f2() { };"
+ "function f3() { };"
+ "function f4() { };"
+ "function f5() { };";
+ CompileRun(source);
+ CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f1()");
+ CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f2()");
+ CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f3()");
+ CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f4()");
+ CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f5()");
+ CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
+
+ // Remove function f1, and
+ CompileRun("f1=null");
+
+ // Scavenge treats these references as strong.
+ for (int j = 0; j < 10; j++) {
+ Heap::PerformScavenge();
+ CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
+ }
+
+ // Mark compact handles the weak references.
+ Heap::CollectAllGarbage(true);
+ CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+
+ // Get rid of f3 and f5 in the same way.
+ CompileRun("f3=null");
+ for (int j = 0; j < 10; j++) {
+ Heap::PerformScavenge();
+ CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+ }
+ Heap::CollectAllGarbage(true);
+ CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+ CompileRun("f5=null");
+ for (int j = 0; j < 10; j++) {
+ Heap::PerformScavenge();
+ CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+ }
+ Heap::CollectAllGarbage(true);
+ CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
+
ctx[i]->Exit();
}
@@ -1076,6 +1146,25 @@
}
+// Count the number of user functions in the weak list of optimized
+// functions attached to a global context causing a GC after the
+// specified number of elements.
+static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
+ int n) {
+ int count = 0;
+ Handle<Context> icontext = v8::Utils::OpenHandle(*context);
+ Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
+ while (object->IsJSFunction() &&
+ !Handle<JSFunction>::cast(object)->IsBuiltin()) {
+ count++;
+ if (count == n) Heap::CollectAllGarbage(true);
+ object = Handle<Object>(
+ Object::cast(JSFunction::cast(*object)->next_function_link()));
+ }
+ return count;
+}
+
+
TEST(TestInternalWeakListsTraverseWithGC) {
static const int kNumTestContexts = 10;
@@ -1090,17 +1179,44 @@
ctx[i] = v8::Context::New();
CHECK_EQ(i + 1, CountGlobalContexts());
CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
-
- ctx[i]->Enter();
- ctx[i]->Exit();
}
+
+ bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
+
+ // Compile a number of functions the length of the weak list of optimized
+ // functions both with and without GCs while iterating the list.
+ ctx[0]->Enter();
+ const char* source = "function f1() { };"
+ "function f2() { };"
+ "function f3() { };"
+ "function f4() { };"
+ "function f5() { };";
+ CompileRun(source);
+ CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
+ CompileRun("f1()");
+ CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
+ CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+ CompileRun("f2()");
+ CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
+ CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+ CompileRun("f3()");
+ CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
+ CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+ CompileRun("f4()");
+ CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
+ CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
+ CompileRun("f5()");
+ CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
+ CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
+
+ ctx[0]->Exit();
}
TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
InitializeVM();
intptr_t size_of_objects_1 = Heap::SizeOfObjects();
- HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
intptr_t size_of_objects_2 = 0;
for (HeapObject* obj = iterator.next();
obj != NULL;
@@ -1124,3 +1240,65 @@
CHECK_GT(size_of_objects_2 / 100, delta);
}
}
+
+
+class HeapIteratorTestHelper {
+ public:
+ HeapIteratorTestHelper(Object* a, Object* b)
+ : a_(a), b_(b), a_found_(false), b_found_(false) {}
+ bool a_found() { return a_found_; }
+ bool b_found() { return b_found_; }
+ void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
+ HeapIterator iterator(mode);
+ for (HeapObject* obj = iterator.next();
+ obj != NULL;
+ obj = iterator.next()) {
+ if (obj == a_)
+ a_found_ = true;
+ else if (obj == b_)
+ b_found_ = true;
+ }
+ }
+ private:
+ Object* a_;
+ Object* b_;
+ bool a_found_;
+ bool b_found_;
+};
+
+TEST(HeapIteratorFilterUnreachable) {
+ InitializeVM();
+ v8::HandleScope scope;
+ CompileRun("a = {}; b = {};");
+ v8::Handle<Object> a(Top::context()->global()->GetProperty(
+ *Factory::LookupAsciiSymbol("a"))->ToObjectChecked());
+ v8::Handle<Object> b(Top::context()->global()->GetProperty(
+ *Factory::LookupAsciiSymbol("b"))->ToObjectChecked());
+ CHECK_NE(*a, *b);
+ {
+ HeapIteratorTestHelper helper(*a, *b);
+ helper.IterateHeap(HeapIterator::kFilterUnreachable);
+ CHECK(helper.a_found());
+ CHECK(helper.b_found());
+ }
+ CHECK(Top::context()->global()->DeleteProperty(
+ *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
+ // We ensure that GC will not happen, so our raw pointer stays valid.
+ AssertNoAllocation no_alloc;
+ Object* a_saved = *a;
+ a.Clear();
+ // Verify that "a" object still resides in the heap...
+ {
+ HeapIteratorTestHelper helper(a_saved, *b);
+ helper.IterateHeap(HeapIterator::kNoFiltering);
+ CHECK(helper.a_found());
+ CHECK(helper.b_found());
+ }
+ // ...but is now unreachable.
+ {
+ HeapIteratorTestHelper helper(a_saved, *b);
+ helper.IterateHeap(HeapIterator::kFilterUnreachable);
+ CHECK(!helper.a_found());
+ CHECK(helper.b_found());
+ }
+}
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 65be6bd..c85f6c0 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -39,6 +39,7 @@
#include "cctest.h"
#include "disassembler.h"
#include "register-allocator-inl.h"
+#include "vm-state-inl.h"
using v8::Function;
using v8::Local;
@@ -200,6 +201,7 @@
static void CheckJSFunctionAtAddress(const char* func_name, Address addr) {
+ CHECK(i::Heap::Contains(addr));
i::Object* obj = i::HeapObject::FromAddress(addr);
CHECK(obj->IsJSFunction());
CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
@@ -298,10 +300,17 @@
// trace(EBP) [native (extension)]
// DoTrace(EBP) [native]
// StackTracer::Trace
- CHECK_GT(sample.frames_count, 1);
+
+ // The VM state tracking keeps track of external callbacks and puts
+ // them at the top of the sample stack.
+ int base = 0;
+ CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::Trace));
+ base++;
+
// Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
- CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[0]);
- CheckJSFunctionAtAddress("JSTrace", sample.stack[1]);
+ CHECK_GT(sample.frames_count, base + 1);
+ CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[base + 0]);
+ CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 1]);
}
@@ -311,6 +320,10 @@
// Top::c_entry_fp value. In this case, StackTracer uses passed frame
// pointer value as a starting point for stack walking.
TEST(PureJSStackTrace) {
+ // This test does not pass with inlining enabled since inlined functions
+ // don't appear in the stack trace.
+ i::FLAG_use_inlining = false;
+
TickSample sample;
InitTraceEnv(&sample);
@@ -341,10 +354,17 @@
// The last JS function called. It is only visible through
// sample.function, as its return address is above captured EBP value.
CheckJSFunctionAtAddress("JSFuncDoTrace", sample.function);
- CHECK_GT(sample.frames_count, 1);
+
+ // The VM state tracking keeps track of external callbacks and puts
+ // them at the top of the sample stack.
+ int base = 0;
+ CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::JSTrace));
+ base++;
+
// Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
- CheckJSFunctionAtAddress("JSTrace", sample.stack[0]);
- CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[1]);
+ CHECK_GT(sample.frames_count, base + 1);
+ CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 0]);
+ CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[base + 1]);
}
diff --git a/test/cctest/test-log-utils.cc b/test/cctest/test-log-utils.cc
index c99d770..861be12 100644
--- a/test/cctest/test-log-utils.cc
+++ b/test/cctest/test-log-utils.cc
@@ -12,7 +12,6 @@
using v8::internal::CStrVector;
using v8::internal::EmbeddedVector;
using v8::internal::LogDynamicBuffer;
-using v8::internal::LogRecordCompressor;
using v8::internal::MutableCStrVector;
using v8::internal::ScopedVector;
using v8::internal::Vector;
@@ -138,173 +137,4 @@
CHECK_EQ(0, ReadData(&dynabuf, 100 + seal_size, &buf));
}
-
-TEST(CompressorStore) {
- LogRecordCompressor comp(2);
- const Vector<const char> empty = CStrVector("");
- CHECK(comp.Store(empty));
- CHECK(!comp.Store(empty));
- CHECK(!comp.Store(empty));
- const Vector<const char> aaa = CStrVector("aaa");
- CHECK(comp.Store(aaa));
- CHECK(!comp.Store(aaa));
- CHECK(!comp.Store(aaa));
- CHECK(comp.Store(empty));
- CHECK(!comp.Store(empty));
- CHECK(!comp.Store(empty));
-}
-
-
-void CheckCompression(LogRecordCompressor* comp,
- const Vector<const char>& after) {
- EmbeddedVector<char, 100> result;
- CHECK(comp->RetrievePreviousCompressed(&result));
- CHECK_EQ(after, result);
-}
-
-
-void CheckCompression(LogRecordCompressor* comp,
- const char* after) {
- CheckCompression(comp, CStrVector(after));
-}
-
-
-TEST(CompressorNonCompressed) {
- LogRecordCompressor comp(0);
- CHECK(!comp.RetrievePreviousCompressed(NULL));
- const Vector<const char> empty = CStrVector("");
- CHECK(comp.Store(empty));
- CHECK(!comp.RetrievePreviousCompressed(NULL));
- const Vector<const char> a_x_20 = CStrVector("aaaaaaaaaaaaaaaaaaaa");
- CHECK(comp.Store(a_x_20));
- CheckCompression(&comp, empty);
- CheckCompression(&comp, empty);
- CHECK(comp.Store(empty));
- CheckCompression(&comp, a_x_20);
- CheckCompression(&comp, a_x_20);
-}
-
-
-TEST(CompressorSingleLine) {
- LogRecordCompressor comp(1);
- const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_1));
- const Vector<const char> string_2 = CStrVector("fff,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_2));
- // string_1 hasn't been compressed.
- CheckCompression(&comp, string_1);
- CheckCompression(&comp, string_1);
- const Vector<const char> string_3 = CStrVector("hhh,ggg,ccc,bbb,aaa");
- CHECK(comp.Store(string_3));
- // string_2 compressed using string_1.
- CheckCompression(&comp, "fff#1:3");
- CheckCompression(&comp, "fff#1:3");
- CHECK(!comp.Store(string_3));
- // Expecting no changes.
- CheckCompression(&comp, "fff#1:3");
- CHECK(!comp.Store(string_3));
- // Expecting no changes.
- CheckCompression(&comp, "fff#1:3");
- const Vector<const char> string_4 = CStrVector("iii,hhh,ggg,ccc,bbb,aaa");
- CHECK(comp.Store(string_4));
- // string_3 compressed using string_2.
- CheckCompression(&comp, "hhh,ggg#1:7");
- const Vector<const char> string_5 = CStrVector("nnn,mmm,lll,kkk,jjj");
- CHECK(comp.Store(string_5));
- // string_4 compressed using string_3.
- CheckCompression(&comp, "iii,#1");
- const Vector<const char> string_6 = CStrVector("nnn,mmmmmm,lll,kkk,jjj");
- CHECK(comp.Store(string_6));
- // string_5 hasn't been compressed.
- CheckCompression(&comp, string_5);
- CHECK(comp.Store(string_5));
- // string_6 compressed using string_5.
- CheckCompression(&comp, "nnn,mmm#1:4");
- const Vector<const char> string_7 = CStrVector("nnnnnn,mmm,lll,kkk,jjj");
- CHECK(comp.Store(string_7));
- // string_5 compressed using string_6.
- CheckCompression(&comp, "nnn,#1:7");
- const Vector<const char> string_8 = CStrVector("xxn,mmm,lll,kkk,jjj");
- CHECK(comp.Store(string_8));
- // string_7 compressed using string_5.
- CheckCompression(&comp, "nnn#1");
- const Vector<const char> string_9 =
- CStrVector("aaaaaaaaaaaaa,bbbbbbbbbbbbbbbbb");
- CHECK(comp.Store(string_9));
- // string_8 compressed using string_7.
- CheckCompression(&comp, "xx#1:5");
- const Vector<const char> string_10 =
- CStrVector("aaaaaaaaaaaaa,cccccccbbbbbbbbbb");
- CHECK(comp.Store(string_10));
- // string_9 hasn't been compressed.
- CheckCompression(&comp, string_9);
- CHECK(comp.Store(string_1));
- // string_10 compressed using string_9.
- CheckCompression(&comp, "aaaaaaaaaaaaa,ccccccc#1:21");
-}
-
-
-
-TEST(CompressorMultiLines) {
- const int kWindowSize = 3;
- LogRecordCompressor comp(kWindowSize);
- const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_1));
- const Vector<const char> string_2 = CStrVector("iii,hhh,ggg,fff,aaa");
- CHECK(comp.Store(string_2));
- const Vector<const char> string_3 = CStrVector("mmm,lll,kkk,jjj,aaa");
- CHECK(comp.Store(string_3));
- const Vector<const char> string_4 = CStrVector("nnn,hhh,ggg,fff,aaa");
- CHECK(comp.Store(string_4));
- const Vector<const char> string_5 = CStrVector("ooo,lll,kkk,jjj,aaa");
- CHECK(comp.Store(string_5));
- // string_4 compressed using string_2.
- CheckCompression(&comp, "nnn#2:3");
- CHECK(comp.Store(string_1));
- // string_5 compressed using string_3.
- CheckCompression(&comp, "ooo#2:3");
- CHECK(comp.Store(string_4));
- // string_1 is out of buffer by now, so it shouldn't be compressed.
- CHECK_GE(3, kWindowSize);
- CheckCompression(&comp, string_1);
- CHECK(comp.Store(string_2));
- // string_4 compressed using itself.
- CheckCompression(&comp, "#3");
-}
-
-
-TEST(CompressorBestSelection) {
- LogRecordCompressor comp(3);
- const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_1));
- const Vector<const char> string_2 = CStrVector("ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_2));
- const Vector<const char> string_3 = CStrVector("fff,eee,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_3));
- // string_2 compressed using string_1.
- CheckCompression(&comp, "#1:4");
- const Vector<const char> string_4 = CStrVector("nnn,hhh,ggg,fff,aaa");
- CHECK(comp.Store(string_4));
- // Compressing string_3 using string_1 gives a better compression than
- // using string_2.
- CheckCompression(&comp, "fff,#2");
-}
-
-
-TEST(CompressorCompressibility) {
- LogRecordCompressor comp(2);
- const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
- CHECK(comp.Store(string_1));
- const Vector<const char> string_2 = CStrVector("ccc,bbb,aaa");
- CHECK(comp.Store(string_2));
- const Vector<const char> string_3 = CStrVector("aaa");
- CHECK(comp.Store(string_3));
- // string_2 compressed using string_1.
- CheckCompression(&comp, "#1:8");
- const Vector<const char> string_4 = CStrVector("xxx");
- CHECK(comp.Store(string_4));
- // string_3 can't be compressed using string_2 --- too short.
- CheckCompression(&comp, string_3);
-}
-
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 710c10e..503e0cf 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -16,6 +16,7 @@
#include "cpu-profiler.h"
#include "v8threads.h"
#include "cctest.h"
+#include "vm-state-inl.h"
using v8::internal::Address;
using v8::internal::EmbeddedVector;
@@ -246,7 +247,8 @@
static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
- CHECK(!LoggerTestHelper::IsSamplerActive());
+ CHECK(i::RuntimeProfiler::IsEnabled() ||
+ !LoggerTestHelper::IsSamplerActive());
LoggerTestHelper::ResetSamplesTaken();
Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
@@ -272,7 +274,8 @@
}
Logger::PauseProfiler(v8::PROFILER_MODULE_CPU, 0);
- CHECK(!LoggerTestHelper::IsSamplerActive());
+ CHECK(i::RuntimeProfiler::IsEnabled() ||
+ !LoggerTestHelper::IsSamplerActive());
// Wait 50 msecs to allow Profiler thread to process the last
// tick sample it has got.
@@ -291,8 +294,12 @@
TEST(ProfLazyMode) {
ScopedLoggerInitializer initialize_logger(true);
- // No sampling should happen prior to resuming profiler.
- CHECK(!LoggerTestHelper::IsSamplerActive());
+ if (!i::V8::UseCrankshaft()) return;
+
+ // No sampling should happen prior to resuming profiler unless we
+ // are runtime profiling.
+ CHECK(i::RuntimeProfiler::IsEnabled() ||
+ !LoggerTestHelper::IsSamplerActive());
LogBufferMatcher matcher;
// Nothing must be logged until profiling is resumed.
@@ -403,7 +410,7 @@
class TestSampler : public v8::internal::Sampler {
public:
TestSampler()
- : Sampler(0, true),
+ : Sampler(0, true, true),
semaphore_(v8::internal::OS::CreateSemaphore(0)),
was_sample_stack_called_(false) {
}
@@ -431,30 +438,38 @@
} // namespace
TEST(ProfMultipleThreads) {
+ TestSampler* sampler = NULL;
+ {
+ v8::Locker locker;
+ sampler = new TestSampler();
+ sampler->Start();
+ CHECK(sampler->IsActive());
+ }
+
LoopingJsThread jsThread;
jsThread.Start();
LoopingNonJsThread nonJsThread;
nonJsThread.Start();
- TestSampler sampler;
- sampler.Start();
- CHECK(!sampler.WasSampleStackCalled());
+ CHECK(!sampler->WasSampleStackCalled());
jsThread.WaitForRunning();
jsThread.SendSigProf();
- CHECK(sampler.WaitForTick());
- CHECK(sampler.WasSampleStackCalled());
- sampler.Reset();
- CHECK(!sampler.WasSampleStackCalled());
+ CHECK(sampler->WaitForTick());
+ CHECK(sampler->WasSampleStackCalled());
+ sampler->Reset();
+ CHECK(!sampler->WasSampleStackCalled());
nonJsThread.WaitForRunning();
nonJsThread.SendSigProf();
- CHECK(!sampler.WaitForTick());
- CHECK(!sampler.WasSampleStackCalled());
- sampler.Stop();
+ CHECK(!sampler->WaitForTick());
+ CHECK(!sampler->WasSampleStackCalled());
+ sampler->Stop();
jsThread.Stop();
nonJsThread.Stop();
jsThread.Join();
nonJsThread.Join();
+
+ delete sampler;
}
#endif // __linux__
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 9942567..86f105f 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -71,6 +71,10 @@
TEST(Promotion) {
+ // This test requires compaction. If compaction is turned off, we
+ // skip the entire test.
+ if (FLAG_never_compact) return;
+
// Ensure that we get a compacting collection so that objects are promoted
// from new space.
FLAG_gc_global = true;
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index a93fc27..e642d1b 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -257,15 +257,22 @@
NULL
};
+ uintptr_t stack_limit = i::StackGuard::real_climit();
for (int i = 0; programs[i]; i++) {
const char* program = programs[i];
- unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+ i::Utf8ToUC16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
i::V8JavaScriptScanner scanner;
- scanner.Initialize(i::Handle<i::String>::null(), &stream);
- v8::preparser::PreParser preparser;
- bool result = preparser.PreParseProgram(&scanner, &log, true);
- CHECK(result);
+ scanner.Initialize(&stream);
+
+ v8::preparser::PreParser::PreParseResult result =
+ v8::preparser::PreParser::PreParseProgram(&scanner,
+ &log,
+ true,
+ stack_limit);
+ CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
i::ScriptDataImpl data(log.ExtractData());
CHECK(!data.has_error());
}
@@ -284,9 +291,10 @@
// and then used the invalid currently scanned literal. This always
// failed in debug mode, and sometimes crashed in release mode.
- unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+ i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data =
- i::ParserApi::PreParse(i::Handle<i::String>::null(), &stream, NULL);
+ i::ParserApi::PreParse(&stream, NULL);
CHECK(data->HasError());
delete data;
}
@@ -305,10 +313,10 @@
"try { } catch (e) { var foo = function () { /* first */ } }"
"var bar = function () { /* second */ }";
- unibrow::Utf8InputBuffer<256> stream(program, strlen(program));
+ i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data =
- i::ParserApi::PartialPreParse(i::Handle<i::String>::null(),
- &stream, NULL);
+ i::ParserApi::PartialPreParse(&stream, NULL);
CHECK(!data->HasError());
data->Initialize();
@@ -327,3 +335,313 @@
CHECK_EQ('}', program[entry2.end_pos() - 1]);
delete data;
}
+
+
+TEST(PreParseOverflow) {
+ int marker;
+ i::StackGuard::SetStackLimit(
+ reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+ size_t kProgramSize = 1024 * 1024;
+ i::SmartPointer<char> program(
+ reinterpret_cast<char*>(malloc(kProgramSize + 1)));
+ memset(*program, '(', kProgramSize);
+ program[kProgramSize] = '\0';
+
+ uintptr_t stack_limit = i::StackGuard::real_climit();
+
+ i::Utf8ToUC16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(*program),
+ static_cast<unsigned>(kProgramSize));
+ i::CompleteParserRecorder log;
+ i::V8JavaScriptScanner scanner;
+ scanner.Initialize(&stream);
+
+
+ v8::preparser::PreParser::PreParseResult result =
+ v8::preparser::PreParser::PreParseProgram(&scanner,
+ &log,
+ true,
+ stack_limit);
+ CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
+}
+
+
+class TestExternalResource: public v8::String::ExternalStringResource {
+ public:
+ explicit TestExternalResource(uint16_t* data, int length)
+ : data_(data), length_(static_cast<size_t>(length)) { }
+
+ ~TestExternalResource() { }
+
+ const uint16_t* data() const {
+ return data_;
+ }
+
+ size_t length() const {
+ return length_;
+ }
+ private:
+ uint16_t* data_;
+ size_t length_;
+};
+
+
+#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
+
+void TestCharacterStream(const char* ascii_source,
+ unsigned length,
+ unsigned start = 0,
+ unsigned end = 0) {
+ if (end == 0) end = length;
+ unsigned sub_length = end - start;
+ i::HandleScope test_scope;
+ i::SmartPointer<i::uc16> uc16_buffer(new i::uc16[length]);
+ for (unsigned i = 0; i < length; i++) {
+ uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
+ }
+ i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
+ i::Handle<i::String> ascii_string(
+ i::Factory::NewStringFromAscii(ascii_vector));
+ TestExternalResource resource(*uc16_buffer, length);
+ i::Handle<i::String> uc16_string(
+ i::Factory::NewExternalStringFromTwoByte(&resource));
+
+ i::ExternalTwoByteStringUC16CharacterStream uc16_stream(
+ i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
+ i::GenericStringUC16CharacterStream string_stream(ascii_string, start, end);
+ i::Utf8ToUC16CharacterStream utf8_stream(
+ reinterpret_cast<const i::byte*>(ascii_source), end);
+ utf8_stream.SeekForward(start);
+
+ unsigned i = start;
+ while (i < end) {
+ // Read streams one char at a time
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ int32_t c0 = ascii_source[i];
+ int32_t c1 = uc16_stream.Advance();
+ int32_t c2 = string_stream.Advance();
+ int32_t c3 = utf8_stream.Advance();
+ i++;
+ CHECK_EQ(c0, c1);
+ CHECK_EQ(c0, c2);
+ CHECK_EQ(c0, c3);
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ }
+ while (i > start + sub_length / 4) {
+ // Pushback, re-read, pushback again.
+ int32_t c0 = ascii_source[i - 1];
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ uc16_stream.PushBack(c0);
+ string_stream.PushBack(c0);
+ utf8_stream.PushBack(c0);
+ i--;
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ int32_t c1 = uc16_stream.Advance();
+ int32_t c2 = string_stream.Advance();
+ int32_t c3 = utf8_stream.Advance();
+ i++;
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ CHECK_EQ(c0, c1);
+ CHECK_EQ(c0, c2);
+ CHECK_EQ(c0, c3);
+ uc16_stream.PushBack(c0);
+ string_stream.PushBack(c0);
+ utf8_stream.PushBack(c0);
+ i--;
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ }
+ unsigned halfway = start + sub_length / 2;
+ uc16_stream.SeekForward(halfway - i);
+ string_stream.SeekForward(halfway - i);
+ utf8_stream.SeekForward(halfway - i);
+ i = halfway;
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+
+ while (i < end) {
+ // Read streams one char at a time
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ int32_t c0 = ascii_source[i];
+ int32_t c1 = uc16_stream.Advance();
+ int32_t c2 = string_stream.Advance();
+ int32_t c3 = utf8_stream.Advance();
+ i++;
+ CHECK_EQ(c0, c1);
+ CHECK_EQ(c0, c2);
+ CHECK_EQ(c0, c3);
+ CHECK_EQU(i, uc16_stream.pos());
+ CHECK_EQU(i, string_stream.pos());
+ CHECK_EQU(i, utf8_stream.pos());
+ }
+
+ int32_t c1 = uc16_stream.Advance();
+ int32_t c2 = string_stream.Advance();
+ int32_t c3 = utf8_stream.Advance();
+ CHECK_LT(c1, 0);
+ CHECK_LT(c2, 0);
+ CHECK_LT(c3, 0);
+}
+
+
+TEST(CharacterStreams) {
+ v8::HandleScope handles;
+ v8::Persistent<v8::Context> context = v8::Context::New();
+ v8::Context::Scope context_scope(context);
+
+ TestCharacterStream("abc\0\n\r\x7f", 7);
+ static const unsigned kBigStringSize = 4096;
+ char buffer[kBigStringSize + 1];
+ for (unsigned i = 0; i < kBigStringSize; i++) {
+ buffer[i] = static_cast<char>(i & 0x7f);
+ }
+ TestCharacterStream(buffer, kBigStringSize);
+
+ TestCharacterStream(buffer, kBigStringSize, 576, 3298);
+
+ TestCharacterStream("\0", 1);
+ TestCharacterStream("", 0);
+}
+
+
+TEST(Utf8CharacterStream) {
+ static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
+ static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
+
+ static const int kAllUtf8CharsSize =
+ (unibrow::Utf8::kMaxOneByteChar + 1) +
+ (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
+ (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
+ static const unsigned kAllUtf8CharsSizeU =
+ static_cast<unsigned>(kAllUtf8CharsSize);
+
+ char buffer[kAllUtf8CharsSizeU];
+ unsigned cursor = 0;
+ for (int i = 0; i <= kMaxUC16Char; i++) {
+ cursor += unibrow::Utf8::Encode(buffer + cursor, i);
+ }
+ ASSERT(cursor == kAllUtf8CharsSizeU);
+
+ i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
+ kAllUtf8CharsSizeU);
+ for (int i = 0; i <= kMaxUC16Char; i++) {
+ CHECK_EQU(i, stream.pos());
+ int32_t c = stream.Advance();
+ CHECK_EQ(i, c);
+ CHECK_EQU(i + 1, stream.pos());
+ }
+ for (int i = kMaxUC16Char; i >= 0; i--) {
+ CHECK_EQU(i + 1, stream.pos());
+ stream.PushBack(i);
+ CHECK_EQU(i, stream.pos());
+ }
+ int i = 0;
+ while (stream.pos() < kMaxUC16CharU) {
+ CHECK_EQU(i, stream.pos());
+ unsigned progress = stream.SeekForward(12);
+ i += progress;
+ int32_t c = stream.Advance();
+ if (i <= kMaxUC16Char) {
+ CHECK_EQ(i, c);
+ } else {
+ CHECK_EQ(-1, c);
+ }
+ i += 1;
+ CHECK_EQU(i, stream.pos());
+ }
+}
+
+#undef CHECK_EQU
+
+void TestStreamScanner(i::UC16CharacterStream* stream,
+ i::Token::Value* expected_tokens,
+ int skip_pos = 0, // Zero means not skipping.
+ int skip_to = 0) {
+ i::V8JavaScriptScanner scanner;
+ scanner.Initialize(stream, i::JavaScriptScanner::kAllLiterals);
+
+ int i = 0;
+ do {
+ i::Token::Value expected = expected_tokens[i];
+ i::Token::Value actual = scanner.Next();
+ CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
+ if (scanner.location().end_pos == skip_pos) {
+ scanner.SeekForward(skip_to);
+ }
+ i++;
+ } while (expected_tokens[i] != i::Token::ILLEGAL);
+}
+
+TEST(StreamScanner) {
+ const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
+ i::Utf8ToUC16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
+ static_cast<unsigned>(strlen(str1)));
+ i::Token::Value expectations1[] = {
+ i::Token::LBRACE,
+ i::Token::IDENTIFIER,
+ i::Token::IDENTIFIER,
+ i::Token::FOR,
+ i::Token::COLON,
+ i::Token::MUL,
+ i::Token::DIV,
+ i::Token::LT,
+ i::Token::SUB,
+ i::Token::IDENTIFIER,
+ i::Token::EOS,
+ i::Token::ILLEGAL
+ };
+ TestStreamScanner(&stream1, expectations1, 0, 0);
+
+ const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
+ i::Utf8ToUC16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
+ static_cast<unsigned>(strlen(str2)));
+ i::Token::Value expectations2[] = {
+ i::Token::CASE,
+ i::Token::DEFAULT,
+ i::Token::CONST,
+ i::Token::LBRACE,
+ // Skipped part here
+ i::Token::RBRACE,
+ i::Token::DO,
+ i::Token::EOS,
+ i::Token::ILLEGAL
+ };
+ ASSERT_EQ('{', str2[19]);
+ ASSERT_EQ('}', str2[37]);
+ TestStreamScanner(&stream2, expectations2, 20, 37);
+
+ const char* str3 = "{}}}}";
+ i::Token::Value expectations3[] = {
+ i::Token::LBRACE,
+ i::Token::RBRACE,
+ i::Token::RBRACE,
+ i::Token::RBRACE,
+ i::Token::RBRACE,
+ i::Token::EOS,
+ i::Token::ILLEGAL
+ };
+ // Skip zero-four RBRACEs.
+ for (int i = 0; i <= 4; i++) {
+ expectations3[6 - i] = i::Token::ILLEGAL;
+ expectations3[5 - i] = i::Token::EOS;
+ i::Utf8ToUC16CharacterStream stream3(
+ reinterpret_cast<const i::byte*>(str3),
+ static_cast<unsigned>(strlen(str3)));
+ TestStreamScanner(&stream3, expectations3, 1, 1 + i);
+ }
+}
diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index f46191a..f849d40 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -757,6 +757,10 @@
TEST(RecordStackTraceAtStartProfiling) {
+ // This test does not pass with inlining enabled since inlined functions
+ // don't appear in the stack trace.
+ i::FLAG_use_inlining = false;
+
if (env.IsEmpty()) {
v8::HandleScope scope;
const char* extensions[] = { "v8/profiler" };
@@ -778,12 +782,16 @@
CpuProfiler::GetProfile(NULL, 0);
const ProfileTree* topDown = profile->top_down();
const ProfileNode* current = topDown->root();
+ const_cast<ProfileNode*>(current)->Print(0);
// The tree should look like this:
// (root)
// (anonymous function)
// a
// b
// c
+ // There can also be:
+ // startProfiling
+ // if the sampler managed to get a tick.
current = PickChild(current, "(anonymous function)");
CHECK_NE(NULL, const_cast<ProfileNode*>(current));
current = PickChild(current, "a");
@@ -792,7 +800,12 @@
CHECK_NE(NULL, const_cast<ProfileNode*>(current));
current = PickChild(current, "c");
CHECK_NE(NULL, const_cast<ProfileNode*>(current));
- CHECK_EQ(0, current->children()->length());
+ CHECK(current->children()->length() == 0 ||
+ current->children()->length() == 1);
+ if (current->children()->length() == 1) {
+ current = PickChild(current, "startProfiling");
+ CHECK_EQ(0, current->children()->length());
+ }
}
diff --git a/test/cctest/test-reloc-info.cc b/test/cctest/test-reloc-info.cc
new file mode 100644
index 0000000..2b9beac
--- /dev/null
+++ b/test/cctest/test-reloc-info.cc
@@ -0,0 +1,109 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#include "cctest.h"
+#include "assembler.h"
+
+namespace v8 {
+namespace internal {
+
+static void WriteRinfo(RelocInfoWriter* writer,
+ byte* pc, RelocInfo::Mode mode, intptr_t data) {
+ RelocInfo rinfo(pc, mode, data);
+ writer->Write(&rinfo);
+}
+
+
+// Tests that writing both types of positions and then reading either
+// or both works as expected.
+TEST(Positions) {
+ const int instr_size = 10 << 10;
+ const int reloc_size = 10 << 10;
+ const int buf_size = instr_size + reloc_size;
+ SmartPointer<byte> buf(new byte[buf_size]);
+ byte* pc = *buf;
+ CodeDesc desc = { *buf, buf_size, instr_size, reloc_size, NULL };
+
+ RelocInfoWriter writer(*buf + buf_size, pc);
+ for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
+ RelocInfo::Mode mode = (i % 2 == 0) ?
+ RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
+ WriteRinfo(&writer, pc, mode, pos);
+ }
+
+ // Read only (non-statement) positions.
+ {
+ RelocIterator it(desc, RelocInfo::ModeMask(RelocInfo::POSITION));
+ pc = *buf;
+ for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
+ RelocInfo::Mode mode = (i % 2 == 0) ?
+ RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
+ if (mode == RelocInfo::POSITION) {
+ CHECK_EQ(pc, it.rinfo()->pc());
+ CHECK_EQ(mode, it.rinfo()->rmode());
+ CHECK_EQ(pos, static_cast<int>(it.rinfo()->data()));
+ it.next();
+ }
+ }
+ CHECK(it.done());
+ }
+
+ // Read only statement positions.
+ {
+ RelocIterator it(desc, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
+ pc = *buf;
+ for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
+ RelocInfo::Mode mode = (i % 2 == 0) ?
+ RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
+ if (mode == RelocInfo::STATEMENT_POSITION) {
+ CHECK_EQ(pc, it.rinfo()->pc());
+ CHECK_EQ(mode, it.rinfo()->rmode());
+ CHECK_EQ(pos, static_cast<int>(it.rinfo()->data()));
+ it.next();
+ }
+ }
+ CHECK(it.done());
+ }
+
+ // Read both types of positions.
+ {
+ RelocIterator it(desc, RelocInfo::kPositionMask);
+ pc = *buf;
+ for (int i = 0, pos = 0; i < 100; i++, pc += i, pos += i) {
+ RelocInfo::Mode mode = (i % 2 == 0) ?
+ RelocInfo::STATEMENT_POSITION : RelocInfo::POSITION;
+ CHECK_EQ(pc, it.rinfo()->pc());
+ CHECK_EQ(mode, it.rinfo()->rmode());
+ CHECK_EQ(pos, static_cast<int>(it.rinfo()->data()));
+ it.next();
+ }
+ CHECK(it.done());
+ }
+}
+
+} } // namespace v8::internal
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index b399a4e..706c6bf 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -95,13 +95,13 @@
OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
int total_pages = 0;
- int requested = 2;
+ int requested = MemoryAllocator::kPagesPerChunk;
int allocated;
- // If we request two pages, we should get one or two.
+ // If we request n pages, we should get n or n - 1.
Page* first_page =
MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
CHECK(first_page->is_valid());
- CHECK(allocated > 0 && allocated <= 2);
+ CHECK(allocated == requested || allocated == requested - 1);
total_pages += allocated;
Page* last_page = first_page;
@@ -110,11 +110,11 @@
last_page = p;
}
- // Again, we should get one or two pages.
+ // Again, we should get n or n - 1 pages.
Page* others =
MemoryAllocator::AllocatePages(requested, &allocated, &faked_space);
CHECK(others->is_valid());
- CHECK(allocated > 0 && allocated <= 2);
+ CHECK(allocated == requested || allocated == requested - 1);
total_pages += allocated;
MemoryAllocator::SetNextPage(last_page, others);
@@ -129,11 +129,10 @@
CHECK(second_page->is_valid());
// Freeing pages at the first chunk starting at or after the second page
- // should free the entire second chunk. It will return the last page in the
- // first chunk (if the second page was in the first chunk) or else an
- // invalid page (if the second page was the start of the second chunk).
+ // should free the entire second chunk. It will return the page it was passed
+ // (since the second page was in the first chunk).
Page* free_return = MemoryAllocator::FreePages(second_page);
- CHECK(free_return == last_page || !free_return->is_valid());
+ CHECK(free_return == second_page);
MemoryAllocator::SetNextPage(first_page, free_return);
// Freeing pages in the first chunk starting at the first page should free
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 88ef0a2..b48dcb8 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -103,6 +103,7 @@
TEST(MemCopy) {
+ V8::Initialize(NULL);
const int N = kMinComplexMemCopy + 128;
Vector<byte> buffer1 = Vector<byte>::New(N);
Vector<byte> buffer2 = Vector<byte>::New(N);
diff --git a/test/cctest/test-version.cc b/test/cctest/test-version.cc
index 6d26855..6bec4b7 100644
--- a/test/cctest/test-version.cc
+++ b/test/cctest/test-version.cc
@@ -74,6 +74,20 @@
TEST(VersionString) {
+#ifdef USE_SIMULATOR
+ CheckVersion(0, 0, 0, 0, false, "0.0.0 SIMULATOR", "libv8-0.0.0.so");
+ CheckVersion(0, 0, 0, 0, true,
+ "0.0.0 (candidate) SIMULATOR", "libv8-0.0.0-candidate.so");
+ CheckVersion(1, 0, 0, 0, false, "1.0.0 SIMULATOR", "libv8-1.0.0.so");
+ CheckVersion(1, 0, 0, 0, true,
+ "1.0.0 (candidate) SIMULATOR", "libv8-1.0.0-candidate.so");
+ CheckVersion(1, 0, 0, 1, false, "1.0.0.1 SIMULATOR", "libv8-1.0.0.1.so");
+ CheckVersion(1, 0, 0, 1, true,
+ "1.0.0.1 (candidate) SIMULATOR", "libv8-1.0.0.1-candidate.so");
+ CheckVersion(2, 5, 10, 7, false, "2.5.10.7 SIMULATOR", "libv8-2.5.10.7.so");
+ CheckVersion(2, 5, 10, 7, true,
+ "2.5.10.7 (candidate) SIMULATOR", "libv8-2.5.10.7-candidate.so");
+#else
CheckVersion(0, 0, 0, 0, false, "0.0.0", "libv8-0.0.0.so");
CheckVersion(0, 0, 0, 0, true,
"0.0.0 (candidate)", "libv8-0.0.0-candidate.so");
@@ -86,4 +100,5 @@
CheckVersion(2, 5, 10, 7, false, "2.5.10.7", "libv8-2.5.10.7.so");
CheckVersion(2, 5, 10, 7, true,
"2.5.10.7 (candidate)", "libv8-2.5.10.7-candidate.so");
+#endif
}