Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index e2a7fb1856c7c97398fa8e932652fbd275b295bf..ab94085a95f0da53624a80c4b0edede4310bfb00 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -30,6 +30,7 @@ |
#include "v8.h" |
#include "api.h" |
+#include "isolate.h" |
#include "compilation-cache.h" |
#include "execution.h" |
#include "snapshot.h" |
@@ -6746,6 +6747,200 @@ THREADED_TEST(Constructor) { |
CHECK(value->BooleanValue()); |
} |
+ |
+static Handle<Value> ConstructorCallback(const Arguments& args) { |
+ ApiTestFuzzer::Fuzz(); |
+ Local<Object> This; |
+ |
+ if (args.IsConstructCall()) { |
+ Local<Object> Holder = args.Holder(); |
+ This = Object::New(); |
+ Local<Value> proto = Holder->GetPrototype(); |
+ if (proto->IsObject()) { |
+ This->SetPrototype(proto); |
+ } |
+ } else { |
+ This = args.This(); |
+ } |
+ |
+ This->Set(v8_str("a"), args[0]); |
+ return This; |
+} |
+ |
+ |
+static Handle<Value> FakeConstructorCallback(const Arguments& args) { |
+ ApiTestFuzzer::Fuzz(); |
+ return args[0]; |
+} |
+ |
+ |
+THREADED_TEST(ConstructorForObject) { |
+ v8::HandleScope handle_scope; |
+ LocalContext context; |
+ |
+ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); |
+ instance_template->SetCallAsFunctionHandler(ConstructorCallback); |
+ Local<Object> instance = instance_template->NewInstance(); |
+ context->Global()->Set(v8_str("obj"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ // Call the Object's constructor with a 32-bit signed integer. |
+ value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsInt32()); |
+ CHECK_EQ(28, value->Int32Value()); |
+ |
+ Local<Value> args1[] = { v8_num(28) }; |
+ Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); |
+ CHECK(value_obj1->IsObject()); |
+ Local<Object> object1 = Local<Object>::Cast(value_obj1); |
+ value = object1->Get(v8_str("a")); |
+ CHECK(value->IsInt32()); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(28, value->Int32Value()); |
+ |
+ // Call the Object's constructor with a String. |
+ value = CompileRun( |
+ "(function() { var o = new obj('tipli'); return o.a; })()"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsString()); |
+ String::AsciiValue string_value1(value->ToString()); |
+ CHECK_EQ("tipli", *string_value1); |
+ |
+ Local<Value> args2[] = { v8_str("tipli") }; |
+ Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); |
+ CHECK(value_obj2->IsObject()); |
+ Local<Object> object2 = Local<Object>::Cast(value_obj2); |
+ value = object2->Get(v8_str("a")); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsString()); |
+ String::AsciiValue string_value2(value->ToString()); |
+ CHECK_EQ("tipli", *string_value2); |
+ |
+ // Call the Object's constructor with a Boolean. |
+ value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsBoolean()); |
+ CHECK_EQ(true, value->BooleanValue()); |
+ |
+ Handle<Value> args3[] = { v8::Boolean::New(true) }; |
+ Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); |
+ CHECK(value_obj3->IsObject()); |
+ Local<Object> object3 = Local<Object>::Cast(value_obj3); |
+ value = object3->Get(v8_str("a")); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsBoolean()); |
+ CHECK_EQ(true, value->BooleanValue()); |
+ |
+ // Call the Object's constructor with undefined. |
+ Handle<Value> args4[] = { v8::Undefined() }; |
+ Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); |
+ CHECK(value_obj4->IsObject()); |
+ Local<Object> object4 = Local<Object>::Cast(value_obj4); |
+ value = object4->Get(v8_str("a")); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsUndefined()); |
+ |
+ // Call the Object's constructor with null. |
+ Handle<Value> args5[] = { v8::Null() }; |
+ Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); |
+ CHECK(value_obj5->IsObject()); |
+ Local<Object> object5 = Local<Object>::Cast(value_obj5); |
+ value = object5->Get(v8_str("a")); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsNull()); |
+ } |
+ |
+ // Check exception handling when there is no constructor set for the Object. |
+ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); |
+ Local<Object> instance = instance_template->NewInstance(); |
+ context->Global()->Set(v8_str("obj2"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ value = CompileRun("new obj2(28)"); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value1(try_catch.Exception()); |
+ CHECK_EQ("TypeError: object is not a function", *exception_value1); |
+ try_catch.Reset(); |
+ |
+ Local<Value> args[] = { v8_num(29) }; |
+ value = instance->CallAsConstructor(1, args); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value2(try_catch.Exception()); |
+ CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); |
+ try_catch.Reset(); |
+ } |
+ |
+ // Check the case when constructor throws exception. |
+ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); |
+ instance_template->SetCallAsFunctionHandler(ThrowValue); |
+ Local<Object> instance = instance_template->NewInstance(); |
+ context->Global()->Set(v8_str("obj3"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ value = CompileRun("new obj3(22)"); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value1(try_catch.Exception()); |
+ CHECK_EQ("22", *exception_value1); |
+ try_catch.Reset(); |
+ |
+ Local<Value> args[] = { v8_num(23) }; |
+ value = instance->CallAsConstructor(1, args); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value2(try_catch.Exception()); |
+ CHECK_EQ("23", *exception_value2); |
+ try_catch.Reset(); |
+ } |
+ |
+ // Check whether constructor returns with an object or non-object. |
+ { Local<FunctionTemplate> function_template = |
+ FunctionTemplate::New(FakeConstructorCallback); |
+ Local<Function> function = function_template->GetFunction(); |
+ Local<Object> instance1 = function; |
+ context->Global()->Set(v8_str("obj4"), instance1); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ CHECK(instance1->IsObject()); |
+ CHECK(instance1->IsFunction()); |
+ |
+ value = CompileRun("new obj4(28)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsObject()); |
+ |
+ Local<Value> args1[] = { v8_num(28) }; |
+ value = instance1->CallAsConstructor(1, args1); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(value->IsObject()); |
+ |
+ Local<ObjectTemplate> instance_template = ObjectTemplate::New(); |
+ instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); |
+ Local<Object> instance2 = instance_template->NewInstance(); |
+ context->Global()->Set(v8_str("obj5"), instance2); |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ CHECK(instance2->IsObject()); |
+ CHECK(!instance2->IsFunction()); |
+ |
+ value = CompileRun("new obj5(28)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(!value->IsObject()); |
+ |
+ Local<Value> args2[] = { v8_num(28) }; |
+ value = instance2->CallAsConstructor(1, args2); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK(!value->IsObject()); |
+ } |
+} |
+ |
+ |
THREADED_TEST(FunctionDescriptorException) { |
v8::HandleScope handle_scope; |
LocalContext context; |
@@ -6962,50 +7157,110 @@ THREADED_TEST(CallAsFunction) { |
v8::HandleScope scope; |
LocalContext context; |
- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); |
- Local<ObjectTemplate> instance_template = t->InstanceTemplate(); |
- instance_template->SetCallAsFunctionHandler(call_as_function); |
- Local<v8::Object> instance = t->GetFunction()->NewInstance(); |
- context->Global()->Set(v8_str("obj"), instance); |
- v8::TryCatch try_catch; |
- Local<Value> value; |
- CHECK(!try_catch.HasCaught()); |
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); |
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); |
+ instance_template->SetCallAsFunctionHandler(call_as_function); |
+ Local<v8::Object> instance = t->GetFunction()->NewInstance(); |
+ context->Global()->Set(v8_str("obj"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
- value = CompileRun("obj(42)"); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(42, value->Int32Value()); |
+ value = CompileRun("obj(42)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(42, value->Int32Value()); |
- value = CompileRun("(function(o){return o(49)})(obj)"); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(49, value->Int32Value()); |
+ value = CompileRun("(function(o){return o(49)})(obj)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(49, value->Int32Value()); |
- // test special case of call as function |
- value = CompileRun("[obj]['0'](45)"); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(45, value->Int32Value()); |
+ // test special case of call as function |
+ value = CompileRun("[obj]['0'](45)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(45, value->Int32Value()); |
- value = CompileRun("obj.call = Function.prototype.call;" |
- "obj.call(null, 87)"); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(87, value->Int32Value()); |
+ value = CompileRun("obj.call = Function.prototype.call;" |
+ "obj.call(null, 87)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(87, value->Int32Value()); |
- // Regression tests for bug #1116356: Calling call through call/apply |
- // must work for non-function receivers. |
- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; |
- value = CompileRun(apply_99); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(99, value->Int32Value()); |
+ // Regression tests for bug #1116356: Calling call through call/apply |
+ // must work for non-function receivers. |
+ const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; |
+ value = CompileRun(apply_99); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(99, value->Int32Value()); |
- const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; |
- value = CompileRun(call_17); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(17, value->Int32Value()); |
+ const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; |
+ value = CompileRun(call_17); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(17, value->Int32Value()); |
- // Check that the call-as-function handler can be called through |
- // new. |
- value = CompileRun("new obj(43)"); |
- CHECK(!try_catch.HasCaught()); |
- CHECK_EQ(-43, value->Int32Value()); |
+ // Check that the call-as-function handler can be called through |
+ // new. |
+ value = CompileRun("new obj(43)"); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(-43, value->Int32Value()); |
+ |
+ // Check that the call-as-function handler can be called through |
+ // the API. |
+ v8::Handle<Value> args[] = { v8_num(28) }; |
+ value = instance->CallAsFunction(instance, 1, args); |
+ CHECK(!try_catch.HasCaught()); |
+ CHECK_EQ(28, value->Int32Value()); |
+ } |
+ |
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); |
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); |
+ Local<v8::Object> instance = t->GetFunction()->NewInstance(); |
+ context->Global()->Set(v8_str("obj2"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ // Call an object without call-as-function handler through the JS |
+ value = CompileRun("obj2(28)"); |
+ CHECK(value.IsEmpty()); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value1(try_catch.Exception()); |
+ CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", |
+ *exception_value1); |
+ try_catch.Reset(); |
+ |
+ // Call an object without call-as-function handler through the API |
+ value = CompileRun("obj2(28)"); |
+ v8::Handle<Value> args[] = { v8_num(28) }; |
+ value = instance->CallAsFunction(instance, 1, args); |
+ CHECK(value.IsEmpty()); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value2(try_catch.Exception()); |
+ CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); |
+ try_catch.Reset(); |
+ } |
+ |
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); |
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); |
+ instance_template->SetCallAsFunctionHandler(ThrowValue); |
+ Local<v8::Object> instance = t->GetFunction()->NewInstance(); |
+ context->Global()->Set(v8_str("obj3"), instance); |
+ v8::TryCatch try_catch; |
+ Local<Value> value; |
+ CHECK(!try_catch.HasCaught()); |
+ |
+ // Catch the exception which is thrown by call-as-function handler |
+ value = CompileRun("obj3(22)"); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value1(try_catch.Exception()); |
+ CHECK_EQ("22", *exception_value1); |
+ try_catch.Reset(); |
+ |
+ v8::Handle<Value> args[] = { v8_num(23) }; |
+ value = instance->CallAsFunction(instance, 1, args); |
+ CHECK(try_catch.HasCaught()); |
+ String::AsciiValue exception_value2(try_catch.Exception()); |
+ CHECK_EQ("23", *exception_value2); |
+ try_catch.Reset(); |
+ } |
} |
@@ -8946,11 +9201,10 @@ static unsigned linear_congruential_generator; |
void ApiTestFuzzer::Setup(PartOfTest part) { |
linear_congruential_generator = i::FLAG_testing_prng_seed; |
fuzzing_ = true; |
- int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1); |
- int end = (part == FIRST_PART) |
- ? (RegisterThreadedTest::count() >> 1) |
- : RegisterThreadedTest::count(); |
- active_tests_ = tests_being_run_ = end - start; |
+ int count = RegisterThreadedTest::count(); |
+ int start = count * part / (LAST_PART + 1); |
+ int end = (count * (part + 1) / (LAST_PART + 1)) - 1; |
+ active_tests_ = tests_being_run_ = end - start + 1; |
for (int i = 0; i < tests_being_run_; i++) { |
RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer( |
i::Isolate::Current(), i + start); |
@@ -9020,6 +9274,17 @@ TEST(Threading2) { |
ApiTestFuzzer::TearDown(); |
} |
+TEST(Threading3) { |
+ ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART); |
+ ApiTestFuzzer::RunAllTests(); |
+ ApiTestFuzzer::TearDown(); |
+} |
+ |
+TEST(Threading4) { |
+ ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART); |
+ ApiTestFuzzer::RunAllTests(); |
+ ApiTestFuzzer::TearDown(); |
+} |
void ApiTestFuzzer::CallTest() { |
if (kLogThreading) |
@@ -13388,6 +13653,28 @@ TEST(MultipleIsolatesOnIndividualThreads) { |
isolate2->Dispose(); |
} |
+TEST(IsolateDifferentContexts) { |
+ v8::Isolate* isolate = v8::Isolate::New(); |
+ Persistent<v8::Context> context; |
+ { |
+ v8::Isolate::Scope isolate_scope(isolate); |
+ v8::HandleScope handle_scope; |
+ context = v8::Context::New(); |
+ v8::Context::Scope context_scope(context); |
+ Local<Value> v = CompileRun("2"); |
+ CHECK(v->IsNumber()); |
+ CHECK_EQ(2, static_cast<int>(v->NumberValue())); |
+ } |
+ { |
+ v8::Isolate::Scope isolate_scope(isolate); |
+ v8::HandleScope handle_scope; |
+ context = v8::Context::New(); |
+ v8::Context::Scope context_scope(context); |
+ Local<Value> v = CompileRun("22"); |
+ CHECK(v->IsNumber()); |
+ CHECK_EQ(22, static_cast<int>(v->NumberValue())); |
+ } |
+} |
class InitDefaultIsolateThread : public v8::internal::Thread { |
public: |
@@ -14104,3 +14391,20 @@ THREADED_TEST(AllowCodeGenFromStrings) { |
V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); |
CheckCodeGenerationDisallowed(); |
} |
+ |
+ |
+static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) { |
+ return v8::Undefined(); |
+} |
+ |
+ |
+THREADED_TEST(CallAPIFunctionOnNonObject) { |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis); |
+ Handle<Function> function = templ->GetFunction(); |
+ context->Global()->Set(v8_str("f"), function); |
+ TryCatch try_catch; |
+ CompileRun("f.call(2)"); |
+ CHECK(try_catch.HasCaught()); |
+} |