Merge V8 at 3.8.9.11
Bug: 5688872
Change-Id: Ie3b1dd67a730ec5e82686b7b37dba26f6a9bb24f
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index 621d8ec..edb859e 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -73,6 +73,7 @@
'test-fixed-dtoa.cc',
'test-flags.cc',
'test-func-name-inference.cc',
+ 'test-hashing.cc',
'test-hashmap.cc',
'test-heap-profiler.cc',
'test-heap.cc',
@@ -110,7 +111,8 @@
],
'arch:x64': ['test-assembler-x64.cc',
'test-macro-assembler-x64.cc',
- 'test-log-stack-tracer.cc'],
+ 'test-log-stack-tracer.cc',
+ 'test-disasm-x64.cc'],
'arch:mips': ['test-assembler-mips.cc',
'test-disasm-mips.cc'],
'os:linux': ['test-platform-linux.cc'],
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index c04d893..0b93562 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -104,7 +104,7 @@
FOURTH_PART,
LAST_PART = FOURTH_PART };
- static void Setup(PartOfTest part);
+ static void SetUp(PartOfTest part);
static void RunAllTests();
static void TearDown();
// This method switches threads if we are running the Threading test.
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 7161345..2de0afb 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -85,9 +85,11 @@
##############################################################################
[ $arch == mips ]
-test-deoptimization: SKIP
test-serialize: SKIP
-# Tests that may time out.
-test-api/ExternalArrays: PASS || TIMEOUT
-test-api/Threading: PASS || TIMEOUT
+##############################################################################
+[ $arch == mips && $crankshaft ]
+
+# Tests that time out with crankshaft.
+test-debug/ThreadedDebugging: SKIP
+test-debug/DebugBreakLoop: SKIP
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index cf9d488..769fe7b 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -203,10 +203,10 @@
TEST(CodeRange) {
const int code_range_size = 32*MB;
- OS::Setup();
+ OS::SetUp();
Isolate::Current()->InitializeLoggingAndCounters();
CodeRange* code_range = new CodeRange(Isolate::Current());
- code_range->Setup(code_range_size);
+ code_range->SetUp(code_range_size);
int current_allocated = 0;
int total_allocated = 0;
List<Block> blocks(1000);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index cc20b6f..59d6d19 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -1189,7 +1189,6 @@
templ->Set("x", v8_num(200));
templ->SetAccessor(v8_str("m"), GetM);
LocalContext env(0, templ);
- v8::Handle<v8::Object> obj(env->Global());
v8::Handle<Script> script(v8_compile("dummy()"));
v8::Handle<Value> result(script->Run());
CHECK_EQ(13.4, result->NumberValue());
@@ -1423,6 +1422,40 @@
THREADED_TEST(SwitchFromInterceptorToAccessor) {
v8::HandleScope scope;
+ Handle<FunctionTemplate> templ = FunctionTemplate::New();
+ AddAccessor(templ, v8_str("age"),
+ SimpleAccessorGetter, SimpleAccessorSetter);
+ AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+ CompileRun("var obj = new Obj;"
+ "function setAge(i){ obj.age = i; };"
+ "for(var i = 0; i <= 10000; i++) setAge(i);");
+ // All i < 10000 go to the interceptor.
+ ExpectInt32("obj.interceptor_age", 9999);
+ // The last i goes to the accessor.
+ ExpectInt32("obj.accessor_age", 10000);
+}
+
+THREADED_TEST(SwitchFromAccessorToInterceptor) {
+ v8::HandleScope scope;
+ Handle<FunctionTemplate> templ = FunctionTemplate::New();
+ AddAccessor(templ, v8_str("age"),
+ SimpleAccessorGetter, SimpleAccessorSetter);
+ AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+ CompileRun("var obj = new Obj;"
+ "function setAge(i){ obj.age = i; };"
+ "for(var i = 20000; i >= 9999; i--) setAge(i);");
+ // All i >= 10000 go to the accessor.
+ ExpectInt32("obj.accessor_age", 10000);
+ // The last i goes to the interceptor.
+ ExpectInt32("obj.interceptor_age", 9999);
+}
+
+THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
+ v8::HandleScope scope;
Handle<FunctionTemplate> parent = FunctionTemplate::New();
Handle<FunctionTemplate> child = FunctionTemplate::New();
child->Inherit(parent);
@@ -1440,7 +1473,7 @@
ExpectInt32("child.accessor_age", 10000);
}
-THREADED_TEST(SwitchFromAccessorToInterceptor) {
+THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
v8::HandleScope scope;
Handle<FunctionTemplate> parent = FunctionTemplate::New();
Handle<FunctionTemplate> child = FunctionTemplate::New();
@@ -1459,6 +1492,54 @@
ExpectInt32("child.interceptor_age", 9999);
}
+THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
+ v8::HandleScope scope;
+ Handle<FunctionTemplate> templ = FunctionTemplate::New();
+ AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+ CompileRun("var obj = new Obj;"
+ "function setter(i) { this.accessor_age = i; };"
+ "function getter() { return this.accessor_age; };"
+ "function setAge(i) { obj.age = i; };"
+ "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
+ "for(var i = 0; i <= 10000; i++) setAge(i);");
+ // All i < 10000 go to the interceptor.
+ ExpectInt32("obj.interceptor_age", 9999);
+ // The last i goes to the JavaScript accessor.
+ ExpectInt32("obj.accessor_age", 10000);
+ // The installed JavaScript getter is still intact.
+ // This last part is a regression test for issue 1651 and relies on the fact
+ // that both interceptor and accessor are being installed on the same object.
+ ExpectInt32("obj.age", 10000);
+ ExpectBoolean("obj.hasOwnProperty('age')", true);
+ ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
+}
+
+THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
+ v8::HandleScope scope;
+ Handle<FunctionTemplate> templ = FunctionTemplate::New();
+ AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+ CompileRun("var obj = new Obj;"
+ "function setter(i) { this.accessor_age = i; };"
+ "function getter() { return this.accessor_age; };"
+ "function setAge(i) { obj.age = i; };"
+ "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
+ "for(var i = 20000; i >= 9999; i--) setAge(i);");
+ // All i >= 10000 go to the accessor.
+ ExpectInt32("obj.accessor_age", 10000);
+ // The last i goes to the interceptor.
+ ExpectInt32("obj.interceptor_age", 9999);
+ // The installed JavaScript getter is still intact.
+ // This last part is a regression test for issue 1651 and relies on the fact
+ // that both interceptor and accessor are being installed on the same object.
+ ExpectInt32("obj.age", 10000);
+ ExpectBoolean("obj.hasOwnProperty('age')", true);
+ ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
+}
+
THREADED_TEST(SwitchFromInterceptorToProperty) {
v8::HandleScope scope;
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1765,7 +1846,7 @@
env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
call_recursively_script = v8_compile("callScriptRecursively()");
- v8::Handle<Value> result(call_recursively_script->Run());
+ call_recursively_script->Run();
call_recursively_script = v8::Handle<Script>();
env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
@@ -2785,6 +2866,16 @@
obj = env->Global()->Get(v8_str("obj"));
CHECK(!obj->IsInt32());
CHECK(!obj->IsUint32());
+ // Positive zero
+ CompileRun("var obj = 0.0;");
+ obj = env->Global()->Get(v8_str("obj"));
+ CHECK(obj->IsInt32());
+ CHECK(obj->IsUint32());
+ // Positive zero
+ CompileRun("var obj = -0.0;");
+ obj = env->Global()->Get(v8_str("obj"));
+ CHECK(!obj->IsInt32());
+ CHECK(!obj->IsUint32());
}
@@ -4384,7 +4475,7 @@
source = v8_str("undetectable.y = 2000;");
script = Script::Compile(source);
- Local<Value> result(script->Run());
+ script->Run();
ExpectBoolean("undetectable.y == undefined", true);
}
@@ -4737,9 +4828,10 @@
const char* extension_names[] = { name };
v8::ExtensionConfiguration extensions(1, extension_names);
v8::Handle<Context> context(Context::New(&extensions));
- ASSERT(context.IsEmpty());
+ CHECK(context.IsEmpty());
}
+
THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
v8::HandleScope handle_scope;
const char* name = "nativedeclerresc";
@@ -4751,7 +4843,7 @@
const char* extension_names[] = { name };
v8::ExtensionConfiguration extensions(1, extension_names);
v8::Handle<Context> context(Context::New(&extensions));
- ASSERT(context.IsEmpty());
+ CHECK(context.IsEmpty());
}
@@ -4917,7 +5009,7 @@
Local<Script> script =
Script::Compile(String::New(js_code_causing_huge_string_flattening));
last_location = NULL;
- Local<Value> result(script->Run());
+ script->Run();
CHECK(false); // Should not return.
}
@@ -5695,7 +5787,6 @@
v8::Handle<String> message = v8_str("message");
v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
CHECK(range_error->IsObject());
- v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
CHECK(reference_error->IsObject());
@@ -7265,7 +7356,7 @@
// 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());
+ Script::Compile(v8_str("foo()"))->Run();
}
}
@@ -7591,6 +7682,7 @@
context->Global()->Set(v8_str("Fun"), cons);
Local<v8::Object> inst = cons->NewInstance();
i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
+ CHECK(obj->IsJSObject());
Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
CHECK(value->BooleanValue());
}
@@ -7859,7 +7951,7 @@
other->SetSecurityToken(token);
current->SetSecurityToken(token);
- // Setup reference from current to other.
+ // Set up reference from current to other.
current->Global()->Set(v8_str("other"), other->Global());
// Check that new variables are introduced in other context.
@@ -7939,7 +8031,7 @@
v8::Persistent<Context> context0 = Context::New();
v8::Persistent<Context> context1 = Context::New();
- // Setup function in context0 that uses eval from context0.
+ // Set up function in context0 that uses eval from context0.
context0->Enter();
v8::Handle<v8::Value> fun =
CompileRun("var x = 42;"
@@ -7977,7 +8069,7 @@
other->SetSecurityToken(token);
current->SetSecurityToken(token);
- // Setup reference from current to other.
+ // Set up reference from current to other.
current->Global()->Set(v8_str("other"), other->Global());
// Trigger lazy loading in other context.
@@ -8062,6 +8154,7 @@
{ Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
Local<ObjectTemplate> instance_template(t->InstanceTemplate());
+ USE(instance_template);
Local<v8::Object> instance = t->GetFunction()->NewInstance();
context->Global()->Set(v8_str("obj2"), instance);
v8::TryCatch try_catch;
@@ -8691,10 +8784,10 @@
0, 0, 0, v8_str("data"));
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
- v8::Handle<Value> value(CompileRun(
- "for (var i = 0; i < 1000; i++) {"
- " o.x = 42;"
- "}"));
+ CompileRun(
+ "for (var i = 0; i < 1000; i++) {"
+ " o.x = 42;"
+ "}");
}
@@ -8820,17 +8913,6 @@
}
-static v8::Handle<Value> call_ic_function5;
-static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- if (v8_str("x")->Equals(name))
- return call_ic_function5;
- else
- return Local<Value>();
-}
-
-
// This test checks that if interceptor doesn't provide a function,
// cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
@@ -8851,6 +8933,17 @@
}
+static v8::Handle<Value> call_ic_function5;
+static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ if (v8_str("x")->Equals(name))
+ return call_ic_function5;
+ else
+ return Local<Value>();
+}
+
+
// This test checks that if interceptor provides a function,
// even if we cached constant function, interceptor's function
// is invoked
@@ -8874,6 +8967,48 @@
}
+static v8::Handle<Value> call_ic_function6;
+static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ if (v8_str("x")->Equals(name))
+ return call_ic_function6;
+ else
+ return Local<Value>();
+}
+
+
+// Same test as above, except the code is wrapped in a function
+// to test the optimized compiler.
+THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
+ i::FLAG_allow_natives_syntax = true;
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ call_ic_function6 =
+ v8_compile("function f(x) { return x - 1; }; f")->Run();
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "o.x = inc;"
+ "function test() {"
+ " var result = 0;"
+ " for (var i = 0; i < 1000; i++) {"
+ " result = o.x(42);"
+ " }"
+ " return result;"
+ "};"
+ "test();"
+ "test();"
+ "test();"
+ "%OptimizeFunctionOnNextCall(test);"
+ "test()");
+ CHECK_EQ(41, value->Int32Value());
+}
+
+
// Test the case when we stored constant function into
// a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
@@ -9120,11 +9255,11 @@
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"var result = 0;"
"for (var i = 0; i < 100; i++) {"
" result = o.method(41);"
- "}"));
+ "}");
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(100, interceptor_call_count);
}
@@ -9147,14 +9282,14 @@
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
"var result = 0;"
"for (var i = 0; i < 100; i++) {"
" result = receiver.method(41);"
- "}"));
+ "}");
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(100, interceptor_call_count);
}
@@ -9177,7 +9312,7 @@
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9189,7 +9324,7 @@
" saved_result = result;"
" receiver = {method: function(x) { return x - 1 }};"
" }"
- "}"));
+ "}");
CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
CHECK_GE(interceptor_call_count, 50);
@@ -9213,7 +9348,7 @@
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9225,7 +9360,7 @@
" saved_result = result;"
" o.method = function(x) { return x - 1 };"
" }"
- "}"));
+ "}");
CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
CHECK_GE(interceptor_call_count, 50);
@@ -9250,7 +9385,7 @@
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
v8::TryCatch try_catch;
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9262,7 +9397,7 @@
" saved_result = result;"
" receiver = 333;"
" }"
- "}"));
+ "}");
CHECK(try_catch.HasCaught());
CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
try_catch.Exception()->ToString());
@@ -9289,7 +9424,7 @@
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
v8::TryCatch try_catch;
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9301,7 +9436,7 @@
" saved_result = result;"
" receiver = {method: receiver.method};"
" }"
- "}"));
+ "}");
CHECK(try_catch.HasCaught());
CHECK_EQ(v8_str("TypeError: Illegal invocation"),
try_catch.Exception()->ToString());
@@ -9319,15 +9454,16 @@
v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+ USE(templ);
LocalContext context;
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"var result = 0;"
"for (var i = 0; i < 100; i++) {"
" result = o.method(41);"
- "}"));
+ "}");
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9342,18 +9478,19 @@
v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+ CHECK(!templ.IsEmpty());
LocalContext context;
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
"var result = 0;"
"for (var i = 0; i < 100; i++) {"
" result = receiver.method(41);"
- "}"));
+ "}");
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9368,11 +9505,12 @@
v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+ CHECK(!templ.IsEmpty());
LocalContext context;
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9384,7 +9522,7 @@
" saved_result = result;"
" receiver = {method: function(x) { return x - 1 }};"
" }"
- "}"));
+ "}");
CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
}
@@ -9399,12 +9537,13 @@
v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+ CHECK(!templ.IsEmpty());
LocalContext context;
v8::Handle<v8::Function> fun = fun_templ->GetFunction();
GenerateSomeGarbage();
context->Global()->Set(v8_str("o"), fun->NewInstance());
v8::TryCatch try_catch;
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o.foo = 17;"
"var receiver = {};"
"receiver.__proto__ = o;"
@@ -9416,7 +9555,7 @@
" saved_result = result;"
" receiver = 333;"
" }"
- "}"));
+ "}");
CHECK(try_catch.HasCaught());
CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
try_catch.Exception()->ToString());
@@ -9444,7 +9583,7 @@
templ->SetNamedPropertyHandler(NoBlockGetterX);
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"proto = new Object();"
"proto.y = function(x) { return x + 1; };"
"proto.z = function(x) { return x - 1; };"
@@ -9454,7 +9593,7 @@
"for (var i = 0; i < 10; i++) {"
" if (i == 5) { method = 'z'; };"
" result += o[method](41);"
- "}"));
+ "}");
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9470,7 +9609,7 @@
context->Global()->Set(v8_str("proto1"), templ->NewInstance());
keyed_call_ic_function =
v8_compile("function f(x) { return x - 1; }; f")->Run();
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"o = new Object();"
"proto2 = new Object();"
"o.y = function(x) { return x + 1; };"
@@ -9482,7 +9621,7 @@
"for (var i = 0; i < 10; i++) {"
" if (i == 5) { method = 'y'; };"
" result += o[method](41);"
- "}"));
+ "}");
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9495,7 +9634,7 @@
templ->SetNamedPropertyHandler(NoBlockGetterX);
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"function inc(x) { return x + 1; };"
"inc(1);"
"function dec(x) { return x - 1; };"
@@ -9508,7 +9647,7 @@
"for (var i = 0; i < 10; i++) {"
" if (i == 5) { method = 'y'; };"
" result += o[method](41);"
- "}"));
+ "}");
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9521,7 +9660,7 @@
LocalContext context;
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"function len(x) { return x.length; };"
"o.__proto__ = this;"
"var m = 'parseFloat';"
@@ -9532,7 +9671,7 @@
" saved_result = result;"
" };"
" result = o[m]('239');"
- "}"));
+ "}");
CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
}
@@ -9545,7 +9684,7 @@
LocalContext context;
context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"var o = new Object();"
"o.__proto__ = proto;"
"o.method = function(x) { return x + 1; };"
@@ -9554,7 +9693,7 @@
"for (var i = 0; i < 10; i++) {"
" if (i == 5) { o.method = function(x) { return x - 1; }; };"
" result += o[m](41);"
- "}"));
+ "}");
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -9567,7 +9706,7 @@
LocalContext context;
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
- v8::Handle<Value> value(CompileRun(
+ CompileRun(
"var proto = new Object();"
"o.__proto__ = proto;"
"proto.method = function(x) { return x + 1; };"
@@ -9576,7 +9715,7 @@
"for (var i = 0; i < 10; i++) {"
" if (i == 5) { proto.method = function(x) { return x - 1; }; };"
" result += o[m](41);"
- "}"));
+ "}");
CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
}
@@ -10088,7 +10227,7 @@
static unsigned linear_congruential_generator;
-void ApiTestFuzzer::Setup(PartOfTest part) {
+void ApiTestFuzzer::SetUp(PartOfTest part) {
linear_congruential_generator = i::FLAG_testing_prng_seed;
fuzzing_ = true;
int count = RegisterThreadedTest::count();
@@ -10152,25 +10291,25 @@
// Lets not be needlessly self-referential.
TEST(Threading) {
- ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
+ ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
TEST(Threading2) {
- ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
+ ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
TEST(Threading3) {
- ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
+ ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
TEST(Threading4) {
- ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
+ ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
@@ -10493,6 +10632,7 @@
env->Enter();
v8::Handle<Value> value = NestedScope(env);
v8::Handle<String> str(value->ToString());
+ CHECK(!str.IsEmpty());
env->Exit();
env.Dispose();
}
@@ -10501,6 +10641,7 @@
THREADED_TEST(ExternalAllocatedMemory) {
v8::HandleScope outer;
v8::Persistent<Context> env(Context::New());
+ CHECK(!env.IsEmpty());
const int kSize = 1024*1024;
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
@@ -10839,6 +10980,7 @@
i::FunctionTemplateInfo::cast(internal_template->constructor()));
CHECK(!constructor->access_check_info()->IsUndefined());
v8::Persistent<Context> context0(Context::New(NULL, global_template));
+ CHECK(!context0.IsEmpty());
CHECK(!constructor->access_check_info()->IsUndefined());
}
@@ -12029,7 +12171,7 @@
callback_templ->GetFunction());
calling_context0->Exit();
- // Expose context0 in context1 and setup a function that calls the
+ // Expose context0 in context1 and set up a function that calls the
// callback function.
calling_context1->Enter();
calling_context1->Global()->Set(v8_str("context0"),
@@ -12187,18 +12329,18 @@
i::Handle<i::Smi> value(i::Smi::FromInt(2));
i::Handle<i::Object> no_failure;
- no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
ASSERT(!no_failure.is_null());
i::USE(no_failure);
CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
*value.location() = i::Smi::FromInt(256);
- no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
ASSERT(!no_failure.is_null());
i::USE(no_failure);
CHECK_EQ(255,
i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
*value.location() = i::Smi::FromInt(-1);
- no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
+ no_failure = i::JSObject::SetElement(jsobj, 1, value, i::kNonStrictMode);
ASSERT(!no_failure.is_null());
i::USE(no_failure);
CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
@@ -12914,11 +13056,6 @@
const int kLargeElementCount = kXSize * kYSize * 4;
ElementType* large_array_data =
static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
- i::Handle<ExternalArrayClass> large_array(
- i::Handle<ExternalArrayClass>::cast(
- FACTORY->NewExternalArray(kLargeElementCount,
- array_type,
- array_data)));
v8::Handle<v8::Object> large_obj = v8::Object::New();
// Set the elements to be the external array.
large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
@@ -13319,8 +13456,8 @@
v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
v8::Handle<Value> overview_result(
v8::Script::New(overview_src, origin)->Run());
- ASSERT(!overview_result.IsEmpty());
- ASSERT(overview_result->IsObject());
+ CHECK(!overview_result.IsEmpty());
+ CHECK(overview_result->IsObject());
// Test getting DETAILED information.
const char *detailed_source =
@@ -13339,8 +13476,8 @@
v8::Handle<v8::Script> detailed_script(
v8::Script::New(detailed_src, &detailed_origin));
v8::Handle<Value> detailed_result(detailed_script->Run());
- ASSERT(!detailed_result.IsEmpty());
- ASSERT(detailed_result->IsObject());
+ CHECK(!detailed_result.IsEmpty());
+ CHECK(detailed_result->IsObject());
}
@@ -13438,7 +13575,23 @@
// Test that idle notification can be handled and eventually returns true.
+// This just checks the contract of the IdleNotification() function,
+// and does not verify that it does reasonable work.
THREADED_TEST(IdleNotification) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun("function binom(n, m) {"
+ " var C = [[1]];"
+ " for (var i = 1; i <= n; ++i) {"
+ " C[i] = [1];"
+ " for (var j = 1; j < i; ++j) {"
+ " C[i][j] = C[i-1][j-1] + C[i-1][j];"
+ " }"
+ " C[i][i] = 1;"
+ " }"
+ " return C[n][m];"
+ "};"
+ "binom(1000, 500)");
bool rv = false;
for (int i = 0; i < 100; i++) {
rv = v8::V8::IdleNotification();
@@ -13448,6 +13601,40 @@
CHECK(rv == true);
}
+// Test that idle notification can be handled and eventually returns true.
+// This just checks the contract of the IdleNotification() function,
+// and does not verify that it does reasonable work.
+TEST(IdleNotificationWithHint) {
+ v8::HandleScope scope;
+ LocalContext env;
+ {
+ i::AlwaysAllocateScope always_allocate;
+ CompileRun("function binom(n, m) {"
+ " var C = [[1]];"
+ " for (var i = 1; i <= n; ++i) {"
+ " C[i] = [1];"
+ " for (var j = 1; j < i; ++j) {"
+ " C[i][j] = C[i-1][j-1] + C[i-1][j];"
+ " }"
+ " C[i][i] = 1;"
+ " }"
+ " return C[n][m];"
+ "};"
+ "binom(1000, 500)");
+ }
+ bool rv = false;
+ intptr_t old_size = HEAP->SizeOfObjects();
+ bool no_idle_work = v8::V8::IdleNotification(10);
+ for (int i = 0; i < 200; i++) {
+ rv = v8::V8::IdleNotification(10);
+ if (rv)
+ break;
+ }
+ CHECK(rv == true);
+ intptr_t new_size = HEAP->SizeOfObjects();
+ CHECK(no_idle_work || new_size < old_size);
+}
+
static uint32_t* stack_limit;
@@ -13536,6 +13723,63 @@
}
+class VisitorImpl : public v8::ExternalResourceVisitor {
+ public:
+ VisitorImpl(TestResource* r1, TestResource* r2)
+ : resource1_(r1),
+ resource2_(r2),
+ found_resource1_(false),
+ found_resource2_(false) {}
+ virtual ~VisitorImpl() {}
+ virtual void VisitExternalString(v8::Handle<v8::String> string) {
+ if (!string->IsExternal()) {
+ CHECK(string->IsExternalAscii());
+ return;
+ }
+ v8::String::ExternalStringResource* resource =
+ string->GetExternalStringResource();
+ CHECK(resource);
+ if (resource1_ == resource) {
+ CHECK(!found_resource1_);
+ found_resource1_ = true;
+ }
+ if (resource2_ == resource) {
+ CHECK(!found_resource2_);
+ found_resource2_ = true;
+ }
+ }
+ void CheckVisitedResources() {
+ CHECK(found_resource1_);
+ CHECK(found_resource2_);
+ }
+
+ private:
+ v8::String::ExternalStringResource* resource1_;
+ v8::String::ExternalStringResource* resource2_;
+ bool found_resource1_;
+ bool found_resource2_;
+};
+
+TEST(VisitExternalStrings) {
+ v8::HandleScope scope;
+ LocalContext env;
+ const char* string = "Some string";
+ uint16_t* two_byte_string = AsciiToTwoByteString(string);
+ TestResource* resource1 = new TestResource(two_byte_string);
+ v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
+ TestResource* resource2 = new TestResource(two_byte_string);
+ v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
+
+ // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
+ CHECK(string1->IsExternal());
+ CHECK(string2->IsExternal());
+
+ VisitorImpl visitor(resource1, resource2);
+ v8::V8::VisitExternalResources(&visitor);
+ visitor.CheckVisitedResources();
+}
+
+
static double DoubleFromBits(uint64_t value) {
double target;
memcpy(&target, &value, sizeof(target));
@@ -13653,6 +13897,7 @@
v8::HandleScope scope;
v8::TryCatch tc;
v8::Handle<v8::String> str(args[0]->ToString());
+ USE(str);
if (tc.HasCaught())
return tc.ReThrow();
return v8::Undefined();
@@ -13797,6 +14042,17 @@
CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
}
+THREADED_TEST(FunctionGetInferredName) {
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
+ v8::Handle<v8::String> script = v8::String::New(
+ "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
+ v8::Script::Compile(script, &origin)->Run();
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(v8::String::New("f")));
+ CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
+}
THREADED_TEST(ScriptLineNumber) {
v8::HandleScope scope;
@@ -14109,7 +14365,7 @@
" for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
" for (var i = 0; i < 16; i++) {"
" var v = %_GetFromCache(0, keys[i]);"
- " if (v !== values[i])"
+ " if (v.toString() !== values[i].toString())"
" return 'Wrong value for ' + "
" keys[i] + ': ' + v + ' vs. ' + values[i];"
" };"
@@ -14951,7 +15207,7 @@
// RegExps are objects on which you can set properties.
re->Set(v8_str("property"), v8::Integer::New(32));
v8::Handle<v8::Value> value(CompileRun("re.property"));
- ASSERT_EQ(32, value->Int32Value());
+ CHECK_EQ(32, value->Int32Value());
v8::TryCatch try_catch;
re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
@@ -15597,3 +15853,98 @@
foreign_context.Dispose();
}
+
+
+uint8_t callback_fired = 0;
+
+
+void CallCompletedCallback1() {
+ i::OS::Print("Firing callback 1.\n");
+ callback_fired ^= 1; // Toggle first bit.
+}
+
+
+void CallCompletedCallback2() {
+ i::OS::Print("Firing callback 2.\n");
+ callback_fired ^= 2; // Toggle second bit.
+}
+
+
+Handle<Value> RecursiveCall(const Arguments& args) {
+ int32_t level = args[0]->Int32Value();
+ if (level < 3) {
+ level++;
+ i::OS::Print("Entering recursion level %d.\n", level);
+ char script[64];
+ i::Vector<char> script_vector(script, sizeof(script));
+ i::OS::SNPrintF(script_vector, "recursion(%d)", level);
+ CompileRun(script_vector.start());
+ i::OS::Print("Leaving recursion level %d.\n", level);
+ CHECK_EQ(0, callback_fired);
+ } else {
+ i::OS::Print("Recursion ends.\n");
+ CHECK_EQ(0, callback_fired);
+ }
+ return Undefined();
+}
+
+
+TEST(CallCompletedCallback) {
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::Handle<v8::FunctionTemplate> recursive_runtime =
+ v8::FunctionTemplate::New(RecursiveCall);
+ env->Global()->Set(v8_str("recursion"),
+ recursive_runtime->GetFunction());
+ // Adding the same callback a second time has no effect.
+ v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
+ v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
+ v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
+ i::OS::Print("--- Script (1) ---\n");
+ Local<Script> script =
+ v8::Script::Compile(v8::String::New("recursion(0)"));
+ script->Run();
+ CHECK_EQ(3, callback_fired);
+
+ i::OS::Print("\n--- Script (2) ---\n");
+ callback_fired = 0;
+ v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
+ script->Run();
+ CHECK_EQ(2, callback_fired);
+
+ i::OS::Print("\n--- Function ---\n");
+ callback_fired = 0;
+ Local<Function> recursive_function =
+ Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
+ v8::Handle<Value> args[] = { v8_num(0) };
+ recursive_function->Call(env->Global(), 1, args);
+ CHECK_EQ(2, callback_fired);
+}
+
+
+void CallCompletedCallbackNoException() {
+ v8::HandleScope scope;
+ CompileRun("1+1;");
+}
+
+
+void CallCompletedCallbackException() {
+ v8::HandleScope scope;
+ CompileRun("throw 'second exception';");
+}
+
+
+TEST(CallCompletedCallbackOneException) {
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
+ CompileRun("throw 'exception';");
+}
+
+
+TEST(CallCompletedCallbackTwoExceptions) {
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
+ CompileRun("throw 'first exception';");
+}
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index cdab8f7..815e618 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -408,4 +408,72 @@
__ nop();
}
+
+TEST(AssemblerMultiByteNop) {
+ InitializeVM();
+ v8::HandleScope scope;
+ v8::internal::byte buffer[1024];
+ Assembler assm(Isolate::Current(), buffer, sizeof(buffer));
+ __ push(ebx);
+ __ push(ecx);
+ __ push(edx);
+ __ push(edi);
+ __ push(esi);
+ __ mov(eax, 1);
+ __ mov(ebx, 2);
+ __ mov(ecx, 3);
+ __ mov(edx, 4);
+ __ mov(edi, 5);
+ __ mov(esi, 6);
+ for (int i = 0; i < 16; i++) {
+ int before = assm.pc_offset();
+ __ Nop(i);
+ CHECK_EQ(assm.pc_offset() - before, i);
+ }
+
+ Label fail;
+ __ cmp(eax, 1);
+ __ j(not_equal, &fail);
+ __ cmp(ebx, 2);
+ __ j(not_equal, &fail);
+ __ cmp(ecx, 3);
+ __ j(not_equal, &fail);
+ __ cmp(edx, 4);
+ __ j(not_equal, &fail);
+ __ cmp(edi, 5);
+ __ j(not_equal, &fail);
+ __ cmp(esi, 6);
+ __ j(not_equal, &fail);
+ __ mov(eax, 42);
+ __ pop(esi);
+ __ pop(edi);
+ __ pop(edx);
+ __ pop(ecx);
+ __ pop(ebx);
+ __ ret(0);
+ __ bind(&fail);
+ __ mov(eax, 13);
+ __ pop(esi);
+ __ pop(edi);
+ __ pop(edx);
+ __ pop(ecx);
+ __ pop(ebx);
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Code* code = Code::cast(HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
+ CHECK(code->IsCode());
+
+ F0 f = FUNCTION_CAST<F0>(code->entry());
+ int res = f();
+ CHECK_EQ(42, res);
+}
+
+
+
+
#undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 28f7c9b..d81923f 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -36,6 +36,7 @@
#include "cctest.h"
using v8::internal::Assembler;
+using v8::internal::Code;
using v8::internal::CodeDesc;
using v8::internal::FUNCTION_CAST;
using v8::internal::Immediate;
@@ -53,6 +54,7 @@
using v8::internal::r8;
using v8::internal::r9;
using v8::internal::rax;
+using v8::internal::rbx;
using v8::internal::rbp;
using v8::internal::rcx;
using v8::internal::rdi;
@@ -86,8 +88,18 @@
#define __ assm.
+static v8::Persistent<v8::Context> env;
+
+
+static void InitializeVM() {
+ if (env.IsEmpty()) {
+ env = v8::Context::New();
+ }
+}
+
+
TEST(AssemblerX64ReturnOperation) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -109,7 +121,7 @@
}
TEST(AssemblerX64StackOperations) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -141,7 +153,7 @@
}
TEST(AssemblerX64ArithmeticOperations) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -163,7 +175,7 @@
}
TEST(AssemblerX64ImulOperation) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -191,7 +203,7 @@
}
TEST(AssemblerX64MemoryOperands) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -225,7 +237,7 @@
}
TEST(AssemblerX64ControlFlow) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -254,7 +266,7 @@
}
TEST(AssemblerX64LoopImmediates) {
- OS::Setup();
+ OS::SetUp();
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
@@ -359,4 +371,73 @@
__ nop();
}
+
+TEST(AssemblerMultiByteNop) {
+ InitializeVM();
+ v8::HandleScope scope;
+ v8::internal::byte buffer[1024];
+ Assembler assm(Isolate::Current(), buffer, sizeof(buffer));
+ __ push(rbx);
+ __ push(rcx);
+ __ push(rdx);
+ __ push(rdi);
+ __ push(rsi);
+ __ movq(rax, Immediate(1));
+ __ movq(rbx, Immediate(2));
+ __ movq(rcx, Immediate(3));
+ __ movq(rdx, Immediate(4));
+ __ movq(rdi, Immediate(5));
+ __ movq(rsi, Immediate(6));
+ for (int i = 0; i < 16; i++) {
+ int before = assm.pc_offset();
+ __ Nop(i);
+ CHECK_EQ(assm.pc_offset() - before, i);
+ }
+
+ Label fail;
+ __ cmpq(rax, Immediate(1));
+ __ j(not_equal, &fail);
+ __ cmpq(rbx, Immediate(2));
+ __ j(not_equal, &fail);
+ __ cmpq(rcx, Immediate(3));
+ __ j(not_equal, &fail);
+ __ cmpq(rdx, Immediate(4));
+ __ j(not_equal, &fail);
+ __ cmpq(rdi, Immediate(5));
+ __ j(not_equal, &fail);
+ __ cmpq(rsi, Immediate(6));
+ __ j(not_equal, &fail);
+ __ movq(rax, Immediate(42));
+ __ pop(rsi);
+ __ pop(rdi);
+ __ pop(rdx);
+ __ pop(rcx);
+ __ pop(rbx);
+ __ ret(0);
+ __ bind(&fail);
+ __ movq(rax, Immediate(13));
+ __ pop(rsi);
+ __ pop(rdi);
+ __ pop(rdx);
+ __ pop(rcx);
+ __ pop(rbx);
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Code* code = Code::cast(HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ v8::internal::Handle<v8::internal::Object>(
+ HEAP->undefined_value()))->ToObjectChecked());
+ CHECK(code->IsCode());
+
+ F0 f = FUNCTION_CAST<F0>(code->entry());
+ int res = f();
+ CHECK_EQ(42, res);
+}
+
+
+
+
#undef __
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 7f63ebc..9ca0b0a 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -270,8 +270,7 @@
CHECK(!fun.is_null());
bool has_pending_exception;
Handle<JSObject> global(Isolate::Current()->context()->global());
- Handle<Object> result(
- Execution::Call(fun, global, 0, NULL, &has_pending_exception));
+ Execution::Call(fun, global, 0, NULL, &has_pending_exception);
CHECK(has_pending_exception);
CHECK_EQ(42.0, Isolate::Current()->pending_exception()->
ToObjectChecked()->Number());
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index f567a0f..b10e688 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -216,7 +216,7 @@
TEST(CrashIfStoppingLastNonExistentProfile) {
InitializeVM();
TestSetup test_setup;
- CpuProfiler::Setup();
+ CpuProfiler::SetUp();
CpuProfiler::StartProfiling("1");
CpuProfiler::StopProfiling("2");
CpuProfiler::StartProfiling("1");
@@ -268,7 +268,7 @@
TEST(DeleteAllCpuProfiles) {
InitializeVM();
TestSetup test_setup;
- CpuProfiler::Setup();
+ CpuProfiler::SetUp();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
CpuProfiler::DeleteAllProfiles();
CHECK_EQ(0, CpuProfiler::GetProfilesCount());
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index a9e2836..c0ea707 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -856,7 +856,7 @@
if (event == v8::Break) {
break_point_hit_count++;
- v8::Handle<v8::Function> fun(v8::Handle<v8::Function>::Cast(data));
+ CHECK(data->IsFunction());
ClearBreakPoint(debug_event_remove_break_point);
}
}
@@ -1447,8 +1447,7 @@
// Test IC store break point with garbage collection.
{
- v8::Local<v8::Function> bar(
- CompileFunction(&env, "function foo(){}", "foo"));
+ CompileFunction(&env, "function foo(){}", "foo");
foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
SetBreakPoint(foo, 0);
}
@@ -1456,8 +1455,7 @@
// Test IC load break point with garbage collection.
{
- v8::Local<v8::Function> bar(
- CompileFunction(&env, "function foo(){}", "foo"));
+ CompileFunction(&env, "function foo(){}", "foo");
foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
SetBreakPoint(foo, 0);
}
@@ -1465,8 +1463,7 @@
// Test IC call break point with garbage collection.
{
- v8::Local<v8::Function> bar(
- CompileFunction(&env, "function foo(){}", "foo"));
+ CompileFunction(&env, "function foo(){}", "foo");
foo = CompileFunction(&env,
"function bar(){};function foo(){bar();}",
"foo");
@@ -1476,8 +1473,7 @@
// Test return break point with garbage collection.
{
- v8::Local<v8::Function> bar(
- CompileFunction(&env, "function foo(){}", "foo"));
+ CompileFunction(&env, "function foo(){}", "foo");
foo = CompileFunction(&env, "function foo(){}", "foo");
SetBreakPoint(foo, 0);
}
@@ -1485,8 +1481,7 @@
// Test non IC break point with garbage collection.
{
- v8::Local<v8::Function> bar(
- CompileFunction(&env, "function foo(){}", "foo"));
+ CompileFunction(&env, "function foo(){}", "foo");
foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
SetBreakPoint(foo, 0);
}
@@ -2743,7 +2738,7 @@
v8::Handle<v8::Value> args[kArgc] = { a };
foo->Call(env->Global(), kArgc, args);
- // Setup break point and step through the function.
+ // Set up break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
break_point_hit_count = 0;
@@ -2790,7 +2785,7 @@
v8::Handle<v8::Value> args[kArgc] = { a };
foo->Call(env->Global(), kArgc, args);
- // Setup break point and step through the function.
+ // Set up break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
break_point_hit_count = 0;
@@ -2834,7 +2829,7 @@
// Call function without any break points to ensure inlining is in place.
foo->Call(env->Global(), 0, NULL);
- // Setup break point and step through the function.
+ // Set up break point and step through the function.
SetBreakPoint(foo, 4);
step_action = StepNext;
break_point_hit_count = 0;
@@ -2869,7 +2864,7 @@
// Call function without any break points to ensure inlining is in place.
foo->Call(env->Global(), 0, NULL);
- // Setup break point and step through the function.
+ // Set up break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
break_point_hit_count = 0;
@@ -3751,8 +3746,7 @@
v8::internal::Isolate::Current()->TraceException(false);
// Create functions for testing break on exception.
- v8::Local<v8::Function> throws(
- CompileFunction(&env, "function throws(){throw 1;}", "throws"));
+ CompileFunction(&env, "function throws(){throw 1;}", "throws");
v8::Local<v8::Function> caught =
CompileFunction(&env,
"function caught(){try {throws();} catch(e) {};}",
@@ -5549,8 +5543,6 @@
// Get the test functions again.
v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
env->Global()->Get(v8::String::New("foo"))));
- v8::Local<v8::Function> bar(v8::Local<v8::Function>::Cast(
- env->Global()->Get(v8::String::New("foo"))));
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(0, break_point_hit_count);
@@ -5709,7 +5701,7 @@
v8::HandleScope scope;
DebugLocalContext env;
- // Setup message and host dispatch handlers.
+ // Set up message and host dispatch handlers.
v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
@@ -5797,7 +5789,7 @@
v8::HandleScope scope;
DebugLocalContext env;
- // Setup debug message dispatch handler.
+ // Set up debug message dispatch handler.
v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
CompileRun("var y = 1 + 2;\n");
@@ -5851,7 +5843,7 @@
bool ok;
// Initialize the socket library.
- i::Socket::Setup();
+ i::Socket::SetUp();
// Test starting and stopping the agent without any client connection.
debugger->StartAgent("test", kPort1);
@@ -5949,7 +5941,7 @@
OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
// Initialize the socket library.
- i::Socket::Setup();
+ i::Socket::SetUp();
// Create a socket server to receive a debugger agent message.
DebuggerAgentProtocolServerThread* server =
@@ -6028,6 +6020,8 @@
EmptyExternalStringResource source_ext_str;
v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
v8::Handle<v8::Script> evil_script(v8::Script::Compile(source));
+ // "use" evil_script to make the compiler happy.
+ (void) evil_script;
Handle<i::ExternalTwoByteString> i_source(
i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
// This situation can happen if source was an external string disposed
@@ -6675,7 +6669,7 @@
break_point_hit_count++;
v8::HandleScope scope;
- v8::Handle<v8::String> json(message.GetJSON());
+ message.GetJSON();
SendContinueCommand();
} else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
@@ -6686,7 +6680,7 @@
isolate->stack_guard()->DebugBreak();
// Force serialization to trigger some internal JS execution.
- v8::Handle<v8::String> json(message.GetJSON());
+ message.GetJSON();
// Restore previous state.
if (is_debug_break) {
@@ -6869,7 +6863,7 @@
foo->Call(env->Global(), 0, NULL);
// When keeping the debug break several break will happen.
- CHECK_EQ(3, break_point_hit_count);
+ CHECK_GT(break_point_hit_count, 1);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
diff --git a/test/cctest/test-deoptimization.cc b/test/cctest/test-deoptimization.cc
index c713b02..ea34a75 100644
--- a/test/cctest/test-deoptimization.cc
+++ b/test/cctest/test-deoptimization.cc
@@ -1,4 +1,4 @@
-// Copyright 2007-2010 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -237,7 +237,7 @@
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));
+ CHECK(!fun.IsEmpty());
}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index 032e6bc..0e9432d 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -69,10 +69,10 @@
}
-// Setup V8 to a state where we can at least run the assembler and
+// Set up V8 to a state where we can at least run the assembler and
// disassembler. Declare the variables and allocate the data structures used
// in the rest of the macros.
-#define SETUP() \
+#define SET_UP() \
InitializeVM(); \
v8::HandleScope scope; \
byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
@@ -102,7 +102,7 @@
TEST(Type0) {
- SETUP();
+ SET_UP();
COMPARE(and_(r0, r1, Operand(r2)),
"e0010002 and r0, r1, r2");
@@ -329,7 +329,7 @@
TEST(Type1) {
- SETUP();
+ SET_UP();
COMPARE(and_(r0, r1, Operand(0x00000000)),
"e2010000 and r0, r1, #0");
@@ -358,7 +358,7 @@
TEST(Type3) {
- SETUP();
+ SET_UP();
if (CpuFeatures::IsSupported(ARMv7)) {
COMPARE(ubfx(r0, r1, 5, 10),
@@ -413,7 +413,7 @@
TEST(Vfp) {
- SETUP();
+ SET_UP();
if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3);
@@ -546,7 +546,7 @@
TEST(LoadStore) {
- SETUP();
+ SET_UP();
COMPARE(ldrb(r0, MemOperand(r1)),
"e5d10000 ldrb r0, [r1, #+0]");
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index 1e38e4e..da09505 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -449,6 +449,11 @@
}
}
+ // Nop instructions
+ for (int i = 0; i < 16; i++) {
+ __ Nop(i);
+ }
+
__ ret(0);
CodeDesc desc;
diff --git a/test/cctest/test-disasm-mips.cc b/test/cctest/test-disasm-mips.cc
index 5ad99d7..8eadc64 100644
--- a/test/cctest/test-disasm-mips.cc
+++ b/test/cctest/test-disasm-mips.cc
@@ -71,10 +71,10 @@
}
-// Setup V8 to a state where we can at least run the assembler and
+// Set up V8 to a state where we can at least run the assembler and
// disassembler. Declare the variables and allocate the data structures used
// in the rest of the macros.
-#define SETUP() \
+#define SET_UP() \
InitializeVM(); \
v8::HandleScope scope; \
byte *buffer = reinterpret_cast<byte*>(malloc(4*1024)); \
@@ -104,7 +104,7 @@
TEST(Type0) {
- SETUP();
+ SET_UP();
COMPARE(addu(a0, a1, a2),
"00a62021 addu a0, a1, a2");
diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc
new file mode 100644
index 0000000..da85eb9
--- /dev/null
+++ b/test/cctest/test-disasm-x64.cc
@@ -0,0 +1,429 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "debug.h"
+#include "disasm.h"
+#include "disassembler.h"
+#include "macro-assembler.h"
+#include "serialize.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+static v8::Persistent<v8::Context> env;
+
+static void InitializeVM() {
+ if (env.IsEmpty()) {
+ env = v8::Context::New();
+ }
+}
+
+
+#define __ assm.
+
+
+static void DummyStaticFunction(Object* result) {
+}
+
+
+TEST(DisasmX64) {
+ InitializeVM();
+ v8::HandleScope scope;
+ v8::internal::byte buffer[2048];
+ Assembler assm(Isolate::Current(), buffer, sizeof buffer);
+ DummyStaticFunction(NULL); // just bloody use it (DELETE; debugging)
+
+ // Short immediate instructions
+ __ addq(rax, Immediate(12345678));
+ __ or_(rax, Immediate(12345678));
+ __ subq(rax, Immediate(12345678));
+ __ xor_(rax, Immediate(12345678));
+ __ and_(rax, Immediate(12345678));
+
+ // ---- This one caused crash
+ __ movq(rbx, Operand(rsp, rcx, times_2, 0)); // [rsp+rcx*4]
+
+ // ---- All instructions that I can think of
+ __ addq(rdx, rbx);
+ __ addq(rdx, Operand(rbx, 0));
+ __ addq(rdx, Operand(rbx, 16));
+ __ addq(rdx, Operand(rbx, 1999));
+ __ addq(rdx, Operand(rsp, 0));
+ __ addq(rdx, Operand(rsp, 16));
+ __ addq(rdx, Operand(rsp, 1999));
+ __ nop();
+ __ addq(rdi, Operand(rbp, rcx, times_4, 0));
+ __ addq(rdi, Operand(rbp, rcx, times_4, 12));
+ __ addq(Operand(rbp, rcx, times_4, 12), Immediate(12));
+
+ __ nop();
+ __ addq(rbx, Immediate(12));
+ __ nop();
+ __ nop();
+ __ and_(rdx, Immediate(3));
+ __ and_(rdx, Operand(rsp, 4));
+ __ cmpq(rdx, Immediate(3));
+ __ cmpq(rdx, Operand(rsp, 4));
+ __ cmpq(Operand(rbp, rcx, times_4, 0), Immediate(1000));
+ __ cmpb(rbx, Operand(rbp, rcx, times_2, 0));
+ __ cmpb(Operand(rbp, rcx, times_2, 0), rbx);
+ __ or_(rdx, Immediate(3));
+ __ xor_(rdx, Immediate(3));
+ __ nop();
+ {
+ CHECK(CpuFeatures::IsSupported(CPUID));
+ CpuFeatures::Scope fscope(CPUID);
+ __ cpuid();
+ }
+ {
+ CHECK(CpuFeatures::IsSupported(RDTSC));
+ CpuFeatures::Scope fscope(RDTSC);
+ __ rdtsc();
+ }
+ __ movsxbq(rdx, Operand(rcx, 0));
+ __ movsxwq(rdx, Operand(rcx, 0));
+ __ movzxbl(rdx, Operand(rcx, 0));
+ __ movzxwl(rdx, Operand(rcx, 0));
+ __ movzxbq(rdx, Operand(rcx, 0));
+ __ movzxwq(rdx, Operand(rcx, 0));
+
+ __ nop();
+ __ imul(rdx, rcx);
+ __ shld(rdx, rcx);
+ __ shrd(rdx, rcx);
+ __ bts(Operand(rdx, 0), rcx);
+ __ bts(Operand(rbx, rcx, times_4, 0), rcx);
+ __ nop();
+ __ push(Immediate(12));
+ __ push(Immediate(23456));
+ __ push(rcx);
+ __ push(rsi);
+ __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
+ __ push(Operand(rbx, rcx, times_4, 0));
+ __ push(Operand(rbx, rcx, times_4, 0));
+ __ push(Operand(rbx, rcx, times_4, 10000));
+ __ pop(rdx);
+ __ pop(rax);
+ __ pop(Operand(rbx, rcx, times_4, 0));
+ __ nop();
+
+ __ addq(rdx, Operand(rsp, 16));
+ __ addq(rdx, rcx);
+ __ movb(rdx, Operand(rcx, 0));
+ __ movb(rcx, Immediate(6));
+ __ movb(Operand(rsp, 16), rdx);
+ __ movw(Operand(rsp, 16), rdx);
+ __ nop();
+ __ movsxwq(rdx, Operand(rsp, 12));
+ __ movsxbq(rdx, Operand(rsp, 12));
+ __ movsxlq(rdx, Operand(rsp, 12));
+ __ movzxwq(rdx, Operand(rsp, 12));
+ __ movzxbq(rdx, Operand(rsp, 12));
+ __ nop();
+ __ movq(rdx, Immediate(1234567));
+ __ movq(rdx, Operand(rsp, 12));
+ __ movq(Operand(rbx, rcx, times_4, 10000), Immediate(12345));
+ __ movq(Operand(rbx, rcx, times_4, 10000), rdx);
+ __ nop();
+ __ decb(rdx);
+ __ decb(Operand(rax, 10));
+ __ decb(Operand(rbx, rcx, times_4, 10000));
+ __ decq(rdx);
+ __ cdq();
+
+ __ nop();
+ __ idivq(rdx);
+ __ mul(rdx);
+ __ neg(rdx);
+ __ not_(rdx);
+ __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
+
+ __ imul(rdx, Operand(rbx, rcx, times_4, 10000));
+ __ imul(rdx, rcx, Immediate(12));
+ __ imul(rdx, rcx, Immediate(1000));
+
+ __ incq(rdx);
+ __ incq(Operand(rbx, rcx, times_4, 10000));
+ __ push(Operand(rbx, rcx, times_4, 10000));
+ __ pop(Operand(rbx, rcx, times_4, 10000));
+ __ jmp(Operand(rbx, rcx, times_4, 10000));
+
+ __ lea(rdx, Operand(rbx, rcx, times_4, 10000));
+ __ or_(rdx, Immediate(12345));
+ __ or_(rdx, Operand(rbx, rcx, times_4, 10000));
+
+ __ nop();
+
+ __ rcl(rdx, Immediate(1));
+ __ rcl(rdx, Immediate(7));
+ __ rcr(rdx, Immediate(1));
+ __ rcr(rdx, Immediate(7));
+ __ sar(rdx, Immediate(1));
+ __ sar(rdx, Immediate(6));
+ __ sar_cl(rdx);
+ __ sbbq(rdx, rbx);
+ __ shld(rdx, rbx);
+ __ shl(rdx, Immediate(1));
+ __ shl(rdx, Immediate(6));
+ __ shl_cl(rdx);
+ __ shrd(rdx, rbx);
+ __ shr(rdx, Immediate(1));
+ __ shr(rdx, Immediate(7));
+ __ shr_cl(rdx);
+
+
+ // Immediates
+
+ __ addq(rbx, Immediate(12));
+ __ addq(Operand(rdx, rcx, times_4, 10000), Immediate(12));
+
+ __ and_(rbx, Immediate(12345));
+
+ __ cmpq(rbx, Immediate(12345));
+ __ cmpq(rbx, Immediate(12));
+ __ cmpq(Operand(rdx, rcx, times_4, 10000), Immediate(12));
+ __ cmpb(rax, Immediate(100));
+
+ __ or_(rbx, Immediate(12345));
+
+ __ subq(rbx, Immediate(12));
+ __ subq(Operand(rdx, rcx, times_4, 10000), Immediate(12));
+
+ __ xor_(rbx, Immediate(12345));
+
+ __ imul(rdx, rcx, Immediate(12));
+ __ imul(rdx, rcx, Immediate(1000));
+
+ __ cld();
+
+ __ subq(rdx, Operand(rbx, rcx, times_4, 10000));
+ __ subq(rdx, rbx);
+
+ __ testq(rdx, Immediate(12345));
+ __ testq(Operand(rbx, rcx, times_8, 10000), rdx);
+ __ testb(Operand(rcx, rbx, times_2, 1000), rdx);
+ __ testb(Operand(rax, -20), Immediate(0x9A));
+ __ nop();
+
+ __ xor_(rdx, Immediate(12345));
+ __ xor_(rdx, Operand(rbx, rcx, times_8, 10000));
+ __ bts(Operand(rbx, rcx, times_8, 10000), rdx);
+ __ hlt();
+ __ int3();
+ __ ret(0);
+ __ ret(8);
+
+ // Calls
+
+ Label L1, L2;
+ __ bind(&L1);
+ __ nop();
+ __ call(&L1);
+ __ call(&L2);
+ __ nop();
+ __ bind(&L2);
+ __ call(Operand(rbx, rcx, times_4, 10000));
+ __ nop();
+ Handle<Code> ic(Isolate::Current()->builtins()->builtin(
+ Builtins::kLoadIC_Initialize));
+ __ call(ic, RelocInfo::CODE_TARGET);
+ __ nop();
+ __ nop();
+
+ __ jmp(&L1);
+ __ jmp(Operand(rbx, rcx, times_4, 10000));
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ ExternalReference after_break_target =
+ ExternalReference(Debug_Address::AfterBreakTarget(),
+ assm.isolate());
+#endif // ENABLE_DEBUGGER_SUPPORT
+ __ jmp(ic, RelocInfo::CODE_TARGET);
+ __ nop();
+
+
+ Label Ljcc;
+ __ nop();
+ // long jumps
+ __ j(overflow, &Ljcc);
+ __ j(no_overflow, &Ljcc);
+ __ j(below, &Ljcc);
+ __ j(above_equal, &Ljcc);
+ __ j(equal, &Ljcc);
+ __ j(not_equal, &Ljcc);
+ __ j(below_equal, &Ljcc);
+ __ j(above, &Ljcc);
+ __ j(sign, &Ljcc);
+ __ j(not_sign, &Ljcc);
+ __ j(parity_even, &Ljcc);
+ __ j(parity_odd, &Ljcc);
+ __ j(less, &Ljcc);
+ __ j(greater_equal, &Ljcc);
+ __ j(less_equal, &Ljcc);
+ __ j(greater, &Ljcc);
+ __ nop();
+ __ bind(&Ljcc);
+ // short jumps
+ __ j(overflow, &Ljcc);
+ __ j(no_overflow, &Ljcc);
+ __ j(below, &Ljcc);
+ __ j(above_equal, &Ljcc);
+ __ j(equal, &Ljcc);
+ __ j(not_equal, &Ljcc);
+ __ j(below_equal, &Ljcc);
+ __ j(above, &Ljcc);
+ __ j(sign, &Ljcc);
+ __ j(not_sign, &Ljcc);
+ __ j(parity_even, &Ljcc);
+ __ j(parity_odd, &Ljcc);
+ __ j(less, &Ljcc);
+ __ j(greater_equal, &Ljcc);
+ __ j(less_equal, &Ljcc);
+ __ j(greater, &Ljcc);
+
+ // 0xD9 instructions
+ __ nop();
+
+ __ fld(1);
+ __ fld1();
+ __ fldz();
+ __ fldpi();
+ __ fabs();
+ __ fchs();
+ __ fprem();
+ __ fprem1();
+ __ fincstp();
+ __ ftst();
+ __ fxch(3);
+ __ fld_s(Operand(rbx, rcx, times_4, 10000));
+ __ fstp_s(Operand(rbx, rcx, times_4, 10000));
+ __ ffree(3);
+ __ fld_d(Operand(rbx, rcx, times_4, 10000));
+ __ fstp_d(Operand(rbx, rcx, times_4, 10000));
+ __ nop();
+
+ __ fild_s(Operand(rbx, rcx, times_4, 10000));
+ __ fistp_s(Operand(rbx, rcx, times_4, 10000));
+ __ fild_d(Operand(rbx, rcx, times_4, 10000));
+ __ fistp_d(Operand(rbx, rcx, times_4, 10000));
+ __ fnstsw_ax();
+ __ nop();
+ __ fadd(3);
+ __ fsub(3);
+ __ fmul(3);
+ __ fdiv(3);
+
+ __ faddp(3);
+ __ fsubp(3);
+ __ fmulp(3);
+ __ fdivp(3);
+ __ fcompp();
+ __ fwait();
+ __ nop();
+ {
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ cvttss2si(rdx, Operand(rbx, rcx, times_4, 10000));
+ __ cvttss2si(rdx, xmm1);
+ __ cvttsd2si(rdx, Operand(rbx, rcx, times_4, 10000));
+ __ cvttsd2si(rdx, xmm1);
+ __ cvttsd2siq(rdx, xmm1);
+ __ addsd(xmm1, xmm0);
+ __ mulsd(xmm1, xmm0);
+ __ subsd(xmm1, xmm0);
+ __ divsd(xmm1, xmm0);
+ __ movsd(xmm1, Operand(rbx, rcx, times_4, 10000));
+ __ movsd(Operand(rbx, rcx, times_4, 10000), xmm1);
+ __ ucomisd(xmm0, xmm1);
+
+ // 128 bit move instructions.
+ __ movdqa(xmm0, Operand(rbx, rcx, times_4, 10000));
+ __ movdqa(Operand(rbx, rcx, times_4, 10000), xmm0);
+ }
+ }
+
+ // cmov.
+ {
+ if (CpuFeatures::IsSupported(CMOV)) {
+ CpuFeatures::Scope use_cmov(CMOV);
+ __ cmovq(overflow, rax, Operand(rax, 0));
+ __ cmovq(no_overflow, rax, Operand(rax, 1));
+ __ cmovq(below, rax, Operand(rax, 2));
+ __ cmovq(above_equal, rax, Operand(rax, 3));
+ __ cmovq(equal, rax, Operand(rbx, 0));
+ __ cmovq(not_equal, rax, Operand(rbx, 1));
+ __ cmovq(below_equal, rax, Operand(rbx, 2));
+ __ cmovq(above, rax, Operand(rbx, 3));
+ __ cmovq(sign, rax, Operand(rcx, 0));
+ __ cmovq(not_sign, rax, Operand(rcx, 1));
+ __ cmovq(parity_even, rax, Operand(rcx, 2));
+ __ cmovq(parity_odd, rax, Operand(rcx, 3));
+ __ cmovq(less, rax, Operand(rdx, 0));
+ __ cmovq(greater_equal, rax, Operand(rdx, 1));
+ __ cmovq(less_equal, rax, Operand(rdx, 2));
+ __ cmovq(greater, rax, Operand(rdx, 3));
+ }
+ }
+
+ // andpd, etc.
+ {
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ andpd(xmm0, xmm1);
+ __ andpd(xmm1, xmm2);
+
+ __ movaps(xmm0, xmm1);
+ __ movaps(xmm1, xmm2);
+ }
+ }
+
+ // Nop instructions
+ for (int i = 0; i < 16; i++) {
+ __ Nop(i);
+ }
+
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+#ifdef OBJECT_PRINT
+ Code::cast(code)->Print();
+ byte* begin = Code::cast(code)->instruction_start();
+ byte* end = begin + Code::cast(code)->instruction_size();
+ disasm::Disassembler::Disassemble(stdout, begin, end);
+#endif
+}
+
+#undef __
diff --git a/test/cctest/test-hashing.cc b/test/cctest/test-hashing.cc
index 9c342a9..a626510 100644
--- a/test/cctest/test-hashing.cc
+++ b/test/cctest/test-hashing.cc
@@ -46,66 +46,108 @@
static v8::Persistent<v8::Context> env;
-#define __ assm->
+#define __ masm->
-void generate(MacroAssembler* assm, i::Vector<const char> string) {
+void generate(MacroAssembler* masm, i::Vector<const char> string) {
+ // GenerateHashInit takes the first character as an argument so it can't
+ // handle the zero length string.
+ ASSERT(string.length() > 0);
#ifdef V8_TARGET_ARCH_IA32
__ push(ebx);
__ push(ecx);
__ mov(eax, Immediate(0));
- if (string.length() > 0) {
- __ mov(ebx, Immediate(string.at(0)));
- StringHelper::GenerateHashInit(assm, eax, ebx, ecx);
- }
+ __ mov(ebx, Immediate(string.at(0)));
+ StringHelper::GenerateHashInit(masm, eax, ebx, ecx);
for (int i = 1; i < string.length(); i++) {
__ mov(ebx, Immediate(string.at(i)));
- StringHelper::GenerateHashAddCharacter(assm, eax, ebx, ecx);
+ StringHelper::GenerateHashAddCharacter(masm, eax, ebx, ecx);
}
- StringHelper::GenerateHashGetHash(assm, eax, ecx);
+ StringHelper::GenerateHashGetHash(masm, eax, ecx);
__ pop(ecx);
__ pop(ebx);
__ Ret();
#elif V8_TARGET_ARCH_X64
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
__ push(rbx);
__ push(rcx);
__ movq(rax, Immediate(0));
- if (string.length() > 0) {
- __ movq(rbx, Immediate(string.at(0)));
- StringHelper::GenerateHashInit(assm, rax, rbx, rcx);
- }
+ __ movq(rbx, Immediate(string.at(0)));
+ StringHelper::GenerateHashInit(masm, rax, rbx, rcx);
for (int i = 1; i < string.length(); i++) {
__ movq(rbx, Immediate(string.at(i)));
- StringHelper::GenerateHashAddCharacter(assm, rax, rbx, rcx);
+ StringHelper::GenerateHashAddCharacter(masm, rax, rbx, rcx);
}
- StringHelper::GenerateHashGetHash(assm, rax, rcx);
+ StringHelper::GenerateHashGetHash(masm, rax, rcx);
__ pop(rcx);
__ pop(rbx);
+ __ pop(kRootRegister);
__ Ret();
#elif V8_TARGET_ARCH_ARM
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
+
__ mov(r0, Operand(0));
- if (string.length() > 0) {
- __ mov(ip, Operand(string.at(0)));
- StringHelper::GenerateHashInit(assm, r0, ip);
- }
+ __ mov(ip, Operand(string.at(0)));
+ StringHelper::GenerateHashInit(masm, r0, ip);
for (int i = 1; i < string.length(); i++) {
__ mov(ip, Operand(string.at(i)));
- StringHelper::GenerateHashAddCharacter(assm, r0, ip);
+ StringHelper::GenerateHashAddCharacter(masm, r0, ip);
}
- StringHelper::GenerateHashGetHash(assm, r0);
+ StringHelper::GenerateHashGetHash(masm, r0);
+ __ pop(kRootRegister);
__ mov(pc, Operand(lr));
#elif V8_TARGET_ARCH_MIPS
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
+
__ li(v0, Operand(0));
- if (string.length() > 0) {
- __ li(t1, Operand(string.at(0)));
- StringHelper::GenerateHashInit(assm, v0, t1);
- }
+ __ li(t1, Operand(string.at(0)));
+ StringHelper::GenerateHashInit(masm, v0, t1);
for (int i = 1; i < string.length(); i++) {
__ li(t1, Operand(string.at(i)));
- StringHelper::GenerateHashAddCharacter(assm, v0, t1);
+ StringHelper::GenerateHashAddCharacter(masm, v0, t1);
}
- StringHelper::GenerateHashGetHash(assm, v0);
+ StringHelper::GenerateHashGetHash(masm, v0);
+ __ pop(kRootRegister);
__ jr(ra);
+ __ nop();
+#endif
+}
+
+
+void generate(MacroAssembler* masm, uint32_t key) {
+#ifdef V8_TARGET_ARCH_IA32
+ __ push(ebx);
+ __ mov(eax, Immediate(key));
+ __ GetNumberHash(eax, ebx);
+ __ pop(ebx);
+ __ Ret();
+#elif V8_TARGET_ARCH_X64
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
+ __ push(rbx);
+ __ movq(rax, Immediate(key));
+ __ GetNumberHash(rax, rbx);
+ __ pop(rbx);
+ __ pop(kRootRegister);
+ __ Ret();
+#elif V8_TARGET_ARCH_ARM
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
+ __ mov(r0, Operand(key));
+ __ GetNumberHash(r0, ip);
+ __ pop(kRootRegister);
+ __ mov(pc, Operand(lr));
+#elif V8_TARGET_ARCH_MIPS
+ __ push(kRootRegister);
+ __ InitializeRootRegister();
+ __ li(v0, Operand(key));
+ __ GetNumberHash(v0, t1);
+ __ pop(kRootRegister);
+ __ jr(ra);
+ __ nop();
#endif
}
@@ -113,19 +155,19 @@
void check(i::Vector<const char> string) {
v8::HandleScope scope;
v8::internal::byte buffer[2048];
- MacroAssembler assm(Isolate::Current(), buffer, sizeof buffer);
+ MacroAssembler masm(Isolate::Current(), buffer, sizeof buffer);
- generate(&assm, string);
+ generate(&masm, string);
CodeDesc desc;
- assm.GetCode(&desc);
+ masm.GetCode(&desc);
Code* code = Code::cast(HEAP->CreateCode(
desc,
Code::ComputeFlags(Code::STUB),
Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
CHECK(code->IsCode());
- HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(Code::cast(code)->entry());
+ HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(code->entry());
Handle<String> v8_string = FACTORY->NewStringFromAscii(string);
v8_string->set_hash_field(String::kEmptyHashField);
#ifdef USE_SIMULATOR
@@ -139,12 +181,47 @@
}
+void check(uint32_t key) {
+ v8::HandleScope scope;
+ v8::internal::byte buffer[2048];
+ MacroAssembler masm(Isolate::Current(), buffer, sizeof buffer);
+
+ generate(&masm, key);
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+ Code* code = Code::cast(HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked());
+ CHECK(code->IsCode());
+
+ HASH_FUNCTION hash = FUNCTION_CAST<HASH_FUNCTION>(code->entry());
+#ifdef USE_SIMULATOR
+ uint32_t codegen_hash =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(hash, 0, 0, 0, 0, 0));
+#else
+ uint32_t codegen_hash = hash();
+#endif
+
+ uint32_t runtime_hash = ComputeIntegerHash(
+ key,
+ Isolate::Current()->heap()->HashSeed());
+ CHECK(runtime_hash == codegen_hash);
+}
+
+
void check_twochars(char a, char b) {
char ab[2] = {a, b};
check(i::Vector<const char>(ab, 2));
}
+static uint32_t PseudoRandom(uint32_t i, uint32_t j) {
+ return ~(~((i * 781) ^ (j * 329)));
+}
+
+
TEST(StringHash) {
if (env.IsEmpty()) env = v8::Context::New();
for (int a = 0; a < String::kMaxAsciiCharCode; a++) {
@@ -155,7 +232,6 @@
check_twochars(static_cast<char>(a), static_cast<char>(b));
}
}
- check(i::Vector<const char>("", 0));
check(i::Vector<const char>("*", 1));
check(i::Vector<const char>(".zZ", 3));
check(i::Vector<const char>("muc", 3));
@@ -163,4 +239,22 @@
check(i::Vector<const char>("-=[ vee eight ftw ]=-", 21));
}
+
+TEST(NumberHash) {
+ if (env.IsEmpty()) env = v8::Context::New();
+
+ // Some specific numbers
+ for (uint32_t key = 0; key < 42; key += 7) {
+ check(key);
+ }
+
+ // Some pseudo-random numbers
+ static const uint32_t kLimit = 1000;
+ for (uint32_t i = 0; i < 5; i++) {
+ for (uint32_t j = 0; j < 5; j++) {
+ check(PseudoRandom(i, j) % kLimit);
+ }
+ }
+}
+
#undef __
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 81b68a7..4b211b4 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -585,6 +585,22 @@
}
+static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
+ const v8::HeapGraphNode* node,
+ int level, int max_level) {
+ if (level > max_level) return;
+ CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
+ for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = node->GetChild(i);
+ const v8::HeapGraphNode* child =
+ snapshot->GetNodeById(prop->GetToNode()->GetId());
+ CHECK_EQ_UINT64_T(prop->GetToNode()->GetId(), child->GetId());
+ CHECK_EQ(prop->GetToNode(), child);
+ CheckChildrenIds(snapshot, child, level + 1, max_level);
+ }
+}
+
+
TEST(HeapSnapshotGetNodeById) {
v8::HandleScope scope;
LocalContext env;
@@ -592,12 +608,7 @@
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("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()));
- }
+ CheckChildrenIds(snapshot, root, 0, 3);
// Check a big id, which should not exist yet.
CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
}
@@ -1065,3 +1076,82 @@
GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
CHECK_NE(NULL, setterFunction);
}
+
+
+bool HasWeakEdge(const v8::HeapGraphNode* node) {
+ for (int i = 0; i < node->GetChildrenCount(); ++i) {
+ const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
+ if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
+ }
+ return false;
+}
+
+
+bool HasWeakGlobalHandle() {
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
+ const v8::HeapGraphNode* gc_roots = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
+ CHECK_NE(NULL, gc_roots);
+ const v8::HeapGraphNode* global_handles = GetNode(
+ gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
+ CHECK_NE(NULL, global_handles);
+ return HasWeakEdge(global_handles);
+}
+
+
+static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
+ handle.Dispose();
+}
+
+
+TEST(WeakGlobalHandle) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CHECK(!HasWeakGlobalHandle());
+
+ v8::Persistent<v8::Object> handle =
+ v8::Persistent<v8::Object>::New(v8::Object::New());
+ handle.MakeWeak(NULL, PersistentHandleCallback);
+
+ CHECK(HasWeakGlobalHandle());
+}
+
+
+TEST(WeakGlobalContextRefs) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
+ const v8::HeapGraphNode* gc_roots = GetNode(
+ snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
+ CHECK_NE(NULL, gc_roots);
+ const v8::HeapGraphNode* global_handles = GetNode(
+ gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
+ CHECK_NE(NULL, global_handles);
+ const v8::HeapGraphNode* global_context = GetNode(
+ global_handles, v8::HeapGraphNode::kHidden, "system / GlobalContext");
+ CHECK_NE(NULL, global_context);
+ CHECK(HasWeakEdge(global_context));
+}
+
+
+TEST(SfiAndJsFunctionWeakRefs) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ CompileRun(
+ "fun = (function (x) { return function () { return x + 1; } })(1);");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("fun"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_NE(NULL, global);
+ const v8::HeapGraphNode* fun =
+ GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun");
+ CHECK(HasWeakEdge(fun));
+ const v8::HeapGraphNode* shared =
+ GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
+ CHECK(HasWeakEdge(shared));
+}
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 2ea359d..6ce3798 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1187,6 +1187,44 @@
}
+TEST(TestSizeOfObjects) {
+ v8::V8::Initialize();
+
+ // Get initial heap size after several full GCs, which will stabilize
+ // the heap size and return with sweeping finished completely.
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
+ int initial_size = static_cast<int>(HEAP->SizeOfObjects());
+
+ {
+ // Allocate objects on several different old-space pages so that
+ // lazy sweeping kicks in for subsequent GC runs.
+ AlwaysAllocateScope always_allocate;
+ int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
+ for (int i = 1; i <= 100; i++) {
+ HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
+ CHECK_EQ(initial_size + i * filler_size,
+ static_cast<int>(HEAP->SizeOfObjects()));
+ }
+ }
+
+ // The heap size should go back to initial size after a full GC, even
+ // though sweeping didn't finish yet.
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(!HEAP->old_pointer_space()->IsSweepingComplete());
+ CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
+
+ // Advancing the sweeper step-wise should not change the heap size.
+ while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
+ HEAP->old_pointer_space()->AdvanceSweeper(KB);
+ CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
+ }
+}
+
+
TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
InitializeVM();
HEAP->EnsureHeapIsIterable();
@@ -1290,6 +1328,35 @@
CHECK(old_capacity == new_capacity);
}
+// This just checks the contract of the IdleNotification() function,
+// and does not verify that it does reasonable work.
+TEST(IdleNotificationAdvancesIncrementalMarking) {
+ if (!FLAG_incremental_marking || !FLAG_incremental_marking_steps) return;
+ InitializeVM();
+ v8::HandleScope scope;
+ const char* source = "function binom(n, m) {"
+ " var C = [[1]];"
+ " for (var i = 1; i <= n; ++i) {"
+ " C[i] = [1];"
+ " for (var j = 1; j < i; ++j) {"
+ " C[i][j] = C[i-1][j-1] + C[i-1][j];"
+ " }"
+ " C[i][i] = 1;"
+ " }"
+ " return C[n][m];"
+ "};"
+ "binom(1000, 500)";
+ {
+ AlwaysAllocateScope aa_scope;
+ CompileRun(source);
+ }
+ intptr_t old_size = HEAP->SizeOfObjects();
+ bool no_idle_work = v8::V8::IdleNotification(900);
+ while (!v8::V8::IdleNotification(900)) ;
+ intptr_t new_size = HEAP->SizeOfObjects();
+ CHECK(no_idle_work || new_size < old_size);
+}
+
static int NumberOfGlobalObjects() {
int count = 0;
@@ -1450,12 +1517,12 @@
TEST(InstanceOfStubWriteBarrier) {
- if (!i::FLAG_crankshaft) return;
i::FLAG_allow_natives_syntax = true;
#ifdef DEBUG
i::FLAG_verify_heap = true;
#endif
InitializeVM();
+ if (!i::V8::UseCrankshaft()) return;
v8::HandleScope outer_scope;
{
@@ -1505,3 +1572,57 @@
HEAP->incremental_marking()->set_should_hurry(true);
HEAP->CollectGarbage(OLD_POINTER_SPACE);
}
+
+
+TEST(PrototypeTransitionClearing) {
+ InitializeVM();
+ v8::HandleScope scope;
+
+ CompileRun(
+ "var base = {};"
+ "var live = [];"
+ "for (var i = 0; i < 10; i++) {"
+ " var object = {};"
+ " var prototype = {};"
+ " object.__proto__ = prototype;"
+ " if (i >= 3) live.push(object, prototype);"
+ "}");
+
+ Handle<JSObject> baseObject =
+ v8::Utils::OpenHandle(
+ *v8::Handle<v8::Object>::Cast(
+ v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
+
+ // Verify that only dead prototype transitions are cleared.
+ CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());
+
+ // Verify that prototype transitions array was compacted.
+ FixedArray* trans = baseObject->map()->prototype_transitions();
+ for (int i = 0; i < 10 - 3; i++) {
+ int j = Map::kProtoTransitionHeaderSize +
+ i * Map::kProtoTransitionElementsPerEntry;
+ CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
+ CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
+ }
+
+ // Make sure next prototype is placed on an old-space evacuation candidate.
+ Handle<JSObject> prototype;
+ PagedSpace* space = HEAP->old_pointer_space();
+ do {
+ prototype = FACTORY->NewJSArray(32 * KB, TENURED);
+ } while (space->FirstPage() == space->LastPage() ||
+ !space->LastPage()->Contains(prototype->address()));
+
+ // Add a prototype on an evacuation candidate and verify that transition
+ // clearing correctly records slots in prototype transition array.
+ i::FLAG_always_compact = true;
+ Handle<Map> map(baseObject->map());
+ CHECK(!space->LastPage()->Contains(map->prototype_transitions()->address()));
+ CHECK(space->LastPage()->Contains(prototype->address()));
+ baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
+ CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+ CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
+}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index cd3c490..f8421e2 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -27,6 +27,14 @@
#include <stdlib.h>
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
#include "v8.h"
#include "global-handles.h"
@@ -142,9 +150,6 @@
// Call mark compact GC, and it should pass.
HEAP->CollectGarbage(OLD_POINTER_SPACE);
-
- // array should not be promoted because the old space is full.
- CHECK(HEAP->InSpace(*array, NEW_SPACE));
}
@@ -447,3 +452,100 @@
global_handles->AddImplicitReferences(
Handle<HeapObject>::cast(object).location(), NULL, 0);
}
+
+
+// Here is a memory use test that uses /proc, and is therefore Linux-only. We
+// do not care how much memory the simulator uses, since it is only there for
+// debugging purposes.
+#if defined(__linux__) && !defined(USE_SIMULATOR)
+
+
+static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) {
+ char* end_address = buffer + *position;
+ uintptr_t result = strtoul(buffer + *position, &end_address, base);
+ CHECK(result != ULONG_MAX || errno != ERANGE);
+ CHECK(end_address > buffer + *position);
+ *position = end_address - buffer;
+ return result;
+}
+
+
+static intptr_t MemoryInUse() {
+ intptr_t memory_use = 0;
+
+ int fd = open("/proc/self/maps", O_RDONLY);
+ if (fd < 0) return -1;
+
+ const int kBufSize = 10000;
+ char buffer[kBufSize];
+ int length = read(fd, buffer, kBufSize);
+ intptr_t line_start = 0;
+ CHECK_LT(length, kBufSize); // Make the buffer bigger.
+ CHECK_GT(length, 0); // We have to find some data in the file.
+ while (line_start < length) {
+ if (buffer[line_start] == '\n') {
+ line_start++;
+ continue;
+ }
+ intptr_t position = line_start;
+ uintptr_t start = ReadLong(buffer, &position, 16);
+ CHECK_EQ(buffer[position++], '-');
+ uintptr_t end = ReadLong(buffer, &position, 16);
+ CHECK_EQ(buffer[position++], ' ');
+ CHECK(buffer[position] == '-' || buffer[position] == 'r');
+ bool read_permission = (buffer[position++] == 'r');
+ CHECK(buffer[position] == '-' || buffer[position] == 'w');
+ bool write_permission = (buffer[position++] == 'w');
+ CHECK(buffer[position] == '-' || buffer[position] == 'x');
+ bool execute_permission = (buffer[position++] == 'x');
+ CHECK(buffer[position] == '-' || buffer[position] == 'p');
+ bool private_mapping = (buffer[position++] == 'p');
+ CHECK_EQ(buffer[position++], ' ');
+ uintptr_t offset = ReadLong(buffer, &position, 16);
+ USE(offset);
+ CHECK_EQ(buffer[position++], ' ');
+ uintptr_t major = ReadLong(buffer, &position, 16);
+ USE(major);
+ CHECK_EQ(buffer[position++], ':');
+ uintptr_t minor = ReadLong(buffer, &position, 16);
+ USE(minor);
+ CHECK_EQ(buffer[position++], ' ');
+ uintptr_t inode = ReadLong(buffer, &position, 10);
+ while (position < length && buffer[position] != '\n') position++;
+ if ((read_permission || write_permission || execute_permission) &&
+ private_mapping && inode == 0) {
+ memory_use += (end - start);
+ }
+
+ line_start = position;
+ }
+ close(fd);
+ return memory_use;
+}
+
+
+TEST(BootUpMemoryUse) {
+ intptr_t initial_memory = MemoryInUse();
+ FLAG_crankshaft = false; // Avoid flakiness.
+ // Only Linux has the proc filesystem and only if it is mapped. If it's not
+ // there we just skip the test.
+ if (initial_memory >= 0) {
+ InitializeVM();
+ intptr_t booted_memory = MemoryInUse();
+ if (sizeof(initial_memory) == 8) {
+ if (v8::internal::Snapshot::IsEnabled()) {
+ CHECK_LE(booted_memory - initial_memory, 6654 * 1024); // 6444.
+ } else {
+ CHECK_LE(booted_memory - initial_memory, 6777 * 1024); // 6596.
+ }
+ } else {
+ if (v8::internal::Snapshot::IsEnabled()) {
+ CHECK_LE(booted_memory - initial_memory, 6500 * 1024); // 6365.
+ } else {
+ CHECK_LE(booted_memory - initial_memory, 6654 * 1024); // 6424
+ }
+ }
+ }
+}
+
+#endif // __linux__ and !USE_SIMULATOR
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 6f394b6..1b6e4ab 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -230,7 +230,7 @@
CHECK_EQ(11, error_location.end_pos);
// Should not crash.
const char* message = pre_impl->BuildMessage();
- i::Vector<const char*> args(pre_impl->BuildArgs());
+ pre_impl->BuildArgs();
CHECK_GT(strlen(message), 0);
}
diff --git a/test/cctest/test-platform-linux.cc b/test/cctest/test-platform-linux.cc
index 756b947..2a8d497 100644
--- a/test/cctest/test-platform-linux.cc
+++ b/test/cctest/test-platform-linux.cc
@@ -67,7 +67,7 @@
TEST(VirtualMemory) {
- OS::Setup();
+ OS::SetUp();
VirtualMemory* vm = new VirtualMemory(1 * MB);
CHECK(vm->IsReserved());
void* block_addr = vm->address();
diff --git a/test/cctest/test-platform-win32.cc b/test/cctest/test-platform-win32.cc
index 9bd0014..36b30aa 100644
--- a/test/cctest/test-platform-win32.cc
+++ b/test/cctest/test-platform-win32.cc
@@ -13,7 +13,7 @@
TEST(VirtualMemory) {
- OS::Setup();
+ OS::SetUp();
VirtualMemory* vm = new VirtualMemory(1 * MB);
CHECK(vm->IsReserved());
void* block_addr = vm->address();
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index b778478..3070e16 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -836,7 +836,8 @@
Handle<Code> code = Handle<Code>::cast(code_object);
int captures[4] = {42, 37, 87, 117};
- const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o', '\xa0'};
+ const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o',
+ static_cast<uc16>('\xa0')};
Handle<String> input =
factory->NewStringFromTwoByte(Vector<const uc16>(input_data, 6));
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
@@ -856,7 +857,8 @@
CHECK_EQ(-1, captures[2]);
CHECK_EQ(-1, captures[3]);
- const uc16 input_data2[9] = {'b', 'a', 'r', 'b', 'a', 'r', 'b', 'a', '\xa0'};
+ const uc16 input_data2[9] = {'b', 'a', 'r', 'b', 'a', 'r', 'b', 'a',
+ static_cast<uc16>('\xa0')};
input = factory->NewStringFromTwoByte(Vector<const uc16>(input_data2, 9));
seq_input = Handle<SeqTwoByteString>::cast(input);
start_adr = seq_input->GetCharsAddress();
diff --git a/test/cctest/test-sockets.cc b/test/cctest/test-sockets.cc
index 4af55db..ad73540 100644
--- a/test/cctest/test-sockets.cc
+++ b/test/cctest/test-sockets.cc
@@ -129,7 +129,7 @@
bool ok;
// Initialize socket support.
- ok = Socket::Setup();
+ ok = Socket::SetUp();
CHECK(ok);
// Send and receive some data.
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index 27f64b4..92de2a6 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -125,14 +125,14 @@
TEST(MemoryAllocator) {
- OS::Setup();
+ OS::SetUp();
Isolate* isolate = Isolate::Current();
isolate->InitializeLoggingAndCounters();
Heap* heap = isolate->heap();
CHECK(isolate->heap()->ConfigureHeapDefault());
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
- CHECK(memory_allocator->Setup(heap->MaxReserved(),
+ CHECK(memory_allocator->SetUp(heap->MaxReserved(),
heap->MaxExecutableSize()));
int total_pages = 0;
@@ -175,21 +175,21 @@
TEST(NewSpace) {
- OS::Setup();
+ OS::SetUp();
Isolate* isolate = Isolate::Current();
isolate->InitializeLoggingAndCounters();
Heap* heap = isolate->heap();
CHECK(heap->ConfigureHeapDefault());
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
- CHECK(memory_allocator->Setup(heap->MaxReserved(),
+ CHECK(memory_allocator->SetUp(heap->MaxReserved(),
heap->MaxExecutableSize()));
TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
NewSpace new_space(heap);
- CHECK(new_space.Setup(HEAP->ReservedSemiSpaceSize(),
+ CHECK(new_space.SetUp(HEAP->ReservedSemiSpaceSize(),
HEAP->ReservedSemiSpaceSize()));
- CHECK(new_space.HasBeenSetup());
+ CHECK(new_space.HasBeenSetUp());
while (new_space.Available() >= Page::kMaxNonCodeHeapObjectSize) {
Object* obj =
@@ -205,13 +205,13 @@
TEST(OldSpace) {
- OS::Setup();
+ OS::SetUp();
Isolate* isolate = Isolate::Current();
isolate->InitializeLoggingAndCounters();
Heap* heap = isolate->heap();
CHECK(heap->ConfigureHeapDefault());
MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
- CHECK(memory_allocator->Setup(heap->MaxReserved(),
+ CHECK(memory_allocator->SetUp(heap->MaxReserved(),
heap->MaxExecutableSize()));
TestMemoryAllocatorScope test_scope(isolate, memory_allocator);
@@ -221,7 +221,7 @@
NOT_EXECUTABLE);
CHECK(s != NULL);
- CHECK(s->Setup());
+ CHECK(s->SetUp());
while (s->Available() > 0) {
s->AllocateRaw(Page::kMaxNonCodeHeapObjectSize)->ToObjectUnchecked();
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index 93f7588..e11349b 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -355,7 +355,7 @@
// Make sure we cover all always-flat lengths and at least one above.
static const int kMaxLength = 20;
- CHECK_GT(kMaxLength, i::String::kMinNonFlatLength);
+ CHECK_GT(kMaxLength, i::ConsString::kMinLength);
// Allocate two JavaScript arrays for holding short strings.
v8::Handle<v8::Array> ascii_external_strings =
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index e4f70df..df8ff72 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -105,7 +105,7 @@
TEST(MemCopy) {
v8::V8::Initialize();
- OS::Setup();
+ OS::SetUp();
const int N = OS::kMinComplexMemCopy + 128;
Vector<byte> buffer1 = Vector<byte>::New(N);
Vector<byte> buffer2 = Vector<byte>::New(N);