Push version 1.3.17 to trunk.
Added API method to get simple heap statistics.
Improved heap profiler support.
Fixed the implementation of the resource constraint API so it works when using snapshots.
Fixed a number of issues in the Windows 64-bit version.
Optimized calls to API getters.
Added valgrind notification on code modification to the 64-bit version.
Fixed issue where we logged shared library addresses on Windows at startup and never used them.
git-svn-id: http://v8.googlecode.com/svn/trunk@3167 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/test/cctest/SConscript b/test/cctest/SConscript
index f041041..9deefa5 100644
--- a/test/cctest/SConscript
+++ b/test/cctest/SConscript
@@ -34,6 +34,7 @@
SOURCES = {
'all': [
+ 'test-accessors.cc',
'test-alloc.cc',
'test-api.cc',
'test-ast.cc',
diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc
index 82a33e6..f638ed4 100644
--- a/test/cctest/cctest.cc
+++ b/test/cctest/cctest.cc
@@ -121,3 +121,6 @@
v8::V8::Dispose();
return 0;
}
+
+RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
+int RegisterThreadedTest::count_ = 0;
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index a95645e..404b692 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -28,6 +28,8 @@
#ifndef CCTEST_H_
#define CCTEST_H_
+#include "v8.h"
+
#ifndef TEST
#define TEST(Name) \
static void Test##Name(); \
@@ -72,4 +74,138 @@
CcTest* prev_;
};
+// Switches between all the Api tests using the threading support.
+// In order to get a surprising but repeatable pattern of thread
+// switching it has extra semaphores to control the order in which
+// the tests alternate, not relying solely on the big V8 lock.
+//
+// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
+// callbacks. This will have no effect when we are not running the
+// thread fuzzing test. In the thread fuzzing test it will
+// pseudorandomly select a successor thread and switch execution
+// to that thread, suspending the current test.
+class ApiTestFuzzer: public v8::internal::Thread {
+ public:
+ void CallTest();
+ explicit ApiTestFuzzer(int num)
+ : test_number_(num),
+ gate_(v8::internal::OS::CreateSemaphore(0)),
+ active_(true) {
+ }
+ ~ApiTestFuzzer() { delete gate_; }
+
+ // The ApiTestFuzzer is also a Thread, so it has a Run method.
+ virtual void Run();
+
+ enum PartOfTest { FIRST_PART, SECOND_PART };
+
+ static void Setup(PartOfTest part);
+ static void RunAllTests();
+ static void TearDown();
+ // This method switches threads if we are running the Threading test.
+ // Otherwise it does nothing.
+ static void Fuzz();
+ private:
+ static bool fuzzing_;
+ static int tests_being_run_;
+ static int current_;
+ static int active_tests_;
+ static bool NextThread();
+ int test_number_;
+ v8::internal::Semaphore* gate_;
+ bool active_;
+ void ContextSwitch();
+ static int GetNextTestNumber();
+ static v8::internal::Semaphore* all_tests_done_;
+};
+
+
+#define THREADED_TEST(Name) \
+ static void Test##Name(); \
+ RegisterThreadedTest register_##Name(Test##Name, #Name); \
+ /* */ TEST(Name)
+
+
+class RegisterThreadedTest {
+ public:
+ explicit RegisterThreadedTest(CcTest::TestFunction* callback,
+ const char* name)
+ : fuzzer_(NULL), callback_(callback), name_(name) {
+ prev_ = first_;
+ first_ = this;
+ count_++;
+ }
+ static int count() { return count_; }
+ static RegisterThreadedTest* nth(int i) {
+ CHECK(i < count());
+ RegisterThreadedTest* current = first_;
+ while (i > 0) {
+ i--;
+ current = current->prev_;
+ }
+ return current;
+ }
+ CcTest::TestFunction* callback() { return callback_; }
+ ApiTestFuzzer* fuzzer_;
+ const char* name() { return name_; }
+
+ private:
+ static RegisterThreadedTest* first_;
+ static int count_;
+ CcTest::TestFunction* callback_;
+ RegisterThreadedTest* prev_;
+ const char* name_;
+};
+
+
+// A LocalContext holds a reference to a v8::Context.
+class LocalContext {
+ public:
+ LocalContext(v8::ExtensionConfiguration* extensions = 0,
+ v8::Handle<v8::ObjectTemplate> global_template =
+ v8::Handle<v8::ObjectTemplate>(),
+ v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
+ : context_(v8::Context::New(extensions, global_template, global_object)) {
+ context_->Enter();
+ }
+
+ virtual ~LocalContext() {
+ context_->Exit();
+ context_.Dispose();
+ }
+
+ v8::Context* operator->() { return *context_; }
+ v8::Context* operator*() { return *context_; }
+ bool IsReady() { return !context_.IsEmpty(); }
+
+ v8::Local<v8::Context> local() {
+ return v8::Local<v8::Context>::New(context_);
+ }
+
+ private:
+ v8::Persistent<v8::Context> context_;
+};
+
+
+static inline v8::Local<v8::Value> v8_num(double x) {
+ return v8::Number::New(x);
+}
+
+
+static inline v8::Local<v8::String> v8_str(const char* x) {
+ return v8::String::New(x);
+}
+
+
+static inline v8::Local<v8::Script> v8_compile(const char* x) {
+ return v8::Script::Compile(v8_str(x));
+}
+
+
+// Helper function that compiles and runs the source.
+static inline v8::Local<v8::Value> CompileRun(const char* source) {
+ return v8::Script::Compile(v8::String::New(source))->Run();
+}
+
+
#endif // ifndef CCTEST_H_
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 8fff769..6ce241f 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -33,9 +33,24 @@
# BUG(382): Weird test. Can't guarantee that it never times out.
test-api/ApplyInterruption: PASS || TIMEOUT
+# This is about to go away anyway since new snapshot code is on the way.
+test-serialize/Deserialize: FAIL
+test-serialize/DeserializeAndRunScript: FAIL
+test-serialize/DeserializeNatives: FAIL
+test-serialize/DeserializeExtensions: 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 == arm ]
+# New serialization doesn't work on ARM yet.
+test-serialize/Deserialize2: SKIP
+test-serialize/DeserializeAndRunScript2: SKIP
+
# BUG(113): Test seems flaky on ARM.
test-spaces/LargeObjectSpace: PASS || FAIL
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
new file mode 100644
index 0000000..b56238a
--- /dev/null
+++ b/test/cctest/test-accessors.cc
@@ -0,0 +1,424 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "api.h"
+#include "cctest.h"
+#include "frames-inl.h"
+#include "string-stream.h"
+
+using ::v8::ObjectTemplate;
+using ::v8::Value;
+using ::v8::Context;
+using ::v8::Local;
+using ::v8::String;
+using ::v8::Script;
+using ::v8::Function;
+using ::v8::AccessorInfo;
+using ::v8::Extension;
+
+namespace i = ::v8::internal;
+
+static v8::Handle<Value> handle_property(Local<String> name,
+ const AccessorInfo&) {
+ ApiTestFuzzer::Fuzz();
+ return v8_num(900);
+}
+
+
+THREADED_TEST(PropertyHandler) {
+ v8::HandleScope scope;
+ Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+ fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
+ LocalContext env;
+ Local<Function> fun = fun_templ->GetFunction();
+ env->Global()->Set(v8_str("Fun"), fun);
+ Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
+ CHECK_EQ(900, getter->Run()->Int32Value());
+ Local<Script> setter = v8_compile("obj.foo = 901;");
+ CHECK_EQ(901, setter->Run()->Int32Value());
+}
+
+
+static v8::Handle<Value> GetIntValue(Local<String> property,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ int* value =
+ static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
+ return v8_num(*value);
+}
+
+
+static void SetIntValue(Local<String> property,
+ Local<Value> value,
+ const AccessorInfo& info) {
+ int* field =
+ static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
+ *field = value->Int32Value();
+}
+
+int foo, bar, baz;
+
+THREADED_TEST(GlobalVariableAccess) {
+ foo = 0;
+ bar = -4;
+ baz = 10;
+ v8::HandleScope scope;
+ v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+ templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
+ GetIntValue,
+ SetIntValue,
+ v8::External::New(&foo));
+ templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
+ GetIntValue,
+ SetIntValue,
+ v8::External::New(&bar));
+ templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
+ GetIntValue,
+ SetIntValue,
+ v8::External::New(&baz));
+ LocalContext env(0, templ->InstanceTemplate());
+ v8_compile("foo = (++bar) + baz")->Run();
+ CHECK_EQ(bar, -3);
+ CHECK_EQ(foo, 7);
+}
+
+
+static int x_register = 0;
+static v8::Handle<v8::Object> x_receiver;
+static v8::Handle<v8::Object> x_holder;
+
+
+static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ CHECK_EQ(x_receiver, info.This());
+ CHECK_EQ(x_holder, info.Holder());
+ return v8_num(x_register);
+}
+
+
+static void XSetter(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info) {
+ CHECK_EQ(x_holder, info.This());
+ CHECK_EQ(x_holder, info.Holder());
+ x_register = value->Int32Value();
+}
+
+
+THREADED_TEST(AccessorIC) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("x"), XGetter, XSetter);
+ LocalContext context;
+ x_holder = obj->NewInstance();
+ context->Global()->Set(v8_str("holder"), x_holder);
+ x_receiver = v8::Object::New();
+ context->Global()->Set(v8_str("obj"), x_receiver);
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
+ "obj.__proto__ = holder;"
+ "var result = [];"
+ "for (var i = 0; i < 10; i++) {"
+ " holder.x = i;"
+ " result.push(obj.x);"
+ "}"
+ "result"));
+ CHECK_EQ(10, array->Length());
+ for (int i = 0; i < 10; i++) {
+ v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
+ CHECK_EQ(v8::Integer::New(i), entry);
+ }
+}
+
+
+static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
+ Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ return v8::True();
+}
+
+
+THREADED_TEST(AccessorProhibitsOverwriting) {
+ v8::HandleScope scope;
+ LocalContext context;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetAccessor(v8_str("x"),
+ AccessorProhibitsOverwritingGetter,
+ 0,
+ v8::Handle<Value>(),
+ v8::PROHIBITS_OVERWRITING,
+ v8::ReadOnly);
+ Local<v8::Object> instance = templ->NewInstance();
+ context->Global()->Set(v8_str("obj"), instance);
+ Local<Value> value = CompileRun(
+ "obj.__defineGetter__('x', function() { return false; });"
+ "obj.x");
+ CHECK(value->BooleanValue());
+ value = CompileRun(
+ "var setter_called = false;"
+ "obj.__defineSetter__('x', function() { setter_called = true; });"
+ "obj.x = 42;"
+ "setter_called");
+ CHECK(!value->BooleanValue());
+ value = CompileRun(
+ "obj2 = {};"
+ "obj2.__proto__ = obj;"
+ "obj2.__defineGetter__('x', function() { return false; });"
+ "obj2.x");
+ CHECK(value->BooleanValue());
+ value = CompileRun(
+ "var setter_called = false;"
+ "obj2 = {};"
+ "obj2.__proto__ = obj;"
+ "obj2.__defineSetter__('x', function() { setter_called = true; });"
+ "obj2.x = 42;"
+ "setter_called");
+ CHECK(!value->BooleanValue());
+}
+
+
+template <int C>
+static v8::Handle<Value> HandleAllocatingGetter(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ for (int i = 0; i < C; i++)
+ v8::String::New("foo");
+ return v8::String::New("foo");
+}
+
+
+THREADED_TEST(HandleScopePop) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
+ obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
+ LocalContext context;
+ v8::Handle<v8::Object> inst = obj->NewInstance();
+ context->Global()->Set(v8::String::New("obj"), inst);
+ int count_before = i::HandleScope::NumberOfHandles();
+ {
+ v8::HandleScope scope;
+ CompileRun(
+ "for (var i = 0; i < 1000; i++) {"
+ " obj.one;"
+ " obj.many;"
+ "}");
+ }
+ int count_after = i::HandleScope::NumberOfHandles();
+ CHECK_EQ(count_before, count_after);
+}
+
+static v8::Handle<Value> CheckAccessorArgsCorrect(Local<String> name,
+ const AccessorInfo& info) {
+ CHECK(info.This() == info.Holder());
+ CHECK(info.Data()->Equals(v8::String::New("data")));
+ ApiTestFuzzer::Fuzz();
+ CHECK(info.This() == info.Holder());
+ CHECK(info.Data()->Equals(v8::String::New("data")));
+ i::Heap::CollectAllGarbage(true);
+ CHECK(info.This() == info.Holder());
+ CHECK(info.Data()->Equals(v8::String::New("data")));
+ return v8::Integer::New(17);
+}
+
+THREADED_TEST(DirectCall) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("xxx"),
+ CheckAccessorArgsCorrect,
+ NULL,
+ v8::String::New("data"));
+ LocalContext context;
+ v8::Handle<v8::Object> inst = obj->NewInstance();
+ context->Global()->Set(v8::String::New("obj"), inst);
+ Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
+ for (int i = 0; i < 10; i++) {
+ Local<Value> result = scr->Run();
+ CHECK(!result.IsEmpty());
+ CHECK_EQ(17, result->Int32Value());
+ }
+}
+
+static v8::Handle<Value> EmptyGetter(Local<String> name,
+ const AccessorInfo& info) {
+ CheckAccessorArgsCorrect(name, info);
+ ApiTestFuzzer::Fuzz();
+ CheckAccessorArgsCorrect(name, info);
+ return v8::Handle<v8::Value>();
+}
+
+THREADED_TEST(EmptyResult) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
+ LocalContext context;
+ v8::Handle<v8::Object> inst = obj->NewInstance();
+ context->Global()->Set(v8::String::New("obj"), inst);
+ Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
+ for (int i = 0; i < 10; i++) {
+ Local<Value> result = scr->Run();
+ CHECK(result == v8::Undefined());
+ }
+}
+
+
+THREADED_TEST(NoReuseRegress) {
+ // Check that the IC generated for the one test doesn't get reused
+ // for the other.
+ v8::HandleScope scope;
+ {
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8::String::New("data"));
+ LocalContext context;
+ v8::Handle<v8::Object> inst = obj->NewInstance();
+ context->Global()->Set(v8::String::New("obj"), inst);
+ Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
+ for (int i = 0; i < 2; i++) {
+ Local<Value> result = scr->Run();
+ CHECK(result == v8::Undefined());
+ }
+ }
+ {
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("xxx"),
+ CheckAccessorArgsCorrect,
+ NULL,
+ v8::String::New("data"));
+ LocalContext context;
+ v8::Handle<v8::Object> inst = obj->NewInstance();
+ context->Global()->Set(v8::String::New("obj"), inst);
+ Local<Script> scr = v8::Script::Compile(v8::String::New("obj.xxx"));
+ for (int i = 0; i < 10; i++) {
+ Local<Value> result = scr->Run();
+ CHECK(!result.IsEmpty());
+ CHECK_EQ(17, result->Int32Value());
+ }
+ }
+}
+
+static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ return v8::ThrowException(v8_str("g"));
+}
+
+
+static void ThrowingSetAccessor(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info) {
+ v8::ThrowException(value);
+}
+
+
+THREADED_TEST(Regress1054726) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("x"),
+ ThrowingGetAccessor,
+ ThrowingSetAccessor,
+ Local<Value>());
+
+ LocalContext env;
+ env->Global()->Set(v8_str("obj"), obj->NewInstance());
+
+ // Use the throwing property setter/getter in a loop to force
+ // the accessor ICs to be initialized.
+ v8::Handle<Value> result;
+ result = Script::Compile(v8_str(
+ "var result = '';"
+ "for (var i = 0; i < 5; i++) {"
+ " try { obj.x; } catch (e) { result += e; }"
+ "}; result"))->Run();
+ CHECK_EQ(v8_str("ggggg"), result);
+
+ result = Script::Compile(String::New(
+ "var result = '';"
+ "for (var i = 0; i < 5; i++) {"
+ " try { obj.x = i; } catch (e) { result += e; }"
+ "}; result"))->Run();
+ CHECK_EQ(v8_str("01234"), result);
+}
+
+
+static v8::Handle<Value> AllocGetter(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ return v8::Array::New(1000);
+}
+
+
+THREADED_TEST(Gc) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ obj->SetAccessor(v8_str("xxx"), AllocGetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("obj"), obj->NewInstance());
+ Script::Compile(String::New(
+ "var last = [];"
+ "for (var i = 0; i < 2048; i++) {"
+ " var result = obj.xxx;"
+ " result[0] = last;"
+ " last = result;"
+ "}"))->Run();
+}
+
+
+static v8::Handle<Value> StackCheck(Local<String> name,
+ const AccessorInfo& info) {
+ i::StackFrameIterator iter;
+ for (int i = 0; !iter.done(); i++) {
+ i::StackFrame* frame = iter.frame();
+ CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
+ CHECK(frame->code()->IsCode());
+ i::Address pc = frame->pc();
+ i::Code* code = frame->code();
+ CHECK(code->contains(pc));
+ iter.Advance();
+ }
+ return v8::Undefined();
+}
+
+
+THREADED_TEST(StackIteration) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
+ i::StringStream::ClearMentionedObjectCache();
+ obj->SetAccessor(v8_str("xxx"), StackCheck);
+ LocalContext env;
+ env->Global()->Set(v8_str("obj"), obj->NewInstance());
+ Script::Compile(String::New(
+ "function foo() {"
+ " return obj.xxx;"
+ "}"
+ "for (var i = 0; i < 100; i++) {"
+ " foo();"
+ "}"))->Run();
+}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index c63ba31..83038ae 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -25,6 +25,8 @@
// (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 <limits.h>
+
#include "v8.h"
#include "api.h"
@@ -33,8 +35,11 @@
#include "snapshot.h"
#include "platform.h"
#include "top.h"
+#include "utils.h"
#include "cctest.h"
+static const bool kLogThreading = false;
+
static bool IsNaN(double x) {
#ifdef WIN32
return _isnan(x);
@@ -55,131 +60,6 @@
namespace i = ::v8::internal;
-static Local<Value> v8_num(double x) {
- return v8::Number::New(x);
-}
-
-
-static Local<String> v8_str(const char* x) {
- return String::New(x);
-}
-
-
-static Local<Script> v8_compile(const char* x) {
- return Script::Compile(v8_str(x));
-}
-
-
-// A LocalContext holds a reference to a v8::Context.
-class LocalContext {
- public:
- LocalContext(v8::ExtensionConfiguration* extensions = 0,
- v8::Handle<ObjectTemplate> global_template =
- v8::Handle<ObjectTemplate>(),
- v8::Handle<Value> global_object = v8::Handle<Value>())
- : context_(Context::New(extensions, global_template, global_object)) {
- context_->Enter();
- }
-
- virtual ~LocalContext() {
- context_->Exit();
- context_.Dispose();
- }
-
- Context* operator->() { return *context_; }
- Context* operator*() { return *context_; }
- Local<Context> local() { return Local<Context>::New(context_); }
- bool IsReady() { return !context_.IsEmpty(); }
-
- private:
- v8::Persistent<Context> context_;
-};
-
-
-// Switches between all the Api tests using the threading support.
-// In order to get a surprising but repeatable pattern of thread
-// switching it has extra semaphores to control the order in which
-// the tests alternate, not relying solely on the big V8 lock.
-//
-// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
-// callbacks. This will have no effect when we are not running the
-// thread fuzzing test. In the thread fuzzing test it will
-// pseudorandomly select a successor thread and switch execution
-// to that thread, suspending the current test.
-class ApiTestFuzzer: public v8::internal::Thread {
- public:
- void CallTest();
- explicit ApiTestFuzzer(int num)
- : test_number_(num),
- gate_(v8::internal::OS::CreateSemaphore(0)),
- active_(true) {
- }
- ~ApiTestFuzzer() { delete gate_; }
-
- // The ApiTestFuzzer is also a Thread, so it has a Run method.
- virtual void Run();
-
- enum PartOfTest { FIRST_PART, SECOND_PART };
-
- static void Setup(PartOfTest part);
- static void RunAllTests();
- static void TearDown();
- // This method switches threads if we are running the Threading test.
- // Otherwise it does nothing.
- static void Fuzz();
- private:
- static bool fuzzing_;
- static int tests_being_run_;
- static int current_;
- static int active_tests_;
- static bool NextThread();
- int test_number_;
- v8::internal::Semaphore* gate_;
- bool active_;
- void ContextSwitch();
- static int GetNextTestNumber();
- static v8::internal::Semaphore* all_tests_done_;
-};
-
-
-#define THREADED_TEST(Name) \
- static void Test##Name(); \
- RegisterThreadedTest register_##Name(Test##Name); \
- /* */ TEST(Name)
-
-
-class RegisterThreadedTest {
- public:
- explicit RegisterThreadedTest(CcTest::TestFunction* callback)
- : fuzzer_(NULL), callback_(callback) {
- prev_ = first_;
- first_ = this;
- count_++;
- }
- static int count() { return count_; }
- static RegisterThreadedTest* nth(int i) {
- CHECK(i < count());
- RegisterThreadedTest* current = first_;
- while (i > 0) {
- i--;
- current = current->prev_;
- }
- return current;
- }
- CcTest::TestFunction* callback() { return callback_; }
- ApiTestFuzzer* fuzzer_;
-
- private:
- static RegisterThreadedTest* first_;
- static int count_;
- CcTest::TestFunction* callback_;
- RegisterThreadedTest* prev_;
-};
-
-
-RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
-int RegisterThreadedTest::count_ = 0;
-
static int signature_callback_count;
static v8::Handle<Value> IncrementingSignatureCallback(
@@ -228,11 +108,6 @@
}
-// Helper function that compiles and runs the source.
-static Local<Value> CompileRun(const char* source) {
- return Script::Compile(String::New(source))->Run();
-}
-
THREADED_TEST(ReceiverSignature) {
v8::HandleScope scope;
LocalContext env;
@@ -717,27 +592,6 @@
}
-static v8::Handle<Value> handle_property(Local<String> name,
- const AccessorInfo&) {
- ApiTestFuzzer::Fuzz();
- return v8_num(900);
-}
-
-
-THREADED_TEST(PropertyHandler) {
- v8::HandleScope scope;
- Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
- fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
- LocalContext env;
- Local<Function> fun = fun_templ->GetFunction();
- env->Global()->Set(v8_str("Fun"), fun);
- Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
- CHECK_EQ(900, getter->Run()->Int32Value());
- Local<Script> setter = v8_compile("obj.foo = 901;");
- CHECK_EQ(901, setter->Run()->Int32Value());
-}
-
-
THREADED_TEST(TinyInteger) {
v8::HandleScope scope;
LocalContext env;
@@ -904,49 +758,6 @@
}
-static v8::Handle<Value> GetIntValue(Local<String> property,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- int* value =
- static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
- return v8_num(*value);
-}
-
-static void SetIntValue(Local<String> property,
- Local<Value> value,
- const AccessorInfo& info) {
- int* field =
- static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
- *field = value->Int32Value();
-}
-
-int foo, bar, baz;
-
-THREADED_TEST(GlobalVariableAccess) {
- foo = 0;
- bar = -4;
- baz = 10;
- v8::HandleScope scope;
- v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
- templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
- GetIntValue,
- SetIntValue,
- v8::External::New(&foo));
- templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
- GetIntValue,
- SetIntValue,
- v8::External::New(&bar));
- templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
- GetIntValue,
- SetIntValue,
- v8::External::New(&baz));
- LocalContext env(0, templ->InstanceTemplate());
- v8_compile("foo = (++bar) + baz")->Run();
- CHECK_EQ(bar, -3);
- CHECK_EQ(foo, 7);
-}
-
-
THREADED_TEST(ObjectTemplate) {
v8::HandleScope scope;
Local<ObjectTemplate> templ1 = ObjectTemplate::New();
@@ -1362,50 +1173,6 @@
}
-static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- return v8::ThrowException(v8_str("g"));
-}
-
-
-static void ThrowingSetAccessor(Local<String> name,
- Local<Value> value,
- const AccessorInfo& info) {
- v8::ThrowException(value);
-}
-
-
-THREADED_TEST(Regress1054726) {
- v8::HandleScope scope;
- v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
- obj->SetAccessor(v8_str("x"),
- ThrowingGetAccessor,
- ThrowingSetAccessor,
- Local<Value>());
-
- LocalContext env;
- env->Global()->Set(v8_str("obj"), obj->NewInstance());
-
- // Use the throwing property setter/getter in a loop to force
- // the accessor ICs to be initialized.
- v8::Handle<Value> result;
- result = Script::Compile(v8_str(
- "var result = '';"
- "for (var i = 0; i < 5; i++) {"
- " try { obj.x; } catch (e) { result += e; }"
- "}; result"))->Run();
- CHECK_EQ(v8_str("ggggg"), result);
-
- result = Script::Compile(String::New(
- "var result = '';"
- "for (var i = 0; i < 5; i++) {"
- " try { obj.x = i; } catch (e) { result += e; }"
- "}; result"))->Run();
- CHECK_EQ(v8_str("01234"), result);
-}
-
-
THREADED_TEST(FunctionPrototype) {
v8::HandleScope scope;
Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
@@ -3181,53 +2948,6 @@
}
-static int x_register = 0;
-static v8::Handle<v8::Object> x_receiver;
-static v8::Handle<v8::Object> x_holder;
-
-
-static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- CHECK_EQ(x_receiver, info.This());
- CHECK_EQ(x_holder, info.Holder());
- return v8_num(x_register);
-}
-
-
-static void XSetter(Local<String> name,
- Local<Value> value,
- const AccessorInfo& info) {
- CHECK_EQ(x_holder, info.This());
- CHECK_EQ(x_holder, info.Holder());
- x_register = value->Int32Value();
-}
-
-
-THREADED_TEST(AccessorIC) {
- v8::HandleScope scope;
- v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
- obj->SetAccessor(v8_str("x"), XGetter, XSetter);
- LocalContext context;
- x_holder = obj->NewInstance();
- context->Global()->Set(v8_str("holder"), x_holder);
- x_receiver = v8::Object::New();
- context->Global()->Set(v8_str("obj"), x_receiver);
- v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
- "obj.__proto__ = holder;"
- "var result = [];"
- "for (var i = 0; i < 10; i++) {"
- " holder.x = i;"
- " result.push(obj.x);"
- "}"
- "result"));
- CHECK_EQ(10, array->Length());
- for (int i = 0; i < 10; i++) {
- v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
- CHECK_EQ(v8::Integer::New(i), entry);
- }
-}
-
-
static v8::Handle<Value> NoBlockGetterX(Local<String> name,
const AccessorInfo&) {
return v8::Handle<Value>();
@@ -6091,13 +5811,17 @@
// not start immediately.
bool ApiTestFuzzer::NextThread() {
int test_position = GetNextTestNumber();
- int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
+ const char* test_name = RegisterThreadedTest::nth(current_)->name();
if (test_position == current_) {
- printf("Stay with %d\n", test_number);
+ if (kLogThreading)
+ printf("Stay with %s\n", test_name);
return false;
}
- printf("Switch from %d to %d\n",
- current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
+ if (kLogThreading) {
+ printf("Switch from %s to %s\n",
+ test_name,
+ RegisterThreadedTest::nth(test_position)->name());
+ }
current_ = test_position;
RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
return true;
@@ -6206,9 +5930,11 @@
void ApiTestFuzzer::CallTest() {
- printf("Start test %d\n", test_number_);
+ if (kLogThreading)
+ printf("Start test %d\n", test_number_);
CallTestNumber(test_number_);
- printf("End test %d\n", test_number_);
+ if (kLogThreading)
+ printf("End test %d\n", test_number_);
}
@@ -6696,53 +6422,6 @@
}
-static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
- Local<String> name,
- const AccessorInfo& info) {
- ApiTestFuzzer::Fuzz();
- return v8::True();
-}
-
-
-THREADED_TEST(AccessorProhibitsOverwriting) {
- v8::HandleScope scope;
- LocalContext context;
- Local<ObjectTemplate> templ = ObjectTemplate::New();
- templ->SetAccessor(v8_str("x"),
- AccessorProhibitsOverwritingGetter,
- 0,
- v8::Handle<Value>(),
- v8::PROHIBITS_OVERWRITING,
- v8::ReadOnly);
- Local<v8::Object> instance = templ->NewInstance();
- context->Global()->Set(v8_str("obj"), instance);
- Local<Value> value = CompileRun(
- "obj.__defineGetter__('x', function() { return false; });"
- "obj.x");
- CHECK(value->BooleanValue());
- value = CompileRun(
- "var setter_called = false;"
- "obj.__defineSetter__('x', function() { setter_called = true; });"
- "obj.x = 42;"
- "setter_called");
- CHECK(!value->BooleanValue());
- value = CompileRun(
- "obj2 = {};"
- "obj2.__proto__ = obj;"
- "obj2.__defineGetter__('x', function() { return false; });"
- "obj2.x");
- CHECK(value->BooleanValue());
- value = CompileRun(
- "var setter_called = false;"
- "obj2 = {};"
- "obj2.__proto__ = obj;"
- "obj2.__defineSetter__('x', function() { setter_called = true; });"
- "obj2.x = 42;"
- "setter_called");
- CHECK(!value->BooleanValue());
-}
-
-
static bool NamedSetAccessBlocker(Local<v8::Object> obj,
Local<Value> name,
v8::AccessType type,
@@ -7279,7 +6958,7 @@
CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
string->map() == i::Heap::medium_external_ascii_string_map());
// Morph external string to be TwoByte string.
- if (string->length() <= i::String::kMaxShortStringSize) {
+ if (string->length() <= i::String::kMaxShortSize) {
string->set_map(i::Heap::short_external_string_map());
} else {
string->set_map(i::Heap::medium_external_string_map());
@@ -7292,7 +6971,7 @@
CHECK(string->map() == i::Heap::short_external_string_map() ||
string->map() == i::Heap::medium_external_string_map());
// Morph external string to be ASCII string.
- if (string->length() <= i::String::kMaxShortStringSize) {
+ if (string->length() <= i::String::kMaxShortSize) {
string->set_map(i::Heap::short_external_ascii_string_map());
} else {
string->set_map(i::Heap::medium_external_ascii_string_map());
@@ -8039,6 +7718,333 @@
}
+template <class ExternalArrayClass, class ElementType>
+static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
+ int64_t low,
+ int64_t high) {
+ v8::HandleScope scope;
+ LocalContext context;
+ const int kElementCount = 40;
+ int element_size = 0;
+ switch (array_type) {
+ case v8::kExternalByteArray:
+ case v8::kExternalUnsignedByteArray:
+ element_size = 1;
+ break;
+ case v8::kExternalShortArray:
+ case v8::kExternalUnsignedShortArray:
+ element_size = 2;
+ break;
+ case v8::kExternalIntArray:
+ case v8::kExternalUnsignedIntArray:
+ case v8::kExternalFloatArray:
+ element_size = 4;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ ElementType* array_data =
+ static_cast<ElementType*>(malloc(kElementCount * element_size));
+ i::Handle<ExternalArrayClass> array =
+ i::Handle<ExternalArrayClass>::cast(
+ i::Factory::NewExternalArray(kElementCount, array_type, array_data));
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ array->set(i, static_cast<ElementType>(i));
+ }
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ for (int i = 0; i < kElementCount; i++) {
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
+ }
+
+ v8::Handle<v8::Object> obj = v8::Object::New();
+ i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
+ // Set the elements to be the external array.
+ obj->SetIndexedPropertiesToExternalArrayData(array_data,
+ array_type,
+ kElementCount);
+ CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
+ obj->Set(v8_str("field"), v8::Int32::New(1503));
+ context->Global()->Set(v8_str("ext_array"), obj);
+ v8::Handle<v8::Value> result = CompileRun("ext_array.field");
+ CHECK_EQ(1503, result->Int32Value());
+ result = CompileRun("ext_array[1]");
+ CHECK_EQ(1, result->Int32Value());
+
+ // Check pass through of assigned smis
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i] = ext_array[i] = -i;"
+ "}"
+ "sum;");
+ CHECK_EQ(-28, result->Int32Value());
+
+ // Check assigned smis
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check assigned smis in reverse order
+ result = CompileRun("for (var i = 8; --i >= 0; ) {"
+ " ext_array[i] = i;"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check pass through of assigned HeapNumbers
+ result = CompileRun("var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
+ "}"
+ "sum;");
+ CHECK_EQ(-28, result->Int32Value());
+
+ // Check assigned HeapNumbers
+ result = CompileRun("for (var i = 0; i < 16; i+=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ // Check assigned HeapNumbers in reverse order
+ result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
+ " ext_array[i] = (i * 0.5);"
+ "}"
+ "var sum = 0;"
+ "for (var i = 0; i < 16; i+=2) {"
+ " sum += ext_array[i];"
+ "}"
+ "sum;");
+ CHECK_EQ(28, result->Int32Value());
+
+ i::ScopedVector<char> test_buf(1024);
+
+ // Check legal boundary conditions.
+ // The repeated loads and stores ensure the ICs are exercised.
+ const char* boundary_program =
+ "var res = 0;"
+ "for (var i = 0; i < 16; i++) {"
+ " ext_array[i] = %lld;"
+ " if (i > 8) {"
+ " res = ext_array[i];"
+ " }"
+ "}"
+ "res;";
+ i::OS::SNPrintF(test_buf,
+ boundary_program,
+ low);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(low, result->IntegerValue());
+
+ i::OS::SNPrintF(test_buf,
+ boundary_program,
+ high);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(high, result->IntegerValue());
+
+ // Check misprediction of type in IC.
+ result = CompileRun("var tmp_array = ext_array;"
+ "var sum = 0;"
+ "for (var i = 0; i < 8; i++) {"
+ " tmp_array[i] = i;"
+ " sum += tmp_array[i];"
+ " if (i == 4) {"
+ " tmp_array = {};"
+ " }"
+ "}"
+ "sum;");
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
+ CHECK_EQ(28, result->Int32Value());
+
+ // Make sure out-of-range loads do not throw.
+ i::OS::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d];"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ kElementCount);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(false, result->BooleanValue());
+
+ // Make sure out-of-range stores do not throw.
+ i::OS::SNPrintF(test_buf,
+ "var caught_exception = false;"
+ "try {"
+ " ext_array[%d] = 1;"
+ "} catch (e) {"
+ " caught_exception = true;"
+ "}"
+ "caught_exception;",
+ kElementCount);
+ result = CompileRun(test_buf.start());
+ CHECK_EQ(false, result->BooleanValue());
+
+ // Check other boundary conditions, values and operations.
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[7] = undefined;"
+ "}"
+ "ext_array[7];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[6] = '2.3';"
+ "}"
+ "ext_array[6];");
+ CHECK_EQ(2, result->Int32Value());
+ CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
+
+ if (array_type != v8::kExternalFloatArray) {
+ // Though the specification doesn't state it, be explicit about
+ // converting NaNs and +/-Infinity to zero.
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = NaN;"
+ "}"
+ "ext_array[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = Infinity;"
+ "}"
+ "ext_array[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
+
+ result = CompileRun("for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = 5;"
+ "}"
+ "for (var i = 0; i < 8; i++) {"
+ " ext_array[i] = -Infinity;"
+ "}"
+ "ext_array[5];");
+ CHECK_EQ(0, result->Int32Value());
+ CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
+ }
+
+ result = CompileRun("ext_array[3] = 33;"
+ "delete ext_array[3];"
+ "ext_array[3];");
+ CHECK_EQ(33, result->Int32Value());
+
+ result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
+ "ext_array[2] = 12; ext_array[3] = 13;"
+ "ext_array.__defineGetter__('2',"
+ "function() { return 120; });"
+ "ext_array[2];");
+ CHECK_EQ(12, result->Int32Value());
+
+ result = CompileRun("var js_array = new Array(40);"
+ "js_array[0] = 77;"
+ "js_array;");
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+
+ result = CompileRun("ext_array[1] = 23;"
+ "ext_array.__proto__ = [];"
+ "js_array.__proto__ = ext_array;"
+ "js_array.concat(ext_array);");
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
+ CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
+
+ result = CompileRun("ext_array[1] = 23;");
+ CHECK_EQ(23, result->Int32Value());
+
+ free(array_data);
+}
+
+
+THREADED_TEST(ExternalByteArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
+ v8::kExternalByteArray,
+ -128,
+ 127);
+}
+
+
+THREADED_TEST(ExternalUnsignedByteArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
+ v8::kExternalUnsignedByteArray,
+ 0,
+ 255);
+}
+
+
+THREADED_TEST(ExternalShortArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
+ v8::kExternalShortArray,
+ -32768,
+ 32767);
+}
+
+
+THREADED_TEST(ExternalUnsignedShortArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
+ v8::kExternalUnsignedShortArray,
+ 0,
+ 65535);
+}
+
+
+THREADED_TEST(ExternalIntArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
+ v8::kExternalIntArray,
+ INT_MIN, // -2147483648
+ INT_MAX); // 2147483647
+}
+
+
+THREADED_TEST(ExternalUnsignedIntArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
+ v8::kExternalUnsignedIntArray,
+ 0,
+ UINT_MAX); // 4294967295
+}
+
+
+THREADED_TEST(ExternalFloatArray) {
+ ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
+ v8::kExternalFloatArray,
+ -500,
+ 500);
+}
+
+
+THREADED_TEST(ExternalArrays) {
+ TestExternalByteArray();
+ TestExternalUnsignedByteArray();
+ TestExternalShortArray();
+ TestExternalUnsignedShortArray();
+ TestExternalIntArray();
+ TestExternalUnsignedIntArray();
+ TestExternalFloatArray();
+}
+
+
THREADED_TEST(ScriptContextDependence) {
v8::HandleScope scope;
LocalContext c1;
@@ -8153,3 +8159,130 @@
CHECK(stack_limit == set_limit);
}
}
+
+
+THREADED_TEST(GetHeapStatistics) {
+ v8::HandleScope scope;
+ LocalContext c1;
+ v8::HeapStatistics heap_statistics;
+ CHECK_EQ(heap_statistics.total_heap_size(), 0);
+ CHECK_EQ(heap_statistics.used_heap_size(), 0);
+ v8::V8::GetHeapStatistics(&heap_statistics);
+ CHECK_NE(heap_statistics.total_heap_size(), 0);
+ CHECK_NE(heap_statistics.used_heap_size(), 0);
+}
+
+
+static double DoubleFromBits(uint64_t value) {
+ double target;
+#ifdef BIG_ENDIAN_FLOATING_POINT
+ const int kIntSize = 4;
+ // Somebody swapped the lower and higher half of doubles.
+ memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
+ memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
+#else
+ memcpy(&target, &value, sizeof(target));
+#endif
+ return target;
+}
+
+
+static uint64_t DoubleToBits(double value) {
+ uint64_t target;
+#ifdef BIG_ENDIAN_FLOATING_POINT
+ const int kIntSize = 4;
+ // Somebody swapped the lower and higher half of doubles.
+ memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
+ memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
+#else
+ memcpy(&target, &value, sizeof(target));
+#endif
+ return target;
+}
+
+
+static double DoubleToDateTime(double input) {
+ double date_limit = 864e13;
+ if (IsNaN(input) || input < -date_limit || input > date_limit) {
+ return i::OS::nan_value();
+ }
+ return (input < 0) ? -(floor(-input)) : floor(input);
+}
+
+// We don't have a consistent way to write 64-bit constants syntactically, so we
+// split them into two 32-bit constants and combine them programmatically.
+static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
+ return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
+}
+
+
+THREADED_TEST(QuietSignalingNaNs) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8::TryCatch try_catch;
+
+ // Special double values.
+ double snan = DoubleFromBits(0x7ff00000, 0x00000001);
+ double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
+ double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
+ double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
+ double min_normal = DoubleFromBits(0x00100000, 0x00000000);
+ double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
+ double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
+
+ // Date values are capped at +/-100000000 days (times 864e5 ms per day)
+ // on either side of the epoch.
+ double date_limit = 864e13;
+
+ double test_values[] = {
+ snan,
+ qnan,
+ infinity,
+ max_normal,
+ date_limit + 1,
+ date_limit,
+ min_normal,
+ max_denormal,
+ min_denormal,
+ 0,
+ -0,
+ -min_denormal,
+ -max_denormal,
+ -min_normal,
+ -date_limit,
+ -date_limit - 1,
+ -max_normal,
+ -infinity,
+ -qnan,
+ -snan
+ };
+ int num_test_values = 20;
+
+ for (int i = 0; i < num_test_values; i++) {
+ double test_value = test_values[i];
+
+ // Check that Number::New preserves non-NaNs and quiets SNaNs.
+ v8::Handle<v8::Value> number = v8::Number::New(test_value);
+ double stored_number = number->NumberValue();
+ if (!IsNaN(test_value)) {
+ CHECK_EQ(test_value, stored_number);
+ } else {
+ uint64_t stored_bits = DoubleToBits(stored_number);
+ // Check if quiet nan (bits 51..62 all set).
+ CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
+ }
+
+ // Check that Date::New preserves non-NaNs in the date range and
+ // quiets SNaNs.
+ v8::Handle<v8::Value> date = v8::Date::New(test_value);
+ double expected_stored_date = DoubleToDateTime(test_value);
+ double stored_date = date->NumberValue();
+ if (!IsNaN(expected_stored_date)) {
+ CHECK_EQ(expected_stored_date, stored_date);
+ } else {
+ uint64_t stored_bits = DoubleToBits(stored_date);
+ // Check if quiet nan (bits 51..62 all set).
+ CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
+ }
+ }
+}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 4ffcee3..656a456 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -178,12 +178,6 @@
}
-// Helper function that compiles and runs the source.
-static v8::Local<v8::Value> CompileRun(const char* source) {
- return v8::Script::Compile(v8::String::New(source))->Run();
-}
-
-
// Is there any debug info for the function?
static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 43df6ba..68cbc26 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -163,11 +163,6 @@
}
-static void CompileRun(const char* source) {
- Script::Compile(String::New(source))->Run();
-}
-
-
v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
const v8::Arguments& args) {
v8::HandleScope scope;
@@ -329,17 +324,16 @@
}
-static void CFuncDoTrace() {
+static void CFuncDoTrace(byte dummy_parameter) {
Address fp;
#ifdef __GNUC__
fp = reinterpret_cast<Address>(__builtin_frame_address(0));
-#elif defined _MSC_VER && defined V8_TARGET_ARCH_IA32
- __asm mov [fp], ebp // NOLINT
-#elif defined _MSC_VER && defined V8_TARGET_ARCH_X64
- // TODO(X64): __asm extension is not supported by the Microsoft Visual C++
- // 64-bit compiler.
- fp = 0;
- UNIMPLEMENTED();
+#elif defined _MSC_VER
+ // Approximate a frame pointer address. We compile without base pointers,
+ // so we can't trust ebp/rbp.
+ fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT
+#else
+#error Unexpected platform.
#endif
DoTrace(fp);
}
@@ -347,7 +341,7 @@
static int CFunc(int depth) {
if (depth <= 0) {
- CFuncDoTrace();
+ CFuncDoTrace(0);
return 0;
} else {
return CFunc(depth - 1) + 1;
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 3983215..b1cb63c 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -256,11 +256,10 @@
// No sampling should happen prior to resuming profiler.
CHECK(!LoggerTestHelper::IsSamplerActive());
- // Read initial logged data (static libs map).
EmbeddedVector<char, 102400> buffer;
+ // Nothing must be logged until profiling is resumed.
int log_pos = GetLogLines(0, &buffer);
- CHECK_GT(log_pos, 0);
- CHECK_GT(buffer.length(), log_pos);
+ CHECK_EQ(0, log_pos);
CompileAndRunScript("var a = (function(x) { return x + 1; })(10);");
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
index 9c1197f..f344ac8 100755
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -57,7 +57,7 @@
using v8::internal::r8;
using v8::internal::r9;
using v8::internal::r11;
-using v8::internal::r12;
+using v8::internal::r12; // Remember: r12..r15 are callee save!
using v8::internal::r13;
using v8::internal::r14;
using v8::internal::r15;
@@ -1144,6 +1144,8 @@
masm->set_allow_stub_calls(false);
Label exit;
+ __ push(r12);
+ __ push(r15);
TestSmiDiv(masm, &exit, 0x10, 1, 1);
TestSmiDiv(masm, &exit, 0x20, 1, 0);
TestSmiDiv(masm, &exit, 0x30, -1, 0);
@@ -1168,6 +1170,8 @@
__ xor_(r15, r15); // Success.
__ bind(&exit);
__ movq(rax, r15);
+ __ pop(r15);
+ __ pop(r12);
__ ret(0);
CodeDesc desc;
@@ -1247,6 +1251,8 @@
masm->set_allow_stub_calls(false);
Label exit;
+ __ push(r12);
+ __ push(r15);
TestSmiMod(masm, &exit, 0x10, 1, 1);
TestSmiMod(masm, &exit, 0x20, 1, 0);
TestSmiMod(masm, &exit, 0x30, -1, 0);
@@ -1271,6 +1277,8 @@
__ xor_(r15, r15); // Success.
__ bind(&exit);
__ movq(rax, r15);
+ __ pop(r15);
+ __ pop(r12);
__ ret(0);
CodeDesc desc;
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 743375d..e56f0f4 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -71,10 +71,6 @@
TEST(Promotion) {
- // Test the situation that some objects in new space are promoted to the
- // old space
- if (Snapshot::IsEnabled()) return;
-
// Ensure that we get a compacting collection so that objects are promoted
// from new space.
FLAG_gc_global = true;
@@ -106,7 +102,6 @@
TEST(NoPromotion) {
- if (Snapshot::IsEnabled()) return;
Heap::ConfigureHeap(2*256*KB, 4*MB);
// Test the situation that some objects in new space are promoted to
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index 6939a80..01e0715 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -185,6 +185,18 @@
}
+static void Serialize2() {
+ Serializer::Enable();
+ // We have to create one context. One reason for this is so that the builtins
+ // can be loaded from v8natives.js and their addresses can be processed. This
+ // will clear the pending fixups array, which would otherwise contain GC roots
+ // that would confuse the serialization/deserialization process.
+ v8::Persistent<v8::Context> env = v8::Context::New();
+ env.Dispose();
+ Snapshot::WriteToFile2(FLAG_testing_serialization_file);
+}
+
+
// Test that the whole heap can be serialized when running from the
// internal snapshot.
// (Smoke test.)
@@ -203,6 +215,13 @@
}
+// Test that the whole heap can be serialized.
+TEST(Serialize2) {
+ v8::V8::Initialize();
+ Serialize2();
+}
+
+
// Test that the heap isn't destroyed after a serialization.
TEST(SerializeNondestructive) {
if (Snapshot::IsEnabled()) return;
@@ -230,6 +249,11 @@
}
+static void Deserialize2() {
+ CHECK(Snapshot::Initialize2(FLAG_testing_serialization_file));
+}
+
+
static void SanityCheck() {
v8::HandleScope scope;
#ifdef DEBUG
@@ -251,6 +275,21 @@
SanityCheck();
}
+
+DEPENDENT_TEST(Deserialize2, Serialize2) {
+ v8::HandleScope scope;
+
+ Deserialize2();
+
+ fflush(stdout);
+
+ v8::Persistent<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ SanityCheck();
+}
+
+
DEPENDENT_TEST(DeserializeAndRunScript, Serialize) {
v8::HandleScope scope;
@@ -263,6 +302,21 @@
}
+DEPENDENT_TEST(DeserializeAndRunScript2, Serialize2) {
+ v8::HandleScope scope;
+
+ Deserialize2();
+
+ v8::Persistent<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ const char* c_source = "\"1234\".length";
+ v8::Local<v8::String> source = v8::String::New(c_source);
+ v8::Local<v8::Script> script = v8::Script::Compile(source);
+ CHECK_EQ(4, script->Run()->Int32Value());
+}
+
+
DEPENDENT_TEST(DeserializeNatives, Serialize) {
v8::HandleScope scope;
@@ -286,3 +340,19 @@
v8::Local<v8::Value> value = script->Run();
CHECK(value->IsUndefined());
}
+
+
+TEST(TestThatAlwaysSucceeds) {
+}
+
+
+TEST(TestThatAlwaysFails) {
+ bool ArtificialFailure = false;
+ CHECK(ArtificialFailure);
+}
+
+
+DEPENDENT_TEST(DependentTestThatAlwaysFails, TestThatAlwaysSucceeds) {
+ bool ArtificialFailure2 = false;
+ CHECK(ArtificialFailure2);
+}
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index d946a7f..1a26883 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -99,9 +99,9 @@
TEST(MemoryAllocator) {
CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+ CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
- OldSpace faked_space(Heap::MaxCapacity(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
+ OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
int total_pages = 0;
int requested = 2;
int allocated;
@@ -155,16 +155,16 @@
TEST(NewSpace) {
CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+ CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
NewSpace new_space;
void* chunk =
- MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
+ MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = RoundUp(static_cast<Address>(chunk),
- Heap::YoungGenerationSize());
- CHECK(new_space.Setup(start, Heap::YoungGenerationSize()));
+ 2 * Heap::ReservedSemiSpaceSize());
+ CHECK(new_space.Setup(start, 2 * Heap::ReservedSemiSpaceSize()));
CHECK(new_space.HasBeenSetup());
while (new_space.Available() >= Page::kMaxHeapObjectSize) {
@@ -180,18 +180,18 @@
TEST(OldSpace) {
CHECK(Heap::ConfigureHeapDefault());
- CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
+ CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
- OldSpace* s = new OldSpace(Heap::OldGenerationSize(),
+ OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
OLD_POINTER_SPACE,
NOT_EXECUTABLE);
CHECK(s != NULL);
void* chunk =
- MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
+ MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = static_cast<Address>(chunk);
- size_t size = RoundUp(start, Heap::YoungGenerationSize()) - start;
+ size_t size = RoundUp(start, 2 * Heap::ReservedSemiSpaceSize()) - start;
CHECK(s->Setup(start, size));
diff --git a/test/mjsunit/compiler/globals.js b/test/mjsunit/compiler/globals.js
new file mode 100644
index 0000000..066f927
--- /dev/null
+++ b/test/mjsunit/compiler/globals.js
@@ -0,0 +1,55 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test references and assignments to global variables.
+var g = 0;
+
+// Test compilation of a global variable store.
+assertEquals(1, eval('g = 1'));
+// Test that the store worked.
+assertEquals(1, g);
+
+// Test that patching the IC in the compiled code works.
+assertEquals(1, eval('g = 1'));
+assertEquals(1, g);
+assertEquals(1, eval('g = 1'));
+assertEquals(1, g);
+
+// Test a second store.
+assertEquals("2", eval('g = "2"'));
+assertEquals("2", g);
+
+// Test a load.
+assertEquals("2", eval('g'));
+
+// Test that patching the IC in the compiled code works.
+assertEquals("2", eval('g'));
+assertEquals("2", eval('g'));
+
+// Test a second load.
+g = 3;
+assertEquals(3, eval('g'));
diff --git a/test/mjsunit/compiler/literals-assignment.js b/test/mjsunit/compiler/literals-assignment.js
index 932bfa7..d2996c7 100644
--- a/test/mjsunit/compiler/literals-assignment.js
+++ b/test/mjsunit/compiler/literals-assignment.js
@@ -69,3 +69,36 @@
})()";
assertEquals(8, eval(code));
+// Test object literals.
+var a, b;
+code = "a = {x:8}";
+eval(code);
+assertEquals(8, a.x);
+
+code = "b = {x:a, y:'abc'}";
+eval(code);
+assertEquals(a, b.x);
+assertEquals(8, b.x.x);
+assertEquals("abc", b.y);
+
+code = "({x:8, y:9}); 10";
+assertEquals(10, eval(code));
+
+code = "({x:8, y:9})";
+eval(code);
+assertEquals(9, eval(code+".y"));
+
+code = "a = {2:8, x:9}";
+eval(code);
+assertEquals(8, a[2]);
+assertEquals(8, a["2"]);
+assertEquals(9, a["x"]);
+
+// Test regexp literals.
+
+a = /abc/;
+
+assertEquals(/abc/, a);
+
+code = "/abc/; 8";
+assertEquals(8, eval(code));
diff --git a/test/mjsunit/compiler/literals.js b/test/mjsunit/compiler/literals.js
index e0e532f..6775401 100644
--- a/test/mjsunit/compiler/literals.js
+++ b/test/mjsunit/compiler/literals.js
@@ -33,3 +33,20 @@
assertEquals("abc", eval("'abc'"));
assertEquals(8, eval("6;'abc';8"));
+
+// Test some materialized array literals.
+assertEquals([1,2,3,4], eval('[1,2,3,4]'));
+assertEquals([[1,2],3,4], eval('[[1,2],3,4]'));
+assertEquals([1,[2,3,4]], eval('[1,[2,3,4]]'));
+
+assertEquals([1,2,3,4], eval('var a=1, b=2; [a,b,3,4]'))
+assertEquals([1,2,3,4], eval('var a=1, b=2, c = [a,b,3,4]; c'));
+
+function double(x) { return x + x; }
+var s = 'var a = 1, b = 2; [double(a), double(b), double(3), double(4)]';
+assertEquals([2,4,6,8], eval(s));
+
+// Test array literals in effect context.
+assertEquals(17, eval('[1,2,3,4]; 17'));
+assertEquals(19, eval('var a=1, b=2; [a,b,3,4]; 19'));
+assertEquals(23, eval('var a=1, b=2; c=23; [a,b,3,4]; c'));
diff --git a/test/mjsunit/compiler/property-simple.js b/test/mjsunit/compiler/property-simple.js
new file mode 100644
index 0000000..b0f0ffa
--- /dev/null
+++ b/test/mjsunit/compiler/property-simple.js
@@ -0,0 +1,39 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test for property access
+
+var a;
+var b;
+
+code = "a = {x:8, y:9}; a.x";
+
+assertEquals(8, eval(code));
+
+code = "b = {z:a}; b.z.y";
+
+assertEquals(9, eval(code));
diff --git a/test/mjsunit/debug-version.js b/test/mjsunit/debug-version.js
new file mode 100644
index 0000000..b1bc1e8
--- /dev/null
+++ b/test/mjsunit/debug-version.js
@@ -0,0 +1,90 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_version_request = '"seq":0,"type":"request","command":"version"'
+
+function safeEval(code) {
+ try {
+ return eval('(' + code + ')');
+ } catch (e) {
+ assertEquals(void 0, e);
+ return undefined;
+ }
+}
+
+function testArguments(exec_state) {
+ // Get the debug command processor in running state.
+ var dcp = exec_state.debugCommandProcessor(true);
+
+ assertTrue(dcp.isRunning());
+
+ var version_request = '{' + base_version_request + '}'
+ var version_response = safeEval(dcp.processDebugJSONRequest(version_request));
+
+ assertTrue(version_response.success);
+
+ var version_string = version_response.body.V8Version;
+
+ assertTrue(!!version_string, version_request + ' -> expected version string');
+
+ var version_pattern = /^\d*\.\d*\.\d*/;
+
+ assertTrue(!!(version_string.match(version_pattern)), "unexpected format of version: " + version_string);
+}
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+
+ // Test simple suspend request.
+ testArguments(exec_state);
+
+ // Indicate that all was processed.
+ listenerComplete = true;
+ }
+ } catch (e) {
+ exception = e
+ };
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+// Stop debugger and check that suspend command changes running flag.
+debugger;
+
+assertFalse(exception, "exception in listener")
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
diff --git a/test/mjsunit/div-mod.js b/test/mjsunit/div-mod.js
index a8a19b3..b3c77e1 100644
--- a/test/mjsunit/div-mod.js
+++ b/test/mjsunit/div-mod.js
@@ -86,3 +86,72 @@
for (var i = 0; i < divisors.length; i++) {
run_tests_for(divisors[i]);
}
+
+// Test extreme corner cases of modulo.
+
+// Computes the modulo by slow but lossless operations.
+function compute_mod(dividend, divisor) {
+ // Return NaN if either operand is NaN, if divisor is 0 or
+ // dividend is an infinity. Return dividend if divisor is an infinity.
+ if (isNaN(dividend) || isNaN(divisor) || divisor == 0) { return NaN; }
+ var sign = 1;
+ if (dividend < 0) { dividend = -dividend; sign = -1; }
+ if (dividend == Infinity) { return NaN; }
+ if (divisor < 0) { divisor = -divisor; }
+ if (divisor == Infinity) { return sign * dividend; }
+ function rec_mod(a, b) {
+ // Subtracts maximal possible multiplum of b from a.
+ if (a >= b) {
+ a = rec_mod(a, 2 * b);
+ if (a >= b) { a -= b; }
+ }
+ return a;
+ }
+ return sign * rec_mod(dividend, divisor);
+}
+
+(function () {
+ var large_non_smi = 1234567891234.12245;
+ var small_non_smi = 43.2367243;
+ var repeating_decimal = 0.3;
+ var finite_decimal = 0.5;
+ var smi = 43;
+ var power_of_two = 64;
+ var min_normal = Number.MIN_VALUE * Math.pow(2, 52);
+ var max_denormal = Number.MIN_VALUE * (Math.pow(2, 52) - 1);
+
+ // All combinations of NaN, Infinity, normal, denormal and zero.
+ var example_numbers = [
+ NaN,
+ 0,
+ Number.MIN_VALUE,
+ 3 * Number.MIN_VALUE,
+ max_denormal,
+ min_normal,
+ repeating_decimal,
+ finite_decimal,
+ smi,
+ power_of_two,
+ small_non_smi,
+ large_non_smi,
+ Number.MAX_VALUE,
+ Infinity
+ ];
+
+ function doTest(a, b) {
+ var exp = compute_mod(a, b);
+ var act = a % b;
+ assertEquals(exp, act, a + " % " + b);
+ }
+
+ for (var i = 0; i < example_numbers.length; i++) {
+ for (var j = 0; j < example_numbers.length; j++) {
+ var a = example_numbers[i];
+ var b = example_numbers[j];
+ doTest(a,b);
+ doTest(-a,b);
+ doTest(a,-b);
+ doTest(-a,-b);
+ }
+ }
+})()
diff --git a/test/mjsunit/fuzz-natives.js b/test/mjsunit/fuzz-natives.js
index c653b18..f495c72 100644
--- a/test/mjsunit/fuzz-natives.js
+++ b/test/mjsunit/fuzz-natives.js
@@ -127,8 +127,11 @@
"IS_VAR": true,
"ResolvePossiblyDirectEval": true,
"Log": true,
+ "DeclareGlobals": true,
- "CollectStackTrace": true
+ "CollectStackTrace": true,
+ "PromoteScheduledException": true,
+ "DeleteHandleScopeExtensions": true
};
var currentlyUncallable = {
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 0b069cc..15f62b0 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -36,6 +36,9 @@
big-object-literal: PASS, SKIP if ($arch == arm)
+# Issue 488: this test sometimes times out.
+array-constructor: PASS || TIMEOUT
+
[ $arch == arm ]
# Slow tests which times out in debug mode.
diff --git a/test/mjsunit/regress/regress-485.js b/test/mjsunit/regress/regress-485.js
new file mode 100644
index 0000000..62c6fb9
--- /dev/null
+++ b/test/mjsunit/regress/regress-485.js
@@ -0,0 +1,64 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// See: http://code.google.com/p/v8/issues/detail?id=485
+
+// Ensure that we don't expose the builtins object when calling
+// builtin functions that use or return "this".
+
+var global = this;
+var global2 = (function(){return this;})();
+assertEquals(global, global2, "direct call to local function returns global");
+
+var builtin = Object.prototype.valueOf; // Builtin function that returns this.
+
+assertEquals(global, builtin(), "Direct call to builtin");
+
+assertEquals(global, builtin.call(), "call() to builtin");
+assertEquals(global, builtin.call(null), "call(null) to builtin");
+assertEquals(global, builtin.call(undefined), "call(undefined) to builtin");
+
+assertEquals(global, builtin.apply(), "apply() to builtin");
+assertEquals(global, builtin.apply(null), "apply(null) to builtin");
+assertEquals(global, builtin.apply(undefined), "apply(undefined) to builtin");
+
+assertEquals(global, builtin.call.call(builtin), "call.call() to builtin");
+assertEquals(global, builtin.call.apply(builtin), "call.apply() to builtin");
+assertEquals(global, builtin.apply.call(builtin), "apply.call() to builtin");
+assertEquals(global, builtin.apply.apply(builtin), "apply.apply() to builtin");
+
+
+// Builtin that depends on value of this to compute result.
+var builtin2 = Object.prototype.toString;
+
+// Global object has class "Object" according to Object.prototype.toString.
+// Builtins object displays as "[object builtins]".
+assertTrue("[object builtins]" != builtin2(), "Direct call to toString");
+assertTrue("[object builtins]" != builtin2.call(), "call() to toString");
+assertTrue("[object builtins]" != builtin2.apply(), "call() to toString");
+assertTrue("[object builtins]" != builtin2.call.call(builtin2),
+ "call.call() to toString");