| Index: test/cctest/test-api.cc
|
| ===================================================================
|
| --- test/cctest/test-api.cc (revision 3935)
|
| +++ test/cctest/test-api.cc (working copy)
|
| @@ -394,6 +394,9 @@
|
| v8::HandleScope scope;
|
| LocalContext env;
|
| Local<String> source = String::New(two_byte_source);
|
| + // Trigger GCs so that the newly allocated string moves to old gen.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
|
| bool success = source->MakeExternal(new TestResource(two_byte_source));
|
| CHECK(success);
|
| Local<Script> script = Script::Compile(source);
|
| @@ -416,6 +419,9 @@
|
| v8::HandleScope scope;
|
| LocalContext env;
|
| Local<String> source = v8_str(c_source);
|
| + // Trigger GCs so that the newly allocated string moves to old gen.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
|
| bool success = source->MakeExternal(
|
| new TestAsciiResource(i::StrDup(c_source)));
|
| CHECK(success);
|
| @@ -432,6 +438,80 @@
|
| }
|
|
|
|
|
| +TEST(MakingExternalStringConditions) {
|
| + v8::HandleScope scope;
|
| + LocalContext env;
|
| +
|
| + // Free some space in the new space so that we can check freshness.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE);
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE);
|
| +
|
| + Local<String> small_string = String::New(AsciiToTwoByteString("small"));
|
| + // We should refuse to externalize newly created small string.
|
| + CHECK(!small_string->CanMakeExternal());
|
| + // Trigger GCs so that the newly allocated string moves to old gen.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
|
| + // Old space strings should be accepted.
|
| + CHECK(small_string->CanMakeExternal());
|
| +
|
| + small_string = String::New(AsciiToTwoByteString("small 2"));
|
| + // We should refuse externalizing newly created small string.
|
| + CHECK(!small_string->CanMakeExternal());
|
| + for (int i = 0; i < 100; i++) {
|
| + String::Value value(small_string);
|
| + }
|
| + // Frequently used strings should be accepted.
|
| + CHECK(small_string->CanMakeExternal());
|
| +
|
| + const int buf_size = 10 * 1024;
|
| + char* buf = i::NewArray<char>(buf_size);
|
| + memset(buf, 'a', buf_size);
|
| + buf[buf_size - 1] = '\0';
|
| + Local<String> large_string = String::New(AsciiToTwoByteString(buf));
|
| + i::DeleteArray(buf);
|
| + // Large strings should be immediately accepted.
|
| + CHECK(large_string->CanMakeExternal());
|
| +}
|
| +
|
| +
|
| +TEST(MakingExternalAsciiStringConditions) {
|
| + v8::HandleScope scope;
|
| + LocalContext env;
|
| +
|
| + // Free some space in the new space so that we can check freshness.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE);
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE);
|
| +
|
| + Local<String> small_string = String::New("small");
|
| + // We should refuse to externalize newly created small string.
|
| + CHECK(!small_string->CanMakeExternal());
|
| + // Trigger GCs so that the newly allocated string moves to old gen.
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
|
| + i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
|
| + // Old space strings should be accepted.
|
| + CHECK(small_string->CanMakeExternal());
|
| +
|
| + small_string = String::New("small 2");
|
| + // We should refuse externalizing newly created small string.
|
| + CHECK(!small_string->CanMakeExternal());
|
| + for (int i = 0; i < 100; i++) {
|
| + String::Value value(small_string);
|
| + }
|
| + // Frequently used strings should be accepted.
|
| + CHECK(small_string->CanMakeExternal());
|
| +
|
| + const int buf_size = 10 * 1024;
|
| + char* buf = i::NewArray<char>(buf_size);
|
| + memset(buf, 'a', buf_size);
|
| + buf[buf_size - 1] = '\0';
|
| + Local<String> large_string = String::New(buf);
|
| + i::DeleteArray(buf);
|
| + // Large strings should be immediately accepted.
|
| + CHECK(large_string->CanMakeExternal());
|
| +}
|
| +
|
| +
|
| THREADED_TEST(UsingExternalString) {
|
| {
|
| v8::HandleScope scope;
|
| @@ -2448,6 +2528,33 @@
|
| }
|
|
|
|
|
| +static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
|
| + const AccessorInfo& info) {
|
| + // Set x on the prototype object and do not handle the get request.
|
| + v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
|
| + v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
|
| + return v8::Handle<Value>();
|
| +}
|
| +
|
| +
|
| +// This is a regression test for http://crbug.com/20104. Map
|
| +// transitions should not interfere with post interceptor lookup.
|
| +THREADED_TEST(NamedInterceptorMapTransitionRead) {
|
| + v8::HandleScope scope;
|
| + Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
|
| + Local<v8::ObjectTemplate> instance_template
|
| + = function_template->InstanceTemplate();
|
| + instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
|
| + LocalContext context;
|
| + context->Global()->Set(v8_str("F"), function_template->GetFunction());
|
| + // Create an instance of F and introduce a map transition for x.
|
| + CompileRun("var o = new F(); o.x = 23;");
|
| + // Create an instance of F and invoke the getter. The result should be 23.
|
| + Local<Value> result = CompileRun("o = new F(); o.x");
|
| + CHECK_EQ(result->Int32Value(), 23);
|
| +}
|
| +
|
| +
|
| static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
|
| const AccessorInfo& info) {
|
| ApiTestFuzzer::Fuzz();
|
| @@ -2529,6 +2636,195 @@
|
| }
|
|
|
|
|
| +THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + obj->TurnOnAccessCheck();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var v = obj[0];"
|
| + " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
|
| + i::FLAG_allow_natives_syntax = true;
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var expected = i;"
|
| + " if (i == 5) {"
|
| + " %EnableAccessChecks(obj);"
|
| + " expected = undefined;"
|
| + " }"
|
| + " var v = obj[i];"
|
| + " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " if (i == 5) %DisableAccessChecks(obj);"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var v = obj[i];"
|
| + " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var expected = i;"
|
| + " if (i == 50) {"
|
| + " i = 'foobar';"
|
| + " expected = undefined;"
|
| + " }"
|
| + " var v = obj[i];"
|
| + " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "var original = obj;"
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var expected = i;"
|
| + " if (i == 50) {"
|
| + " obj = {50: 'foobar'};"
|
| + " expected = 'foobar';"
|
| + " }"
|
| + " var v = obj[i];"
|
| + " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " if (i == 50) obj = original;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "var original = obj;"
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var expected = i;"
|
| + " if (i == 5) {"
|
| + " obj = 239;"
|
| + " expected = undefined;"
|
| + " }"
|
| + " var v = obj[i];"
|
| + " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " if (i == 5) obj = original;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(IndexedInterceptorOnProto) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
|
| +
|
| + LocalContext context;
|
| + Local<v8::Object> obj = templ->NewInstance();
|
| + context->Global()->Set(v8_str("obj"), obj);
|
| +
|
| + const char* code =
|
| + "var o = {__proto__: obj};"
|
| + "try {"
|
| + " for (var i = 0; i < 100; i++) {"
|
| + " var v = o[i];"
|
| + " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
|
| + " }"
|
| + " 'PASSED'"
|
| + "} catch(e) {"
|
| + " e"
|
| + "}";
|
| + ExpectString(code, "PASSED");
|
| +}
|
| +
|
| +
|
| THREADED_TEST(MultiContexts) {
|
| v8::HandleScope scope;
|
| v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
|
| @@ -4844,6 +5140,84 @@
|
| }
|
|
|
|
|
| +THREADED_TEST(SetPrototype) {
|
| + v8::HandleScope handle_scope;
|
| + LocalContext context;
|
| +
|
| + Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
|
| + t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
|
| + Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
|
| + t1->SetHiddenPrototype(true);
|
| + t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
|
| + Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
|
| + t2->SetHiddenPrototype(true);
|
| + t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
|
| + Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
|
| + t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
|
| +
|
| + Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
|
| + Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
|
| + Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
|
| + Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
|
| +
|
| + // Setting the prototype on an object does not skip hidden prototypes.
|
| + CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
|
| + CHECK(o0->SetPrototype(o1));
|
| + CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
|
| + CHECK(o1->SetPrototype(o2));
|
| + CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
|
| + CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
|
| + CHECK(o2->SetPrototype(o3));
|
| + CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
|
| + CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
|
| + CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
|
| +
|
| + // Getting the prototype of o0 should get the first visible one
|
| + // which is o3. Therefore, z should not be defined on the prototype
|
| + // object.
|
| + Local<Value> proto = o0->Get(v8_str("__proto__"));
|
| + CHECK(proto->IsObject());
|
| + CHECK_EQ(v8::Handle<v8::Object>::Cast(proto), o3);
|
| +
|
| + // However, Object::GetPrototype ignores hidden prototype.
|
| + Local<Value> proto0 = o0->GetPrototype();
|
| + CHECK(proto0->IsObject());
|
| + CHECK_EQ(v8::Handle<v8::Object>::Cast(proto0), o1);
|
| +
|
| + Local<Value> proto1 = o1->GetPrototype();
|
| + CHECK(proto1->IsObject());
|
| + CHECK_EQ(v8::Handle<v8::Object>::Cast(proto1), o2);
|
| +
|
| + Local<Value> proto2 = o2->GetPrototype();
|
| + CHECK(proto2->IsObject());
|
| + CHECK_EQ(v8::Handle<v8::Object>::Cast(proto2), o3);
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(SetPrototypeThrows) {
|
| + v8::HandleScope handle_scope;
|
| + LocalContext context;
|
| +
|
| + Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
|
| +
|
| + Local<v8::Object> o0 = t->GetFunction()->NewInstance();
|
| + Local<v8::Object> o1 = t->GetFunction()->NewInstance();
|
| +
|
| + CHECK(o0->SetPrototype(o1));
|
| + // If setting the prototype leads to the cycle, SetPrototype should
|
| + // return false and keep VM in sane state.
|
| + v8::TryCatch try_catch;
|
| + CHECK(!o1->SetPrototype(o0));
|
| + CHECK(!try_catch.HasCaught());
|
| + ASSERT(!i::Top::has_pending_exception());
|
| +
|
| + CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
|
| +}
|
| +
|
| +
|
| THREADED_TEST(GetterSetterExceptions) {
|
| v8::HandleScope handle_scope;
|
| LocalContext context;
|
| @@ -5078,7 +5452,7 @@
|
|
|
|
|
| static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
|
| - //ApiTestFuzzer::Fuzz();
|
| + ApiTestFuzzer::Fuzz();
|
| if (args.IsConstructCall()) {
|
| if (args[0]->IsInt32()) {
|
| return v8_num(-args[0]->Int32Value());
|
| @@ -5891,7 +6265,295 @@
|
| CHECK_EQ(239 * 10, value->Int32Value());
|
| }
|
|
|
| +static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
|
| + const AccessorInfo& info) {
|
| + ApiTestFuzzer::Fuzz();
|
| + int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
|
| + ++(*call_count);
|
| + if ((*call_count) % 20 == 0) {
|
| + v8::internal::Heap::CollectAllGarbage(true);
|
| + }
|
| + return v8::Handle<Value>();
|
| +}
|
|
|
| +static v8::Handle<Value> FastApiCallback_TrivialSignature(
|
| + const v8::Arguments& args) {
|
| + ApiTestFuzzer::Fuzz();
|
| + CHECK_EQ(args.This(), args.Holder());
|
| + CHECK(args.Data()->Equals(v8_str("method_data")));
|
| + return v8::Integer::New(args[0]->Int32Value() + 1);
|
| +}
|
| +
|
| +static v8::Handle<Value> FastApiCallback_SimpleSignature(
|
| + const v8::Arguments& args) {
|
| + ApiTestFuzzer::Fuzz();
|
| + CHECK_EQ(args.This()->GetPrototype(), args.Holder());
|
| + CHECK(args.Data()->Equals(v8_str("method_data")));
|
| + // Note, we're using HasRealNamedProperty instead of Has to avoid
|
| + // invoking the interceptor again.
|
| + CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
|
| + return v8::Integer::New(args[0]->Int32Value() + 1);
|
| +}
|
| +
|
| +// Helper to maximize the odds of object moving.
|
| +static void GenerateSomeGarbage() {
|
| + CompileRun(
|
| + "var garbage;"
|
| + "for (var i = 0; i < 1000; i++) {"
|
| + " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
|
| + "}"
|
| + "garbage = undefined;");
|
| +}
|
| +
|
| +THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
|
| + int interceptor_call_count = 0;
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
|
| + v8_str("method_data"),
|
| + v8::Handle<v8::Signature>());
|
| + 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();
|
| + templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
|
| + NULL, NULL, NULL, NULL,
|
| + v8::External::Wrap(&interceptor_call_count));
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = 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);
|
| +}
|
| +
|
| +THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
|
| + int interceptor_call_count = 0;
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
|
| + NULL, NULL, NULL, NULL,
|
| + v8::External::Wrap(&interceptor_call_count));
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = 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);
|
| +}
|
| +
|
| +THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
|
| + int interceptor_call_count = 0;
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
|
| + NULL, NULL, NULL, NULL,
|
| + v8::External::Wrap(&interceptor_call_count));
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = CompileRun(
|
| + "o.foo = 17;"
|
| + "var receiver = {};"
|
| + "receiver.__proto__ = o;"
|
| + "var result = 0;"
|
| + "var saved_result = 0;"
|
| + "for (var i = 0; i < 100; i++) {"
|
| + " result = receiver.method(41);"
|
| + " if (i == 50) {"
|
| + " 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);
|
| +}
|
| +
|
| +THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
|
| + int interceptor_call_count = 0;
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
|
| + NULL, NULL, NULL, NULL,
|
| + v8::External::Wrap(&interceptor_call_count));
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = CompileRun(
|
| + "o.foo = 17;"
|
| + "var receiver = {};"
|
| + "receiver.__proto__ = o;"
|
| + "var result = 0;"
|
| + "var saved_result = 0;"
|
| + "for (var i = 0; i < 100; i++) {"
|
| + " result = receiver.method(41);"
|
| + " if (i == 50) {"
|
| + " 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);
|
| +}
|
| +
|
| +THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
|
| + int interceptor_call_count = 0;
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
|
| + NULL, NULL, NULL, NULL,
|
| + v8::External::Wrap(&interceptor_call_count));
|
| + 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(
|
| + "o.foo = 17;"
|
| + "var receiver = {};"
|
| + "receiver.__proto__ = o;"
|
| + "var result = 0;"
|
| + "var saved_result = 0;"
|
| + "for (var i = 0; i < 100; i++) {"
|
| + " result = receiver.method(41);"
|
| + " if (i == 50) {"
|
| + " saved_result = result;"
|
| + " receiver = {method: receiver.method};"
|
| + " }"
|
| + "}");
|
| + CHECK(try_catch.HasCaught());
|
| + CHECK_EQ(v8_str("TypeError: Illegal invocation"),
|
| + try_catch.Exception()->ToString());
|
| + CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
|
| + CHECK_GE(interceptor_call_count, 50);
|
| +}
|
| +
|
| +THREADED_TEST(CallICFastApi_TrivialSignature) {
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
|
| + v8_str("method_data"),
|
| + v8::Handle<v8::Signature>());
|
| + 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();
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = 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());
|
| +}
|
| +
|
| +THREADED_TEST(CallICFastApi_SimpleSignature) {
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = 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());
|
| +}
|
| +
|
| +THREADED_TEST(CallICFastApi_SimpleSignature_Miss) {
|
| + v8::HandleScope scope;
|
| + v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
| + v8::Handle<v8::FunctionTemplate> method_templ =
|
| + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
|
| + v8_str("method_data"),
|
| + v8::Signature::New(fun_templ));
|
| + 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();
|
| + LocalContext context;
|
| + v8::Handle<v8::Function> fun = fun_templ->GetFunction();
|
| + GenerateSomeGarbage();
|
| + context->Global()->Set(v8_str("o"), fun->NewInstance());
|
| + v8::Handle<Value> value = CompileRun(
|
| + "o.foo = 17;"
|
| + "var receiver = {};"
|
| + "receiver.__proto__ = o;"
|
| + "var result = 0;"
|
| + "var saved_result = 0;"
|
| + "for (var i = 0; i < 100; i++) {"
|
| + " result = receiver.method(41);"
|
| + " if (i == 50) {"
|
| + " 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());
|
| +}
|
| +
|
| +
|
| static int interceptor_call_count = 0;
|
|
|
| static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
|
| @@ -8927,3 +9589,138 @@
|
|
|
| other_context.Dispose();
|
| }
|
| +
|
| +
|
| +THREADED_TEST(ScriptOrigin) {
|
| + v8::HandleScope scope;
|
| + LocalContext env;
|
| + v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
|
| + v8::Handle<v8::String> script = v8::String::New(
|
| + "function f() {}\n\nfunction g() {}");
|
| + v8::Script::Compile(script, &origin)->Run();
|
| + v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("f")));
|
| + v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("g")));
|
| +
|
| + v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
|
| + CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
|
| + CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
|
| +
|
| + v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
|
| + CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
|
| + CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(ScriptLineNumber) {
|
| + v8::HandleScope scope;
|
| + LocalContext env;
|
| + v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
|
| + v8::Handle<v8::String> script = v8::String::New(
|
| + "function f() {}\n\nfunction g() {}");
|
| + v8::Script::Compile(script, &origin)->Run();
|
| + v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("f")));
|
| + v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(v8::String::New("g")));
|
| + CHECK_EQ(0, f->GetScriptLineNumber());
|
| + CHECK_EQ(2, g->GetScriptLineNumber());
|
| +}
|
| +
|
| +
|
| +static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
|
| + const AccessorInfo& info) {
|
| + return v8_num(42);
|
| +}
|
| +
|
| +
|
| +static void SetterWhichSetsYOnThisTo23(Local<String> name,
|
| + Local<Value> value,
|
| + const AccessorInfo& info) {
|
| + info.This()->Set(v8_str("y"), v8_num(23));
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(SetterOnConstructorPrototype) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetAccessor(v8_str("x"),
|
| + GetterWhichReturns42,
|
| + SetterWhichSetsYOnThisTo23);
|
| + LocalContext context;
|
| + context->Global()->Set(v8_str("P"), templ->NewInstance());
|
| + CompileRun("function C1() {"
|
| + " this.x = 23;"
|
| + "};"
|
| + "C1.prototype = P;"
|
| + "function C2() {"
|
| + " this.x = 23"
|
| + "};"
|
| + "C2.prototype = { };"
|
| + "C2.prototype.__proto__ = P;");
|
| +
|
| + v8::Local<v8::Script> script;
|
| + script = v8::Script::Compile(v8_str("new C1();"));
|
| + for (int i = 0; i < 10; i++) {
|
| + v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
|
| + CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
|
| + }
|
| +
|
| + script = v8::Script::Compile(v8_str("new C2();"));
|
| + for (int i = 0; i < 10; i++) {
|
| + v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
|
| + CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
|
| + }
|
| +}
|
| +
|
| +
|
| +static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
|
| + Local<String> name, const AccessorInfo& info) {
|
| + return v8_num(42);
|
| +}
|
| +
|
| +
|
| +static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
|
| + Local<String> name, Local<Value> value, const AccessorInfo& info) {
|
| + if (name->Equals(v8_str("x"))) {
|
| + info.This()->Set(v8_str("y"), v8_num(23));
|
| + }
|
| + return v8::Handle<Value>();
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(InterceptorOnConstructorPrototype) {
|
| + v8::HandleScope scope;
|
| + Local<ObjectTemplate> templ = ObjectTemplate::New();
|
| + templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
|
| + NamedPropertySetterWhichSetsYOnThisTo23);
|
| + LocalContext context;
|
| + context->Global()->Set(v8_str("P"), templ->NewInstance());
|
| + CompileRun("function C1() {"
|
| + " this.x = 23;"
|
| + "};"
|
| + "C1.prototype = P;"
|
| + "function C2() {"
|
| + " this.x = 23"
|
| + "};"
|
| + "C2.prototype = { };"
|
| + "C2.prototype.__proto__ = P;");
|
| +
|
| + v8::Local<v8::Script> script;
|
| + script = v8::Script::Compile(v8_str("new C1();"));
|
| + for (int i = 0; i < 10; i++) {
|
| + v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
|
| + CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
|
| + }
|
| +
|
| + script = v8::Script::Compile(v8_str("new C2();"));
|
| + for (int i = 0; i < 10; i++) {
|
| + v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
|
| + CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
|
| + CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
|
| + }
|
| +}
|
|
|