1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <climits> 29 #include <csignal> 30 #include <string> 31 #include <map> 32 33 #include "src/v8.h" 34 35 #if V8_OS_POSIX 36 #include <unistd.h> // NOLINT 37 #endif 38 39 #include "include/v8-util.h" 40 #include "src/api.h" 41 #include "src/arguments.h" 42 #include "src/compilation-cache.h" 43 #include "src/cpu-profiler.h" 44 #include "src/execution.h" 45 #include "src/isolate.h" 46 #include "src/objects.h" 47 #include "src/parser.h" 48 #include "src/platform.h" 49 #include "src/snapshot.h" 50 #include "src/unicode-inl.h" 51 #include "src/utils.h" 52 #include "src/vm-state.h" 53 #include "test/cctest/cctest.h" 54 55 static const bool kLogThreading = false; 56 57 using ::v8::Boolean; 58 using ::v8::BooleanObject; 59 using ::v8::Context; 60 using ::v8::Extension; 61 using ::v8::Function; 62 using ::v8::FunctionTemplate; 63 using ::v8::Handle; 64 using ::v8::HandleScope; 65 using ::v8::Local; 66 using ::v8::Message; 67 using ::v8::MessageCallback; 68 using ::v8::Object; 69 using ::v8::ObjectTemplate; 70 using ::v8::Persistent; 71 using ::v8::Script; 72 using ::v8::StackTrace; 73 using ::v8::String; 74 using ::v8::TryCatch; 75 using ::v8::Undefined; 76 using ::v8::UniqueId; 77 using ::v8::V8; 78 using ::v8::Value; 79 80 81 #define THREADED_PROFILED_TEST(Name) \ 82 static void Test##Name(); \ 83 TEST(Name##WithProfiler) { \ 84 RunWithProfiler(&Test##Name); \ 85 } \ 86 THREADED_TEST(Name) 87 88 89 void RunWithProfiler(void (*test)()) { 90 LocalContext env; 91 v8::HandleScope scope(env->GetIsolate()); 92 v8::Local<v8::String> profile_name = 93 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1"); 94 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 95 96 cpu_profiler->StartProfiling(profile_name); 97 (*test)(); 98 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles(); 99 } 100 101 102 static int signature_callback_count; 103 static Local<Value> signature_expected_receiver; 104 static void IncrementingSignatureCallback( 105 const v8::FunctionCallbackInfo<v8::Value>& args) { 106 ApiTestFuzzer::Fuzz(); 107 signature_callback_count++; 108 CHECK_EQ(signature_expected_receiver, args.Holder()); 109 CHECK_EQ(signature_expected_receiver, args.This()); 110 v8::Handle<v8::Array> result = 111 v8::Array::New(args.GetIsolate(), args.Length()); 112 for (int i = 0; i < args.Length(); i++) 113 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]); 114 args.GetReturnValue().Set(result); 115 } 116 117 118 static void SignatureCallback( 119 const v8::FunctionCallbackInfo<v8::Value>& args) { 120 ApiTestFuzzer::Fuzz(); 121 v8::Handle<v8::Array> result = 122 v8::Array::New(args.GetIsolate(), args.Length()); 123 for (int i = 0; i < args.Length(); i++) { 124 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]); 125 } 126 args.GetReturnValue().Set(result); 127 } 128 129 130 // Tests that call v8::V8::Dispose() cannot be threaded. 131 TEST(InitializeAndDisposeOnce) { 132 CHECK(v8::V8::Initialize()); 133 CHECK(v8::V8::Dispose()); 134 } 135 136 137 // Tests that call v8::V8::Dispose() cannot be threaded. 138 TEST(InitializeAndDisposeMultiple) { 139 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 140 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 142 // TODO(mstarzinger): This should fail gracefully instead of asserting. 143 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 145 } 146 147 148 THREADED_TEST(Handles) { 149 v8::HandleScope scope(CcTest::isolate()); 150 Local<Context> local_env; 151 { 152 LocalContext env; 153 local_env = env.local(); 154 } 155 156 // Local context should still be live. 157 CHECK(!local_env.IsEmpty()); 158 local_env->Enter(); 159 160 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); 161 CHECK(!undef.IsEmpty()); 162 CHECK(undef->IsUndefined()); 163 164 const char* source = "1 + 2 + 3"; 165 Local<Script> script = v8_compile(source); 166 CHECK_EQ(6, script->Run()->Int32Value()); 167 168 local_env->Exit(); 169 } 170 171 172 THREADED_TEST(IsolateOfContext) { 173 v8::HandleScope scope(CcTest::isolate()); 174 v8::Handle<Context> env = Context::New(CcTest::isolate()); 175 176 CHECK(!env->GetIsolate()->InContext()); 177 CHECK(env->GetIsolate() == CcTest::isolate()); 178 env->Enter(); 179 CHECK(env->GetIsolate()->InContext()); 180 CHECK(env->GetIsolate() == CcTest::isolate()); 181 env->Exit(); 182 CHECK(!env->GetIsolate()->InContext()); 183 CHECK(env->GetIsolate() == CcTest::isolate()); 184 } 185 186 187 static void TestSignature(const char* loop_js, Local<Value> receiver) { 188 i::ScopedVector<char> source(200); 189 i::SNPrintF(source, 190 "for (var i = 0; i < 10; i++) {" 191 " %s" 192 "}", 193 loop_js); 194 signature_callback_count = 0; 195 signature_expected_receiver = receiver; 196 bool expected_to_throw = receiver.IsEmpty(); 197 v8::TryCatch try_catch; 198 CompileRun(source.start()); 199 CHECK_EQ(expected_to_throw, try_catch.HasCaught()); 200 if (!expected_to_throw) { 201 CHECK_EQ(10, signature_callback_count); 202 } else { 203 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 204 try_catch.Exception()->ToString()); 205 } 206 } 207 208 209 THREADED_TEST(ReceiverSignature) { 210 LocalContext env; 211 v8::Isolate* isolate = env->GetIsolate(); 212 v8::HandleScope scope(isolate); 213 // Setup templates. 214 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 215 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun); 216 v8::Handle<v8::FunctionTemplate> callback_sig = 217 v8::FunctionTemplate::New( 218 isolate, IncrementingSignatureCallback, Local<Value>(), sig); 219 v8::Handle<v8::FunctionTemplate> callback = 220 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback); 221 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate); 222 sub_fun->Inherit(fun); 223 v8::Handle<v8::FunctionTemplate> unrel_fun = 224 v8::FunctionTemplate::New(isolate); 225 // Install properties. 226 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); 227 fun_proto->Set(v8_str("prop_sig"), callback_sig); 228 fun_proto->Set(v8_str("prop"), callback); 229 fun_proto->SetAccessorProperty( 230 v8_str("accessor_sig"), callback_sig, callback_sig); 231 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); 232 // Instantiate templates. 233 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance(); 234 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance(); 235 // Setup global variables. 236 env->Global()->Set(v8_str("Fun"), fun->GetFunction()); 237 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); 238 env->Global()->Set(v8_str("fun_instance"), fun_instance); 239 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance); 240 CompileRun( 241 "var accessor_sig_key = 'accessor_sig';" 242 "var accessor_key = 'accessor';" 243 "var prop_sig_key = 'prop_sig';" 244 "var prop_key = 'prop';" 245 "" 246 "function copy_props(obj) {" 247 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" 248 " var source = Fun.prototype;" 249 " for (var i in keys) {" 250 " var key = keys[i];" 251 " var desc = Object.getOwnPropertyDescriptor(source, key);" 252 " Object.defineProperty(obj, key, desc);" 253 " }" 254 "}" 255 "" 256 "var obj = {};" 257 "copy_props(obj);" 258 "var unrel = new UnrelFun();" 259 "copy_props(unrel);"); 260 // Test with and without ICs 261 const char* test_objects[] = { 262 "fun_instance", "sub_fun_instance", "obj", "unrel" }; 263 unsigned bad_signature_start_offset = 2; 264 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) { 265 i::ScopedVector<char> source(200); 266 i::SNPrintF( 267 source, "var test_object = %s; test_object", test_objects[i]); 268 Local<Value> test_object = CompileRun(source.start()); 269 TestSignature("test_object.prop();", test_object); 270 TestSignature("test_object.accessor;", test_object); 271 TestSignature("test_object[accessor_key];", test_object); 272 TestSignature("test_object.accessor = 1;", test_object); 273 TestSignature("test_object[accessor_key] = 1;", test_object); 274 if (i >= bad_signature_start_offset) test_object = Local<Value>(); 275 TestSignature("test_object.prop_sig();", test_object); 276 TestSignature("test_object.accessor_sig;", test_object); 277 TestSignature("test_object[accessor_sig_key];", test_object); 278 TestSignature("test_object.accessor_sig = 1;", test_object); 279 TestSignature("test_object[accessor_sig_key] = 1;", test_object); 280 } 281 } 282 283 284 THREADED_TEST(ArgumentSignature) { 285 LocalContext env; 286 v8::Isolate* isolate = env->GetIsolate(); 287 v8::HandleScope scope(isolate); 288 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate); 289 cons->SetClassName(v8_str("Cons")); 290 v8::Handle<v8::Signature> sig = v8::Signature::New( 291 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons); 292 v8::Handle<v8::FunctionTemplate> fun = 293 v8::FunctionTemplate::New(isolate, 294 SignatureCallback, 295 v8::Handle<Value>(), 296 sig); 297 env->Global()->Set(v8_str("Cons"), cons->GetFunction()); 298 env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); 299 300 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); 301 CHECK(value1->IsTrue()); 302 303 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); 304 CHECK(value2->IsTrue()); 305 306 v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); 307 CHECK(value3->IsTrue()); 308 309 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate); 310 cons1->SetClassName(v8_str("Cons1")); 311 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate); 312 cons2->SetClassName(v8_str("Cons2")); 313 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate); 314 cons3->SetClassName(v8_str("Cons3")); 315 316 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; 317 v8::Handle<v8::Signature> wsig = v8::Signature::New( 318 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args); 319 v8::Handle<v8::FunctionTemplate> fun2 = 320 v8::FunctionTemplate::New(isolate, 321 SignatureCallback, 322 v8::Handle<Value>(), 323 wsig); 324 325 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); 326 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); 327 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); 328 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); 329 v8::Handle<Value> value4 = CompileRun( 330 "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" 331 "'[object Cons1],[object Cons2],[object Cons3]'"); 332 CHECK(value4->IsTrue()); 333 334 v8::Handle<Value> value5 = CompileRun( 335 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); 336 CHECK(value5->IsTrue()); 337 338 v8::Handle<Value> value6 = CompileRun( 339 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); 340 CHECK(value6->IsTrue()); 341 342 v8::Handle<Value> value7 = CompileRun( 343 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " 344 "'[object Cons1],[object Cons2],[object Cons3],d';"); 345 CHECK(value7->IsTrue()); 346 347 v8::Handle<Value> value8 = CompileRun( 348 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); 349 CHECK(value8->IsTrue()); 350 } 351 352 353 THREADED_TEST(HulIgennem) { 354 LocalContext env; 355 v8::Isolate* isolate = env->GetIsolate(); 356 v8::HandleScope scope(isolate); 357 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate); 358 Local<String> undef_str = undef->ToString(); 359 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 360 undef_str->WriteUtf8(value); 361 CHECK_EQ(0, strcmp(value, "undefined")); 362 i::DeleteArray(value); 363 } 364 365 366 THREADED_TEST(Access) { 367 LocalContext env; 368 v8::Isolate* isolate = env->GetIsolate(); 369 v8::HandleScope scope(isolate); 370 Local<v8::Object> obj = v8::Object::New(isolate); 371 Local<Value> foo_before = obj->Get(v8_str("foo")); 372 CHECK(foo_before->IsUndefined()); 373 Local<String> bar_str = v8_str("bar"); 374 obj->Set(v8_str("foo"), bar_str); 375 Local<Value> foo_after = obj->Get(v8_str("foo")); 376 CHECK(!foo_after->IsUndefined()); 377 CHECK(foo_after->IsString()); 378 CHECK_EQ(bar_str, foo_after); 379 } 380 381 382 THREADED_TEST(AccessElement) { 383 LocalContext env; 384 v8::HandleScope scope(env->GetIsolate()); 385 Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 386 Local<Value> before = obj->Get(1); 387 CHECK(before->IsUndefined()); 388 Local<String> bar_str = v8_str("bar"); 389 obj->Set(1, bar_str); 390 Local<Value> after = obj->Get(1); 391 CHECK(!after->IsUndefined()); 392 CHECK(after->IsString()); 393 CHECK_EQ(bar_str, after); 394 395 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 396 CHECK_EQ(v8_str("a"), value->Get(0)); 397 CHECK_EQ(v8_str("b"), value->Get(1)); 398 } 399 400 401 THREADED_TEST(Script) { 402 LocalContext env; 403 v8::HandleScope scope(env->GetIsolate()); 404 const char* source = "1 + 2 + 3"; 405 Local<Script> script = v8_compile(source); 406 CHECK_EQ(6, script->Run()->Int32Value()); 407 } 408 409 410 class TestResource: public String::ExternalStringResource { 411 public: 412 TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true) 413 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { 414 while (data[length_]) ++length_; 415 } 416 417 ~TestResource() { 418 if (owning_data_) i::DeleteArray(data_); 419 if (counter_ != NULL) ++*counter_; 420 } 421 422 const uint16_t* data() const { 423 return data_; 424 } 425 426 size_t length() const { 427 return length_; 428 } 429 430 private: 431 uint16_t* data_; 432 size_t length_; 433 int* counter_; 434 bool owning_data_; 435 }; 436 437 438 class TestAsciiResource: public String::ExternalAsciiStringResource { 439 public: 440 TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0) 441 : orig_data_(data), 442 data_(data + offset), 443 length_(strlen(data) - offset), 444 counter_(counter) { } 445 446 ~TestAsciiResource() { 447 i::DeleteArray(orig_data_); 448 if (counter_ != NULL) ++*counter_; 449 } 450 451 const char* data() const { 452 return data_; 453 } 454 455 size_t length() const { 456 return length_; 457 } 458 459 private: 460 const char* orig_data_; 461 const char* data_; 462 size_t length_; 463 int* counter_; 464 }; 465 466 467 THREADED_TEST(ScriptUsingStringResource) { 468 int dispose_count = 0; 469 const char* c_source = "1 + 2 * 3"; 470 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 471 { 472 LocalContext env; 473 v8::HandleScope scope(env->GetIsolate()); 474 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 475 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 476 Local<Script> script = v8_compile(source); 477 Local<Value> value = script->Run(); 478 CHECK(value->IsNumber()); 479 CHECK_EQ(7, value->Int32Value()); 480 CHECK(source->IsExternal()); 481 CHECK_EQ(resource, 482 static_cast<TestResource*>(source->GetExternalStringResource())); 483 String::Encoding encoding = String::UNKNOWN_ENCODING; 484 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 485 source->GetExternalStringResourceBase(&encoding)); 486 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 487 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 488 CHECK_EQ(0, dispose_count); 489 } 490 CcTest::i_isolate()->compilation_cache()->Clear(); 491 CcTest::heap()->CollectAllAvailableGarbage(); 492 CHECK_EQ(1, dispose_count); 493 } 494 495 496 THREADED_TEST(ScriptUsingAsciiStringResource) { 497 int dispose_count = 0; 498 const char* c_source = "1 + 2 * 3"; 499 { 500 LocalContext env; 501 v8::HandleScope scope(env->GetIsolate()); 502 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source), 503 &dispose_count); 504 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 505 CHECK(source->IsExternalAscii()); 506 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 507 source->GetExternalAsciiStringResource()); 508 String::Encoding encoding = String::UNKNOWN_ENCODING; 509 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 510 source->GetExternalStringResourceBase(&encoding)); 511 CHECK_EQ(String::ASCII_ENCODING, encoding); 512 Local<Script> script = v8_compile(source); 513 Local<Value> value = script->Run(); 514 CHECK(value->IsNumber()); 515 CHECK_EQ(7, value->Int32Value()); 516 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 517 CHECK_EQ(0, dispose_count); 518 } 519 CcTest::i_isolate()->compilation_cache()->Clear(); 520 CcTest::heap()->CollectAllAvailableGarbage(); 521 CHECK_EQ(1, dispose_count); 522 } 523 524 525 THREADED_TEST(ScriptMakingExternalString) { 526 int dispose_count = 0; 527 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 528 { 529 LocalContext env; 530 v8::HandleScope scope(env->GetIsolate()); 531 Local<String> source = 532 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 533 // Trigger GCs so that the newly allocated string moves to old gen. 534 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 535 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 536 CHECK_EQ(source->IsExternal(), false); 537 CHECK_EQ(source->IsExternalAscii(), false); 538 String::Encoding encoding = String::UNKNOWN_ENCODING; 539 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); 540 CHECK_EQ(String::ASCII_ENCODING, encoding); 541 bool success = source->MakeExternal(new TestResource(two_byte_source, 542 &dispose_count)); 543 CHECK(success); 544 Local<Script> script = v8_compile(source); 545 Local<Value> value = script->Run(); 546 CHECK(value->IsNumber()); 547 CHECK_EQ(7, value->Int32Value()); 548 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 549 CHECK_EQ(0, dispose_count); 550 } 551 CcTest::i_isolate()->compilation_cache()->Clear(); 552 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 553 CHECK_EQ(1, dispose_count); 554 } 555 556 557 THREADED_TEST(ScriptMakingExternalAsciiString) { 558 int dispose_count = 0; 559 const char* c_source = "1 + 2 * 3"; 560 { 561 LocalContext env; 562 v8::HandleScope scope(env->GetIsolate()); 563 Local<String> source = v8_str(c_source); 564 // Trigger GCs so that the newly allocated string moves to old gen. 565 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 566 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 567 bool success = source->MakeExternal( 568 new TestAsciiResource(i::StrDup(c_source), &dispose_count)); 569 CHECK(success); 570 Local<Script> script = v8_compile(source); 571 Local<Value> value = script->Run(); 572 CHECK(value->IsNumber()); 573 CHECK_EQ(7, value->Int32Value()); 574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 575 CHECK_EQ(0, dispose_count); 576 } 577 CcTest::i_isolate()->compilation_cache()->Clear(); 578 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 579 CHECK_EQ(1, dispose_count); 580 } 581 582 583 TEST(MakingExternalStringConditions) { 584 LocalContext env; 585 v8::HandleScope scope(env->GetIsolate()); 586 587 // Free some space in the new space so that we can check freshness. 588 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 589 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 590 591 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 592 Local<String> small_string = 593 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 594 i::DeleteArray(two_byte_string); 595 596 // We should refuse to externalize newly created small string. 597 CHECK(!small_string->CanMakeExternal()); 598 // Trigger GCs so that the newly allocated string moves to old gen. 599 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 600 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 601 // Old space strings should be accepted. 602 CHECK(small_string->CanMakeExternal()); 603 604 two_byte_string = AsciiToTwoByteString("small string 2"); 605 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 606 i::DeleteArray(two_byte_string); 607 608 // We should refuse externalizing newly created small string. 609 CHECK(!small_string->CanMakeExternal()); 610 for (int i = 0; i < 100; i++) { 611 String::Value value(small_string); 612 } 613 // Frequently used strings should be accepted. 614 CHECK(small_string->CanMakeExternal()); 615 616 const int buf_size = 10 * 1024; 617 char* buf = i::NewArray<char>(buf_size); 618 memset(buf, 'a', buf_size); 619 buf[buf_size - 1] = '\0'; 620 621 two_byte_string = AsciiToTwoByteString(buf); 622 Local<String> large_string = 623 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 624 i::DeleteArray(buf); 625 i::DeleteArray(two_byte_string); 626 // Large strings should be immediately accepted. 627 CHECK(large_string->CanMakeExternal()); 628 } 629 630 631 TEST(MakingExternalAsciiStringConditions) { 632 LocalContext env; 633 v8::HandleScope scope(env->GetIsolate()); 634 635 // Free some space in the new space so that we can check freshness. 636 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 637 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 638 639 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1"); 640 // We should refuse to externalize newly created small string. 641 CHECK(!small_string->CanMakeExternal()); 642 // Trigger GCs so that the newly allocated string moves to old gen. 643 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 644 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 645 // Old space strings should be accepted. 646 CHECK(small_string->CanMakeExternal()); 647 648 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2"); 649 // We should refuse externalizing newly created small string. 650 CHECK(!small_string->CanMakeExternal()); 651 for (int i = 0; i < 100; i++) { 652 String::Value value(small_string); 653 } 654 // Frequently used strings should be accepted. 655 CHECK(small_string->CanMakeExternal()); 656 657 const int buf_size = 10 * 1024; 658 char* buf = i::NewArray<char>(buf_size); 659 memset(buf, 'a', buf_size); 660 buf[buf_size - 1] = '\0'; 661 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf); 662 i::DeleteArray(buf); 663 // Large strings should be immediately accepted. 664 CHECK(large_string->CanMakeExternal()); 665 } 666 667 668 TEST(MakingExternalUnalignedAsciiString) { 669 LocalContext env; 670 v8::HandleScope scope(env->GetIsolate()); 671 672 CompileRun("function cons(a, b) { return a + b; }" 673 "function slice(a) { return a.substring(1); }"); 674 // Create a cons string that will land in old pointer space. 675 Local<String> cons = Local<String>::Cast(CompileRun( 676 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 677 // Create a sliced string that will land in old pointer space. 678 Local<String> slice = Local<String>::Cast(CompileRun( 679 "slice('abcdefghijklmnopqrstuvwxyz');")); 680 681 // Trigger GCs so that the newly allocated string moves to old gen. 682 SimulateFullSpace(CcTest::heap()->old_pointer_space()); 683 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 684 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 685 686 // Turn into external string with unaligned resource data. 687 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 688 bool success = cons->MakeExternal( 689 new TestAsciiResource(i::StrDup(c_cons), NULL, 1)); 690 CHECK(success); 691 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 692 success = slice->MakeExternal( 693 new TestAsciiResource(i::StrDup(c_slice), NULL, 1)); 694 CHECK(success); 695 696 // Trigger GCs and force evacuation. 697 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 698 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 699 } 700 701 702 THREADED_TEST(UsingExternalString) { 703 i::Factory* factory = CcTest::i_isolate()->factory(); 704 { 705 v8::HandleScope scope(CcTest::isolate()); 706 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 707 Local<String> string = String::NewExternal( 708 CcTest::isolate(), new TestResource(two_byte_string)); 709 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 710 // Trigger GCs so that the newly allocated string moves to old gen. 711 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 712 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 713 i::Handle<i::String> isymbol = 714 factory->InternalizeString(istring); 715 CHECK(isymbol->IsInternalizedString()); 716 } 717 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 718 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 719 } 720 721 722 THREADED_TEST(UsingExternalAsciiString) { 723 i::Factory* factory = CcTest::i_isolate()->factory(); 724 { 725 v8::HandleScope scope(CcTest::isolate()); 726 const char* one_byte_string = "test string"; 727 Local<String> string = String::NewExternal( 728 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string))); 729 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 730 // Trigger GCs so that the newly allocated string moves to old gen. 731 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 732 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 733 i::Handle<i::String> isymbol = 734 factory->InternalizeString(istring); 735 CHECK(isymbol->IsInternalizedString()); 736 } 737 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 738 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 739 } 740 741 742 THREADED_TEST(ScavengeExternalString) { 743 i::FLAG_stress_compaction = false; 744 i::FLAG_gc_global = false; 745 int dispose_count = 0; 746 bool in_new_space = false; 747 { 748 v8::HandleScope scope(CcTest::isolate()); 749 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 750 Local<String> string = String::NewExternal( 751 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count)); 752 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 753 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 754 in_new_space = CcTest::heap()->InNewSpace(*istring); 755 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 756 CHECK_EQ(0, dispose_count); 757 } 758 CcTest::heap()->CollectGarbage( 759 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 760 CHECK_EQ(1, dispose_count); 761 } 762 763 764 THREADED_TEST(ScavengeExternalAsciiString) { 765 i::FLAG_stress_compaction = false; 766 i::FLAG_gc_global = false; 767 int dispose_count = 0; 768 bool in_new_space = false; 769 { 770 v8::HandleScope scope(CcTest::isolate()); 771 const char* one_byte_string = "test string"; 772 Local<String> string = String::NewExternal( 773 CcTest::isolate(), 774 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count)); 775 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 776 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 777 in_new_space = CcTest::heap()->InNewSpace(*istring); 778 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 779 CHECK_EQ(0, dispose_count); 780 } 781 CcTest::heap()->CollectGarbage( 782 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 783 CHECK_EQ(1, dispose_count); 784 } 785 786 787 class TestAsciiResourceWithDisposeControl: public TestAsciiResource { 788 public: 789 // Only used by non-threaded tests, so it can use static fields. 790 static int dispose_calls; 791 static int dispose_count; 792 793 TestAsciiResourceWithDisposeControl(const char* data, bool dispose) 794 : TestAsciiResource(data, &dispose_count), 795 dispose_(dispose) { } 796 797 void Dispose() { 798 ++dispose_calls; 799 if (dispose_) delete this; 800 } 801 private: 802 bool dispose_; 803 }; 804 805 806 int TestAsciiResourceWithDisposeControl::dispose_count = 0; 807 int TestAsciiResourceWithDisposeControl::dispose_calls = 0; 808 809 810 TEST(ExternalStringWithDisposeHandling) { 811 const char* c_source = "1 + 2 * 3"; 812 813 // Use a stack allocated external string resource allocated object. 814 TestAsciiResourceWithDisposeControl::dispose_count = 0; 815 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 816 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 817 { 818 LocalContext env; 819 v8::HandleScope scope(env->GetIsolate()); 820 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack); 821 Local<Script> script = v8_compile(source); 822 Local<Value> value = script->Run(); 823 CHECK(value->IsNumber()); 824 CHECK_EQ(7, value->Int32Value()); 825 CcTest::heap()->CollectAllAvailableGarbage(); 826 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 827 } 828 CcTest::i_isolate()->compilation_cache()->Clear(); 829 CcTest::heap()->CollectAllAvailableGarbage(); 830 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 831 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 832 833 // Use a heap allocated external string resource allocated object. 834 TestAsciiResourceWithDisposeControl::dispose_count = 0; 835 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 836 TestAsciiResource* res_heap = 837 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true); 838 { 839 LocalContext env; 840 v8::HandleScope scope(env->GetIsolate()); 841 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap); 842 Local<Script> script = v8_compile(source); 843 Local<Value> value = script->Run(); 844 CHECK(value->IsNumber()); 845 CHECK_EQ(7, value->Int32Value()); 846 CcTest::heap()->CollectAllAvailableGarbage(); 847 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 848 } 849 CcTest::i_isolate()->compilation_cache()->Clear(); 850 CcTest::heap()->CollectAllAvailableGarbage(); 851 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 852 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count); 853 } 854 855 856 THREADED_TEST(StringConcat) { 857 { 858 LocalContext env; 859 v8::HandleScope scope(env->GetIsolate()); 860 const char* one_byte_string_1 = "function a_times_t"; 861 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 862 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 863 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 864 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 865 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 866 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 867 Local<String> left = v8_str(one_byte_string_1); 868 869 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 870 Local<String> right = 871 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 872 i::DeleteArray(two_byte_source); 873 874 Local<String> source = String::Concat(left, right); 875 right = String::NewExternal( 876 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1))); 877 source = String::Concat(source, right); 878 right = String::NewExternal( 879 env->GetIsolate(), 880 new TestResource(AsciiToTwoByteString(two_byte_extern_1))); 881 source = String::Concat(source, right); 882 right = v8_str(one_byte_string_2); 883 source = String::Concat(source, right); 884 885 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 886 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 887 i::DeleteArray(two_byte_source); 888 889 source = String::Concat(source, right); 890 right = String::NewExternal( 891 env->GetIsolate(), 892 new TestResource(AsciiToTwoByteString(two_byte_extern_2))); 893 source = String::Concat(source, right); 894 Local<Script> script = v8_compile(source); 895 Local<Value> value = script->Run(); 896 CHECK(value->IsNumber()); 897 CHECK_EQ(68, value->Int32Value()); 898 } 899 CcTest::i_isolate()->compilation_cache()->Clear(); 900 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 901 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 902 } 903 904 905 THREADED_TEST(GlobalProperties) { 906 LocalContext env; 907 v8::HandleScope scope(env->GetIsolate()); 908 v8::Handle<v8::Object> global = env->Global(); 909 global->Set(v8_str("pi"), v8_num(3.1415926)); 910 Local<Value> pi = global->Get(v8_str("pi")); 911 CHECK_EQ(3.1415926, pi->NumberValue()); 912 } 913 914 915 template<typename T> 916 static void CheckReturnValue(const T& t, i::Address callback) { 917 v8::ReturnValue<v8::Value> rv = t.GetReturnValue(); 918 i::Object** o = *reinterpret_cast<i::Object***>(&rv); 919 CHECK_EQ(CcTest::isolate(), t.GetIsolate()); 920 CHECK_EQ(t.GetIsolate(), rv.GetIsolate()); 921 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 922 // Verify reset 923 bool is_runtime = (*o)->IsTheHole(); 924 rv.Set(true); 925 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined()); 926 rv.Set(v8::Handle<v8::Object>()); 927 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 928 CHECK_EQ(is_runtime, (*o)->IsTheHole()); 929 930 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate()); 931 // If CPU profiler is active check that when API callback is invoked 932 // VMState is set to EXTERNAL. 933 if (isolate->cpu_profiler()->is_profiling()) { 934 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state()); 935 CHECK(isolate->external_callback_scope()); 936 CHECK_EQ(callback, isolate->external_callback_scope()->callback()); 937 } 938 } 939 940 941 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 942 i::Address callback) { 943 ApiTestFuzzer::Fuzz(); 944 CheckReturnValue(info, callback); 945 info.GetReturnValue().Set(v8_str("bad value")); 946 info.GetReturnValue().Set(v8_num(102)); 947 } 948 949 950 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 951 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 952 } 953 954 955 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 956 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 957 } 958 959 static void construct_callback( 960 const v8::FunctionCallbackInfo<Value>& info) { 961 ApiTestFuzzer::Fuzz(); 962 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 963 info.This()->Set(v8_str("x"), v8_num(1)); 964 info.This()->Set(v8_str("y"), v8_num(2)); 965 info.GetReturnValue().Set(v8_str("bad value")); 966 info.GetReturnValue().Set(info.This()); 967 } 968 969 970 static void Return239Callback( 971 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 972 ApiTestFuzzer::Fuzz(); 973 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 974 info.GetReturnValue().Set(v8_str("bad value")); 975 info.GetReturnValue().Set(v8_num(239)); 976 } 977 978 979 template<typename Handler> 980 static void TestFunctionTemplateInitializer(Handler handler, 981 Handler handler_2) { 982 // Test constructor calls. 983 { 984 LocalContext env; 985 v8::Isolate* isolate = env->GetIsolate(); 986 v8::HandleScope scope(isolate); 987 988 Local<v8::FunctionTemplate> fun_templ = 989 v8::FunctionTemplate::New(isolate, handler); 990 Local<Function> fun = fun_templ->GetFunction(); 991 env->Global()->Set(v8_str("obj"), fun); 992 Local<Script> script = v8_compile("obj()"); 993 for (int i = 0; i < 30; i++) { 994 CHECK_EQ(102, script->Run()->Int32Value()); 995 } 996 } 997 // Use SetCallHandler to initialize a function template, should work like 998 // the previous one. 999 { 1000 LocalContext env; 1001 v8::Isolate* isolate = env->GetIsolate(); 1002 v8::HandleScope scope(isolate); 1003 1004 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 1005 fun_templ->SetCallHandler(handler_2); 1006 Local<Function> fun = fun_templ->GetFunction(); 1007 env->Global()->Set(v8_str("obj"), fun); 1008 Local<Script> script = v8_compile("obj()"); 1009 for (int i = 0; i < 30; i++) { 1010 CHECK_EQ(102, script->Run()->Int32Value()); 1011 } 1012 } 1013 } 1014 1015 1016 template<typename Constructor, typename Accessor> 1017 static void TestFunctionTemplateAccessor(Constructor constructor, 1018 Accessor accessor) { 1019 LocalContext env; 1020 v8::HandleScope scope(env->GetIsolate()); 1021 1022 Local<v8::FunctionTemplate> fun_templ = 1023 v8::FunctionTemplate::New(env->GetIsolate(), constructor); 1024 fun_templ->SetClassName(v8_str("funky")); 1025 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 1026 Local<Function> fun = fun_templ->GetFunction(); 1027 env->Global()->Set(v8_str("obj"), fun); 1028 Local<Value> result = v8_compile("(new obj()).toString()")->Run(); 1029 CHECK_EQ(v8_str("[object funky]"), result); 1030 CompileRun("var obj_instance = new obj();"); 1031 Local<Script> script; 1032 script = v8_compile("obj_instance.x"); 1033 for (int i = 0; i < 30; i++) { 1034 CHECK_EQ(1, script->Run()->Int32Value()); 1035 } 1036 script = v8_compile("obj_instance.m"); 1037 for (int i = 0; i < 30; i++) { 1038 CHECK_EQ(239, script->Run()->Int32Value()); 1039 } 1040 } 1041 1042 1043 THREADED_PROFILED_TEST(FunctionTemplate) { 1044 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 1045 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 1046 } 1047 1048 1049 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1050 ApiTestFuzzer::Fuzz(); 1051 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1052 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1053 } 1054 1055 1056 template<typename Callback> 1057 static void TestSimpleCallback(Callback callback) { 1058 LocalContext env; 1059 v8::Isolate* isolate = env->GetIsolate(); 1060 v8::HandleScope scope(isolate); 1061 1062 v8::Handle<v8::ObjectTemplate> object_template = 1063 v8::ObjectTemplate::New(isolate); 1064 object_template->Set(isolate, "callback", 1065 v8::FunctionTemplate::New(isolate, callback)); 1066 v8::Local<v8::Object> object = object_template->NewInstance(); 1067 (*env)->Global()->Set(v8_str("callback_object"), object); 1068 v8::Handle<v8::Script> script; 1069 script = v8_compile("callback_object.callback(17)"); 1070 for (int i = 0; i < 30; i++) { 1071 CHECK_EQ(51424, script->Run()->Int32Value()); 1072 } 1073 script = v8_compile("callback_object.callback(17, 24)"); 1074 for (int i = 0; i < 30; i++) { 1075 CHECK_EQ(51425, script->Run()->Int32Value()); 1076 } 1077 } 1078 1079 1080 THREADED_PROFILED_TEST(SimpleCallback) { 1081 TestSimpleCallback(SimpleCallback); 1082 } 1083 1084 1085 template<typename T> 1086 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1087 1088 // constant return values 1089 static int32_t fast_return_value_int32 = 471; 1090 static uint32_t fast_return_value_uint32 = 571; 1091 static const double kFastReturnValueDouble = 2.7; 1092 // variable return values 1093 static bool fast_return_value_bool = false; 1094 enum ReturnValueOddball { 1095 kNullReturnValue, 1096 kUndefinedReturnValue, 1097 kEmptyStringReturnValue 1098 }; 1099 static ReturnValueOddball fast_return_value_void; 1100 static bool fast_return_value_object_is_empty = false; 1101 1102 // Helper function to avoid compiler error: insufficient contextual information 1103 // to determine type when applying FUNCTION_ADDR to a template function. 1104 static i::Address address_of(v8::FunctionCallback callback) { 1105 return FUNCTION_ADDR(callback); 1106 } 1107 1108 template<> 1109 void FastReturnValueCallback<int32_t>( 1110 const v8::FunctionCallbackInfo<v8::Value>& info) { 1111 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1112 info.GetReturnValue().Set(fast_return_value_int32); 1113 } 1114 1115 template<> 1116 void FastReturnValueCallback<uint32_t>( 1117 const v8::FunctionCallbackInfo<v8::Value>& info) { 1118 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1119 info.GetReturnValue().Set(fast_return_value_uint32); 1120 } 1121 1122 template<> 1123 void FastReturnValueCallback<double>( 1124 const v8::FunctionCallbackInfo<v8::Value>& info) { 1125 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1126 info.GetReturnValue().Set(kFastReturnValueDouble); 1127 } 1128 1129 template<> 1130 void FastReturnValueCallback<bool>( 1131 const v8::FunctionCallbackInfo<v8::Value>& info) { 1132 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1133 info.GetReturnValue().Set(fast_return_value_bool); 1134 } 1135 1136 template<> 1137 void FastReturnValueCallback<void>( 1138 const v8::FunctionCallbackInfo<v8::Value>& info) { 1139 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1140 switch (fast_return_value_void) { 1141 case kNullReturnValue: 1142 info.GetReturnValue().SetNull(); 1143 break; 1144 case kUndefinedReturnValue: 1145 info.GetReturnValue().SetUndefined(); 1146 break; 1147 case kEmptyStringReturnValue: 1148 info.GetReturnValue().SetEmptyString(); 1149 break; 1150 } 1151 } 1152 1153 template<> 1154 void FastReturnValueCallback<Object>( 1155 const v8::FunctionCallbackInfo<v8::Value>& info) { 1156 v8::Handle<v8::Object> object; 1157 if (!fast_return_value_object_is_empty) { 1158 object = Object::New(info.GetIsolate()); 1159 } 1160 info.GetReturnValue().Set(object); 1161 } 1162 1163 template<typename T> 1164 Handle<Value> TestFastReturnValues() { 1165 LocalContext env; 1166 v8::Isolate* isolate = env->GetIsolate(); 1167 v8::EscapableHandleScope scope(isolate); 1168 v8::Handle<v8::ObjectTemplate> object_template = 1169 v8::ObjectTemplate::New(isolate); 1170 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1171 object_template->Set(isolate, "callback", 1172 v8::FunctionTemplate::New(isolate, callback)); 1173 v8::Local<v8::Object> object = object_template->NewInstance(); 1174 (*env)->Global()->Set(v8_str("callback_object"), object); 1175 return scope.Escape(CompileRun("callback_object.callback()")); 1176 } 1177 1178 1179 THREADED_PROFILED_TEST(FastReturnValues) { 1180 LocalContext env; 1181 v8::HandleScope scope(CcTest::isolate()); 1182 v8::Handle<v8::Value> value; 1183 // check int32_t and uint32_t 1184 int32_t int_values[] = { 1185 0, 234, -723, 1186 i::Smi::kMinValue, i::Smi::kMaxValue 1187 }; 1188 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) { 1189 for (int modifier = -1; modifier <= 1; modifier++) { 1190 int int_value = int_values[i] + modifier; 1191 // check int32_t 1192 fast_return_value_int32 = int_value; 1193 value = TestFastReturnValues<int32_t>(); 1194 CHECK(value->IsInt32()); 1195 CHECK(fast_return_value_int32 == value->Int32Value()); 1196 // check uint32_t 1197 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1198 value = TestFastReturnValues<uint32_t>(); 1199 CHECK(value->IsUint32()); 1200 CHECK(fast_return_value_uint32 == value->Uint32Value()); 1201 } 1202 } 1203 // check double 1204 value = TestFastReturnValues<double>(); 1205 CHECK(value->IsNumber()); 1206 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value()); 1207 // check bool values 1208 for (int i = 0; i < 2; i++) { 1209 fast_return_value_bool = i == 0; 1210 value = TestFastReturnValues<bool>(); 1211 CHECK(value->IsBoolean()); 1212 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value()); 1213 } 1214 // check oddballs 1215 ReturnValueOddball oddballs[] = { 1216 kNullReturnValue, 1217 kUndefinedReturnValue, 1218 kEmptyStringReturnValue 1219 }; 1220 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) { 1221 fast_return_value_void = oddballs[i]; 1222 value = TestFastReturnValues<void>(); 1223 switch (fast_return_value_void) { 1224 case kNullReturnValue: 1225 CHECK(value->IsNull()); 1226 break; 1227 case kUndefinedReturnValue: 1228 CHECK(value->IsUndefined()); 1229 break; 1230 case kEmptyStringReturnValue: 1231 CHECK(value->IsString()); 1232 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1233 break; 1234 } 1235 } 1236 // check handles 1237 fast_return_value_object_is_empty = false; 1238 value = TestFastReturnValues<Object>(); 1239 CHECK(value->IsObject()); 1240 fast_return_value_object_is_empty = true; 1241 value = TestFastReturnValues<Object>(); 1242 CHECK(value->IsUndefined()); 1243 } 1244 1245 1246 THREADED_TEST(FunctionTemplateSetLength) { 1247 LocalContext env; 1248 v8::Isolate* isolate = env->GetIsolate(); 1249 v8::HandleScope scope(isolate); 1250 { 1251 Local<v8::FunctionTemplate> fun_templ = 1252 v8::FunctionTemplate::New(isolate, 1253 handle_callback, 1254 Handle<v8::Value>(), 1255 Handle<v8::Signature>(), 1256 23); 1257 Local<Function> fun = fun_templ->GetFunction(); 1258 env->Global()->Set(v8_str("obj"), fun); 1259 Local<Script> script = v8_compile("obj.length"); 1260 CHECK_EQ(23, script->Run()->Int32Value()); 1261 } 1262 { 1263 Local<v8::FunctionTemplate> fun_templ = 1264 v8::FunctionTemplate::New(isolate, handle_callback); 1265 fun_templ->SetLength(22); 1266 Local<Function> fun = fun_templ->GetFunction(); 1267 env->Global()->Set(v8_str("obj"), fun); 1268 Local<Script> script = v8_compile("obj.length"); 1269 CHECK_EQ(22, script->Run()->Int32Value()); 1270 } 1271 { 1272 // Without setting length it defaults to 0. 1273 Local<v8::FunctionTemplate> fun_templ = 1274 v8::FunctionTemplate::New(isolate, handle_callback); 1275 Local<Function> fun = fun_templ->GetFunction(); 1276 env->Global()->Set(v8_str("obj"), fun); 1277 Local<Script> script = v8_compile("obj.length"); 1278 CHECK_EQ(0, script->Run()->Int32Value()); 1279 } 1280 } 1281 1282 1283 static void* expected_ptr; 1284 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1285 void* ptr = v8::External::Cast(*args.Data())->Value(); 1286 CHECK_EQ(expected_ptr, ptr); 1287 args.GetReturnValue().Set(true); 1288 } 1289 1290 1291 static void TestExternalPointerWrapping() { 1292 LocalContext env; 1293 v8::Isolate* isolate = env->GetIsolate(); 1294 v8::HandleScope scope(isolate); 1295 1296 v8::Handle<v8::Value> data = 1297 v8::External::New(isolate, expected_ptr); 1298 1299 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 1300 obj->Set(v8_str("func"), 1301 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction()); 1302 env->Global()->Set(v8_str("obj"), obj); 1303 1304 CHECK(CompileRun( 1305 "function foo() {\n" 1306 " for (var i = 0; i < 13; i++) obj.func();\n" 1307 "}\n" 1308 "foo(), true")->BooleanValue()); 1309 } 1310 1311 1312 THREADED_TEST(ExternalWrap) { 1313 // Check heap allocated object. 1314 int* ptr = new int; 1315 expected_ptr = ptr; 1316 TestExternalPointerWrapping(); 1317 delete ptr; 1318 1319 // Check stack allocated object. 1320 int foo; 1321 expected_ptr = &foo; 1322 TestExternalPointerWrapping(); 1323 1324 // Check not aligned addresses. 1325 const int n = 100; 1326 char* s = new char[n]; 1327 for (int i = 0; i < n; i++) { 1328 expected_ptr = s + i; 1329 TestExternalPointerWrapping(); 1330 } 1331 1332 delete[] s; 1333 1334 // Check several invalid addresses. 1335 expected_ptr = reinterpret_cast<void*>(1); 1336 TestExternalPointerWrapping(); 1337 1338 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1339 TestExternalPointerWrapping(); 1340 1341 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1342 TestExternalPointerWrapping(); 1343 1344 #if defined(V8_HOST_ARCH_X64) 1345 // Check a value with a leading 1 bit in x64 Smi encoding. 1346 expected_ptr = reinterpret_cast<void*>(0x400000000); 1347 TestExternalPointerWrapping(); 1348 1349 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1350 TestExternalPointerWrapping(); 1351 1352 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1353 TestExternalPointerWrapping(); 1354 #endif 1355 } 1356 1357 1358 THREADED_TEST(FindInstanceInPrototypeChain) { 1359 LocalContext env; 1360 v8::Isolate* isolate = env->GetIsolate(); 1361 v8::HandleScope scope(isolate); 1362 1363 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate); 1364 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate); 1365 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate); 1366 derived->Inherit(base); 1367 1368 Local<v8::Function> base_function = base->GetFunction(); 1369 Local<v8::Function> derived_function = derived->GetFunction(); 1370 Local<v8::Function> other_function = other->GetFunction(); 1371 1372 Local<v8::Object> base_instance = base_function->NewInstance(); 1373 Local<v8::Object> derived_instance = derived_function->NewInstance(); 1374 Local<v8::Object> derived_instance2 = derived_function->NewInstance(); 1375 Local<v8::Object> other_instance = other_function->NewInstance(); 1376 derived_instance2->Set(v8_str("__proto__"), derived_instance); 1377 other_instance->Set(v8_str("__proto__"), derived_instance2); 1378 1379 // base_instance is only an instance of base. 1380 CHECK_EQ(base_instance, 1381 base_instance->FindInstanceInPrototypeChain(base)); 1382 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1383 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1384 1385 // derived_instance is an instance of base and derived. 1386 CHECK_EQ(derived_instance, 1387 derived_instance->FindInstanceInPrototypeChain(base)); 1388 CHECK_EQ(derived_instance, 1389 derived_instance->FindInstanceInPrototypeChain(derived)); 1390 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1391 1392 // other_instance is an instance of other and its immediate 1393 // prototype derived_instance2 is an instance of base and derived. 1394 // Note, derived_instance is an instance of base and derived too, 1395 // but it comes after derived_instance2 in the prototype chain of 1396 // other_instance. 1397 CHECK_EQ(derived_instance2, 1398 other_instance->FindInstanceInPrototypeChain(base)); 1399 CHECK_EQ(derived_instance2, 1400 other_instance->FindInstanceInPrototypeChain(derived)); 1401 CHECK_EQ(other_instance, 1402 other_instance->FindInstanceInPrototypeChain(other)); 1403 } 1404 1405 1406 THREADED_TEST(TinyInteger) { 1407 LocalContext env; 1408 v8::Isolate* isolate = env->GetIsolate(); 1409 v8::HandleScope scope(isolate); 1410 1411 int32_t value = 239; 1412 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1413 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1414 1415 value_obj = v8::Integer::New(isolate, value); 1416 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1417 } 1418 1419 1420 THREADED_TEST(BigSmiInteger) { 1421 LocalContext env; 1422 v8::HandleScope scope(env->GetIsolate()); 1423 v8::Isolate* isolate = CcTest::isolate(); 1424 1425 int32_t value = i::Smi::kMaxValue; 1426 // We cannot add one to a Smi::kMaxValue without wrapping. 1427 if (i::SmiValuesAre31Bits()) { 1428 CHECK(i::Smi::IsValid(value)); 1429 CHECK(!i::Smi::IsValid(value + 1)); 1430 1431 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1432 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1433 1434 value_obj = v8::Integer::New(isolate, value); 1435 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1436 } 1437 } 1438 1439 1440 THREADED_TEST(BigInteger) { 1441 LocalContext env; 1442 v8::HandleScope scope(env->GetIsolate()); 1443 v8::Isolate* isolate = CcTest::isolate(); 1444 1445 // We cannot add one to a Smi::kMaxValue without wrapping. 1446 if (i::SmiValuesAre31Bits()) { 1447 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1448 // The code will not be run in that case, due to the "if" guard. 1449 int32_t value = 1450 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1451 CHECK(value > i::Smi::kMaxValue); 1452 CHECK(!i::Smi::IsValid(value)); 1453 1454 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1455 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1456 1457 value_obj = v8::Integer::New(isolate, value); 1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1459 } 1460 } 1461 1462 1463 THREADED_TEST(TinyUnsignedInteger) { 1464 LocalContext env; 1465 v8::HandleScope scope(env->GetIsolate()); 1466 v8::Isolate* isolate = CcTest::isolate(); 1467 1468 uint32_t value = 239; 1469 1470 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1471 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1472 1473 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1474 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1475 } 1476 1477 1478 THREADED_TEST(BigUnsignedSmiInteger) { 1479 LocalContext env; 1480 v8::HandleScope scope(env->GetIsolate()); 1481 v8::Isolate* isolate = CcTest::isolate(); 1482 1483 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1484 CHECK(i::Smi::IsValid(value)); 1485 CHECK(!i::Smi::IsValid(value + 1)); 1486 1487 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1488 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1489 1490 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1491 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1492 } 1493 1494 1495 THREADED_TEST(BigUnsignedInteger) { 1496 LocalContext env; 1497 v8::HandleScope scope(env->GetIsolate()); 1498 v8::Isolate* isolate = CcTest::isolate(); 1499 1500 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1501 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1502 CHECK(!i::Smi::IsValid(value)); 1503 1504 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1505 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1506 1507 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1509 } 1510 1511 1512 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1513 LocalContext env; 1514 v8::HandleScope scope(env->GetIsolate()); 1515 v8::Isolate* isolate = CcTest::isolate(); 1516 1517 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1518 uint32_t value = INT32_MAX_AS_UINT + 1; 1519 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1520 1521 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1522 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1523 1524 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1525 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1526 } 1527 1528 1529 THREADED_TEST(IsNativeError) { 1530 LocalContext env; 1531 v8::HandleScope scope(env->GetIsolate()); 1532 v8::Handle<Value> syntax_error = CompileRun( 1533 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1534 CHECK(syntax_error->IsNativeError()); 1535 v8::Handle<Value> not_error = CompileRun("{a:42}"); 1536 CHECK(!not_error->IsNativeError()); 1537 v8::Handle<Value> not_object = CompileRun("42"); 1538 CHECK(!not_object->IsNativeError()); 1539 } 1540 1541 1542 THREADED_TEST(StringObject) { 1543 LocalContext env; 1544 v8::HandleScope scope(env->GetIsolate()); 1545 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); 1546 CHECK(boxed_string->IsStringObject()); 1547 v8::Handle<Value> unboxed_string = CompileRun("\"test\""); 1548 CHECK(!unboxed_string->IsStringObject()); 1549 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); 1550 CHECK(!boxed_not_string->IsStringObject()); 1551 v8::Handle<Value> not_object = CompileRun("0"); 1552 CHECK(!not_object->IsStringObject()); 1553 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1554 CHECK(!as_boxed.IsEmpty()); 1555 Local<v8::String> the_string = as_boxed->ValueOf(); 1556 CHECK(!the_string.IsEmpty()); 1557 ExpectObject("\"test\"", the_string); 1558 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1559 CHECK(new_boxed_string->IsStringObject()); 1560 as_boxed = new_boxed_string.As<v8::StringObject>(); 1561 the_string = as_boxed->ValueOf(); 1562 CHECK(!the_string.IsEmpty()); 1563 ExpectObject("\"test\"", the_string); 1564 } 1565 1566 1567 THREADED_TEST(NumberObject) { 1568 LocalContext env; 1569 v8::HandleScope scope(env->GetIsolate()); 1570 v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); 1571 CHECK(boxed_number->IsNumberObject()); 1572 v8::Handle<Value> unboxed_number = CompileRun("42"); 1573 CHECK(!unboxed_number->IsNumberObject()); 1574 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1575 CHECK(!boxed_not_number->IsNumberObject()); 1576 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1577 CHECK(!as_boxed.IsEmpty()); 1578 double the_number = as_boxed->ValueOf(); 1579 CHECK_EQ(42.0, the_number); 1580 v8::Handle<v8::Value> new_boxed_number = 1581 v8::NumberObject::New(env->GetIsolate(), 43); 1582 CHECK(new_boxed_number->IsNumberObject()); 1583 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1584 the_number = as_boxed->ValueOf(); 1585 CHECK_EQ(43.0, the_number); 1586 } 1587 1588 1589 THREADED_TEST(BooleanObject) { 1590 LocalContext env; 1591 v8::HandleScope scope(env->GetIsolate()); 1592 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1593 CHECK(boxed_boolean->IsBooleanObject()); 1594 v8::Handle<Value> unboxed_boolean = CompileRun("true"); 1595 CHECK(!unboxed_boolean->IsBooleanObject()); 1596 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1597 CHECK(!boxed_not_boolean->IsBooleanObject()); 1598 v8::Handle<v8::BooleanObject> as_boxed = 1599 boxed_boolean.As<v8::BooleanObject>(); 1600 CHECK(!as_boxed.IsEmpty()); 1601 bool the_boolean = as_boxed->ValueOf(); 1602 CHECK_EQ(true, the_boolean); 1603 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); 1604 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); 1605 CHECK(boxed_true->IsBooleanObject()); 1606 CHECK(boxed_false->IsBooleanObject()); 1607 as_boxed = boxed_true.As<v8::BooleanObject>(); 1608 CHECK_EQ(true, as_boxed->ValueOf()); 1609 as_boxed = boxed_false.As<v8::BooleanObject>(); 1610 CHECK_EQ(false, as_boxed->ValueOf()); 1611 } 1612 1613 1614 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1615 LocalContext env; 1616 v8::HandleScope scope(env->GetIsolate()); 1617 1618 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); 1619 CHECK(primitive_false->IsBoolean()); 1620 CHECK(!primitive_false->IsBooleanObject()); 1621 CHECK(!primitive_false->BooleanValue()); 1622 CHECK(!primitive_false->IsTrue()); 1623 CHECK(primitive_false->IsFalse()); 1624 1625 Local<Value> false_value = BooleanObject::New(false); 1626 CHECK(!false_value->IsBoolean()); 1627 CHECK(false_value->IsBooleanObject()); 1628 CHECK(false_value->BooleanValue()); 1629 CHECK(!false_value->IsTrue()); 1630 CHECK(!false_value->IsFalse()); 1631 1632 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1633 CHECK(!false_boolean_object->IsBoolean()); 1634 CHECK(false_boolean_object->IsBooleanObject()); 1635 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1636 // CHECK(false_boolean_object->BooleanValue()); 1637 CHECK(!false_boolean_object->ValueOf()); 1638 CHECK(!false_boolean_object->IsTrue()); 1639 CHECK(!false_boolean_object->IsFalse()); 1640 1641 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); 1642 CHECK(primitive_true->IsBoolean()); 1643 CHECK(!primitive_true->IsBooleanObject()); 1644 CHECK(primitive_true->BooleanValue()); 1645 CHECK(primitive_true->IsTrue()); 1646 CHECK(!primitive_true->IsFalse()); 1647 1648 Local<Value> true_value = BooleanObject::New(true); 1649 CHECK(!true_value->IsBoolean()); 1650 CHECK(true_value->IsBooleanObject()); 1651 CHECK(true_value->BooleanValue()); 1652 CHECK(!true_value->IsTrue()); 1653 CHECK(!true_value->IsFalse()); 1654 1655 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1656 CHECK(!true_boolean_object->IsBoolean()); 1657 CHECK(true_boolean_object->IsBooleanObject()); 1658 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1659 // CHECK(true_boolean_object->BooleanValue()); 1660 CHECK(true_boolean_object->ValueOf()); 1661 CHECK(!true_boolean_object->IsTrue()); 1662 CHECK(!true_boolean_object->IsFalse()); 1663 } 1664 1665 1666 THREADED_TEST(Number) { 1667 LocalContext env; 1668 v8::HandleScope scope(env->GetIsolate()); 1669 double PI = 3.1415926; 1670 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI); 1671 CHECK_EQ(PI, pi_obj->NumberValue()); 1672 } 1673 1674 1675 THREADED_TEST(ToNumber) { 1676 LocalContext env; 1677 v8::Isolate* isolate = CcTest::isolate(); 1678 v8::HandleScope scope(isolate); 1679 Local<String> str = v8_str("3.1415926"); 1680 CHECK_EQ(3.1415926, str->NumberValue()); 1681 v8::Handle<v8::Boolean> t = v8::True(isolate); 1682 CHECK_EQ(1.0, t->NumberValue()); 1683 v8::Handle<v8::Boolean> f = v8::False(isolate); 1684 CHECK_EQ(0.0, f->NumberValue()); 1685 } 1686 1687 1688 THREADED_TEST(Date) { 1689 LocalContext env; 1690 v8::HandleScope scope(env->GetIsolate()); 1691 double PI = 3.1415926; 1692 Local<Value> date = v8::Date::New(env->GetIsolate(), PI); 1693 CHECK_EQ(3.0, date->NumberValue()); 1694 date.As<v8::Date>()->Set(v8_str("property"), 1695 v8::Integer::New(env->GetIsolate(), 42)); 1696 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value()); 1697 } 1698 1699 1700 THREADED_TEST(Boolean) { 1701 LocalContext env; 1702 v8::Isolate* isolate = env->GetIsolate(); 1703 v8::HandleScope scope(isolate); 1704 v8::Handle<v8::Boolean> t = v8::True(isolate); 1705 CHECK(t->Value()); 1706 v8::Handle<v8::Boolean> f = v8::False(isolate); 1707 CHECK(!f->Value()); 1708 v8::Handle<v8::Primitive> u = v8::Undefined(isolate); 1709 CHECK(!u->BooleanValue()); 1710 v8::Handle<v8::Primitive> n = v8::Null(isolate); 1711 CHECK(!n->BooleanValue()); 1712 v8::Handle<String> str1 = v8_str(""); 1713 CHECK(!str1->BooleanValue()); 1714 v8::Handle<String> str2 = v8_str("x"); 1715 CHECK(str2->BooleanValue()); 1716 CHECK(!v8::Number::New(isolate, 0)->BooleanValue()); 1717 CHECK(v8::Number::New(isolate, -1)->BooleanValue()); 1718 CHECK(v8::Number::New(isolate, 1)->BooleanValue()); 1719 CHECK(v8::Number::New(isolate, 42)->BooleanValue()); 1720 CHECK(!v8_compile("NaN")->Run()->BooleanValue()); 1721 } 1722 1723 1724 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1725 ApiTestFuzzer::Fuzz(); 1726 args.GetReturnValue().Set(v8_num(13.4)); 1727 } 1728 1729 1730 static void GetM(Local<String> name, 1731 const v8::PropertyCallbackInfo<v8::Value>& info) { 1732 ApiTestFuzzer::Fuzz(); 1733 info.GetReturnValue().Set(v8_num(876)); 1734 } 1735 1736 1737 THREADED_TEST(GlobalPrototype) { 1738 v8::Isolate* isolate = CcTest::isolate(); 1739 v8::HandleScope scope(isolate); 1740 v8::Handle<v8::FunctionTemplate> func_templ = 1741 v8::FunctionTemplate::New(isolate); 1742 func_templ->PrototypeTemplate()->Set( 1743 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler)); 1744 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1745 templ->Set(isolate, "x", v8_num(200)); 1746 templ->SetAccessor(v8_str("m"), GetM); 1747 LocalContext env(0, templ); 1748 v8::Handle<Script> script(v8_compile("dummy()")); 1749 v8::Handle<Value> result(script->Run()); 1750 CHECK_EQ(13.4, result->NumberValue()); 1751 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); 1752 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value()); 1753 } 1754 1755 1756 THREADED_TEST(ObjectTemplate) { 1757 v8::Isolate* isolate = CcTest::isolate(); 1758 v8::HandleScope scope(isolate); 1759 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate); 1760 templ1->Set(isolate, "x", v8_num(10)); 1761 templ1->Set(isolate, "y", v8_num(13)); 1762 LocalContext env; 1763 Local<v8::Object> instance1 = templ1->NewInstance(); 1764 env->Global()->Set(v8_str("p"), instance1); 1765 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); 1766 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); 1767 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 1768 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); 1769 Local<ObjectTemplate> templ2 = fun->InstanceTemplate(); 1770 templ2->Set(isolate, "a", v8_num(12)); 1771 templ2->Set(isolate, "b", templ1); 1772 Local<v8::Object> instance2 = templ2->NewInstance(); 1773 env->Global()->Set(v8_str("q"), instance2); 1774 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); 1775 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); 1776 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); 1777 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue()); 1778 } 1779 1780 1781 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 1782 ApiTestFuzzer::Fuzz(); 1783 args.GetReturnValue().Set(v8_num(17.2)); 1784 } 1785 1786 1787 static void GetKnurd(Local<String> property, 1788 const v8::PropertyCallbackInfo<v8::Value>& info) { 1789 ApiTestFuzzer::Fuzz(); 1790 info.GetReturnValue().Set(v8_num(15.2)); 1791 } 1792 1793 1794 THREADED_TEST(DescriptorInheritance) { 1795 v8::Isolate* isolate = CcTest::isolate(); 1796 v8::HandleScope scope(isolate); 1797 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate); 1798 super->PrototypeTemplate()->Set(isolate, "flabby", 1799 v8::FunctionTemplate::New(isolate, 1800 GetFlabby)); 1801 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14)); 1802 1803 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1804 1805 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate); 1806 base1->Inherit(super); 1807 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1)); 1808 1809 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate); 1810 base2->Inherit(super); 1811 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1)); 1812 1813 LocalContext env; 1814 1815 env->Global()->Set(v8_str("s"), super->GetFunction()); 1816 env->Global()->Set(v8_str("base1"), base1->GetFunction()); 1817 env->Global()->Set(v8_str("base2"), base2->GetFunction()); 1818 1819 // Checks right __proto__ chain. 1820 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); 1821 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); 1822 1823 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); 1824 1825 // Instance accessor should not be visible on function object or its prototype 1826 CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); 1827 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); 1828 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); 1829 1830 env->Global()->Set(v8_str("obj"), 1831 base1->GetFunction()->NewInstance()); 1832 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); 1833 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); 1834 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); 1835 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); 1836 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); 1837 1838 env->Global()->Set(v8_str("obj2"), 1839 base2->GetFunction()->NewInstance()); 1840 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); 1841 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); 1842 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); 1843 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); 1844 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); 1845 1846 // base1 and base2 cannot cross reference to each's prototype 1847 CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); 1848 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined()); 1849 } 1850 1851 1852 int echo_named_call_count; 1853 1854 1855 static void EchoNamedProperty(Local<String> name, 1856 const v8::PropertyCallbackInfo<v8::Value>& info) { 1857 ApiTestFuzzer::Fuzz(); 1858 CHECK_EQ(v8_str("data"), info.Data()); 1859 echo_named_call_count++; 1860 info.GetReturnValue().Set(name); 1861 } 1862 1863 1864 // Helper functions for Interceptor/Accessor interaction tests 1865 1866 void SimpleAccessorGetter(Local<String> name, 1867 const v8::PropertyCallbackInfo<v8::Value>& info) { 1868 Handle<Object> self = Handle<Object>::Cast(info.This()); 1869 info.GetReturnValue().Set( 1870 self->Get(String::Concat(v8_str("accessor_"), name))); 1871 } 1872 1873 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 1874 const v8::PropertyCallbackInfo<void>& info) { 1875 Handle<Object> self = Handle<Object>::Cast(info.This()); 1876 self->Set(String::Concat(v8_str("accessor_"), name), value); 1877 } 1878 1879 void EmptyInterceptorGetter(Local<String> name, 1880 const v8::PropertyCallbackInfo<v8::Value>& info) { 1881 } 1882 1883 void EmptyInterceptorSetter(Local<String> name, 1884 Local<Value> value, 1885 const v8::PropertyCallbackInfo<v8::Value>& info) { 1886 } 1887 1888 void InterceptorGetter(Local<String> name, 1889 const v8::PropertyCallbackInfo<v8::Value>& info) { 1890 // Intercept names that start with 'interceptor_'. 1891 String::Utf8Value utf8(name); 1892 char* name_str = *utf8; 1893 char prefix[] = "interceptor_"; 1894 int i; 1895 for (i = 0; name_str[i] && prefix[i]; ++i) { 1896 if (name_str[i] != prefix[i]) return; 1897 } 1898 Handle<Object> self = Handle<Object>::Cast(info.This()); 1899 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i))); 1900 } 1901 1902 void InterceptorSetter(Local<String> name, 1903 Local<Value> value, 1904 const v8::PropertyCallbackInfo<v8::Value>& info) { 1905 // Intercept accesses that set certain integer values, for which the name does 1906 // not start with 'accessor_'. 1907 String::Utf8Value utf8(name); 1908 char* name_str = *utf8; 1909 char prefix[] = "accessor_"; 1910 int i; 1911 for (i = 0; name_str[i] && prefix[i]; ++i) { 1912 if (name_str[i] != prefix[i]) break; 1913 } 1914 if (!prefix[i]) return; 1915 1916 if (value->IsInt32() && value->Int32Value() < 10000) { 1917 Handle<Object> self = Handle<Object>::Cast(info.This()); 1918 self->SetHiddenValue(name, value); 1919 info.GetReturnValue().Set(value); 1920 } 1921 } 1922 1923 void AddAccessor(Handle<FunctionTemplate> templ, 1924 Handle<String> name, 1925 v8::AccessorGetterCallback getter, 1926 v8::AccessorSetterCallback setter) { 1927 templ->PrototypeTemplate()->SetAccessor(name, getter, setter); 1928 } 1929 1930 void AddInterceptor(Handle<FunctionTemplate> templ, 1931 v8::NamedPropertyGetterCallback getter, 1932 v8::NamedPropertySetterCallback setter) { 1933 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter); 1934 } 1935 1936 1937 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { 1938 v8::HandleScope scope(CcTest::isolate()); 1939 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 1940 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 1941 child->Inherit(parent); 1942 AddAccessor(parent, v8_str("age"), 1943 SimpleAccessorGetter, SimpleAccessorSetter); 1944 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1945 LocalContext env; 1946 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1947 CompileRun("var child = new Child;" 1948 "child.age = 10;"); 1949 ExpectBoolean("child.hasOwnProperty('age')", false); 1950 ExpectInt32("child.age", 10); 1951 ExpectInt32("child.accessor_age", 10); 1952 } 1953 1954 1955 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { 1956 v8::Isolate* isolate = CcTest::isolate(); 1957 v8::HandleScope scope(isolate); 1958 LocalContext env; 1959 v8::Local<v8::Value> res = CompileRun("var a = []; a;"); 1960 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); 1961 CHECK(a->map()->instance_descriptors()->IsFixedArray()); 1962 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 1963 CompileRun("Object.defineProperty(a, 'length', { writable: false });"); 1964 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 1965 // But we should still have an ExecutableAccessorInfo. 1966 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 1967 i::LookupResult lookup(i_isolate); 1968 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); 1969 a->LookupOwnRealNamedProperty(name, &lookup); 1970 CHECK(lookup.IsPropertyCallbacks()); 1971 i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate); 1972 CHECK(callback->IsExecutableAccessorInfo()); 1973 } 1974 1975 1976 THREADED_TEST(EmptyInterceptorBreakTransitions) { 1977 v8::HandleScope scope(CcTest::isolate()); 1978 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 1979 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 1980 LocalContext env; 1981 env->Global()->Set(v8_str("Constructor"), templ->GetFunction()); 1982 CompileRun("var o1 = new Constructor;" 1983 "o1.a = 1;" // Ensure a and x share the descriptor array. 1984 "Object.defineProperty(o1, 'x', {value: 10});"); 1985 CompileRun("var o2 = new Constructor;" 1986 "o2.a = 1;" 1987 "Object.defineProperty(o2, 'x', {value: 10});"); 1988 } 1989 1990 1991 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) { 1992 v8::Isolate* isolate = CcTest::isolate(); 1993 v8::HandleScope scope(isolate); 1994 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate); 1995 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate); 1996 child->Inherit(parent); 1997 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1998 LocalContext env; 1999 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2000 CompileRun("var child = new Child;" 2001 "var parent = child.__proto__;" 2002 "Object.defineProperty(parent, 'age', " 2003 " {get: function(){ return this.accessor_age; }, " 2004 " set: function(v){ this.accessor_age = v; }, " 2005 " enumerable: true, configurable: true});" 2006 "child.age = 10;"); 2007 ExpectBoolean("child.hasOwnProperty('age')", false); 2008 ExpectInt32("child.age", 10); 2009 ExpectInt32("child.accessor_age", 10); 2010 } 2011 2012 2013 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) { 2014 v8::Isolate* isolate = CcTest::isolate(); 2015 v8::HandleScope scope(isolate); 2016 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate); 2017 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate); 2018 child->Inherit(parent); 2019 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 2020 LocalContext env; 2021 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2022 CompileRun("var child = new Child;" 2023 "var parent = child.__proto__;" 2024 "parent.name = 'Alice';"); 2025 ExpectBoolean("child.hasOwnProperty('name')", false); 2026 ExpectString("child.name", "Alice"); 2027 CompileRun("child.name = 'Bob';"); 2028 ExpectString("child.name", "Bob"); 2029 ExpectBoolean("child.hasOwnProperty('name')", true); 2030 ExpectString("parent.name", "Alice"); 2031 } 2032 2033 2034 THREADED_TEST(SwitchFromInterceptorToAccessor) { 2035 v8::HandleScope scope(CcTest::isolate()); 2036 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2037 AddAccessor(templ, v8_str("age"), 2038 SimpleAccessorGetter, SimpleAccessorSetter); 2039 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2040 LocalContext env; 2041 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2042 CompileRun("var obj = new Obj;" 2043 "function setAge(i){ obj.age = i; };" 2044 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2045 // All i < 10000 go to the interceptor. 2046 ExpectInt32("obj.interceptor_age", 9999); 2047 // The last i goes to the accessor. 2048 ExpectInt32("obj.accessor_age", 10000); 2049 } 2050 2051 2052 THREADED_TEST(SwitchFromAccessorToInterceptor) { 2053 v8::HandleScope scope(CcTest::isolate()); 2054 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2055 AddAccessor(templ, v8_str("age"), 2056 SimpleAccessorGetter, SimpleAccessorSetter); 2057 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2058 LocalContext env; 2059 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2060 CompileRun("var obj = new Obj;" 2061 "function setAge(i){ obj.age = i; };" 2062 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2063 // All i >= 10000 go to the accessor. 2064 ExpectInt32("obj.accessor_age", 10000); 2065 // The last i goes to the interceptor. 2066 ExpectInt32("obj.interceptor_age", 9999); 2067 } 2068 2069 2070 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) { 2071 v8::HandleScope scope(CcTest::isolate()); 2072 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2073 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2074 child->Inherit(parent); 2075 AddAccessor(parent, v8_str("age"), 2076 SimpleAccessorGetter, SimpleAccessorSetter); 2077 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2078 LocalContext env; 2079 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2080 CompileRun("var child = new Child;" 2081 "function setAge(i){ child.age = i; };" 2082 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2083 // All i < 10000 go to the interceptor. 2084 ExpectInt32("child.interceptor_age", 9999); 2085 // The last i goes to the accessor. 2086 ExpectInt32("child.accessor_age", 10000); 2087 } 2088 2089 2090 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) { 2091 v8::HandleScope scope(CcTest::isolate()); 2092 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2093 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2094 child->Inherit(parent); 2095 AddAccessor(parent, v8_str("age"), 2096 SimpleAccessorGetter, SimpleAccessorSetter); 2097 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2098 LocalContext env; 2099 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2100 CompileRun("var child = new Child;" 2101 "function setAge(i){ child.age = i; };" 2102 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2103 // All i >= 10000 go to the accessor. 2104 ExpectInt32("child.accessor_age", 10000); 2105 // The last i goes to the interceptor. 2106 ExpectInt32("child.interceptor_age", 9999); 2107 } 2108 2109 2110 THREADED_TEST(SwitchFromInterceptorToJSAccessor) { 2111 v8::HandleScope scope(CcTest::isolate()); 2112 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2113 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2114 LocalContext env; 2115 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2116 CompileRun("var obj = new Obj;" 2117 "function setter(i) { this.accessor_age = i; };" 2118 "function getter() { return this.accessor_age; };" 2119 "function setAge(i) { obj.age = i; };" 2120 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2121 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2122 // All i < 10000 go to the interceptor. 2123 ExpectInt32("obj.interceptor_age", 9999); 2124 // The last i goes to the JavaScript accessor. 2125 ExpectInt32("obj.accessor_age", 10000); 2126 // The installed JavaScript getter is still intact. 2127 // This last part is a regression test for issue 1651 and relies on the fact 2128 // that both interceptor and accessor are being installed on the same object. 2129 ExpectInt32("obj.age", 10000); 2130 ExpectBoolean("obj.hasOwnProperty('age')", true); 2131 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2132 } 2133 2134 2135 THREADED_TEST(SwitchFromJSAccessorToInterceptor) { 2136 v8::HandleScope scope(CcTest::isolate()); 2137 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2138 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2139 LocalContext env; 2140 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2141 CompileRun("var obj = new Obj;" 2142 "function setter(i) { this.accessor_age = i; };" 2143 "function getter() { return this.accessor_age; };" 2144 "function setAge(i) { obj.age = i; };" 2145 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2146 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2147 // All i >= 10000 go to the accessor. 2148 ExpectInt32("obj.accessor_age", 10000); 2149 // The last i goes to the interceptor. 2150 ExpectInt32("obj.interceptor_age", 9999); 2151 // The installed JavaScript getter is still intact. 2152 // This last part is a regression test for issue 1651 and relies on the fact 2153 // that both interceptor and accessor are being installed on the same object. 2154 ExpectInt32("obj.age", 10000); 2155 ExpectBoolean("obj.hasOwnProperty('age')", true); 2156 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2157 } 2158 2159 2160 THREADED_TEST(SwitchFromInterceptorToProperty) { 2161 v8::HandleScope scope(CcTest::isolate()); 2162 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2163 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2164 child->Inherit(parent); 2165 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2166 LocalContext env; 2167 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2168 CompileRun("var child = new Child;" 2169 "function setAge(i){ child.age = i; };" 2170 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2171 // All i < 10000 go to the interceptor. 2172 ExpectInt32("child.interceptor_age", 9999); 2173 // The last i goes to child's own property. 2174 ExpectInt32("child.age", 10000); 2175 } 2176 2177 2178 THREADED_TEST(SwitchFromPropertyToInterceptor) { 2179 v8::HandleScope scope(CcTest::isolate()); 2180 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2181 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2182 child->Inherit(parent); 2183 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2184 LocalContext env; 2185 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2186 CompileRun("var child = new Child;" 2187 "function setAge(i){ child.age = i; };" 2188 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2189 // All i >= 10000 go to child's own property. 2190 ExpectInt32("child.age", 10000); 2191 // The last i goes to the interceptor. 2192 ExpectInt32("child.interceptor_age", 9999); 2193 } 2194 2195 2196 THREADED_TEST(NamedPropertyHandlerGetter) { 2197 echo_named_call_count = 0; 2198 v8::HandleScope scope(CcTest::isolate()); 2199 v8::Handle<v8::FunctionTemplate> templ = 2200 v8::FunctionTemplate::New(CcTest::isolate()); 2201 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty, 2202 0, 0, 0, 0, 2203 v8_str("data")); 2204 LocalContext env; 2205 env->Global()->Set(v8_str("obj"), 2206 templ->GetFunction()->NewInstance()); 2207 CHECK_EQ(echo_named_call_count, 0); 2208 v8_compile("obj.x")->Run(); 2209 CHECK_EQ(echo_named_call_count, 1); 2210 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;"; 2211 v8::Handle<Value> str = CompileRun(code); 2212 String::Utf8Value value(str); 2213 CHECK_EQ(*value, "oddlepoddle"); 2214 // Check default behavior 2215 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10); 2216 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue()); 2217 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); 2218 } 2219 2220 2221 int echo_indexed_call_count = 0; 2222 2223 2224 static void EchoIndexedProperty( 2225 uint32_t index, 2226 const v8::PropertyCallbackInfo<v8::Value>& info) { 2227 ApiTestFuzzer::Fuzz(); 2228 CHECK_EQ(v8_num(637), info.Data()); 2229 echo_indexed_call_count++; 2230 info.GetReturnValue().Set(v8_num(index)); 2231 } 2232 2233 2234 THREADED_TEST(IndexedPropertyHandlerGetter) { 2235 v8::Isolate* isolate = CcTest::isolate(); 2236 v8::HandleScope scope(isolate); 2237 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2238 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty, 2239 0, 0, 0, 0, 2240 v8_num(637)); 2241 LocalContext env; 2242 env->Global()->Set(v8_str("obj"), 2243 templ->GetFunction()->NewInstance()); 2244 Local<Script> script = v8_compile("obj[900]"); 2245 CHECK_EQ(script->Run()->Int32Value(), 900); 2246 } 2247 2248 2249 v8::Handle<v8::Object> bottom; 2250 2251 static void CheckThisIndexedPropertyHandler( 2252 uint32_t index, 2253 const v8::PropertyCallbackInfo<v8::Value>& info) { 2254 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler)); 2255 ApiTestFuzzer::Fuzz(); 2256 CHECK(info.This()->Equals(bottom)); 2257 } 2258 2259 static void CheckThisNamedPropertyHandler( 2260 Local<String> name, 2261 const v8::PropertyCallbackInfo<v8::Value>& info) { 2262 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler)); 2263 ApiTestFuzzer::Fuzz(); 2264 CHECK(info.This()->Equals(bottom)); 2265 } 2266 2267 void CheckThisIndexedPropertySetter( 2268 uint32_t index, 2269 Local<Value> value, 2270 const v8::PropertyCallbackInfo<v8::Value>& info) { 2271 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter)); 2272 ApiTestFuzzer::Fuzz(); 2273 CHECK(info.This()->Equals(bottom)); 2274 } 2275 2276 2277 void CheckThisNamedPropertySetter( 2278 Local<String> property, 2279 Local<Value> value, 2280 const v8::PropertyCallbackInfo<v8::Value>& info) { 2281 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter)); 2282 ApiTestFuzzer::Fuzz(); 2283 CHECK(info.This()->Equals(bottom)); 2284 } 2285 2286 void CheckThisIndexedPropertyQuery( 2287 uint32_t index, 2288 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2289 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery)); 2290 ApiTestFuzzer::Fuzz(); 2291 CHECK(info.This()->Equals(bottom)); 2292 } 2293 2294 2295 void CheckThisNamedPropertyQuery( 2296 Local<String> property, 2297 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2298 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery)); 2299 ApiTestFuzzer::Fuzz(); 2300 CHECK(info.This()->Equals(bottom)); 2301 } 2302 2303 2304 void CheckThisIndexedPropertyDeleter( 2305 uint32_t index, 2306 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2307 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter)); 2308 ApiTestFuzzer::Fuzz(); 2309 CHECK(info.This()->Equals(bottom)); 2310 } 2311 2312 2313 void CheckThisNamedPropertyDeleter( 2314 Local<String> property, 2315 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2316 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter)); 2317 ApiTestFuzzer::Fuzz(); 2318 CHECK(info.This()->Equals(bottom)); 2319 } 2320 2321 2322 void CheckThisIndexedPropertyEnumerator( 2323 const v8::PropertyCallbackInfo<v8::Array>& info) { 2324 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator)); 2325 ApiTestFuzzer::Fuzz(); 2326 CHECK(info.This()->Equals(bottom)); 2327 } 2328 2329 2330 void CheckThisNamedPropertyEnumerator( 2331 const v8::PropertyCallbackInfo<v8::Array>& info) { 2332 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator)); 2333 ApiTestFuzzer::Fuzz(); 2334 CHECK(info.This()->Equals(bottom)); 2335 } 2336 2337 2338 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) { 2339 LocalContext env; 2340 v8::Isolate* isolate = env->GetIsolate(); 2341 v8::HandleScope scope(isolate); 2342 2343 // Set up a prototype chain with three interceptors. 2344 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2345 templ->InstanceTemplate()->SetIndexedPropertyHandler( 2346 CheckThisIndexedPropertyHandler, 2347 CheckThisIndexedPropertySetter, 2348 CheckThisIndexedPropertyQuery, 2349 CheckThisIndexedPropertyDeleter, 2350 CheckThisIndexedPropertyEnumerator); 2351 2352 templ->InstanceTemplate()->SetNamedPropertyHandler( 2353 CheckThisNamedPropertyHandler, 2354 CheckThisNamedPropertySetter, 2355 CheckThisNamedPropertyQuery, 2356 CheckThisNamedPropertyDeleter, 2357 CheckThisNamedPropertyEnumerator); 2358 2359 bottom = templ->GetFunction()->NewInstance(); 2360 Local<v8::Object> top = templ->GetFunction()->NewInstance(); 2361 Local<v8::Object> middle = templ->GetFunction()->NewInstance(); 2362 2363 bottom->SetPrototype(middle); 2364 middle->SetPrototype(top); 2365 env->Global()->Set(v8_str("obj"), bottom); 2366 2367 // Indexed and named get. 2368 CompileRun("obj[0]"); 2369 CompileRun("obj.x"); 2370 2371 // Indexed and named set. 2372 CompileRun("obj[1] = 42"); 2373 CompileRun("obj.y = 42"); 2374 2375 // Indexed and named query. 2376 CompileRun("0 in obj"); 2377 CompileRun("'x' in obj"); 2378 2379 // Indexed and named deleter. 2380 CompileRun("delete obj[0]"); 2381 CompileRun("delete obj.x"); 2382 2383 // Enumerators. 2384 CompileRun("for (var p in obj) ;"); 2385 } 2386 2387 2388 static void PrePropertyHandlerGet( 2389 Local<String> key, 2390 const v8::PropertyCallbackInfo<v8::Value>& info) { 2391 ApiTestFuzzer::Fuzz(); 2392 if (v8_str("pre")->Equals(key)) { 2393 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre")); 2394 } 2395 } 2396 2397 2398 static void PrePropertyHandlerQuery( 2399 Local<String> key, 2400 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2401 if (v8_str("pre")->Equals(key)) { 2402 info.GetReturnValue().Set(static_cast<int32_t>(v8::None)); 2403 } 2404 } 2405 2406 2407 THREADED_TEST(PrePropertyHandler) { 2408 v8::Isolate* isolate = CcTest::isolate(); 2409 v8::HandleScope scope(isolate); 2410 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 2411 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet, 2412 0, 2413 PrePropertyHandlerQuery); 2414 LocalContext env(NULL, desc->InstanceTemplate()); 2415 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';"); 2416 v8::Handle<Value> result_pre = CompileRun("pre"); 2417 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre); 2418 v8::Handle<Value> result_on = CompileRun("on"); 2419 CHECK_EQ(v8_str("Object: on"), result_on); 2420 v8::Handle<Value> result_post = CompileRun("post"); 2421 CHECK(result_post.IsEmpty()); 2422 } 2423 2424 2425 THREADED_TEST(UndefinedIsNotEnumerable) { 2426 LocalContext env; 2427 v8::HandleScope scope(env->GetIsolate()); 2428 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)"); 2429 CHECK(result->IsFalse()); 2430 } 2431 2432 2433 v8::Handle<Script> call_recursively_script; 2434 static const int kTargetRecursionDepth = 200; // near maximum 2435 2436 2437 static void CallScriptRecursivelyCall( 2438 const v8::FunctionCallbackInfo<v8::Value>& args) { 2439 ApiTestFuzzer::Fuzz(); 2440 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2441 if (depth == kTargetRecursionDepth) return; 2442 args.This()->Set(v8_str("depth"), 2443 v8::Integer::New(args.GetIsolate(), depth + 1)); 2444 args.GetReturnValue().Set(call_recursively_script->Run()); 2445 } 2446 2447 2448 static void CallFunctionRecursivelyCall( 2449 const v8::FunctionCallbackInfo<v8::Value>& args) { 2450 ApiTestFuzzer::Fuzz(); 2451 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2452 if (depth == kTargetRecursionDepth) { 2453 printf("[depth = %d]\n", depth); 2454 return; 2455 } 2456 args.This()->Set(v8_str("depth"), 2457 v8::Integer::New(args.GetIsolate(), depth + 1)); 2458 v8::Handle<Value> function = 2459 args.This()->Get(v8_str("callFunctionRecursively")); 2460 args.GetReturnValue().Set( 2461 function.As<Function>()->Call(args.This(), 0, NULL)); 2462 } 2463 2464 2465 THREADED_TEST(DeepCrossLanguageRecursion) { 2466 v8::Isolate* isolate = CcTest::isolate(); 2467 v8::HandleScope scope(isolate); 2468 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 2469 global->Set(v8_str("callScriptRecursively"), 2470 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall)); 2471 global->Set(v8_str("callFunctionRecursively"), 2472 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall)); 2473 LocalContext env(NULL, global); 2474 2475 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); 2476 call_recursively_script = v8_compile("callScriptRecursively()"); 2477 call_recursively_script->Run(); 2478 call_recursively_script = v8::Handle<Script>(); 2479 2480 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); 2481 CompileRun("callFunctionRecursively()"); 2482 } 2483 2484 2485 static void ThrowingPropertyHandlerGet( 2486 Local<String> key, 2487 const v8::PropertyCallbackInfo<v8::Value>& info) { 2488 ApiTestFuzzer::Fuzz(); 2489 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key)); 2490 } 2491 2492 2493 static void ThrowingPropertyHandlerSet( 2494 Local<String> key, 2495 Local<Value>, 2496 const v8::PropertyCallbackInfo<v8::Value>& info) { 2497 info.GetIsolate()->ThrowException(key); 2498 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2499 } 2500 2501 2502 THREADED_TEST(CallbackExceptionRegression) { 2503 v8::Isolate* isolate = CcTest::isolate(); 2504 v8::HandleScope scope(isolate); 2505 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 2506 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet, 2507 ThrowingPropertyHandlerSet); 2508 LocalContext env; 2509 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 2510 v8::Handle<Value> otto = CompileRun( 2511 "try { with (obj) { otto; } } catch (e) { e; }"); 2512 CHECK_EQ(v8_str("otto"), otto); 2513 v8::Handle<Value> netto = CompileRun( 2514 "try { with (obj) { netto = 4; } } catch (e) { e; }"); 2515 CHECK_EQ(v8_str("netto"), netto); 2516 } 2517 2518 2519 THREADED_TEST(FunctionPrototype) { 2520 v8::Isolate* isolate = CcTest::isolate(); 2521 v8::HandleScope scope(isolate); 2522 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate); 2523 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2524 LocalContext env; 2525 env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); 2526 Local<Script> script = v8_compile("Foo.prototype.plak"); 2527 CHECK_EQ(script->Run()->Int32Value(), 321); 2528 } 2529 2530 2531 THREADED_TEST(InternalFields) { 2532 LocalContext env; 2533 v8::Isolate* isolate = env->GetIsolate(); 2534 v8::HandleScope scope(isolate); 2535 2536 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2537 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2538 instance_templ->SetInternalFieldCount(1); 2539 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2540 CHECK_EQ(1, obj->InternalFieldCount()); 2541 CHECK(obj->GetInternalField(0)->IsUndefined()); 2542 obj->SetInternalField(0, v8_num(17)); 2543 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value()); 2544 } 2545 2546 2547 THREADED_TEST(GlobalObjectInternalFields) { 2548 v8::Isolate* isolate = CcTest::isolate(); 2549 v8::HandleScope scope(isolate); 2550 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 2551 global_template->SetInternalFieldCount(1); 2552 LocalContext env(NULL, global_template); 2553 v8::Handle<v8::Object> global_proxy = env->Global(); 2554 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2555 CHECK_EQ(1, global->InternalFieldCount()); 2556 CHECK(global->GetInternalField(0)->IsUndefined()); 2557 global->SetInternalField(0, v8_num(17)); 2558 CHECK_EQ(17, global->GetInternalField(0)->Int32Value()); 2559 } 2560 2561 2562 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2563 LocalContext env; 2564 v8::HandleScope scope(CcTest::isolate()); 2565 2566 v8::Local<v8::Object> global = env->Global(); 2567 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value")); 2568 CHECK(global->HasRealIndexedProperty(0)); 2569 } 2570 2571 2572 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, 2573 void* value) { 2574 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2575 obj->SetAlignedPointerInInternalField(0, value); 2576 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2577 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2578 } 2579 2580 2581 THREADED_TEST(InternalFieldsAlignedPointers) { 2582 LocalContext env; 2583 v8::Isolate* isolate = env->GetIsolate(); 2584 v8::HandleScope scope(isolate); 2585 2586 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2587 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2588 instance_templ->SetInternalFieldCount(1); 2589 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2590 CHECK_EQ(1, obj->InternalFieldCount()); 2591 2592 CheckAlignedPointerInInternalField(obj, NULL); 2593 2594 int* heap_allocated = new int[100]; 2595 CheckAlignedPointerInInternalField(obj, heap_allocated); 2596 delete[] heap_allocated; 2597 2598 int stack_allocated[100]; 2599 CheckAlignedPointerInInternalField(obj, stack_allocated); 2600 2601 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2602 CheckAlignedPointerInInternalField(obj, huge); 2603 2604 v8::UniquePersistent<v8::Object> persistent(isolate, obj); 2605 CHECK_EQ(1, Object::InternalFieldCount(persistent)); 2606 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0)); 2607 } 2608 2609 2610 static void CheckAlignedPointerInEmbedderData(LocalContext* env, 2611 int index, 2612 void* value) { 2613 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2614 (*env)->SetAlignedPointerInEmbedderData(index, value); 2615 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2616 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2617 } 2618 2619 2620 static void* AlignedTestPointer(int i) { 2621 return reinterpret_cast<void*>(i * 1234); 2622 } 2623 2624 2625 THREADED_TEST(EmbedderDataAlignedPointers) { 2626 LocalContext env; 2627 v8::HandleScope scope(env->GetIsolate()); 2628 2629 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2630 2631 int* heap_allocated = new int[100]; 2632 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2633 delete[] heap_allocated; 2634 2635 int stack_allocated[100]; 2636 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2637 2638 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2639 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2640 2641 // Test growing of the embedder data's backing store. 2642 for (int i = 0; i < 100; i++) { 2643 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2644 } 2645 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2646 for (int i = 0; i < 100; i++) { 2647 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2648 } 2649 } 2650 2651 2652 static void CheckEmbedderData(LocalContext* env, 2653 int index, 2654 v8::Handle<Value> data) { 2655 (*env)->SetEmbedderData(index, data); 2656 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2657 } 2658 2659 2660 THREADED_TEST(EmbedderData) { 2661 LocalContext env; 2662 v8::Isolate* isolate = env->GetIsolate(); 2663 v8::HandleScope scope(isolate); 2664 2665 CheckEmbedderData( 2666 &env, 3, 2667 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps")); 2668 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate, 2669 "over the lazy dog.")); 2670 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345)); 2671 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true)); 2672 } 2673 2674 2675 THREADED_TEST(IdentityHash) { 2676 LocalContext env; 2677 v8::Isolate* isolate = env->GetIsolate(); 2678 v8::HandleScope scope(isolate); 2679 2680 // Ensure that the test starts with an fresh heap to test whether the hash 2681 // code is based on the address. 2682 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2683 Local<v8::Object> obj = v8::Object::New(isolate); 2684 int hash = obj->GetIdentityHash(); 2685 int hash1 = obj->GetIdentityHash(); 2686 CHECK_EQ(hash, hash1); 2687 int hash2 = v8::Object::New(isolate)->GetIdentityHash(); 2688 // Since the identity hash is essentially a random number two consecutive 2689 // objects should not be assigned the same hash code. If the test below fails 2690 // the random number generator should be evaluated. 2691 CHECK_NE(hash, hash2); 2692 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2693 int hash3 = v8::Object::New(isolate)->GetIdentityHash(); 2694 // Make sure that the identity hash is not based on the initial address of 2695 // the object alone. If the test below fails the random number generator 2696 // should be evaluated. 2697 CHECK_NE(hash, hash3); 2698 int hash4 = obj->GetIdentityHash(); 2699 CHECK_EQ(hash, hash4); 2700 2701 // Check identity hashes behaviour in the presence of JS accessors. 2702 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2703 { 2704 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2705 Local<v8::Object> o1 = v8::Object::New(isolate); 2706 Local<v8::Object> o2 = v8::Object::New(isolate); 2707 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2708 } 2709 { 2710 CompileRun( 2711 "function cnst() { return 42; };\n" 2712 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2713 Local<v8::Object> o1 = v8::Object::New(isolate); 2714 Local<v8::Object> o2 = v8::Object::New(isolate); 2715 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2716 } 2717 } 2718 2719 2720 THREADED_TEST(GlobalProxyIdentityHash) { 2721 LocalContext env; 2722 v8::Isolate* isolate = env->GetIsolate(); 2723 v8::HandleScope scope(isolate); 2724 Handle<Object> global_proxy = env->Global(); 2725 int hash1 = global_proxy->GetIdentityHash(); 2726 // Hash should be retained after being detached. 2727 env->DetachGlobal(); 2728 int hash2 = global_proxy->GetIdentityHash(); 2729 CHECK_EQ(hash1, hash2); 2730 { 2731 // Re-attach global proxy to a new context, hash should stay the same. 2732 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy); 2733 int hash3 = global_proxy->GetIdentityHash(); 2734 CHECK_EQ(hash1, hash3); 2735 } 2736 } 2737 2738 2739 THREADED_TEST(SymbolProperties) { 2740 i::FLAG_harmony_symbols = true; 2741 2742 LocalContext env; 2743 v8::Isolate* isolate = env->GetIsolate(); 2744 v8::HandleScope scope(isolate); 2745 2746 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2747 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2748 v8::Local<v8::Symbol> sym2 = 2749 v8::Symbol::New(isolate, v8_str("my-symbol")); 2750 2751 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2752 2753 // Check basic symbol functionality. 2754 CHECK(sym1->IsSymbol()); 2755 CHECK(sym2->IsSymbol()); 2756 CHECK(!obj->IsSymbol()); 2757 2758 CHECK(sym1->Equals(sym1)); 2759 CHECK(sym2->Equals(sym2)); 2760 CHECK(!sym1->Equals(sym2)); 2761 CHECK(!sym2->Equals(sym1)); 2762 CHECK(sym1->StrictEquals(sym1)); 2763 CHECK(sym2->StrictEquals(sym2)); 2764 CHECK(!sym1->StrictEquals(sym2)); 2765 CHECK(!sym2->StrictEquals(sym1)); 2766 2767 CHECK(sym2->Name()->Equals(v8_str("my-symbol"))); 2768 2769 v8::Local<v8::Value> sym_val = sym2; 2770 CHECK(sym_val->IsSymbol()); 2771 CHECK(sym_val->Equals(sym2)); 2772 CHECK(sym_val->StrictEquals(sym2)); 2773 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2)); 2774 2775 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2776 CHECK(sym_obj->IsSymbolObject()); 2777 CHECK(!sym2->IsSymbolObject()); 2778 CHECK(!obj->IsSymbolObject()); 2779 CHECK(!sym_obj->Equals(sym2)); 2780 CHECK(!sym_obj->StrictEquals(sym2)); 2781 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj)); 2782 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2)); 2783 2784 // Make sure delete of a non-existent symbol property works. 2785 CHECK(obj->Delete(sym1)); 2786 CHECK(!obj->Has(sym1)); 2787 2788 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503))); 2789 CHECK(obj->Has(sym1)); 2790 CHECK_EQ(1503, obj->Get(sym1)->Int32Value()); 2791 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002))); 2792 CHECK(obj->Has(sym1)); 2793 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2794 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1)); 2795 2796 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2797 int num_props = obj->GetPropertyNames()->Length(); 2798 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"), 2799 v8::Integer::New(isolate, 20))); 2800 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2801 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2802 2803 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2804 2805 // Add another property and delete it afterwards to force the object in 2806 // slow case. 2807 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008))); 2808 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2809 CHECK_EQ(2008, obj->Get(sym2)->Int32Value()); 2810 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2811 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2812 2813 CHECK(obj->Has(sym1)); 2814 CHECK(obj->Has(sym2)); 2815 CHECK(obj->Delete(sym2)); 2816 CHECK(obj->Has(sym1)); 2817 CHECK(!obj->Has(sym2)); 2818 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2819 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2820 2821 // Symbol properties are inherited. 2822 v8::Local<v8::Object> child = v8::Object::New(isolate); 2823 child->SetPrototype(obj); 2824 CHECK(child->Has(sym1)); 2825 CHECK_EQ(2002, child->Get(sym1)->Int32Value()); 2826 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2827 } 2828 2829 2830 THREADED_TEST(PrivateProperties) { 2831 LocalContext env; 2832 v8::Isolate* isolate = env->GetIsolate(); 2833 v8::HandleScope scope(isolate); 2834 2835 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2836 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 2837 v8::Local<v8::Private> priv2 = 2838 v8::Private::New(isolate, v8_str("my-private")); 2839 2840 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2841 2842 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private"))); 2843 2844 // Make sure delete of a non-existent private symbol property works. 2845 CHECK(obj->DeletePrivate(priv1)); 2846 CHECK(!obj->HasPrivate(priv1)); 2847 2848 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503))); 2849 CHECK(obj->HasPrivate(priv1)); 2850 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value()); 2851 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002))); 2852 CHECK(obj->HasPrivate(priv1)); 2853 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2854 2855 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2856 int num_props = obj->GetPropertyNames()->Length(); 2857 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"), 2858 v8::Integer::New(isolate, 20))); 2859 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2860 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2861 2862 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2863 2864 // Add another property and delete it afterwards to force the object in 2865 // slow case. 2866 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008))); 2867 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2868 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value()); 2869 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2870 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2871 2872 CHECK(obj->HasPrivate(priv1)); 2873 CHECK(obj->HasPrivate(priv2)); 2874 CHECK(obj->DeletePrivate(priv2)); 2875 CHECK(obj->HasPrivate(priv1)); 2876 CHECK(!obj->HasPrivate(priv2)); 2877 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2878 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2879 2880 // Private properties are inherited (for the time being). 2881 v8::Local<v8::Object> child = v8::Object::New(isolate); 2882 child->SetPrototype(obj); 2883 CHECK(child->HasPrivate(priv1)); 2884 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value()); 2885 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2886 } 2887 2888 2889 THREADED_TEST(GlobalSymbols) { 2890 i::FLAG_harmony_symbols = true; 2891 2892 LocalContext env; 2893 v8::Isolate* isolate = env->GetIsolate(); 2894 v8::HandleScope scope(isolate); 2895 2896 v8::Local<String> name = v8_str("my-symbol"); 2897 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name); 2898 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name); 2899 CHECK(glob2->SameValue(glob)); 2900 2901 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name); 2902 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name); 2903 CHECK(glob_api2->SameValue(glob_api)); 2904 CHECK(!glob_api->SameValue(glob)); 2905 2906 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name); 2907 CHECK(!sym->SameValue(glob)); 2908 2909 CompileRun("var sym2 = Symbol.for('my-symbol')"); 2910 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2")); 2911 CHECK(sym2->SameValue(glob)); 2912 CHECK(!sym2->SameValue(glob_api)); 2913 } 2914 2915 2916 THREADED_TEST(GlobalPrivates) { 2917 LocalContext env; 2918 v8::Isolate* isolate = env->GetIsolate(); 2919 v8::HandleScope scope(isolate); 2920 2921 v8::Local<String> name = v8_str("my-private"); 2922 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name); 2923 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2924 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3))); 2925 2926 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name); 2927 CHECK(obj->HasPrivate(glob2)); 2928 2929 v8::Local<v8::Private> priv = v8::Private::New(isolate, name); 2930 CHECK(!obj->HasPrivate(priv)); 2931 2932 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')"); 2933 v8::Local<Value> intern = env->Global()->Get(v8_str("intern")); 2934 CHECK(!obj->Has(intern)); 2935 } 2936 2937 2938 class ScopedArrayBufferContents { 2939 public: 2940 explicit ScopedArrayBufferContents( 2941 const v8::ArrayBuffer::Contents& contents) 2942 : contents_(contents) {} 2943 ~ScopedArrayBufferContents() { free(contents_.Data()); } 2944 void* Data() const { return contents_.Data(); } 2945 size_t ByteLength() const { return contents_.ByteLength(); } 2946 private: 2947 const v8::ArrayBuffer::Contents contents_; 2948 }; 2949 2950 template <typename T> 2951 static void CheckInternalFieldsAreZero(v8::Handle<T> value) { 2952 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 2953 for (int i = 0; i < value->InternalFieldCount(); i++) { 2954 CHECK_EQ(0, value->GetInternalField(i)->Int32Value()); 2955 } 2956 } 2957 2958 2959 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 2960 LocalContext env; 2961 v8::Isolate* isolate = env->GetIsolate(); 2962 v8::HandleScope handle_scope(isolate); 2963 2964 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024); 2965 CheckInternalFieldsAreZero(ab); 2966 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 2967 CHECK(!ab->IsExternal()); 2968 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2969 2970 ScopedArrayBufferContents ab_contents(ab->Externalize()); 2971 CHECK(ab->IsExternal()); 2972 2973 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 2974 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 2975 ASSERT(data != NULL); 2976 env->Global()->Set(v8_str("ab"), ab); 2977 2978 v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); 2979 CHECK_EQ(1024, result->Int32Value()); 2980 2981 result = CompileRun("var u8 = new Uint8Array(ab);" 2982 "u8[0] = 0xFF;" 2983 "u8[1] = 0xAA;" 2984 "u8.length"); 2985 CHECK_EQ(1024, result->Int32Value()); 2986 CHECK_EQ(0xFF, data[0]); 2987 CHECK_EQ(0xAA, data[1]); 2988 data[0] = 0xCC; 2989 data[1] = 0x11; 2990 result = CompileRun("u8[0] + u8[1]"); 2991 CHECK_EQ(0xDD, result->Int32Value()); 2992 } 2993 2994 2995 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 2996 LocalContext env; 2997 v8::Isolate* isolate = env->GetIsolate(); 2998 v8::HandleScope handle_scope(isolate); 2999 3000 3001 v8::Local<v8::Value> result = 3002 CompileRun("var ab1 = new ArrayBuffer(2);" 3003 "var u8_a = new Uint8Array(ab1);" 3004 "u8_a[0] = 0xAA;" 3005 "u8_a[1] = 0xFF; u8_a.buffer"); 3006 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 3007 CheckInternalFieldsAreZero(ab1); 3008 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3009 CHECK(!ab1->IsExternal()); 3010 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 3011 CHECK(ab1->IsExternal()); 3012 3013 result = CompileRun("ab1.byteLength"); 3014 CHECK_EQ(2, result->Int32Value()); 3015 result = CompileRun("u8_a[0]"); 3016 CHECK_EQ(0xAA, result->Int32Value()); 3017 result = CompileRun("u8_a[1]"); 3018 CHECK_EQ(0xFF, result->Int32Value()); 3019 result = CompileRun("var u8_b = new Uint8Array(ab1);" 3020 "u8_b[0] = 0xBB;" 3021 "u8_a[0]"); 3022 CHECK_EQ(0xBB, result->Int32Value()); 3023 result = CompileRun("u8_b[1]"); 3024 CHECK_EQ(0xFF, result->Int32Value()); 3025 3026 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3027 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3028 CHECK_EQ(0xBB, ab1_data[0]); 3029 CHECK_EQ(0xFF, ab1_data[1]); 3030 ab1_data[0] = 0xCC; 3031 ab1_data[1] = 0x11; 3032 result = CompileRun("u8_a[0] + u8_a[1]"); 3033 CHECK_EQ(0xDD, result->Int32Value()); 3034 } 3035 3036 3037 THREADED_TEST(ArrayBuffer_External) { 3038 LocalContext env; 3039 v8::Isolate* isolate = env->GetIsolate(); 3040 v8::HandleScope handle_scope(isolate); 3041 3042 i::ScopedVector<uint8_t> my_data(100); 3043 memset(my_data.start(), 0, 100); 3044 Local<v8::ArrayBuffer> ab3 = 3045 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3046 CheckInternalFieldsAreZero(ab3); 3047 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3048 CHECK(ab3->IsExternal()); 3049 3050 env->Global()->Set(v8_str("ab3"), ab3); 3051 3052 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength"); 3053 CHECK_EQ(100, result->Int32Value()); 3054 3055 result = CompileRun("var u8_b = new Uint8Array(ab3);" 3056 "u8_b[0] = 0xBB;" 3057 "u8_b[1] = 0xCC;" 3058 "u8_b.length"); 3059 CHECK_EQ(100, result->Int32Value()); 3060 CHECK_EQ(0xBB, my_data[0]); 3061 CHECK_EQ(0xCC, my_data[1]); 3062 my_data[0] = 0xCC; 3063 my_data[1] = 0x11; 3064 result = CompileRun("u8_b[0] + u8_b[1]"); 3065 CHECK_EQ(0xDD, result->Int32Value()); 3066 } 3067 3068 3069 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) { 3070 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 3071 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 3072 } 3073 3074 3075 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) { 3076 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 3077 CHECK_EQ(0, static_cast<int>(ta->Length())); 3078 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 3079 } 3080 3081 3082 static void CheckIsTypedArrayVarNeutered(const char* name) { 3083 i::ScopedVector<char> source(1024); 3084 i::SNPrintF(source, 3085 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 3086 name, name, name); 3087 CHECK(CompileRun(source.start())->IsTrue()); 3088 v8::Handle<v8::TypedArray> ta = 3089 v8::Handle<v8::TypedArray>::Cast(CompileRun(name)); 3090 CheckIsNeutered(ta); 3091 } 3092 3093 3094 template <typename TypedArray, int kElementSize> 3095 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab, 3096 int byteOffset, 3097 int length) { 3098 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 3099 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 3100 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 3101 CHECK_EQ(length, static_cast<int>(ta->Length())); 3102 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 3103 return ta; 3104 } 3105 3106 3107 THREADED_TEST(ArrayBuffer_NeuteringApi) { 3108 LocalContext env; 3109 v8::Isolate* isolate = env->GetIsolate(); 3110 v8::HandleScope handle_scope(isolate); 3111 3112 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024); 3113 3114 v8::Handle<v8::Uint8Array> u8a = 3115 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 3116 v8::Handle<v8::Uint8ClampedArray> u8c = 3117 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 3118 v8::Handle<v8::Int8Array> i8a = 3119 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 3120 3121 v8::Handle<v8::Uint16Array> u16a = 3122 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 3123 v8::Handle<v8::Int16Array> i16a = 3124 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 3125 3126 v8::Handle<v8::Uint32Array> u32a = 3127 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 3128 v8::Handle<v8::Int32Array> i32a = 3129 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 3130 3131 v8::Handle<v8::Float32Array> f32a = 3132 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 3133 v8::Handle<v8::Float64Array> f64a = 3134 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 3135 3136 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 3137 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 3138 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 3139 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 3140 3141 ScopedArrayBufferContents contents(buffer->Externalize()); 3142 buffer->Neuter(); 3143 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 3144 CheckIsNeutered(u8a); 3145 CheckIsNeutered(u8c); 3146 CheckIsNeutered(i8a); 3147 CheckIsNeutered(u16a); 3148 CheckIsNeutered(i16a); 3149 CheckIsNeutered(u32a); 3150 CheckIsNeutered(i32a); 3151 CheckIsNeutered(f32a); 3152 CheckIsNeutered(f64a); 3153 CheckDataViewIsNeutered(dv); 3154 } 3155 3156 3157 THREADED_TEST(ArrayBuffer_NeuteringScript) { 3158 LocalContext env; 3159 v8::Isolate* isolate = env->GetIsolate(); 3160 v8::HandleScope handle_scope(isolate); 3161 3162 CompileRun( 3163 "var ab = new ArrayBuffer(1024);" 3164 "var u8a = new Uint8Array(ab, 1, 1023);" 3165 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 3166 "var i8a = new Int8Array(ab, 1, 1023);" 3167 "var u16a = new Uint16Array(ab, 2, 511);" 3168 "var i16a = new Int16Array(ab, 2, 511);" 3169 "var u32a = new Uint32Array(ab, 4, 255);" 3170 "var i32a = new Int32Array(ab, 4, 255);" 3171 "var f32a = new Float32Array(ab, 4, 255);" 3172 "var f64a = new Float64Array(ab, 8, 127);" 3173 "var dv = new DataView(ab, 1, 1023);"); 3174 3175 v8::Handle<v8::ArrayBuffer> ab = 3176 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 3177 3178 v8::Handle<v8::DataView> dv = 3179 v8::Handle<v8::DataView>::Cast(CompileRun("dv")); 3180 3181 ScopedArrayBufferContents contents(ab->Externalize()); 3182 ab->Neuter(); 3183 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 3184 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value()); 3185 3186 CheckIsTypedArrayVarNeutered("u8a"); 3187 CheckIsTypedArrayVarNeutered("u8c"); 3188 CheckIsTypedArrayVarNeutered("i8a"); 3189 CheckIsTypedArrayVarNeutered("u16a"); 3190 CheckIsTypedArrayVarNeutered("i16a"); 3191 CheckIsTypedArrayVarNeutered("u32a"); 3192 CheckIsTypedArrayVarNeutered("i32a"); 3193 CheckIsTypedArrayVarNeutered("f32a"); 3194 CheckIsTypedArrayVarNeutered("f64a"); 3195 3196 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 3197 CheckDataViewIsNeutered(dv); 3198 } 3199 3200 3201 3202 THREADED_TEST(HiddenProperties) { 3203 LocalContext env; 3204 v8::Isolate* isolate = env->GetIsolate(); 3205 v8::HandleScope scope(isolate); 3206 3207 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3208 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3209 v8::Local<v8::String> empty = v8_str(""); 3210 v8::Local<v8::String> prop_name = v8_str("prop_name"); 3211 3212 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3213 3214 // Make sure delete of a non-existent hidden value works 3215 CHECK(obj->DeleteHiddenValue(key)); 3216 3217 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503))); 3218 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value()); 3219 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002))); 3220 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3221 3222 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3223 3224 // Make sure we do not find the hidden property. 3225 CHECK(!obj->Has(empty)); 3226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3227 CHECK(obj->Get(empty)->IsUndefined()); 3228 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3229 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003))); 3230 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3231 CHECK_EQ(2003, obj->Get(empty)->Int32Value()); 3232 3233 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3234 3235 // Add another property and delete it afterwards to force the object in 3236 // slow case. 3237 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008))); 3238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3239 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value()); 3240 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3241 CHECK(obj->Delete(prop_name)); 3242 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3243 3244 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3245 3246 CHECK(obj->SetHiddenValue(key, Handle<Value>())); 3247 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3248 3249 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002))); 3250 CHECK(obj->DeleteHiddenValue(key)); 3251 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3252 } 3253 3254 3255 THREADED_TEST(Regress97784) { 3256 // Regression test for crbug.com/97784 3257 // Messing with the Object.prototype should not have effect on 3258 // hidden properties. 3259 LocalContext env; 3260 v8::HandleScope scope(env->GetIsolate()); 3261 3262 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3263 v8::Local<v8::String> key = v8_str("hidden"); 3264 3265 CompileRun( 3266 "set_called = false;" 3267 "Object.defineProperty(" 3268 " Object.prototype," 3269 " 'hidden'," 3270 " {get: function() { return 45; }," 3271 " set: function() { set_called = true; }})"); 3272 3273 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3274 // Make sure that the getter and setter from Object.prototype is not invoked. 3275 // If it did we would have full access to the hidden properties in 3276 // the accessor. 3277 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42))); 3278 ExpectFalse("set_called"); 3279 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value()); 3280 } 3281 3282 3283 static bool interceptor_for_hidden_properties_called; 3284 static void InterceptorForHiddenProperties( 3285 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 3286 interceptor_for_hidden_properties_called = true; 3287 } 3288 3289 3290 THREADED_TEST(HiddenPropertiesWithInterceptors) { 3291 LocalContext context; 3292 v8::Isolate* isolate = context->GetIsolate(); 3293 v8::HandleScope scope(isolate); 3294 3295 interceptor_for_hidden_properties_called = false; 3296 3297 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3298 3299 // Associate an interceptor with an object and start setting hidden values. 3300 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 3301 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 3302 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties); 3303 Local<v8::Function> function = fun_templ->GetFunction(); 3304 Local<v8::Object> obj = function->NewInstance(); 3305 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302))); 3306 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value()); 3307 CHECK(!interceptor_for_hidden_properties_called); 3308 } 3309 3310 3311 THREADED_TEST(External) { 3312 v8::HandleScope scope(CcTest::isolate()); 3313 int x = 3; 3314 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x); 3315 LocalContext env; 3316 env->Global()->Set(v8_str("ext"), ext); 3317 Local<Value> reext_obj = CompileRun("this.ext"); 3318 v8::Handle<v8::External> reext = reext_obj.As<v8::External>(); 3319 int* ptr = static_cast<int*>(reext->Value()); 3320 CHECK_EQ(x, 3); 3321 *ptr = 10; 3322 CHECK_EQ(x, 10); 3323 3324 // Make sure unaligned pointers are wrapped properly. 3325 char* data = i::StrDup("0123456789"); 3326 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]); 3327 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]); 3328 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]); 3329 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]); 3330 3331 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3332 CHECK_EQ('0', *char_ptr); 3333 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3334 CHECK_EQ('1', *char_ptr); 3335 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3336 CHECK_EQ('2', *char_ptr); 3337 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3338 CHECK_EQ('3', *char_ptr); 3339 i::DeleteArray(data); 3340 } 3341 3342 3343 THREADED_TEST(GlobalHandle) { 3344 v8::Isolate* isolate = CcTest::isolate(); 3345 v8::Persistent<String> global; 3346 { 3347 v8::HandleScope scope(isolate); 3348 global.Reset(isolate, v8_str("str")); 3349 } 3350 { 3351 v8::HandleScope scope(isolate); 3352 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3353 } 3354 global.Reset(); 3355 { 3356 v8::HandleScope scope(isolate); 3357 global.Reset(isolate, v8_str("str")); 3358 } 3359 { 3360 v8::HandleScope scope(isolate); 3361 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3362 } 3363 global.Reset(); 3364 } 3365 3366 3367 THREADED_TEST(ResettingGlobalHandle) { 3368 v8::Isolate* isolate = CcTest::isolate(); 3369 v8::Persistent<String> global; 3370 { 3371 v8::HandleScope scope(isolate); 3372 global.Reset(isolate, v8_str("str")); 3373 } 3374 v8::internal::GlobalHandles* global_handles = 3375 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3376 int initial_handle_count = global_handles->global_handles_count(); 3377 { 3378 v8::HandleScope scope(isolate); 3379 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3380 } 3381 { 3382 v8::HandleScope scope(isolate); 3383 global.Reset(isolate, v8_str("longer")); 3384 } 3385 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3386 { 3387 v8::HandleScope scope(isolate); 3388 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3389 } 3390 global.Reset(); 3391 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3392 } 3393 3394 3395 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3396 v8::Isolate* isolate = CcTest::isolate(); 3397 v8::Persistent<String> global; 3398 { 3399 v8::HandleScope scope(isolate); 3400 global.Reset(isolate, v8_str("str")); 3401 } 3402 v8::internal::GlobalHandles* global_handles = 3403 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3404 int initial_handle_count = global_handles->global_handles_count(); 3405 { 3406 v8::HandleScope scope(isolate); 3407 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3408 } 3409 { 3410 v8::HandleScope scope(isolate); 3411 Local<String> empty; 3412 global.Reset(isolate, empty); 3413 } 3414 CHECK(global.IsEmpty()); 3415 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3416 } 3417 3418 3419 template<class T> 3420 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) { 3421 return unique.Pass(); 3422 } 3423 3424 3425 template<class T> 3426 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate, 3427 const v8::Persistent<T> & global) { 3428 v8::UniquePersistent<String> unique(isolate, global); 3429 return unique.Pass(); 3430 } 3431 3432 3433 THREADED_TEST(UniquePersistent) { 3434 v8::Isolate* isolate = CcTest::isolate(); 3435 v8::Persistent<String> global; 3436 { 3437 v8::HandleScope scope(isolate); 3438 global.Reset(isolate, v8_str("str")); 3439 } 3440 v8::internal::GlobalHandles* global_handles = 3441 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3442 int initial_handle_count = global_handles->global_handles_count(); 3443 { 3444 v8::UniquePersistent<String> unique(isolate, global); 3445 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3446 // Test assignment via Pass 3447 { 3448 v8::UniquePersistent<String> copy = unique.Pass(); 3449 CHECK(unique.IsEmpty()); 3450 CHECK(copy == global); 3451 CHECK_EQ(initial_handle_count + 1, 3452 global_handles->global_handles_count()); 3453 unique = copy.Pass(); 3454 } 3455 // Test ctor via Pass 3456 { 3457 v8::UniquePersistent<String> copy(unique.Pass()); 3458 CHECK(unique.IsEmpty()); 3459 CHECK(copy == global); 3460 CHECK_EQ(initial_handle_count + 1, 3461 global_handles->global_handles_count()); 3462 unique = copy.Pass(); 3463 } 3464 // Test pass through function call 3465 { 3466 v8::UniquePersistent<String> copy = PassUnique(unique.Pass()); 3467 CHECK(unique.IsEmpty()); 3468 CHECK(copy == global); 3469 CHECK_EQ(initial_handle_count + 1, 3470 global_handles->global_handles_count()); 3471 unique = copy.Pass(); 3472 } 3473 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3474 } 3475 // Test pass from function call 3476 { 3477 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global); 3478 CHECK(unique == global); 3479 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3480 } 3481 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3482 global.Reset(); 3483 } 3484 3485 3486 template<typename K, typename V> 3487 class WeakStdMapTraits : public v8::StdMapTraits<K, V> { 3488 public: 3489 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> > 3490 MapType; 3491 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak; 3492 struct WeakCallbackDataType { 3493 MapType* map; 3494 K key; 3495 }; 3496 static WeakCallbackDataType* WeakCallbackParameter( 3497 MapType* map, const K& key, Local<V> value) { 3498 WeakCallbackDataType* data = new WeakCallbackDataType; 3499 data->map = map; 3500 data->key = key; 3501 return data; 3502 } 3503 static MapType* MapFromWeakCallbackData( 3504 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) { 3505 return data.GetParameter()->map; 3506 } 3507 static K KeyFromWeakCallbackData( 3508 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) { 3509 return data.GetParameter()->key; 3510 } 3511 static void DisposeCallbackData(WeakCallbackDataType* data) { 3512 delete data; 3513 } 3514 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value, 3515 K key) { } 3516 }; 3517 3518 3519 template<typename Map> 3520 static void TestPersistentValueMap() { 3521 LocalContext env; 3522 v8::Isolate* isolate = env->GetIsolate(); 3523 Map map(isolate); 3524 v8::internal::GlobalHandles* global_handles = 3525 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3526 int initial_handle_count = global_handles->global_handles_count(); 3527 CHECK_EQ(0, static_cast<int>(map.Size())); 3528 { 3529 HandleScope scope(isolate); 3530 Local<v8::Object> obj = map.Get(7); 3531 CHECK(obj.IsEmpty()); 3532 Local<v8::Object> expected = v8::Object::New(isolate); 3533 map.Set(7, expected); 3534 CHECK_EQ(1, static_cast<int>(map.Size())); 3535 obj = map.Get(7); 3536 CHECK_EQ(expected, obj); 3537 { 3538 typename Map::PersistentValueReference ref = map.GetReference(7); 3539 CHECK_EQ(expected, ref.NewLocal(isolate)); 3540 } 3541 v8::UniquePersistent<v8::Object> removed = map.Remove(7); 3542 CHECK_EQ(0, static_cast<int>(map.Size())); 3543 CHECK(expected == removed); 3544 removed = map.Remove(7); 3545 CHECK(removed.IsEmpty()); 3546 map.Set(8, expected); 3547 CHECK_EQ(1, static_cast<int>(map.Size())); 3548 map.Set(8, expected); 3549 CHECK_EQ(1, static_cast<int>(map.Size())); 3550 { 3551 typename Map::PersistentValueReference ref; 3552 Local<v8::Object> expected2 = v8::Object::New(isolate); 3553 removed = map.Set(8, 3554 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref); 3555 CHECK_EQ(1, static_cast<int>(map.Size())); 3556 CHECK(expected == removed); 3557 CHECK_EQ(expected2, ref.NewLocal(isolate)); 3558 } 3559 } 3560 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3561 if (map.IsWeak()) { 3562 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()-> 3563 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3564 } else { 3565 map.Clear(); 3566 } 3567 CHECK_EQ(0, static_cast<int>(map.Size())); 3568 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3569 } 3570 3571 3572 TEST(PersistentValueMap) { 3573 // Default case, w/o weak callbacks: 3574 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >(); 3575 3576 // Custom traits with weak callbacks: 3577 typedef v8::PersistentValueMap<int, v8::Object, 3578 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap; 3579 TestPersistentValueMap<WeakPersistentValueMap>(); 3580 } 3581 3582 3583 TEST(PersistentValueVector) { 3584 LocalContext env; 3585 v8::Isolate* isolate = env->GetIsolate(); 3586 v8::internal::GlobalHandles* global_handles = 3587 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3588 int handle_count = global_handles->global_handles_count(); 3589 HandleScope scope(isolate); 3590 3591 v8::PersistentValueVector<v8::Object> vector(isolate); 3592 3593 Local<v8::Object> obj1 = v8::Object::New(isolate); 3594 Local<v8::Object> obj2 = v8::Object::New(isolate); 3595 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate)); 3596 3597 CHECK(vector.IsEmpty()); 3598 CHECK_EQ(0, static_cast<int>(vector.Size())); 3599 3600 vector.ReserveCapacity(3); 3601 CHECK(vector.IsEmpty()); 3602 3603 vector.Append(obj1); 3604 vector.Append(obj2); 3605 vector.Append(obj1); 3606 vector.Append(obj3.Pass()); 3607 vector.Append(obj1); 3608 3609 CHECK(!vector.IsEmpty()); 3610 CHECK_EQ(5, static_cast<int>(vector.Size())); 3611 CHECK(obj3.IsEmpty()); 3612 CHECK_EQ(obj1, vector.Get(0)); 3613 CHECK_EQ(obj1, vector.Get(2)); 3614 CHECK_EQ(obj1, vector.Get(4)); 3615 CHECK_EQ(obj2, vector.Get(1)); 3616 3617 CHECK_EQ(5 + handle_count, global_handles->global_handles_count()); 3618 3619 vector.Clear(); 3620 CHECK(vector.IsEmpty()); 3621 CHECK_EQ(0, static_cast<int>(vector.Size())); 3622 CHECK_EQ(handle_count, global_handles->global_handles_count()); 3623 } 3624 3625 3626 THREADED_TEST(GlobalHandleUpcast) { 3627 v8::Isolate* isolate = CcTest::isolate(); 3628 v8::HandleScope scope(isolate); 3629 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str")); 3630 v8::Persistent<String> global_string(isolate, local); 3631 v8::Persistent<Value>& global_value = 3632 v8::Persistent<Value>::Cast(global_string); 3633 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 3634 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 3635 global_string.Reset(); 3636 } 3637 3638 3639 THREADED_TEST(HandleEquality) { 3640 v8::Isolate* isolate = CcTest::isolate(); 3641 v8::Persistent<String> global1; 3642 v8::Persistent<String> global2; 3643 { 3644 v8::HandleScope scope(isolate); 3645 global1.Reset(isolate, v8_str("str")); 3646 global2.Reset(isolate, v8_str("str2")); 3647 } 3648 CHECK_EQ(global1 == global1, true); 3649 CHECK_EQ(global1 != global1, false); 3650 { 3651 v8::HandleScope scope(isolate); 3652 Local<String> local1 = Local<String>::New(isolate, global1); 3653 Local<String> local2 = Local<String>::New(isolate, global2); 3654 3655 CHECK_EQ(global1 == local1, true); 3656 CHECK_EQ(global1 != local1, false); 3657 CHECK_EQ(local1 == global1, true); 3658 CHECK_EQ(local1 != global1, false); 3659 3660 CHECK_EQ(global1 == local2, false); 3661 CHECK_EQ(global1 != local2, true); 3662 CHECK_EQ(local2 == global1, false); 3663 CHECK_EQ(local2 != global1, true); 3664 3665 CHECK_EQ(local1 == local2, false); 3666 CHECK_EQ(local1 != local2, true); 3667 3668 Local<String> anotherLocal1 = Local<String>::New(isolate, global1); 3669 CHECK_EQ(local1 == anotherLocal1, true); 3670 CHECK_EQ(local1 != anotherLocal1, false); 3671 } 3672 global1.Reset(); 3673 global2.Reset(); 3674 } 3675 3676 3677 THREADED_TEST(LocalHandle) { 3678 v8::HandleScope scope(CcTest::isolate()); 3679 v8::Local<String> local = 3680 v8::Local<String>::New(CcTest::isolate(), v8_str("str")); 3681 CHECK_EQ(local->Length(), 3); 3682 } 3683 3684 3685 class WeakCallCounter { 3686 public: 3687 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } 3688 int id() { return id_; } 3689 void increment() { number_of_weak_calls_++; } 3690 int NumberOfWeakCalls() { return number_of_weak_calls_; } 3691 private: 3692 int id_; 3693 int number_of_weak_calls_; 3694 }; 3695 3696 3697 template<typename T> 3698 struct WeakCallCounterAndPersistent { 3699 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) 3700 : counter(counter) {} 3701 WeakCallCounter* counter; 3702 v8::Persistent<T> handle; 3703 }; 3704 3705 3706 template <typename T> 3707 static void WeakPointerCallback( 3708 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) { 3709 CHECK_EQ(1234, data.GetParameter()->counter->id()); 3710 data.GetParameter()->counter->increment(); 3711 data.GetParameter()->handle.Reset(); 3712 } 3713 3714 3715 template<typename T> 3716 static UniqueId MakeUniqueId(const Persistent<T>& p) { 3717 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 3718 } 3719 3720 3721 THREADED_TEST(ApiObjectGroups) { 3722 LocalContext env; 3723 v8::Isolate* iso = env->GetIsolate(); 3724 HandleScope scope(iso); 3725 3726 WeakCallCounter counter(1234); 3727 3728 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3729 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3730 WeakCallCounterAndPersistent<Value> g1c1(&counter); 3731 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3732 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3733 WeakCallCounterAndPersistent<Value> g2c1(&counter); 3734 3735 { 3736 HandleScope scope(iso); 3737 g1s1.handle.Reset(iso, Object::New(iso)); 3738 g1s2.handle.Reset(iso, Object::New(iso)); 3739 g1c1.handle.Reset(iso, Object::New(iso)); 3740 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3741 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3742 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3743 3744 g2s1.handle.Reset(iso, Object::New(iso)); 3745 g2s2.handle.Reset(iso, Object::New(iso)); 3746 g2c1.handle.Reset(iso, Object::New(iso)); 3747 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3748 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3749 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3750 } 3751 3752 WeakCallCounterAndPersistent<Value> root(&counter); 3753 root.handle.Reset(iso, g1s1.handle); // make a root. 3754 3755 // Connect group 1 and 2, make a cycle. 3756 { 3757 HandleScope scope(iso); 3758 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())-> 3759 Set(0, Local<Value>::New(iso, g2s2.handle))); 3760 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())-> 3761 Set(0, Local<Value>::New(iso, g1s1.handle))); 3762 } 3763 3764 { 3765 UniqueId id1 = MakeUniqueId(g1s1.handle); 3766 UniqueId id2 = MakeUniqueId(g2s2.handle); 3767 iso->SetObjectGroupId(g1s1.handle, id1); 3768 iso->SetObjectGroupId(g1s2.handle, id1); 3769 iso->SetReferenceFromGroup(id1, g1c1.handle); 3770 iso->SetObjectGroupId(g2s1.handle, id2); 3771 iso->SetObjectGroupId(g2s2.handle, id2); 3772 iso->SetReferenceFromGroup(id2, g2c1.handle); 3773 } 3774 // Do a single full GC, ensure incremental marking is stopped. 3775 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3776 iso)->heap(); 3777 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3778 3779 // All object should be alive. 3780 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3781 3782 // Weaken the root. 3783 root.handle.SetWeak(&root, &WeakPointerCallback); 3784 // But make children strong roots---all the objects (except for children) 3785 // should be collectable now. 3786 g1c1.handle.ClearWeak(); 3787 g2c1.handle.ClearWeak(); 3788 3789 // Groups are deleted, rebuild groups. 3790 { 3791 UniqueId id1 = MakeUniqueId(g1s1.handle); 3792 UniqueId id2 = MakeUniqueId(g2s2.handle); 3793 iso->SetObjectGroupId(g1s1.handle, id1); 3794 iso->SetObjectGroupId(g1s2.handle, id1); 3795 iso->SetReferenceFromGroup(id1, g1c1.handle); 3796 iso->SetObjectGroupId(g2s1.handle, id2); 3797 iso->SetObjectGroupId(g2s2.handle, id2); 3798 iso->SetReferenceFromGroup(id2, g2c1.handle); 3799 } 3800 3801 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3802 3803 // All objects should be gone. 5 global handles in total. 3804 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3805 3806 // And now make children weak again and collect them. 3807 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3808 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3809 3810 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3811 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3812 } 3813 3814 3815 THREADED_TEST(ApiObjectGroupsForSubtypes) { 3816 LocalContext env; 3817 v8::Isolate* iso = env->GetIsolate(); 3818 HandleScope scope(iso); 3819 3820 WeakCallCounter counter(1234); 3821 3822 WeakCallCounterAndPersistent<Object> g1s1(&counter); 3823 WeakCallCounterAndPersistent<String> g1s2(&counter); 3824 WeakCallCounterAndPersistent<String> g1c1(&counter); 3825 WeakCallCounterAndPersistent<Object> g2s1(&counter); 3826 WeakCallCounterAndPersistent<String> g2s2(&counter); 3827 WeakCallCounterAndPersistent<String> g2c1(&counter); 3828 3829 { 3830 HandleScope scope(iso); 3831 g1s1.handle.Reset(iso, Object::New(iso)); 3832 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1")); 3833 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2")); 3834 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3835 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3836 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3837 3838 g2s1.handle.Reset(iso, Object::New(iso)); 3839 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3")); 3840 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4")); 3841 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3842 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3843 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3844 } 3845 3846 WeakCallCounterAndPersistent<Value> root(&counter); 3847 root.handle.Reset(iso, g1s1.handle); // make a root. 3848 3849 // Connect group 1 and 2, make a cycle. 3850 { 3851 HandleScope scope(iso); 3852 CHECK(Local<Object>::New(iso, g1s1.handle) 3853 ->Set(0, Local<Object>::New(iso, g2s1.handle))); 3854 CHECK(Local<Object>::New(iso, g2s1.handle) 3855 ->Set(0, Local<Object>::New(iso, g1s1.handle))); 3856 } 3857 3858 { 3859 UniqueId id1 = MakeUniqueId(g1s1.handle); 3860 UniqueId id2 = MakeUniqueId(g2s2.handle); 3861 iso->SetObjectGroupId(g1s1.handle, id1); 3862 iso->SetObjectGroupId(g1s2.handle, id1); 3863 iso->SetReference(g1s1.handle, g1c1.handle); 3864 iso->SetObjectGroupId(g2s1.handle, id2); 3865 iso->SetObjectGroupId(g2s2.handle, id2); 3866 iso->SetReferenceFromGroup(id2, g2c1.handle); 3867 } 3868 // Do a single full GC, ensure incremental marking is stopped. 3869 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3870 iso)->heap(); 3871 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3872 3873 // All object should be alive. 3874 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3875 3876 // Weaken the root. 3877 root.handle.SetWeak(&root, &WeakPointerCallback); 3878 // But make children strong roots---all the objects (except for children) 3879 // should be collectable now. 3880 g1c1.handle.ClearWeak(); 3881 g2c1.handle.ClearWeak(); 3882 3883 // Groups are deleted, rebuild groups. 3884 { 3885 UniqueId id1 = MakeUniqueId(g1s1.handle); 3886 UniqueId id2 = MakeUniqueId(g2s2.handle); 3887 iso->SetObjectGroupId(g1s1.handle, id1); 3888 iso->SetObjectGroupId(g1s2.handle, id1); 3889 iso->SetReference(g1s1.handle, g1c1.handle); 3890 iso->SetObjectGroupId(g2s1.handle, id2); 3891 iso->SetObjectGroupId(g2s2.handle, id2); 3892 iso->SetReferenceFromGroup(id2, g2c1.handle); 3893 } 3894 3895 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3896 3897 // All objects should be gone. 5 global handles in total. 3898 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3899 3900 // And now make children weak again and collect them. 3901 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3902 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3903 3904 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3905 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3906 } 3907 3908 3909 THREADED_TEST(ApiObjectGroupsCycle) { 3910 LocalContext env; 3911 v8::Isolate* iso = env->GetIsolate(); 3912 HandleScope scope(iso); 3913 3914 WeakCallCounter counter(1234); 3915 3916 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3917 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3918 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3919 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3920 WeakCallCounterAndPersistent<Value> g3s1(&counter); 3921 WeakCallCounterAndPersistent<Value> g3s2(&counter); 3922 WeakCallCounterAndPersistent<Value> g4s1(&counter); 3923 WeakCallCounterAndPersistent<Value> g4s2(&counter); 3924 3925 { 3926 HandleScope scope(iso); 3927 g1s1.handle.Reset(iso, Object::New(iso)); 3928 g1s2.handle.Reset(iso, Object::New(iso)); 3929 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3930 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3931 CHECK(g1s1.handle.IsWeak()); 3932 CHECK(g1s2.handle.IsWeak()); 3933 3934 g2s1.handle.Reset(iso, Object::New(iso)); 3935 g2s2.handle.Reset(iso, Object::New(iso)); 3936 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3937 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3938 CHECK(g2s1.handle.IsWeak()); 3939 CHECK(g2s2.handle.IsWeak()); 3940 3941 g3s1.handle.Reset(iso, Object::New(iso)); 3942 g3s2.handle.Reset(iso, Object::New(iso)); 3943 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 3944 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 3945 CHECK(g3s1.handle.IsWeak()); 3946 CHECK(g3s2.handle.IsWeak()); 3947 3948 g4s1.handle.Reset(iso, Object::New(iso)); 3949 g4s2.handle.Reset(iso, Object::New(iso)); 3950 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback); 3951 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback); 3952 CHECK(g4s1.handle.IsWeak()); 3953 CHECK(g4s2.handle.IsWeak()); 3954 } 3955 3956 WeakCallCounterAndPersistent<Value> root(&counter); 3957 root.handle.Reset(iso, g1s1.handle); // make a root. 3958 3959 // Connect groups. We're building the following cycle: 3960 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 3961 // groups. 3962 { 3963 UniqueId id1 = MakeUniqueId(g1s1.handle); 3964 UniqueId id2 = MakeUniqueId(g2s1.handle); 3965 UniqueId id3 = MakeUniqueId(g3s1.handle); 3966 UniqueId id4 = MakeUniqueId(g4s1.handle); 3967 iso->SetObjectGroupId(g1s1.handle, id1); 3968 iso->SetObjectGroupId(g1s2.handle, id1); 3969 iso->SetReferenceFromGroup(id1, g2s1.handle); 3970 iso->SetObjectGroupId(g2s1.handle, id2); 3971 iso->SetObjectGroupId(g2s2.handle, id2); 3972 iso->SetReferenceFromGroup(id2, g3s1.handle); 3973 iso->SetObjectGroupId(g3s1.handle, id3); 3974 iso->SetObjectGroupId(g3s2.handle, id3); 3975 iso->SetReferenceFromGroup(id3, g4s1.handle); 3976 iso->SetObjectGroupId(g4s1.handle, id4); 3977 iso->SetObjectGroupId(g4s2.handle, id4); 3978 iso->SetReferenceFromGroup(id4, g1s1.handle); 3979 } 3980 // Do a single full GC 3981 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3982 iso)->heap(); 3983 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3984 3985 // All object should be alive. 3986 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3987 3988 // Weaken the root. 3989 root.handle.SetWeak(&root, &WeakPointerCallback); 3990 3991 // Groups are deleted, rebuild groups. 3992 { 3993 UniqueId id1 = MakeUniqueId(g1s1.handle); 3994 UniqueId id2 = MakeUniqueId(g2s1.handle); 3995 UniqueId id3 = MakeUniqueId(g3s1.handle); 3996 UniqueId id4 = MakeUniqueId(g4s1.handle); 3997 iso->SetObjectGroupId(g1s1.handle, id1); 3998 iso->SetObjectGroupId(g1s2.handle, id1); 3999 iso->SetReferenceFromGroup(id1, g2s1.handle); 4000 iso->SetObjectGroupId(g2s1.handle, id2); 4001 iso->SetObjectGroupId(g2s2.handle, id2); 4002 iso->SetReferenceFromGroup(id2, g3s1.handle); 4003 iso->SetObjectGroupId(g3s1.handle, id3); 4004 iso->SetObjectGroupId(g3s2.handle, id3); 4005 iso->SetReferenceFromGroup(id3, g4s1.handle); 4006 iso->SetObjectGroupId(g4s1.handle, id4); 4007 iso->SetObjectGroupId(g4s2.handle, id4); 4008 iso->SetReferenceFromGroup(id4, g1s1.handle); 4009 } 4010 4011 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4012 4013 // All objects should be gone. 9 global handles in total. 4014 CHECK_EQ(9, counter.NumberOfWeakCalls()); 4015 } 4016 4017 4018 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures 4019 // on the buildbots, so was made non-threaded for the time being. 4020 TEST(ApiObjectGroupsCycleForScavenger) { 4021 i::FLAG_stress_compaction = false; 4022 i::FLAG_gc_global = false; 4023 LocalContext env; 4024 v8::Isolate* iso = env->GetIsolate(); 4025 HandleScope scope(iso); 4026 4027 WeakCallCounter counter(1234); 4028 4029 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4030 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4031 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4032 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4033 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4034 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4035 4036 { 4037 HandleScope scope(iso); 4038 g1s1.handle.Reset(iso, Object::New(iso)); 4039 g1s2.handle.Reset(iso, Object::New(iso)); 4040 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 4041 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 4042 4043 g2s1.handle.Reset(iso, Object::New(iso)); 4044 g2s2.handle.Reset(iso, Object::New(iso)); 4045 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 4046 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 4047 4048 g3s1.handle.Reset(iso, Object::New(iso)); 4049 g3s2.handle.Reset(iso, Object::New(iso)); 4050 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 4051 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 4052 } 4053 4054 // Make a root. 4055 WeakCallCounterAndPersistent<Value> root(&counter); 4056 root.handle.Reset(iso, g1s1.handle); 4057 root.handle.MarkPartiallyDependent(); 4058 4059 // Connect groups. We're building the following cycle: 4060 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4061 // groups. 4062 { 4063 HandleScope handle_scope(iso); 4064 g1s1.handle.MarkPartiallyDependent(); 4065 g1s2.handle.MarkPartiallyDependent(); 4066 g2s1.handle.MarkPartiallyDependent(); 4067 g2s2.handle.MarkPartiallyDependent(); 4068 g3s1.handle.MarkPartiallyDependent(); 4069 g3s2.handle.MarkPartiallyDependent(); 4070 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4071 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4072 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 4073 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 4074 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4075 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4076 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 4077 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 4078 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4079 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4080 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 4081 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 4082 } 4083 4084 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 4085 iso)->heap(); 4086 heap->CollectAllGarbage(i::Heap::kNoGCFlags); 4087 4088 // All objects should be alive. 4089 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4090 4091 // Weaken the root. 4092 root.handle.SetWeak(&root, &WeakPointerCallback); 4093 root.handle.MarkPartiallyDependent(); 4094 4095 // Groups are deleted, rebuild groups. 4096 { 4097 HandleScope handle_scope(iso); 4098 g1s1.handle.MarkPartiallyDependent(); 4099 g1s2.handle.MarkPartiallyDependent(); 4100 g2s1.handle.MarkPartiallyDependent(); 4101 g2s2.handle.MarkPartiallyDependent(); 4102 g3s1.handle.MarkPartiallyDependent(); 4103 g3s2.handle.MarkPartiallyDependent(); 4104 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4105 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4106 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 4107 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 4108 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4109 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4110 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 4111 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 4112 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4113 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4114 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 4115 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 4116 } 4117 4118 heap->CollectAllGarbage(i::Heap::kNoGCFlags); 4119 4120 // All objects should be gone. 7 global handles in total. 4121 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4122 } 4123 4124 4125 THREADED_TEST(ScriptException) { 4126 LocalContext env; 4127 v8::HandleScope scope(env->GetIsolate()); 4128 Local<Script> script = v8_compile("throw 'panama!';"); 4129 v8::TryCatch try_catch; 4130 Local<Value> result = script->Run(); 4131 CHECK(result.IsEmpty()); 4132 CHECK(try_catch.HasCaught()); 4133 String::Utf8Value exception_value(try_catch.Exception()); 4134 CHECK_EQ(*exception_value, "panama!"); 4135 } 4136 4137 4138 TEST(TryCatchCustomException) { 4139 LocalContext env; 4140 v8::HandleScope scope(env->GetIsolate()); 4141 v8::TryCatch try_catch; 4142 CompileRun("function CustomError() { this.a = 'b'; }" 4143 "(function f() { throw new CustomError(); })();"); 4144 CHECK(try_catch.HasCaught()); 4145 CHECK(try_catch.Exception()->ToObject()-> 4146 Get(v8_str("a"))->Equals(v8_str("b"))); 4147 } 4148 4149 4150 bool message_received; 4151 4152 4153 static void check_message_0(v8::Handle<v8::Message> message, 4154 v8::Handle<Value> data) { 4155 CHECK_EQ(5.76, data->NumberValue()); 4156 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4157 CHECK(!message->IsSharedCrossOrigin()); 4158 message_received = true; 4159 } 4160 4161 4162 THREADED_TEST(MessageHandler0) { 4163 message_received = false; 4164 v8::HandleScope scope(CcTest::isolate()); 4165 CHECK(!message_received); 4166 LocalContext context; 4167 v8::V8::AddMessageListener(check_message_0, v8_num(5.76)); 4168 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75"); 4169 script->Run(); 4170 CHECK(message_received); 4171 // clear out the message listener 4172 v8::V8::RemoveMessageListeners(check_message_0); 4173 } 4174 4175 4176 static void check_message_1(v8::Handle<v8::Message> message, 4177 v8::Handle<Value> data) { 4178 CHECK(data->IsNumber()); 4179 CHECK_EQ(1337, data->Int32Value()); 4180 CHECK(!message->IsSharedCrossOrigin()); 4181 message_received = true; 4182 } 4183 4184 4185 TEST(MessageHandler1) { 4186 message_received = false; 4187 v8::HandleScope scope(CcTest::isolate()); 4188 CHECK(!message_received); 4189 v8::V8::AddMessageListener(check_message_1); 4190 LocalContext context; 4191 CompileRun("throw 1337;"); 4192 CHECK(message_received); 4193 // clear out the message listener 4194 v8::V8::RemoveMessageListeners(check_message_1); 4195 } 4196 4197 4198 static void check_message_2(v8::Handle<v8::Message> message, 4199 v8::Handle<Value> data) { 4200 LocalContext context; 4201 CHECK(data->IsObject()); 4202 v8::Local<v8::Value> hidden_property = 4203 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); 4204 CHECK(v8_str("hidden value")->Equals(hidden_property)); 4205 CHECK(!message->IsSharedCrossOrigin()); 4206 message_received = true; 4207 } 4208 4209 4210 TEST(MessageHandler2) { 4211 message_received = false; 4212 v8::HandleScope scope(CcTest::isolate()); 4213 CHECK(!message_received); 4214 v8::V8::AddMessageListener(check_message_2); 4215 LocalContext context; 4216 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 4217 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), 4218 v8_str("hidden value")); 4219 context->Global()->Set(v8_str("error"), error); 4220 CompileRun("throw error;"); 4221 CHECK(message_received); 4222 // clear out the message listener 4223 v8::V8::RemoveMessageListeners(check_message_2); 4224 } 4225 4226 4227 static void check_message_3(v8::Handle<v8::Message> message, 4228 v8::Handle<Value> data) { 4229 CHECK(message->IsSharedCrossOrigin()); 4230 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4231 message_received = true; 4232 } 4233 4234 4235 TEST(MessageHandler3) { 4236 message_received = false; 4237 v8::Isolate* isolate = CcTest::isolate(); 4238 v8::HandleScope scope(isolate); 4239 CHECK(!message_received); 4240 v8::V8::AddMessageListener(check_message_3); 4241 LocalContext context; 4242 v8::ScriptOrigin origin = 4243 v8::ScriptOrigin(v8_str("6.75"), 4244 v8::Integer::New(isolate, 1), 4245 v8::Integer::New(isolate, 2), 4246 v8::True(isolate)); 4247 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4248 &origin); 4249 script->Run(); 4250 CHECK(message_received); 4251 // clear out the message listener 4252 v8::V8::RemoveMessageListeners(check_message_3); 4253 } 4254 4255 4256 static void check_message_4(v8::Handle<v8::Message> message, 4257 v8::Handle<Value> data) { 4258 CHECK(!message->IsSharedCrossOrigin()); 4259 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4260 message_received = true; 4261 } 4262 4263 4264 TEST(MessageHandler4) { 4265 message_received = false; 4266 v8::Isolate* isolate = CcTest::isolate(); 4267 v8::HandleScope scope(isolate); 4268 CHECK(!message_received); 4269 v8::V8::AddMessageListener(check_message_4); 4270 LocalContext context; 4271 v8::ScriptOrigin origin = 4272 v8::ScriptOrigin(v8_str("6.75"), 4273 v8::Integer::New(isolate, 1), 4274 v8::Integer::New(isolate, 2), 4275 v8::False(isolate)); 4276 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4277 &origin); 4278 script->Run(); 4279 CHECK(message_received); 4280 // clear out the message listener 4281 v8::V8::RemoveMessageListeners(check_message_4); 4282 } 4283 4284 4285 static void check_message_5a(v8::Handle<v8::Message> message, 4286 v8::Handle<Value> data) { 4287 CHECK(message->IsSharedCrossOrigin()); 4288 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4289 message_received = true; 4290 } 4291 4292 4293 static void check_message_5b(v8::Handle<v8::Message> message, 4294 v8::Handle<Value> data) { 4295 CHECK(!message->IsSharedCrossOrigin()); 4296 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4297 message_received = true; 4298 } 4299 4300 4301 TEST(MessageHandler5) { 4302 message_received = false; 4303 v8::Isolate* isolate = CcTest::isolate(); 4304 v8::HandleScope scope(isolate); 4305 CHECK(!message_received); 4306 v8::V8::AddMessageListener(check_message_5a); 4307 LocalContext context; 4308 v8::ScriptOrigin origin = 4309 v8::ScriptOrigin(v8_str("6.75"), 4310 v8::Integer::New(isolate, 1), 4311 v8::Integer::New(isolate, 2), 4312 v8::True(isolate)); 4313 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4314 &origin); 4315 script->Run(); 4316 CHECK(message_received); 4317 // clear out the message listener 4318 v8::V8::RemoveMessageListeners(check_message_5a); 4319 4320 message_received = false; 4321 v8::V8::AddMessageListener(check_message_5b); 4322 origin = 4323 v8::ScriptOrigin(v8_str("6.75"), 4324 v8::Integer::New(isolate, 1), 4325 v8::Integer::New(isolate, 2), 4326 v8::False(isolate)); 4327 script = Script::Compile(v8_str("throw 'error'"), 4328 &origin); 4329 script->Run(); 4330 CHECK(message_received); 4331 // clear out the message listener 4332 v8::V8::RemoveMessageListeners(check_message_5b); 4333 } 4334 4335 4336 THREADED_TEST(GetSetProperty) { 4337 LocalContext context; 4338 v8::Isolate* isolate = context->GetIsolate(); 4339 v8::HandleScope scope(isolate); 4340 context->Global()->Set(v8_str("foo"), v8_num(14)); 4341 context->Global()->Set(v8_str("12"), v8_num(92)); 4342 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32)); 4343 context->Global()->Set(v8_num(13), v8_num(56)); 4344 Local<Value> foo = CompileRun("this.foo"); 4345 CHECK_EQ(14, foo->Int32Value()); 4346 Local<Value> twelve = CompileRun("this[12]"); 4347 CHECK_EQ(92, twelve->Int32Value()); 4348 Local<Value> sixteen = CompileRun("this[16]"); 4349 CHECK_EQ(32, sixteen->Int32Value()); 4350 Local<Value> thirteen = CompileRun("this[13]"); 4351 CHECK_EQ(56, thirteen->Int32Value()); 4352 CHECK_EQ(92, 4353 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value()); 4354 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value()); 4355 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value()); 4356 CHECK_EQ(32, 4357 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value()); 4358 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value()); 4359 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value()); 4360 CHECK_EQ(56, 4361 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value()); 4362 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value()); 4363 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value()); 4364 } 4365 4366 4367 THREADED_TEST(PropertyAttributes) { 4368 LocalContext context; 4369 v8::HandleScope scope(context->GetIsolate()); 4370 // none 4371 Local<String> prop = v8_str("none"); 4372 context->Global()->Set(prop, v8_num(7)); 4373 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4374 // read-only 4375 prop = v8_str("read_only"); 4376 context->Global()->Set(prop, v8_num(7), v8::ReadOnly); 4377 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4378 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); 4379 CompileRun("read_only = 9"); 4380 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4381 context->Global()->Set(prop, v8_num(10)); 4382 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4383 // dont-delete 4384 prop = v8_str("dont_delete"); 4385 context->Global()->Set(prop, v8_num(13), v8::DontDelete); 4386 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4387 CompileRun("delete dont_delete"); 4388 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4389 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); 4390 // dont-enum 4391 prop = v8_str("dont_enum"); 4392 context->Global()->Set(prop, v8_num(28), v8::DontEnum); 4393 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); 4394 // absent 4395 prop = v8_str("absent"); 4396 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4397 Local<Value> fake_prop = v8_num(1); 4398 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); 4399 // exception 4400 TryCatch try_catch; 4401 Local<Value> exception = 4402 CompileRun("({ toString: function() { throw 'exception';} })"); 4403 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); 4404 CHECK(try_catch.HasCaught()); 4405 String::Utf8Value exception_value(try_catch.Exception()); 4406 CHECK_EQ("exception", *exception_value); 4407 try_catch.Reset(); 4408 } 4409 4410 4411 THREADED_TEST(Array) { 4412 LocalContext context; 4413 v8::HandleScope scope(context->GetIsolate()); 4414 Local<v8::Array> array = v8::Array::New(context->GetIsolate()); 4415 CHECK_EQ(0, array->Length()); 4416 CHECK(array->Get(0)->IsUndefined()); 4417 CHECK(!array->Has(0)); 4418 CHECK(array->Get(100)->IsUndefined()); 4419 CHECK(!array->Has(100)); 4420 array->Set(2, v8_num(7)); 4421 CHECK_EQ(3, array->Length()); 4422 CHECK(!array->Has(0)); 4423 CHECK(!array->Has(1)); 4424 CHECK(array->Has(2)); 4425 CHECK_EQ(7, array->Get(2)->Int32Value()); 4426 Local<Value> obj = CompileRun("[1, 2, 3]"); 4427 Local<v8::Array> arr = obj.As<v8::Array>(); 4428 CHECK_EQ(3, arr->Length()); 4429 CHECK_EQ(1, arr->Get(0)->Int32Value()); 4430 CHECK_EQ(2, arr->Get(1)->Int32Value()); 4431 CHECK_EQ(3, arr->Get(2)->Int32Value()); 4432 array = v8::Array::New(context->GetIsolate(), 27); 4433 CHECK_EQ(27, array->Length()); 4434 array = v8::Array::New(context->GetIsolate(), -27); 4435 CHECK_EQ(0, array->Length()); 4436 } 4437 4438 4439 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 4440 v8::EscapableHandleScope scope(args.GetIsolate()); 4441 ApiTestFuzzer::Fuzz(); 4442 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); 4443 for (int i = 0; i < args.Length(); i++) 4444 result->Set(i, args[i]); 4445 args.GetReturnValue().Set(scope.Escape(result)); 4446 } 4447 4448 4449 THREADED_TEST(Vector) { 4450 v8::Isolate* isolate = CcTest::isolate(); 4451 v8::HandleScope scope(isolate); 4452 Local<ObjectTemplate> global = ObjectTemplate::New(isolate); 4453 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF)); 4454 LocalContext context(0, global); 4455 4456 const char* fun = "f()"; 4457 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 4458 CHECK_EQ(0, a0->Length()); 4459 4460 const char* fun2 = "f(11)"; 4461 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 4462 CHECK_EQ(1, a1->Length()); 4463 CHECK_EQ(11, a1->Get(0)->Int32Value()); 4464 4465 const char* fun3 = "f(12, 13)"; 4466 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 4467 CHECK_EQ(2, a2->Length()); 4468 CHECK_EQ(12, a2->Get(0)->Int32Value()); 4469 CHECK_EQ(13, a2->Get(1)->Int32Value()); 4470 4471 const char* fun4 = "f(14, 15, 16)"; 4472 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 4473 CHECK_EQ(3, a3->Length()); 4474 CHECK_EQ(14, a3->Get(0)->Int32Value()); 4475 CHECK_EQ(15, a3->Get(1)->Int32Value()); 4476 CHECK_EQ(16, a3->Get(2)->Int32Value()); 4477 4478 const char* fun5 = "f(17, 18, 19, 20)"; 4479 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 4480 CHECK_EQ(4, a4->Length()); 4481 CHECK_EQ(17, a4->Get(0)->Int32Value()); 4482 CHECK_EQ(18, a4->Get(1)->Int32Value()); 4483 CHECK_EQ(19, a4->Get(2)->Int32Value()); 4484 CHECK_EQ(20, a4->Get(3)->Int32Value()); 4485 } 4486 4487 4488 THREADED_TEST(FunctionCall) { 4489 LocalContext context; 4490 v8::Isolate* isolate = context->GetIsolate(); 4491 v8::HandleScope scope(isolate); 4492 CompileRun( 4493 "function Foo() {" 4494 " var result = [];" 4495 " for (var i = 0; i < arguments.length; i++) {" 4496 " result.push(arguments[i]);" 4497 " }" 4498 " return result;" 4499 "}" 4500 "function ReturnThisSloppy() {" 4501 " return this;" 4502 "}" 4503 "function ReturnThisStrict() {" 4504 " 'use strict';" 4505 " return this;" 4506 "}"); 4507 Local<Function> Foo = 4508 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4509 Local<Function> ReturnThisSloppy = 4510 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy"))); 4511 Local<Function> ReturnThisStrict = 4512 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict"))); 4513 4514 v8::Handle<Value>* args0 = NULL; 4515 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0)); 4516 CHECK_EQ(0, a0->Length()); 4517 4518 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4519 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1)); 4520 CHECK_EQ(1, a1->Length()); 4521 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4522 4523 v8::Handle<Value> args2[] = { v8_num(2.2), 4524 v8_num(3.3) }; 4525 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2)); 4526 CHECK_EQ(2, a2->Length()); 4527 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4528 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4529 4530 v8::Handle<Value> args3[] = { v8_num(4.4), 4531 v8_num(5.5), 4532 v8_num(6.6) }; 4533 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3)); 4534 CHECK_EQ(3, a3->Length()); 4535 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4536 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4537 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4538 4539 v8::Handle<Value> args4[] = { v8_num(7.7), 4540 v8_num(8.8), 4541 v8_num(9.9), 4542 v8_num(10.11) }; 4543 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4)); 4544 CHECK_EQ(4, a4->Length()); 4545 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4546 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4547 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4548 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue()); 4549 4550 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL); 4551 CHECK(r1->StrictEquals(context->Global())); 4552 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL); 4553 CHECK(r2->StrictEquals(context->Global())); 4554 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL); 4555 CHECK(r3->IsNumberObject()); 4556 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf()); 4557 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL); 4558 CHECK(r4->IsStringObject()); 4559 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 4560 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL); 4561 CHECK(r5->IsBooleanObject()); 4562 CHECK(r5.As<v8::BooleanObject>()->ValueOf()); 4563 4564 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL); 4565 CHECK(r6->IsUndefined()); 4566 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL); 4567 CHECK(r7->IsNull()); 4568 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL); 4569 CHECK(r8->StrictEquals(v8_num(42))); 4570 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL); 4571 CHECK(r9->StrictEquals(v8_str("hello"))); 4572 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL); 4573 CHECK(r10->StrictEquals(v8::True(isolate))); 4574 } 4575 4576 4577 THREADED_TEST(ConstructCall) { 4578 LocalContext context; 4579 v8::Isolate* isolate = context->GetIsolate(); 4580 v8::HandleScope scope(isolate); 4581 CompileRun( 4582 "function Foo() {" 4583 " var result = [];" 4584 " for (var i = 0; i < arguments.length; i++) {" 4585 " result.push(arguments[i]);" 4586 " }" 4587 " return result;" 4588 "}"); 4589 Local<Function> Foo = 4590 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4591 4592 v8::Handle<Value>* args0 = NULL; 4593 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0)); 4594 CHECK_EQ(0, a0->Length()); 4595 4596 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4597 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1)); 4598 CHECK_EQ(1, a1->Length()); 4599 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4600 4601 v8::Handle<Value> args2[] = { v8_num(2.2), 4602 v8_num(3.3) }; 4603 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2)); 4604 CHECK_EQ(2, a2->Length()); 4605 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4606 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4607 4608 v8::Handle<Value> args3[] = { v8_num(4.4), 4609 v8_num(5.5), 4610 v8_num(6.6) }; 4611 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3)); 4612 CHECK_EQ(3, a3->Length()); 4613 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4614 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4615 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4616 4617 v8::Handle<Value> args4[] = { v8_num(7.7), 4618 v8_num(8.8), 4619 v8_num(9.9), 4620 v8_num(10.11) }; 4621 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4)); 4622 CHECK_EQ(4, a4->Length()); 4623 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4624 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4625 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4626 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue()); 4627 } 4628 4629 4630 static void CheckUncle(v8::TryCatch* try_catch) { 4631 CHECK(try_catch->HasCaught()); 4632 String::Utf8Value str_value(try_catch->Exception()); 4633 CHECK_EQ(*str_value, "uncle?"); 4634 try_catch->Reset(); 4635 } 4636 4637 4638 THREADED_TEST(ConversionNumber) { 4639 LocalContext env; 4640 v8::HandleScope scope(env->GetIsolate()); 4641 // Very large number. 4642 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4643 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4644 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value()); 4645 CHECK_EQ(0, obj->ToInt32()->Value()); 4646 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned. 4647 // Large number. 4648 CompileRun("var obj = -1234567890123;"); 4649 obj = env->Global()->Get(v8_str("obj")); 4650 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value()); 4651 CHECK_EQ(-1912276171, obj->ToInt32()->Value()); 4652 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT 4653 // Small positive integer. 4654 CompileRun("var obj = 42;"); 4655 obj = env->Global()->Get(v8_str("obj")); 4656 CHECK_EQ(42.0, obj->ToNumber()->Value()); 4657 CHECK_EQ(42, obj->ToInt32()->Value()); 4658 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4659 // Negative integer. 4660 CompileRun("var obj = -37;"); 4661 obj = env->Global()->Get(v8_str("obj")); 4662 CHECK_EQ(-37.0, obj->ToNumber()->Value()); 4663 CHECK_EQ(-37, obj->ToInt32()->Value()); 4664 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT 4665 // Positive non-int32 integer. 4666 CompileRun("var obj = 0x81234567;"); 4667 obj = env->Global()->Get(v8_str("obj")); 4668 CHECK_EQ(2166572391.0, obj->ToNumber()->Value()); 4669 CHECK_EQ(-2128394905, obj->ToInt32()->Value()); 4670 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT 4671 // Fraction. 4672 CompileRun("var obj = 42.3;"); 4673 obj = env->Global()->Get(v8_str("obj")); 4674 CHECK_EQ(42.3, obj->ToNumber()->Value()); 4675 CHECK_EQ(42, obj->ToInt32()->Value()); 4676 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4677 // Large negative fraction. 4678 CompileRun("var obj = -5726623061.75;"); 4679 obj = env->Global()->Get(v8_str("obj")); 4680 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value()); 4681 CHECK_EQ(-1431655765, obj->ToInt32()->Value()); 4682 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT 4683 } 4684 4685 4686 THREADED_TEST(isNumberType) { 4687 LocalContext env; 4688 v8::HandleScope scope(env->GetIsolate()); 4689 // Very large number. 4690 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4691 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4692 CHECK(!obj->IsInt32()); 4693 CHECK(!obj->IsUint32()); 4694 // Large negative number. 4695 CompileRun("var obj = -1234567890123;"); 4696 obj = env->Global()->Get(v8_str("obj")); 4697 CHECK(!obj->IsInt32()); 4698 CHECK(!obj->IsUint32()); 4699 // Small positive integer. 4700 CompileRun("var obj = 42;"); 4701 obj = env->Global()->Get(v8_str("obj")); 4702 CHECK(obj->IsInt32()); 4703 CHECK(obj->IsUint32()); 4704 // Negative integer. 4705 CompileRun("var obj = -37;"); 4706 obj = env->Global()->Get(v8_str("obj")); 4707 CHECK(obj->IsInt32()); 4708 CHECK(!obj->IsUint32()); 4709 // Positive non-int32 integer. 4710 CompileRun("var obj = 0x81234567;"); 4711 obj = env->Global()->Get(v8_str("obj")); 4712 CHECK(!obj->IsInt32()); 4713 CHECK(obj->IsUint32()); 4714 // Fraction. 4715 CompileRun("var obj = 42.3;"); 4716 obj = env->Global()->Get(v8_str("obj")); 4717 CHECK(!obj->IsInt32()); 4718 CHECK(!obj->IsUint32()); 4719 // Large negative fraction. 4720 CompileRun("var obj = -5726623061.75;"); 4721 obj = env->Global()->Get(v8_str("obj")); 4722 CHECK(!obj->IsInt32()); 4723 CHECK(!obj->IsUint32()); 4724 // Positive zero 4725 CompileRun("var obj = 0.0;"); 4726 obj = env->Global()->Get(v8_str("obj")); 4727 CHECK(obj->IsInt32()); 4728 CHECK(obj->IsUint32()); 4729 // Positive zero 4730 CompileRun("var obj = -0.0;"); 4731 obj = env->Global()->Get(v8_str("obj")); 4732 CHECK(!obj->IsInt32()); 4733 CHECK(!obj->IsUint32()); 4734 } 4735 4736 4737 THREADED_TEST(ConversionException) { 4738 LocalContext env; 4739 v8::Isolate* isolate = env->GetIsolate(); 4740 v8::HandleScope scope(isolate); 4741 CompileRun( 4742 "function TestClass() { };" 4743 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 4744 "var obj = new TestClass();"); 4745 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4746 4747 v8::TryCatch try_catch; 4748 4749 Local<Value> to_string_result = obj->ToString(); 4750 CHECK(to_string_result.IsEmpty()); 4751 CheckUncle(&try_catch); 4752 4753 Local<Value> to_number_result = obj->ToNumber(); 4754 CHECK(to_number_result.IsEmpty()); 4755 CheckUncle(&try_catch); 4756 4757 Local<Value> to_integer_result = obj->ToInteger(); 4758 CHECK(to_integer_result.IsEmpty()); 4759 CheckUncle(&try_catch); 4760 4761 Local<Value> to_uint32_result = obj->ToUint32(); 4762 CHECK(to_uint32_result.IsEmpty()); 4763 CheckUncle(&try_catch); 4764 4765 Local<Value> to_int32_result = obj->ToInt32(); 4766 CHECK(to_int32_result.IsEmpty()); 4767 CheckUncle(&try_catch); 4768 4769 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(); 4770 CHECK(to_object_result.IsEmpty()); 4771 CHECK(try_catch.HasCaught()); 4772 try_catch.Reset(); 4773 4774 int32_t int32_value = obj->Int32Value(); 4775 CHECK_EQ(0, int32_value); 4776 CheckUncle(&try_catch); 4777 4778 uint32_t uint32_value = obj->Uint32Value(); 4779 CHECK_EQ(0, uint32_value); 4780 CheckUncle(&try_catch); 4781 4782 double number_value = obj->NumberValue(); 4783 CHECK_NE(0, std::isnan(number_value)); 4784 CheckUncle(&try_catch); 4785 4786 int64_t integer_value = obj->IntegerValue(); 4787 CHECK_EQ(0.0, static_cast<double>(integer_value)); 4788 CheckUncle(&try_catch); 4789 } 4790 4791 4792 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 4793 ApiTestFuzzer::Fuzz(); 4794 args.GetIsolate()->ThrowException(v8_str("konto")); 4795 } 4796 4797 4798 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 4799 if (args.Length() < 1) { 4800 args.GetReturnValue().Set(false); 4801 return; 4802 } 4803 v8::HandleScope scope(args.GetIsolate()); 4804 v8::TryCatch try_catch; 4805 Local<Value> result = CompileRun(args[0]->ToString()); 4806 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 4807 args.GetReturnValue().Set(try_catch.HasCaught()); 4808 } 4809 4810 4811 THREADED_TEST(APICatch) { 4812 v8::Isolate* isolate = CcTest::isolate(); 4813 v8::HandleScope scope(isolate); 4814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4815 templ->Set(v8_str("ThrowFromC"), 4816 v8::FunctionTemplate::New(isolate, ThrowFromC)); 4817 LocalContext context(0, templ); 4818 CompileRun( 4819 "var thrown = false;" 4820 "try {" 4821 " ThrowFromC();" 4822 "} catch (e) {" 4823 " thrown = true;" 4824 "}"); 4825 Local<Value> thrown = context->Global()->Get(v8_str("thrown")); 4826 CHECK(thrown->BooleanValue()); 4827 } 4828 4829 4830 THREADED_TEST(APIThrowTryCatch) { 4831 v8::Isolate* isolate = CcTest::isolate(); 4832 v8::HandleScope scope(isolate); 4833 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4834 templ->Set(v8_str("ThrowFromC"), 4835 v8::FunctionTemplate::New(isolate, ThrowFromC)); 4836 LocalContext context(0, templ); 4837 v8::TryCatch try_catch; 4838 CompileRun("ThrowFromC();"); 4839 CHECK(try_catch.HasCaught()); 4840 } 4841 4842 4843 // Test that a try-finally block doesn't shadow a try-catch block 4844 // when setting up an external handler. 4845 // 4846 // BUG(271): Some of the exception propagation does not work on the 4847 // ARM simulator because the simulator separates the C++ stack and the 4848 // JS stack. This test therefore fails on the simulator. The test is 4849 // not threaded to allow the threading tests to run on the simulator. 4850 TEST(TryCatchInTryFinally) { 4851 v8::Isolate* isolate = CcTest::isolate(); 4852 v8::HandleScope scope(isolate); 4853 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4854 templ->Set(v8_str("CCatcher"), 4855 v8::FunctionTemplate::New(isolate, CCatcher)); 4856 LocalContext context(0, templ); 4857 Local<Value> result = CompileRun("try {" 4858 " try {" 4859 " CCatcher('throw 7;');" 4860 " } finally {" 4861 " }" 4862 "} catch (e) {" 4863 "}"); 4864 CHECK(result->IsTrue()); 4865 } 4866 4867 4868 static void check_reference_error_message( 4869 v8::Handle<v8::Message> message, 4870 v8::Handle<v8::Value> data) { 4871 const char* reference_error = "Uncaught ReferenceError: asdf is not defined"; 4872 CHECK(message->Get()->Equals(v8_str(reference_error))); 4873 } 4874 4875 4876 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) { 4877 ApiTestFuzzer::Fuzz(); 4878 CHECK(false); 4879 } 4880 4881 4882 // Test that overwritten methods are not invoked on uncaught exception 4883 // formatting. However, they are invoked when performing normal error 4884 // string conversions. 4885 TEST(APIThrowMessageOverwrittenToString) { 4886 v8::Isolate* isolate = CcTest::isolate(); 4887 v8::HandleScope scope(isolate); 4888 v8::V8::AddMessageListener(check_reference_error_message); 4889 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4890 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail)); 4891 LocalContext context(NULL, templ); 4892 CompileRun("asdf;"); 4893 CompileRun("var limit = {};" 4894 "limit.valueOf = fail;" 4895 "Error.stackTraceLimit = limit;"); 4896 CompileRun("asdf"); 4897 CompileRun("Array.prototype.pop = fail;"); 4898 CompileRun("Object.prototype.hasOwnProperty = fail;"); 4899 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); 4900 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); 4901 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); 4902 CompileRun("ReferenceError.prototype.toString =" 4903 " function() { return 'Whoops' }"); 4904 CompileRun("asdf;"); 4905 CompileRun("ReferenceError.prototype.constructor.name = void 0;"); 4906 CompileRun("asdf;"); 4907 CompileRun("ReferenceError.prototype.constructor = void 0;"); 4908 CompileRun("asdf;"); 4909 CompileRun("ReferenceError.prototype.__proto__ = new Object();"); 4910 CompileRun("asdf;"); 4911 CompileRun("ReferenceError.prototype = new Object();"); 4912 CompileRun("asdf;"); 4913 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }"); 4914 CHECK(string->Equals(v8_str("Whoops"))); 4915 CompileRun("ReferenceError.prototype.constructor = new Object();" 4916 "ReferenceError.prototype.constructor.name = 1;" 4917 "Number.prototype.toString = function() { return 'Whoops'; };" 4918 "ReferenceError.prototype.toString = Object.prototype.toString;"); 4919 CompileRun("asdf;"); 4920 v8::V8::RemoveMessageListeners(check_reference_error_message); 4921 } 4922 4923 4924 static void check_custom_error_tostring( 4925 v8::Handle<v8::Message> message, 4926 v8::Handle<v8::Value> data) { 4927 const char* uncaught_error = "Uncaught MyError toString"; 4928 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4929 } 4930 4931 4932 TEST(CustomErrorToString) { 4933 LocalContext context; 4934 v8::HandleScope scope(context->GetIsolate()); 4935 v8::V8::AddMessageListener(check_custom_error_tostring); 4936 CompileRun( 4937 "function MyError(name, message) { " 4938 " this.name = name; " 4939 " this.message = message; " 4940 "} " 4941 "MyError.prototype = Object.create(Error.prototype); " 4942 "MyError.prototype.toString = function() { " 4943 " return 'MyError toString'; " 4944 "}; " 4945 "throw new MyError('my name', 'my message'); "); 4946 v8::V8::RemoveMessageListeners(check_custom_error_tostring); 4947 } 4948 4949 4950 static void check_custom_error_message( 4951 v8::Handle<v8::Message> message, 4952 v8::Handle<v8::Value> data) { 4953 const char* uncaught_error = "Uncaught MyError: my message"; 4954 printf("%s\n", *v8::String::Utf8Value(message->Get())); 4955 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4956 } 4957 4958 4959 TEST(CustomErrorMessage) { 4960 LocalContext context; 4961 v8::HandleScope scope(context->GetIsolate()); 4962 v8::V8::AddMessageListener(check_custom_error_message); 4963 4964 // Handlebars. 4965 CompileRun( 4966 "function MyError(msg) { " 4967 " this.name = 'MyError'; " 4968 " this.message = msg; " 4969 "} " 4970 "MyError.prototype = new Error(); " 4971 "throw new MyError('my message'); "); 4972 4973 // Closure. 4974 CompileRun( 4975 "function MyError(msg) { " 4976 " this.name = 'MyError'; " 4977 " this.message = msg; " 4978 "} " 4979 "inherits = function(childCtor, parentCtor) { " 4980 " function tempCtor() {}; " 4981 " tempCtor.prototype = parentCtor.prototype; " 4982 " childCtor.superClass_ = parentCtor.prototype; " 4983 " childCtor.prototype = new tempCtor(); " 4984 " childCtor.prototype.constructor = childCtor; " 4985 "}; " 4986 "inherits(MyError, Error); " 4987 "throw new MyError('my message'); "); 4988 4989 // Object.create. 4990 CompileRun( 4991 "function MyError(msg) { " 4992 " this.name = 'MyError'; " 4993 " this.message = msg; " 4994 "} " 4995 "MyError.prototype = Object.create(Error.prototype); " 4996 "throw new MyError('my message'); "); 4997 4998 v8::V8::RemoveMessageListeners(check_custom_error_message); 4999 } 5000 5001 5002 static void receive_message(v8::Handle<v8::Message> message, 5003 v8::Handle<v8::Value> data) { 5004 message->Get(); 5005 message_received = true; 5006 } 5007 5008 5009 TEST(APIThrowMessage) { 5010 message_received = false; 5011 v8::Isolate* isolate = CcTest::isolate(); 5012 v8::HandleScope scope(isolate); 5013 v8::V8::AddMessageListener(receive_message); 5014 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5015 templ->Set(v8_str("ThrowFromC"), 5016 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5017 LocalContext context(0, templ); 5018 CompileRun("ThrowFromC();"); 5019 CHECK(message_received); 5020 v8::V8::RemoveMessageListeners(receive_message); 5021 } 5022 5023 5024 TEST(APIThrowMessageAndVerboseTryCatch) { 5025 message_received = false; 5026 v8::Isolate* isolate = CcTest::isolate(); 5027 v8::HandleScope scope(isolate); 5028 v8::V8::AddMessageListener(receive_message); 5029 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5030 templ->Set(v8_str("ThrowFromC"), 5031 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5032 LocalContext context(0, templ); 5033 v8::TryCatch try_catch; 5034 try_catch.SetVerbose(true); 5035 Local<Value> result = CompileRun("ThrowFromC();"); 5036 CHECK(try_catch.HasCaught()); 5037 CHECK(result.IsEmpty()); 5038 CHECK(message_received); 5039 v8::V8::RemoveMessageListeners(receive_message); 5040 } 5041 5042 5043 TEST(APIStackOverflowAndVerboseTryCatch) { 5044 message_received = false; 5045 LocalContext context; 5046 v8::HandleScope scope(context->GetIsolate()); 5047 v8::V8::AddMessageListener(receive_message); 5048 v8::TryCatch try_catch; 5049 try_catch.SetVerbose(true); 5050 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 5051 CHECK(try_catch.HasCaught()); 5052 CHECK(result.IsEmpty()); 5053 CHECK(message_received); 5054 v8::V8::RemoveMessageListeners(receive_message); 5055 } 5056 5057 5058 THREADED_TEST(ExternalScriptException) { 5059 v8::Isolate* isolate = CcTest::isolate(); 5060 v8::HandleScope scope(isolate); 5061 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5062 templ->Set(v8_str("ThrowFromC"), 5063 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5064 LocalContext context(0, templ); 5065 5066 v8::TryCatch try_catch; 5067 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';"); 5068 CHECK(result.IsEmpty()); 5069 CHECK(try_catch.HasCaught()); 5070 String::Utf8Value exception_value(try_catch.Exception()); 5071 CHECK_EQ("konto", *exception_value); 5072 } 5073 5074 5075 5076 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 5077 ApiTestFuzzer::Fuzz(); 5078 CHECK_EQ(4, args.Length()); 5079 int count = args[0]->Int32Value(); 5080 int cInterval = args[2]->Int32Value(); 5081 if (count == 0) { 5082 args.GetIsolate()->ThrowException(v8_str("FromC")); 5083 return; 5084 } else { 5085 Local<v8::Object> global = 5086 args.GetIsolate()->GetCurrentContext()->Global(); 5087 Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); 5088 v8::Handle<Value> argv[] = { v8_num(count - 1), 5089 args[1], 5090 args[2], 5091 args[3] }; 5092 if (count % cInterval == 0) { 5093 v8::TryCatch try_catch; 5094 Local<Value> result = fun.As<Function>()->Call(global, 4, argv); 5095 int expected = args[3]->Int32Value(); 5096 if (try_catch.HasCaught()) { 5097 CHECK_EQ(expected, count); 5098 CHECK(result.IsEmpty()); 5099 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 5100 } else { 5101 CHECK_NE(expected, count); 5102 } 5103 args.GetReturnValue().Set(result); 5104 return; 5105 } else { 5106 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv)); 5107 return; 5108 } 5109 } 5110 } 5111 5112 5113 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 5114 ApiTestFuzzer::Fuzz(); 5115 CHECK_EQ(3, args.Length()); 5116 bool equality = args[0]->BooleanValue(); 5117 int count = args[1]->Int32Value(); 5118 int expected = args[2]->Int32Value(); 5119 if (equality) { 5120 CHECK_EQ(count, expected); 5121 } else { 5122 CHECK_NE(count, expected); 5123 } 5124 } 5125 5126 5127 THREADED_TEST(EvalInTryFinally) { 5128 LocalContext context; 5129 v8::HandleScope scope(context->GetIsolate()); 5130 v8::TryCatch try_catch; 5131 CompileRun("(function() {" 5132 " try {" 5133 " eval('asldkf (*&^&*^');" 5134 " } finally {" 5135 " return;" 5136 " }" 5137 "})()"); 5138 CHECK(!try_catch.HasCaught()); 5139 } 5140 5141 5142 // This test works by making a stack of alternating JavaScript and C 5143 // activations. These activations set up exception handlers with regular 5144 // intervals, one interval for C activations and another for JavaScript 5145 // activations. When enough activations have been created an exception is 5146 // thrown and we check that the right activation catches the exception and that 5147 // no other activations do. The right activation is always the topmost one with 5148 // a handler, regardless of whether it is in JavaScript or C. 5149 // 5150 // The notation used to describe a test case looks like this: 5151 // 5152 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5153 // 5154 // Each entry is an activation, either JS or C. The index is the count at that 5155 // level. Stars identify activations with exception handlers, the @ identifies 5156 // the exception handler that should catch the exception. 5157 // 5158 // BUG(271): Some of the exception propagation does not work on the 5159 // ARM simulator because the simulator separates the C++ stack and the 5160 // JS stack. This test therefore fails on the simulator. The test is 5161 // not threaded to allow the threading tests to run on the simulator. 5162 TEST(ExceptionOrder) { 5163 v8::Isolate* isolate = CcTest::isolate(); 5164 v8::HandleScope scope(isolate); 5165 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5166 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck)); 5167 templ->Set(v8_str("CThrowCountDown"), 5168 v8::FunctionTemplate::New(isolate, CThrowCountDown)); 5169 LocalContext context(0, templ); 5170 CompileRun( 5171 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 5172 " if (count == 0) throw 'FromJS';" 5173 " if (count % jsInterval == 0) {" 5174 " try {" 5175 " var value = CThrowCountDown(count - 1," 5176 " jsInterval," 5177 " cInterval," 5178 " expected);" 5179 " check(false, count, expected);" 5180 " return value;" 5181 " } catch (e) {" 5182 " check(true, count, expected);" 5183 " }" 5184 " } else {" 5185 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 5186 " }" 5187 "}"); 5188 Local<Function> fun = 5189 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown"))); 5190 5191 const int argc = 4; 5192 // count jsInterval cInterval expected 5193 5194 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5195 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) }; 5196 fun->Call(fun, argc, a0); 5197 5198 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 5199 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) }; 5200 fun->Call(fun, argc, a1); 5201 5202 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 5203 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) }; 5204 fun->Call(fun, argc, a2); 5205 5206 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 5207 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) }; 5208 fun->Call(fun, argc, a3); 5209 5210 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 5211 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) }; 5212 fun->Call(fun, argc, a4); 5213 5214 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 5215 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) }; 5216 fun->Call(fun, argc, a5); 5217 } 5218 5219 5220 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 5221 ApiTestFuzzer::Fuzz(); 5222 CHECK_EQ(1, args.Length()); 5223 args.GetIsolate()->ThrowException(args[0]); 5224 } 5225 5226 5227 THREADED_TEST(ThrowValues) { 5228 v8::Isolate* isolate = CcTest::isolate(); 5229 v8::HandleScope scope(isolate); 5230 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5231 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue)); 5232 LocalContext context(0, templ); 5233 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 5234 "function Run(obj) {" 5235 " try {" 5236 " Throw(obj);" 5237 " } catch (e) {" 5238 " return e;" 5239 " }" 5240 " return 'no exception';" 5241 "}" 5242 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 5243 CHECK_EQ(5, result->Length()); 5244 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString()); 5245 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber()); 5246 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value()); 5247 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber()); 5248 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value()); 5249 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull()); 5250 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined()); 5251 } 5252 5253 5254 THREADED_TEST(CatchZero) { 5255 LocalContext context; 5256 v8::HandleScope scope(context->GetIsolate()); 5257 v8::TryCatch try_catch; 5258 CHECK(!try_catch.HasCaught()); 5259 CompileRun("throw 10"); 5260 CHECK(try_catch.HasCaught()); 5261 CHECK_EQ(10, try_catch.Exception()->Int32Value()); 5262 try_catch.Reset(); 5263 CHECK(!try_catch.HasCaught()); 5264 CompileRun("throw 0"); 5265 CHECK(try_catch.HasCaught()); 5266 CHECK_EQ(0, try_catch.Exception()->Int32Value()); 5267 } 5268 5269 5270 THREADED_TEST(CatchExceptionFromWith) { 5271 LocalContext context; 5272 v8::HandleScope scope(context->GetIsolate()); 5273 v8::TryCatch try_catch; 5274 CHECK(!try_catch.HasCaught()); 5275 CompileRun("var o = {}; with (o) { throw 42; }"); 5276 CHECK(try_catch.HasCaught()); 5277 } 5278 5279 5280 THREADED_TEST(TryCatchAndFinallyHidingException) { 5281 LocalContext context; 5282 v8::HandleScope scope(context->GetIsolate()); 5283 v8::TryCatch try_catch; 5284 CHECK(!try_catch.HasCaught()); 5285 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 5286 CompileRun("f({toString: function() { throw 42; }});"); 5287 CHECK(!try_catch.HasCaught()); 5288 } 5289 5290 5291 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 5292 v8::TryCatch try_catch; 5293 } 5294 5295 5296 THREADED_TEST(TryCatchAndFinally) { 5297 LocalContext context; 5298 v8::Isolate* isolate = context->GetIsolate(); 5299 v8::HandleScope scope(isolate); 5300 context->Global()->Set( 5301 v8_str("native_with_try_catch"), 5302 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction()); 5303 v8::TryCatch try_catch; 5304 CHECK(!try_catch.HasCaught()); 5305 CompileRun( 5306 "try {\n" 5307 " throw new Error('a');\n" 5308 "} finally {\n" 5309 " native_with_try_catch();\n" 5310 "}\n"); 5311 CHECK(try_catch.HasCaught()); 5312 } 5313 5314 5315 static void TryCatchNestedHelper(int depth) { 5316 if (depth > 0) { 5317 v8::TryCatch try_catch; 5318 try_catch.SetVerbose(true); 5319 TryCatchNestedHelper(depth - 1); 5320 CHECK(try_catch.HasCaught()); 5321 try_catch.ReThrow(); 5322 } else { 5323 CcTest::isolate()->ThrowException(v8_str("back")); 5324 } 5325 } 5326 5327 5328 TEST(TryCatchNested) { 5329 v8::V8::Initialize(); 5330 LocalContext context; 5331 v8::HandleScope scope(context->GetIsolate()); 5332 v8::TryCatch try_catch; 5333 TryCatchNestedHelper(5); 5334 CHECK(try_catch.HasCaught()); 5335 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); 5336 } 5337 5338 5339 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 5340 CHECK(try_catch->HasCaught()); 5341 Handle<Message> message = try_catch->Message(); 5342 Handle<Value> resource = message->GetScriptResourceName(); 5343 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 5344 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()), 5345 "Uncaught Error: a")); 5346 CHECK_EQ(1, message->GetLineNumber()); 5347 CHECK_EQ(6, message->GetStartColumn()); 5348 } 5349 5350 5351 void TryCatchMixedNestingHelper( 5352 const v8::FunctionCallbackInfo<v8::Value>& args) { 5353 ApiTestFuzzer::Fuzz(); 5354 v8::TryCatch try_catch; 5355 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 5356 CHECK(try_catch.HasCaught()); 5357 TryCatchMixedNestingCheck(&try_catch); 5358 try_catch.ReThrow(); 5359 } 5360 5361 5362 // This test ensures that an outer TryCatch in the following situation: 5363 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 5364 // does not clobber the Message object generated for the inner TryCatch. 5365 // This exercises the ability of TryCatch.ReThrow() to restore the 5366 // inner pending Message before throwing the exception again. 5367 TEST(TryCatchMixedNesting) { 5368 v8::Isolate* isolate = CcTest::isolate(); 5369 v8::HandleScope scope(isolate); 5370 v8::V8::Initialize(); 5371 v8::TryCatch try_catch; 5372 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5373 templ->Set(v8_str("TryCatchMixedNestingHelper"), 5374 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper)); 5375 LocalContext context(0, templ); 5376 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 5377 TryCatchMixedNestingCheck(&try_catch); 5378 } 5379 5380 5381 THREADED_TEST(Equality) { 5382 LocalContext context; 5383 v8::Isolate* isolate = context->GetIsolate(); 5384 v8::HandleScope scope(context->GetIsolate()); 5385 // Check that equality works at all before relying on CHECK_EQ 5386 CHECK(v8_str("a")->Equals(v8_str("a"))); 5387 CHECK(!v8_str("a")->Equals(v8_str("b"))); 5388 5389 CHECK_EQ(v8_str("a"), v8_str("a")); 5390 CHECK_NE(v8_str("a"), v8_str("b")); 5391 CHECK_EQ(v8_num(1), v8_num(1)); 5392 CHECK_EQ(v8_num(1.00), v8_num(1)); 5393 CHECK_NE(v8_num(1), v8_num(2)); 5394 5395 // Assume String is not internalized. 5396 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 5397 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 5398 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 5399 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 5400 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 5401 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); 5402 Local<Value> not_a_number = v8_num(i::OS::nan_value()); 5403 CHECK(!not_a_number->StrictEquals(not_a_number)); 5404 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); 5405 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); 5406 5407 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 5408 v8::Persistent<v8::Object> alias(isolate, obj); 5409 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 5410 alias.Reset(); 5411 5412 CHECK(v8_str("a")->SameValue(v8_str("a"))); 5413 CHECK(!v8_str("a")->SameValue(v8_str("b"))); 5414 CHECK(!v8_str("5")->SameValue(v8_num(5))); 5415 CHECK(v8_num(1)->SameValue(v8_num(1))); 5416 CHECK(!v8_num(1)->SameValue(v8_num(2))); 5417 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0))); 5418 CHECK(not_a_number->SameValue(not_a_number)); 5419 CHECK(v8::False(isolate)->SameValue(v8::False(isolate))); 5420 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate))); 5421 } 5422 5423 5424 THREADED_TEST(MultiRun) { 5425 LocalContext context; 5426 v8::HandleScope scope(context->GetIsolate()); 5427 Local<Script> script = v8_compile("x"); 5428 for (int i = 0; i < 10; i++) 5429 script->Run(); 5430 } 5431 5432 5433 static void GetXValue(Local<String> name, 5434 const v8::PropertyCallbackInfo<v8::Value>& info) { 5435 ApiTestFuzzer::Fuzz(); 5436 CHECK_EQ(info.Data(), v8_str("donut")); 5437 CHECK_EQ(name, v8_str("x")); 5438 info.GetReturnValue().Set(name); 5439 } 5440 5441 5442 THREADED_TEST(SimplePropertyRead) { 5443 LocalContext context; 5444 v8::Isolate* isolate = context->GetIsolate(); 5445 v8::HandleScope scope(isolate); 5446 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5447 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5448 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5449 Local<Script> script = v8_compile("obj.x"); 5450 for (int i = 0; i < 10; i++) { 5451 Local<Value> result = script->Run(); 5452 CHECK_EQ(result, v8_str("x")); 5453 } 5454 } 5455 5456 5457 THREADED_TEST(DefinePropertyOnAPIAccessor) { 5458 LocalContext context; 5459 v8::Isolate* isolate = context->GetIsolate(); 5460 v8::HandleScope scope(isolate); 5461 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5462 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5463 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5464 5465 // Uses getOwnPropertyDescriptor to check the configurable status 5466 Local<Script> script_desc = v8_compile( 5467 "var prop = Object.getOwnPropertyDescriptor( " 5468 "obj, 'x');" 5469 "prop.configurable;"); 5470 Local<Value> result = script_desc->Run(); 5471 CHECK_EQ(result->BooleanValue(), true); 5472 5473 // Redefine get - but still configurable 5474 Local<Script> script_define = v8_compile( 5475 "var desc = { get: function(){return 42; }," 5476 " configurable: true };" 5477 "Object.defineProperty(obj, 'x', desc);" 5478 "obj.x"); 5479 result = script_define->Run(); 5480 CHECK_EQ(result, v8_num(42)); 5481 5482 // Check that the accessor is still configurable 5483 result = script_desc->Run(); 5484 CHECK_EQ(result->BooleanValue(), true); 5485 5486 // Redefine to a non-configurable 5487 script_define = v8_compile( 5488 "var desc = { get: function(){return 43; }," 5489 " configurable: false };" 5490 "Object.defineProperty(obj, 'x', desc);" 5491 "obj.x"); 5492 result = script_define->Run(); 5493 CHECK_EQ(result, v8_num(43)); 5494 result = script_desc->Run(); 5495 CHECK_EQ(result->BooleanValue(), false); 5496 5497 // Make sure that it is not possible to redefine again 5498 v8::TryCatch try_catch; 5499 result = script_define->Run(); 5500 CHECK(try_catch.HasCaught()); 5501 String::Utf8Value exception_value(try_catch.Exception()); 5502 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5503 } 5504 5505 5506 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 5507 v8::Isolate* isolate = CcTest::isolate(); 5508 v8::HandleScope scope(isolate); 5509 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5510 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5511 LocalContext context; 5512 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5513 5514 Local<Script> script_desc = v8_compile( 5515 "var prop =" 5516 "Object.getOwnPropertyDescriptor( " 5517 "obj, 'x');" 5518 "prop.configurable;"); 5519 Local<Value> result = script_desc->Run(); 5520 CHECK_EQ(result->BooleanValue(), true); 5521 5522 Local<Script> script_define = v8_compile( 5523 "var desc = {get: function(){return 42; }," 5524 " configurable: true };" 5525 "Object.defineProperty(obj, 'x', desc);" 5526 "obj.x"); 5527 result = script_define->Run(); 5528 CHECK_EQ(result, v8_num(42)); 5529 5530 5531 result = script_desc->Run(); 5532 CHECK_EQ(result->BooleanValue(), true); 5533 5534 5535 script_define = v8_compile( 5536 "var desc = {get: function(){return 43; }," 5537 " configurable: false };" 5538 "Object.defineProperty(obj, 'x', desc);" 5539 "obj.x"); 5540 result = script_define->Run(); 5541 CHECK_EQ(result, v8_num(43)); 5542 result = script_desc->Run(); 5543 5544 CHECK_EQ(result->BooleanValue(), false); 5545 5546 v8::TryCatch try_catch; 5547 result = script_define->Run(); 5548 CHECK(try_catch.HasCaught()); 5549 String::Utf8Value exception_value(try_catch.Exception()); 5550 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5551 } 5552 5553 5554 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context, 5555 char const* name) { 5556 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name))); 5557 } 5558 5559 5560 THREADED_TEST(DefineAPIAccessorOnObject) { 5561 v8::Isolate* isolate = CcTest::isolate(); 5562 v8::HandleScope scope(isolate); 5563 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5564 LocalContext context; 5565 5566 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5567 CompileRun("var obj2 = {};"); 5568 5569 CHECK(CompileRun("obj1.x")->IsUndefined()); 5570 CHECK(CompileRun("obj2.x")->IsUndefined()); 5571 5572 CHECK(GetGlobalProperty(&context, "obj1")-> 5573 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5574 5575 ExpectString("obj1.x", "x"); 5576 CHECK(CompileRun("obj2.x")->IsUndefined()); 5577 5578 CHECK(GetGlobalProperty(&context, "obj2")-> 5579 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5580 5581 ExpectString("obj1.x", "x"); 5582 ExpectString("obj2.x", "x"); 5583 5584 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5585 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5586 5587 CompileRun("Object.defineProperty(obj1, 'x'," 5588 "{ get: function() { return 'y'; }, configurable: true })"); 5589 5590 ExpectString("obj1.x", "y"); 5591 ExpectString("obj2.x", "x"); 5592 5593 CompileRun("Object.defineProperty(obj2, 'x'," 5594 "{ get: function() { return 'y'; }, configurable: true })"); 5595 5596 ExpectString("obj1.x", "y"); 5597 ExpectString("obj2.x", "y"); 5598 5599 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5600 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5601 5602 CHECK(GetGlobalProperty(&context, "obj1")-> 5603 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5604 CHECK(GetGlobalProperty(&context, "obj2")-> 5605 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5606 5607 ExpectString("obj1.x", "x"); 5608 ExpectString("obj2.x", "x"); 5609 5610 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5611 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5612 5613 // Define getters/setters, but now make them not configurable. 5614 CompileRun("Object.defineProperty(obj1, 'x'," 5615 "{ get: function() { return 'z'; }, configurable: false })"); 5616 CompileRun("Object.defineProperty(obj2, 'x'," 5617 "{ get: function() { return 'z'; }, configurable: false })"); 5618 5619 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5620 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5621 5622 ExpectString("obj1.x", "z"); 5623 ExpectString("obj2.x", "z"); 5624 5625 CHECK(!GetGlobalProperty(&context, "obj1")-> 5626 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5627 CHECK(!GetGlobalProperty(&context, "obj2")-> 5628 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5629 5630 ExpectString("obj1.x", "z"); 5631 ExpectString("obj2.x", "z"); 5632 } 5633 5634 5635 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 5636 v8::Isolate* isolate = CcTest::isolate(); 5637 v8::HandleScope scope(isolate); 5638 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5639 LocalContext context; 5640 5641 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5642 CompileRun("var obj2 = {};"); 5643 5644 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5645 v8_str("x"), 5646 GetXValue, NULL, 5647 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5648 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5649 v8_str("x"), 5650 GetXValue, NULL, 5651 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5652 5653 ExpectString("obj1.x", "x"); 5654 ExpectString("obj2.x", "x"); 5655 5656 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5657 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5658 5659 CHECK(!GetGlobalProperty(&context, "obj1")-> 5660 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5661 CHECK(!GetGlobalProperty(&context, "obj2")-> 5662 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5663 5664 { 5665 v8::TryCatch try_catch; 5666 CompileRun("Object.defineProperty(obj1, 'x'," 5667 "{get: function() { return 'func'; }})"); 5668 CHECK(try_catch.HasCaught()); 5669 String::Utf8Value exception_value(try_catch.Exception()); 5670 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5671 } 5672 { 5673 v8::TryCatch try_catch; 5674 CompileRun("Object.defineProperty(obj2, 'x'," 5675 "{get: function() { return 'func'; }})"); 5676 CHECK(try_catch.HasCaught()); 5677 String::Utf8Value exception_value(try_catch.Exception()); 5678 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5679 } 5680 } 5681 5682 5683 static void Get239Value(Local<String> name, 5684 const v8::PropertyCallbackInfo<v8::Value>& info) { 5685 ApiTestFuzzer::Fuzz(); 5686 CHECK_EQ(info.Data(), v8_str("donut")); 5687 CHECK_EQ(name, v8_str("239")); 5688 info.GetReturnValue().Set(name); 5689 } 5690 5691 5692 THREADED_TEST(ElementAPIAccessor) { 5693 v8::Isolate* isolate = CcTest::isolate(); 5694 v8::HandleScope scope(isolate); 5695 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5696 LocalContext context; 5697 5698 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5699 CompileRun("var obj2 = {};"); 5700 5701 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5702 v8_str("239"), 5703 Get239Value, NULL, 5704 v8_str("donut"))); 5705 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5706 v8_str("239"), 5707 Get239Value, NULL, 5708 v8_str("donut"))); 5709 5710 ExpectString("obj1[239]", "239"); 5711 ExpectString("obj2[239]", "239"); 5712 ExpectString("obj1['239']", "239"); 5713 ExpectString("obj2['239']", "239"); 5714 } 5715 5716 5717 v8::Persistent<Value> xValue; 5718 5719 5720 static void SetXValue(Local<String> name, 5721 Local<Value> value, 5722 const v8::PropertyCallbackInfo<void>& info) { 5723 CHECK_EQ(value, v8_num(4)); 5724 CHECK_EQ(info.Data(), v8_str("donut")); 5725 CHECK_EQ(name, v8_str("x")); 5726 CHECK(xValue.IsEmpty()); 5727 xValue.Reset(info.GetIsolate(), value); 5728 } 5729 5730 5731 THREADED_TEST(SimplePropertyWrite) { 5732 v8::Isolate* isolate = CcTest::isolate(); 5733 v8::HandleScope scope(isolate); 5734 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5735 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 5736 LocalContext context; 5737 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5738 Local<Script> script = v8_compile("obj.x = 4"); 5739 for (int i = 0; i < 10; i++) { 5740 CHECK(xValue.IsEmpty()); 5741 script->Run(); 5742 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5743 xValue.Reset(); 5744 } 5745 } 5746 5747 5748 THREADED_TEST(SetterOnly) { 5749 v8::Isolate* isolate = CcTest::isolate(); 5750 v8::HandleScope scope(isolate); 5751 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5752 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 5753 LocalContext context; 5754 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5755 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 5756 for (int i = 0; i < 10; i++) { 5757 CHECK(xValue.IsEmpty()); 5758 script->Run(); 5759 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5760 xValue.Reset(); 5761 } 5762 } 5763 5764 5765 THREADED_TEST(NoAccessors) { 5766 v8::Isolate* isolate = CcTest::isolate(); 5767 v8::HandleScope scope(isolate); 5768 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5769 templ->SetAccessor(v8_str("x"), 5770 static_cast<v8::AccessorGetterCallback>(NULL), 5771 NULL, 5772 v8_str("donut")); 5773 LocalContext context; 5774 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5775 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 5776 for (int i = 0; i < 10; i++) { 5777 script->Run(); 5778 } 5779 } 5780 5781 5782 static void XPropertyGetter(Local<String> property, 5783 const v8::PropertyCallbackInfo<v8::Value>& info) { 5784 ApiTestFuzzer::Fuzz(); 5785 CHECK(info.Data()->IsUndefined()); 5786 info.GetReturnValue().Set(property); 5787 } 5788 5789 5790 THREADED_TEST(NamedInterceptorPropertyRead) { 5791 v8::Isolate* isolate = CcTest::isolate(); 5792 v8::HandleScope scope(isolate); 5793 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5794 templ->SetNamedPropertyHandler(XPropertyGetter); 5795 LocalContext context; 5796 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5797 Local<Script> script = v8_compile("obj.x"); 5798 for (int i = 0; i < 10; i++) { 5799 Local<Value> result = script->Run(); 5800 CHECK_EQ(result, v8_str("x")); 5801 } 5802 } 5803 5804 5805 THREADED_TEST(NamedInterceptorDictionaryIC) { 5806 v8::Isolate* isolate = CcTest::isolate(); 5807 v8::HandleScope scope(isolate); 5808 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5809 templ->SetNamedPropertyHandler(XPropertyGetter); 5810 LocalContext context; 5811 // Create an object with a named interceptor. 5812 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance()); 5813 Local<Script> script = v8_compile("interceptor_obj.x"); 5814 for (int i = 0; i < 10; i++) { 5815 Local<Value> result = script->Run(); 5816 CHECK_EQ(result, v8_str("x")); 5817 } 5818 // Create a slow case object and a function accessing a property in 5819 // that slow case object (with dictionary probing in generated 5820 // code). Then force object with a named interceptor into slow-case, 5821 // pass it to the function, and check that the interceptor is called 5822 // instead of accessing the local property. 5823 Local<Value> result = 5824 CompileRun("function get_x(o) { return o.x; };" 5825 "var obj = { x : 42, y : 0 };" 5826 "delete obj.y;" 5827 "for (var i = 0; i < 10; i++) get_x(obj);" 5828 "interceptor_obj.x = 42;" 5829 "interceptor_obj.y = 10;" 5830 "delete interceptor_obj.y;" 5831 "get_x(interceptor_obj)"); 5832 CHECK_EQ(result, v8_str("x")); 5833 } 5834 5835 5836 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) { 5837 v8::Isolate* isolate = CcTest::isolate(); 5838 v8::HandleScope scope(isolate); 5839 v8::Local<Context> context1 = Context::New(isolate); 5840 5841 context1->Enter(); 5842 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5843 templ->SetNamedPropertyHandler(XPropertyGetter); 5844 // Create an object with a named interceptor. 5845 v8::Local<v8::Object> object = templ->NewInstance(); 5846 context1->Global()->Set(v8_str("interceptor_obj"), object); 5847 5848 // Force the object into the slow case. 5849 CompileRun("interceptor_obj.y = 0;" 5850 "delete interceptor_obj.y;"); 5851 context1->Exit(); 5852 5853 { 5854 // Introduce the object into a different context. 5855 // Repeat named loads to exercise ICs. 5856 LocalContext context2; 5857 context2->Global()->Set(v8_str("interceptor_obj"), object); 5858 Local<Value> result = 5859 CompileRun("function get_x(o) { return o.x; }" 5860 "interceptor_obj.x = 42;" 5861 "for (var i=0; i != 10; i++) {" 5862 " get_x(interceptor_obj);" 5863 "}" 5864 "get_x(interceptor_obj)"); 5865 // Check that the interceptor was actually invoked. 5866 CHECK_EQ(result, v8_str("x")); 5867 } 5868 5869 // Return to the original context and force some object to the slow case 5870 // to cause the NormalizedMapCache to verify. 5871 context1->Enter(); 5872 CompileRun("var obj = { x : 0 }; delete obj.x;"); 5873 context1->Exit(); 5874 } 5875 5876 5877 static void SetXOnPrototypeGetter( 5878 Local<String> property, 5879 const v8::PropertyCallbackInfo<v8::Value>& info) { 5880 // Set x on the prototype object and do not handle the get request. 5881 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype(); 5882 proto.As<v8::Object>()->Set(v8_str("x"), 5883 v8::Integer::New(info.GetIsolate(), 23)); 5884 } 5885 5886 5887 // This is a regression test for http://crbug.com/20104. Map 5888 // transitions should not interfere with post interceptor lookup. 5889 THREADED_TEST(NamedInterceptorMapTransitionRead) { 5890 v8::Isolate* isolate = CcTest::isolate(); 5891 v8::HandleScope scope(isolate); 5892 Local<v8::FunctionTemplate> function_template = 5893 v8::FunctionTemplate::New(isolate); 5894 Local<v8::ObjectTemplate> instance_template 5895 = function_template->InstanceTemplate(); 5896 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter); 5897 LocalContext context; 5898 context->Global()->Set(v8_str("F"), function_template->GetFunction()); 5899 // Create an instance of F and introduce a map transition for x. 5900 CompileRun("var o = new F(); o.x = 23;"); 5901 // Create an instance of F and invoke the getter. The result should be 23. 5902 Local<Value> result = CompileRun("o = new F(); o.x"); 5903 CHECK_EQ(result->Int32Value(), 23); 5904 } 5905 5906 5907 static void IndexedPropertyGetter( 5908 uint32_t index, 5909 const v8::PropertyCallbackInfo<v8::Value>& info) { 5910 ApiTestFuzzer::Fuzz(); 5911 if (index == 37) { 5912 info.GetReturnValue().Set(v8_num(625)); 5913 } 5914 } 5915 5916 5917 static void IndexedPropertySetter( 5918 uint32_t index, 5919 Local<Value> value, 5920 const v8::PropertyCallbackInfo<v8::Value>& info) { 5921 ApiTestFuzzer::Fuzz(); 5922 if (index == 39) { 5923 info.GetReturnValue().Set(value); 5924 } 5925 } 5926 5927 5928 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { 5929 v8::Isolate* isolate = CcTest::isolate(); 5930 v8::HandleScope scope(isolate); 5931 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5932 templ->SetIndexedPropertyHandler(IndexedPropertyGetter, 5933 IndexedPropertySetter); 5934 LocalContext context; 5935 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5936 Local<Script> getter_script = v8_compile( 5937 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"); 5938 Local<Script> setter_script = v8_compile( 5939 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" 5940 "obj[17] = 23;" 5941 "obj.foo;"); 5942 Local<Script> interceptor_setter_script = v8_compile( 5943 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" 5944 "obj[39] = 47;" 5945 "obj.foo;"); // This setter should not run, due to the interceptor. 5946 Local<Script> interceptor_getter_script = v8_compile( 5947 "obj[37];"); 5948 Local<Value> result = getter_script->Run(); 5949 CHECK_EQ(v8_num(5), result); 5950 result = setter_script->Run(); 5951 CHECK_EQ(v8_num(23), result); 5952 result = interceptor_setter_script->Run(); 5953 CHECK_EQ(v8_num(23), result); 5954 result = interceptor_getter_script->Run(); 5955 CHECK_EQ(v8_num(625), result); 5956 } 5957 5958 5959 static void UnboxedDoubleIndexedPropertyGetter( 5960 uint32_t index, 5961 const v8::PropertyCallbackInfo<v8::Value>& info) { 5962 ApiTestFuzzer::Fuzz(); 5963 if (index < 25) { 5964 info.GetReturnValue().Set(v8_num(index)); 5965 } 5966 } 5967 5968 5969 static void UnboxedDoubleIndexedPropertySetter( 5970 uint32_t index, 5971 Local<Value> value, 5972 const v8::PropertyCallbackInfo<v8::Value>& info) { 5973 ApiTestFuzzer::Fuzz(); 5974 if (index < 25) { 5975 info.GetReturnValue().Set(v8_num(index)); 5976 } 5977 } 5978 5979 5980 void UnboxedDoubleIndexedPropertyEnumerator( 5981 const v8::PropertyCallbackInfo<v8::Array>& info) { 5982 // Force the list of returned keys to be stored in a FastDoubleArray. 5983 Local<Script> indexed_property_names_script = v8_compile( 5984 "keys = new Array(); keys[125000] = 1;" 5985 "for(i = 0; i < 80000; i++) { keys[i] = i; };" 5986 "keys.length = 25; keys;"); 5987 Local<Value> result = indexed_property_names_script->Run(); 5988 info.GetReturnValue().Set(Local<v8::Array>::Cast(result)); 5989 } 5990 5991 5992 // Make sure that the the interceptor code in the runtime properly handles 5993 // merging property name lists for double-array-backed arrays. 5994 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { 5995 v8::Isolate* isolate = CcTest::isolate(); 5996 v8::HandleScope scope(isolate); 5997 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5998 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter, 5999 UnboxedDoubleIndexedPropertySetter, 6000 0, 6001 0, 6002 UnboxedDoubleIndexedPropertyEnumerator); 6003 LocalContext context; 6004 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6005 // When obj is created, force it to be Stored in a FastDoubleArray. 6006 Local<Script> create_unboxed_double_script = v8_compile( 6007 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } " 6008 "key_count = 0; " 6009 "for (x in obj) {key_count++;};" 6010 "obj;"); 6011 Local<Value> result = create_unboxed_double_script->Run(); 6012 CHECK(result->ToObject()->HasRealIndexedProperty(2000)); 6013 Local<Script> key_count_check = v8_compile("key_count;"); 6014 result = key_count_check->Run(); 6015 CHECK_EQ(v8_num(40013), result); 6016 } 6017 6018 6019 void SloppyArgsIndexedPropertyEnumerator( 6020 const v8::PropertyCallbackInfo<v8::Array>& info) { 6021 // Force the list of returned keys to be stored in a Arguments object. 6022 Local<Script> indexed_property_names_script = v8_compile( 6023 "function f(w,x) {" 6024 " return arguments;" 6025 "}" 6026 "keys = f(0, 1, 2, 3);" 6027 "keys;"); 6028 Local<Object> result = 6029 Local<Object>::Cast(indexed_property_names_script->Run()); 6030 // Have to populate the handle manually, as it's not Cast-able. 6031 i::Handle<i::JSObject> o = 6032 v8::Utils::OpenHandle<Object, i::JSObject>(result); 6033 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o)); 6034 info.GetReturnValue().Set(v8::Utils::ToLocal(array)); 6035 } 6036 6037 6038 static void SloppyIndexedPropertyGetter( 6039 uint32_t index, 6040 const v8::PropertyCallbackInfo<v8::Value>& info) { 6041 ApiTestFuzzer::Fuzz(); 6042 if (index < 4) { 6043 info.GetReturnValue().Set(v8_num(index)); 6044 } 6045 } 6046 6047 6048 // Make sure that the the interceptor code in the runtime properly handles 6049 // merging property name lists for non-string arguments arrays. 6050 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) { 6051 v8::Isolate* isolate = CcTest::isolate(); 6052 v8::HandleScope scope(isolate); 6053 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6054 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter, 6055 0, 6056 0, 6057 0, 6058 SloppyArgsIndexedPropertyEnumerator); 6059 LocalContext context; 6060 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6061 Local<Script> create_args_script = v8_compile( 6062 "var key_count = 0;" 6063 "for (x in obj) {key_count++;} key_count;"); 6064 Local<Value> result = create_args_script->Run(); 6065 CHECK_EQ(v8_num(4), result); 6066 } 6067 6068 6069 static void IdentityIndexedPropertyGetter( 6070 uint32_t index, 6071 const v8::PropertyCallbackInfo<v8::Value>& info) { 6072 info.GetReturnValue().Set(index); 6073 } 6074 6075 6076 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) { 6077 v8::Isolate* isolate = CcTest::isolate(); 6078 v8::HandleScope scope(isolate); 6079 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6080 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6081 6082 LocalContext context; 6083 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6084 6085 // Check fast object case. 6086 const char* fast_case_code = 6087 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()"; 6088 ExpectString(fast_case_code, "0"); 6089 6090 // Check slow case. 6091 const char* slow_case_code = 6092 "obj.x = 1; delete obj.x;" 6093 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()"; 6094 ExpectString(slow_case_code, "1"); 6095 } 6096 6097 6098 THREADED_TEST(IndexedInterceptorWithNoSetter) { 6099 v8::Isolate* isolate = CcTest::isolate(); 6100 v8::HandleScope scope(isolate); 6101 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6102 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6103 6104 LocalContext context; 6105 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6106 6107 const char* code = 6108 "try {" 6109 " obj[0] = 239;" 6110 " for (var i = 0; i < 100; i++) {" 6111 " var v = obj[0];" 6112 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;" 6113 " }" 6114 " 'PASSED'" 6115 "} catch(e) {" 6116 " e" 6117 "}"; 6118 ExpectString(code, "PASSED"); 6119 } 6120 6121 6122 THREADED_TEST(IndexedInterceptorWithAccessorCheck) { 6123 v8::Isolate* isolate = CcTest::isolate(); 6124 v8::HandleScope scope(isolate); 6125 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6126 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6127 6128 LocalContext context; 6129 Local<v8::Object> obj = templ->NewInstance(); 6130 obj->TurnOnAccessCheck(); 6131 context->Global()->Set(v8_str("obj"), obj); 6132 6133 const char* code = 6134 "try {" 6135 " for (var i = 0; i < 100; i++) {" 6136 " var v = obj[0];" 6137 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;" 6138 " }" 6139 " 'PASSED'" 6140 "} catch(e) {" 6141 " e" 6142 "}"; 6143 ExpectString(code, "PASSED"); 6144 } 6145 6146 6147 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { 6148 i::FLAG_allow_natives_syntax = true; 6149 v8::Isolate* isolate = CcTest::isolate(); 6150 v8::HandleScope scope(isolate); 6151 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6152 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6153 6154 LocalContext context; 6155 Local<v8::Object> obj = templ->NewInstance(); 6156 context->Global()->Set(v8_str("obj"), obj); 6157 6158 const char* code = 6159 "try {" 6160 " for (var i = 0; i < 100; i++) {" 6161 " var expected = i;" 6162 " if (i == 5) {" 6163 " %EnableAccessChecks(obj);" 6164 " expected = undefined;" 6165 " }" 6166 " var v = obj[i];" 6167 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6168 " if (i == 5) %DisableAccessChecks(obj);" 6169 " }" 6170 " 'PASSED'" 6171 "} catch(e) {" 6172 " e" 6173 "}"; 6174 ExpectString(code, "PASSED"); 6175 } 6176 6177 6178 THREADED_TEST(IndexedInterceptorWithDifferentIndices) { 6179 v8::Isolate* isolate = CcTest::isolate(); 6180 v8::HandleScope scope(isolate); 6181 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6182 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6183 6184 LocalContext context; 6185 Local<v8::Object> obj = templ->NewInstance(); 6186 context->Global()->Set(v8_str("obj"), obj); 6187 6188 const char* code = 6189 "try {" 6190 " for (var i = 0; i < 100; i++) {" 6191 " var v = obj[i];" 6192 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6193 " }" 6194 " 'PASSED'" 6195 "} catch(e) {" 6196 " e" 6197 "}"; 6198 ExpectString(code, "PASSED"); 6199 } 6200 6201 6202 THREADED_TEST(IndexedInterceptorWithNegativeIndices) { 6203 v8::Isolate* isolate = CcTest::isolate(); 6204 v8::HandleScope scope(isolate); 6205 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6206 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6207 6208 LocalContext context; 6209 Local<v8::Object> obj = templ->NewInstance(); 6210 context->Global()->Set(v8_str("obj"), obj); 6211 6212 const char* code = 6213 "try {" 6214 " for (var i = 0; i < 100; i++) {" 6215 " var expected = i;" 6216 " var key = i;" 6217 " if (i == 25) {" 6218 " key = -1;" 6219 " expected = undefined;" 6220 " }" 6221 " if (i == 50) {" 6222 " /* probe minimal Smi number on 32-bit platforms */" 6223 " key = -(1 << 30);" 6224 " expected = undefined;" 6225 " }" 6226 " if (i == 75) {" 6227 " /* probe minimal Smi number on 64-bit platforms */" 6228 " key = 1 << 31;" 6229 " expected = undefined;" 6230 " }" 6231 " var v = obj[key];" 6232 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6233 " }" 6234 " 'PASSED'" 6235 "} catch(e) {" 6236 " e" 6237 "}"; 6238 ExpectString(code, "PASSED"); 6239 } 6240 6241 6242 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) { 6243 v8::Isolate* isolate = CcTest::isolate(); 6244 v8::HandleScope scope(isolate); 6245 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6246 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6247 6248 LocalContext context; 6249 Local<v8::Object> obj = templ->NewInstance(); 6250 context->Global()->Set(v8_str("obj"), obj); 6251 6252 const char* code = 6253 "try {" 6254 " for (var i = 0; i < 100; i++) {" 6255 " var expected = i;" 6256 " var key = i;" 6257 " if (i == 50) {" 6258 " key = 'foobar';" 6259 " expected = undefined;" 6260 " }" 6261 " var v = obj[key];" 6262 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6263 " }" 6264 " 'PASSED'" 6265 "} catch(e) {" 6266 " e" 6267 "}"; 6268 ExpectString(code, "PASSED"); 6269 } 6270 6271 6272 THREADED_TEST(IndexedInterceptorGoingMegamorphic) { 6273 v8::Isolate* isolate = CcTest::isolate(); 6274 v8::HandleScope scope(isolate); 6275 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6276 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6277 6278 LocalContext context; 6279 Local<v8::Object> obj = templ->NewInstance(); 6280 context->Global()->Set(v8_str("obj"), obj); 6281 6282 const char* code = 6283 "var original = obj;" 6284 "try {" 6285 " for (var i = 0; i < 100; i++) {" 6286 " var expected = i;" 6287 " if (i == 50) {" 6288 " obj = {50: 'foobar'};" 6289 " expected = 'foobar';" 6290 " }" 6291 " var v = obj[i];" 6292 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6293 " if (i == 50) obj = original;" 6294 " }" 6295 " 'PASSED'" 6296 "} catch(e) {" 6297 " e" 6298 "}"; 6299 ExpectString(code, "PASSED"); 6300 } 6301 6302 6303 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) { 6304 v8::Isolate* isolate = CcTest::isolate(); 6305 v8::HandleScope scope(isolate); 6306 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6307 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6308 6309 LocalContext context; 6310 Local<v8::Object> obj = templ->NewInstance(); 6311 context->Global()->Set(v8_str("obj"), obj); 6312 6313 const char* code = 6314 "var original = obj;" 6315 "try {" 6316 " for (var i = 0; i < 100; i++) {" 6317 " var expected = i;" 6318 " if (i == 5) {" 6319 " obj = 239;" 6320 " expected = undefined;" 6321 " }" 6322 " var v = obj[i];" 6323 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6324 " if (i == 5) obj = original;" 6325 " }" 6326 " 'PASSED'" 6327 "} catch(e) {" 6328 " e" 6329 "}"; 6330 ExpectString(code, "PASSED"); 6331 } 6332 6333 6334 THREADED_TEST(IndexedInterceptorOnProto) { 6335 v8::Isolate* isolate = CcTest::isolate(); 6336 v8::HandleScope scope(isolate); 6337 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6338 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6339 6340 LocalContext context; 6341 Local<v8::Object> obj = templ->NewInstance(); 6342 context->Global()->Set(v8_str("obj"), obj); 6343 6344 const char* code = 6345 "var o = {__proto__: obj};" 6346 "try {" 6347 " for (var i = 0; i < 100; i++) {" 6348 " var v = o[i];" 6349 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6350 " }" 6351 " 'PASSED'" 6352 "} catch(e) {" 6353 " e" 6354 "}"; 6355 ExpectString(code, "PASSED"); 6356 } 6357 6358 6359 THREADED_TEST(MultiContexts) { 6360 v8::Isolate* isolate = CcTest::isolate(); 6361 v8::HandleScope scope(isolate); 6362 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6363 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate, 6364 DummyCallHandler)); 6365 6366 Local<String> password = v8_str("Password"); 6367 6368 // Create an environment 6369 LocalContext context0(0, templ); 6370 context0->SetSecurityToken(password); 6371 v8::Handle<v8::Object> global0 = context0->Global(); 6372 global0->Set(v8_str("custom"), v8_num(1234)); 6373 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6374 6375 // Create an independent environment 6376 LocalContext context1(0, templ); 6377 context1->SetSecurityToken(password); 6378 v8::Handle<v8::Object> global1 = context1->Global(); 6379 global1->Set(v8_str("custom"), v8_num(1234)); 6380 CHECK_NE(global0, global1); 6381 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6382 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value()); 6383 6384 // Now create a new context with the old global 6385 LocalContext context2(0, templ, global1); 6386 context2->SetSecurityToken(password); 6387 v8::Handle<v8::Object> global2 = context2->Global(); 6388 CHECK_EQ(global1, global2); 6389 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value()); 6390 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value()); 6391 } 6392 6393 6394 THREADED_TEST(FunctionPrototypeAcrossContexts) { 6395 // Make sure that functions created by cloning boilerplates cannot 6396 // communicate through their __proto__ field. 6397 6398 v8::HandleScope scope(CcTest::isolate()); 6399 6400 LocalContext env0; 6401 v8::Handle<v8::Object> global0 = 6402 env0->Global(); 6403 v8::Handle<v8::Object> object0 = 6404 global0->Get(v8_str("Object")).As<v8::Object>(); 6405 v8::Handle<v8::Object> tostring0 = 6406 object0->Get(v8_str("toString")).As<v8::Object>(); 6407 v8::Handle<v8::Object> proto0 = 6408 tostring0->Get(v8_str("__proto__")).As<v8::Object>(); 6409 proto0->Set(v8_str("custom"), v8_num(1234)); 6410 6411 LocalContext env1; 6412 v8::Handle<v8::Object> global1 = 6413 env1->Global(); 6414 v8::Handle<v8::Object> object1 = 6415 global1->Get(v8_str("Object")).As<v8::Object>(); 6416 v8::Handle<v8::Object> tostring1 = 6417 object1->Get(v8_str("toString")).As<v8::Object>(); 6418 v8::Handle<v8::Object> proto1 = 6419 tostring1->Get(v8_str("__proto__")).As<v8::Object>(); 6420 CHECK(!proto1->Has(v8_str("custom"))); 6421 } 6422 6423 6424 THREADED_TEST(Regress892105) { 6425 // Make sure that object and array literals created by cloning 6426 // boilerplates cannot communicate through their __proto__ 6427 // field. This is rather difficult to check, but we try to add stuff 6428 // to Object.prototype and Array.prototype and create a new 6429 // environment. This should succeed. 6430 6431 v8::HandleScope scope(CcTest::isolate()); 6432 6433 Local<String> source = v8_str("Object.prototype.obj = 1234;" 6434 "Array.prototype.arr = 4567;" 6435 "8901"); 6436 6437 LocalContext env0; 6438 Local<Script> script0 = v8_compile(source); 6439 CHECK_EQ(8901.0, script0->Run()->NumberValue()); 6440 6441 LocalContext env1; 6442 Local<Script> script1 = v8_compile(source); 6443 CHECK_EQ(8901.0, script1->Run()->NumberValue()); 6444 } 6445 6446 6447 THREADED_TEST(UndetectableObject) { 6448 LocalContext env; 6449 v8::HandleScope scope(env->GetIsolate()); 6450 6451 Local<v8::FunctionTemplate> desc = 6452 v8::FunctionTemplate::New(env->GetIsolate()); 6453 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6454 6455 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6456 env->Global()->Set(v8_str("undetectable"), obj); 6457 6458 ExpectString("undetectable.toString()", "[object Object]"); 6459 ExpectString("typeof undetectable", "undefined"); 6460 ExpectString("typeof(undetectable)", "undefined"); 6461 ExpectBoolean("typeof undetectable == 'undefined'", true); 6462 ExpectBoolean("typeof undetectable == 'object'", false); 6463 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6464 ExpectBoolean("!undetectable", true); 6465 6466 ExpectObject("true&&undetectable", obj); 6467 ExpectBoolean("false&&undetectable", false); 6468 ExpectBoolean("true||undetectable", true); 6469 ExpectObject("false||undetectable", obj); 6470 6471 ExpectObject("undetectable&&true", obj); 6472 ExpectObject("undetectable&&false", obj); 6473 ExpectBoolean("undetectable||true", true); 6474 ExpectBoolean("undetectable||false", false); 6475 6476 ExpectBoolean("undetectable==null", true); 6477 ExpectBoolean("null==undetectable", true); 6478 ExpectBoolean("undetectable==undefined", true); 6479 ExpectBoolean("undefined==undetectable", true); 6480 ExpectBoolean("undetectable==undetectable", true); 6481 6482 6483 ExpectBoolean("undetectable===null", false); 6484 ExpectBoolean("null===undetectable", false); 6485 ExpectBoolean("undetectable===undefined", false); 6486 ExpectBoolean("undefined===undetectable", false); 6487 ExpectBoolean("undetectable===undetectable", true); 6488 } 6489 6490 6491 THREADED_TEST(VoidLiteral) { 6492 LocalContext env; 6493 v8::Isolate* isolate = env->GetIsolate(); 6494 v8::HandleScope scope(isolate); 6495 6496 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6497 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6498 6499 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6500 env->Global()->Set(v8_str("undetectable"), obj); 6501 6502 ExpectBoolean("undefined == void 0", true); 6503 ExpectBoolean("undetectable == void 0", true); 6504 ExpectBoolean("null == void 0", true); 6505 ExpectBoolean("undefined === void 0", true); 6506 ExpectBoolean("undetectable === void 0", false); 6507 ExpectBoolean("null === void 0", false); 6508 6509 ExpectBoolean("void 0 == undefined", true); 6510 ExpectBoolean("void 0 == undetectable", true); 6511 ExpectBoolean("void 0 == null", true); 6512 ExpectBoolean("void 0 === undefined", true); 6513 ExpectBoolean("void 0 === undetectable", false); 6514 ExpectBoolean("void 0 === null", false); 6515 6516 ExpectString("(function() {" 6517 " try {" 6518 " return x === void 0;" 6519 " } catch(e) {" 6520 " return e.toString();" 6521 " }" 6522 "})()", 6523 "ReferenceError: x is not defined"); 6524 ExpectString("(function() {" 6525 " try {" 6526 " return void 0 === x;" 6527 " } catch(e) {" 6528 " return e.toString();" 6529 " }" 6530 "})()", 6531 "ReferenceError: x is not defined"); 6532 } 6533 6534 6535 THREADED_TEST(ExtensibleOnUndetectable) { 6536 LocalContext env; 6537 v8::Isolate* isolate = env->GetIsolate(); 6538 v8::HandleScope scope(isolate); 6539 6540 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6541 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6542 6543 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6544 env->Global()->Set(v8_str("undetectable"), obj); 6545 6546 Local<String> source = v8_str("undetectable.x = 42;" 6547 "undetectable.x"); 6548 6549 Local<Script> script = v8_compile(source); 6550 6551 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run()); 6552 6553 ExpectBoolean("Object.isExtensible(undetectable)", true); 6554 6555 source = v8_str("Object.preventExtensions(undetectable);"); 6556 script = v8_compile(source); 6557 script->Run(); 6558 ExpectBoolean("Object.isExtensible(undetectable)", false); 6559 6560 source = v8_str("undetectable.y = 2000;"); 6561 script = v8_compile(source); 6562 script->Run(); 6563 ExpectBoolean("undetectable.y == undefined", true); 6564 } 6565 6566 6567 6568 THREADED_TEST(UndetectableString) { 6569 LocalContext env; 6570 v8::HandleScope scope(env->GetIsolate()); 6571 6572 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6573 String::kUndetectableString); 6574 env->Global()->Set(v8_str("undetectable"), obj); 6575 6576 ExpectString("undetectable", "foo"); 6577 ExpectString("typeof undetectable", "undefined"); 6578 ExpectString("typeof(undetectable)", "undefined"); 6579 ExpectBoolean("typeof undetectable == 'undefined'", true); 6580 ExpectBoolean("typeof undetectable == 'string'", false); 6581 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6582 ExpectBoolean("!undetectable", true); 6583 6584 ExpectObject("true&&undetectable", obj); 6585 ExpectBoolean("false&&undetectable", false); 6586 ExpectBoolean("true||undetectable", true); 6587 ExpectObject("false||undetectable", obj); 6588 6589 ExpectObject("undetectable&&true", obj); 6590 ExpectObject("undetectable&&false", obj); 6591 ExpectBoolean("undetectable||true", true); 6592 ExpectBoolean("undetectable||false", false); 6593 6594 ExpectBoolean("undetectable==null", true); 6595 ExpectBoolean("null==undetectable", true); 6596 ExpectBoolean("undetectable==undefined", true); 6597 ExpectBoolean("undefined==undetectable", true); 6598 ExpectBoolean("undetectable==undetectable", true); 6599 6600 6601 ExpectBoolean("undetectable===null", false); 6602 ExpectBoolean("null===undetectable", false); 6603 ExpectBoolean("undetectable===undefined", false); 6604 ExpectBoolean("undefined===undetectable", false); 6605 ExpectBoolean("undetectable===undetectable", true); 6606 } 6607 6608 6609 TEST(UndetectableOptimized) { 6610 i::FLAG_allow_natives_syntax = true; 6611 LocalContext env; 6612 v8::HandleScope scope(env->GetIsolate()); 6613 6614 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6615 String::kUndetectableString); 6616 env->Global()->Set(v8_str("undetectable"), obj); 6617 env->Global()->Set(v8_str("detectable"), v8_str("bar")); 6618 6619 ExpectString( 6620 "function testBranch() {" 6621 " if (!%_IsUndetectableObject(undetectable)) throw 1;" 6622 " if (%_IsUndetectableObject(detectable)) throw 2;" 6623 "}\n" 6624 "function testBool() {" 6625 " var b1 = !%_IsUndetectableObject(undetectable);" 6626 " var b2 = %_IsUndetectableObject(detectable);" 6627 " if (b1) throw 3;" 6628 " if (b2) throw 4;" 6629 " return b1 == b2;" 6630 "}\n" 6631 "%OptimizeFunctionOnNextCall(testBranch);" 6632 "%OptimizeFunctionOnNextCall(testBool);" 6633 "for (var i = 0; i < 10; i++) {" 6634 " testBranch();" 6635 " testBool();" 6636 "}\n" 6637 "\"PASS\"", 6638 "PASS"); 6639 } 6640 6641 6642 // The point of this test is type checking. We run it only so compilers 6643 // don't complain about an unused function. 6644 TEST(PersistentHandles) { 6645 LocalContext env; 6646 v8::Isolate* isolate = CcTest::isolate(); 6647 v8::HandleScope scope(isolate); 6648 Local<String> str = v8_str("foo"); 6649 v8::Persistent<String> p_str(isolate, str); 6650 p_str.Reset(); 6651 Local<Script> scr = v8_compile(""); 6652 v8::Persistent<Script> p_scr(isolate, scr); 6653 p_scr.Reset(); 6654 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6655 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 6656 p_templ.Reset(); 6657 } 6658 6659 6660 static void HandleLogDelegator( 6661 const v8::FunctionCallbackInfo<v8::Value>& args) { 6662 ApiTestFuzzer::Fuzz(); 6663 } 6664 6665 6666 THREADED_TEST(GlobalObjectTemplate) { 6667 v8::Isolate* isolate = CcTest::isolate(); 6668 v8::HandleScope handle_scope(isolate); 6669 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 6670 global_template->Set(v8_str("JSNI_Log"), 6671 v8::FunctionTemplate::New(isolate, HandleLogDelegator)); 6672 v8::Local<Context> context = Context::New(isolate, 0, global_template); 6673 Context::Scope context_scope(context); 6674 CompileRun("JSNI_Log('LOG')"); 6675 } 6676 6677 6678 static const char* kSimpleExtensionSource = 6679 "function Foo() {" 6680 " return 4;" 6681 "}"; 6682 6683 6684 TEST(SimpleExtensions) { 6685 v8::HandleScope handle_scope(CcTest::isolate()); 6686 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 6687 const char* extension_names[] = { "simpletest" }; 6688 v8::ExtensionConfiguration extensions(1, extension_names); 6689 v8::Handle<Context> context = 6690 Context::New(CcTest::isolate(), &extensions); 6691 Context::Scope lock(context); 6692 v8::Handle<Value> result = CompileRun("Foo()"); 6693 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 6694 } 6695 6696 6697 TEST(NullExtensions) { 6698 v8::HandleScope handle_scope(CcTest::isolate()); 6699 v8::RegisterExtension(new Extension("nulltest", NULL)); 6700 const char* extension_names[] = { "nulltest" }; 6701 v8::ExtensionConfiguration extensions(1, extension_names); 6702 v8::Handle<Context> context = 6703 Context::New(CcTest::isolate(), &extensions); 6704 Context::Scope lock(context); 6705 v8::Handle<Value> result = CompileRun("1+3"); 6706 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 6707 } 6708 6709 6710 static const char* kEmbeddedExtensionSource = 6711 "function Ret54321(){return 54321;}~~@@$" 6712 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 6713 static const int kEmbeddedExtensionSourceValidLen = 34; 6714 6715 6716 TEST(ExtensionMissingSourceLength) { 6717 v8::HandleScope handle_scope(CcTest::isolate()); 6718 v8::RegisterExtension(new Extension("srclentest_fail", 6719 kEmbeddedExtensionSource)); 6720 const char* extension_names[] = { "srclentest_fail" }; 6721 v8::ExtensionConfiguration extensions(1, extension_names); 6722 v8::Handle<Context> context = 6723 Context::New(CcTest::isolate(), &extensions); 6724 CHECK_EQ(0, *context); 6725 } 6726 6727 6728 TEST(ExtensionWithSourceLength) { 6729 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 6730 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 6731 v8::HandleScope handle_scope(CcTest::isolate()); 6732 i::ScopedVector<char> extension_name(32); 6733 i::SNPrintF(extension_name, "ext #%d", source_len); 6734 v8::RegisterExtension(new Extension(extension_name.start(), 6735 kEmbeddedExtensionSource, 0, 0, 6736 source_len)); 6737 const char* extension_names[1] = { extension_name.start() }; 6738 v8::ExtensionConfiguration extensions(1, extension_names); 6739 v8::Handle<Context> context = 6740 Context::New(CcTest::isolate(), &extensions); 6741 if (source_len == kEmbeddedExtensionSourceValidLen) { 6742 Context::Scope lock(context); 6743 v8::Handle<Value> result = CompileRun("Ret54321()"); 6744 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result); 6745 } else { 6746 // Anything but exactly the right length should fail to compile. 6747 CHECK_EQ(0, *context); 6748 } 6749 } 6750 } 6751 6752 6753 static const char* kEvalExtensionSource1 = 6754 "function UseEval1() {" 6755 " var x = 42;" 6756 " return eval('x');" 6757 "}"; 6758 6759 6760 static const char* kEvalExtensionSource2 = 6761 "(function() {" 6762 " var x = 42;" 6763 " function e() {" 6764 " return eval('x');" 6765 " }" 6766 " this.UseEval2 = e;" 6767 "})()"; 6768 6769 6770 TEST(UseEvalFromExtension) { 6771 v8::HandleScope handle_scope(CcTest::isolate()); 6772 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 6773 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 6774 const char* extension_names[] = { "evaltest1", "evaltest2" }; 6775 v8::ExtensionConfiguration extensions(2, extension_names); 6776 v8::Handle<Context> context = 6777 Context::New(CcTest::isolate(), &extensions); 6778 Context::Scope lock(context); 6779 v8::Handle<Value> result = CompileRun("UseEval1()"); 6780 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 6781 result = CompileRun("UseEval2()"); 6782 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 6783 } 6784 6785 6786 static const char* kWithExtensionSource1 = 6787 "function UseWith1() {" 6788 " var x = 42;" 6789 " with({x:87}) { return x; }" 6790 "}"; 6791 6792 6793 6794 static const char* kWithExtensionSource2 = 6795 "(function() {" 6796 " var x = 42;" 6797 " function e() {" 6798 " with ({x:87}) { return x; }" 6799 " }" 6800 " this.UseWith2 = e;" 6801 "})()"; 6802 6803 6804 TEST(UseWithFromExtension) { 6805 v8::HandleScope handle_scope(CcTest::isolate()); 6806 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 6807 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 6808 const char* extension_names[] = { "withtest1", "withtest2" }; 6809 v8::ExtensionConfiguration extensions(2, extension_names); 6810 v8::Handle<Context> context = 6811 Context::New(CcTest::isolate(), &extensions); 6812 Context::Scope lock(context); 6813 v8::Handle<Value> result = CompileRun("UseWith1()"); 6814 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87)); 6815 result = CompileRun("UseWith2()"); 6816 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87)); 6817 } 6818 6819 6820 TEST(AutoExtensions) { 6821 v8::HandleScope handle_scope(CcTest::isolate()); 6822 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 6823 extension->set_auto_enable(true); 6824 v8::RegisterExtension(extension); 6825 v8::Handle<Context> context = 6826 Context::New(CcTest::isolate()); 6827 Context::Scope lock(context); 6828 v8::Handle<Value> result = CompileRun("Foo()"); 6829 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 6830 } 6831 6832 6833 static const char* kSyntaxErrorInExtensionSource = 6834 "["; 6835 6836 6837 // Test that a syntax error in an extension does not cause a fatal 6838 // error but results in an empty context. 6839 TEST(SyntaxErrorExtensions) { 6840 v8::HandleScope handle_scope(CcTest::isolate()); 6841 v8::RegisterExtension(new Extension("syntaxerror", 6842 kSyntaxErrorInExtensionSource)); 6843 const char* extension_names[] = { "syntaxerror" }; 6844 v8::ExtensionConfiguration extensions(1, extension_names); 6845 v8::Handle<Context> context = 6846 Context::New(CcTest::isolate(), &extensions); 6847 CHECK(context.IsEmpty()); 6848 } 6849 6850 6851 static const char* kExceptionInExtensionSource = 6852 "throw 42"; 6853 6854 6855 // Test that an exception when installing an extension does not cause 6856 // a fatal error but results in an empty context. 6857 TEST(ExceptionExtensions) { 6858 v8::HandleScope handle_scope(CcTest::isolate()); 6859 v8::RegisterExtension(new Extension("exception", 6860 kExceptionInExtensionSource)); 6861 const char* extension_names[] = { "exception" }; 6862 v8::ExtensionConfiguration extensions(1, extension_names); 6863 v8::Handle<Context> context = 6864 Context::New(CcTest::isolate(), &extensions); 6865 CHECK(context.IsEmpty()); 6866 } 6867 6868 6869 static const char* kNativeCallInExtensionSource = 6870 "function call_runtime_last_index_of(x) {" 6871 " return %StringLastIndexOf(x, 'bob', 10);" 6872 "}"; 6873 6874 6875 static const char* kNativeCallTest = 6876 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 6877 6878 // Test that a native runtime calls are supported in extensions. 6879 TEST(NativeCallInExtensions) { 6880 v8::HandleScope handle_scope(CcTest::isolate()); 6881 v8::RegisterExtension(new Extension("nativecall", 6882 kNativeCallInExtensionSource)); 6883 const char* extension_names[] = { "nativecall" }; 6884 v8::ExtensionConfiguration extensions(1, extension_names); 6885 v8::Handle<Context> context = 6886 Context::New(CcTest::isolate(), &extensions); 6887 Context::Scope lock(context); 6888 v8::Handle<Value> result = CompileRun(kNativeCallTest); 6889 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3)); 6890 } 6891 6892 6893 class NativeFunctionExtension : public Extension { 6894 public: 6895 NativeFunctionExtension(const char* name, 6896 const char* source, 6897 v8::FunctionCallback fun = &Echo) 6898 : Extension(name, source), 6899 function_(fun) { } 6900 6901 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 6902 v8::Isolate* isolate, 6903 v8::Handle<v8::String> name) { 6904 return v8::FunctionTemplate::New(isolate, function_); 6905 } 6906 6907 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 6908 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 6909 } 6910 private: 6911 v8::FunctionCallback function_; 6912 }; 6913 6914 6915 TEST(NativeFunctionDeclaration) { 6916 v8::HandleScope handle_scope(CcTest::isolate()); 6917 const char* name = "nativedecl"; 6918 v8::RegisterExtension(new NativeFunctionExtension(name, 6919 "native function foo();")); 6920 const char* extension_names[] = { name }; 6921 v8::ExtensionConfiguration extensions(1, extension_names); 6922 v8::Handle<Context> context = 6923 Context::New(CcTest::isolate(), &extensions); 6924 Context::Scope lock(context); 6925 v8::Handle<Value> result = CompileRun("foo(42);"); 6926 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 6927 } 6928 6929 6930 TEST(NativeFunctionDeclarationError) { 6931 v8::HandleScope handle_scope(CcTest::isolate()); 6932 const char* name = "nativedeclerr"; 6933 // Syntax error in extension code. 6934 v8::RegisterExtension(new NativeFunctionExtension(name, 6935 "native\nfunction foo();")); 6936 const char* extension_names[] = { name }; 6937 v8::ExtensionConfiguration extensions(1, extension_names); 6938 v8::Handle<Context> context = 6939 Context::New(CcTest::isolate(), &extensions); 6940 CHECK(context.IsEmpty()); 6941 } 6942 6943 6944 TEST(NativeFunctionDeclarationErrorEscape) { 6945 v8::HandleScope handle_scope(CcTest::isolate()); 6946 const char* name = "nativedeclerresc"; 6947 // Syntax error in extension code - escape code in "native" means that 6948 // it's not treated as a keyword. 6949 v8::RegisterExtension(new NativeFunctionExtension( 6950 name, 6951 "nativ\\u0065 function foo();")); 6952 const char* extension_names[] = { name }; 6953 v8::ExtensionConfiguration extensions(1, extension_names); 6954 v8::Handle<Context> context = 6955 Context::New(CcTest::isolate(), &extensions); 6956 CHECK(context.IsEmpty()); 6957 } 6958 6959 6960 static void CheckDependencies(const char* name, const char* expected) { 6961 v8::HandleScope handle_scope(CcTest::isolate()); 6962 v8::ExtensionConfiguration config(1, &name); 6963 LocalContext context(&config); 6964 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected), 6965 context->Global()->Get(v8_str("loaded"))); 6966 } 6967 6968 6969 /* 6970 * Configuration: 6971 * 6972 * /-- B <--\ 6973 * A <- -- D <-- E 6974 * \-- C <--/ 6975 */ 6976 THREADED_TEST(ExtensionDependency) { 6977 static const char* kEDeps[] = { "D" }; 6978 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 6979 static const char* kDDeps[] = { "B", "C" }; 6980 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 6981 static const char* kBCDeps[] = { "A" }; 6982 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 6983 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 6984 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 6985 CheckDependencies("A", "undefinedA"); 6986 CheckDependencies("B", "undefinedAB"); 6987 CheckDependencies("C", "undefinedAC"); 6988 CheckDependencies("D", "undefinedABCD"); 6989 CheckDependencies("E", "undefinedABCDE"); 6990 v8::HandleScope handle_scope(CcTest::isolate()); 6991 static const char* exts[2] = { "C", "E" }; 6992 v8::ExtensionConfiguration config(2, exts); 6993 LocalContext context(&config); 6994 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded"))); 6995 } 6996 6997 6998 static const char* kExtensionTestScript = 6999 "native function A();" 7000 "native function B();" 7001 "native function C();" 7002 "function Foo(i) {" 7003 " if (i == 0) return A();" 7004 " if (i == 1) return B();" 7005 " if (i == 2) return C();" 7006 "}"; 7007 7008 7009 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 7010 ApiTestFuzzer::Fuzz(); 7011 if (args.IsConstructCall()) { 7012 args.This()->Set(v8_str("data"), args.Data()); 7013 args.GetReturnValue().SetNull(); 7014 return; 7015 } 7016 args.GetReturnValue().Set(args.Data()); 7017 } 7018 7019 7020 class FunctionExtension : public Extension { 7021 public: 7022 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { } 7023 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 7024 v8::Isolate* isolate, 7025 v8::Handle<String> name); 7026 }; 7027 7028 7029 static int lookup_count = 0; 7030 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate( 7031 v8::Isolate* isolate, v8::Handle<String> name) { 7032 lookup_count++; 7033 if (name->Equals(v8_str("A"))) { 7034 return v8::FunctionTemplate::New( 7035 isolate, CallFun, v8::Integer::New(isolate, 8)); 7036 } else if (name->Equals(v8_str("B"))) { 7037 return v8::FunctionTemplate::New( 7038 isolate, CallFun, v8::Integer::New(isolate, 7)); 7039 } else if (name->Equals(v8_str("C"))) { 7040 return v8::FunctionTemplate::New( 7041 isolate, CallFun, v8::Integer::New(isolate, 6)); 7042 } else { 7043 return v8::Handle<v8::FunctionTemplate>(); 7044 } 7045 } 7046 7047 7048 THREADED_TEST(FunctionLookup) { 7049 v8::RegisterExtension(new FunctionExtension()); 7050 v8::HandleScope handle_scope(CcTest::isolate()); 7051 static const char* exts[1] = { "functiontest" }; 7052 v8::ExtensionConfiguration config(1, exts); 7053 LocalContext context(&config); 7054 CHECK_EQ(3, lookup_count); 7055 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8), 7056 CompileRun("Foo(0)")); 7057 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7), 7058 CompileRun("Foo(1)")); 7059 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6), 7060 CompileRun("Foo(2)")); 7061 } 7062 7063 7064 THREADED_TEST(NativeFunctionConstructCall) { 7065 v8::RegisterExtension(new FunctionExtension()); 7066 v8::HandleScope handle_scope(CcTest::isolate()); 7067 static const char* exts[1] = { "functiontest" }; 7068 v8::ExtensionConfiguration config(1, exts); 7069 LocalContext context(&config); 7070 for (int i = 0; i < 10; i++) { 7071 // Run a few times to ensure that allocation of objects doesn't 7072 // change behavior of a constructor function. 7073 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8), 7074 CompileRun("(new A()).data")); 7075 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7), 7076 CompileRun("(new B()).data")); 7077 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6), 7078 CompileRun("(new C()).data")); 7079 } 7080 } 7081 7082 7083 static const char* last_location; 7084 static const char* last_message; 7085 void StoringErrorCallback(const char* location, const char* message) { 7086 if (last_location == NULL) { 7087 last_location = location; 7088 last_message = message; 7089 } 7090 } 7091 7092 7093 // ErrorReporting creates a circular extensions configuration and 7094 // tests that the fatal error handler gets called. This renders V8 7095 // unusable and therefore this test cannot be run in parallel. 7096 TEST(ErrorReporting) { 7097 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 7098 static const char* aDeps[] = { "B" }; 7099 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 7100 static const char* bDeps[] = { "A" }; 7101 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 7102 last_location = NULL; 7103 v8::ExtensionConfiguration config(1, bDeps); 7104 v8::Handle<Context> context = 7105 Context::New(CcTest::isolate(), &config); 7106 CHECK(context.IsEmpty()); 7107 CHECK_NE(last_location, NULL); 7108 } 7109 7110 7111 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, 7112 v8::Handle<Value> data) { 7113 CHECK(message->GetScriptResourceName()->IsUndefined()); 7114 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName()); 7115 message->GetLineNumber(); 7116 message->GetSourceLine(); 7117 } 7118 7119 7120 THREADED_TEST(ErrorWithMissingScriptInfo) { 7121 LocalContext context; 7122 v8::HandleScope scope(context->GetIsolate()); 7123 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); 7124 CompileRun("throw Error()"); 7125 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); 7126 } 7127 7128 7129 struct FlagAndPersistent { 7130 bool flag; 7131 v8::Persistent<v8::Object> handle; 7132 }; 7133 7134 7135 static void DisposeAndSetFlag( 7136 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7137 data.GetParameter()->handle.Reset(); 7138 data.GetParameter()->flag = true; 7139 } 7140 7141 7142 THREADED_TEST(IndependentWeakHandle) { 7143 v8::Isolate* iso = CcTest::isolate(); 7144 v8::HandleScope scope(iso); 7145 v8::Handle<Context> context = Context::New(iso); 7146 Context::Scope context_scope(context); 7147 7148 FlagAndPersistent object_a, object_b; 7149 7150 { 7151 v8::HandleScope handle_scope(iso); 7152 object_a.handle.Reset(iso, v8::Object::New(iso)); 7153 object_b.handle.Reset(iso, v8::Object::New(iso)); 7154 } 7155 7156 object_a.flag = false; 7157 object_b.flag = false; 7158 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag); 7159 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag); 7160 CHECK(!object_b.handle.IsIndependent()); 7161 object_a.handle.MarkIndependent(); 7162 object_b.handle.MarkIndependent(); 7163 CHECK(object_b.handle.IsIndependent()); 7164 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7165 CHECK(object_a.flag); 7166 CHECK(object_b.flag); 7167 } 7168 7169 7170 static void InvokeScavenge() { 7171 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7172 } 7173 7174 7175 static void InvokeMarkSweep() { 7176 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7177 } 7178 7179 7180 static void ForceScavenge( 7181 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7182 data.GetParameter()->handle.Reset(); 7183 data.GetParameter()->flag = true; 7184 InvokeScavenge(); 7185 } 7186 7187 7188 static void ForceMarkSweep( 7189 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7190 data.GetParameter()->handle.Reset(); 7191 data.GetParameter()->flag = true; 7192 InvokeMarkSweep(); 7193 } 7194 7195 7196 THREADED_TEST(GCFromWeakCallbacks) { 7197 v8::Isolate* isolate = CcTest::isolate(); 7198 v8::HandleScope scope(isolate); 7199 v8::Handle<Context> context = Context::New(isolate); 7200 Context::Scope context_scope(context); 7201 7202 static const int kNumberOfGCTypes = 2; 7203 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback 7204 Callback; 7205 Callback gc_forcing_callback[kNumberOfGCTypes] = 7206 {&ForceScavenge, &ForceMarkSweep}; 7207 7208 typedef void (*GCInvoker)(); 7209 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 7210 7211 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 7212 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 7213 FlagAndPersistent object; 7214 { 7215 v8::HandleScope handle_scope(isolate); 7216 object.handle.Reset(isolate, v8::Object::New(isolate)); 7217 } 7218 object.flag = false; 7219 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]); 7220 object.handle.MarkIndependent(); 7221 invoke_gc[outer_gc](); 7222 CHECK(object.flag); 7223 } 7224 } 7225 } 7226 7227 7228 static void RevivingCallback( 7229 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7230 data.GetParameter()->handle.ClearWeak(); 7231 data.GetParameter()->flag = true; 7232 } 7233 7234 7235 THREADED_TEST(IndependentHandleRevival) { 7236 v8::Isolate* isolate = CcTest::isolate(); 7237 v8::HandleScope scope(isolate); 7238 v8::Handle<Context> context = Context::New(isolate); 7239 Context::Scope context_scope(context); 7240 7241 FlagAndPersistent object; 7242 { 7243 v8::HandleScope handle_scope(isolate); 7244 v8::Local<v8::Object> o = v8::Object::New(isolate); 7245 object.handle.Reset(isolate, o); 7246 o->Set(v8_str("x"), v8::Integer::New(isolate, 1)); 7247 v8::Local<String> y_str = v8_str("y"); 7248 o->Set(y_str, y_str); 7249 } 7250 object.flag = false; 7251 object.handle.SetWeak(&object, &RevivingCallback); 7252 object.handle.MarkIndependent(); 7253 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7254 CHECK(object.flag); 7255 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 7256 { 7257 v8::HandleScope handle_scope(isolate); 7258 v8::Local<v8::Object> o = 7259 v8::Local<v8::Object>::New(isolate, object.handle); 7260 v8::Local<String> y_str = v8_str("y"); 7261 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x"))); 7262 CHECK(o->Get(y_str)->Equals(y_str)); 7263 } 7264 } 7265 7266 7267 v8::Handle<Function> args_fun; 7268 7269 7270 static void ArgumentsTestCallback( 7271 const v8::FunctionCallbackInfo<v8::Value>& args) { 7272 ApiTestFuzzer::Fuzz(); 7273 v8::Isolate* isolate = args.GetIsolate(); 7274 CHECK_EQ(args_fun, args.Callee()); 7275 CHECK_EQ(3, args.Length()); 7276 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]); 7277 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]); 7278 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]); 7279 CHECK_EQ(v8::Undefined(isolate), args[3]); 7280 v8::HandleScope scope(args.GetIsolate()); 7281 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7282 } 7283 7284 7285 THREADED_TEST(Arguments) { 7286 v8::Isolate* isolate = CcTest::isolate(); 7287 v8::HandleScope scope(isolate); 7288 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 7289 global->Set(v8_str("f"), 7290 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback)); 7291 LocalContext context(NULL, global); 7292 args_fun = context->Global()->Get(v8_str("f")).As<Function>(); 7293 v8_compile("f(1, 2, 3)")->Run(); 7294 } 7295 7296 7297 static void NoBlockGetterX(Local<String> name, 7298 const v8::PropertyCallbackInfo<v8::Value>&) { 7299 } 7300 7301 7302 static void NoBlockGetterI(uint32_t index, 7303 const v8::PropertyCallbackInfo<v8::Value>&) { 7304 } 7305 7306 7307 static void PDeleter(Local<String> name, 7308 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7309 if (!name->Equals(v8_str("foo"))) { 7310 return; // not intercepted 7311 } 7312 7313 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7314 } 7315 7316 7317 static void IDeleter(uint32_t index, 7318 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7319 if (index != 2) { 7320 return; // not intercepted 7321 } 7322 7323 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7324 } 7325 7326 7327 THREADED_TEST(Deleter) { 7328 v8::Isolate* isolate = CcTest::isolate(); 7329 v8::HandleScope scope(isolate); 7330 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7331 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL); 7332 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL); 7333 LocalContext context; 7334 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7335 CompileRun( 7336 "k.foo = 'foo';" 7337 "k.bar = 'bar';" 7338 "k[2] = 2;" 7339 "k[4] = 4;"); 7340 CHECK(v8_compile("delete k.foo")->Run()->IsFalse()); 7341 CHECK(v8_compile("delete k.bar")->Run()->IsTrue()); 7342 7343 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo")); 7344 CHECK(v8_compile("k.bar")->Run()->IsUndefined()); 7345 7346 CHECK(v8_compile("delete k[2]")->Run()->IsFalse()); 7347 CHECK(v8_compile("delete k[4]")->Run()->IsTrue()); 7348 7349 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2)); 7350 CHECK(v8_compile("k[4]")->Run()->IsUndefined()); 7351 } 7352 7353 7354 static void GetK(Local<String> name, 7355 const v8::PropertyCallbackInfo<v8::Value>& info) { 7356 ApiTestFuzzer::Fuzz(); 7357 if (name->Equals(v8_str("foo")) || 7358 name->Equals(v8_str("bar")) || 7359 name->Equals(v8_str("baz"))) { 7360 info.GetReturnValue().SetUndefined(); 7361 } 7362 } 7363 7364 7365 static void IndexedGetK(uint32_t index, 7366 const v8::PropertyCallbackInfo<v8::Value>& info) { 7367 ApiTestFuzzer::Fuzz(); 7368 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined(); 7369 } 7370 7371 7372 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7373 ApiTestFuzzer::Fuzz(); 7374 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3); 7375 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo")); 7376 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar")); 7377 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz")); 7378 info.GetReturnValue().Set(result); 7379 } 7380 7381 7382 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7383 ApiTestFuzzer::Fuzz(); 7384 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 7385 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0")); 7386 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1")); 7387 info.GetReturnValue().Set(result); 7388 } 7389 7390 7391 THREADED_TEST(Enumerators) { 7392 v8::Isolate* isolate = CcTest::isolate(); 7393 v8::HandleScope scope(isolate); 7394 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7395 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); 7396 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); 7397 LocalContext context; 7398 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7399 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 7400 "k[10] = 0;" 7401 "k.a = 0;" 7402 "k[5] = 0;" 7403 "k.b = 0;" 7404 "k[4294967295] = 0;" 7405 "k.c = 0;" 7406 "k[4294967296] = 0;" 7407 "k.d = 0;" 7408 "k[140000] = 0;" 7409 "k.e = 0;" 7410 "k[30000000000] = 0;" 7411 "k.f = 0;" 7412 "var result = [];" 7413 "for (var prop in k) {" 7414 " result.push(prop);" 7415 "}" 7416 "result")); 7417 // Check that we get all the property names returned including the 7418 // ones from the enumerators in the right order: indexed properties 7419 // in numerical order, indexed interceptor properties, named 7420 // properties in insertion order, named interceptor properties. 7421 // This order is not mandated by the spec, so this test is just 7422 // documenting our behavior. 7423 CHECK_EQ(17, result->Length()); 7424 // Indexed properties in numerical order. 7425 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0))); 7426 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1))); 7427 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2))); 7428 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3))); 7429 // Indexed interceptor properties in the order they are returned 7430 // from the enumerator interceptor. 7431 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4))); 7432 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5))); 7433 // Named properties in insertion order. 7434 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6))); 7435 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7))); 7436 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8))); 7437 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9))); 7438 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10))); 7439 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11))); 7440 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12))); 7441 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13))); 7442 // Named interceptor properties. 7443 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14))); 7444 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15))); 7445 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16))); 7446 } 7447 7448 7449 int p_getter_count; 7450 int p_getter_count2; 7451 7452 7453 static void PGetter(Local<String> name, 7454 const v8::PropertyCallbackInfo<v8::Value>& info) { 7455 ApiTestFuzzer::Fuzz(); 7456 p_getter_count++; 7457 v8::Handle<v8::Object> global = 7458 info.GetIsolate()->GetCurrentContext()->Global(); 7459 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7460 if (name->Equals(v8_str("p1"))) { 7461 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7462 } else if (name->Equals(v8_str("p2"))) { 7463 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7464 } else if (name->Equals(v8_str("p3"))) { 7465 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7466 } else if (name->Equals(v8_str("p4"))) { 7467 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7468 } 7469 } 7470 7471 7472 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) { 7473 ApiTestFuzzer::Fuzz(); 7474 LocalContext context; 7475 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 7476 CompileRun( 7477 "o1.__proto__ = { };" 7478 "var o2 = { __proto__: o1 };" 7479 "var o3 = { __proto__: o2 };" 7480 "var o4 = { __proto__: o3 };" 7481 "for (var i = 0; i < 10; i++) o4.p4;" 7482 "for (var i = 0; i < 10; i++) o3.p3;" 7483 "for (var i = 0; i < 10; i++) o2.p2;" 7484 "for (var i = 0; i < 10; i++) o1.p1;"); 7485 } 7486 7487 7488 static void PGetter2(Local<String> name, 7489 const v8::PropertyCallbackInfo<v8::Value>& info) { 7490 ApiTestFuzzer::Fuzz(); 7491 p_getter_count2++; 7492 v8::Handle<v8::Object> global = 7493 info.GetIsolate()->GetCurrentContext()->Global(); 7494 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7495 if (name->Equals(v8_str("p1"))) { 7496 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7497 } else if (name->Equals(v8_str("p2"))) { 7498 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7499 } else if (name->Equals(v8_str("p3"))) { 7500 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7501 } else if (name->Equals(v8_str("p4"))) { 7502 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7503 } 7504 } 7505 7506 7507 THREADED_TEST(GetterHolders) { 7508 v8::Isolate* isolate = CcTest::isolate(); 7509 v8::HandleScope scope(isolate); 7510 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7511 obj->SetAccessor(v8_str("p1"), PGetter); 7512 obj->SetAccessor(v8_str("p2"), PGetter); 7513 obj->SetAccessor(v8_str("p3"), PGetter); 7514 obj->SetAccessor(v8_str("p4"), PGetter); 7515 p_getter_count = 0; 7516 RunHolderTest(obj); 7517 CHECK_EQ(40, p_getter_count); 7518 } 7519 7520 7521 THREADED_TEST(PreInterceptorHolders) { 7522 v8::Isolate* isolate = CcTest::isolate(); 7523 v8::HandleScope scope(isolate); 7524 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7525 obj->SetNamedPropertyHandler(PGetter2); 7526 p_getter_count2 = 0; 7527 RunHolderTest(obj); 7528 CHECK_EQ(40, p_getter_count2); 7529 } 7530 7531 7532 THREADED_TEST(ObjectInstantiation) { 7533 v8::Isolate* isolate = CcTest::isolate(); 7534 v8::HandleScope scope(isolate); 7535 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 7536 templ->SetAccessor(v8_str("t"), PGetter2); 7537 LocalContext context; 7538 context->Global()->Set(v8_str("o"), templ->NewInstance()); 7539 for (int i = 0; i < 100; i++) { 7540 v8::HandleScope inner_scope(CcTest::isolate()); 7541 v8::Handle<v8::Object> obj = templ->NewInstance(); 7542 CHECK_NE(obj, context->Global()->Get(v8_str("o"))); 7543 context->Global()->Set(v8_str("o2"), obj); 7544 v8::Handle<Value> value = 7545 CompileRun("o.__proto__ === o2.__proto__"); 7546 CHECK_EQ(v8::True(isolate), value); 7547 context->Global()->Set(v8_str("o"), obj); 7548 } 7549 } 7550 7551 7552 static int StrCmp16(uint16_t* a, uint16_t* b) { 7553 while (true) { 7554 if (*a == 0 && *b == 0) return 0; 7555 if (*a != *b) return 0 + *a - *b; 7556 a++; 7557 b++; 7558 } 7559 } 7560 7561 7562 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 7563 while (true) { 7564 if (n-- == 0) return 0; 7565 if (*a == 0 && *b == 0) return 0; 7566 if (*a != *b) return 0 + *a - *b; 7567 a++; 7568 b++; 7569 } 7570 } 7571 7572 7573 int GetUtf8Length(Handle<String> str) { 7574 int len = str->Utf8Length(); 7575 if (len < 0) { 7576 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 7577 i::String::Flatten(istr); 7578 len = str->Utf8Length(); 7579 } 7580 return len; 7581 } 7582 7583 7584 THREADED_TEST(StringWrite) { 7585 LocalContext context; 7586 v8::HandleScope scope(context->GetIsolate()); 7587 v8::Handle<String> str = v8_str("abcde"); 7588 // abc<Icelandic eth><Unicode snowman>. 7589 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203"); 7590 v8::Handle<String> str3 = v8::String::NewFromUtf8( 7591 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7); 7592 // "ab" + lead surrogate + "cd" + trail surrogate + "ef" 7593 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 }; 7594 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte( 7595 context->GetIsolate(), orphans, v8::String::kNormalString, 8); 7596 // single lead surrogate 7597 uint16_t lead[1] = { 0xd800 }; 7598 v8::Handle<String> lead_str = v8::String::NewFromTwoByte( 7599 context->GetIsolate(), lead, v8::String::kNormalString, 1); 7600 // single trail surrogate 7601 uint16_t trail[1] = { 0xdc00 }; 7602 v8::Handle<String> trail_str = v8::String::NewFromTwoByte( 7603 context->GetIsolate(), trail, v8::String::kNormalString, 1); 7604 // surrogate pair 7605 uint16_t pair[2] = { 0xd800, 0xdc00 }; 7606 v8::Handle<String> pair_str = v8::String::NewFromTwoByte( 7607 context->GetIsolate(), pair, v8::String::kNormalString, 2); 7608 const int kStride = 4; // Must match stride in for loops in JS below. 7609 CompileRun( 7610 "var left = '';" 7611 "for (var i = 0; i < 0xd800; i += 4) {" 7612 " left = left + String.fromCharCode(i);" 7613 "}"); 7614 CompileRun( 7615 "var right = '';" 7616 "for (var i = 0; i < 0xd800; i += 4) {" 7617 " right = String.fromCharCode(i) + right;" 7618 "}"); 7619 v8::Handle<v8::Object> global = context->Global(); 7620 Handle<String> left_tree = global->Get(v8_str("left")).As<String>(); 7621 Handle<String> right_tree = global->Get(v8_str("right")).As<String>(); 7622 7623 CHECK_EQ(5, str2->Length()); 7624 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 7625 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 7626 7627 char buf[100]; 7628 char utf8buf[0xd800 * 3]; 7629 uint16_t wbuf[100]; 7630 int len; 7631 int charlen; 7632 7633 memset(utf8buf, 0x1, 1000); 7634 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7635 CHECK_EQ(9, len); 7636 CHECK_EQ(5, charlen); 7637 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7638 7639 memset(utf8buf, 0x1, 1000); 7640 len = str2->WriteUtf8(utf8buf, 8, &charlen); 7641 CHECK_EQ(8, len); 7642 CHECK_EQ(5, charlen); 7643 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 7644 7645 memset(utf8buf, 0x1, 1000); 7646 len = str2->WriteUtf8(utf8buf, 7, &charlen); 7647 CHECK_EQ(5, len); 7648 CHECK_EQ(4, charlen); 7649 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7650 7651 memset(utf8buf, 0x1, 1000); 7652 len = str2->WriteUtf8(utf8buf, 6, &charlen); 7653 CHECK_EQ(5, len); 7654 CHECK_EQ(4, charlen); 7655 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7656 7657 memset(utf8buf, 0x1, 1000); 7658 len = str2->WriteUtf8(utf8buf, 5, &charlen); 7659 CHECK_EQ(5, len); 7660 CHECK_EQ(4, charlen); 7661 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7662 7663 memset(utf8buf, 0x1, 1000); 7664 len = str2->WriteUtf8(utf8buf, 4, &charlen); 7665 CHECK_EQ(3, len); 7666 CHECK_EQ(3, charlen); 7667 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7668 7669 memset(utf8buf, 0x1, 1000); 7670 len = str2->WriteUtf8(utf8buf, 3, &charlen); 7671 CHECK_EQ(3, len); 7672 CHECK_EQ(3, charlen); 7673 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7674 7675 memset(utf8buf, 0x1, 1000); 7676 len = str2->WriteUtf8(utf8buf, 2, &charlen); 7677 CHECK_EQ(2, len); 7678 CHECK_EQ(2, charlen); 7679 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 7680 7681 // allow orphan surrogates by default 7682 memset(utf8buf, 0x1, 1000); 7683 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7684 CHECK_EQ(13, len); 7685 CHECK_EQ(8, charlen); 7686 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef")); 7687 7688 // replace orphan surrogates with unicode replacement character 7689 memset(utf8buf, 0x1, 1000); 7690 len = orphans_str->WriteUtf8(utf8buf, 7691 sizeof(utf8buf), 7692 &charlen, 7693 String::REPLACE_INVALID_UTF8); 7694 CHECK_EQ(13, len); 7695 CHECK_EQ(8, charlen); 7696 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef")); 7697 7698 // replace single lead surrogate with unicode replacement character 7699 memset(utf8buf, 0x1, 1000); 7700 len = lead_str->WriteUtf8(utf8buf, 7701 sizeof(utf8buf), 7702 &charlen, 7703 String::REPLACE_INVALID_UTF8); 7704 CHECK_EQ(4, len); 7705 CHECK_EQ(1, charlen); 7706 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 7707 7708 // replace single trail surrogate with unicode replacement character 7709 memset(utf8buf, 0x1, 1000); 7710 len = trail_str->WriteUtf8(utf8buf, 7711 sizeof(utf8buf), 7712 &charlen, 7713 String::REPLACE_INVALID_UTF8); 7714 CHECK_EQ(4, len); 7715 CHECK_EQ(1, charlen); 7716 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 7717 7718 // do not replace / write anything if surrogate pair does not fit the buffer 7719 // space 7720 memset(utf8buf, 0x1, 1000); 7721 len = pair_str->WriteUtf8(utf8buf, 7722 3, 7723 &charlen, 7724 String::REPLACE_INVALID_UTF8); 7725 CHECK_EQ(0, len); 7726 CHECK_EQ(0, charlen); 7727 7728 memset(utf8buf, 0x1, sizeof(utf8buf)); 7729 len = GetUtf8Length(left_tree); 7730 int utf8_expected = 7731 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 7732 CHECK_EQ(utf8_expected, len); 7733 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7734 CHECK_EQ(utf8_expected, len); 7735 CHECK_EQ(0xd800 / kStride, charlen); 7736 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 7737 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 7738 CHECK_EQ(0xc0 - kStride, 7739 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 7740 CHECK_EQ(1, utf8buf[utf8_expected]); 7741 7742 memset(utf8buf, 0x1, sizeof(utf8buf)); 7743 len = GetUtf8Length(right_tree); 7744 CHECK_EQ(utf8_expected, len); 7745 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7746 CHECK_EQ(utf8_expected, len); 7747 CHECK_EQ(0xd800 / kStride, charlen); 7748 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 7749 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 7750 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 7751 CHECK_EQ(1, utf8buf[utf8_expected]); 7752 7753 memset(buf, 0x1, sizeof(buf)); 7754 memset(wbuf, 0x1, sizeof(wbuf)); 7755 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7756 CHECK_EQ(5, len); 7757 len = str->Write(wbuf); 7758 CHECK_EQ(5, len); 7759 CHECK_EQ(0, strcmp("abcde", buf)); 7760 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7761 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 7762 7763 memset(buf, 0x1, sizeof(buf)); 7764 memset(wbuf, 0x1, sizeof(wbuf)); 7765 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 7766 CHECK_EQ(4, len); 7767 len = str->Write(wbuf, 0, 4); 7768 CHECK_EQ(4, len); 7769 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 7770 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 7771 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 7772 7773 memset(buf, 0x1, sizeof(buf)); 7774 memset(wbuf, 0x1, sizeof(wbuf)); 7775 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 7776 CHECK_EQ(5, len); 7777 len = str->Write(wbuf, 0, 5); 7778 CHECK_EQ(5, len); 7779 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 7780 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 7781 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 7782 7783 memset(buf, 0x1, sizeof(buf)); 7784 memset(wbuf, 0x1, sizeof(wbuf)); 7785 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 7786 CHECK_EQ(5, len); 7787 len = str->Write(wbuf, 0, 6); 7788 CHECK_EQ(5, len); 7789 CHECK_EQ(0, strcmp("abcde", buf)); 7790 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7791 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 7792 7793 memset(buf, 0x1, sizeof(buf)); 7794 memset(wbuf, 0x1, sizeof(wbuf)); 7795 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 7796 CHECK_EQ(1, len); 7797 len = str->Write(wbuf, 4, -1); 7798 CHECK_EQ(1, len); 7799 CHECK_EQ(0, strcmp("e", buf)); 7800 uint16_t answer5[] = {'e', '\0'}; 7801 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7802 7803 memset(buf, 0x1, sizeof(buf)); 7804 memset(wbuf, 0x1, sizeof(wbuf)); 7805 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 7806 CHECK_EQ(1, len); 7807 len = str->Write(wbuf, 4, 6); 7808 CHECK_EQ(1, len); 7809 CHECK_EQ(0, strcmp("e", buf)); 7810 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7811 7812 memset(buf, 0x1, sizeof(buf)); 7813 memset(wbuf, 0x1, sizeof(wbuf)); 7814 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 7815 CHECK_EQ(1, len); 7816 len = str->Write(wbuf, 4, 1); 7817 CHECK_EQ(1, len); 7818 CHECK_EQ(0, strncmp("e\1", buf, 2)); 7819 uint16_t answer6[] = {'e', 0x101}; 7820 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 7821 7822 memset(buf, 0x1, sizeof(buf)); 7823 memset(wbuf, 0x1, sizeof(wbuf)); 7824 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 7825 CHECK_EQ(1, len); 7826 len = str->Write(wbuf, 3, 1); 7827 CHECK_EQ(1, len); 7828 CHECK_EQ(0, strncmp("d\1", buf, 2)); 7829 uint16_t answer7[] = {'d', 0x101}; 7830 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 7831 7832 memset(wbuf, 0x1, sizeof(wbuf)); 7833 wbuf[5] = 'X'; 7834 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 7835 CHECK_EQ(5, len); 7836 CHECK_EQ('X', wbuf[5]); 7837 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 7838 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7839 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 7840 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 7841 wbuf[5] = '\0'; 7842 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 7843 7844 memset(buf, 0x1, sizeof(buf)); 7845 buf[5] = 'X'; 7846 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 7847 0, 7848 6, 7849 String::NO_NULL_TERMINATION); 7850 CHECK_EQ(5, len); 7851 CHECK_EQ('X', buf[5]); 7852 CHECK_EQ(0, strncmp("abcde", buf, 5)); 7853 CHECK_NE(0, strcmp("abcde", buf)); 7854 buf[5] = '\0'; 7855 CHECK_EQ(0, strcmp("abcde", buf)); 7856 7857 memset(utf8buf, 0x1, sizeof(utf8buf)); 7858 utf8buf[8] = 'X'; 7859 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7860 String::NO_NULL_TERMINATION); 7861 CHECK_EQ(8, len); 7862 CHECK_EQ('X', utf8buf[8]); 7863 CHECK_EQ(5, charlen); 7864 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 7865 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7866 utf8buf[8] = '\0'; 7867 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7868 7869 memset(utf8buf, 0x1, sizeof(utf8buf)); 7870 utf8buf[5] = 'X'; 7871 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7872 String::NO_NULL_TERMINATION); 7873 CHECK_EQ(5, len); 7874 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 7875 CHECK_EQ(5, charlen); 7876 utf8buf[5] = '\0'; 7877 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 7878 7879 memset(buf, 0x1, sizeof(buf)); 7880 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7881 CHECK_EQ(7, len); 7882 CHECK_EQ(0, strcmp("abc", buf)); 7883 CHECK_EQ(0, buf[3]); 7884 CHECK_EQ(0, strcmp("def", buf + 4)); 7885 7886 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7887 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7888 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7889 } 7890 7891 7892 static void Utf16Helper( 7893 LocalContext& context, // NOLINT 7894 const char* name, 7895 const char* lengths_name, 7896 int len) { 7897 Local<v8::Array> a = 7898 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7899 Local<v8::Array> alens = 7900 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7901 for (int i = 0; i < len; i++) { 7902 Local<v8::String> string = 7903 Local<v8::String>::Cast(a->Get(i)); 7904 Local<v8::Number> expected_len = 7905 Local<v8::Number>::Cast(alens->Get(i)); 7906 int length = GetUtf8Length(string); 7907 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 7908 } 7909 } 7910 7911 7912 static uint16_t StringGet(Handle<String> str, int index) { 7913 i::Handle<i::String> istring = 7914 v8::Utils::OpenHandle(String::Cast(*str)); 7915 return istring->Get(index); 7916 } 7917 7918 7919 static void WriteUtf8Helper( 7920 LocalContext& context, // NOLINT 7921 const char* name, 7922 const char* lengths_name, 7923 int len) { 7924 Local<v8::Array> b = 7925 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7926 Local<v8::Array> alens = 7927 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7928 char buffer[1000]; 7929 char buffer2[1000]; 7930 for (int i = 0; i < len; i++) { 7931 Local<v8::String> string = 7932 Local<v8::String>::Cast(b->Get(i)); 7933 Local<v8::Number> expected_len = 7934 Local<v8::Number>::Cast(alens->Get(i)); 7935 int utf8_length = static_cast<int>(expected_len->Value()); 7936 for (int j = utf8_length + 1; j >= 0; j--) { 7937 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer)); 7938 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2)); 7939 int nchars; 7940 int utf8_written = 7941 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS); 7942 int utf8_written2 = 7943 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION); 7944 CHECK_GE(utf8_length + 1, utf8_written); 7945 CHECK_GE(utf8_length, utf8_written2); 7946 for (int k = 0; k < utf8_written2; k++) { 7947 CHECK_EQ(buffer[k], buffer2[k]); 7948 } 7949 CHECK(nchars * 3 >= utf8_written - 1); 7950 CHECK(nchars <= utf8_written); 7951 if (j == utf8_length + 1) { 7952 CHECK_EQ(utf8_written2, utf8_length); 7953 CHECK_EQ(utf8_written2 + 1, utf8_written); 7954 } 7955 CHECK_EQ(buffer[utf8_written], 42); 7956 if (j > utf8_length) { 7957 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0); 7958 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42); 7959 Handle<String> roundtrip = v8_str(buffer); 7960 CHECK(roundtrip->Equals(string)); 7961 } else { 7962 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7963 } 7964 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7965 if (nchars >= 2) { 7966 uint16_t trail = StringGet(string, nchars - 1); 7967 uint16_t lead = StringGet(string, nchars - 2); 7968 if (((lead & 0xfc00) == 0xd800) && 7969 ((trail & 0xfc00) == 0xdc00)) { 7970 unsigned char u1 = buffer2[utf8_written2 - 4]; 7971 unsigned char u2 = buffer2[utf8_written2 - 3]; 7972 unsigned char u3 = buffer2[utf8_written2 - 2]; 7973 unsigned char u4 = buffer2[utf8_written2 - 1]; 7974 CHECK_EQ((u1 & 0xf8), 0xf0); 7975 CHECK_EQ((u2 & 0xc0), 0x80); 7976 CHECK_EQ((u3 & 0xc0), 0x80); 7977 CHECK_EQ((u4 & 0xc0), 0x80); 7978 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff); 7979 CHECK_EQ((u4 & 0x3f), (c & 0x3f)); 7980 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f)); 7981 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f)); 7982 CHECK_EQ((u1 & 0x3), c >> 18); 7983 } 7984 } 7985 } 7986 } 7987 } 7988 7989 7990 THREADED_TEST(Utf16) { 7991 LocalContext context; 7992 v8::HandleScope scope(context->GetIsolate()); 7993 CompileRun( 7994 "var pad = '01234567890123456789';" 7995 "var p = [];" 7996 "var plens = [20, 3, 3];" 7997 "p.push('01234567890123456789');" 7998 "var lead = 0xd800;" 7999 "var trail = 0xdc00;" 8000 "p.push(String.fromCharCode(0xd800));" 8001 "p.push(String.fromCharCode(0xdc00));" 8002 "var a = [];" 8003 "var b = [];" 8004 "var c = [];" 8005 "var alens = [];" 8006 "for (var i = 0; i < 3; i++) {" 8007 " p[1] = String.fromCharCode(lead++);" 8008 " for (var j = 0; j < 3; j++) {" 8009 " p[2] = String.fromCharCode(trail++);" 8010 " a.push(p[i] + p[j]);" 8011 " b.push(p[i] + p[j]);" 8012 " c.push(p[i] + p[j]);" 8013 " alens.push(plens[i] + plens[j]);" 8014 " }" 8015 "}" 8016 "alens[5] -= 2;" // Here the surrogate pairs match up. 8017 "var a2 = [];" 8018 "var b2 = [];" 8019 "var c2 = [];" 8020 "var a2lens = [];" 8021 "for (var m = 0; m < 9; m++) {" 8022 " for (var n = 0; n < 9; n++) {" 8023 " a2.push(a[m] + a[n]);" 8024 " b2.push(b[m] + b[n]);" 8025 " var newc = 'x' + c[m] + c[n] + 'y';" 8026 " c2.push(newc.substring(1, newc.length - 1));" 8027 " var utf = alens[m] + alens[n];" // And here. 8028 // The 'n's that start with 0xdc.. are 6-8 8029 // The 'm's that end with 0xd8.. are 1, 4 and 7 8030 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 8031 " a2lens.push(utf);" 8032 " }" 8033 "}"); 8034 Utf16Helper(context, "a", "alens", 9); 8035 Utf16Helper(context, "a2", "a2lens", 81); 8036 WriteUtf8Helper(context, "b", "alens", 9); 8037 WriteUtf8Helper(context, "b2", "a2lens", 81); 8038 WriteUtf8Helper(context, "c2", "a2lens", 81); 8039 } 8040 8041 8042 static bool SameSymbol(Handle<String> s1, Handle<String> s2) { 8043 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 8044 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 8045 return *is1 == *is2; 8046 } 8047 8048 static void SameSymbolHelper(v8::Isolate* isolate, const char* a, 8049 const char* b) { 8050 Handle<String> symbol1 = 8051 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString); 8052 Handle<String> symbol2 = 8053 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString); 8054 CHECK(SameSymbol(symbol1, symbol2)); 8055 } 8056 8057 8058 THREADED_TEST(Utf16Symbol) { 8059 LocalContext context; 8060 v8::HandleScope scope(context->GetIsolate()); 8061 8062 Handle<String> symbol1 = v8::String::NewFromUtf8( 8063 context->GetIsolate(), "abc", v8::String::kInternalizedString); 8064 Handle<String> symbol2 = v8::String::NewFromUtf8( 8065 context->GetIsolate(), "abc", v8::String::kInternalizedString); 8066 CHECK(SameSymbol(symbol1, symbol2)); 8067 8068 SameSymbolHelper(context->GetIsolate(), 8069 "\360\220\220\205", // 4 byte encoding. 8070 "\355\240\201\355\260\205"); // 2 3-byte surrogates. 8071 SameSymbolHelper(context->GetIsolate(), 8072 "\355\240\201\355\260\206", // 2 3-byte surrogates. 8073 "\360\220\220\206"); // 4 byte encoding. 8074 SameSymbolHelper(context->GetIsolate(), 8075 "x\360\220\220\205", // 4 byte encoding. 8076 "x\355\240\201\355\260\205"); // 2 3-byte surrogates. 8077 SameSymbolHelper(context->GetIsolate(), 8078 "x\355\240\201\355\260\206", // 2 3-byte surrogates. 8079 "x\360\220\220\206"); // 4 byte encoding. 8080 CompileRun( 8081 "var sym0 = 'benedictus';" 8082 "var sym0b = 'S\303\270ren';" 8083 "var sym1 = '\355\240\201\355\260\207';" 8084 "var sym2 = '\360\220\220\210';" 8085 "var sym3 = 'x\355\240\201\355\260\207';" 8086 "var sym4 = 'x\360\220\220\210';" 8087 "if (sym1.length != 2) throw sym1;" 8088 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 8089 "if (sym2.length != 2) throw sym2;" 8090 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 8091 "if (sym3.length != 3) throw sym3;" 8092 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 8093 "if (sym4.length != 3) throw sym4;" 8094 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 8095 Handle<String> sym0 = v8::String::NewFromUtf8( 8096 context->GetIsolate(), "benedictus", v8::String::kInternalizedString); 8097 Handle<String> sym0b = v8::String::NewFromUtf8( 8098 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString); 8099 Handle<String> sym1 = 8100 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207", 8101 v8::String::kInternalizedString); 8102 Handle<String> sym2 = 8103 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210", 8104 v8::String::kInternalizedString); 8105 Handle<String> sym3 = v8::String::NewFromUtf8( 8106 context->GetIsolate(), "x\355\240\201\355\260\207", 8107 v8::String::kInternalizedString); 8108 Handle<String> sym4 = 8109 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210", 8110 v8::String::kInternalizedString); 8111 v8::Local<v8::Object> global = context->Global(); 8112 Local<Value> s0 = global->Get(v8_str("sym0")); 8113 Local<Value> s0b = global->Get(v8_str("sym0b")); 8114 Local<Value> s1 = global->Get(v8_str("sym1")); 8115 Local<Value> s2 = global->Get(v8_str("sym2")); 8116 Local<Value> s3 = global->Get(v8_str("sym3")); 8117 Local<Value> s4 = global->Get(v8_str("sym4")); 8118 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0))); 8119 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b))); 8120 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1))); 8121 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2))); 8122 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3))); 8123 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4))); 8124 } 8125 8126 8127 THREADED_TEST(ToArrayIndex) { 8128 LocalContext context; 8129 v8::Isolate* isolate = context->GetIsolate(); 8130 v8::HandleScope scope(isolate); 8131 8132 v8::Handle<String> str = v8_str("42"); 8133 v8::Handle<v8::Uint32> index = str->ToArrayIndex(); 8134 CHECK(!index.IsEmpty()); 8135 CHECK_EQ(42.0, index->Uint32Value()); 8136 str = v8_str("42asdf"); 8137 index = str->ToArrayIndex(); 8138 CHECK(index.IsEmpty()); 8139 str = v8_str("-42"); 8140 index = str->ToArrayIndex(); 8141 CHECK(index.IsEmpty()); 8142 str = v8_str("4294967295"); 8143 index = str->ToArrayIndex(); 8144 CHECK(!index.IsEmpty()); 8145 CHECK_EQ(4294967295.0, index->Uint32Value()); 8146 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1); 8147 index = num->ToArrayIndex(); 8148 CHECK(!index.IsEmpty()); 8149 CHECK_EQ(1.0, index->Uint32Value()); 8150 num = v8::Number::New(isolate, -1); 8151 index = num->ToArrayIndex(); 8152 CHECK(index.IsEmpty()); 8153 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 8154 index = obj->ToArrayIndex(); 8155 CHECK(index.IsEmpty()); 8156 } 8157 8158 8159 THREADED_TEST(ErrorConstruction) { 8160 LocalContext context; 8161 v8::HandleScope scope(context->GetIsolate()); 8162 8163 v8::Handle<String> foo = v8_str("foo"); 8164 v8::Handle<String> message = v8_str("message"); 8165 v8::Handle<Value> range_error = v8::Exception::RangeError(foo); 8166 CHECK(range_error->IsObject()); 8167 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo)); 8168 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo); 8169 CHECK(reference_error->IsObject()); 8170 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo)); 8171 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo); 8172 CHECK(syntax_error->IsObject()); 8173 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo)); 8174 v8::Handle<Value> type_error = v8::Exception::TypeError(foo); 8175 CHECK(type_error->IsObject()); 8176 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo)); 8177 v8::Handle<Value> error = v8::Exception::Error(foo); 8178 CHECK(error->IsObject()); 8179 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo)); 8180 } 8181 8182 8183 static void YGetter(Local<String> name, 8184 const v8::PropertyCallbackInfo<v8::Value>& info) { 8185 ApiTestFuzzer::Fuzz(); 8186 info.GetReturnValue().Set(v8_num(10)); 8187 } 8188 8189 8190 static void YSetter(Local<String> name, 8191 Local<Value> value, 8192 const v8::PropertyCallbackInfo<void>& info) { 8193 Local<Object> this_obj = Local<Object>::Cast(info.This()); 8194 if (this_obj->Has(name)) this_obj->Delete(name); 8195 this_obj->Set(name, value); 8196 } 8197 8198 8199 THREADED_TEST(DeleteAccessor) { 8200 v8::Isolate* isolate = CcTest::isolate(); 8201 v8::HandleScope scope(isolate); 8202 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8203 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 8204 LocalContext context; 8205 v8::Handle<v8::Object> holder = obj->NewInstance(); 8206 context->Global()->Set(v8_str("holder"), holder); 8207 v8::Handle<Value> result = CompileRun( 8208 "holder.y = 11; holder.y = 12; holder.y"); 8209 CHECK_EQ(12, result->Uint32Value()); 8210 } 8211 8212 8213 THREADED_TEST(TypeSwitch) { 8214 v8::Isolate* isolate = CcTest::isolate(); 8215 v8::HandleScope scope(isolate); 8216 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate); 8217 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate); 8218 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate); 8219 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 }; 8220 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs); 8221 LocalContext context; 8222 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate); 8223 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance(); 8224 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance(); 8225 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance(); 8226 for (int i = 0; i < 10; i++) { 8227 CHECK_EQ(0, type_switch->match(obj0)); 8228 CHECK_EQ(1, type_switch->match(obj1)); 8229 CHECK_EQ(2, type_switch->match(obj2)); 8230 CHECK_EQ(3, type_switch->match(obj3)); 8231 CHECK_EQ(3, type_switch->match(obj3)); 8232 CHECK_EQ(2, type_switch->match(obj2)); 8233 CHECK_EQ(1, type_switch->match(obj1)); 8234 CHECK_EQ(0, type_switch->match(obj0)); 8235 } 8236 } 8237 8238 8239 static int trouble_nesting = 0; 8240 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 8241 ApiTestFuzzer::Fuzz(); 8242 trouble_nesting++; 8243 8244 // Call a JS function that throws an uncaught exception. 8245 Local<v8::Object> arg_this = 8246 args.GetIsolate()->GetCurrentContext()->Global(); 8247 Local<Value> trouble_callee = (trouble_nesting == 3) ? 8248 arg_this->Get(v8_str("trouble_callee")) : 8249 arg_this->Get(v8_str("trouble_caller")); 8250 CHECK(trouble_callee->IsFunction()); 8251 args.GetReturnValue().Set( 8252 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL)); 8253 } 8254 8255 8256 static int report_count = 0; 8257 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>, 8258 v8::Handle<Value>) { 8259 report_count++; 8260 } 8261 8262 8263 // Counts uncaught exceptions, but other tests running in parallel 8264 // also have uncaught exceptions. 8265 TEST(ApiUncaughtException) { 8266 report_count = 0; 8267 LocalContext env; 8268 v8::Isolate* isolate = env->GetIsolate(); 8269 v8::HandleScope scope(isolate); 8270 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener); 8271 8272 Local<v8::FunctionTemplate> fun = 8273 v8::FunctionTemplate::New(isolate, TroubleCallback); 8274 v8::Local<v8::Object> global = env->Global(); 8275 global->Set(v8_str("trouble"), fun->GetFunction()); 8276 8277 CompileRun( 8278 "function trouble_callee() {" 8279 " var x = null;" 8280 " return x.foo;" 8281 "};" 8282 "function trouble_caller() {" 8283 " trouble();" 8284 "};"); 8285 Local<Value> trouble = global->Get(v8_str("trouble")); 8286 CHECK(trouble->IsFunction()); 8287 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee")); 8288 CHECK(trouble_callee->IsFunction()); 8289 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller")); 8290 CHECK(trouble_caller->IsFunction()); 8291 Function::Cast(*trouble_caller)->Call(global, 0, NULL); 8292 CHECK_EQ(1, report_count); 8293 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener); 8294 } 8295 8296 static const char* script_resource_name = "ExceptionInNativeScript.js"; 8297 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, 8298 v8::Handle<Value>) { 8299 v8::Handle<v8::Value> name_val = message->GetScriptResourceName(); 8300 CHECK(!name_val.IsEmpty() && name_val->IsString()); 8301 v8::String::Utf8Value name(message->GetScriptResourceName()); 8302 CHECK_EQ(script_resource_name, *name); 8303 CHECK_EQ(3, message->GetLineNumber()); 8304 v8::String::Utf8Value source_line(message->GetSourceLine()); 8305 CHECK_EQ(" new o.foo();", *source_line); 8306 } 8307 8308 8309 TEST(ExceptionInNativeScript) { 8310 LocalContext env; 8311 v8::Isolate* isolate = env->GetIsolate(); 8312 v8::HandleScope scope(isolate); 8313 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener); 8314 8315 Local<v8::FunctionTemplate> fun = 8316 v8::FunctionTemplate::New(isolate, TroubleCallback); 8317 v8::Local<v8::Object> global = env->Global(); 8318 global->Set(v8_str("trouble"), fun->GetFunction()); 8319 8320 CompileRunWithOrigin( 8321 "function trouble() {\n" 8322 " var o = {};\n" 8323 " new o.foo();\n" 8324 "};", 8325 script_resource_name); 8326 Local<Value> trouble = global->Get(v8_str("trouble")); 8327 CHECK(trouble->IsFunction()); 8328 Function::Cast(*trouble)->Call(global, 0, NULL); 8329 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener); 8330 } 8331 8332 8333 TEST(CompilationErrorUsingTryCatchHandler) { 8334 LocalContext env; 8335 v8::HandleScope scope(env->GetIsolate()); 8336 v8::TryCatch try_catch; 8337 v8_compile("This doesn't &*&@#$&*^ compile."); 8338 CHECK_NE(NULL, *try_catch.Exception()); 8339 CHECK(try_catch.HasCaught()); 8340 } 8341 8342 8343 TEST(TryCatchFinallyUsingTryCatchHandler) { 8344 LocalContext env; 8345 v8::HandleScope scope(env->GetIsolate()); 8346 v8::TryCatch try_catch; 8347 CompileRun("try { throw ''; } catch (e) {}"); 8348 CHECK(!try_catch.HasCaught()); 8349 CompileRun("try { throw ''; } finally {}"); 8350 CHECK(try_catch.HasCaught()); 8351 try_catch.Reset(); 8352 CompileRun( 8353 "(function() {" 8354 "try { throw ''; } finally { return; }" 8355 "})()"); 8356 CHECK(!try_catch.HasCaught()); 8357 CompileRun( 8358 "(function()" 8359 " { try { throw ''; } finally { throw 0; }" 8360 "})()"); 8361 CHECK(try_catch.HasCaught()); 8362 } 8363 8364 8365 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) { 8366 v8::HandleScope scope(args.GetIsolate()); 8367 CompileRun(args[0]->ToString()); 8368 } 8369 8370 8371 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { 8372 v8::Isolate* isolate = CcTest::isolate(); 8373 v8::HandleScope scope(isolate); 8374 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 8375 templ->Set(v8_str("CEvaluate"), 8376 v8::FunctionTemplate::New(isolate, CEvaluate)); 8377 LocalContext context(0, templ); 8378 v8::TryCatch try_catch; 8379 CompileRun("try {" 8380 " CEvaluate('throw 1;');" 8381 "} finally {" 8382 "}"); 8383 CHECK(try_catch.HasCaught()); 8384 CHECK(!try_catch.Message().IsEmpty()); 8385 String::Utf8Value exception_value(try_catch.Exception()); 8386 CHECK_EQ(*exception_value, "1"); 8387 try_catch.Reset(); 8388 CompileRun("try {" 8389 " CEvaluate('throw 1;');" 8390 "} finally {" 8391 " throw 2;" 8392 "}"); 8393 CHECK(try_catch.HasCaught()); 8394 CHECK(!try_catch.Message().IsEmpty()); 8395 String::Utf8Value finally_exception_value(try_catch.Exception()); 8396 CHECK_EQ(*finally_exception_value, "2"); 8397 } 8398 8399 8400 // For use within the TestSecurityHandler() test. 8401 static bool g_security_callback_result = false; 8402 static bool NamedSecurityTestCallback(Local<v8::Object> global, 8403 Local<Value> name, 8404 v8::AccessType type, 8405 Local<Value> data) { 8406 printf("a\n"); 8407 // Always allow read access. 8408 if (type == v8::ACCESS_GET) 8409 return true; 8410 8411 // Sometimes allow other access. 8412 return g_security_callback_result; 8413 } 8414 8415 8416 static bool IndexedSecurityTestCallback(Local<v8::Object> global, 8417 uint32_t key, 8418 v8::AccessType type, 8419 Local<Value> data) { 8420 printf("b\n"); 8421 // Always allow read access. 8422 if (type == v8::ACCESS_GET) 8423 return true; 8424 8425 // Sometimes allow other access. 8426 return g_security_callback_result; 8427 } 8428 8429 8430 // SecurityHandler can't be run twice 8431 TEST(SecurityHandler) { 8432 v8::Isolate* isolate = CcTest::isolate(); 8433 v8::HandleScope scope0(isolate); 8434 v8::Handle<v8::ObjectTemplate> global_template = 8435 v8::ObjectTemplate::New(isolate); 8436 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, 8437 IndexedSecurityTestCallback); 8438 // Create an environment 8439 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template); 8440 context0->Enter(); 8441 8442 v8::Handle<v8::Object> global0 = context0->Global(); 8443 v8::Handle<Script> script0 = v8_compile("foo = 111"); 8444 script0->Run(); 8445 global0->Set(v8_str("0"), v8_num(999)); 8446 v8::Handle<Value> foo0 = global0->Get(v8_str("foo")); 8447 CHECK_EQ(111, foo0->Int32Value()); 8448 v8::Handle<Value> z0 = global0->Get(v8_str("0")); 8449 CHECK_EQ(999, z0->Int32Value()); 8450 8451 // Create another environment, should fail security checks. 8452 v8::HandleScope scope1(isolate); 8453 8454 v8::Handle<Context> context1 = 8455 Context::New(isolate, NULL, global_template); 8456 context1->Enter(); 8457 8458 v8::Handle<v8::Object> global1 = context1->Global(); 8459 global1->Set(v8_str("othercontext"), global0); 8460 // This set will fail the security check. 8461 v8::Handle<Script> script1 = 8462 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 8463 script1->Run(); 8464 // This read will pass the security check. 8465 v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); 8466 CHECK_EQ(111, foo1->Int32Value()); 8467 // This read will pass the security check. 8468 v8::Handle<Value> z1 = global0->Get(v8_str("0")); 8469 CHECK_EQ(999, z1->Int32Value()); 8470 8471 // Create another environment, should pass security checks. 8472 { g_security_callback_result = true; // allow security handler to pass. 8473 v8::HandleScope scope2(isolate); 8474 LocalContext context2; 8475 v8::Handle<v8::Object> global2 = context2->Global(); 8476 global2->Set(v8_str("othercontext"), global0); 8477 v8::Handle<Script> script2 = 8478 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 8479 script2->Run(); 8480 v8::Handle<Value> foo2 = global0->Get(v8_str("foo")); 8481 CHECK_EQ(333, foo2->Int32Value()); 8482 v8::Handle<Value> z2 = global0->Get(v8_str("0")); 8483 CHECK_EQ(888, z2->Int32Value()); 8484 } 8485 8486 context1->Exit(); 8487 context0->Exit(); 8488 } 8489 8490 8491 THREADED_TEST(SecurityChecks) { 8492 LocalContext env1; 8493 v8::HandleScope handle_scope(env1->GetIsolate()); 8494 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8495 8496 Local<Value> foo = v8_str("foo"); 8497 Local<Value> bar = v8_str("bar"); 8498 8499 // Set to the same domain. 8500 env1->SetSecurityToken(foo); 8501 8502 // Create a function in env1. 8503 CompileRun("spy=function(){return spy;}"); 8504 Local<Value> spy = env1->Global()->Get(v8_str("spy")); 8505 CHECK(spy->IsFunction()); 8506 8507 // Create another function accessing global objects. 8508 CompileRun("spy2=function(){return new this.Array();}"); 8509 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2")); 8510 CHECK(spy2->IsFunction()); 8511 8512 // Switch to env2 in the same domain and invoke spy on env2. 8513 { 8514 env2->SetSecurityToken(foo); 8515 // Enter env2 8516 Context::Scope scope_env2(env2); 8517 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL); 8518 CHECK(result->IsFunction()); 8519 } 8520 8521 { 8522 env2->SetSecurityToken(bar); 8523 Context::Scope scope_env2(env2); 8524 8525 // Call cross_domain_call, it should throw an exception 8526 v8::TryCatch try_catch; 8527 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); 8528 CHECK(try_catch.HasCaught()); 8529 } 8530 } 8531 8532 8533 // Regression test case for issue 1183439. 8534 THREADED_TEST(SecurityChecksForPrototypeChain) { 8535 LocalContext current; 8536 v8::HandleScope scope(current->GetIsolate()); 8537 v8::Handle<Context> other = Context::New(current->GetIsolate()); 8538 8539 // Change context to be able to get to the Object function in the 8540 // other context without hitting the security checks. 8541 v8::Local<Value> other_object; 8542 { Context::Scope scope(other); 8543 other_object = other->Global()->Get(v8_str("Object")); 8544 other->Global()->Set(v8_num(42), v8_num(87)); 8545 } 8546 8547 current->Global()->Set(v8_str("other"), other->Global()); 8548 CHECK(v8_compile("other")->Run()->Equals(other->Global())); 8549 8550 // Make sure the security check fails here and we get an undefined 8551 // result instead of getting the Object function. Repeat in a loop 8552 // to make sure to exercise the IC code. 8553 v8::Local<Script> access_other0 = v8_compile("other.Object"); 8554 v8::Local<Script> access_other1 = v8_compile("other[42]"); 8555 for (int i = 0; i < 5; i++) { 8556 CHECK(!access_other0->Run()->Equals(other_object)); 8557 CHECK(access_other0->Run()->IsUndefined()); 8558 CHECK(!access_other1->Run()->Equals(v8_num(87))); 8559 CHECK(access_other1->Run()->IsUndefined()); 8560 } 8561 8562 // Create an object that has 'other' in its prototype chain and make 8563 // sure we cannot access the Object function indirectly through 8564 // that. Repeat in a loop to make sure to exercise the IC code. 8565 v8_compile("function F() { };" 8566 "F.prototype = other;" 8567 "var f = new F();")->Run(); 8568 v8::Local<Script> access_f0 = v8_compile("f.Object"); 8569 v8::Local<Script> access_f1 = v8_compile("f[42]"); 8570 for (int j = 0; j < 5; j++) { 8571 CHECK(!access_f0->Run()->Equals(other_object)); 8572 CHECK(access_f0->Run()->IsUndefined()); 8573 CHECK(!access_f1->Run()->Equals(v8_num(87))); 8574 CHECK(access_f1->Run()->IsUndefined()); 8575 } 8576 8577 // Now it gets hairy: Set the prototype for the other global object 8578 // to be the current global object. The prototype chain for 'f' now 8579 // goes through 'other' but ends up in the current global object. 8580 { Context::Scope scope(other); 8581 other->Global()->Set(v8_str("__proto__"), current->Global()); 8582 } 8583 // Set a named and an index property on the current global 8584 // object. To force the lookup to go through the other global object, 8585 // the properties must not exist in the other global object. 8586 current->Global()->Set(v8_str("foo"), v8_num(100)); 8587 current->Global()->Set(v8_num(99), v8_num(101)); 8588 // Try to read the properties from f and make sure that the access 8589 // gets stopped by the security checks on the other global object. 8590 Local<Script> access_f2 = v8_compile("f.foo"); 8591 Local<Script> access_f3 = v8_compile("f[99]"); 8592 for (int k = 0; k < 5; k++) { 8593 CHECK(!access_f2->Run()->Equals(v8_num(100))); 8594 CHECK(access_f2->Run()->IsUndefined()); 8595 CHECK(!access_f3->Run()->Equals(v8_num(101))); 8596 CHECK(access_f3->Run()->IsUndefined()); 8597 } 8598 } 8599 8600 8601 static bool named_security_check_with_gc_called; 8602 8603 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global, 8604 Local<Value> name, 8605 v8::AccessType type, 8606 Local<Value> data) { 8607 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 8608 named_security_check_with_gc_called = true; 8609 return true; 8610 } 8611 8612 8613 static bool indexed_security_check_with_gc_called; 8614 8615 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global, 8616 uint32_t key, 8617 v8::AccessType type, 8618 Local<Value> data) { 8619 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 8620 indexed_security_check_with_gc_called = true; 8621 return true; 8622 } 8623 8624 8625 TEST(SecurityTestGCAllowed) { 8626 v8::Isolate* isolate = CcTest::isolate(); 8627 v8::HandleScope handle_scope(isolate); 8628 v8::Handle<v8::ObjectTemplate> object_template = 8629 v8::ObjectTemplate::New(isolate); 8630 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC, 8631 IndexedSecurityTestCallbackWithGC); 8632 8633 v8::Handle<Context> context = Context::New(isolate); 8634 v8::Context::Scope context_scope(context); 8635 8636 context->Global()->Set(v8_str("obj"), object_template->NewInstance()); 8637 8638 named_security_check_with_gc_called = false; 8639 CompileRun("obj.foo = new String(1001);"); 8640 CHECK(named_security_check_with_gc_called); 8641 8642 indexed_security_check_with_gc_called = false; 8643 CompileRun("obj[0] = new String(1002);"); 8644 CHECK(indexed_security_check_with_gc_called); 8645 8646 named_security_check_with_gc_called = false; 8647 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001"))); 8648 CHECK(named_security_check_with_gc_called); 8649 8650 indexed_security_check_with_gc_called = false; 8651 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002"))); 8652 CHECK(indexed_security_check_with_gc_called); 8653 } 8654 8655 8656 THREADED_TEST(CrossDomainDelete) { 8657 LocalContext env1; 8658 v8::HandleScope handle_scope(env1->GetIsolate()); 8659 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8660 8661 Local<Value> foo = v8_str("foo"); 8662 Local<Value> bar = v8_str("bar"); 8663 8664 // Set to the same domain. 8665 env1->SetSecurityToken(foo); 8666 env2->SetSecurityToken(foo); 8667 8668 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8669 env2->Global()->Set(v8_str("env1"), env1->Global()); 8670 8671 // Change env2 to a different domain and delete env1.prop. 8672 env2->SetSecurityToken(bar); 8673 { 8674 Context::Scope scope_env2(env2); 8675 Local<Value> result = 8676 CompileRun("delete env1.prop"); 8677 CHECK(result->IsFalse()); 8678 } 8679 8680 // Check that env1.prop still exists. 8681 Local<Value> v = env1->Global()->Get(v8_str("prop")); 8682 CHECK(v->IsNumber()); 8683 CHECK_EQ(3, v->Int32Value()); 8684 } 8685 8686 8687 THREADED_TEST(CrossDomainIsPropertyEnumerable) { 8688 LocalContext env1; 8689 v8::HandleScope handle_scope(env1->GetIsolate()); 8690 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8691 8692 Local<Value> foo = v8_str("foo"); 8693 Local<Value> bar = v8_str("bar"); 8694 8695 // Set to the same domain. 8696 env1->SetSecurityToken(foo); 8697 env2->SetSecurityToken(foo); 8698 8699 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8700 env2->Global()->Set(v8_str("env1"), env1->Global()); 8701 8702 // env1.prop is enumerable in env2. 8703 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 8704 { 8705 Context::Scope scope_env2(env2); 8706 Local<Value> result = CompileRun(test); 8707 CHECK(result->IsTrue()); 8708 } 8709 8710 // Change env2 to a different domain and test again. 8711 env2->SetSecurityToken(bar); 8712 { 8713 Context::Scope scope_env2(env2); 8714 Local<Value> result = CompileRun(test); 8715 CHECK(result->IsFalse()); 8716 } 8717 } 8718 8719 8720 THREADED_TEST(CrossDomainForIn) { 8721 LocalContext env1; 8722 v8::HandleScope handle_scope(env1->GetIsolate()); 8723 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8724 8725 Local<Value> foo = v8_str("foo"); 8726 Local<Value> bar = v8_str("bar"); 8727 8728 // Set to the same domain. 8729 env1->SetSecurityToken(foo); 8730 env2->SetSecurityToken(foo); 8731 8732 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8733 env2->Global()->Set(v8_str("env1"), env1->Global()); 8734 8735 // Change env2 to a different domain and set env1's global object 8736 // as the __proto__ of an object in env2 and enumerate properties 8737 // in for-in. It shouldn't enumerate properties on env1's global 8738 // object. 8739 env2->SetSecurityToken(bar); 8740 { 8741 Context::Scope scope_env2(env2); 8742 Local<Value> result = 8743 CompileRun("(function(){var obj = {'__proto__':env1};" 8744 "for (var p in obj)" 8745 " if (p == 'prop') return false;" 8746 "return true;})()"); 8747 CHECK(result->IsTrue()); 8748 } 8749 } 8750 8751 8752 TEST(ContextDetachGlobal) { 8753 LocalContext env1; 8754 v8::HandleScope handle_scope(env1->GetIsolate()); 8755 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8756 8757 Local<v8::Object> global1 = env1->Global(); 8758 8759 Local<Value> foo = v8_str("foo"); 8760 8761 // Set to the same domain. 8762 env1->SetSecurityToken(foo); 8763 env2->SetSecurityToken(foo); 8764 8765 // Enter env2 8766 env2->Enter(); 8767 8768 // Create a function in env2 and add a reference to it in env1. 8769 Local<v8::Object> global2 = env2->Global(); 8770 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1)); 8771 CompileRun("function getProp() {return prop;}"); 8772 8773 env1->Global()->Set(v8_str("getProp"), 8774 global2->Get(v8_str("getProp"))); 8775 8776 // Detach env2's global, and reuse the global object of env2 8777 env2->Exit(); 8778 env2->DetachGlobal(); 8779 8780 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8781 0, 8782 v8::Handle<v8::ObjectTemplate>(), 8783 global2); 8784 env3->SetSecurityToken(v8_str("bar")); 8785 env3->Enter(); 8786 8787 Local<v8::Object> global3 = env3->Global(); 8788 CHECK_EQ(global2, global3); 8789 CHECK(global3->Get(v8_str("prop"))->IsUndefined()); 8790 CHECK(global3->Get(v8_str("getProp"))->IsUndefined()); 8791 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1)); 8792 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2)); 8793 env3->Exit(); 8794 8795 // Call getProp in env1, and it should return the value 1 8796 { 8797 Local<Value> get_prop = global1->Get(v8_str("getProp")); 8798 CHECK(get_prop->IsFunction()); 8799 v8::TryCatch try_catch; 8800 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); 8801 CHECK(!try_catch.HasCaught()); 8802 CHECK_EQ(1, r->Int32Value()); 8803 } 8804 8805 // Check that env3 is not accessible from env1 8806 { 8807 Local<Value> r = global3->Get(v8_str("prop2")); 8808 CHECK(r->IsUndefined()); 8809 } 8810 } 8811 8812 8813 TEST(DetachGlobal) { 8814 LocalContext env1; 8815 v8::HandleScope scope(env1->GetIsolate()); 8816 8817 // Create second environment. 8818 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8819 8820 Local<Value> foo = v8_str("foo"); 8821 8822 // Set same security token for env1 and env2. 8823 env1->SetSecurityToken(foo); 8824 env2->SetSecurityToken(foo); 8825 8826 // Create a property on the global object in env2. 8827 { 8828 v8::Context::Scope scope(env2); 8829 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42)); 8830 } 8831 8832 // Create a reference to env2 global from env1 global. 8833 env1->Global()->Set(v8_str("other"), env2->Global()); 8834 8835 // Check that we have access to other.p in env2 from env1. 8836 Local<Value> result = CompileRun("other.p"); 8837 CHECK(result->IsInt32()); 8838 CHECK_EQ(42, result->Int32Value()); 8839 8840 // Hold on to global from env2 and detach global from env2. 8841 Local<v8::Object> global2 = env2->Global(); 8842 env2->DetachGlobal(); 8843 8844 // Check that the global has been detached. No other.p property can 8845 // be found. 8846 result = CompileRun("other.p"); 8847 CHECK(result->IsUndefined()); 8848 8849 // Reuse global2 for env3. 8850 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8851 0, 8852 v8::Handle<v8::ObjectTemplate>(), 8853 global2); 8854 CHECK_EQ(global2, env3->Global()); 8855 8856 // Start by using the same security token for env3 as for env1 and env2. 8857 env3->SetSecurityToken(foo); 8858 8859 // Create a property on the global object in env3. 8860 { 8861 v8::Context::Scope scope(env3); 8862 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24)); 8863 } 8864 8865 // Check that other.p is now the property in env3 and that we have access. 8866 result = CompileRun("other.p"); 8867 CHECK(result->IsInt32()); 8868 CHECK_EQ(24, result->Int32Value()); 8869 8870 // Change security token for env3 to something different from env1 and env2. 8871 env3->SetSecurityToken(v8_str("bar")); 8872 8873 // Check that we do not have access to other.p in env1. |other| is now 8874 // the global object for env3 which has a different security token, 8875 // so access should be blocked. 8876 result = CompileRun("other.p"); 8877 CHECK(result->IsUndefined()); 8878 } 8879 8880 8881 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) { 8882 info.GetReturnValue().Set( 8883 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x"))); 8884 } 8885 8886 8887 TEST(DetachedAccesses) { 8888 LocalContext env1; 8889 v8::HandleScope scope(env1->GetIsolate()); 8890 8891 // Create second environment. 8892 Local<ObjectTemplate> inner_global_template = 8893 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate(); 8894 inner_global_template ->SetAccessorProperty( 8895 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX)); 8896 v8::Local<Context> env2 = 8897 Context::New(env1->GetIsolate(), NULL, inner_global_template); 8898 8899 Local<Value> foo = v8_str("foo"); 8900 8901 // Set same security token for env1 and env2. 8902 env1->SetSecurityToken(foo); 8903 env2->SetSecurityToken(foo); 8904 8905 env1->Global()->Set(v8_str("x"), v8_str("env1_x")); 8906 8907 { 8908 v8::Context::Scope scope(env2); 8909 env2->Global()->Set(v8_str("x"), v8_str("env2_x")); 8910 CompileRun( 8911 "function bound_x() { return x; }" 8912 "function get_x() { return this.x; }" 8913 "function get_x_w() { return (function() {return this.x;})(); }"); 8914 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x")); 8915 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x")); 8916 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w")); 8917 env1->Global()->Set( 8918 v8_str("this_x"), 8919 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get")); 8920 } 8921 8922 Local<Object> env2_global = env2->Global(); 8923 env2_global->TurnOnAccessCheck(); 8924 env2->DetachGlobal(); 8925 8926 Local<Value> result; 8927 result = CompileRun("bound_x()"); 8928 CHECK_EQ(v8_str("env2_x"), result); 8929 result = CompileRun("get_x()"); 8930 CHECK(result->IsUndefined()); 8931 result = CompileRun("get_x_w()"); 8932 CHECK(result->IsUndefined()); 8933 result = CompileRun("this_x()"); 8934 CHECK_EQ(v8_str("env2_x"), result); 8935 8936 // Reattach env2's proxy 8937 env2 = Context::New(env1->GetIsolate(), 8938 0, 8939 v8::Handle<v8::ObjectTemplate>(), 8940 env2_global); 8941 env2->SetSecurityToken(foo); 8942 { 8943 v8::Context::Scope scope(env2); 8944 env2->Global()->Set(v8_str("x"), v8_str("env3_x")); 8945 env2->Global()->Set(v8_str("env1"), env1->Global()); 8946 result = CompileRun( 8947 "results = [];" 8948 "for (var i = 0; i < 4; i++ ) {" 8949 " results.push(env1.bound_x());" 8950 " results.push(env1.get_x());" 8951 " results.push(env1.get_x_w());" 8952 " results.push(env1.this_x());" 8953 "}" 8954 "results"); 8955 Local<v8::Array> results = Local<v8::Array>::Cast(result); 8956 CHECK_EQ(16, results->Length()); 8957 for (int i = 0; i < 16; i += 4) { 8958 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 8959 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1)); 8960 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 8961 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 8962 } 8963 } 8964 8965 result = CompileRun( 8966 "results = [];" 8967 "for (var i = 0; i < 4; i++ ) {" 8968 " results.push(bound_x());" 8969 " results.push(get_x());" 8970 " results.push(get_x_w());" 8971 " results.push(this_x());" 8972 "}" 8973 "results"); 8974 Local<v8::Array> results = Local<v8::Array>::Cast(result); 8975 CHECK_EQ(16, results->Length()); 8976 for (int i = 0; i < 16; i += 4) { 8977 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 8978 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1)); 8979 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 8980 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 8981 } 8982 8983 result = CompileRun( 8984 "results = [];" 8985 "for (var i = 0; i < 4; i++ ) {" 8986 " results.push(this.bound_x());" 8987 " results.push(this.get_x());" 8988 " results.push(this.get_x_w());" 8989 " results.push(this.this_x());" 8990 "}" 8991 "results"); 8992 results = Local<v8::Array>::Cast(result); 8993 CHECK_EQ(16, results->Length()); 8994 for (int i = 0; i < 16; i += 4) { 8995 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 8996 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1)); 8997 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 8998 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 8999 } 9000 } 9001 9002 9003 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; 9004 static bool NamedAccessBlocker(Local<v8::Object> global, 9005 Local<Value> name, 9006 v8::AccessType type, 9007 Local<Value> data) { 9008 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 9009 allowed_access_type[type]; 9010 } 9011 9012 9013 static bool IndexedAccessBlocker(Local<v8::Object> global, 9014 uint32_t key, 9015 v8::AccessType type, 9016 Local<Value> data) { 9017 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 9018 allowed_access_type[type]; 9019 } 9020 9021 9022 static int g_echo_value_1 = -1; 9023 static int g_echo_value_2 = -1; 9024 9025 9026 static void EchoGetter( 9027 Local<String> name, 9028 const v8::PropertyCallbackInfo<v8::Value>& info) { 9029 info.GetReturnValue().Set(v8_num(g_echo_value_1)); 9030 } 9031 9032 9033 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 9034 info.GetReturnValue().Set(v8_num(g_echo_value_2)); 9035 } 9036 9037 9038 static void EchoSetter(Local<String> name, 9039 Local<Value> value, 9040 const v8::PropertyCallbackInfo<void>&) { 9041 if (value->IsNumber()) 9042 g_echo_value_1 = value->Int32Value(); 9043 } 9044 9045 9046 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 9047 v8::Handle<v8::Value> value = info[0]; 9048 if (value->IsNumber()) 9049 g_echo_value_2 = value->Int32Value(); 9050 } 9051 9052 9053 static void UnreachableGetter( 9054 Local<String> name, 9055 const v8::PropertyCallbackInfo<v8::Value>& info) { 9056 CHECK(false); // This function should not be called.. 9057 } 9058 9059 9060 static void UnreachableSetter(Local<String>, 9061 Local<Value>, 9062 const v8::PropertyCallbackInfo<void>&) { 9063 CHECK(false); // This function should nto be called. 9064 } 9065 9066 9067 static void UnreachableFunction( 9068 const v8::FunctionCallbackInfo<v8::Value>& info) { 9069 CHECK(false); // This function should not be called.. 9070 } 9071 9072 9073 TEST(AccessControl) { 9074 v8::Isolate* isolate = CcTest::isolate(); 9075 v8::HandleScope handle_scope(isolate); 9076 v8::Handle<v8::ObjectTemplate> global_template = 9077 v8::ObjectTemplate::New(isolate); 9078 9079 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 9080 IndexedAccessBlocker); 9081 9082 // Add an accessor accessible by cross-domain JS code. 9083 global_template->SetAccessor( 9084 v8_str("accessible_prop"), 9085 EchoGetter, EchoSetter, 9086 v8::Handle<Value>(), 9087 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9088 9089 9090 global_template->SetAccessorProperty( 9091 v8_str("accessible_js_prop"), 9092 v8::FunctionTemplate::New(isolate, EchoGetter), 9093 v8::FunctionTemplate::New(isolate, EchoSetter), 9094 v8::None, 9095 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9096 9097 // Add an accessor that is not accessible by cross-domain JS code. 9098 global_template->SetAccessor(v8_str("blocked_prop"), 9099 UnreachableGetter, UnreachableSetter, 9100 v8::Handle<Value>(), 9101 v8::DEFAULT); 9102 9103 global_template->SetAccessorProperty( 9104 v8_str("blocked_js_prop"), 9105 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9106 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9107 v8::None, 9108 v8::DEFAULT); 9109 9110 // Create an environment 9111 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9112 context0->Enter(); 9113 9114 v8::Handle<v8::Object> global0 = context0->Global(); 9115 9116 // Define a property with JS getter and setter. 9117 CompileRun( 9118 "function getter() { return 'getter'; };\n" 9119 "function setter() { return 'setter'; }\n" 9120 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 9121 9122 Local<Value> getter = global0->Get(v8_str("getter")); 9123 Local<Value> setter = global0->Get(v8_str("setter")); 9124 9125 // And define normal element. 9126 global0->Set(239, v8_str("239")); 9127 9128 // Define an element with JS getter and setter. 9129 CompileRun( 9130 "function el_getter() { return 'el_getter'; };\n" 9131 "function el_setter() { return 'el_setter'; };\n" 9132 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 9133 9134 Local<Value> el_getter = global0->Get(v8_str("el_getter")); 9135 Local<Value> el_setter = global0->Get(v8_str("el_setter")); 9136 9137 v8::HandleScope scope1(isolate); 9138 9139 v8::Local<Context> context1 = Context::New(isolate); 9140 context1->Enter(); 9141 9142 v8::Handle<v8::Object> global1 = context1->Global(); 9143 global1->Set(v8_str("other"), global0); 9144 9145 // Access blocked property. 9146 CompileRun("other.blocked_prop = 1"); 9147 9148 ExpectUndefined("other.blocked_prop"); 9149 ExpectUndefined( 9150 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 9151 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')"); 9152 9153 // Enable ACCESS_HAS 9154 allowed_access_type[v8::ACCESS_HAS] = true; 9155 ExpectUndefined("other.blocked_prop"); 9156 // ... and now we can get the descriptor... 9157 ExpectUndefined( 9158 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value"); 9159 // ... and enumerate the property. 9160 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')"); 9161 allowed_access_type[v8::ACCESS_HAS] = false; 9162 9163 // Access blocked element. 9164 CompileRun("other[239] = 1"); 9165 9166 ExpectUndefined("other[239]"); 9167 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')"); 9168 ExpectFalse("propertyIsEnumerable.call(other, '239')"); 9169 9170 // Enable ACCESS_HAS 9171 allowed_access_type[v8::ACCESS_HAS] = true; 9172 ExpectUndefined("other[239]"); 9173 // ... and now we can get the descriptor... 9174 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value"); 9175 // ... and enumerate the property. 9176 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 9177 allowed_access_type[v8::ACCESS_HAS] = false; 9178 9179 // Access a property with JS accessor. 9180 CompileRun("other.js_accessor_p = 2"); 9181 9182 ExpectUndefined("other.js_accessor_p"); 9183 ExpectUndefined( 9184 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')"); 9185 9186 // Enable ACCESS_HAS. 9187 allowed_access_type[v8::ACCESS_HAS] = true; 9188 ExpectUndefined("other.js_accessor_p"); 9189 ExpectUndefined( 9190 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 9191 ExpectUndefined( 9192 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 9193 ExpectUndefined( 9194 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9195 allowed_access_type[v8::ACCESS_HAS] = false; 9196 9197 // Enable both ACCESS_HAS and ACCESS_GET. 9198 allowed_access_type[v8::ACCESS_HAS] = true; 9199 allowed_access_type[v8::ACCESS_GET] = true; 9200 9201 ExpectString("other.js_accessor_p", "getter"); 9202 ExpectObject( 9203 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 9204 ExpectUndefined( 9205 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 9206 ExpectUndefined( 9207 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9208 9209 allowed_access_type[v8::ACCESS_GET] = false; 9210 allowed_access_type[v8::ACCESS_HAS] = false; 9211 9212 // Enable both ACCESS_HAS and ACCESS_SET. 9213 allowed_access_type[v8::ACCESS_HAS] = true; 9214 allowed_access_type[v8::ACCESS_SET] = true; 9215 9216 ExpectUndefined("other.js_accessor_p"); 9217 ExpectUndefined( 9218 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 9219 ExpectObject( 9220 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 9221 ExpectUndefined( 9222 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9223 9224 allowed_access_type[v8::ACCESS_SET] = false; 9225 allowed_access_type[v8::ACCESS_HAS] = false; 9226 9227 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 9228 allowed_access_type[v8::ACCESS_HAS] = true; 9229 allowed_access_type[v8::ACCESS_GET] = true; 9230 allowed_access_type[v8::ACCESS_SET] = true; 9231 9232 ExpectString("other.js_accessor_p", "getter"); 9233 ExpectObject( 9234 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 9235 ExpectObject( 9236 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 9237 ExpectUndefined( 9238 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9239 9240 allowed_access_type[v8::ACCESS_SET] = false; 9241 allowed_access_type[v8::ACCESS_GET] = false; 9242 allowed_access_type[v8::ACCESS_HAS] = false; 9243 9244 // Access an element with JS accessor. 9245 CompileRun("other[42] = 2"); 9246 9247 ExpectUndefined("other[42]"); 9248 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')"); 9249 9250 // Enable ACCESS_HAS. 9251 allowed_access_type[v8::ACCESS_HAS] = true; 9252 ExpectUndefined("other[42]"); 9253 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 9254 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 9255 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9256 allowed_access_type[v8::ACCESS_HAS] = false; 9257 9258 // Enable both ACCESS_HAS and ACCESS_GET. 9259 allowed_access_type[v8::ACCESS_HAS] = true; 9260 allowed_access_type[v8::ACCESS_GET] = true; 9261 9262 ExpectString("other[42]", "el_getter"); 9263 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 9264 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 9265 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9266 9267 allowed_access_type[v8::ACCESS_GET] = false; 9268 allowed_access_type[v8::ACCESS_HAS] = false; 9269 9270 // Enable both ACCESS_HAS and ACCESS_SET. 9271 allowed_access_type[v8::ACCESS_HAS] = true; 9272 allowed_access_type[v8::ACCESS_SET] = true; 9273 9274 ExpectUndefined("other[42]"); 9275 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 9276 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 9277 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9278 9279 allowed_access_type[v8::ACCESS_SET] = false; 9280 allowed_access_type[v8::ACCESS_HAS] = false; 9281 9282 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 9283 allowed_access_type[v8::ACCESS_HAS] = true; 9284 allowed_access_type[v8::ACCESS_GET] = true; 9285 allowed_access_type[v8::ACCESS_SET] = true; 9286 9287 ExpectString("other[42]", "el_getter"); 9288 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 9289 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 9290 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9291 9292 allowed_access_type[v8::ACCESS_SET] = false; 9293 allowed_access_type[v8::ACCESS_GET] = false; 9294 allowed_access_type[v8::ACCESS_HAS] = false; 9295 9296 v8::Handle<Value> value; 9297 9298 // Access accessible property 9299 value = CompileRun("other.accessible_prop = 3"); 9300 CHECK(value->IsNumber()); 9301 CHECK_EQ(3, value->Int32Value()); 9302 CHECK_EQ(3, g_echo_value_1); 9303 9304 // Access accessible js property 9305 value = CompileRun("other.accessible_js_prop = 3"); 9306 CHECK(value->IsNumber()); 9307 CHECK_EQ(3, value->Int32Value()); 9308 CHECK_EQ(3, g_echo_value_2); 9309 9310 value = CompileRun("other.accessible_prop"); 9311 CHECK(value->IsNumber()); 9312 CHECK_EQ(3, value->Int32Value()); 9313 9314 value = CompileRun("other.accessible_js_prop"); 9315 CHECK(value->IsNumber()); 9316 CHECK_EQ(3, value->Int32Value()); 9317 9318 value = CompileRun( 9319 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 9320 CHECK(value->IsNumber()); 9321 CHECK_EQ(3, value->Int32Value()); 9322 9323 value = CompileRun( 9324 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()"); 9325 CHECK(value->IsNumber()); 9326 CHECK_EQ(3, value->Int32Value()); 9327 9328 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 9329 CHECK(value->IsTrue()); 9330 9331 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')"); 9332 CHECK(value->IsTrue()); 9333 9334 // Enumeration doesn't enumerate accessors from inaccessible objects in 9335 // the prototype chain even if the accessors are in themselves accessible. 9336 value = 9337 CompileRun("(function(){var obj = {'__proto__':other};" 9338 "for (var p in obj)" 9339 " if (p == 'accessible_prop' ||" 9340 " p == 'accessible_js_prop' ||" 9341 " p == 'blocked_js_prop' ||" 9342 " p == 'blocked_js_prop') {" 9343 " return false;" 9344 " }" 9345 "return true;})()"); 9346 CHECK(value->IsTrue()); 9347 9348 context1->Exit(); 9349 context0->Exit(); 9350 } 9351 9352 9353 TEST(AccessControlES5) { 9354 v8::Isolate* isolate = CcTest::isolate(); 9355 v8::HandleScope handle_scope(isolate); 9356 v8::Handle<v8::ObjectTemplate> global_template = 9357 v8::ObjectTemplate::New(isolate); 9358 9359 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 9360 IndexedAccessBlocker); 9361 9362 // Add accessible accessor. 9363 global_template->SetAccessor( 9364 v8_str("accessible_prop"), 9365 EchoGetter, EchoSetter, 9366 v8::Handle<Value>(), 9367 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9368 9369 9370 // Add an accessor that is not accessible by cross-domain JS code. 9371 global_template->SetAccessor(v8_str("blocked_prop"), 9372 UnreachableGetter, UnreachableSetter, 9373 v8::Handle<Value>(), 9374 v8::DEFAULT); 9375 9376 // Create an environment 9377 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9378 context0->Enter(); 9379 9380 v8::Handle<v8::Object> global0 = context0->Global(); 9381 9382 v8::Local<Context> context1 = Context::New(isolate); 9383 context1->Enter(); 9384 v8::Handle<v8::Object> global1 = context1->Global(); 9385 global1->Set(v8_str("other"), global0); 9386 9387 // Regression test for issue 1154. 9388 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1"); 9389 9390 ExpectUndefined("other.blocked_prop"); 9391 9392 // Regression test for issue 1027. 9393 CompileRun("Object.defineProperty(\n" 9394 " other, 'blocked_prop', {configurable: false})"); 9395 ExpectUndefined("other.blocked_prop"); 9396 ExpectUndefined( 9397 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 9398 9399 // Regression test for issue 1171. 9400 ExpectTrue("Object.isExtensible(other)"); 9401 CompileRun("Object.preventExtensions(other)"); 9402 ExpectTrue("Object.isExtensible(other)"); 9403 9404 // Object.seal and Object.freeze. 9405 CompileRun("Object.freeze(other)"); 9406 ExpectTrue("Object.isExtensible(other)"); 9407 9408 CompileRun("Object.seal(other)"); 9409 ExpectTrue("Object.isExtensible(other)"); 9410 9411 // Regression test for issue 1250. 9412 // Make sure that we can set the accessible accessors value using normal 9413 // assignment. 9414 CompileRun("other.accessible_prop = 42"); 9415 CHECK_EQ(42, g_echo_value_1); 9416 9417 v8::Handle<Value> value; 9418 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); 9419 value = CompileRun("other.accessible_prop == 42"); 9420 CHECK(value->IsTrue()); 9421 } 9422 9423 9424 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global, 9425 Local<Value> name, 9426 v8::AccessType type, 9427 Local<Value> data) { 9428 return false; 9429 } 9430 9431 9432 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global, 9433 uint32_t key, 9434 v8::AccessType type, 9435 Local<Value> data) { 9436 return false; 9437 } 9438 9439 9440 THREADED_TEST(AccessControlGetOwnPropertyNames) { 9441 v8::Isolate* isolate = CcTest::isolate(); 9442 v8::HandleScope handle_scope(isolate); 9443 v8::Handle<v8::ObjectTemplate> obj_template = 9444 v8::ObjectTemplate::New(isolate); 9445 9446 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 9447 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker, 9448 GetOwnPropertyNamesIndexedBlocker); 9449 9450 // Create an environment 9451 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 9452 context0->Enter(); 9453 9454 v8::Handle<v8::Object> global0 = context0->Global(); 9455 9456 v8::HandleScope scope1(CcTest::isolate()); 9457 9458 v8::Local<Context> context1 = Context::New(isolate); 9459 context1->Enter(); 9460 9461 v8::Handle<v8::Object> global1 = context1->Global(); 9462 global1->Set(v8_str("other"), global0); 9463 global1->Set(v8_str("object"), obj_template->NewInstance()); 9464 9465 v8::Handle<Value> value; 9466 9467 // Attempt to get the property names of the other global object and 9468 // of an object that requires access checks. Accessing the other 9469 // global object should be blocked by access checks on the global 9470 // proxy object. Accessing the object that requires access checks 9471 // is blocked by the access checks on the object itself. 9472 value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); 9473 CHECK(value->IsTrue()); 9474 9475 value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); 9476 CHECK(value->IsTrue()); 9477 9478 context1->Exit(); 9479 context0->Exit(); 9480 } 9481 9482 9483 static void IndexedPropertyEnumerator( 9484 const v8::PropertyCallbackInfo<v8::Array>& info) { 9485 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9486 result->Set(0, v8::Integer::New(info.GetIsolate(), 7)); 9487 result->Set(1, v8::Object::New(info.GetIsolate())); 9488 info.GetReturnValue().Set(result); 9489 } 9490 9491 9492 static void NamedPropertyEnumerator( 9493 const v8::PropertyCallbackInfo<v8::Array>& info) { 9494 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9495 result->Set(0, v8_str("x")); 9496 result->Set(1, v8::Object::New(info.GetIsolate())); 9497 info.GetReturnValue().Set(result); 9498 } 9499 9500 9501 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { 9502 v8::Isolate* isolate = CcTest::isolate(); 9503 v8::HandleScope handle_scope(isolate); 9504 v8::Handle<v8::ObjectTemplate> obj_template = 9505 v8::ObjectTemplate::New(isolate); 9506 9507 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7)); 9508 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42)); 9509 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, 9510 IndexedPropertyEnumerator); 9511 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL, 9512 NamedPropertyEnumerator); 9513 9514 LocalContext context; 9515 v8::Handle<v8::Object> global = context->Global(); 9516 global->Set(v8_str("object"), obj_template->NewInstance()); 9517 9518 v8::Handle<v8::Value> result = 9519 CompileRun("Object.getOwnPropertyNames(object)"); 9520 CHECK(result->IsArray()); 9521 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result); 9522 CHECK_EQ(3, result_array->Length()); 9523 CHECK(result_array->Get(0)->IsString()); 9524 CHECK(result_array->Get(1)->IsString()); 9525 CHECK(result_array->Get(2)->IsString()); 9526 CHECK_EQ(v8_str("7"), result_array->Get(0)); 9527 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1)); 9528 CHECK_EQ(v8_str("x"), result_array->Get(2)); 9529 } 9530 9531 9532 static void ConstTenGetter(Local<String> name, 9533 const v8::PropertyCallbackInfo<v8::Value>& info) { 9534 info.GetReturnValue().Set(v8_num(10)); 9535 } 9536 9537 9538 THREADED_TEST(CrossDomainAccessors) { 9539 v8::Isolate* isolate = CcTest::isolate(); 9540 v8::HandleScope handle_scope(isolate); 9541 9542 v8::Handle<v8::FunctionTemplate> func_template = 9543 v8::FunctionTemplate::New(isolate); 9544 9545 v8::Handle<v8::ObjectTemplate> global_template = 9546 func_template->InstanceTemplate(); 9547 9548 v8::Handle<v8::ObjectTemplate> proto_template = 9549 func_template->PrototypeTemplate(); 9550 9551 // Add an accessor to proto that's accessible by cross-domain JS code. 9552 proto_template->SetAccessor(v8_str("accessible"), 9553 ConstTenGetter, 0, 9554 v8::Handle<Value>(), 9555 v8::ALL_CAN_READ); 9556 9557 // Add an accessor that is not accessible by cross-domain JS code. 9558 global_template->SetAccessor(v8_str("unreachable"), 9559 UnreachableGetter, 0, 9560 v8::Handle<Value>(), 9561 v8::DEFAULT); 9562 9563 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9564 context0->Enter(); 9565 9566 Local<v8::Object> global = context0->Global(); 9567 // Add a normal property that shadows 'accessible' 9568 global->Set(v8_str("accessible"), v8_num(11)); 9569 9570 // Enter a new context. 9571 v8::HandleScope scope1(CcTest::isolate()); 9572 v8::Local<Context> context1 = Context::New(isolate); 9573 context1->Enter(); 9574 9575 v8::Handle<v8::Object> global1 = context1->Global(); 9576 global1->Set(v8_str("other"), global); 9577 9578 // Should return 10, instead of 11 9579 v8::Handle<Value> value = v8_compile("other.accessible")->Run(); 9580 CHECK(value->IsNumber()); 9581 CHECK_EQ(10, value->Int32Value()); 9582 9583 value = v8_compile("other.unreachable")->Run(); 9584 CHECK(value->IsUndefined()); 9585 9586 context1->Exit(); 9587 context0->Exit(); 9588 } 9589 9590 9591 static int named_access_count = 0; 9592 static int indexed_access_count = 0; 9593 9594 static bool NamedAccessCounter(Local<v8::Object> global, 9595 Local<Value> name, 9596 v8::AccessType type, 9597 Local<Value> data) { 9598 named_access_count++; 9599 return true; 9600 } 9601 9602 9603 static bool IndexedAccessCounter(Local<v8::Object> global, 9604 uint32_t key, 9605 v8::AccessType type, 9606 Local<Value> data) { 9607 indexed_access_count++; 9608 return true; 9609 } 9610 9611 9612 // This one is too easily disturbed by other tests. 9613 TEST(AccessControlIC) { 9614 named_access_count = 0; 9615 indexed_access_count = 0; 9616 9617 v8::Isolate* isolate = CcTest::isolate(); 9618 v8::HandleScope handle_scope(isolate); 9619 9620 // Create an environment. 9621 v8::Local<Context> context0 = Context::New(isolate); 9622 context0->Enter(); 9623 9624 // Create an object that requires access-check functions to be 9625 // called for cross-domain access. 9626 v8::Handle<v8::ObjectTemplate> object_template = 9627 v8::ObjectTemplate::New(isolate); 9628 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9629 IndexedAccessCounter); 9630 Local<v8::Object> object = object_template->NewInstance(); 9631 9632 v8::HandleScope scope1(isolate); 9633 9634 // Create another environment. 9635 v8::Local<Context> context1 = Context::New(isolate); 9636 context1->Enter(); 9637 9638 // Make easy access to the object from the other environment. 9639 v8::Handle<v8::Object> global1 = context1->Global(); 9640 global1->Set(v8_str("obj"), object); 9641 9642 v8::Handle<Value> value; 9643 9644 // Check that the named access-control function is called every time. 9645 CompileRun("function testProp(obj) {" 9646 " for (var i = 0; i < 10; i++) obj.prop = 1;" 9647 " for (var j = 0; j < 10; j++) obj.prop;" 9648 " return obj.prop" 9649 "}"); 9650 value = CompileRun("testProp(obj)"); 9651 CHECK(value->IsNumber()); 9652 CHECK_EQ(1, value->Int32Value()); 9653 CHECK_EQ(21, named_access_count); 9654 9655 // Check that the named access-control function is called every time. 9656 CompileRun("var p = 'prop';" 9657 "function testKeyed(obj) {" 9658 " for (var i = 0; i < 10; i++) obj[p] = 1;" 9659 " for (var j = 0; j < 10; j++) obj[p];" 9660 " return obj[p];" 9661 "}"); 9662 // Use obj which requires access checks. No inline caching is used 9663 // in that case. 9664 value = CompileRun("testKeyed(obj)"); 9665 CHECK(value->IsNumber()); 9666 CHECK_EQ(1, value->Int32Value()); 9667 CHECK_EQ(42, named_access_count); 9668 // Force the inline caches into generic state and try again. 9669 CompileRun("testKeyed({ a: 0 })"); 9670 CompileRun("testKeyed({ b: 0 })"); 9671 value = CompileRun("testKeyed(obj)"); 9672 CHECK(value->IsNumber()); 9673 CHECK_EQ(1, value->Int32Value()); 9674 CHECK_EQ(63, named_access_count); 9675 9676 // Check that the indexed access-control function is called every time. 9677 CompileRun("function testIndexed(obj) {" 9678 " for (var i = 0; i < 10; i++) obj[0] = 1;" 9679 " for (var j = 0; j < 10; j++) obj[0];" 9680 " return obj[0]" 9681 "}"); 9682 value = CompileRun("testIndexed(obj)"); 9683 CHECK(value->IsNumber()); 9684 CHECK_EQ(1, value->Int32Value()); 9685 CHECK_EQ(21, indexed_access_count); 9686 // Force the inline caches into generic state. 9687 CompileRun("testIndexed(new Array(1))"); 9688 // Test that the indexed access check is called. 9689 value = CompileRun("testIndexed(obj)"); 9690 CHECK(value->IsNumber()); 9691 CHECK_EQ(1, value->Int32Value()); 9692 CHECK_EQ(42, indexed_access_count); 9693 9694 // Check that the named access check is called when invoking 9695 // functions on an object that requires access checks. 9696 CompileRun("obj.f = function() {}"); 9697 CompileRun("function testCallNormal(obj) {" 9698 " for (var i = 0; i < 10; i++) obj.f();" 9699 "}"); 9700 CompileRun("testCallNormal(obj)"); 9701 CHECK_EQ(74, named_access_count); 9702 9703 // Force obj into slow case. 9704 value = CompileRun("delete obj.prop"); 9705 CHECK(value->BooleanValue()); 9706 // Force inline caches into dictionary probing mode. 9707 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 9708 // Test that the named access check is called. 9709 value = CompileRun("testProp(obj);"); 9710 CHECK(value->IsNumber()); 9711 CHECK_EQ(1, value->Int32Value()); 9712 CHECK_EQ(96, named_access_count); 9713 9714 // Force the call inline cache into dictionary probing mode. 9715 CompileRun("o.f = function() {}; testCallNormal(o)"); 9716 // Test that the named access check is still called for each 9717 // invocation of the function. 9718 value = CompileRun("testCallNormal(obj)"); 9719 CHECK_EQ(106, named_access_count); 9720 9721 context1->Exit(); 9722 context0->Exit(); 9723 } 9724 9725 9726 static bool NamedAccessFlatten(Local<v8::Object> global, 9727 Local<Value> name, 9728 v8::AccessType type, 9729 Local<Value> data) { 9730 char buf[100]; 9731 int len; 9732 9733 CHECK(name->IsString()); 9734 9735 memset(buf, 0x1, sizeof(buf)); 9736 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 9737 CHECK_EQ(4, len); 9738 9739 uint16_t buf2[100]; 9740 9741 memset(buf, 0x1, sizeof(buf)); 9742 len = name.As<String>()->Write(buf2); 9743 CHECK_EQ(4, len); 9744 9745 return true; 9746 } 9747 9748 9749 static bool IndexedAccessFlatten(Local<v8::Object> global, 9750 uint32_t key, 9751 v8::AccessType type, 9752 Local<Value> data) { 9753 return true; 9754 } 9755 9756 9757 // Regression test. In access checks, operations that may cause 9758 // garbage collection are not allowed. It used to be the case that 9759 // using the Write operation on a string could cause a garbage 9760 // collection due to flattening of the string. This is no longer the 9761 // case. 9762 THREADED_TEST(AccessControlFlatten) { 9763 named_access_count = 0; 9764 indexed_access_count = 0; 9765 9766 v8::Isolate* isolate = CcTest::isolate(); 9767 v8::HandleScope handle_scope(isolate); 9768 9769 // Create an environment. 9770 v8::Local<Context> context0 = Context::New(isolate); 9771 context0->Enter(); 9772 9773 // Create an object that requires access-check functions to be 9774 // called for cross-domain access. 9775 v8::Handle<v8::ObjectTemplate> object_template = 9776 v8::ObjectTemplate::New(isolate); 9777 object_template->SetAccessCheckCallbacks(NamedAccessFlatten, 9778 IndexedAccessFlatten); 9779 Local<v8::Object> object = object_template->NewInstance(); 9780 9781 v8::HandleScope scope1(isolate); 9782 9783 // Create another environment. 9784 v8::Local<Context> context1 = Context::New(isolate); 9785 context1->Enter(); 9786 9787 // Make easy access to the object from the other environment. 9788 v8::Handle<v8::Object> global1 = context1->Global(); 9789 global1->Set(v8_str("obj"), object); 9790 9791 v8::Handle<Value> value; 9792 9793 value = v8_compile("var p = 'as' + 'df';")->Run(); 9794 value = v8_compile("obj[p];")->Run(); 9795 9796 context1->Exit(); 9797 context0->Exit(); 9798 } 9799 9800 9801 static void AccessControlNamedGetter( 9802 Local<String>, 9803 const v8::PropertyCallbackInfo<v8::Value>& info) { 9804 info.GetReturnValue().Set(42); 9805 } 9806 9807 9808 static void AccessControlNamedSetter( 9809 Local<String>, 9810 Local<Value> value, 9811 const v8::PropertyCallbackInfo<v8::Value>& info) { 9812 info.GetReturnValue().Set(value); 9813 } 9814 9815 9816 static void AccessControlIndexedGetter( 9817 uint32_t index, 9818 const v8::PropertyCallbackInfo<v8::Value>& info) { 9819 info.GetReturnValue().Set(v8_num(42)); 9820 } 9821 9822 9823 static void AccessControlIndexedSetter( 9824 uint32_t, 9825 Local<Value> value, 9826 const v8::PropertyCallbackInfo<v8::Value>& info) { 9827 info.GetReturnValue().Set(value); 9828 } 9829 9830 9831 THREADED_TEST(AccessControlInterceptorIC) { 9832 named_access_count = 0; 9833 indexed_access_count = 0; 9834 9835 v8::Isolate* isolate = CcTest::isolate(); 9836 v8::HandleScope handle_scope(isolate); 9837 9838 // Create an environment. 9839 v8::Local<Context> context0 = Context::New(isolate); 9840 context0->Enter(); 9841 9842 // Create an object that requires access-check functions to be 9843 // called for cross-domain access. The object also has interceptors 9844 // interceptor. 9845 v8::Handle<v8::ObjectTemplate> object_template = 9846 v8::ObjectTemplate::New(isolate); 9847 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9848 IndexedAccessCounter); 9849 object_template->SetNamedPropertyHandler(AccessControlNamedGetter, 9850 AccessControlNamedSetter); 9851 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter, 9852 AccessControlIndexedSetter); 9853 Local<v8::Object> object = object_template->NewInstance(); 9854 9855 v8::HandleScope scope1(isolate); 9856 9857 // Create another environment. 9858 v8::Local<Context> context1 = Context::New(isolate); 9859 context1->Enter(); 9860 9861 // Make easy access to the object from the other environment. 9862 v8::Handle<v8::Object> global1 = context1->Global(); 9863 global1->Set(v8_str("obj"), object); 9864 9865 v8::Handle<Value> value; 9866 9867 // Check that the named access-control function is called every time 9868 // eventhough there is an interceptor on the object. 9869 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run(); 9870 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;" 9871 "obj.x")->Run(); 9872 CHECK(value->IsNumber()); 9873 CHECK_EQ(42, value->Int32Value()); 9874 CHECK_EQ(21, named_access_count); 9875 9876 value = v8_compile("var p = 'x';")->Run(); 9877 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run(); 9878 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];" 9879 "obj[p]")->Run(); 9880 CHECK(value->IsNumber()); 9881 CHECK_EQ(42, value->Int32Value()); 9882 CHECK_EQ(42, named_access_count); 9883 9884 // Check that the indexed access-control function is called every 9885 // time eventhough there is an interceptor on the object. 9886 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run(); 9887 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];" 9888 "obj[0]")->Run(); 9889 CHECK(value->IsNumber()); 9890 CHECK_EQ(42, value->Int32Value()); 9891 CHECK_EQ(21, indexed_access_count); 9892 9893 context1->Exit(); 9894 context0->Exit(); 9895 } 9896 9897 9898 THREADED_TEST(Version) { 9899 v8::V8::GetVersion(); 9900 } 9901 9902 9903 static void InstanceFunctionCallback( 9904 const v8::FunctionCallbackInfo<v8::Value>& args) { 9905 ApiTestFuzzer::Fuzz(); 9906 args.GetReturnValue().Set(v8_num(12)); 9907 } 9908 9909 9910 THREADED_TEST(InstanceProperties) { 9911 LocalContext context; 9912 v8::Isolate* isolate = context->GetIsolate(); 9913 v8::HandleScope handle_scope(isolate); 9914 9915 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 9916 Local<ObjectTemplate> instance = t->InstanceTemplate(); 9917 9918 instance->Set(v8_str("x"), v8_num(42)); 9919 instance->Set(v8_str("f"), 9920 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback)); 9921 9922 Local<Value> o = t->GetFunction()->NewInstance(); 9923 9924 context->Global()->Set(v8_str("i"), o); 9925 Local<Value> value = CompileRun("i.x"); 9926 CHECK_EQ(42, value->Int32Value()); 9927 9928 value = CompileRun("i.f()"); 9929 CHECK_EQ(12, value->Int32Value()); 9930 } 9931 9932 9933 static void GlobalObjectInstancePropertiesGet( 9934 Local<String> key, 9935 const v8::PropertyCallbackInfo<v8::Value>&) { 9936 ApiTestFuzzer::Fuzz(); 9937 } 9938 9939 9940 THREADED_TEST(GlobalObjectInstanceProperties) { 9941 v8::Isolate* isolate = CcTest::isolate(); 9942 v8::HandleScope handle_scope(isolate); 9943 9944 Local<Value> global_object; 9945 9946 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 9947 t->InstanceTemplate()->SetNamedPropertyHandler( 9948 GlobalObjectInstancePropertiesGet); 9949 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9950 instance_template->Set(v8_str("x"), v8_num(42)); 9951 instance_template->Set(v8_str("f"), 9952 v8::FunctionTemplate::New(isolate, 9953 InstanceFunctionCallback)); 9954 9955 // The script to check how Crankshaft compiles missing global function 9956 // invocations. function g is not defined and should throw on call. 9957 const char* script = 9958 "function wrapper(call) {" 9959 " var x = 0, y = 1;" 9960 " for (var i = 0; i < 1000; i++) {" 9961 " x += i * 100;" 9962 " y += i * 100;" 9963 " }" 9964 " if (call) g();" 9965 "}" 9966 "for (var i = 0; i < 17; i++) wrapper(false);" 9967 "var thrown = 0;" 9968 "try { wrapper(true); } catch (e) { thrown = 1; };" 9969 "thrown"; 9970 9971 { 9972 LocalContext env(NULL, instance_template); 9973 // Hold on to the global object so it can be used again in another 9974 // environment initialization. 9975 global_object = env->Global(); 9976 9977 Local<Value> value = CompileRun("x"); 9978 CHECK_EQ(42, value->Int32Value()); 9979 value = CompileRun("f()"); 9980 CHECK_EQ(12, value->Int32Value()); 9981 value = CompileRun(script); 9982 CHECK_EQ(1, value->Int32Value()); 9983 } 9984 9985 { 9986 // Create new environment reusing the global object. 9987 LocalContext env(NULL, instance_template, global_object); 9988 Local<Value> value = CompileRun("x"); 9989 CHECK_EQ(42, value->Int32Value()); 9990 value = CompileRun("f()"); 9991 CHECK_EQ(12, value->Int32Value()); 9992 value = CompileRun(script); 9993 CHECK_EQ(1, value->Int32Value()); 9994 } 9995 } 9996 9997 9998 THREADED_TEST(CallKnownGlobalReceiver) { 9999 v8::Isolate* isolate = CcTest::isolate(); 10000 v8::HandleScope handle_scope(isolate); 10001 10002 Local<Value> global_object; 10003 10004 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10005 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10006 10007 // The script to check that we leave global object not 10008 // global object proxy on stack when we deoptimize from inside 10009 // arguments evaluation. 10010 // To provoke error we need to both force deoptimization 10011 // from arguments evaluation and to force CallIC to take 10012 // CallIC_Miss code path that can't cope with global proxy. 10013 const char* script = 10014 "function bar(x, y) { try { } finally { } }" 10015 "function baz(x) { try { } finally { } }" 10016 "function bom(x) { try { } finally { } }" 10017 "function foo(x) { bar([x], bom(2)); }" 10018 "for (var i = 0; i < 10000; i++) foo(1);" 10019 "foo"; 10020 10021 Local<Value> foo; 10022 { 10023 LocalContext env(NULL, instance_template); 10024 // Hold on to the global object so it can be used again in another 10025 // environment initialization. 10026 global_object = env->Global(); 10027 foo = CompileRun(script); 10028 } 10029 10030 { 10031 // Create new environment reusing the global object. 10032 LocalContext env(NULL, instance_template, global_object); 10033 env->Global()->Set(v8_str("foo"), foo); 10034 CompileRun("foo()"); 10035 } 10036 } 10037 10038 10039 static void ShadowFunctionCallback( 10040 const v8::FunctionCallbackInfo<v8::Value>& args) { 10041 ApiTestFuzzer::Fuzz(); 10042 args.GetReturnValue().Set(v8_num(42)); 10043 } 10044 10045 10046 static int shadow_y; 10047 static int shadow_y_setter_call_count; 10048 static int shadow_y_getter_call_count; 10049 10050 10051 static void ShadowYSetter(Local<String>, 10052 Local<Value>, 10053 const v8::PropertyCallbackInfo<void>&) { 10054 shadow_y_setter_call_count++; 10055 shadow_y = 42; 10056 } 10057 10058 10059 static void ShadowYGetter(Local<String> name, 10060 const v8::PropertyCallbackInfo<v8::Value>& info) { 10061 ApiTestFuzzer::Fuzz(); 10062 shadow_y_getter_call_count++; 10063 info.GetReturnValue().Set(v8_num(shadow_y)); 10064 } 10065 10066 10067 static void ShadowIndexedGet(uint32_t index, 10068 const v8::PropertyCallbackInfo<v8::Value>&) { 10069 } 10070 10071 10072 static void ShadowNamedGet(Local<String> key, 10073 const v8::PropertyCallbackInfo<v8::Value>&) { 10074 } 10075 10076 10077 THREADED_TEST(ShadowObject) { 10078 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 10079 v8::Isolate* isolate = CcTest::isolate(); 10080 v8::HandleScope handle_scope(isolate); 10081 10082 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 10083 LocalContext context(NULL, global_template); 10084 10085 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10086 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet); 10087 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet); 10088 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 10089 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10090 10091 proto->Set(v8_str("f"), 10092 v8::FunctionTemplate::New(isolate, 10093 ShadowFunctionCallback, 10094 Local<Value>())); 10095 proto->Set(v8_str("x"), v8_num(12)); 10096 10097 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 10098 10099 Local<Value> o = t->GetFunction()->NewInstance(); 10100 context->Global()->Set(v8_str("__proto__"), o); 10101 10102 Local<Value> value = 10103 CompileRun("this.propertyIsEnumerable(0)"); 10104 CHECK(value->IsBoolean()); 10105 CHECK(!value->BooleanValue()); 10106 10107 value = CompileRun("x"); 10108 CHECK_EQ(12, value->Int32Value()); 10109 10110 value = CompileRun("f()"); 10111 CHECK_EQ(42, value->Int32Value()); 10112 10113 CompileRun("y = 43"); 10114 CHECK_EQ(1, shadow_y_setter_call_count); 10115 value = CompileRun("y"); 10116 CHECK_EQ(1, shadow_y_getter_call_count); 10117 CHECK_EQ(42, value->Int32Value()); 10118 } 10119 10120 10121 THREADED_TEST(HiddenPrototype) { 10122 LocalContext context; 10123 v8::Isolate* isolate = context->GetIsolate(); 10124 v8::HandleScope handle_scope(isolate); 10125 10126 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10127 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10128 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10129 t1->SetHiddenPrototype(true); 10130 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10131 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10132 t2->SetHiddenPrototype(true); 10133 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10134 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10135 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10136 10137 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 10138 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10139 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10140 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10141 10142 // Setting the prototype on an object skips hidden prototypes. 10143 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10144 o0->Set(v8_str("__proto__"), o1); 10145 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10146 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10147 o0->Set(v8_str("__proto__"), o2); 10148 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10149 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10150 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10151 o0->Set(v8_str("__proto__"), o3); 10152 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10153 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10154 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10155 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 10156 10157 // Getting the prototype of o0 should get the first visible one 10158 // which is o3. Therefore, z should not be defined on the prototype 10159 // object. 10160 Local<Value> proto = o0->Get(v8_str("__proto__")); 10161 CHECK(proto->IsObject()); 10162 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined()); 10163 } 10164 10165 10166 THREADED_TEST(HiddenPrototypeSet) { 10167 LocalContext context; 10168 v8::Isolate* isolate = context->GetIsolate(); 10169 v8::HandleScope handle_scope(isolate); 10170 10171 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate); 10172 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate); 10173 ht->SetHiddenPrototype(true); 10174 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate); 10175 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10176 10177 Local<v8::Object> o = ot->GetFunction()->NewInstance(); 10178 Local<v8::Object> h = ht->GetFunction()->NewInstance(); 10179 Local<v8::Object> p = pt->GetFunction()->NewInstance(); 10180 o->Set(v8_str("__proto__"), h); 10181 h->Set(v8_str("__proto__"), p); 10182 10183 // Setting a property that exists on the hidden prototype goes there. 10184 o->Set(v8_str("x"), v8_num(7)); 10185 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value()); 10186 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value()); 10187 CHECK(p->Get(v8_str("x"))->IsUndefined()); 10188 10189 // Setting a new property should not be forwarded to the hidden prototype. 10190 o->Set(v8_str("y"), v8_num(6)); 10191 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value()); 10192 CHECK(h->Get(v8_str("y"))->IsUndefined()); 10193 CHECK(p->Get(v8_str("y"))->IsUndefined()); 10194 10195 // Setting a property that only exists on a prototype of the hidden prototype 10196 // is treated normally again. 10197 p->Set(v8_str("z"), v8_num(8)); 10198 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value()); 10199 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 10200 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 10201 o->Set(v8_str("z"), v8_num(9)); 10202 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value()); 10203 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 10204 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 10205 } 10206 10207 10208 // Regression test for issue 2457. 10209 THREADED_TEST(HiddenPrototypeIdentityHash) { 10210 LocalContext context; 10211 v8::HandleScope handle_scope(context->GetIsolate()); 10212 10213 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate()); 10214 t->SetHiddenPrototype(true); 10215 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 10216 Handle<Object> p = t->GetFunction()->NewInstance(); 10217 Handle<Object> o = Object::New(context->GetIsolate()); 10218 o->SetPrototype(p); 10219 10220 int hash = o->GetIdentityHash(); 10221 USE(hash); 10222 o->Set(v8_str("foo"), v8_num(42)); 10223 ASSERT_EQ(hash, o->GetIdentityHash()); 10224 } 10225 10226 10227 THREADED_TEST(SetPrototype) { 10228 LocalContext context; 10229 v8::Isolate* isolate = context->GetIsolate(); 10230 v8::HandleScope handle_scope(isolate); 10231 10232 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10233 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10234 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10235 t1->SetHiddenPrototype(true); 10236 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10237 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10238 t2->SetHiddenPrototype(true); 10239 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10240 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10241 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10242 10243 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 10244 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10245 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10246 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10247 10248 // Setting the prototype on an object does not skip hidden prototypes. 10249 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10250 CHECK(o0->SetPrototype(o1)); 10251 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10252 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10253 CHECK(o1->SetPrototype(o2)); 10254 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10255 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10256 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10257 CHECK(o2->SetPrototype(o3)); 10258 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10259 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10260 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10261 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 10262 10263 // Getting the prototype of o0 should get the first visible one 10264 // which is o3. Therefore, z should not be defined on the prototype 10265 // object. 10266 Local<Value> proto = o0->Get(v8_str("__proto__")); 10267 CHECK(proto->IsObject()); 10268 CHECK_EQ(proto.As<v8::Object>(), o3); 10269 10270 // However, Object::GetPrototype ignores hidden prototype. 10271 Local<Value> proto0 = o0->GetPrototype(); 10272 CHECK(proto0->IsObject()); 10273 CHECK_EQ(proto0.As<v8::Object>(), o1); 10274 10275 Local<Value> proto1 = o1->GetPrototype(); 10276 CHECK(proto1->IsObject()); 10277 CHECK_EQ(proto1.As<v8::Object>(), o2); 10278 10279 Local<Value> proto2 = o2->GetPrototype(); 10280 CHECK(proto2->IsObject()); 10281 CHECK_EQ(proto2.As<v8::Object>(), o3); 10282 } 10283 10284 10285 // Getting property names of an object with a prototype chain that 10286 // triggers dictionary elements in GetOwnPropertyNames() shouldn't 10287 // crash the runtime. 10288 THREADED_TEST(Regress91517) { 10289 i::FLAG_allow_natives_syntax = true; 10290 LocalContext context; 10291 v8::Isolate* isolate = context->GetIsolate(); 10292 v8::HandleScope handle_scope(isolate); 10293 10294 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10295 t1->SetHiddenPrototype(true); 10296 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 10297 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10298 t2->SetHiddenPrototype(true); 10299 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 10300 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate)); 10301 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 10302 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10303 t3->SetHiddenPrototype(true); 10304 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 10305 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate); 10306 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 10307 10308 // Force dictionary-based properties. 10309 i::ScopedVector<char> name_buf(1024); 10310 for (int i = 1; i <= 1000; i++) { 10311 i::SNPrintF(name_buf, "sdf%d", i); 10312 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 10313 } 10314 10315 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10316 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10317 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10318 Local<v8::Object> o4 = t4->GetFunction()->NewInstance(); 10319 10320 // Create prototype chain of hidden prototypes. 10321 CHECK(o4->SetPrototype(o3)); 10322 CHECK(o3->SetPrototype(o2)); 10323 CHECK(o2->SetPrototype(o1)); 10324 10325 // Call the runtime version of GetOwnPropertyNames() on the natively 10326 // created object through JavaScript. 10327 context->Global()->Set(v8_str("obj"), o4); 10328 // PROPERTY_ATTRIBUTES_NONE = 0 10329 CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); 10330 10331 ExpectInt32("names.length", 1006); 10332 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10333 ExpectTrue("names.indexOf(\"boo\") >= 0"); 10334 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10335 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 10336 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 10337 ExpectFalse("names[1005] == undefined"); 10338 } 10339 10340 10341 // Getting property names of an object with a hidden and inherited 10342 // prototype should not duplicate the accessor properties inherited. 10343 THREADED_TEST(Regress269562) { 10344 i::FLAG_allow_natives_syntax = true; 10345 LocalContext context; 10346 v8::HandleScope handle_scope(context->GetIsolate()); 10347 10348 Local<v8::FunctionTemplate> t1 = 10349 v8::FunctionTemplate::New(context->GetIsolate()); 10350 t1->SetHiddenPrototype(true); 10351 10352 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate(); 10353 i1->SetAccessor(v8_str("foo"), 10354 SimpleAccessorGetter, SimpleAccessorSetter); 10355 i1->SetAccessor(v8_str("bar"), 10356 SimpleAccessorGetter, SimpleAccessorSetter); 10357 i1->SetAccessor(v8_str("baz"), 10358 SimpleAccessorGetter, SimpleAccessorSetter); 10359 i1->Set(v8_str("n1"), v8_num(1)); 10360 i1->Set(v8_str("n2"), v8_num(2)); 10361 10362 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10363 Local<v8::FunctionTemplate> t2 = 10364 v8::FunctionTemplate::New(context->GetIsolate()); 10365 t2->SetHiddenPrototype(true); 10366 10367 // Inherit from t1 and mark prototype as hidden. 10368 t2->Inherit(t1); 10369 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4)); 10370 10371 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10372 CHECK(o2->SetPrototype(o1)); 10373 10374 v8::Local<v8::Symbol> sym = 10375 v8::Symbol::New(context->GetIsolate(), v8_str("s1")); 10376 o1->Set(sym, v8_num(3)); 10377 o1->SetHiddenValue( 10378 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013)); 10379 10380 // Call the runtime version of GetOwnPropertyNames() on 10381 // the natively created object through JavaScript. 10382 context->Global()->Set(v8_str("obj"), o2); 10383 context->Global()->Set(v8_str("sym"), sym); 10384 // PROPERTY_ATTRIBUTES_NONE = 0 10385 CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); 10386 10387 ExpectInt32("names.length", 7); 10388 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10389 ExpectTrue("names.indexOf(\"bar\") >= 0"); 10390 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10391 ExpectTrue("names.indexOf(\"n1\") >= 0"); 10392 ExpectTrue("names.indexOf(\"n2\") >= 0"); 10393 ExpectTrue("names.indexOf(sym) >= 0"); 10394 ExpectTrue("names.indexOf(\"mine\") >= 0"); 10395 } 10396 10397 10398 THREADED_TEST(FunctionReadOnlyPrototype) { 10399 LocalContext context; 10400 v8::Isolate* isolate = context->GetIsolate(); 10401 v8::HandleScope handle_scope(isolate); 10402 10403 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10404 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10405 t1->ReadOnlyPrototype(); 10406 context->Global()->Set(v8_str("func1"), t1->GetFunction()); 10407 // Configured value of ReadOnly flag. 10408 CHECK(CompileRun( 10409 "(function() {" 10410 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 10411 " return (descriptor['writable'] == false);" 10412 "})()")->BooleanValue()); 10413 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value()); 10414 CHECK_EQ(42, 10415 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value()); 10416 10417 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10418 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10419 context->Global()->Set(v8_str("func2"), t2->GetFunction()); 10420 // Default value of ReadOnly flag. 10421 CHECK(CompileRun( 10422 "(function() {" 10423 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 10424 " return (descriptor['writable'] == true);" 10425 "})()")->BooleanValue()); 10426 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value()); 10427 } 10428 10429 10430 THREADED_TEST(SetPrototypeThrows) { 10431 LocalContext context; 10432 v8::Isolate* isolate = context->GetIsolate(); 10433 v8::HandleScope handle_scope(isolate); 10434 10435 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10436 10437 Local<v8::Object> o0 = t->GetFunction()->NewInstance(); 10438 Local<v8::Object> o1 = t->GetFunction()->NewInstance(); 10439 10440 CHECK(o0->SetPrototype(o1)); 10441 // If setting the prototype leads to the cycle, SetPrototype should 10442 // return false and keep VM in sane state. 10443 v8::TryCatch try_catch; 10444 CHECK(!o1->SetPrototype(o0)); 10445 CHECK(!try_catch.HasCaught()); 10446 ASSERT(!CcTest::i_isolate()->has_pending_exception()); 10447 10448 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); 10449 } 10450 10451 10452 THREADED_TEST(FunctionRemovePrototype) { 10453 LocalContext context; 10454 v8::Isolate* isolate = context->GetIsolate(); 10455 v8::HandleScope handle_scope(isolate); 10456 10457 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10458 t1->RemovePrototype(); 10459 Local<v8::Function> fun = t1->GetFunction(); 10460 context->Global()->Set(v8_str("fun"), fun); 10461 CHECK(!CompileRun("'prototype' in fun")->BooleanValue()); 10462 10463 v8::TryCatch try_catch; 10464 CompileRun("new fun()"); 10465 CHECK(try_catch.HasCaught()); 10466 10467 try_catch.Reset(); 10468 fun->NewInstance(); 10469 CHECK(try_catch.HasCaught()); 10470 } 10471 10472 10473 THREADED_TEST(GetterSetterExceptions) { 10474 LocalContext context; 10475 v8::Isolate* isolate = context->GetIsolate(); 10476 v8::HandleScope handle_scope(isolate); 10477 CompileRun( 10478 "function Foo() { };" 10479 "function Throw() { throw 5; };" 10480 "var x = { };" 10481 "x.__defineSetter__('set', Throw);" 10482 "x.__defineGetter__('get', Throw);"); 10483 Local<v8::Object> x = 10484 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); 10485 v8::TryCatch try_catch; 10486 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10487 x->Get(v8_str("get")); 10488 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10489 x->Get(v8_str("get")); 10490 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10491 x->Get(v8_str("get")); 10492 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10493 x->Get(v8_str("get")); 10494 } 10495 10496 10497 THREADED_TEST(Constructor) { 10498 LocalContext context; 10499 v8::Isolate* isolate = context->GetIsolate(); 10500 v8::HandleScope handle_scope(isolate); 10501 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 10502 templ->SetClassName(v8_str("Fun")); 10503 Local<Function> cons = templ->GetFunction(); 10504 context->Global()->Set(v8_str("Fun"), cons); 10505 Local<v8::Object> inst = cons->NewInstance(); 10506 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst)); 10507 CHECK(obj->IsJSObject()); 10508 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 10509 CHECK(value->BooleanValue()); 10510 } 10511 10512 10513 static void ConstructorCallback( 10514 const v8::FunctionCallbackInfo<v8::Value>& args) { 10515 ApiTestFuzzer::Fuzz(); 10516 Local<Object> This; 10517 10518 if (args.IsConstructCall()) { 10519 Local<Object> Holder = args.Holder(); 10520 This = Object::New(args.GetIsolate()); 10521 Local<Value> proto = Holder->GetPrototype(); 10522 if (proto->IsObject()) { 10523 This->SetPrototype(proto); 10524 } 10525 } else { 10526 This = args.This(); 10527 } 10528 10529 This->Set(v8_str("a"), args[0]); 10530 args.GetReturnValue().Set(This); 10531 } 10532 10533 10534 static void FakeConstructorCallback( 10535 const v8::FunctionCallbackInfo<v8::Value>& args) { 10536 ApiTestFuzzer::Fuzz(); 10537 args.GetReturnValue().Set(args[0]); 10538 } 10539 10540 10541 THREADED_TEST(ConstructorForObject) { 10542 LocalContext context; 10543 v8::Isolate* isolate = context->GetIsolate(); 10544 v8::HandleScope handle_scope(isolate); 10545 10546 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10547 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 10548 Local<Object> instance = instance_template->NewInstance(); 10549 context->Global()->Set(v8_str("obj"), instance); 10550 v8::TryCatch try_catch; 10551 Local<Value> value; 10552 CHECK(!try_catch.HasCaught()); 10553 10554 // Call the Object's constructor with a 32-bit signed integer. 10555 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 10556 CHECK(!try_catch.HasCaught()); 10557 CHECK(value->IsInt32()); 10558 CHECK_EQ(28, value->Int32Value()); 10559 10560 Local<Value> args1[] = { v8_num(28) }; 10561 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); 10562 CHECK(value_obj1->IsObject()); 10563 Local<Object> object1 = Local<Object>::Cast(value_obj1); 10564 value = object1->Get(v8_str("a")); 10565 CHECK(value->IsInt32()); 10566 CHECK(!try_catch.HasCaught()); 10567 CHECK_EQ(28, value->Int32Value()); 10568 10569 // Call the Object's constructor with a String. 10570 value = CompileRun( 10571 "(function() { var o = new obj('tipli'); return o.a; })()"); 10572 CHECK(!try_catch.HasCaught()); 10573 CHECK(value->IsString()); 10574 String::Utf8Value string_value1(value->ToString()); 10575 CHECK_EQ("tipli", *string_value1); 10576 10577 Local<Value> args2[] = { v8_str("tipli") }; 10578 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); 10579 CHECK(value_obj2->IsObject()); 10580 Local<Object> object2 = Local<Object>::Cast(value_obj2); 10581 value = object2->Get(v8_str("a")); 10582 CHECK(!try_catch.HasCaught()); 10583 CHECK(value->IsString()); 10584 String::Utf8Value string_value2(value->ToString()); 10585 CHECK_EQ("tipli", *string_value2); 10586 10587 // Call the Object's constructor with a Boolean. 10588 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 10589 CHECK(!try_catch.HasCaught()); 10590 CHECK(value->IsBoolean()); 10591 CHECK_EQ(true, value->BooleanValue()); 10592 10593 Handle<Value> args3[] = { v8::True(isolate) }; 10594 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); 10595 CHECK(value_obj3->IsObject()); 10596 Local<Object> object3 = Local<Object>::Cast(value_obj3); 10597 value = object3->Get(v8_str("a")); 10598 CHECK(!try_catch.HasCaught()); 10599 CHECK(value->IsBoolean()); 10600 CHECK_EQ(true, value->BooleanValue()); 10601 10602 // Call the Object's constructor with undefined. 10603 Handle<Value> args4[] = { v8::Undefined(isolate) }; 10604 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); 10605 CHECK(value_obj4->IsObject()); 10606 Local<Object> object4 = Local<Object>::Cast(value_obj4); 10607 value = object4->Get(v8_str("a")); 10608 CHECK(!try_catch.HasCaught()); 10609 CHECK(value->IsUndefined()); 10610 10611 // Call the Object's constructor with null. 10612 Handle<Value> args5[] = { v8::Null(isolate) }; 10613 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); 10614 CHECK(value_obj5->IsObject()); 10615 Local<Object> object5 = Local<Object>::Cast(value_obj5); 10616 value = object5->Get(v8_str("a")); 10617 CHECK(!try_catch.HasCaught()); 10618 CHECK(value->IsNull()); 10619 } 10620 10621 // Check exception handling when there is no constructor set for the Object. 10622 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10623 Local<Object> instance = instance_template->NewInstance(); 10624 context->Global()->Set(v8_str("obj2"), instance); 10625 v8::TryCatch try_catch; 10626 Local<Value> value; 10627 CHECK(!try_catch.HasCaught()); 10628 10629 value = CompileRun("new obj2(28)"); 10630 CHECK(try_catch.HasCaught()); 10631 String::Utf8Value exception_value1(try_catch.Exception()); 10632 CHECK_EQ("TypeError: object is not a function", *exception_value1); 10633 try_catch.Reset(); 10634 10635 Local<Value> args[] = { v8_num(29) }; 10636 value = instance->CallAsConstructor(1, args); 10637 CHECK(try_catch.HasCaught()); 10638 String::Utf8Value exception_value2(try_catch.Exception()); 10639 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); 10640 try_catch.Reset(); 10641 } 10642 10643 // Check the case when constructor throws exception. 10644 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10645 instance_template->SetCallAsFunctionHandler(ThrowValue); 10646 Local<Object> instance = instance_template->NewInstance(); 10647 context->Global()->Set(v8_str("obj3"), instance); 10648 v8::TryCatch try_catch; 10649 Local<Value> value; 10650 CHECK(!try_catch.HasCaught()); 10651 10652 value = CompileRun("new obj3(22)"); 10653 CHECK(try_catch.HasCaught()); 10654 String::Utf8Value exception_value1(try_catch.Exception()); 10655 CHECK_EQ("22", *exception_value1); 10656 try_catch.Reset(); 10657 10658 Local<Value> args[] = { v8_num(23) }; 10659 value = instance->CallAsConstructor(1, args); 10660 CHECK(try_catch.HasCaught()); 10661 String::Utf8Value exception_value2(try_catch.Exception()); 10662 CHECK_EQ("23", *exception_value2); 10663 try_catch.Reset(); 10664 } 10665 10666 // Check whether constructor returns with an object or non-object. 10667 { Local<FunctionTemplate> function_template = 10668 FunctionTemplate::New(isolate, FakeConstructorCallback); 10669 Local<Function> function = function_template->GetFunction(); 10670 Local<Object> instance1 = function; 10671 context->Global()->Set(v8_str("obj4"), instance1); 10672 v8::TryCatch try_catch; 10673 Local<Value> value; 10674 CHECK(!try_catch.HasCaught()); 10675 10676 CHECK(instance1->IsObject()); 10677 CHECK(instance1->IsFunction()); 10678 10679 value = CompileRun("new obj4(28)"); 10680 CHECK(!try_catch.HasCaught()); 10681 CHECK(value->IsObject()); 10682 10683 Local<Value> args1[] = { v8_num(28) }; 10684 value = instance1->CallAsConstructor(1, args1); 10685 CHECK(!try_catch.HasCaught()); 10686 CHECK(value->IsObject()); 10687 10688 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10689 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 10690 Local<Object> instance2 = instance_template->NewInstance(); 10691 context->Global()->Set(v8_str("obj5"), instance2); 10692 CHECK(!try_catch.HasCaught()); 10693 10694 CHECK(instance2->IsObject()); 10695 CHECK(!instance2->IsFunction()); 10696 10697 value = CompileRun("new obj5(28)"); 10698 CHECK(!try_catch.HasCaught()); 10699 CHECK(!value->IsObject()); 10700 10701 Local<Value> args2[] = { v8_num(28) }; 10702 value = instance2->CallAsConstructor(1, args2); 10703 CHECK(!try_catch.HasCaught()); 10704 CHECK(!value->IsObject()); 10705 } 10706 } 10707 10708 10709 THREADED_TEST(FunctionDescriptorException) { 10710 LocalContext context; 10711 v8::Isolate* isolate = context->GetIsolate(); 10712 v8::HandleScope handle_scope(isolate); 10713 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 10714 templ->SetClassName(v8_str("Fun")); 10715 Local<Function> cons = templ->GetFunction(); 10716 context->Global()->Set(v8_str("Fun"), cons); 10717 Local<Value> value = CompileRun( 10718 "function test() {" 10719 " try {" 10720 " (new Fun()).blah()" 10721 " } catch (e) {" 10722 " var str = String(e);" 10723 // " if (str.indexOf('TypeError') == -1) return 1;" 10724 // " if (str.indexOf('[object Fun]') != -1) return 2;" 10725 // " if (str.indexOf('#<Fun>') == -1) return 3;" 10726 " return 0;" 10727 " }" 10728 " return 4;" 10729 "}" 10730 "test();"); 10731 CHECK_EQ(0, value->Int32Value()); 10732 } 10733 10734 10735 THREADED_TEST(EvalAliasedDynamic) { 10736 LocalContext current; 10737 v8::HandleScope scope(current->GetIsolate()); 10738 10739 // Tests where aliased eval can only be resolved dynamically. 10740 Local<Script> script = v8_compile( 10741 "function f(x) { " 10742 " var foo = 2;" 10743 " with (x) { return eval('foo'); }" 10744 "}" 10745 "foo = 0;" 10746 "result1 = f(new Object());" 10747 "result2 = f(this);" 10748 "var x = new Object();" 10749 "x.eval = function(x) { return 1; };" 10750 "result3 = f(x);"); 10751 script->Run(); 10752 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value()); 10753 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); 10754 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); 10755 10756 v8::TryCatch try_catch; 10757 script = v8_compile( 10758 "function f(x) { " 10759 " var bar = 2;" 10760 " with (x) { return eval('bar'); }" 10761 "}" 10762 "result4 = f(this)"); 10763 script->Run(); 10764 CHECK(!try_catch.HasCaught()); 10765 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value()); 10766 10767 try_catch.Reset(); 10768 } 10769 10770 10771 THREADED_TEST(CrossEval) { 10772 v8::HandleScope scope(CcTest::isolate()); 10773 LocalContext other; 10774 LocalContext current; 10775 10776 Local<String> token = v8_str("<security token>"); 10777 other->SetSecurityToken(token); 10778 current->SetSecurityToken(token); 10779 10780 // Set up reference from current to other. 10781 current->Global()->Set(v8_str("other"), other->Global()); 10782 10783 // Check that new variables are introduced in other context. 10784 Local<Script> script = v8_compile("other.eval('var foo = 1234')"); 10785 script->Run(); 10786 Local<Value> foo = other->Global()->Get(v8_str("foo")); 10787 CHECK_EQ(1234, foo->Int32Value()); 10788 CHECK(!current->Global()->Has(v8_str("foo"))); 10789 10790 // Check that writing to non-existing properties introduces them in 10791 // the other context. 10792 script = v8_compile("other.eval('na = 1234')"); 10793 script->Run(); 10794 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value()); 10795 CHECK(!current->Global()->Has(v8_str("na"))); 10796 10797 // Check that global variables in current context are not visible in other 10798 // context. 10799 v8::TryCatch try_catch; 10800 script = v8_compile("var bar = 42; other.eval('bar');"); 10801 Local<Value> result = script->Run(); 10802 CHECK(try_catch.HasCaught()); 10803 try_catch.Reset(); 10804 10805 // Check that local variables in current context are not visible in other 10806 // context. 10807 script = v8_compile( 10808 "(function() { " 10809 " var baz = 87;" 10810 " return other.eval('baz');" 10811 "})();"); 10812 result = script->Run(); 10813 CHECK(try_catch.HasCaught()); 10814 try_catch.Reset(); 10815 10816 // Check that global variables in the other environment are visible 10817 // when evaluting code. 10818 other->Global()->Set(v8_str("bis"), v8_num(1234)); 10819 script = v8_compile("other.eval('bis')"); 10820 CHECK_EQ(1234, script->Run()->Int32Value()); 10821 CHECK(!try_catch.HasCaught()); 10822 10823 // Check that the 'this' pointer points to the global object evaluating 10824 // code. 10825 other->Global()->Set(v8_str("t"), other->Global()); 10826 script = v8_compile("other.eval('this == t')"); 10827 result = script->Run(); 10828 CHECK(result->IsTrue()); 10829 CHECK(!try_catch.HasCaught()); 10830 10831 // Check that variables introduced in with-statement are not visible in 10832 // other context. 10833 script = v8_compile("with({x:2}){other.eval('x')}"); 10834 result = script->Run(); 10835 CHECK(try_catch.HasCaught()); 10836 try_catch.Reset(); 10837 10838 // Check that you cannot use 'eval.call' with another object than the 10839 // current global object. 10840 script = v8_compile("other.y = 1; eval.call(other, 'y')"); 10841 result = script->Run(); 10842 CHECK(try_catch.HasCaught()); 10843 } 10844 10845 10846 // Test that calling eval in a context which has been detached from 10847 // its global throws an exception. This behavior is consistent with 10848 // other JavaScript implementations. 10849 THREADED_TEST(EvalInDetachedGlobal) { 10850 v8::Isolate* isolate = CcTest::isolate(); 10851 v8::HandleScope scope(isolate); 10852 10853 v8::Local<Context> context0 = Context::New(isolate); 10854 v8::Local<Context> context1 = Context::New(isolate); 10855 10856 // Set up function in context0 that uses eval from context0. 10857 context0->Enter(); 10858 v8::Handle<v8::Value> fun = 10859 CompileRun("var x = 42;" 10860 "(function() {" 10861 " var e = eval;" 10862 " return function(s) { return e(s); }" 10863 "})()"); 10864 context0->Exit(); 10865 10866 // Put the function into context1 and call it before and after 10867 // detaching the global. Before detaching, the call succeeds and 10868 // after detaching and exception is thrown. 10869 context1->Enter(); 10870 context1->Global()->Set(v8_str("fun"), fun); 10871 v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); 10872 CHECK_EQ(42, x_value->Int32Value()); 10873 context0->DetachGlobal(); 10874 v8::TryCatch catcher; 10875 x_value = CompileRun("fun('x')"); 10876 CHECK(x_value.IsEmpty()); 10877 CHECK(catcher.HasCaught()); 10878 context1->Exit(); 10879 } 10880 10881 10882 THREADED_TEST(CrossLazyLoad) { 10883 v8::HandleScope scope(CcTest::isolate()); 10884 LocalContext other; 10885 LocalContext current; 10886 10887 Local<String> token = v8_str("<security token>"); 10888 other->SetSecurityToken(token); 10889 current->SetSecurityToken(token); 10890 10891 // Set up reference from current to other. 10892 current->Global()->Set(v8_str("other"), other->Global()); 10893 10894 // Trigger lazy loading in other context. 10895 Local<Script> script = v8_compile("other.eval('new Date(42)')"); 10896 Local<Value> value = script->Run(); 10897 CHECK_EQ(42.0, value->NumberValue()); 10898 } 10899 10900 10901 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 10902 ApiTestFuzzer::Fuzz(); 10903 if (args.IsConstructCall()) { 10904 if (args[0]->IsInt32()) { 10905 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value())); 10906 return; 10907 } 10908 } 10909 10910 args.GetReturnValue().Set(args[0]); 10911 } 10912 10913 10914 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 10915 args.GetReturnValue().Set(args.This()); 10916 } 10917 10918 10919 // Test that a call handler can be set for objects which will allow 10920 // non-function objects created through the API to be called as 10921 // functions. 10922 THREADED_TEST(CallAsFunction) { 10923 LocalContext context; 10924 v8::Isolate* isolate = context->GetIsolate(); 10925 v8::HandleScope scope(isolate); 10926 10927 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10928 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10929 instance_template->SetCallAsFunctionHandler(call_as_function); 10930 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10931 context->Global()->Set(v8_str("obj"), instance); 10932 v8::TryCatch try_catch; 10933 Local<Value> value; 10934 CHECK(!try_catch.HasCaught()); 10935 10936 value = CompileRun("obj(42)"); 10937 CHECK(!try_catch.HasCaught()); 10938 CHECK_EQ(42, value->Int32Value()); 10939 10940 value = CompileRun("(function(o){return o(49)})(obj)"); 10941 CHECK(!try_catch.HasCaught()); 10942 CHECK_EQ(49, value->Int32Value()); 10943 10944 // test special case of call as function 10945 value = CompileRun("[obj]['0'](45)"); 10946 CHECK(!try_catch.HasCaught()); 10947 CHECK_EQ(45, value->Int32Value()); 10948 10949 value = CompileRun("obj.call = Function.prototype.call;" 10950 "obj.call(null, 87)"); 10951 CHECK(!try_catch.HasCaught()); 10952 CHECK_EQ(87, value->Int32Value()); 10953 10954 // Regression tests for bug #1116356: Calling call through call/apply 10955 // must work for non-function receivers. 10956 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 10957 value = CompileRun(apply_99); 10958 CHECK(!try_catch.HasCaught()); 10959 CHECK_EQ(99, value->Int32Value()); 10960 10961 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 10962 value = CompileRun(call_17); 10963 CHECK(!try_catch.HasCaught()); 10964 CHECK_EQ(17, value->Int32Value()); 10965 10966 // Check that the call-as-function handler can be called through 10967 // new. 10968 value = CompileRun("new obj(43)"); 10969 CHECK(!try_catch.HasCaught()); 10970 CHECK_EQ(-43, value->Int32Value()); 10971 10972 // Check that the call-as-function handler can be called through 10973 // the API. 10974 v8::Handle<Value> args[] = { v8_num(28) }; 10975 value = instance->CallAsFunction(instance, 1, args); 10976 CHECK(!try_catch.HasCaught()); 10977 CHECK_EQ(28, value->Int32Value()); 10978 } 10979 10980 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10981 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 10982 USE(instance_template); 10983 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10984 context->Global()->Set(v8_str("obj2"), instance); 10985 v8::TryCatch try_catch; 10986 Local<Value> value; 10987 CHECK(!try_catch.HasCaught()); 10988 10989 // Call an object without call-as-function handler through the JS 10990 value = CompileRun("obj2(28)"); 10991 CHECK(value.IsEmpty()); 10992 CHECK(try_catch.HasCaught()); 10993 String::Utf8Value exception_value1(try_catch.Exception()); 10994 // TODO(verwaest): Better message 10995 CHECK_EQ("TypeError: object is not a function", 10996 *exception_value1); 10997 try_catch.Reset(); 10998 10999 // Call an object without call-as-function handler through the API 11000 value = CompileRun("obj2(28)"); 11001 v8::Handle<Value> args[] = { v8_num(28) }; 11002 value = instance->CallAsFunction(instance, 1, args); 11003 CHECK(value.IsEmpty()); 11004 CHECK(try_catch.HasCaught()); 11005 String::Utf8Value exception_value2(try_catch.Exception()); 11006 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); 11007 try_catch.Reset(); 11008 } 11009 11010 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11011 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11012 instance_template->SetCallAsFunctionHandler(ThrowValue); 11013 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11014 context->Global()->Set(v8_str("obj3"), instance); 11015 v8::TryCatch try_catch; 11016 Local<Value> value; 11017 CHECK(!try_catch.HasCaught()); 11018 11019 // Catch the exception which is thrown by call-as-function handler 11020 value = CompileRun("obj3(22)"); 11021 CHECK(try_catch.HasCaught()); 11022 String::Utf8Value exception_value1(try_catch.Exception()); 11023 CHECK_EQ("22", *exception_value1); 11024 try_catch.Reset(); 11025 11026 v8::Handle<Value> args[] = { v8_num(23) }; 11027 value = instance->CallAsFunction(instance, 1, args); 11028 CHECK(try_catch.HasCaught()); 11029 String::Utf8Value exception_value2(try_catch.Exception()); 11030 CHECK_EQ("23", *exception_value2); 11031 try_catch.Reset(); 11032 } 11033 11034 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11035 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11036 instance_template->SetCallAsFunctionHandler(ReturnThis); 11037 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11038 11039 Local<v8::Value> a1 = 11040 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11041 CHECK(a1->StrictEquals(instance)); 11042 Local<v8::Value> a2 = 11043 instance->CallAsFunction(v8::Null(isolate), 0, NULL); 11044 CHECK(a2->StrictEquals(instance)); 11045 Local<v8::Value> a3 = 11046 instance->CallAsFunction(v8_num(42), 0, NULL); 11047 CHECK(a3->StrictEquals(instance)); 11048 Local<v8::Value> a4 = 11049 instance->CallAsFunction(v8_str("hello"), 0, NULL); 11050 CHECK(a4->StrictEquals(instance)); 11051 Local<v8::Value> a5 = 11052 instance->CallAsFunction(v8::True(isolate), 0, NULL); 11053 CHECK(a5->StrictEquals(instance)); 11054 } 11055 11056 { CompileRun( 11057 "function ReturnThisSloppy() {" 11058 " return this;" 11059 "}" 11060 "function ReturnThisStrict() {" 11061 " 'use strict';" 11062 " return this;" 11063 "}"); 11064 Local<Function> ReturnThisSloppy = 11065 Local<Function>::Cast( 11066 context->Global()->Get(v8_str("ReturnThisSloppy"))); 11067 Local<Function> ReturnThisStrict = 11068 Local<Function>::Cast( 11069 context->Global()->Get(v8_str("ReturnThisStrict"))); 11070 11071 Local<v8::Value> a1 = 11072 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11073 CHECK(a1->StrictEquals(context->Global())); 11074 Local<v8::Value> a2 = 11075 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL); 11076 CHECK(a2->StrictEquals(context->Global())); 11077 Local<v8::Value> a3 = 11078 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL); 11079 CHECK(a3->IsNumberObject()); 11080 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf()); 11081 Local<v8::Value> a4 = 11082 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL); 11083 CHECK(a4->IsStringObject()); 11084 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 11085 Local<v8::Value> a5 = 11086 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL); 11087 CHECK(a5->IsBooleanObject()); 11088 CHECK(a5.As<v8::BooleanObject>()->ValueOf()); 11089 11090 Local<v8::Value> a6 = 11091 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11092 CHECK(a6->IsUndefined()); 11093 Local<v8::Value> a7 = 11094 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL); 11095 CHECK(a7->IsNull()); 11096 Local<v8::Value> a8 = 11097 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL); 11098 CHECK(a8->StrictEquals(v8_num(42))); 11099 Local<v8::Value> a9 = 11100 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL); 11101 CHECK(a9->StrictEquals(v8_str("hello"))); 11102 Local<v8::Value> a10 = 11103 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL); 11104 CHECK(a10->StrictEquals(v8::True(isolate))); 11105 } 11106 } 11107 11108 11109 // Check whether a non-function object is callable. 11110 THREADED_TEST(CallableObject) { 11111 LocalContext context; 11112 v8::Isolate* isolate = context->GetIsolate(); 11113 v8::HandleScope scope(isolate); 11114 11115 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11116 instance_template->SetCallAsFunctionHandler(call_as_function); 11117 Local<Object> instance = instance_template->NewInstance(); 11118 v8::TryCatch try_catch; 11119 11120 CHECK(instance->IsCallable()); 11121 CHECK(!try_catch.HasCaught()); 11122 } 11123 11124 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11125 Local<Object> instance = instance_template->NewInstance(); 11126 v8::TryCatch try_catch; 11127 11128 CHECK(!instance->IsCallable()); 11129 CHECK(!try_catch.HasCaught()); 11130 } 11131 11132 { Local<FunctionTemplate> function_template = 11133 FunctionTemplate::New(isolate, call_as_function); 11134 Local<Function> function = function_template->GetFunction(); 11135 Local<Object> instance = function; 11136 v8::TryCatch try_catch; 11137 11138 CHECK(instance->IsCallable()); 11139 CHECK(!try_catch.HasCaught()); 11140 } 11141 11142 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate); 11143 Local<Function> function = function_template->GetFunction(); 11144 Local<Object> instance = function; 11145 v8::TryCatch try_catch; 11146 11147 CHECK(instance->IsCallable()); 11148 CHECK(!try_catch.HasCaught()); 11149 } 11150 } 11151 11152 11153 static int Recurse(v8::Isolate* isolate, int depth, int iterations) { 11154 v8::HandleScope scope(isolate); 11155 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate); 11156 for (int i = 0; i < iterations; i++) { 11157 Local<v8::Number> n(v8::Integer::New(isolate, 42)); 11158 } 11159 return Recurse(isolate, depth - 1, iterations); 11160 } 11161 11162 11163 THREADED_TEST(HandleIteration) { 11164 static const int kIterations = 500; 11165 static const int kNesting = 200; 11166 LocalContext context; 11167 v8::Isolate* isolate = context->GetIsolate(); 11168 v8::HandleScope scope0(isolate); 11169 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11170 { 11171 v8::HandleScope scope1(isolate); 11172 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11173 for (int i = 0; i < kIterations; i++) { 11174 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11175 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate)); 11176 } 11177 11178 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11179 { 11180 v8::HandleScope scope2(CcTest::isolate()); 11181 for (int j = 0; j < kIterations; j++) { 11182 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11183 CHECK_EQ(j + 1 + kIterations, 11184 v8::HandleScope::NumberOfHandles(isolate)); 11185 } 11186 } 11187 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11188 } 11189 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11190 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations)); 11191 } 11192 11193 11194 static void InterceptorHasOwnPropertyGetter( 11195 Local<String> name, 11196 const v8::PropertyCallbackInfo<v8::Value>& info) { 11197 ApiTestFuzzer::Fuzz(); 11198 } 11199 11200 11201 THREADED_TEST(InterceptorHasOwnProperty) { 11202 LocalContext context; 11203 v8::Isolate* isolate = context->GetIsolate(); 11204 v8::HandleScope scope(isolate); 11205 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 11206 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 11207 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter); 11208 Local<Function> function = fun_templ->GetFunction(); 11209 context->Global()->Set(v8_str("constructor"), function); 11210 v8::Handle<Value> value = CompileRun( 11211 "var o = new constructor();" 11212 "o.hasOwnProperty('ostehaps');"); 11213 CHECK_EQ(false, value->BooleanValue()); 11214 value = CompileRun( 11215 "o.ostehaps = 42;" 11216 "o.hasOwnProperty('ostehaps');"); 11217 CHECK_EQ(true, value->BooleanValue()); 11218 value = CompileRun( 11219 "var p = new constructor();" 11220 "p.hasOwnProperty('ostehaps');"); 11221 CHECK_EQ(false, value->BooleanValue()); 11222 } 11223 11224 11225 static void InterceptorHasOwnPropertyGetterGC( 11226 Local<String> name, 11227 const v8::PropertyCallbackInfo<v8::Value>& info) { 11228 ApiTestFuzzer::Fuzz(); 11229 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 11230 } 11231 11232 11233 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { 11234 LocalContext context; 11235 v8::Isolate* isolate = context->GetIsolate(); 11236 v8::HandleScope scope(isolate); 11237 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 11238 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 11239 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); 11240 Local<Function> function = fun_templ->GetFunction(); 11241 context->Global()->Set(v8_str("constructor"), function); 11242 // Let's first make some stuff so we can be sure to get a good GC. 11243 CompileRun( 11244 "function makestr(size) {" 11245 " switch (size) {" 11246 " case 1: return 'f';" 11247 " case 2: return 'fo';" 11248 " case 3: return 'foo';" 11249 " }" 11250 " return makestr(size >> 1) + makestr((size + 1) >> 1);" 11251 "}" 11252 "var x = makestr(12345);" 11253 "x = makestr(31415);" 11254 "x = makestr(23456);"); 11255 v8::Handle<Value> value = CompileRun( 11256 "var o = new constructor();" 11257 "o.__proto__ = new String(x);" 11258 "o.hasOwnProperty('ostehaps');"); 11259 CHECK_EQ(false, value->BooleanValue()); 11260 } 11261 11262 11263 typedef void (*NamedPropertyGetter)( 11264 Local<String> property, 11265 const v8::PropertyCallbackInfo<v8::Value>& info); 11266 11267 11268 static void CheckInterceptorLoadIC(NamedPropertyGetter getter, 11269 const char* source, 11270 int expected) { 11271 v8::Isolate* isolate = CcTest::isolate(); 11272 v8::HandleScope scope(isolate); 11273 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11274 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data")); 11275 LocalContext context; 11276 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11277 v8::Handle<Value> value = CompileRun(source); 11278 CHECK_EQ(expected, value->Int32Value()); 11279 } 11280 11281 11282 static void InterceptorLoadICGetter( 11283 Local<String> name, 11284 const v8::PropertyCallbackInfo<v8::Value>& info) { 11285 ApiTestFuzzer::Fuzz(); 11286 v8::Isolate* isolate = CcTest::isolate(); 11287 CHECK_EQ(isolate, info.GetIsolate()); 11288 CHECK_EQ(v8_str("data"), info.Data()); 11289 CHECK_EQ(v8_str("x"), name); 11290 info.GetReturnValue().Set(v8::Integer::New(isolate, 42)); 11291 } 11292 11293 11294 // This test should hit the load IC for the interceptor case. 11295 THREADED_TEST(InterceptorLoadIC) { 11296 CheckInterceptorLoadIC(InterceptorLoadICGetter, 11297 "var result = 0;" 11298 "for (var i = 0; i < 1000; i++) {" 11299 " result = o.x;" 11300 "}", 11301 42); 11302 } 11303 11304 11305 // Below go several tests which verify that JITing for various 11306 // configurations of interceptor and explicit fields works fine 11307 // (those cases are special cased to get better performance). 11308 11309 static void InterceptorLoadXICGetter( 11310 Local<String> name, 11311 const v8::PropertyCallbackInfo<v8::Value>& info) { 11312 ApiTestFuzzer::Fuzz(); 11313 info.GetReturnValue().Set( 11314 v8_str("x")->Equals(name) ? 11315 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) : 11316 v8::Handle<v8::Value>()); 11317 } 11318 11319 11320 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { 11321 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11322 "var result = 0;" 11323 "o.y = 239;" 11324 "for (var i = 0; i < 1000; i++) {" 11325 " result = o.y;" 11326 "}", 11327 239); 11328 } 11329 11330 11331 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) { 11332 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11333 "var result = 0;" 11334 "o.__proto__ = { 'y': 239 };" 11335 "for (var i = 0; i < 1000; i++) {" 11336 " result = o.y + o.x;" 11337 "}", 11338 239 + 42); 11339 } 11340 11341 11342 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) { 11343 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11344 "var result = 0;" 11345 "o.__proto__.y = 239;" 11346 "for (var i = 0; i < 1000; i++) {" 11347 " result = o.y + o.x;" 11348 "}", 11349 239 + 42); 11350 } 11351 11352 11353 THREADED_TEST(InterceptorLoadICUndefined) { 11354 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11355 "var result = 0;" 11356 "for (var i = 0; i < 1000; i++) {" 11357 " result = (o.y == undefined) ? 239 : 42;" 11358 "}", 11359 239); 11360 } 11361 11362 11363 THREADED_TEST(InterceptorLoadICWithOverride) { 11364 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11365 "fst = new Object(); fst.__proto__ = o;" 11366 "snd = new Object(); snd.__proto__ = fst;" 11367 "var result1 = 0;" 11368 "for (var i = 0; i < 1000; i++) {" 11369 " result1 = snd.x;" 11370 "}" 11371 "fst.x = 239;" 11372 "var result = 0;" 11373 "for (var i = 0; i < 1000; i++) {" 11374 " result = snd.x;" 11375 "}" 11376 "result + result1", 11377 239 + 42); 11378 } 11379 11380 11381 // Test the case when we stored field into 11382 // a stub, but interceptor produced value on its own. 11383 THREADED_TEST(InterceptorLoadICFieldNotNeeded) { 11384 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11385 "proto = new Object();" 11386 "o.__proto__ = proto;" 11387 "proto.x = 239;" 11388 "for (var i = 0; i < 1000; i++) {" 11389 " o.x;" 11390 // Now it should be ICed and keep a reference to x defined on proto 11391 "}" 11392 "var result = 0;" 11393 "for (var i = 0; i < 1000; i++) {" 11394 " result += o.x;" 11395 "}" 11396 "result;", 11397 42 * 1000); 11398 } 11399 11400 11401 // Test the case when we stored field into 11402 // a stub, but it got invalidated later on. 11403 THREADED_TEST(InterceptorLoadICInvalidatedField) { 11404 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11405 "proto1 = new Object();" 11406 "proto2 = new Object();" 11407 "o.__proto__ = proto1;" 11408 "proto1.__proto__ = proto2;" 11409 "proto2.y = 239;" 11410 "for (var i = 0; i < 1000; i++) {" 11411 " o.y;" 11412 // Now it should be ICed and keep a reference to y defined on proto2 11413 "}" 11414 "proto1.y = 42;" 11415 "var result = 0;" 11416 "for (var i = 0; i < 1000; i++) {" 11417 " result += o.y;" 11418 "}" 11419 "result;", 11420 42 * 1000); 11421 } 11422 11423 11424 static int interceptor_load_not_handled_calls = 0; 11425 static void InterceptorLoadNotHandled( 11426 Local<String> name, 11427 const v8::PropertyCallbackInfo<v8::Value>& info) { 11428 ++interceptor_load_not_handled_calls; 11429 } 11430 11431 11432 // Test how post-interceptor lookups are done in the non-cacheable 11433 // case: the interceptor should not be invoked during this lookup. 11434 THREADED_TEST(InterceptorLoadICPostInterceptor) { 11435 interceptor_load_not_handled_calls = 0; 11436 CheckInterceptorLoadIC(InterceptorLoadNotHandled, 11437 "receiver = new Object();" 11438 "receiver.__proto__ = o;" 11439 "proto = new Object();" 11440 "/* Make proto a slow-case object. */" 11441 "for (var i = 0; i < 1000; i++) {" 11442 " proto[\"xxxxxxxx\" + i] = [];" 11443 "}" 11444 "proto.x = 17;" 11445 "o.__proto__ = proto;" 11446 "var result = 0;" 11447 "for (var i = 0; i < 1000; i++) {" 11448 " result += receiver.x;" 11449 "}" 11450 "result;", 11451 17 * 1000); 11452 CHECK_EQ(1000, interceptor_load_not_handled_calls); 11453 } 11454 11455 11456 // Test the case when we stored field into 11457 // a stub, but it got invalidated later on due to override on 11458 // global object which is between interceptor and fields' holders. 11459 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) { 11460 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11461 "o.__proto__ = this;" // set a global to be a proto of o. 11462 "this.__proto__.y = 239;" 11463 "for (var i = 0; i < 10; i++) {" 11464 " if (o.y != 239) throw 'oops: ' + o.y;" 11465 // Now it should be ICed and keep a reference to y defined on field_holder. 11466 "}" 11467 "this.y = 42;" // Assign on a global. 11468 "var result = 0;" 11469 "for (var i = 0; i < 10; i++) {" 11470 " result += o.y;" 11471 "}" 11472 "result;", 11473 42 * 10); 11474 } 11475 11476 11477 static void SetOnThis(Local<String> name, 11478 Local<Value> value, 11479 const v8::PropertyCallbackInfo<void>& info) { 11480 Local<Object>::Cast(info.This())->ForceSet(name, value); 11481 } 11482 11483 11484 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) { 11485 v8::Isolate* isolate = CcTest::isolate(); 11486 v8::HandleScope scope(isolate); 11487 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11488 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11489 templ->SetAccessor(v8_str("y"), Return239Callback); 11490 LocalContext context; 11491 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11492 11493 // Check the case when receiver and interceptor's holder 11494 // are the same objects. 11495 v8::Handle<Value> value = CompileRun( 11496 "var result = 0;" 11497 "for (var i = 0; i < 7; i++) {" 11498 " result = o.y;" 11499 "}"); 11500 CHECK_EQ(239, value->Int32Value()); 11501 11502 // Check the case when interceptor's holder is in proto chain 11503 // of receiver. 11504 value = CompileRun( 11505 "r = { __proto__: o };" 11506 "var result = 0;" 11507 "for (var i = 0; i < 7; i++) {" 11508 " result = r.y;" 11509 "}"); 11510 CHECK_EQ(239, value->Int32Value()); 11511 } 11512 11513 11514 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) { 11515 v8::Isolate* isolate = CcTest::isolate(); 11516 v8::HandleScope scope(isolate); 11517 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11518 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11519 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11520 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11521 11522 LocalContext context; 11523 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11524 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11525 11526 // Check the case when receiver and interceptor's holder 11527 // are the same objects. 11528 v8::Handle<Value> value = CompileRun( 11529 "o.__proto__ = p;" 11530 "var result = 0;" 11531 "for (var i = 0; i < 7; i++) {" 11532 " result = o.x + o.y;" 11533 "}"); 11534 CHECK_EQ(239 + 42, value->Int32Value()); 11535 11536 // Check the case when interceptor's holder is in proto chain 11537 // of receiver. 11538 value = CompileRun( 11539 "r = { __proto__: o };" 11540 "var result = 0;" 11541 "for (var i = 0; i < 7; i++) {" 11542 " result = r.x + r.y;" 11543 "}"); 11544 CHECK_EQ(239 + 42, value->Int32Value()); 11545 } 11546 11547 11548 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) { 11549 v8::Isolate* isolate = CcTest::isolate(); 11550 v8::HandleScope scope(isolate); 11551 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11552 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11553 templ->SetAccessor(v8_str("y"), Return239Callback); 11554 11555 LocalContext context; 11556 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11557 11558 v8::Handle<Value> value = CompileRun( 11559 "fst = new Object(); fst.__proto__ = o;" 11560 "snd = new Object(); snd.__proto__ = fst;" 11561 "var result1 = 0;" 11562 "for (var i = 0; i < 7; i++) {" 11563 " result1 = snd.x;" 11564 "}" 11565 "fst.x = 239;" 11566 "var result = 0;" 11567 "for (var i = 0; i < 7; i++) {" 11568 " result = snd.x;" 11569 "}" 11570 "result + result1"); 11571 CHECK_EQ(239 + 42, value->Int32Value()); 11572 } 11573 11574 11575 // Test the case when we stored callback into 11576 // a stub, but interceptor produced value on its own. 11577 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) { 11578 v8::Isolate* isolate = CcTest::isolate(); 11579 v8::HandleScope scope(isolate); 11580 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11581 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11582 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11583 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11584 11585 LocalContext context; 11586 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11587 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11588 11589 v8::Handle<Value> value = CompileRun( 11590 "o.__proto__ = p;" 11591 "for (var i = 0; i < 7; i++) {" 11592 " o.x;" 11593 // Now it should be ICed and keep a reference to x defined on p 11594 "}" 11595 "var result = 0;" 11596 "for (var i = 0; i < 7; i++) {" 11597 " result += o.x;" 11598 "}" 11599 "result"); 11600 CHECK_EQ(42 * 7, value->Int32Value()); 11601 } 11602 11603 11604 // Test the case when we stored callback into 11605 // a stub, but it got invalidated later on. 11606 THREADED_TEST(InterceptorLoadICInvalidatedCallback) { 11607 v8::Isolate* isolate = CcTest::isolate(); 11608 v8::HandleScope scope(isolate); 11609 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11610 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11611 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11612 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11613 11614 LocalContext context; 11615 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11616 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11617 11618 v8::Handle<Value> value = CompileRun( 11619 "inbetween = new Object();" 11620 "o.__proto__ = inbetween;" 11621 "inbetween.__proto__ = p;" 11622 "for (var i = 0; i < 10; i++) {" 11623 " o.y;" 11624 // Now it should be ICed and keep a reference to y defined on p 11625 "}" 11626 "inbetween.y = 42;" 11627 "var result = 0;" 11628 "for (var i = 0; i < 10; i++) {" 11629 " result += o.y;" 11630 "}" 11631 "result"); 11632 CHECK_EQ(42 * 10, value->Int32Value()); 11633 } 11634 11635 11636 // Test the case when we stored callback into 11637 // a stub, but it got invalidated later on due to override on 11638 // global object which is between interceptor and callbacks' holders. 11639 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) { 11640 v8::Isolate* isolate = CcTest::isolate(); 11641 v8::HandleScope scope(isolate); 11642 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11643 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11644 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11645 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11646 11647 LocalContext context; 11648 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11649 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11650 11651 v8::Handle<Value> value = CompileRun( 11652 "o.__proto__ = this;" 11653 "this.__proto__ = p;" 11654 "for (var i = 0; i < 10; i++) {" 11655 " if (o.y != 239) throw 'oops: ' + o.y;" 11656 // Now it should be ICed and keep a reference to y defined on p 11657 "}" 11658 "this.y = 42;" 11659 "var result = 0;" 11660 "for (var i = 0; i < 10; i++) {" 11661 " result += o.y;" 11662 "}" 11663 "result"); 11664 CHECK_EQ(42 * 10, value->Int32Value()); 11665 } 11666 11667 11668 static void InterceptorLoadICGetter0( 11669 Local<String> name, 11670 const v8::PropertyCallbackInfo<v8::Value>& info) { 11671 ApiTestFuzzer::Fuzz(); 11672 CHECK(v8_str("x")->Equals(name)); 11673 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0)); 11674 } 11675 11676 11677 THREADED_TEST(InterceptorReturningZero) { 11678 CheckInterceptorLoadIC(InterceptorLoadICGetter0, 11679 "o.x == undefined ? 1 : 0", 11680 0); 11681 } 11682 11683 11684 static void InterceptorStoreICSetter( 11685 Local<String> key, 11686 Local<Value> value, 11687 const v8::PropertyCallbackInfo<v8::Value>& info) { 11688 CHECK(v8_str("x")->Equals(key)); 11689 CHECK_EQ(42, value->Int32Value()); 11690 info.GetReturnValue().Set(value); 11691 } 11692 11693 11694 // This test should hit the store IC for the interceptor case. 11695 THREADED_TEST(InterceptorStoreIC) { 11696 v8::Isolate* isolate = CcTest::isolate(); 11697 v8::HandleScope scope(isolate); 11698 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11699 templ->SetNamedPropertyHandler(InterceptorLoadICGetter, 11700 InterceptorStoreICSetter, 11701 0, 0, 0, v8_str("data")); 11702 LocalContext context; 11703 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11704 CompileRun( 11705 "for (var i = 0; i < 1000; i++) {" 11706 " o.x = 42;" 11707 "}"); 11708 } 11709 11710 11711 THREADED_TEST(InterceptorStoreICWithNoSetter) { 11712 v8::Isolate* isolate = CcTest::isolate(); 11713 v8::HandleScope scope(isolate); 11714 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11715 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11716 LocalContext context; 11717 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11718 v8::Handle<Value> value = CompileRun( 11719 "for (var i = 0; i < 1000; i++) {" 11720 " o.y = 239;" 11721 "}" 11722 "42 + o.y"); 11723 CHECK_EQ(239 + 42, value->Int32Value()); 11724 } 11725 11726 11727 11728 11729 v8::Handle<Value> call_ic_function; 11730 v8::Handle<Value> call_ic_function2; 11731 v8::Handle<Value> call_ic_function3; 11732 11733 static void InterceptorCallICGetter( 11734 Local<String> name, 11735 const v8::PropertyCallbackInfo<v8::Value>& info) { 11736 ApiTestFuzzer::Fuzz(); 11737 CHECK(v8_str("x")->Equals(name)); 11738 info.GetReturnValue().Set(call_ic_function); 11739 } 11740 11741 11742 // This test should hit the call IC for the interceptor case. 11743 THREADED_TEST(InterceptorCallIC) { 11744 v8::Isolate* isolate = CcTest::isolate(); 11745 v8::HandleScope scope(isolate); 11746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11747 templ->SetNamedPropertyHandler(InterceptorCallICGetter); 11748 LocalContext context; 11749 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11750 call_ic_function = 11751 v8_compile("function f(x) { return x + 1; }; f")->Run(); 11752 v8::Handle<Value> value = CompileRun( 11753 "var result = 0;" 11754 "for (var i = 0; i < 1000; i++) {" 11755 " result = o.x(41);" 11756 "}"); 11757 CHECK_EQ(42, value->Int32Value()); 11758 } 11759 11760 11761 // This test checks that if interceptor doesn't provide 11762 // a value, we can fetch regular value. 11763 THREADED_TEST(InterceptorCallICSeesOthers) { 11764 v8::Isolate* isolate = CcTest::isolate(); 11765 v8::HandleScope scope(isolate); 11766 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11767 templ->SetNamedPropertyHandler(NoBlockGetterX); 11768 LocalContext context; 11769 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11770 v8::Handle<Value> value = CompileRun( 11771 "o.x = function f(x) { return x + 1; };" 11772 "var result = 0;" 11773 "for (var i = 0; i < 7; i++) {" 11774 " result = o.x(41);" 11775 "}"); 11776 CHECK_EQ(42, value->Int32Value()); 11777 } 11778 11779 11780 static v8::Handle<Value> call_ic_function4; 11781 static void InterceptorCallICGetter4( 11782 Local<String> name, 11783 const v8::PropertyCallbackInfo<v8::Value>& info) { 11784 ApiTestFuzzer::Fuzz(); 11785 CHECK(v8_str("x")->Equals(name)); 11786 info.GetReturnValue().Set(call_ic_function4); 11787 } 11788 11789 11790 // This test checks that if interceptor provides a function, 11791 // even if we cached shadowed variant, interceptor's function 11792 // is invoked 11793 THREADED_TEST(InterceptorCallICCacheableNotNeeded) { 11794 v8::Isolate* isolate = CcTest::isolate(); 11795 v8::HandleScope scope(isolate); 11796 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11797 templ->SetNamedPropertyHandler(InterceptorCallICGetter4); 11798 LocalContext context; 11799 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11800 call_ic_function4 = 11801 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11802 v8::Handle<Value> value = CompileRun( 11803 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };" 11804 "var result = 0;" 11805 "for (var i = 0; i < 1000; i++) {" 11806 " result = o.x(42);" 11807 "}"); 11808 CHECK_EQ(41, value->Int32Value()); 11809 } 11810 11811 11812 // Test the case when we stored cacheable lookup into 11813 // a stub, but it got invalidated later on 11814 THREADED_TEST(InterceptorCallICInvalidatedCacheable) { 11815 v8::Isolate* isolate = CcTest::isolate(); 11816 v8::HandleScope scope(isolate); 11817 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11818 templ->SetNamedPropertyHandler(NoBlockGetterX); 11819 LocalContext context; 11820 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11821 v8::Handle<Value> value = CompileRun( 11822 "proto1 = new Object();" 11823 "proto2 = new Object();" 11824 "o.__proto__ = proto1;" 11825 "proto1.__proto__ = proto2;" 11826 "proto2.y = function(x) { return x + 1; };" 11827 // Invoke it many times to compile a stub 11828 "for (var i = 0; i < 7; i++) {" 11829 " o.y(42);" 11830 "}" 11831 "proto1.y = function(x) { return x - 1; };" 11832 "var result = 0;" 11833 "for (var i = 0; i < 7; i++) {" 11834 " result += o.y(42);" 11835 "}"); 11836 CHECK_EQ(41 * 7, value->Int32Value()); 11837 } 11838 11839 11840 // This test checks that if interceptor doesn't provide a function, 11841 // cached constant function is used 11842 THREADED_TEST(InterceptorCallICConstantFunctionUsed) { 11843 v8::Isolate* isolate = CcTest::isolate(); 11844 v8::HandleScope scope(isolate); 11845 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11846 templ->SetNamedPropertyHandler(NoBlockGetterX); 11847 LocalContext context; 11848 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11849 v8::Handle<Value> value = CompileRun( 11850 "function inc(x) { return x + 1; };" 11851 "inc(1);" 11852 "o.x = inc;" 11853 "var result = 0;" 11854 "for (var i = 0; i < 1000; i++) {" 11855 " result = o.x(42);" 11856 "}"); 11857 CHECK_EQ(43, value->Int32Value()); 11858 } 11859 11860 11861 static v8::Handle<Value> call_ic_function5; 11862 static void InterceptorCallICGetter5( 11863 Local<String> name, 11864 const v8::PropertyCallbackInfo<v8::Value>& info) { 11865 ApiTestFuzzer::Fuzz(); 11866 if (v8_str("x")->Equals(name)) 11867 info.GetReturnValue().Set(call_ic_function5); 11868 } 11869 11870 11871 // This test checks that if interceptor provides a function, 11872 // even if we cached constant function, interceptor's function 11873 // is invoked 11874 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { 11875 v8::Isolate* isolate = CcTest::isolate(); 11876 v8::HandleScope scope(isolate); 11877 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11878 templ->SetNamedPropertyHandler(InterceptorCallICGetter5); 11879 LocalContext context; 11880 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11881 call_ic_function5 = 11882 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11883 v8::Handle<Value> value = CompileRun( 11884 "function inc(x) { return x + 1; };" 11885 "inc(1);" 11886 "o.x = inc;" 11887 "var result = 0;" 11888 "for (var i = 0; i < 1000; i++) {" 11889 " result = o.x(42);" 11890 "}"); 11891 CHECK_EQ(41, value->Int32Value()); 11892 } 11893 11894 11895 static v8::Handle<Value> call_ic_function6; 11896 static void InterceptorCallICGetter6( 11897 Local<String> name, 11898 const v8::PropertyCallbackInfo<v8::Value>& info) { 11899 ApiTestFuzzer::Fuzz(); 11900 if (v8_str("x")->Equals(name)) 11901 info.GetReturnValue().Set(call_ic_function6); 11902 } 11903 11904 11905 // Same test as above, except the code is wrapped in a function 11906 // to test the optimized compiler. 11907 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) { 11908 i::FLAG_allow_natives_syntax = true; 11909 v8::Isolate* isolate = CcTest::isolate(); 11910 v8::HandleScope scope(isolate); 11911 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11912 templ->SetNamedPropertyHandler(InterceptorCallICGetter6); 11913 LocalContext context; 11914 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11915 call_ic_function6 = 11916 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11917 v8::Handle<Value> value = CompileRun( 11918 "function inc(x) { return x + 1; };" 11919 "inc(1);" 11920 "o.x = inc;" 11921 "function test() {" 11922 " var result = 0;" 11923 " for (var i = 0; i < 1000; i++) {" 11924 " result = o.x(42);" 11925 " }" 11926 " return result;" 11927 "};" 11928 "test();" 11929 "test();" 11930 "test();" 11931 "%OptimizeFunctionOnNextCall(test);" 11932 "test()"); 11933 CHECK_EQ(41, value->Int32Value()); 11934 } 11935 11936 11937 // Test the case when we stored constant function into 11938 // a stub, but it got invalidated later on 11939 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { 11940 v8::Isolate* isolate = CcTest::isolate(); 11941 v8::HandleScope scope(isolate); 11942 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11943 templ->SetNamedPropertyHandler(NoBlockGetterX); 11944 LocalContext context; 11945 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11946 v8::Handle<Value> value = CompileRun( 11947 "function inc(x) { return x + 1; };" 11948 "inc(1);" 11949 "proto1 = new Object();" 11950 "proto2 = new Object();" 11951 "o.__proto__ = proto1;" 11952 "proto1.__proto__ = proto2;" 11953 "proto2.y = inc;" 11954 // Invoke it many times to compile a stub 11955 "for (var i = 0; i < 7; i++) {" 11956 " o.y(42);" 11957 "}" 11958 "proto1.y = function(x) { return x - 1; };" 11959 "var result = 0;" 11960 "for (var i = 0; i < 7; i++) {" 11961 " result += o.y(42);" 11962 "}"); 11963 CHECK_EQ(41 * 7, value->Int32Value()); 11964 } 11965 11966 11967 // Test the case when we stored constant function into 11968 // a stub, but it got invalidated later on due to override on 11969 // global object which is between interceptor and constant function' holders. 11970 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) { 11971 v8::Isolate* isolate = CcTest::isolate(); 11972 v8::HandleScope scope(isolate); 11973 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11974 templ->SetNamedPropertyHandler(NoBlockGetterX); 11975 LocalContext context; 11976 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11977 v8::Handle<Value> value = CompileRun( 11978 "function inc(x) { return x + 1; };" 11979 "inc(1);" 11980 "o.__proto__ = this;" 11981 "this.__proto__.y = inc;" 11982 // Invoke it many times to compile a stub 11983 "for (var i = 0; i < 7; i++) {" 11984 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);" 11985 "}" 11986 "this.y = function(x) { return x - 1; };" 11987 "var result = 0;" 11988 "for (var i = 0; i < 7; i++) {" 11989 " result += o.y(42);" 11990 "}"); 11991 CHECK_EQ(41 * 7, value->Int32Value()); 11992 } 11993 11994 11995 // Test the case when actual function to call sits on global object. 11996 THREADED_TEST(InterceptorCallICCachedFromGlobal) { 11997 v8::Isolate* isolate = CcTest::isolate(); 11998 v8::HandleScope scope(isolate); 11999 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12000 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12001 12002 LocalContext context; 12003 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12004 12005 v8::Handle<Value> value = CompileRun( 12006 "try {" 12007 " o.__proto__ = this;" 12008 " for (var i = 0; i < 10; i++) {" 12009 " var v = o.parseFloat('239');" 12010 " if (v != 239) throw v;" 12011 // Now it should be ICed and keep a reference to parseFloat. 12012 " }" 12013 " var result = 0;" 12014 " for (var i = 0; i < 10; i++) {" 12015 " result += o.parseFloat('239');" 12016 " }" 12017 " result" 12018 "} catch(e) {" 12019 " e" 12020 "};"); 12021 CHECK_EQ(239 * 10, value->Int32Value()); 12022 } 12023 12024 static void InterceptorCallICFastApi( 12025 Local<String> name, 12026 const v8::PropertyCallbackInfo<v8::Value>& info) { 12027 ApiTestFuzzer::Fuzz(); 12028 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 12029 int* call_count = 12030 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 12031 ++(*call_count); 12032 if ((*call_count) % 20 == 0) { 12033 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 12034 } 12035 } 12036 12037 static void FastApiCallback_TrivialSignature( 12038 const v8::FunctionCallbackInfo<v8::Value>& args) { 12039 ApiTestFuzzer::Fuzz(); 12040 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 12041 v8::Isolate* isolate = CcTest::isolate(); 12042 CHECK_EQ(isolate, args.GetIsolate()); 12043 CHECK_EQ(args.This(), args.Holder()); 12044 CHECK(args.Data()->Equals(v8_str("method_data"))); 12045 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 12046 } 12047 12048 static void FastApiCallback_SimpleSignature( 12049 const v8::FunctionCallbackInfo<v8::Value>& args) { 12050 ApiTestFuzzer::Fuzz(); 12051 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 12052 v8::Isolate* isolate = CcTest::isolate(); 12053 CHECK_EQ(isolate, args.GetIsolate()); 12054 CHECK_EQ(args.This()->GetPrototype(), args.Holder()); 12055 CHECK(args.Data()->Equals(v8_str("method_data"))); 12056 // Note, we're using HasRealNamedProperty instead of Has to avoid 12057 // invoking the interceptor again. 12058 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo"))); 12059 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 12060 } 12061 12062 12063 // Helper to maximize the odds of object moving. 12064 static void GenerateSomeGarbage() { 12065 CompileRun( 12066 "var garbage;" 12067 "for (var i = 0; i < 1000; i++) {" 12068 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 12069 "}" 12070 "garbage = undefined;"); 12071 } 12072 12073 12074 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 12075 static int count = 0; 12076 if (count++ % 3 == 0) { 12077 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 12078 // This should move the stub 12079 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 12080 } 12081 } 12082 12083 12084 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 12085 LocalContext context; 12086 v8::Isolate* isolate = context->GetIsolate(); 12087 v8::HandleScope scope(isolate); 12088 v8::Handle<v8::ObjectTemplate> nativeobject_templ = 12089 v8::ObjectTemplate::New(isolate); 12090 nativeobject_templ->Set(isolate, "callback", 12091 v8::FunctionTemplate::New(isolate, 12092 DirectApiCallback)); 12093 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 12094 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 12095 // call the api function multiple times to ensure direct call stub creation. 12096 CompileRun( 12097 "function f() {" 12098 " for (var i = 1; i <= 30; i++) {" 12099 " nativeobject.callback();" 12100 " }" 12101 "}" 12102 "f();"); 12103 } 12104 12105 12106 void ThrowingDirectApiCallback( 12107 const v8::FunctionCallbackInfo<v8::Value>& args) { 12108 args.GetIsolate()->ThrowException(v8_str("g")); 12109 } 12110 12111 12112 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 12113 LocalContext context; 12114 v8::Isolate* isolate = context->GetIsolate(); 12115 v8::HandleScope scope(isolate); 12116 v8::Handle<v8::ObjectTemplate> nativeobject_templ = 12117 v8::ObjectTemplate::New(isolate); 12118 nativeobject_templ->Set(isolate, "callback", 12119 v8::FunctionTemplate::New(isolate, 12120 ThrowingDirectApiCallback)); 12121 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 12122 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 12123 // call the api function multiple times to ensure direct call stub creation. 12124 v8::Handle<Value> result = CompileRun( 12125 "var result = '';" 12126 "function f() {" 12127 " for (var i = 1; i <= 5; i++) {" 12128 " try { nativeobject.callback(); } catch (e) { result += e; }" 12129 " }" 12130 "}" 12131 "f(); result;"); 12132 CHECK_EQ(v8_str("ggggg"), result); 12133 } 12134 12135 12136 static Handle<Value> DoDirectGetter() { 12137 if (++p_getter_count % 3 == 0) { 12138 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 12139 GenerateSomeGarbage(); 12140 } 12141 return v8_str("Direct Getter Result"); 12142 } 12143 12144 static void DirectGetterCallback( 12145 Local<String> name, 12146 const v8::PropertyCallbackInfo<v8::Value>& info) { 12147 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 12148 info.GetReturnValue().Set(DoDirectGetter()); 12149 } 12150 12151 12152 template<typename Accessor> 12153 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 12154 LocalContext context; 12155 v8::Isolate* isolate = context->GetIsolate(); 12156 v8::HandleScope scope(isolate); 12157 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12158 obj->SetAccessor(v8_str("p1"), accessor); 12159 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 12160 p_getter_count = 0; 12161 v8::Handle<v8::Value> result = CompileRun( 12162 "function f() {" 12163 " for (var i = 0; i < 30; i++) o1.p1;" 12164 " return o1.p1" 12165 "}" 12166 "f();"); 12167 CHECK_EQ(v8_str("Direct Getter Result"), result); 12168 CHECK_EQ(31, p_getter_count); 12169 } 12170 12171 12172 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 12173 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 12174 } 12175 12176 12177 void ThrowingDirectGetterCallback( 12178 Local<String> name, 12179 const v8::PropertyCallbackInfo<v8::Value>& info) { 12180 info.GetIsolate()->ThrowException(v8_str("g")); 12181 } 12182 12183 12184 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 12185 LocalContext context; 12186 v8::Isolate* isolate = context->GetIsolate(); 12187 v8::HandleScope scope(isolate); 12188 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12189 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 12190 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 12191 v8::Handle<Value> result = CompileRun( 12192 "var result = '';" 12193 "for (var i = 0; i < 5; i++) {" 12194 " try { o1.p1; } catch (e) { result += e; }" 12195 "}" 12196 "result;"); 12197 CHECK_EQ(v8_str("ggggg"), result); 12198 } 12199 12200 12201 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 12202 int interceptor_call_count = 0; 12203 v8::Isolate* isolate = CcTest::isolate(); 12204 v8::HandleScope scope(isolate); 12205 v8::Handle<v8::FunctionTemplate> fun_templ = 12206 v8::FunctionTemplate::New(isolate); 12207 v8::Handle<v8::FunctionTemplate> method_templ = 12208 v8::FunctionTemplate::New(isolate, 12209 FastApiCallback_TrivialSignature, 12210 v8_str("method_data"), 12211 v8::Handle<v8::Signature>()); 12212 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12213 proto_templ->Set(v8_str("method"), method_templ); 12214 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12215 templ->SetNamedPropertyHandler( 12216 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12217 v8::External::New(isolate, &interceptor_call_count)); 12218 LocalContext context; 12219 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12220 GenerateSomeGarbage(); 12221 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12222 CompileRun( 12223 "var result = 0;" 12224 "for (var i = 0; i < 100; i++) {" 12225 " result = o.method(41);" 12226 "}"); 12227 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12228 CHECK_EQ(100, interceptor_call_count); 12229 } 12230 12231 12232 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 12233 int interceptor_call_count = 0; 12234 v8::Isolate* isolate = CcTest::isolate(); 12235 v8::HandleScope scope(isolate); 12236 v8::Handle<v8::FunctionTemplate> fun_templ = 12237 v8::FunctionTemplate::New(isolate); 12238 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12239 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12240 v8::Signature::New(isolate, fun_templ)); 12241 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12242 proto_templ->Set(v8_str("method"), method_templ); 12243 fun_templ->SetHiddenPrototype(true); 12244 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12245 templ->SetNamedPropertyHandler( 12246 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12247 v8::External::New(isolate, &interceptor_call_count)); 12248 LocalContext context; 12249 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12250 GenerateSomeGarbage(); 12251 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12252 CompileRun( 12253 "o.foo = 17;" 12254 "var receiver = {};" 12255 "receiver.__proto__ = o;" 12256 "var result = 0;" 12257 "for (var i = 0; i < 100; i++) {" 12258 " result = receiver.method(41);" 12259 "}"); 12260 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12261 CHECK_EQ(100, interceptor_call_count); 12262 } 12263 12264 12265 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 12266 int interceptor_call_count = 0; 12267 v8::Isolate* isolate = CcTest::isolate(); 12268 v8::HandleScope scope(isolate); 12269 v8::Handle<v8::FunctionTemplate> fun_templ = 12270 v8::FunctionTemplate::New(isolate); 12271 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12272 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12273 v8::Signature::New(isolate, fun_templ)); 12274 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12275 proto_templ->Set(v8_str("method"), method_templ); 12276 fun_templ->SetHiddenPrototype(true); 12277 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12278 templ->SetNamedPropertyHandler( 12279 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12280 v8::External::New(isolate, &interceptor_call_count)); 12281 LocalContext context; 12282 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12283 GenerateSomeGarbage(); 12284 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12285 CompileRun( 12286 "o.foo = 17;" 12287 "var receiver = {};" 12288 "receiver.__proto__ = o;" 12289 "var result = 0;" 12290 "var saved_result = 0;" 12291 "for (var i = 0; i < 100; i++) {" 12292 " result = receiver.method(41);" 12293 " if (i == 50) {" 12294 " saved_result = result;" 12295 " receiver = {method: function(x) { return x - 1 }};" 12296 " }" 12297 "}"); 12298 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12299 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12300 CHECK_GE(interceptor_call_count, 50); 12301 } 12302 12303 12304 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 12305 int interceptor_call_count = 0; 12306 v8::Isolate* isolate = CcTest::isolate(); 12307 v8::HandleScope scope(isolate); 12308 v8::Handle<v8::FunctionTemplate> fun_templ = 12309 v8::FunctionTemplate::New(isolate); 12310 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12311 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12312 v8::Signature::New(isolate, fun_templ)); 12313 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12314 proto_templ->Set(v8_str("method"), method_templ); 12315 fun_templ->SetHiddenPrototype(true); 12316 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12317 templ->SetNamedPropertyHandler( 12318 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12319 v8::External::New(isolate, &interceptor_call_count)); 12320 LocalContext context; 12321 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12322 GenerateSomeGarbage(); 12323 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12324 CompileRun( 12325 "o.foo = 17;" 12326 "var receiver = {};" 12327 "receiver.__proto__ = o;" 12328 "var result = 0;" 12329 "var saved_result = 0;" 12330 "for (var i = 0; i < 100; i++) {" 12331 " result = receiver.method(41);" 12332 " if (i == 50) {" 12333 " saved_result = result;" 12334 " o.method = function(x) { return x - 1 };" 12335 " }" 12336 "}"); 12337 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12338 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12339 CHECK_GE(interceptor_call_count, 50); 12340 } 12341 12342 12343 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 12344 int interceptor_call_count = 0; 12345 v8::Isolate* isolate = CcTest::isolate(); 12346 v8::HandleScope scope(isolate); 12347 v8::Handle<v8::FunctionTemplate> fun_templ = 12348 v8::FunctionTemplate::New(isolate); 12349 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12350 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12351 v8::Signature::New(isolate, fun_templ)); 12352 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12353 proto_templ->Set(v8_str("method"), method_templ); 12354 fun_templ->SetHiddenPrototype(true); 12355 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12356 templ->SetNamedPropertyHandler( 12357 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12358 v8::External::New(isolate, &interceptor_call_count)); 12359 LocalContext context; 12360 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12361 GenerateSomeGarbage(); 12362 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12363 v8::TryCatch try_catch; 12364 CompileRun( 12365 "o.foo = 17;" 12366 "var receiver = {};" 12367 "receiver.__proto__ = o;" 12368 "var result = 0;" 12369 "var saved_result = 0;" 12370 "for (var i = 0; i < 100; i++) {" 12371 " result = receiver.method(41);" 12372 " if (i == 50) {" 12373 " saved_result = result;" 12374 " receiver = 333;" 12375 " }" 12376 "}"); 12377 CHECK(try_catch.HasCaught()); 12378 // TODO(verwaest): Adjust message. 12379 CHECK_EQ(v8_str("TypeError: undefined is not a function"), 12380 try_catch.Exception()->ToString()); 12381 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12382 CHECK_GE(interceptor_call_count, 50); 12383 } 12384 12385 12386 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 12387 int interceptor_call_count = 0; 12388 v8::Isolate* isolate = CcTest::isolate(); 12389 v8::HandleScope scope(isolate); 12390 v8::Handle<v8::FunctionTemplate> fun_templ = 12391 v8::FunctionTemplate::New(isolate); 12392 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12393 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12394 v8::Signature::New(isolate, fun_templ)); 12395 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12396 proto_templ->Set(v8_str("method"), method_templ); 12397 fun_templ->SetHiddenPrototype(true); 12398 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12399 templ->SetNamedPropertyHandler( 12400 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12401 v8::External::New(isolate, &interceptor_call_count)); 12402 LocalContext context; 12403 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12404 GenerateSomeGarbage(); 12405 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12406 v8::TryCatch try_catch; 12407 CompileRun( 12408 "o.foo = 17;" 12409 "var receiver = {};" 12410 "receiver.__proto__ = o;" 12411 "var result = 0;" 12412 "var saved_result = 0;" 12413 "for (var i = 0; i < 100; i++) {" 12414 " result = receiver.method(41);" 12415 " if (i == 50) {" 12416 " saved_result = result;" 12417 " receiver = {method: receiver.method};" 12418 " }" 12419 "}"); 12420 CHECK(try_catch.HasCaught()); 12421 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 12422 try_catch.Exception()->ToString()); 12423 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12424 CHECK_GE(interceptor_call_count, 50); 12425 } 12426 12427 12428 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 12429 v8::Isolate* isolate = CcTest::isolate(); 12430 v8::HandleScope scope(isolate); 12431 v8::Handle<v8::FunctionTemplate> fun_templ = 12432 v8::FunctionTemplate::New(isolate); 12433 v8::Handle<v8::FunctionTemplate> method_templ = 12434 v8::FunctionTemplate::New(isolate, 12435 FastApiCallback_TrivialSignature, 12436 v8_str("method_data"), 12437 v8::Handle<v8::Signature>()); 12438 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12439 proto_templ->Set(v8_str("method"), method_templ); 12440 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12441 USE(templ); 12442 LocalContext context; 12443 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12444 GenerateSomeGarbage(); 12445 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12446 CompileRun( 12447 "var result = 0;" 12448 "for (var i = 0; i < 100; i++) {" 12449 " result = o.method(41);" 12450 "}"); 12451 12452 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12453 } 12454 12455 12456 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 12457 v8::Isolate* isolate = CcTest::isolate(); 12458 v8::HandleScope scope(isolate); 12459 v8::Handle<v8::FunctionTemplate> fun_templ = 12460 v8::FunctionTemplate::New(isolate); 12461 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12462 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12463 v8::Signature::New(isolate, fun_templ)); 12464 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12465 proto_templ->Set(v8_str("method"), method_templ); 12466 fun_templ->SetHiddenPrototype(true); 12467 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12468 CHECK(!templ.IsEmpty()); 12469 LocalContext context; 12470 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12471 GenerateSomeGarbage(); 12472 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12473 CompileRun( 12474 "o.foo = 17;" 12475 "var receiver = {};" 12476 "receiver.__proto__ = o;" 12477 "var result = 0;" 12478 "for (var i = 0; i < 100; i++) {" 12479 " result = receiver.method(41);" 12480 "}"); 12481 12482 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12483 } 12484 12485 12486 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 12487 v8::Isolate* isolate = CcTest::isolate(); 12488 v8::HandleScope scope(isolate); 12489 v8::Handle<v8::FunctionTemplate> fun_templ = 12490 v8::FunctionTemplate::New(isolate); 12491 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12492 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12493 v8::Signature::New(isolate, fun_templ)); 12494 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12495 proto_templ->Set(v8_str("method"), method_templ); 12496 fun_templ->SetHiddenPrototype(true); 12497 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12498 CHECK(!templ.IsEmpty()); 12499 LocalContext context; 12500 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12501 GenerateSomeGarbage(); 12502 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12503 CompileRun( 12504 "o.foo = 17;" 12505 "var receiver = {};" 12506 "receiver.__proto__ = o;" 12507 "var result = 0;" 12508 "var saved_result = 0;" 12509 "for (var i = 0; i < 100; i++) {" 12510 " result = receiver.method(41);" 12511 " if (i == 50) {" 12512 " saved_result = result;" 12513 " receiver = {method: function(x) { return x - 1 }};" 12514 " }" 12515 "}"); 12516 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12517 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12518 } 12519 12520 12521 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 12522 v8::Isolate* isolate = CcTest::isolate(); 12523 v8::HandleScope scope(isolate); 12524 v8::Handle<v8::FunctionTemplate> fun_templ = 12525 v8::FunctionTemplate::New(isolate); 12526 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12527 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12528 v8::Signature::New(isolate, fun_templ)); 12529 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12530 proto_templ->Set(v8_str("method"), method_templ); 12531 fun_templ->SetHiddenPrototype(true); 12532 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12533 CHECK(!templ.IsEmpty()); 12534 LocalContext context; 12535 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12536 GenerateSomeGarbage(); 12537 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12538 v8::TryCatch try_catch; 12539 CompileRun( 12540 "o.foo = 17;" 12541 "var receiver = {};" 12542 "receiver.__proto__ = o;" 12543 "var result = 0;" 12544 "var saved_result = 0;" 12545 "for (var i = 0; i < 100; i++) {" 12546 " result = receiver.method(41);" 12547 " if (i == 50) {" 12548 " saved_result = result;" 12549 " receiver = 333;" 12550 " }" 12551 "}"); 12552 CHECK(try_catch.HasCaught()); 12553 // TODO(verwaest): Adjust message. 12554 CHECK_EQ(v8_str("TypeError: undefined is not a function"), 12555 try_catch.Exception()->ToString()); 12556 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12557 } 12558 12559 12560 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 12561 v8::Isolate* isolate = CcTest::isolate(); 12562 v8::HandleScope scope(isolate); 12563 v8::Handle<v8::FunctionTemplate> fun_templ = 12564 v8::FunctionTemplate::New(isolate); 12565 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12566 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12567 v8::Signature::New(isolate, fun_templ)); 12568 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12569 proto_templ->Set(v8_str("method"), method_templ); 12570 fun_templ->SetHiddenPrototype(true); 12571 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12572 CHECK(!templ.IsEmpty()); 12573 LocalContext context; 12574 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12575 GenerateSomeGarbage(); 12576 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12577 v8::TryCatch try_catch; 12578 CompileRun( 12579 "o.foo = 17;" 12580 "var receiver = {};" 12581 "receiver.__proto__ = o;" 12582 "var result = 0;" 12583 "var saved_result = 0;" 12584 "for (var i = 0; i < 100; i++) {" 12585 " result = receiver.method(41);" 12586 " if (i == 50) {" 12587 " saved_result = result;" 12588 " receiver = Object.create(receiver);" 12589 " }" 12590 "}"); 12591 CHECK(try_catch.HasCaught()); 12592 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 12593 try_catch.Exception()->ToString()); 12594 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12595 } 12596 12597 12598 v8::Handle<Value> keyed_call_ic_function; 12599 12600 static void InterceptorKeyedCallICGetter( 12601 Local<String> name, 12602 const v8::PropertyCallbackInfo<v8::Value>& info) { 12603 ApiTestFuzzer::Fuzz(); 12604 if (v8_str("x")->Equals(name)) { 12605 info.GetReturnValue().Set(keyed_call_ic_function); 12606 } 12607 } 12608 12609 12610 // Test the case when we stored cacheable lookup into 12611 // a stub, but the function name changed (to another cacheable function). 12612 THREADED_TEST(InterceptorKeyedCallICKeyChange1) { 12613 v8::Isolate* isolate = CcTest::isolate(); 12614 v8::HandleScope scope(isolate); 12615 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12616 templ->SetNamedPropertyHandler(NoBlockGetterX); 12617 LocalContext context; 12618 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12619 CompileRun( 12620 "proto = new Object();" 12621 "proto.y = function(x) { return x + 1; };" 12622 "proto.z = function(x) { return x - 1; };" 12623 "o.__proto__ = proto;" 12624 "var result = 0;" 12625 "var method = 'y';" 12626 "for (var i = 0; i < 10; i++) {" 12627 " if (i == 5) { method = 'z'; };" 12628 " result += o[method](41);" 12629 "}"); 12630 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12631 } 12632 12633 12634 // Test the case when we stored cacheable lookup into 12635 // a stub, but the function name changed (and the new function is present 12636 // both before and after the interceptor in the prototype chain). 12637 THREADED_TEST(InterceptorKeyedCallICKeyChange2) { 12638 v8::Isolate* isolate = CcTest::isolate(); 12639 v8::HandleScope scope(isolate); 12640 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12641 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); 12642 LocalContext context; 12643 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); 12644 keyed_call_ic_function = 12645 v8_compile("function f(x) { return x - 1; }; f")->Run(); 12646 CompileRun( 12647 "o = new Object();" 12648 "proto2 = new Object();" 12649 "o.y = function(x) { return x + 1; };" 12650 "proto2.y = function(x) { return x + 2; };" 12651 "o.__proto__ = proto1;" 12652 "proto1.__proto__ = proto2;" 12653 "var result = 0;" 12654 "var method = 'x';" 12655 "for (var i = 0; i < 10; i++) {" 12656 " if (i == 5) { method = 'y'; };" 12657 " result += o[method](41);" 12658 "}"); 12659 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12660 } 12661 12662 12663 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit 12664 // on the global object. 12665 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { 12666 v8::Isolate* isolate = CcTest::isolate(); 12667 v8::HandleScope scope(isolate); 12668 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12669 templ->SetNamedPropertyHandler(NoBlockGetterX); 12670 LocalContext context; 12671 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12672 CompileRun( 12673 "function inc(x) { return x + 1; };" 12674 "inc(1);" 12675 "function dec(x) { return x - 1; };" 12676 "dec(1);" 12677 "o.__proto__ = this;" 12678 "this.__proto__.x = inc;" 12679 "this.__proto__.y = dec;" 12680 "var result = 0;" 12681 "var method = 'x';" 12682 "for (var i = 0; i < 10; i++) {" 12683 " if (i == 5) { method = 'y'; };" 12684 " result += o[method](41);" 12685 "}"); 12686 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12687 } 12688 12689 12690 // Test the case when actual function to call sits on global object. 12691 THREADED_TEST(InterceptorKeyedCallICFromGlobal) { 12692 v8::Isolate* isolate = CcTest::isolate(); 12693 v8::HandleScope scope(isolate); 12694 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12695 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12696 LocalContext context; 12697 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12698 12699 CompileRun( 12700 "function len(x) { return x.length; };" 12701 "o.__proto__ = this;" 12702 "var m = 'parseFloat';" 12703 "var result = 0;" 12704 "for (var i = 0; i < 10; i++) {" 12705 " if (i == 5) {" 12706 " m = 'len';" 12707 " saved_result = result;" 12708 " };" 12709 " result = o[m]('239');" 12710 "}"); 12711 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); 12712 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12713 } 12714 12715 12716 // Test the map transition before the interceptor. 12717 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { 12718 v8::Isolate* isolate = CcTest::isolate(); 12719 v8::HandleScope scope(isolate); 12720 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12721 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12722 LocalContext context; 12723 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); 12724 12725 CompileRun( 12726 "var o = new Object();" 12727 "o.__proto__ = proto;" 12728 "o.method = function(x) { return x + 1; };" 12729 "var m = 'method';" 12730 "var result = 0;" 12731 "for (var i = 0; i < 10; i++) {" 12732 " if (i == 5) { o.method = function(x) { return x - 1; }; };" 12733 " result += o[m](41);" 12734 "}"); 12735 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12736 } 12737 12738 12739 // Test the map transition after the interceptor. 12740 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { 12741 v8::Isolate* isolate = CcTest::isolate(); 12742 v8::HandleScope scope(isolate); 12743 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12744 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12745 LocalContext context; 12746 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12747 12748 CompileRun( 12749 "var proto = new Object();" 12750 "o.__proto__ = proto;" 12751 "proto.method = function(x) { return x + 1; };" 12752 "var m = 'method';" 12753 "var result = 0;" 12754 "for (var i = 0; i < 10; i++) {" 12755 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" 12756 " result += o[m](41);" 12757 "}"); 12758 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12759 } 12760 12761 12762 static int interceptor_call_count = 0; 12763 12764 static void InterceptorICRefErrorGetter( 12765 Local<String> name, 12766 const v8::PropertyCallbackInfo<v8::Value>& info) { 12767 ApiTestFuzzer::Fuzz(); 12768 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { 12769 info.GetReturnValue().Set(call_ic_function2); 12770 } 12771 } 12772 12773 12774 // This test should hit load and call ICs for the interceptor case. 12775 // Once in a while, the interceptor will reply that a property was not 12776 // found in which case we should get a reference error. 12777 THREADED_TEST(InterceptorICReferenceErrors) { 12778 v8::Isolate* isolate = CcTest::isolate(); 12779 v8::HandleScope scope(isolate); 12780 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12781 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter); 12782 LocalContext context(0, templ, v8::Handle<Value>()); 12783 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); 12784 v8::Handle<Value> value = CompileRun( 12785 "function f() {" 12786 " for (var i = 0; i < 1000; i++) {" 12787 " try { x; } catch(e) { return true; }" 12788 " }" 12789 " return false;" 12790 "};" 12791 "f();"); 12792 CHECK_EQ(true, value->BooleanValue()); 12793 interceptor_call_count = 0; 12794 value = CompileRun( 12795 "function g() {" 12796 " for (var i = 0; i < 1000; i++) {" 12797 " try { x(42); } catch(e) { return true; }" 12798 " }" 12799 " return false;" 12800 "};" 12801 "g();"); 12802 CHECK_EQ(true, value->BooleanValue()); 12803 } 12804 12805 12806 static int interceptor_ic_exception_get_count = 0; 12807 12808 static void InterceptorICExceptionGetter( 12809 Local<String> name, 12810 const v8::PropertyCallbackInfo<v8::Value>& info) { 12811 ApiTestFuzzer::Fuzz(); 12812 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { 12813 info.GetReturnValue().Set(call_ic_function3); 12814 } 12815 if (interceptor_ic_exception_get_count == 20) { 12816 info.GetIsolate()->ThrowException(v8_num(42)); 12817 return; 12818 } 12819 } 12820 12821 12822 // Test interceptor load/call IC where the interceptor throws an 12823 // exception once in a while. 12824 THREADED_TEST(InterceptorICGetterExceptions) { 12825 interceptor_ic_exception_get_count = 0; 12826 v8::Isolate* isolate = CcTest::isolate(); 12827 v8::HandleScope scope(isolate); 12828 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12829 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter); 12830 LocalContext context(0, templ, v8::Handle<Value>()); 12831 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); 12832 v8::Handle<Value> value = CompileRun( 12833 "function f() {" 12834 " for (var i = 0; i < 100; i++) {" 12835 " try { x; } catch(e) { return true; }" 12836 " }" 12837 " return false;" 12838 "};" 12839 "f();"); 12840 CHECK_EQ(true, value->BooleanValue()); 12841 interceptor_ic_exception_get_count = 0; 12842 value = CompileRun( 12843 "function f() {" 12844 " for (var i = 0; i < 100; i++) {" 12845 " try { x(42); } catch(e) { return true; }" 12846 " }" 12847 " return false;" 12848 "};" 12849 "f();"); 12850 CHECK_EQ(true, value->BooleanValue()); 12851 } 12852 12853 12854 static int interceptor_ic_exception_set_count = 0; 12855 12856 static void InterceptorICExceptionSetter( 12857 Local<String> key, 12858 Local<Value> value, 12859 const v8::PropertyCallbackInfo<v8::Value>& info) { 12860 ApiTestFuzzer::Fuzz(); 12861 if (++interceptor_ic_exception_set_count > 20) { 12862 info.GetIsolate()->ThrowException(v8_num(42)); 12863 } 12864 } 12865 12866 12867 // Test interceptor store IC where the interceptor throws an exception 12868 // once in a while. 12869 THREADED_TEST(InterceptorICSetterExceptions) { 12870 interceptor_ic_exception_set_count = 0; 12871 v8::Isolate* isolate = CcTest::isolate(); 12872 v8::HandleScope scope(isolate); 12873 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12874 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter); 12875 LocalContext context(0, templ, v8::Handle<Value>()); 12876 v8::Handle<Value> value = CompileRun( 12877 "function f() {" 12878 " for (var i = 0; i < 100; i++) {" 12879 " try { x = 42; } catch(e) { return true; }" 12880 " }" 12881 " return false;" 12882 "};" 12883 "f();"); 12884 CHECK_EQ(true, value->BooleanValue()); 12885 } 12886 12887 12888 // Test that we ignore null interceptors. 12889 THREADED_TEST(NullNamedInterceptor) { 12890 v8::Isolate* isolate = CcTest::isolate(); 12891 v8::HandleScope scope(isolate); 12892 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12893 templ->SetNamedPropertyHandler( 12894 static_cast<v8::NamedPropertyGetterCallback>(0)); 12895 LocalContext context; 12896 templ->Set(CcTest::isolate(), "x", v8_num(42)); 12897 v8::Handle<v8::Object> obj = templ->NewInstance(); 12898 context->Global()->Set(v8_str("obj"), obj); 12899 v8::Handle<Value> value = CompileRun("obj.x"); 12900 CHECK(value->IsInt32()); 12901 CHECK_EQ(42, value->Int32Value()); 12902 } 12903 12904 12905 // Test that we ignore null interceptors. 12906 THREADED_TEST(NullIndexedInterceptor) { 12907 v8::Isolate* isolate = CcTest::isolate(); 12908 v8::HandleScope scope(isolate); 12909 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12910 templ->SetIndexedPropertyHandler( 12911 static_cast<v8::IndexedPropertyGetterCallback>(0)); 12912 LocalContext context; 12913 templ->Set(CcTest::isolate(), "42", v8_num(42)); 12914 v8::Handle<v8::Object> obj = templ->NewInstance(); 12915 context->Global()->Set(v8_str("obj"), obj); 12916 v8::Handle<Value> value = CompileRun("obj[42]"); 12917 CHECK(value->IsInt32()); 12918 CHECK_EQ(42, value->Int32Value()); 12919 } 12920 12921 12922 THREADED_TEST(NamedPropertyHandlerGetterAttributes) { 12923 v8::Isolate* isolate = CcTest::isolate(); 12924 v8::HandleScope scope(isolate); 12925 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 12926 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter); 12927 LocalContext env; 12928 env->Global()->Set(v8_str("obj"), 12929 templ->GetFunction()->NewInstance()); 12930 ExpectTrue("obj.x === 42"); 12931 ExpectTrue("!obj.propertyIsEnumerable('x')"); 12932 } 12933 12934 12935 static void ThrowingGetter(Local<String> name, 12936 const v8::PropertyCallbackInfo<v8::Value>& info) { 12937 ApiTestFuzzer::Fuzz(); 12938 info.GetIsolate()->ThrowException(Handle<Value>()); 12939 info.GetReturnValue().SetUndefined(); 12940 } 12941 12942 12943 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 12944 LocalContext context; 12945 HandleScope scope(context->GetIsolate()); 12946 12947 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 12948 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 12949 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 12950 12951 Local<Object> instance = templ->GetFunction()->NewInstance(); 12952 12953 Local<Object> another = Object::New(context->GetIsolate()); 12954 another->SetPrototype(instance); 12955 12956 Local<Object> with_js_getter = CompileRun( 12957 "o = {};\n" 12958 "o.__defineGetter__('f', function() { throw undefined; });\n" 12959 "o\n").As<Object>(); 12960 CHECK(!with_js_getter.IsEmpty()); 12961 12962 TryCatch try_catch; 12963 12964 Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); 12965 CHECK(try_catch.HasCaught()); 12966 try_catch.Reset(); 12967 CHECK(result.IsEmpty()); 12968 12969 result = another->GetRealNamedProperty(v8_str("f")); 12970 CHECK(try_catch.HasCaught()); 12971 try_catch.Reset(); 12972 CHECK(result.IsEmpty()); 12973 12974 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); 12975 CHECK(try_catch.HasCaught()); 12976 try_catch.Reset(); 12977 CHECK(result.IsEmpty()); 12978 12979 result = another->Get(v8_str("f")); 12980 CHECK(try_catch.HasCaught()); 12981 try_catch.Reset(); 12982 CHECK(result.IsEmpty()); 12983 12984 result = with_js_getter->GetRealNamedProperty(v8_str("f")); 12985 CHECK(try_catch.HasCaught()); 12986 try_catch.Reset(); 12987 CHECK(result.IsEmpty()); 12988 12989 result = with_js_getter->Get(v8_str("f")); 12990 CHECK(try_catch.HasCaught()); 12991 try_catch.Reset(); 12992 CHECK(result.IsEmpty()); 12993 } 12994 12995 12996 static void ThrowingCallbackWithTryCatch( 12997 const v8::FunctionCallbackInfo<v8::Value>& args) { 12998 TryCatch try_catch; 12999 // Verboseness is important: it triggers message delivery which can call into 13000 // external code. 13001 try_catch.SetVerbose(true); 13002 CompileRun("throw 'from JS';"); 13003 CHECK(try_catch.HasCaught()); 13004 CHECK(!CcTest::i_isolate()->has_pending_exception()); 13005 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 13006 } 13007 13008 13009 static int call_depth; 13010 13011 13012 static void WithTryCatch(Handle<Message> message, Handle<Value> data) { 13013 TryCatch try_catch; 13014 } 13015 13016 13017 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) { 13018 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 13019 } 13020 13021 13022 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) { 13023 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi")); 13024 } 13025 13026 13027 static void WebKitLike(Handle<Message> message, Handle<Value> data) { 13028 Handle<String> errorMessageString = message->Get(); 13029 CHECK(!errorMessageString.IsEmpty()); 13030 message->GetStackTrace(); 13031 message->GetScriptResourceName(); 13032 } 13033 13034 13035 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 13036 LocalContext context; 13037 v8::Isolate* isolate = context->GetIsolate(); 13038 HandleScope scope(isolate); 13039 13040 Local<Function> func = 13041 FunctionTemplate::New(isolate, 13042 ThrowingCallbackWithTryCatch)->GetFunction(); 13043 context->Global()->Set(v8_str("func"), func); 13044 13045 MessageCallback callbacks[] = 13046 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 13047 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 13048 MessageCallback callback = callbacks[i]; 13049 if (callback != NULL) { 13050 V8::AddMessageListener(callback); 13051 } 13052 // Some small number to control number of times message handler should 13053 // throw an exception. 13054 call_depth = 5; 13055 ExpectFalse( 13056 "var thrown = false;\n" 13057 "try { func(); } catch(e) { thrown = true; }\n" 13058 "thrown\n"); 13059 if (callback != NULL) { 13060 V8::RemoveMessageListeners(callback); 13061 } 13062 } 13063 } 13064 13065 13066 static void ParentGetter(Local<String> name, 13067 const v8::PropertyCallbackInfo<v8::Value>& info) { 13068 ApiTestFuzzer::Fuzz(); 13069 info.GetReturnValue().Set(v8_num(1)); 13070 } 13071 13072 13073 static void ChildGetter(Local<String> name, 13074 const v8::PropertyCallbackInfo<v8::Value>& info) { 13075 ApiTestFuzzer::Fuzz(); 13076 info.GetReturnValue().Set(v8_num(42)); 13077 } 13078 13079 13080 THREADED_TEST(Overriding) { 13081 LocalContext context; 13082 v8::Isolate* isolate = context->GetIsolate(); 13083 v8::HandleScope scope(isolate); 13084 13085 // Parent template. 13086 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate); 13087 Local<ObjectTemplate> parent_instance_templ = 13088 parent_templ->InstanceTemplate(); 13089 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 13090 13091 // Template that inherits from the parent template. 13092 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate); 13093 Local<ObjectTemplate> child_instance_templ = 13094 child_templ->InstanceTemplate(); 13095 child_templ->Inherit(parent_templ); 13096 // Override 'f'. The child version of 'f' should get called for child 13097 // instances. 13098 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 13099 // Add 'g' twice. The 'g' added last should get called for instances. 13100 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 13101 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 13102 13103 // Add 'h' as an accessor to the proto template with ReadOnly attributes 13104 // so 'h' can be shadowed on the instance object. 13105 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 13106 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 13107 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 13108 13109 // Add 'i' as an accessor to the instance template with ReadOnly attributes 13110 // but the attribute does not have effect because it is duplicated with 13111 // NULL setter. 13112 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 13113 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 13114 13115 13116 13117 // Instantiate the child template. 13118 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance(); 13119 13120 // Check that the child function overrides the parent one. 13121 context->Global()->Set(v8_str("o"), instance); 13122 Local<Value> value = v8_compile("o.f")->Run(); 13123 // Check that the 'g' that was added last is hit. 13124 CHECK_EQ(42, value->Int32Value()); 13125 value = v8_compile("o.g")->Run(); 13126 CHECK_EQ(42, value->Int32Value()); 13127 13128 // Check that 'h' cannot be shadowed. 13129 value = v8_compile("o.h = 3; o.h")->Run(); 13130 CHECK_EQ(1, value->Int32Value()); 13131 13132 // Check that 'i' cannot be shadowed or changed. 13133 value = v8_compile("o.i = 3; o.i")->Run(); 13134 CHECK_EQ(42, value->Int32Value()); 13135 } 13136 13137 13138 static void IsConstructHandler( 13139 const v8::FunctionCallbackInfo<v8::Value>& args) { 13140 ApiTestFuzzer::Fuzz(); 13141 args.GetReturnValue().Set(args.IsConstructCall()); 13142 } 13143 13144 13145 THREADED_TEST(IsConstructCall) { 13146 v8::Isolate* isolate = CcTest::isolate(); 13147 v8::HandleScope scope(isolate); 13148 13149 // Function template with call handler. 13150 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13151 templ->SetCallHandler(IsConstructHandler); 13152 13153 LocalContext context; 13154 13155 context->Global()->Set(v8_str("f"), templ->GetFunction()); 13156 Local<Value> value = v8_compile("f()")->Run(); 13157 CHECK(!value->BooleanValue()); 13158 value = v8_compile("new f()")->Run(); 13159 CHECK(value->BooleanValue()); 13160 } 13161 13162 13163 THREADED_TEST(ObjectProtoToString) { 13164 v8::Isolate* isolate = CcTest::isolate(); 13165 v8::HandleScope scope(isolate); 13166 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13167 templ->SetClassName(v8_str("MyClass")); 13168 13169 LocalContext context; 13170 13171 Local<String> customized_tostring = v8_str("customized toString"); 13172 13173 // Replace Object.prototype.toString 13174 v8_compile("Object.prototype.toString = function() {" 13175 " return 'customized toString';" 13176 "}")->Run(); 13177 13178 // Normal ToString call should call replaced Object.prototype.toString 13179 Local<v8::Object> instance = templ->GetFunction()->NewInstance(); 13180 Local<String> value = instance->ToString(); 13181 CHECK(value->IsString() && value->Equals(customized_tostring)); 13182 13183 // ObjectProtoToString should not call replace toString function. 13184 value = instance->ObjectProtoToString(); 13185 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]"))); 13186 13187 // Check global 13188 value = context->Global()->ObjectProtoToString(); 13189 CHECK(value->IsString() && value->Equals(v8_str("[object global]"))); 13190 13191 // Check ordinary object 13192 Local<Value> object = v8_compile("new Object()")->Run(); 13193 value = object.As<v8::Object>()->ObjectProtoToString(); 13194 CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); 13195 } 13196 13197 13198 THREADED_TEST(ObjectGetConstructorName) { 13199 LocalContext context; 13200 v8::HandleScope scope(context->GetIsolate()); 13201 v8_compile("function Parent() {};" 13202 "function Child() {};" 13203 "Child.prototype = new Parent();" 13204 "var outer = { inner: function() { } };" 13205 "var p = new Parent();" 13206 "var c = new Child();" 13207 "var x = new outer.inner();")->Run(); 13208 13209 Local<v8::Value> p = context->Global()->Get(v8_str("p")); 13210 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals( 13211 v8_str("Parent"))); 13212 13213 Local<v8::Value> c = context->Global()->Get(v8_str("c")); 13214 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals( 13215 v8_str("Child"))); 13216 13217 Local<v8::Value> x = context->Global()->Get(v8_str("x")); 13218 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals( 13219 v8_str("outer.inner"))); 13220 } 13221 13222 13223 bool ApiTestFuzzer::fuzzing_ = false; 13224 i::Semaphore ApiTestFuzzer::all_tests_done_(0); 13225 int ApiTestFuzzer::active_tests_; 13226 int ApiTestFuzzer::tests_being_run_; 13227 int ApiTestFuzzer::current_; 13228 13229 13230 // We are in a callback and want to switch to another thread (if we 13231 // are currently running the thread fuzzing test). 13232 void ApiTestFuzzer::Fuzz() { 13233 if (!fuzzing_) return; 13234 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 13235 test->ContextSwitch(); 13236 } 13237 13238 13239 // Let the next thread go. Since it is also waiting on the V8 lock it may 13240 // not start immediately. 13241 bool ApiTestFuzzer::NextThread() { 13242 int test_position = GetNextTestNumber(); 13243 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 13244 if (test_position == current_) { 13245 if (kLogThreading) 13246 printf("Stay with %s\n", test_name); 13247 return false; 13248 } 13249 if (kLogThreading) { 13250 printf("Switch from %s to %s\n", 13251 test_name, 13252 RegisterThreadedTest::nth(test_position)->name()); 13253 } 13254 current_ = test_position; 13255 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal(); 13256 return true; 13257 } 13258 13259 13260 void ApiTestFuzzer::Run() { 13261 // When it is our turn... 13262 gate_.Wait(); 13263 { 13264 // ... get the V8 lock and start running the test. 13265 v8::Locker locker(CcTest::isolate()); 13266 CallTest(); 13267 } 13268 // This test finished. 13269 active_ = false; 13270 active_tests_--; 13271 // If it was the last then signal that fact. 13272 if (active_tests_ == 0) { 13273 all_tests_done_.Signal(); 13274 } else { 13275 // Otherwise select a new test and start that. 13276 NextThread(); 13277 } 13278 } 13279 13280 13281 static unsigned linear_congruential_generator; 13282 13283 13284 void ApiTestFuzzer::SetUp(PartOfTest part) { 13285 linear_congruential_generator = i::FLAG_testing_prng_seed; 13286 fuzzing_ = true; 13287 int count = RegisterThreadedTest::count(); 13288 int start = count * part / (LAST_PART + 1); 13289 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 13290 active_tests_ = tests_being_run_ = end - start + 1; 13291 for (int i = 0; i < tests_being_run_; i++) { 13292 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 13293 } 13294 for (int i = 0; i < active_tests_; i++) { 13295 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 13296 } 13297 } 13298 13299 13300 static void CallTestNumber(int test_number) { 13301 (RegisterThreadedTest::nth(test_number)->callback())(); 13302 } 13303 13304 13305 void ApiTestFuzzer::RunAllTests() { 13306 // Set off the first test. 13307 current_ = -1; 13308 NextThread(); 13309 // Wait till they are all done. 13310 all_tests_done_.Wait(); 13311 } 13312 13313 13314 int ApiTestFuzzer::GetNextTestNumber() { 13315 int next_test; 13316 do { 13317 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 13318 linear_congruential_generator *= 1664525u; 13319 linear_congruential_generator += 1013904223u; 13320 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 13321 return next_test; 13322 } 13323 13324 13325 void ApiTestFuzzer::ContextSwitch() { 13326 // If the new thread is the same as the current thread there is nothing to do. 13327 if (NextThread()) { 13328 // Now it can start. 13329 v8::Unlocker unlocker(CcTest::isolate()); 13330 // Wait till someone starts us again. 13331 gate_.Wait(); 13332 // And we're off. 13333 } 13334 } 13335 13336 13337 void ApiTestFuzzer::TearDown() { 13338 fuzzing_ = false; 13339 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 13340 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 13341 if (fuzzer != NULL) fuzzer->Join(); 13342 } 13343 } 13344 13345 13346 // Lets not be needlessly self-referential. 13347 TEST(Threading1) { 13348 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 13349 ApiTestFuzzer::RunAllTests(); 13350 ApiTestFuzzer::TearDown(); 13351 } 13352 13353 13354 TEST(Threading2) { 13355 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 13356 ApiTestFuzzer::RunAllTests(); 13357 ApiTestFuzzer::TearDown(); 13358 } 13359 13360 13361 TEST(Threading3) { 13362 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 13363 ApiTestFuzzer::RunAllTests(); 13364 ApiTestFuzzer::TearDown(); 13365 } 13366 13367 13368 TEST(Threading4) { 13369 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 13370 ApiTestFuzzer::RunAllTests(); 13371 ApiTestFuzzer::TearDown(); 13372 } 13373 13374 13375 void ApiTestFuzzer::CallTest() { 13376 v8::Isolate::Scope scope(CcTest::isolate()); 13377 if (kLogThreading) 13378 printf("Start test %d\n", test_number_); 13379 CallTestNumber(test_number_); 13380 if (kLogThreading) 13381 printf("End test %d\n", test_number_); 13382 } 13383 13384 13385 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 13386 v8::Isolate* isolate = args.GetIsolate(); 13387 CHECK(v8::Locker::IsLocked(isolate)); 13388 ApiTestFuzzer::Fuzz(); 13389 v8::Unlocker unlocker(isolate); 13390 const char* code = "throw 7;"; 13391 { 13392 v8::Locker nested_locker(isolate); 13393 v8::HandleScope scope(isolate); 13394 v8::Handle<Value> exception; 13395 { v8::TryCatch try_catch; 13396 v8::Handle<Value> value = CompileRun(code); 13397 CHECK(value.IsEmpty()); 13398 CHECK(try_catch.HasCaught()); 13399 // Make sure to wrap the exception in a new handle because 13400 // the handle returned from the TryCatch is destroyed 13401 // when the TryCatch is destroyed. 13402 exception = Local<Value>::New(isolate, try_catch.Exception()); 13403 } 13404 args.GetIsolate()->ThrowException(exception); 13405 } 13406 } 13407 13408 13409 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 13410 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13411 ApiTestFuzzer::Fuzz(); 13412 v8::Unlocker unlocker(CcTest::isolate()); 13413 const char* code = "throw 7;"; 13414 { 13415 v8::Locker nested_locker(CcTest::isolate()); 13416 v8::HandleScope scope(args.GetIsolate()); 13417 v8::Handle<Value> value = CompileRun(code); 13418 CHECK(value.IsEmpty()); 13419 args.GetReturnValue().Set(v8_str("foo")); 13420 } 13421 } 13422 13423 13424 // These are locking tests that don't need to be run again 13425 // as part of the locking aggregation tests. 13426 TEST(NestedLockers) { 13427 v8::Isolate* isolate = CcTest::isolate(); 13428 v8::Locker locker(isolate); 13429 CHECK(v8::Locker::IsLocked(isolate)); 13430 LocalContext env; 13431 v8::HandleScope scope(env->GetIsolate()); 13432 Local<v8::FunctionTemplate> fun_templ = 13433 v8::FunctionTemplate::New(isolate, ThrowInJS); 13434 Local<Function> fun = fun_templ->GetFunction(); 13435 env->Global()->Set(v8_str("throw_in_js"), fun); 13436 Local<Script> script = v8_compile("(function () {" 13437 " try {" 13438 " throw_in_js();" 13439 " return 42;" 13440 " } catch (e) {" 13441 " return e * 13;" 13442 " }" 13443 "})();"); 13444 CHECK_EQ(91, script->Run()->Int32Value()); 13445 } 13446 13447 13448 // These are locking tests that don't need to be run again 13449 // as part of the locking aggregation tests. 13450 TEST(NestedLockersNoTryCatch) { 13451 v8::Locker locker(CcTest::isolate()); 13452 LocalContext env; 13453 v8::HandleScope scope(env->GetIsolate()); 13454 Local<v8::FunctionTemplate> fun_templ = 13455 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch); 13456 Local<Function> fun = fun_templ->GetFunction(); 13457 env->Global()->Set(v8_str("throw_in_js"), fun); 13458 Local<Script> script = v8_compile("(function () {" 13459 " try {" 13460 " throw_in_js();" 13461 " return 42;" 13462 " } catch (e) {" 13463 " return e * 13;" 13464 " }" 13465 "})();"); 13466 CHECK_EQ(91, script->Run()->Int32Value()); 13467 } 13468 13469 13470 THREADED_TEST(RecursiveLocking) { 13471 v8::Locker locker(CcTest::isolate()); 13472 { 13473 v8::Locker locker2(CcTest::isolate()); 13474 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13475 } 13476 } 13477 13478 13479 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 13480 ApiTestFuzzer::Fuzz(); 13481 v8::Unlocker unlocker(CcTest::isolate()); 13482 } 13483 13484 13485 THREADED_TEST(LockUnlockLock) { 13486 { 13487 v8::Locker locker(CcTest::isolate()); 13488 v8::HandleScope scope(CcTest::isolate()); 13489 LocalContext env; 13490 Local<v8::FunctionTemplate> fun_templ = 13491 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13492 Local<Function> fun = fun_templ->GetFunction(); 13493 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13494 Local<Script> script = v8_compile("(function () {" 13495 " unlock_for_a_moment();" 13496 " return 42;" 13497 "})();"); 13498 CHECK_EQ(42, script->Run()->Int32Value()); 13499 } 13500 { 13501 v8::Locker locker(CcTest::isolate()); 13502 v8::HandleScope scope(CcTest::isolate()); 13503 LocalContext env; 13504 Local<v8::FunctionTemplate> fun_templ = 13505 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13506 Local<Function> fun = fun_templ->GetFunction(); 13507 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13508 Local<Script> script = v8_compile("(function () {" 13509 " unlock_for_a_moment();" 13510 " return 42;" 13511 "})();"); 13512 CHECK_EQ(42, script->Run()->Int32Value()); 13513 } 13514 } 13515 13516 13517 static int GetGlobalObjectsCount() { 13518 int count = 0; 13519 i::HeapIterator it(CcTest::heap()); 13520 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 13521 if (object->IsJSGlobalObject()) count++; 13522 return count; 13523 } 13524 13525 13526 static void CheckSurvivingGlobalObjectsCount(int expected) { 13527 // We need to collect all garbage twice to be sure that everything 13528 // has been collected. This is because inline caches are cleared in 13529 // the first garbage collection but some of the maps have already 13530 // been marked at that point. Therefore some of the maps are not 13531 // collected until the second garbage collection. 13532 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13533 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 13534 int count = GetGlobalObjectsCount(); 13535 #ifdef DEBUG 13536 if (count != expected) CcTest::heap()->TracePathToGlobal(); 13537 #endif 13538 CHECK_EQ(expected, count); 13539 } 13540 13541 13542 TEST(DontLeakGlobalObjects) { 13543 // Regression test for issues 1139850 and 1174891. 13544 13545 i::FLAG_expose_gc = true; 13546 v8::V8::Initialize(); 13547 13548 for (int i = 0; i < 5; i++) { 13549 { v8::HandleScope scope(CcTest::isolate()); 13550 LocalContext context; 13551 } 13552 v8::V8::ContextDisposedNotification(); 13553 CheckSurvivingGlobalObjectsCount(0); 13554 13555 { v8::HandleScope scope(CcTest::isolate()); 13556 LocalContext context; 13557 v8_compile("Date")->Run(); 13558 } 13559 v8::V8::ContextDisposedNotification(); 13560 CheckSurvivingGlobalObjectsCount(0); 13561 13562 { v8::HandleScope scope(CcTest::isolate()); 13563 LocalContext context; 13564 v8_compile("/aaa/")->Run(); 13565 } 13566 v8::V8::ContextDisposedNotification(); 13567 CheckSurvivingGlobalObjectsCount(0); 13568 13569 { v8::HandleScope scope(CcTest::isolate()); 13570 const char* extension_list[] = { "v8/gc" }; 13571 v8::ExtensionConfiguration extensions(1, extension_list); 13572 LocalContext context(&extensions); 13573 v8_compile("gc();")->Run(); 13574 } 13575 v8::V8::ContextDisposedNotification(); 13576 CheckSurvivingGlobalObjectsCount(0); 13577 } 13578 } 13579 13580 13581 TEST(CopyablePersistent) { 13582 LocalContext context; 13583 v8::Isolate* isolate = context->GetIsolate(); 13584 i::GlobalHandles* globals = 13585 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13586 int initial_handles = globals->global_handles_count(); 13587 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > 13588 CopyableObject; 13589 { 13590 CopyableObject handle1; 13591 { 13592 v8::HandleScope scope(isolate); 13593 handle1.Reset(isolate, v8::Object::New(isolate)); 13594 } 13595 CHECK_EQ(initial_handles + 1, globals->global_handles_count()); 13596 CopyableObject handle2; 13597 handle2 = handle1; 13598 CHECK(handle1 == handle2); 13599 CHECK_EQ(initial_handles + 2, globals->global_handles_count()); 13600 CopyableObject handle3(handle2); 13601 CHECK(handle1 == handle3); 13602 CHECK_EQ(initial_handles + 3, globals->global_handles_count()); 13603 } 13604 // Verify autodispose 13605 CHECK_EQ(initial_handles, globals->global_handles_count()); 13606 } 13607 13608 13609 static void WeakApiCallback( 13610 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) { 13611 Local<Value> value = data.GetValue()->Get(v8_str("key")); 13612 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value())); 13613 data.GetParameter()->Reset(); 13614 delete data.GetParameter(); 13615 } 13616 13617 13618 TEST(WeakCallbackApi) { 13619 LocalContext context; 13620 v8::Isolate* isolate = context->GetIsolate(); 13621 i::GlobalHandles* globals = 13622 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13623 int initial_handles = globals->global_handles_count(); 13624 { 13625 v8::HandleScope scope(isolate); 13626 v8::Local<v8::Object> obj = v8::Object::New(isolate); 13627 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231)); 13628 v8::Persistent<v8::Object>* handle = 13629 new v8::Persistent<v8::Object>(isolate, obj); 13630 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle, 13631 WeakApiCallback); 13632 } 13633 reinterpret_cast<i::Isolate*>(isolate)->heap()-> 13634 CollectAllGarbage(i::Heap::kNoGCFlags); 13635 // Verify disposed. 13636 CHECK_EQ(initial_handles, globals->global_handles_count()); 13637 } 13638 13639 13640 v8::Persistent<v8::Object> some_object; 13641 v8::Persistent<v8::Object> bad_handle; 13642 13643 void NewPersistentHandleCallback( 13644 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13645 v8::HandleScope scope(data.GetIsolate()); 13646 bad_handle.Reset(data.GetIsolate(), some_object); 13647 data.GetParameter()->Reset(); 13648 } 13649 13650 13651 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 13652 LocalContext context; 13653 v8::Isolate* isolate = context->GetIsolate(); 13654 13655 v8::Persistent<v8::Object> handle1, handle2; 13656 { 13657 v8::HandleScope scope(isolate); 13658 some_object.Reset(isolate, v8::Object::New(isolate)); 13659 handle1.Reset(isolate, v8::Object::New(isolate)); 13660 handle2.Reset(isolate, v8::Object::New(isolate)); 13661 } 13662 // Note: order is implementation dependent alas: currently 13663 // global handle nodes are processed by PostGarbageCollectionProcessing 13664 // in reverse allocation order, so if second allocated handle is deleted, 13665 // weak callback of the first handle would be able to 'reallocate' it. 13666 handle1.SetWeak(&handle1, NewPersistentHandleCallback); 13667 handle2.Reset(); 13668 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13669 } 13670 13671 13672 v8::Persistent<v8::Object> to_be_disposed; 13673 13674 void DisposeAndForceGcCallback( 13675 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13676 to_be_disposed.Reset(); 13677 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13678 data.GetParameter()->Reset(); 13679 } 13680 13681 13682 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 13683 LocalContext context; 13684 v8::Isolate* isolate = context->GetIsolate(); 13685 13686 v8::Persistent<v8::Object> handle1, handle2; 13687 { 13688 v8::HandleScope scope(isolate); 13689 handle1.Reset(isolate, v8::Object::New(isolate)); 13690 handle2.Reset(isolate, v8::Object::New(isolate)); 13691 } 13692 handle1.SetWeak(&handle1, DisposeAndForceGcCallback); 13693 to_be_disposed.Reset(isolate, handle2); 13694 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13695 } 13696 13697 void DisposingCallback( 13698 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13699 data.GetParameter()->Reset(); 13700 } 13701 13702 void HandleCreatingCallback( 13703 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13704 v8::HandleScope scope(data.GetIsolate()); 13705 v8::Persistent<v8::Object>(data.GetIsolate(), 13706 v8::Object::New(data.GetIsolate())); 13707 data.GetParameter()->Reset(); 13708 } 13709 13710 13711 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 13712 LocalContext context; 13713 v8::Isolate* isolate = context->GetIsolate(); 13714 13715 v8::Persistent<v8::Object> handle1, handle2, handle3; 13716 { 13717 v8::HandleScope scope(isolate); 13718 handle3.Reset(isolate, v8::Object::New(isolate)); 13719 handle2.Reset(isolate, v8::Object::New(isolate)); 13720 handle1.Reset(isolate, v8::Object::New(isolate)); 13721 } 13722 handle2.SetWeak(&handle2, DisposingCallback); 13723 handle3.SetWeak(&handle3, HandleCreatingCallback); 13724 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13725 } 13726 13727 13728 THREADED_TEST(CheckForCrossContextObjectLiterals) { 13729 v8::V8::Initialize(); 13730 13731 const int nof = 2; 13732 const char* sources[nof] = { 13733 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 13734 "Object()" 13735 }; 13736 13737 for (int i = 0; i < nof; i++) { 13738 const char* source = sources[i]; 13739 { v8::HandleScope scope(CcTest::isolate()); 13740 LocalContext context; 13741 CompileRun(source); 13742 } 13743 { v8::HandleScope scope(CcTest::isolate()); 13744 LocalContext context; 13745 CompileRun(source); 13746 } 13747 } 13748 } 13749 13750 13751 static v8::Handle<Value> NestedScope(v8::Local<Context> env) { 13752 v8::EscapableHandleScope inner(env->GetIsolate()); 13753 env->Enter(); 13754 v8::Local<Value> three = v8_num(3); 13755 v8::Local<Value> value = inner.Escape(three); 13756 env->Exit(); 13757 return value; 13758 } 13759 13760 13761 THREADED_TEST(NestedHandleScopeAndContexts) { 13762 v8::Isolate* isolate = CcTest::isolate(); 13763 v8::HandleScope outer(isolate); 13764 v8::Local<Context> env = Context::New(isolate); 13765 env->Enter(); 13766 v8::Handle<Value> value = NestedScope(env); 13767 v8::Handle<String> str(value->ToString()); 13768 CHECK(!str.IsEmpty()); 13769 env->Exit(); 13770 } 13771 13772 13773 static bool MatchPointers(void* key1, void* key2) { 13774 return key1 == key2; 13775 } 13776 13777 13778 struct SymbolInfo { 13779 size_t id; 13780 size_t size; 13781 std::string name; 13782 }; 13783 13784 13785 class SetFunctionEntryHookTest { 13786 public: 13787 SetFunctionEntryHookTest() { 13788 CHECK(instance_ == NULL); 13789 instance_ = this; 13790 } 13791 ~SetFunctionEntryHookTest() { 13792 CHECK(instance_ == this); 13793 instance_ = NULL; 13794 } 13795 void Reset() { 13796 symbols_.clear(); 13797 symbol_locations_.clear(); 13798 invocations_.clear(); 13799 } 13800 void RunTest(); 13801 void OnJitEvent(const v8::JitCodeEvent* event); 13802 static void JitEvent(const v8::JitCodeEvent* event) { 13803 CHECK(instance_ != NULL); 13804 instance_->OnJitEvent(event); 13805 } 13806 13807 void OnEntryHook(uintptr_t function, 13808 uintptr_t return_addr_location); 13809 static void EntryHook(uintptr_t function, 13810 uintptr_t return_addr_location) { 13811 CHECK(instance_ != NULL); 13812 instance_->OnEntryHook(function, return_addr_location); 13813 } 13814 13815 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 13816 CHECK(instance_ != NULL); 13817 args.GetReturnValue().Set(v8_num(42)); 13818 } 13819 void RunLoopInNewEnv(v8::Isolate* isolate); 13820 13821 // Records addr as location of symbol. 13822 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 13823 13824 // Finds the symbol containing addr 13825 SymbolInfo* FindSymbolForAddr(i::Address addr); 13826 // Returns the number of invocations where the caller name contains 13827 // \p caller_name and the function name contains \p function_name. 13828 int CountInvocations(const char* caller_name, 13829 const char* function_name); 13830 13831 i::Handle<i::JSFunction> foo_func_; 13832 i::Handle<i::JSFunction> bar_func_; 13833 13834 typedef std::map<size_t, SymbolInfo> SymbolMap; 13835 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 13836 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 13837 SymbolMap symbols_; 13838 SymbolLocationMap symbol_locations_; 13839 InvocationMap invocations_; 13840 13841 static SetFunctionEntryHookTest* instance_; 13842 }; 13843 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 13844 13845 13846 // Returns true if addr is in the range [start, start+len). 13847 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 13848 if (start <= addr && start + len > addr) 13849 return true; 13850 13851 return false; 13852 } 13853 13854 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 13855 SymbolInfo* symbol) { 13856 // Insert the symbol at the new location. 13857 SymbolLocationMap::iterator it = 13858 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 13859 // Now erase symbols to the left and right that overlap this one. 13860 while (it != symbol_locations_.begin()) { 13861 SymbolLocationMap::iterator left = it; 13862 --left; 13863 if (!Overlaps(left->first, left->second->size, addr)) 13864 break; 13865 symbol_locations_.erase(left); 13866 } 13867 13868 // Now erase symbols to the left and right that overlap this one. 13869 while (true) { 13870 SymbolLocationMap::iterator right = it; 13871 ++right; 13872 if (right == symbol_locations_.end()) 13873 break; 13874 if (!Overlaps(addr, symbol->size, right->first)) 13875 break; 13876 symbol_locations_.erase(right); 13877 } 13878 } 13879 13880 13881 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 13882 switch (event->type) { 13883 case v8::JitCodeEvent::CODE_ADDED: { 13884 CHECK(event->code_start != NULL); 13885 CHECK_NE(0, static_cast<int>(event->code_len)); 13886 CHECK(event->name.str != NULL); 13887 size_t symbol_id = symbols_.size(); 13888 13889 // Record the new symbol. 13890 SymbolInfo& info = symbols_[symbol_id]; 13891 info.id = symbol_id; 13892 info.size = event->code_len; 13893 info.name.assign(event->name.str, event->name.str + event->name.len); 13894 13895 // And record it's location. 13896 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 13897 } 13898 break; 13899 13900 case v8::JitCodeEvent::CODE_MOVED: { 13901 // We would like to never see code move that we haven't seen before, 13902 // but the code creation event does not happen until the line endings 13903 // have been calculated (this is so that we can report the line in the 13904 // script at which the function source is found, see 13905 // Compiler::RecordFunctionCompilation) and the line endings 13906 // calculations can cause a GC, which can move the newly created code 13907 // before its existence can be logged. 13908 SymbolLocationMap::iterator it( 13909 symbol_locations_.find( 13910 reinterpret_cast<i::Address>(event->code_start))); 13911 if (it != symbol_locations_.end()) { 13912 // Found a symbol at this location, move it. 13913 SymbolInfo* info = it->second; 13914 symbol_locations_.erase(it); 13915 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 13916 info); 13917 } 13918 } 13919 default: 13920 break; 13921 } 13922 } 13923 13924 void SetFunctionEntryHookTest::OnEntryHook( 13925 uintptr_t function, uintptr_t return_addr_location) { 13926 // Get the function's code object. 13927 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 13928 reinterpret_cast<i::Address>(function)); 13929 CHECK(function_code != NULL); 13930 13931 // Then try and look up the caller's code object. 13932 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 13933 13934 // Count the invocation. 13935 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 13936 SymbolInfo* function_symbol = 13937 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 13938 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 13939 13940 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 13941 // Check that we have a symbol for the "bar" function at the right location. 13942 SymbolLocationMap::iterator it( 13943 symbol_locations_.find(function_code->instruction_start())); 13944 CHECK(it != symbol_locations_.end()); 13945 } 13946 13947 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 13948 // Check that we have a symbol for "foo" at the right location. 13949 SymbolLocationMap::iterator it( 13950 symbol_locations_.find(function_code->instruction_start())); 13951 CHECK(it != symbol_locations_.end()); 13952 } 13953 } 13954 13955 13956 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 13957 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 13958 // Do we have a direct hit on a symbol? 13959 if (it != symbol_locations_.end()) { 13960 if (it->first == addr) 13961 return it->second; 13962 } 13963 13964 // If not a direct hit, it'll have to be the previous symbol. 13965 if (it == symbol_locations_.begin()) 13966 return NULL; 13967 13968 --it; 13969 size_t offs = addr - it->first; 13970 if (offs < it->second->size) 13971 return it->second; 13972 13973 return NULL; 13974 } 13975 13976 13977 int SetFunctionEntryHookTest::CountInvocations( 13978 const char* caller_name, const char* function_name) { 13979 InvocationMap::iterator it(invocations_.begin()); 13980 int invocations = 0; 13981 for (; it != invocations_.end(); ++it) { 13982 SymbolInfo* caller = it->first.first; 13983 SymbolInfo* function = it->first.second; 13984 13985 // Filter out non-matching functions. 13986 if (function_name != NULL) { 13987 if (function->name.find(function_name) == std::string::npos) 13988 continue; 13989 } 13990 13991 // Filter out non-matching callers. 13992 if (caller_name != NULL) { 13993 if (caller == NULL) 13994 continue; 13995 if (caller->name.find(caller_name) == std::string::npos) 13996 continue; 13997 } 13998 13999 // It matches add the invocation count to the tally. 14000 invocations += it->second; 14001 } 14002 14003 return invocations; 14004 } 14005 14006 14007 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 14008 v8::HandleScope outer(isolate); 14009 v8::Local<Context> env = Context::New(isolate); 14010 env->Enter(); 14011 14012 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14013 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback)); 14014 env->Global()->Set(v8_str("obj"), t->NewInstance()); 14015 14016 const char* script = 14017 "function bar() {\n" 14018 " var sum = 0;\n" 14019 " for (i = 0; i < 100; ++i)\n" 14020 " sum = foo(i);\n" 14021 " return sum;\n" 14022 "}\n" 14023 "function foo(i) { return i * i; }\n" 14024 "// Invoke on the runtime function.\n" 14025 "obj.asdf()"; 14026 CompileRun(script); 14027 bar_func_ = i::Handle<i::JSFunction>::cast( 14028 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar")))); 14029 ASSERT(!bar_func_.is_null()); 14030 14031 foo_func_ = 14032 i::Handle<i::JSFunction>::cast( 14033 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo")))); 14034 ASSERT(!foo_func_.is_null()); 14035 14036 v8::Handle<v8::Value> value = CompileRun("bar();"); 14037 CHECK(value->IsNumber()); 14038 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14039 14040 // Test the optimized codegen path. 14041 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 14042 "bar();"); 14043 CHECK(value->IsNumber()); 14044 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14045 14046 env->Exit(); 14047 } 14048 14049 14050 void SetFunctionEntryHookTest::RunTest() { 14051 // Work in a new isolate throughout. 14052 v8::Isolate* isolate = v8::Isolate::New(); 14053 14054 // Test setting the entry hook on the new isolate. 14055 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 14056 14057 // Replacing the hook, once set should fail. 14058 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 14059 14060 { 14061 v8::Isolate::Scope scope(isolate); 14062 14063 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent); 14064 14065 RunLoopInNewEnv(isolate); 14066 14067 // Check the exepected invocation counts. 14068 CHECK_EQ(2, CountInvocations(NULL, "bar")); 14069 CHECK_EQ(200, CountInvocations("bar", "foo")); 14070 CHECK_EQ(200, CountInvocations(NULL, "foo")); 14071 14072 // Verify that we have an entry hook on some specific stubs. 14073 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 14074 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 14075 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 14076 } 14077 isolate->Dispose(); 14078 14079 Reset(); 14080 14081 // Make sure a second isolate is unaffected by the previous entry hook. 14082 isolate = v8::Isolate::New(); 14083 { 14084 v8::Isolate::Scope scope(isolate); 14085 14086 // Reset the entry count to zero and set the entry hook. 14087 RunLoopInNewEnv(isolate); 14088 14089 // We should record no invocations in this isolate. 14090 CHECK_EQ(0, static_cast<int>(invocations_.size())); 14091 } 14092 // Since the isolate has been used, we shouldn't be able to set an entry 14093 // hook anymore. 14094 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 14095 14096 isolate->Dispose(); 14097 } 14098 14099 14100 TEST(SetFunctionEntryHook) { 14101 // FunctionEntryHook does not work well with experimental natives. 14102 // Experimental natives are compiled during snapshot deserialization. 14103 // This test breaks because InstallGetter (function from snapshot that 14104 // only gets called from experimental natives) is compiled with entry hooks. 14105 i::FLAG_allow_natives_syntax = true; 14106 i::FLAG_use_inlining = false; 14107 14108 SetFunctionEntryHookTest test; 14109 test.RunTest(); 14110 } 14111 14112 14113 static i::HashMap* code_map = NULL; 14114 static i::HashMap* jitcode_line_info = NULL; 14115 static int saw_bar = 0; 14116 static int move_events = 0; 14117 14118 14119 static bool FunctionNameIs(const char* expected, 14120 const v8::JitCodeEvent* event) { 14121 // Log lines for functions are of the general form: 14122 // "LazyCompile:<type><function_name>", where the type is one of 14123 // "*", "~" or "". 14124 static const char kPreamble[] = "LazyCompile:"; 14125 static size_t kPreambleLen = sizeof(kPreamble) - 1; 14126 14127 if (event->name.len < sizeof(kPreamble) - 1 || 14128 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 14129 return false; 14130 } 14131 14132 const char* tail = event->name.str + kPreambleLen; 14133 size_t tail_len = event->name.len - kPreambleLen; 14134 size_t expected_len = strlen(expected); 14135 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 14136 --tail_len; 14137 ++tail; 14138 } 14139 14140 // Check for tails like 'bar :1'. 14141 if (tail_len > expected_len + 2 && 14142 tail[expected_len] == ' ' && 14143 tail[expected_len + 1] == ':' && 14144 tail[expected_len + 2] && 14145 !strncmp(tail, expected, expected_len)) { 14146 return true; 14147 } 14148 14149 if (tail_len != expected_len) 14150 return false; 14151 14152 return strncmp(tail, expected, expected_len) == 0; 14153 } 14154 14155 14156 static void event_handler(const v8::JitCodeEvent* event) { 14157 CHECK(event != NULL); 14158 CHECK(code_map != NULL); 14159 CHECK(jitcode_line_info != NULL); 14160 14161 class DummyJitCodeLineInfo { 14162 }; 14163 14164 switch (event->type) { 14165 case v8::JitCodeEvent::CODE_ADDED: { 14166 CHECK(event->code_start != NULL); 14167 CHECK_NE(0, static_cast<int>(event->code_len)); 14168 CHECK(event->name.str != NULL); 14169 i::HashMap::Entry* entry = 14170 code_map->Lookup(event->code_start, 14171 i::ComputePointerHash(event->code_start), 14172 true); 14173 entry->value = reinterpret_cast<void*>(event->code_len); 14174 14175 if (FunctionNameIs("bar", event)) { 14176 ++saw_bar; 14177 } 14178 } 14179 break; 14180 14181 case v8::JitCodeEvent::CODE_MOVED: { 14182 uint32_t hash = i::ComputePointerHash(event->code_start); 14183 // We would like to never see code move that we haven't seen before, 14184 // but the code creation event does not happen until the line endings 14185 // have been calculated (this is so that we can report the line in the 14186 // script at which the function source is found, see 14187 // Compiler::RecordFunctionCompilation) and the line endings 14188 // calculations can cause a GC, which can move the newly created code 14189 // before its existence can be logged. 14190 i::HashMap::Entry* entry = 14191 code_map->Lookup(event->code_start, hash, false); 14192 if (entry != NULL) { 14193 ++move_events; 14194 14195 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 14196 code_map->Remove(event->code_start, hash); 14197 14198 entry = code_map->Lookup(event->new_code_start, 14199 i::ComputePointerHash(event->new_code_start), 14200 true); 14201 CHECK(entry != NULL); 14202 entry->value = reinterpret_cast<void*>(event->code_len); 14203 } 14204 } 14205 break; 14206 14207 case v8::JitCodeEvent::CODE_REMOVED: 14208 // Object/code removal events are currently not dispatched from the GC. 14209 CHECK(false); 14210 break; 14211 14212 // For CODE_START_LINE_INFO_RECORDING event, we will create one 14213 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 14214 // record it in jitcode_line_info. 14215 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 14216 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 14217 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 14218 temp_event->user_data = line_info; 14219 i::HashMap::Entry* entry = 14220 jitcode_line_info->Lookup(line_info, 14221 i::ComputePointerHash(line_info), 14222 true); 14223 entry->value = reinterpret_cast<void*>(line_info); 14224 } 14225 break; 14226 // For these two events, we will check whether the event->user_data 14227 // data structure is created before during CODE_START_LINE_INFO_RECORDING 14228 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 14229 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 14230 CHECK(event->user_data != NULL); 14231 uint32_t hash = i::ComputePointerHash(event->user_data); 14232 i::HashMap::Entry* entry = 14233 jitcode_line_info->Lookup(event->user_data, hash, false); 14234 CHECK(entry != NULL); 14235 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 14236 } 14237 break; 14238 14239 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 14240 CHECK(event->user_data != NULL); 14241 uint32_t hash = i::ComputePointerHash(event->user_data); 14242 i::HashMap::Entry* entry = 14243 jitcode_line_info->Lookup(event->user_data, hash, false); 14244 CHECK(entry != NULL); 14245 } 14246 break; 14247 14248 default: 14249 // Impossible event. 14250 CHECK(false); 14251 break; 14252 } 14253 } 14254 14255 14256 UNINITIALIZED_TEST(SetJitCodeEventHandler) { 14257 i::FLAG_stress_compaction = true; 14258 i::FLAG_incremental_marking = false; 14259 if (i::FLAG_never_compact) return; 14260 const char* script = 14261 "function bar() {" 14262 " var sum = 0;" 14263 " for (i = 0; i < 100; ++i)" 14264 " sum = foo(i);" 14265 " return sum;" 14266 "}" 14267 "function foo(i) { return i * i; };" 14268 "bar();"; 14269 14270 // Run this test in a new isolate to make sure we don't 14271 // have remnants of state from other code. 14272 v8::Isolate* isolate = v8::Isolate::New(); 14273 isolate->Enter(); 14274 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 14275 i::Heap* heap = i_isolate->heap(); 14276 14277 { 14278 v8::HandleScope scope(isolate); 14279 i::HashMap code(MatchPointers); 14280 code_map = &code; 14281 14282 i::HashMap lineinfo(MatchPointers); 14283 jitcode_line_info = &lineinfo; 14284 14285 saw_bar = 0; 14286 move_events = 0; 14287 14288 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 14289 14290 // Generate new code objects sparsely distributed across several 14291 // different fragmented code-space pages. 14292 const int kIterations = 10; 14293 for (int i = 0; i < kIterations; ++i) { 14294 LocalContext env(isolate); 14295 i::AlwaysAllocateScope always_allocate(i_isolate); 14296 SimulateFullSpace(heap->code_space()); 14297 CompileRun(script); 14298 14299 // Keep a strong reference to the code object in the handle scope. 14300 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast( 14301 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code()); 14302 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast( 14303 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code()); 14304 14305 // Clear the compilation cache to get more wastage. 14306 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear(); 14307 } 14308 14309 // Force code movement. 14310 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler"); 14311 14312 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14313 14314 CHECK_LE(kIterations, saw_bar); 14315 CHECK_LT(0, move_events); 14316 14317 code_map = NULL; 14318 jitcode_line_info = NULL; 14319 } 14320 14321 isolate->Exit(); 14322 isolate->Dispose(); 14323 14324 // Do this in a new isolate. 14325 isolate = v8::Isolate::New(); 14326 isolate->Enter(); 14327 14328 // Verify that we get callbacks for existing code objects when we 14329 // request enumeration of existing code. 14330 { 14331 v8::HandleScope scope(isolate); 14332 LocalContext env(isolate); 14333 CompileRun(script); 14334 14335 // Now get code through initial iteration. 14336 i::HashMap code(MatchPointers); 14337 code_map = &code; 14338 14339 i::HashMap lineinfo(MatchPointers); 14340 jitcode_line_info = &lineinfo; 14341 14342 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler); 14343 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14344 14345 jitcode_line_info = NULL; 14346 // We expect that we got some events. Note that if we could get code removal 14347 // notifications, we could compare two collections, one created by listening 14348 // from the time of creation of an isolate, and the other by subscribing 14349 // with EnumExisting. 14350 CHECK_LT(0, code.occupancy()); 14351 14352 code_map = NULL; 14353 } 14354 14355 isolate->Exit(); 14356 isolate->Dispose(); 14357 } 14358 14359 14360 THREADED_TEST(ExternalAllocatedMemory) { 14361 v8::Isolate* isolate = CcTest::isolate(); 14362 v8::HandleScope outer(isolate); 14363 v8::Local<Context> env(Context::New(isolate)); 14364 CHECK(!env.IsEmpty()); 14365 const int64_t kSize = 1024*1024; 14366 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0); 14367 CHECK_EQ(baseline + kSize, 14368 isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); 14369 CHECK_EQ(baseline, 14370 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); 14371 } 14372 14373 14374 // Regression test for issue 54, object templates with internal fields 14375 // but no accessors or interceptors did not get their internal field 14376 // count set on instances. 14377 THREADED_TEST(Regress54) { 14378 LocalContext context; 14379 v8::Isolate* isolate = context->GetIsolate(); 14380 v8::HandleScope outer(isolate); 14381 static v8::Persistent<v8::ObjectTemplate> templ; 14382 if (templ.IsEmpty()) { 14383 v8::EscapableHandleScope inner(isolate); 14384 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate); 14385 local->SetInternalFieldCount(1); 14386 templ.Reset(isolate, inner.Escape(local)); 14387 } 14388 v8::Handle<v8::Object> result = 14389 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance(); 14390 CHECK_EQ(1, result->InternalFieldCount()); 14391 } 14392 14393 14394 // If part of the threaded tests, this test makes ThreadingTest fail 14395 // on mac. 14396 TEST(CatchStackOverflow) { 14397 LocalContext context; 14398 v8::HandleScope scope(context->GetIsolate()); 14399 v8::TryCatch try_catch; 14400 v8::Handle<v8::Value> result = CompileRun( 14401 "function f() {" 14402 " return f();" 14403 "}" 14404 "" 14405 "f();"); 14406 CHECK(result.IsEmpty()); 14407 } 14408 14409 14410 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, 14411 const char* resource_name, 14412 int line_offset) { 14413 v8::HandleScope scope(CcTest::isolate()); 14414 v8::TryCatch try_catch; 14415 v8::Handle<v8::Value> result = script->Run(); 14416 CHECK(result.IsEmpty()); 14417 CHECK(try_catch.HasCaught()); 14418 v8::Handle<v8::Message> message = try_catch.Message(); 14419 CHECK(!message.IsEmpty()); 14420 CHECK_EQ(10 + line_offset, message->GetLineNumber()); 14421 CHECK_EQ(91, message->GetStartPosition()); 14422 CHECK_EQ(92, message->GetEndPosition()); 14423 CHECK_EQ(2, message->GetStartColumn()); 14424 CHECK_EQ(3, message->GetEndColumn()); 14425 v8::String::Utf8Value line(message->GetSourceLine()); 14426 CHECK_EQ(" throw 'nirk';", *line); 14427 v8::String::Utf8Value name(message->GetScriptResourceName()); 14428 CHECK_EQ(resource_name, *name); 14429 } 14430 14431 14432 THREADED_TEST(TryCatchSourceInfo) { 14433 LocalContext context; 14434 v8::HandleScope scope(context->GetIsolate()); 14435 v8::Local<v8::String> source = v8_str( 14436 "function Foo() {\n" 14437 " return Bar();\n" 14438 "}\n" 14439 "\n" 14440 "function Bar() {\n" 14441 " return Baz();\n" 14442 "}\n" 14443 "\n" 14444 "function Baz() {\n" 14445 " throw 'nirk';\n" 14446 "}\n" 14447 "\n" 14448 "Foo();\n"); 14449 14450 const char* resource_name; 14451 v8::Handle<v8::Script> script; 14452 resource_name = "test.js"; 14453 script = CompileWithOrigin(source, resource_name); 14454 CheckTryCatchSourceInfo(script, resource_name, 0); 14455 14456 resource_name = "test1.js"; 14457 v8::ScriptOrigin origin1( 14458 v8::String::NewFromUtf8(context->GetIsolate(), resource_name)); 14459 script = v8::Script::Compile(source, &origin1); 14460 CheckTryCatchSourceInfo(script, resource_name, 0); 14461 14462 resource_name = "test2.js"; 14463 v8::ScriptOrigin origin2( 14464 v8::String::NewFromUtf8(context->GetIsolate(), resource_name), 14465 v8::Integer::New(context->GetIsolate(), 7)); 14466 script = v8::Script::Compile(source, &origin2); 14467 CheckTryCatchSourceInfo(script, resource_name, 7); 14468 } 14469 14470 14471 THREADED_TEST(CompilationCache) { 14472 LocalContext context; 14473 v8::HandleScope scope(context->GetIsolate()); 14474 v8::Handle<v8::String> source0 = 14475 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14476 v8::Handle<v8::String> source1 = 14477 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14478 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js"); 14479 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js"); 14480 v8::Handle<v8::Script> script2 = 14481 v8::Script::Compile(source0); // different origin 14482 CHECK_EQ(1234, script0->Run()->Int32Value()); 14483 CHECK_EQ(1234, script1->Run()->Int32Value()); 14484 CHECK_EQ(1234, script2->Run()->Int32Value()); 14485 } 14486 14487 14488 static void FunctionNameCallback( 14489 const v8::FunctionCallbackInfo<v8::Value>& args) { 14490 ApiTestFuzzer::Fuzz(); 14491 args.GetReturnValue().Set(v8_num(42)); 14492 } 14493 14494 14495 THREADED_TEST(CallbackFunctionName) { 14496 LocalContext context; 14497 v8::Isolate* isolate = context->GetIsolate(); 14498 v8::HandleScope scope(isolate); 14499 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14500 t->Set(v8_str("asdf"), 14501 v8::FunctionTemplate::New(isolate, FunctionNameCallback)); 14502 context->Global()->Set(v8_str("obj"), t->NewInstance()); 14503 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name"); 14504 CHECK(value->IsString()); 14505 v8::String::Utf8Value name(value); 14506 CHECK_EQ("asdf", *name); 14507 } 14508 14509 14510 THREADED_TEST(DateAccess) { 14511 LocalContext context; 14512 v8::HandleScope scope(context->GetIsolate()); 14513 v8::Handle<v8::Value> date = 14514 v8::Date::New(context->GetIsolate(), 1224744689038.0); 14515 CHECK(date->IsDate()); 14516 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 14517 } 14518 14519 14520 void CheckProperties(v8::Isolate* isolate, 14521 v8::Handle<v8::Value> val, 14522 int elmc, 14523 const char* elmv[]) { 14524 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14525 v8::Handle<v8::Array> props = obj->GetPropertyNames(); 14526 CHECK_EQ(elmc, props->Length()); 14527 for (int i = 0; i < elmc; i++) { 14528 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i))); 14529 CHECK_EQ(elmv[i], *elm); 14530 } 14531 } 14532 14533 14534 void CheckOwnProperties(v8::Isolate* isolate, 14535 v8::Handle<v8::Value> val, 14536 int elmc, 14537 const char* elmv[]) { 14538 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14539 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames(); 14540 CHECK_EQ(elmc, props->Length()); 14541 for (int i = 0; i < elmc; i++) { 14542 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i))); 14543 CHECK_EQ(elmv[i], *elm); 14544 } 14545 } 14546 14547 14548 THREADED_TEST(PropertyEnumeration) { 14549 LocalContext context; 14550 v8::Isolate* isolate = context->GetIsolate(); 14551 v8::HandleScope scope(isolate); 14552 v8::Handle<v8::Value> obj = CompileRun( 14553 "var result = [];" 14554 "result[0] = {};" 14555 "result[1] = {a: 1, b: 2};" 14556 "result[2] = [1, 2, 3];" 14557 "var proto = {x: 1, y: 2, z: 3};" 14558 "var x = { __proto__: proto, w: 0, z: 1 };" 14559 "result[3] = x;" 14560 "result;"); 14561 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14562 CHECK_EQ(4, elms->Length()); 14563 int elmc0 = 0; 14564 const char** elmv0 = NULL; 14565 CheckProperties( 14566 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14567 CheckOwnProperties( 14568 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14569 int elmc1 = 2; 14570 const char* elmv1[] = {"a", "b"}; 14571 CheckProperties( 14572 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1); 14573 CheckOwnProperties( 14574 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1); 14575 int elmc2 = 3; 14576 const char* elmv2[] = {"0", "1", "2"}; 14577 CheckProperties( 14578 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2); 14579 CheckOwnProperties( 14580 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2); 14581 int elmc3 = 4; 14582 const char* elmv3[] = {"w", "z", "x", "y"}; 14583 CheckProperties( 14584 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3); 14585 int elmc4 = 2; 14586 const char* elmv4[] = {"w", "z"}; 14587 CheckOwnProperties( 14588 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4); 14589 } 14590 14591 14592 THREADED_TEST(PropertyEnumeration2) { 14593 LocalContext context; 14594 v8::Isolate* isolate = context->GetIsolate(); 14595 v8::HandleScope scope(isolate); 14596 v8::Handle<v8::Value> obj = CompileRun( 14597 "var result = [];" 14598 "result[0] = {};" 14599 "result[1] = {a: 1, b: 2};" 14600 "result[2] = [1, 2, 3];" 14601 "var proto = {x: 1, y: 2, z: 3};" 14602 "var x = { __proto__: proto, w: 0, z: 1 };" 14603 "result[3] = x;" 14604 "result;"); 14605 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14606 CHECK_EQ(4, elms->Length()); 14607 int elmc0 = 0; 14608 const char** elmv0 = NULL; 14609 CheckProperties(isolate, 14610 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14611 14612 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0)); 14613 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames(); 14614 CHECK_EQ(0, props->Length()); 14615 for (uint32_t i = 0; i < props->Length(); i++) { 14616 printf("p[%d]\n", i); 14617 } 14618 } 14619 14620 static bool NamedSetAccessBlocker(Local<v8::Object> obj, 14621 Local<Value> name, 14622 v8::AccessType type, 14623 Local<Value> data) { 14624 return type != v8::ACCESS_SET; 14625 } 14626 14627 14628 static bool IndexedSetAccessBlocker(Local<v8::Object> obj, 14629 uint32_t key, 14630 v8::AccessType type, 14631 Local<Value> data) { 14632 return type != v8::ACCESS_SET; 14633 } 14634 14635 14636 THREADED_TEST(DisableAccessChecksWhileConfiguring) { 14637 LocalContext context; 14638 v8::Isolate* isolate = context->GetIsolate(); 14639 v8::HandleScope scope(isolate); 14640 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 14641 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14642 IndexedSetAccessBlocker); 14643 templ->Set(v8_str("x"), v8::True(isolate)); 14644 Local<v8::Object> instance = templ->NewInstance(); 14645 context->Global()->Set(v8_str("obj"), instance); 14646 Local<Value> value = CompileRun("obj.x"); 14647 CHECK(value->BooleanValue()); 14648 } 14649 14650 14651 static bool NamedGetAccessBlocker(Local<v8::Object> obj, 14652 Local<Value> name, 14653 v8::AccessType type, 14654 Local<Value> data) { 14655 return false; 14656 } 14657 14658 14659 static bool IndexedGetAccessBlocker(Local<v8::Object> obj, 14660 uint32_t key, 14661 v8::AccessType type, 14662 Local<Value> data) { 14663 return false; 14664 } 14665 14666 14667 14668 THREADED_TEST(AccessChecksReenabledCorrectly) { 14669 LocalContext context; 14670 v8::Isolate* isolate = context->GetIsolate(); 14671 v8::HandleScope scope(isolate); 14672 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 14673 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14674 IndexedGetAccessBlocker); 14675 templ->Set(v8_str("a"), v8_str("a")); 14676 // Add more than 8 (see kMaxFastProperties) properties 14677 // so that the constructor will force copying map. 14678 // Cannot sprintf, gcc complains unsafety. 14679 char buf[4]; 14680 for (char i = '0'; i <= '9' ; i++) { 14681 buf[0] = i; 14682 for (char j = '0'; j <= '9'; j++) { 14683 buf[1] = j; 14684 for (char k = '0'; k <= '9'; k++) { 14685 buf[2] = k; 14686 buf[3] = 0; 14687 templ->Set(v8_str(buf), v8::Number::New(isolate, k)); 14688 } 14689 } 14690 } 14691 14692 Local<v8::Object> instance_1 = templ->NewInstance(); 14693 context->Global()->Set(v8_str("obj_1"), instance_1); 14694 14695 Local<Value> value_1 = CompileRun("obj_1.a"); 14696 CHECK(value_1->IsUndefined()); 14697 14698 Local<v8::Object> instance_2 = templ->NewInstance(); 14699 context->Global()->Set(v8_str("obj_2"), instance_2); 14700 14701 Local<Value> value_2 = CompileRun("obj_2.a"); 14702 CHECK(value_2->IsUndefined()); 14703 } 14704 14705 14706 // This tests that access check information remains on the global 14707 // object template when creating contexts. 14708 THREADED_TEST(AccessControlRepeatedContextCreation) { 14709 v8::Isolate* isolate = CcTest::isolate(); 14710 v8::HandleScope handle_scope(isolate); 14711 v8::Handle<v8::ObjectTemplate> global_template = 14712 v8::ObjectTemplate::New(isolate); 14713 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14714 IndexedSetAccessBlocker); 14715 i::Handle<i::ObjectTemplateInfo> internal_template = 14716 v8::Utils::OpenHandle(*global_template); 14717 CHECK(!internal_template->constructor()->IsUndefined()); 14718 i::Handle<i::FunctionTemplateInfo> constructor( 14719 i::FunctionTemplateInfo::cast(internal_template->constructor())); 14720 CHECK(!constructor->access_check_info()->IsUndefined()); 14721 v8::Local<Context> context0(Context::New(isolate, NULL, global_template)); 14722 CHECK(!context0.IsEmpty()); 14723 CHECK(!constructor->access_check_info()->IsUndefined()); 14724 } 14725 14726 14727 THREADED_TEST(TurnOnAccessCheck) { 14728 v8::Isolate* isolate = CcTest::isolate(); 14729 v8::HandleScope handle_scope(isolate); 14730 14731 // Create an environment with access check to the global object disabled by 14732 // default. 14733 v8::Handle<v8::ObjectTemplate> global_template = 14734 v8::ObjectTemplate::New(isolate); 14735 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14736 IndexedGetAccessBlocker, 14737 v8::Handle<v8::Value>(), 14738 false); 14739 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14740 Context::Scope context_scope(context); 14741 14742 // Set up a property and a number of functions. 14743 context->Global()->Set(v8_str("a"), v8_num(1)); 14744 CompileRun("function f1() {return a;}" 14745 "function f2() {return a;}" 14746 "function g1() {return h();}" 14747 "function g2() {return h();}" 14748 "function h() {return 1;}"); 14749 Local<Function> f1 = 14750 Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14751 Local<Function> f2 = 14752 Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14753 Local<Function> g1 = 14754 Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14755 Local<Function> g2 = 14756 Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14757 Local<Function> h = 14758 Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14759 14760 // Get the global object. 14761 v8::Handle<v8::Object> global = context->Global(); 14762 14763 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14764 // uses the runtime system to retreive property a whereas f2 uses global load 14765 // inline cache. 14766 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14767 for (int i = 0; i < 4; i++) { 14768 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14769 } 14770 14771 // Same for g1 and g2. 14772 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14773 for (int i = 0; i < 4; i++) { 14774 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14775 } 14776 14777 // Detach the global and turn on access check. 14778 Local<Object> hidden_global = Local<Object>::Cast( 14779 context->Global()->GetPrototype()); 14780 context->DetachGlobal(); 14781 hidden_global->TurnOnAccessCheck(); 14782 14783 // Failing access check to property get results in undefined. 14784 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14785 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14786 14787 // Failing access check to function call results in exception. 14788 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14789 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14790 14791 // No failing access check when just returning a constant. 14792 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 14793 } 14794 14795 14796 static const char* kPropertyA = "a"; 14797 static const char* kPropertyH = "h"; 14798 14799 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, 14800 Local<Value> name, 14801 v8::AccessType type, 14802 Local<Value> data) { 14803 if (!name->IsString()) return false; 14804 i::Handle<i::String> name_handle = 14805 v8::Utils::OpenHandle(String::Cast(*name)); 14806 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA)) 14807 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH)); 14808 } 14809 14810 14811 THREADED_TEST(TurnOnAccessCheckAndRecompile) { 14812 v8::Isolate* isolate = CcTest::isolate(); 14813 v8::HandleScope handle_scope(isolate); 14814 14815 // Create an environment with access check to the global object disabled by 14816 // default. When the registered access checker will block access to properties 14817 // a and h. 14818 v8::Handle<v8::ObjectTemplate> global_template = 14819 v8::ObjectTemplate::New(isolate); 14820 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, 14821 IndexedGetAccessBlocker, 14822 v8::Handle<v8::Value>(), 14823 false); 14824 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14825 Context::Scope context_scope(context); 14826 14827 // Set up a property and a number of functions. 14828 context->Global()->Set(v8_str("a"), v8_num(1)); 14829 static const char* source = "function f1() {return a;}" 14830 "function f2() {return a;}" 14831 "function g1() {return h();}" 14832 "function g2() {return h();}" 14833 "function h() {return 1;}"; 14834 14835 CompileRun(source); 14836 Local<Function> f1; 14837 Local<Function> f2; 14838 Local<Function> g1; 14839 Local<Function> g2; 14840 Local<Function> h; 14841 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14842 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14843 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14844 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14845 h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14846 14847 // Get the global object. 14848 v8::Handle<v8::Object> global = context->Global(); 14849 14850 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14851 // uses the runtime system to retreive property a whereas f2 uses global load 14852 // inline cache. 14853 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14854 for (int i = 0; i < 4; i++) { 14855 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14856 } 14857 14858 // Same for g1 and g2. 14859 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14860 for (int i = 0; i < 4; i++) { 14861 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14862 } 14863 14864 // Detach the global and turn on access check now blocking access to property 14865 // a and function h. 14866 Local<Object> hidden_global = Local<Object>::Cast( 14867 context->Global()->GetPrototype()); 14868 context->DetachGlobal(); 14869 hidden_global->TurnOnAccessCheck(); 14870 14871 // Failing access check to property get results in undefined. 14872 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14873 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14874 14875 // Failing access check to function call results in exception. 14876 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14877 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14878 14879 // No failing access check when just returning a constant. 14880 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 14881 14882 // Now compile the source again. And get the newly compiled functions, except 14883 // for h for which access is blocked. 14884 CompileRun(source); 14885 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1"))); 14886 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2"))); 14887 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1"))); 14888 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2"))); 14889 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined()); 14890 14891 // Failing access check to property get results in undefined. 14892 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14893 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14894 14895 // Failing access check to function call results in exception. 14896 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14897 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14898 } 14899 14900 14901 // Tests that ScriptData can be serialized and deserialized. 14902 TEST(PreCompileSerialization) { 14903 v8::V8::Initialize(); 14904 LocalContext env; 14905 v8::Isolate* isolate = env->GetIsolate(); 14906 HandleScope handle_scope(isolate); 14907 14908 i::FLAG_min_preparse_length = 0; 14909 const char* script = "function foo(a) { return a+1; }"; 14910 v8::ScriptCompiler::Source source(v8_str(script)); 14911 v8::ScriptCompiler::Compile(isolate, &source, 14912 v8::ScriptCompiler::kProduceDataToCache); 14913 // Serialize. 14914 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); 14915 char* serialized_data = i::NewArray<char>(cd->length); 14916 i::MemCopy(serialized_data, cd->data, cd->length); 14917 14918 // Deserialize. 14919 i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length); 14920 14921 // Verify that the original is the same as the deserialized. 14922 CHECK_EQ(cd->length, deserialized->Length()); 14923 CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length)); 14924 14925 delete deserialized; 14926 i::DeleteArray(serialized_data); 14927 } 14928 14929 14930 // Attempts to deserialize bad data. 14931 TEST(PreCompileDeserializationError) { 14932 v8::V8::Initialize(); 14933 const char* data = "DONT CARE"; 14934 int invalid_size = 3; 14935 i::ScriptData* sd = i::ScriptData::New(data, invalid_size); 14936 CHECK_EQ(NULL, sd); 14937 } 14938 14939 14940 TEST(CompileWithInvalidCachedData) { 14941 v8::V8::Initialize(); 14942 v8::Isolate* isolate = CcTest::isolate(); 14943 LocalContext context; 14944 v8::HandleScope scope(context->GetIsolate()); 14945 i::FLAG_min_preparse_length = 0; 14946 14947 const char* script = "function foo(){ return 5;}\n" 14948 "function bar(){ return 6 + 7;} foo();"; 14949 v8::ScriptCompiler::Source source(v8_str(script)); 14950 v8::ScriptCompiler::Compile(isolate, &source, 14951 v8::ScriptCompiler::kProduceDataToCache); 14952 // source owns its cached data. Create a ScriptData based on it. The user 14953 // never needs to create ScriptDatas any more; we only need it here because we 14954 // want to modify the data before passing it back. 14955 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); 14956 // ScriptData does not take ownership of the buffers passed to it. 14957 i::ScriptData* sd = 14958 i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); 14959 CHECK(!sd->HasError()); 14960 // ScriptData private implementation details 14961 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; 14962 const int kFunctionEntrySize = i::FunctionEntry::kSize; 14963 const int kFunctionEntryStartOffset = 0; 14964 const int kFunctionEntryEndOffset = 1; 14965 unsigned* sd_data = 14966 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 14967 14968 // Overwrite function bar's end position with 0. 14969 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; 14970 v8::TryCatch try_catch; 14971 14972 // Make the script slightly different so that we don't hit the compilation 14973 // cache. Don't change the lenghts of tokens. 14974 const char* script2 = "function foo(){ return 6;}\n" 14975 "function bar(){ return 6 + 7;} foo();"; 14976 v8::ScriptCompiler::Source source2( 14977 v8_str(script2), 14978 // CachedData doesn't take ownership of the buffers, Source takes 14979 // ownership of CachedData. 14980 new v8::ScriptCompiler::CachedData( 14981 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); 14982 Local<v8::UnboundScript> compiled_script = 14983 v8::ScriptCompiler::CompileUnbound(isolate, &source2); 14984 14985 CHECK(try_catch.HasCaught()); 14986 { 14987 String::Utf8Value exception_value(try_catch.Message()->Get()); 14988 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar", 14989 *exception_value); 14990 } 14991 14992 try_catch.Reset(); 14993 delete sd; 14994 14995 // Overwrite function bar's start position with 200. The function entry will 14996 // not be found when searching for it by position, and the compilation fails. 14997 14998 // ScriptData does not take ownership of the buffers passed to it. 14999 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); 15000 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 15001 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = 15002 200; 15003 const char* script3 = "function foo(){ return 7;}\n" 15004 "function bar(){ return 6 + 7;} foo();"; 15005 v8::ScriptCompiler::Source source3( 15006 v8_str(script3), 15007 new v8::ScriptCompiler::CachedData( 15008 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); 15009 compiled_script = 15010 v8::ScriptCompiler::CompileUnbound(isolate, &source3); 15011 CHECK(try_catch.HasCaught()); 15012 { 15013 String::Utf8Value exception_value(try_catch.Message()->Get()); 15014 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar", 15015 *exception_value); 15016 } 15017 CHECK(compiled_script.IsEmpty()); 15018 try_catch.Reset(); 15019 delete sd; 15020 15021 // Try passing in cached data which is obviously invalid (wrong length). 15022 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length); 15023 const char* script4 = 15024 "function foo(){ return 8;}\n" 15025 "function bar(){ return 6 + 7;} foo();"; 15026 v8::ScriptCompiler::Source source4( 15027 v8_str(script4), 15028 new v8::ScriptCompiler::CachedData( 15029 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1)); 15030 compiled_script = 15031 v8::ScriptCompiler::CompileUnbound(isolate, &source4); 15032 CHECK(try_catch.HasCaught()); 15033 { 15034 String::Utf8Value exception_value(try_catch.Message()->Get()); 15035 CHECK_EQ("Uncaught SyntaxError: Invalid cached data", 15036 *exception_value); 15037 } 15038 CHECK(compiled_script.IsEmpty()); 15039 delete sd; 15040 } 15041 15042 15043 // This tests that we do not allow dictionary load/call inline caches 15044 // to use functions that have not yet been compiled. The potential 15045 // problem of loading a function that has not yet been compiled can 15046 // arise because we share code between contexts via the compilation 15047 // cache. 15048 THREADED_TEST(DictionaryICLoadedFunction) { 15049 v8::HandleScope scope(CcTest::isolate()); 15050 // Test LoadIC. 15051 for (int i = 0; i < 2; i++) { 15052 LocalContext context; 15053 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 15054 context->Global()->Delete(v8_str("tmp")); 15055 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 15056 } 15057 // Test CallIC. 15058 for (int i = 0; i < 2; i++) { 15059 LocalContext context; 15060 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 15061 context->Global()->Delete(v8_str("tmp")); 15062 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 15063 } 15064 } 15065 15066 15067 // Test that cross-context new calls use the context of the callee to 15068 // create the new JavaScript object. 15069 THREADED_TEST(CrossContextNew) { 15070 v8::Isolate* isolate = CcTest::isolate(); 15071 v8::HandleScope scope(isolate); 15072 v8::Local<Context> context0 = Context::New(isolate); 15073 v8::Local<Context> context1 = Context::New(isolate); 15074 15075 // Allow cross-domain access. 15076 Local<String> token = v8_str("<security token>"); 15077 context0->SetSecurityToken(token); 15078 context1->SetSecurityToken(token); 15079 15080 // Set an 'x' property on the Object prototype and define a 15081 // constructor function in context0. 15082 context0->Enter(); 15083 CompileRun("Object.prototype.x = 42; function C() {};"); 15084 context0->Exit(); 15085 15086 // Call the constructor function from context0 and check that the 15087 // result has the 'x' property. 15088 context1->Enter(); 15089 context1->Global()->Set(v8_str("other"), context0->Global()); 15090 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 15091 CHECK(value->IsInt32()); 15092 CHECK_EQ(42, value->Int32Value()); 15093 context1->Exit(); 15094 } 15095 15096 15097 // Verify that we can clone an object 15098 TEST(ObjectClone) { 15099 LocalContext env; 15100 v8::Isolate* isolate = env->GetIsolate(); 15101 v8::HandleScope scope(isolate); 15102 15103 const char* sample = 15104 "var rv = {};" \ 15105 "rv.alpha = 'hello';" \ 15106 "rv.beta = 123;" \ 15107 "rv;"; 15108 15109 // Create an object, verify basics. 15110 Local<Value> val = CompileRun(sample); 15111 CHECK(val->IsObject()); 15112 Local<v8::Object> obj = val.As<v8::Object>(); 15113 obj->Set(v8_str("gamma"), v8_str("cloneme")); 15114 15115 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); 15116 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta"))); 15117 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma"))); 15118 15119 // Clone it. 15120 Local<v8::Object> clone = obj->Clone(); 15121 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 15122 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta"))); 15123 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 15124 15125 // Set a property on the clone, verify each object. 15126 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456)); 15127 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta"))); 15128 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta"))); 15129 } 15130 15131 15132 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { 15133 public: 15134 explicit AsciiVectorResource(i::Vector<const char> vector) 15135 : data_(vector) {} 15136 virtual ~AsciiVectorResource() {} 15137 virtual size_t length() const { return data_.length(); } 15138 virtual const char* data() const { return data_.start(); } 15139 private: 15140 i::Vector<const char> data_; 15141 }; 15142 15143 15144 class UC16VectorResource : public v8::String::ExternalStringResource { 15145 public: 15146 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 15147 : data_(vector) {} 15148 virtual ~UC16VectorResource() {} 15149 virtual size_t length() const { return data_.length(); } 15150 virtual const i::uc16* data() const { return data_.start(); } 15151 private: 15152 i::Vector<const i::uc16> data_; 15153 }; 15154 15155 15156 static void MorphAString(i::String* string, 15157 AsciiVectorResource* ascii_resource, 15158 UC16VectorResource* uc16_resource) { 15159 CHECK(i::StringShape(string).IsExternal()); 15160 if (string->IsOneByteRepresentation()) { 15161 // Check old map is not internalized or long. 15162 CHECK(string->map() == CcTest::heap()->external_ascii_string_map()); 15163 // Morph external string to be TwoByte string. 15164 string->set_map(CcTest::heap()->external_string_map()); 15165 i::ExternalTwoByteString* morphed = 15166 i::ExternalTwoByteString::cast(string); 15167 morphed->set_resource(uc16_resource); 15168 } else { 15169 // Check old map is not internalized or long. 15170 CHECK(string->map() == CcTest::heap()->external_string_map()); 15171 // Morph external string to be ASCII string. 15172 string->set_map(CcTest::heap()->external_ascii_string_map()); 15173 i::ExternalAsciiString* morphed = 15174 i::ExternalAsciiString::cast(string); 15175 morphed->set_resource(ascii_resource); 15176 } 15177 } 15178 15179 15180 // Test that we can still flatten a string if the components it is built up 15181 // from have been turned into 16 bit strings in the mean time. 15182 THREADED_TEST(MorphCompositeStringTest) { 15183 char utf_buffer[129]; 15184 const char* c_string = "Now is the time for all good men" 15185 " to come to the aid of the party"; 15186 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 15187 { 15188 LocalContext env; 15189 i::Factory* factory = CcTest::i_isolate()->factory(); 15190 v8::HandleScope scope(env->GetIsolate()); 15191 AsciiVectorResource ascii_resource( 15192 i::Vector<const char>(c_string, i::StrLength(c_string))); 15193 UC16VectorResource uc16_resource( 15194 i::Vector<const uint16_t>(two_byte_string, 15195 i::StrLength(c_string))); 15196 15197 Local<String> lhs(v8::Utils::ToLocal( 15198 factory->NewExternalStringFromAscii(&ascii_resource) 15199 .ToHandleChecked())); 15200 Local<String> rhs(v8::Utils::ToLocal( 15201 factory->NewExternalStringFromAscii(&ascii_resource) 15202 .ToHandleChecked())); 15203 15204 env->Global()->Set(v8_str("lhs"), lhs); 15205 env->Global()->Set(v8_str("rhs"), rhs); 15206 15207 CompileRun( 15208 "var cons = lhs + rhs;" 15209 "var slice = lhs.substring(1, lhs.length - 1);" 15210 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 15211 15212 CHECK(lhs->IsOneByte()); 15213 CHECK(rhs->IsOneByte()); 15214 15215 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource); 15216 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource); 15217 15218 // This should UTF-8 without flattening, since everything is ASCII. 15219 Handle<String> cons = v8_compile("cons")->Run().As<String>(); 15220 CHECK_EQ(128, cons->Utf8Length()); 15221 int nchars = -1; 15222 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 15223 CHECK_EQ(128, nchars); 15224 CHECK_EQ(0, strcmp( 15225 utf_buffer, 15226 "Now is the time for all good men to come to the aid of the party" 15227 "Now is the time for all good men to come to the aid of the party")); 15228 15229 // Now do some stuff to make sure the strings are flattened, etc. 15230 CompileRun( 15231 "/[^a-z]/.test(cons);" 15232 "/[^a-z]/.test(slice);" 15233 "/[^a-z]/.test(slice_on_cons);"); 15234 const char* expected_cons = 15235 "Now is the time for all good men to come to the aid of the party" 15236 "Now is the time for all good men to come to the aid of the party"; 15237 const char* expected_slice = 15238 "ow is the time for all good men to come to the aid of the part"; 15239 const char* expected_slice_on_cons = 15240 "ow is the time for all good men to come to the aid of the party" 15241 "Now is the time for all good men to come to the aid of the part"; 15242 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons), 15243 env->Global()->Get(v8_str("cons"))); 15244 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice), 15245 env->Global()->Get(v8_str("slice"))); 15246 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons), 15247 env->Global()->Get(v8_str("slice_on_cons"))); 15248 } 15249 i::DeleteArray(two_byte_string); 15250 } 15251 15252 15253 TEST(CompileExternalTwoByteSource) { 15254 LocalContext context; 15255 v8::HandleScope scope(context->GetIsolate()); 15256 15257 // This is a very short list of sources, which currently is to check for a 15258 // regression caused by r2703. 15259 const char* ascii_sources[] = { 15260 "0.5", 15261 "-0.5", // This mainly testes PushBack in the Scanner. 15262 "--0.5", // This mainly testes PushBack in the Scanner. 15263 NULL 15264 }; 15265 15266 // Compile the sources as external two byte strings. 15267 for (int i = 0; ascii_sources[i] != NULL; i++) { 15268 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]); 15269 TestResource* uc16_resource = new TestResource(two_byte_string); 15270 v8::Local<v8::String> source = 15271 v8::String::NewExternal(context->GetIsolate(), uc16_resource); 15272 v8::Script::Compile(source); 15273 } 15274 } 15275 15276 15277 #ifndef V8_INTERPRETED_REGEXP 15278 15279 struct RegExpInterruptionData { 15280 int loop_count; 15281 UC16VectorResource* string_resource; 15282 v8::Persistent<v8::String> string; 15283 } regexp_interruption_data; 15284 15285 15286 class RegExpInterruptionThread : public i::Thread { 15287 public: 15288 explicit RegExpInterruptionThread(v8::Isolate* isolate) 15289 : Thread("TimeoutThread"), isolate_(isolate) {} 15290 15291 virtual void Run() { 15292 for (regexp_interruption_data.loop_count = 0; 15293 regexp_interruption_data.loop_count < 7; 15294 regexp_interruption_data.loop_count++) { 15295 i::OS::Sleep(50); // Wait a bit before requesting GC. 15296 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); 15297 } 15298 i::OS::Sleep(50); // Wait a bit before terminating. 15299 v8::V8::TerminateExecution(isolate_); 15300 } 15301 15302 private: 15303 v8::Isolate* isolate_; 15304 }; 15305 15306 15307 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) { 15308 if (regexp_interruption_data.loop_count != 2) return; 15309 v8::HandleScope scope(CcTest::isolate()); 15310 v8::Local<v8::String> string = v8::Local<v8::String>::New( 15311 CcTest::isolate(), regexp_interruption_data.string); 15312 string->MakeExternal(regexp_interruption_data.string_resource); 15313 } 15314 15315 15316 // Test that RegExp execution can be interrupted. Specifically, we test 15317 // * interrupting with GC 15318 // * turn the subject string from one-byte internal to two-byte external string 15319 // * force termination 15320 TEST(RegExpInterruption) { 15321 v8::HandleScope scope(CcTest::isolate()); 15322 LocalContext env; 15323 15324 RegExpInterruptionThread timeout_thread(CcTest::isolate()); 15325 15326 v8::V8::AddGCPrologueCallback(RunBeforeGC); 15327 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 15328 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content); 15329 v8::Local<v8::String> string = v8_str(ascii_content); 15330 15331 CcTest::global()->Set(v8_str("a"), string); 15332 regexp_interruption_data.string.Reset(CcTest::isolate(), string); 15333 regexp_interruption_data.string_resource = new UC16VectorResource( 15334 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content))); 15335 15336 v8::TryCatch try_catch; 15337 timeout_thread.Start(); 15338 15339 CompileRun("/((a*)*)*b/.exec(a)"); 15340 CHECK(try_catch.HasTerminated()); 15341 15342 timeout_thread.Join(); 15343 15344 regexp_interruption_data.string.Reset(); 15345 i::DeleteArray(uc16_content); 15346 } 15347 15348 #endif // V8_INTERPRETED_REGEXP 15349 15350 15351 // Test that we cannot set a property on the global object if there 15352 // is a read-only property in the prototype chain. 15353 TEST(ReadOnlyPropertyInGlobalProto) { 15354 v8::Isolate* isolate = CcTest::isolate(); 15355 v8::HandleScope scope(isolate); 15356 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15357 LocalContext context(0, templ); 15358 v8::Handle<v8::Object> global = context->Global(); 15359 v8::Handle<v8::Object> global_proto = 15360 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); 15361 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly); 15362 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly); 15363 // Check without 'eval' or 'with'. 15364 v8::Handle<v8::Value> res = 15365 CompileRun("function f() { x = 42; return x; }; f()"); 15366 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15367 // Check with 'eval'. 15368 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 15369 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15370 // Check with 'with'. 15371 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 15372 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15373 } 15374 15375 static int force_set_set_count = 0; 15376 static int force_set_get_count = 0; 15377 bool pass_on_get = false; 15378 15379 static void ForceSetGetter(v8::Local<v8::String> name, 15380 const v8::PropertyCallbackInfo<v8::Value>& info) { 15381 force_set_get_count++; 15382 if (pass_on_get) { 15383 return; 15384 } 15385 info.GetReturnValue().Set(3); 15386 } 15387 15388 static void ForceSetSetter(v8::Local<v8::String> name, 15389 v8::Local<v8::Value> value, 15390 const v8::PropertyCallbackInfo<void>& info) { 15391 force_set_set_count++; 15392 } 15393 15394 static void ForceSetInterceptSetter( 15395 v8::Local<v8::String> name, 15396 v8::Local<v8::Value> value, 15397 const v8::PropertyCallbackInfo<v8::Value>& info) { 15398 force_set_set_count++; 15399 info.GetReturnValue().SetUndefined(); 15400 } 15401 15402 15403 TEST(ForceSet) { 15404 force_set_get_count = 0; 15405 force_set_set_count = 0; 15406 pass_on_get = false; 15407 15408 v8::Isolate* isolate = CcTest::isolate(); 15409 v8::HandleScope scope(isolate); 15410 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15411 v8::Handle<v8::String> access_property = 15412 v8::String::NewFromUtf8(isolate, "a"); 15413 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); 15414 LocalContext context(NULL, templ); 15415 v8::Handle<v8::Object> global = context->Global(); 15416 15417 // Ordinary properties 15418 v8::Handle<v8::String> simple_property = 15419 v8::String::NewFromUtf8(isolate, "p"); 15420 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly); 15421 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15422 // This should fail because the property is read-only 15423 global->Set(simple_property, v8::Int32::New(isolate, 5)); 15424 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15425 // This should succeed even though the property is read-only 15426 global->ForceSet(simple_property, v8::Int32::New(isolate, 6)); 15427 CHECK_EQ(6, global->Get(simple_property)->Int32Value()); 15428 15429 // Accessors 15430 CHECK_EQ(0, force_set_set_count); 15431 CHECK_EQ(0, force_set_get_count); 15432 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 15433 // CHECK_EQ the property shouldn't override it, just call the setter 15434 // which in this case does nothing. 15435 global->Set(access_property, v8::Int32::New(isolate, 7)); 15436 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 15437 CHECK_EQ(1, force_set_set_count); 15438 CHECK_EQ(2, force_set_get_count); 15439 // Forcing the property to be set should override the accessor without 15440 // calling it 15441 global->ForceSet(access_property, v8::Int32::New(isolate, 8)); 15442 CHECK_EQ(8, global->Get(access_property)->Int32Value()); 15443 CHECK_EQ(1, force_set_set_count); 15444 CHECK_EQ(2, force_set_get_count); 15445 } 15446 15447 15448 TEST(ForceSetWithInterceptor) { 15449 force_set_get_count = 0; 15450 force_set_set_count = 0; 15451 pass_on_get = false; 15452 15453 v8::Isolate* isolate = CcTest::isolate(); 15454 v8::HandleScope scope(isolate); 15455 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15456 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); 15457 LocalContext context(NULL, templ); 15458 v8::Handle<v8::Object> global = context->Global(); 15459 15460 v8::Handle<v8::String> some_property = 15461 v8::String::NewFromUtf8(isolate, "a"); 15462 CHECK_EQ(0, force_set_set_count); 15463 CHECK_EQ(0, force_set_get_count); 15464 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15465 // Setting the property shouldn't override it, just call the setter 15466 // which in this case does nothing. 15467 global->Set(some_property, v8::Int32::New(isolate, 7)); 15468 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15469 CHECK_EQ(1, force_set_set_count); 15470 CHECK_EQ(2, force_set_get_count); 15471 // Getting the property when the interceptor returns an empty handle 15472 // should yield undefined, since the property isn't present on the 15473 // object itself yet. 15474 pass_on_get = true; 15475 CHECK(global->Get(some_property)->IsUndefined()); 15476 CHECK_EQ(1, force_set_set_count); 15477 CHECK_EQ(3, force_set_get_count); 15478 // Forcing the property to be set should cause the value to be 15479 // set locally without calling the interceptor. 15480 global->ForceSet(some_property, v8::Int32::New(isolate, 8)); 15481 CHECK_EQ(8, global->Get(some_property)->Int32Value()); 15482 CHECK_EQ(1, force_set_set_count); 15483 CHECK_EQ(4, force_set_get_count); 15484 // Reenabling the interceptor should cause it to take precedence over 15485 // the property 15486 pass_on_get = false; 15487 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15488 CHECK_EQ(1, force_set_set_count); 15489 CHECK_EQ(5, force_set_get_count); 15490 // The interceptor should also work for other properties 15491 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b")) 15492 ->Int32Value()); 15493 CHECK_EQ(1, force_set_set_count); 15494 CHECK_EQ(6, force_set_get_count); 15495 } 15496 15497 15498 THREADED_TEST(ForceDelete) { 15499 v8::Isolate* isolate = CcTest::isolate(); 15500 v8::HandleScope scope(isolate); 15501 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15502 LocalContext context(NULL, templ); 15503 v8::Handle<v8::Object> global = context->Global(); 15504 15505 // Ordinary properties 15506 v8::Handle<v8::String> simple_property = 15507 v8::String::NewFromUtf8(isolate, "p"); 15508 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete); 15509 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15510 // This should fail because the property is dont-delete. 15511 CHECK(!global->Delete(simple_property)); 15512 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15513 // This should succeed even though the property is dont-delete. 15514 CHECK(global->ForceDelete(simple_property)); 15515 CHECK(global->Get(simple_property)->IsUndefined()); 15516 } 15517 15518 15519 static int force_delete_interceptor_count = 0; 15520 static bool pass_on_delete = false; 15521 15522 15523 static void ForceDeleteDeleter( 15524 v8::Local<v8::String> name, 15525 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 15526 force_delete_interceptor_count++; 15527 if (pass_on_delete) return; 15528 info.GetReturnValue().Set(true); 15529 } 15530 15531 15532 THREADED_TEST(ForceDeleteWithInterceptor) { 15533 force_delete_interceptor_count = 0; 15534 pass_on_delete = false; 15535 15536 v8::Isolate* isolate = CcTest::isolate(); 15537 v8::HandleScope scope(isolate); 15538 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15539 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter); 15540 LocalContext context(NULL, templ); 15541 v8::Handle<v8::Object> global = context->Global(); 15542 15543 v8::Handle<v8::String> some_property = 15544 v8::String::NewFromUtf8(isolate, "a"); 15545 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete); 15546 15547 // Deleting a property should get intercepted and nothing should 15548 // happen. 15549 CHECK_EQ(0, force_delete_interceptor_count); 15550 CHECK(global->Delete(some_property)); 15551 CHECK_EQ(1, force_delete_interceptor_count); 15552 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15553 // Deleting the property when the interceptor returns an empty 15554 // handle should not delete the property since it is DontDelete. 15555 pass_on_delete = true; 15556 CHECK(!global->Delete(some_property)); 15557 CHECK_EQ(2, force_delete_interceptor_count); 15558 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15559 // Forcing the property to be deleted should delete the value 15560 // without calling the interceptor. 15561 CHECK(global->ForceDelete(some_property)); 15562 CHECK(global->Get(some_property)->IsUndefined()); 15563 CHECK_EQ(2, force_delete_interceptor_count); 15564 } 15565 15566 15567 // Make sure that forcing a delete invalidates any IC stubs, so we 15568 // don't read the hole value. 15569 THREADED_TEST(ForceDeleteIC) { 15570 LocalContext context; 15571 v8::HandleScope scope(context->GetIsolate()); 15572 // Create a DontDelete variable on the global object. 15573 CompileRun("this.__proto__ = { foo: 'horse' };" 15574 "var foo = 'fish';" 15575 "function f() { return foo.length; }"); 15576 // Initialize the IC for foo in f. 15577 CompileRun("for (var i = 0; i < 4; i++) f();"); 15578 // Make sure the value of foo is correct before the deletion. 15579 CHECK_EQ(4, CompileRun("f()")->Int32Value()); 15580 // Force the deletion of foo. 15581 CHECK(context->Global()->ForceDelete(v8_str("foo"))); 15582 // Make sure the value for foo is read from the prototype, and that 15583 // we don't get in trouble with reading the deleted cell value 15584 // sentinel. 15585 CHECK_EQ(5, CompileRun("f()")->Int32Value()); 15586 } 15587 15588 15589 TEST(InlinedFunctionAcrossContexts) { 15590 i::FLAG_allow_natives_syntax = true; 15591 v8::Isolate* isolate = CcTest::isolate(); 15592 v8::HandleScope outer_scope(isolate); 15593 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate); 15594 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate); 15595 ctx1->Enter(); 15596 15597 { 15598 v8::HandleScope inner_scope(CcTest::isolate()); 15599 CompileRun("var G = 42; function foo() { return G; }"); 15600 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo")); 15601 ctx2->Enter(); 15602 ctx2->Global()->Set(v8_str("o"), foo); 15603 v8::Local<v8::Value> res = CompileRun( 15604 "function f() { return o(); }" 15605 "for (var i = 0; i < 10; ++i) f();" 15606 "%OptimizeFunctionOnNextCall(f);" 15607 "f();"); 15608 CHECK_EQ(42, res->Int32Value()); 15609 ctx2->Exit(); 15610 v8::Handle<v8::String> G_property = 15611 v8::String::NewFromUtf8(CcTest::isolate(), "G"); 15612 CHECK(ctx1->Global()->ForceDelete(G_property)); 15613 ctx2->Enter(); 15614 ExpectString( 15615 "(function() {" 15616 " try {" 15617 " return f();" 15618 " } catch(e) {" 15619 " return e.toString();" 15620 " }" 15621 " })()", 15622 "ReferenceError: G is not defined"); 15623 ctx2->Exit(); 15624 ctx1->Exit(); 15625 } 15626 } 15627 15628 15629 static v8::Local<Context> calling_context0; 15630 static v8::Local<Context> calling_context1; 15631 static v8::Local<Context> calling_context2; 15632 15633 15634 // Check that the call to the callback is initiated in 15635 // calling_context2, the directly calling context is calling_context1 15636 // and the callback itself is in calling_context0. 15637 static void GetCallingContextCallback( 15638 const v8::FunctionCallbackInfo<v8::Value>& args) { 15639 ApiTestFuzzer::Fuzz(); 15640 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0); 15641 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1); 15642 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2); 15643 args.GetReturnValue().Set(42); 15644 } 15645 15646 15647 THREADED_TEST(GetCurrentContextWhenNotInContext) { 15648 i::Isolate* isolate = CcTest::i_isolate(); 15649 CHECK(isolate != NULL); 15650 CHECK(isolate->context() == NULL); 15651 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 15652 v8::HandleScope scope(v8_isolate); 15653 // The following should not crash, but return an empty handle. 15654 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 15655 CHECK(current.IsEmpty()); 15656 } 15657 15658 15659 THREADED_TEST(GetCallingContext) { 15660 v8::Isolate* isolate = CcTest::isolate(); 15661 v8::HandleScope scope(isolate); 15662 15663 Local<Context> calling_context0(Context::New(isolate)); 15664 Local<Context> calling_context1(Context::New(isolate)); 15665 Local<Context> calling_context2(Context::New(isolate)); 15666 ::calling_context0 = calling_context0; 15667 ::calling_context1 = calling_context1; 15668 ::calling_context2 = calling_context2; 15669 15670 // Allow cross-domain access. 15671 Local<String> token = v8_str("<security token>"); 15672 calling_context0->SetSecurityToken(token); 15673 calling_context1->SetSecurityToken(token); 15674 calling_context2->SetSecurityToken(token); 15675 15676 // Create an object with a C++ callback in context0. 15677 calling_context0->Enter(); 15678 Local<v8::FunctionTemplate> callback_templ = 15679 v8::FunctionTemplate::New(isolate, GetCallingContextCallback); 15680 calling_context0->Global()->Set(v8_str("callback"), 15681 callback_templ->GetFunction()); 15682 calling_context0->Exit(); 15683 15684 // Expose context0 in context1 and set up a function that calls the 15685 // callback function. 15686 calling_context1->Enter(); 15687 calling_context1->Global()->Set(v8_str("context0"), 15688 calling_context0->Global()); 15689 CompileRun("function f() { context0.callback() }"); 15690 calling_context1->Exit(); 15691 15692 // Expose context1 in context2 and call the callback function in 15693 // context0 indirectly through f in context1. 15694 calling_context2->Enter(); 15695 calling_context2->Global()->Set(v8_str("context1"), 15696 calling_context1->Global()); 15697 CompileRun("context1.f()"); 15698 calling_context2->Exit(); 15699 ::calling_context0.Clear(); 15700 ::calling_context1.Clear(); 15701 ::calling_context2.Clear(); 15702 } 15703 15704 15705 // Check that a variable declaration with no explicit initialization 15706 // value does shadow an existing property in the prototype chain. 15707 THREADED_TEST(InitGlobalVarInProtoChain) { 15708 LocalContext context; 15709 v8::HandleScope scope(context->GetIsolate()); 15710 // Introduce a variable in the prototype chain. 15711 CompileRun("__proto__.x = 42"); 15712 v8::Handle<v8::Value> result = CompileRun("var x = 43; x"); 15713 CHECK(!result->IsUndefined()); 15714 CHECK_EQ(43, result->Int32Value()); 15715 } 15716 15717 15718 // Regression test for issue 398. 15719 // If a function is added to an object, creating a constant function 15720 // field, and the result is cloned, replacing the constant function on the 15721 // original should not affect the clone. 15722 // See http://code.google.com/p/v8/issues/detail?id=398 15723 THREADED_TEST(ReplaceConstantFunction) { 15724 LocalContext context; 15725 v8::Isolate* isolate = context->GetIsolate(); 15726 v8::HandleScope scope(isolate); 15727 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 15728 v8::Handle<v8::FunctionTemplate> func_templ = 15729 v8::FunctionTemplate::New(isolate); 15730 v8::Handle<v8::String> foo_string = 15731 v8::String::NewFromUtf8(isolate, "foo"); 15732 obj->Set(foo_string, func_templ->GetFunction()); 15733 v8::Handle<v8::Object> obj_clone = obj->Clone(); 15734 obj_clone->Set(foo_string, 15735 v8::String::NewFromUtf8(isolate, "Hello")); 15736 CHECK(!obj->Get(foo_string)->IsUndefined()); 15737 } 15738 15739 15740 static void CheckElementValue(i::Isolate* isolate, 15741 int expected, 15742 i::Handle<i::Object> obj, 15743 int offset) { 15744 i::Object* element = 15745 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked(); 15746 CHECK_EQ(expected, i::Smi::cast(element)->value()); 15747 } 15748 15749 15750 THREADED_TEST(PixelArray) { 15751 LocalContext context; 15752 i::Isolate* isolate = CcTest::i_isolate(); 15753 i::Factory* factory = isolate->factory(); 15754 v8::HandleScope scope(context->GetIsolate()); 15755 const int kElementCount = 260; 15756 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 15757 i::Handle<i::ExternalUint8ClampedArray> pixels = 15758 i::Handle<i::ExternalUint8ClampedArray>::cast( 15759 factory->NewExternalArray(kElementCount, 15760 v8::kExternalUint8ClampedArray, 15761 pixel_data)); 15762 // Force GC to trigger verification. 15763 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15764 for (int i = 0; i < kElementCount; i++) { 15765 pixels->set(i, i % 256); 15766 } 15767 // Force GC to trigger verification. 15768 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15769 for (int i = 0; i < kElementCount; i++) { 15770 CHECK_EQ(i % 256, pixels->get_scalar(i)); 15771 CHECK_EQ(i % 256, pixel_data[i]); 15772 } 15773 15774 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 15775 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15776 // Set the elements to be the pixels. 15777 // jsobj->set_elements(*pixels); 15778 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 15779 CheckElementValue(isolate, 1, jsobj, 1); 15780 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503)); 15781 context->Global()->Set(v8_str("pixels"), obj); 15782 v8::Handle<v8::Value> result = CompileRun("pixels.field"); 15783 CHECK_EQ(1503, result->Int32Value()); 15784 result = CompileRun("pixels[1]"); 15785 CHECK_EQ(1, result->Int32Value()); 15786 15787 result = CompileRun("var sum = 0;" 15788 "for (var i = 0; i < 8; i++) {" 15789 " sum += pixels[i] = pixels[i] = -i;" 15790 "}" 15791 "sum;"); 15792 CHECK_EQ(-28, result->Int32Value()); 15793 15794 result = CompileRun("var sum = 0;" 15795 "for (var i = 0; i < 8; i++) {" 15796 " sum += pixels[i] = pixels[i] = 0;" 15797 "}" 15798 "sum;"); 15799 CHECK_EQ(0, result->Int32Value()); 15800 15801 result = CompileRun("var sum = 0;" 15802 "for (var i = 0; i < 8; i++) {" 15803 " sum += pixels[i] = pixels[i] = 255;" 15804 "}" 15805 "sum;"); 15806 CHECK_EQ(8 * 255, result->Int32Value()); 15807 15808 result = CompileRun("var sum = 0;" 15809 "for (var i = 0; i < 8; i++) {" 15810 " sum += pixels[i] = pixels[i] = 256 + i;" 15811 "}" 15812 "sum;"); 15813 CHECK_EQ(2076, result->Int32Value()); 15814 15815 result = CompileRun("var sum = 0;" 15816 "for (var i = 0; i < 8; i++) {" 15817 " sum += pixels[i] = pixels[i] = i;" 15818 "}" 15819 "sum;"); 15820 CHECK_EQ(28, result->Int32Value()); 15821 15822 result = CompileRun("var sum = 0;" 15823 "for (var i = 0; i < 8; i++) {" 15824 " sum += pixels[i];" 15825 "}" 15826 "sum;"); 15827 CHECK_EQ(28, result->Int32Value()); 15828 15829 i::Handle<i::Smi> value(i::Smi::FromInt(2), 15830 reinterpret_cast<i::Isolate*>(context->GetIsolate())); 15831 i::Handle<i::Object> no_failure; 15832 no_failure = i::JSObject::SetElement( 15833 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15834 ASSERT(!no_failure.is_null()); 15835 USE(no_failure); 15836 CheckElementValue(isolate, 2, jsobj, 1); 15837 *value.location() = i::Smi::FromInt(256); 15838 no_failure = i::JSObject::SetElement( 15839 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15840 ASSERT(!no_failure.is_null()); 15841 USE(no_failure); 15842 CheckElementValue(isolate, 255, jsobj, 1); 15843 *value.location() = i::Smi::FromInt(-1); 15844 no_failure = i::JSObject::SetElement( 15845 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15846 ASSERT(!no_failure.is_null()); 15847 USE(no_failure); 15848 CheckElementValue(isolate, 0, jsobj, 1); 15849 15850 result = CompileRun("for (var i = 0; i < 8; i++) {" 15851 " pixels[i] = (i * 65) - 109;" 15852 "}" 15853 "pixels[1] + pixels[6];"); 15854 CHECK_EQ(255, result->Int32Value()); 15855 CheckElementValue(isolate, 0, jsobj, 0); 15856 CheckElementValue(isolate, 0, jsobj, 1); 15857 CheckElementValue(isolate, 21, jsobj, 2); 15858 CheckElementValue(isolate, 86, jsobj, 3); 15859 CheckElementValue(isolate, 151, jsobj, 4); 15860 CheckElementValue(isolate, 216, jsobj, 5); 15861 CheckElementValue(isolate, 255, jsobj, 6); 15862 CheckElementValue(isolate, 255, jsobj, 7); 15863 result = CompileRun("var sum = 0;" 15864 "for (var i = 0; i < 8; i++) {" 15865 " sum += pixels[i];" 15866 "}" 15867 "sum;"); 15868 CHECK_EQ(984, result->Int32Value()); 15869 15870 result = CompileRun("for (var i = 0; i < 8; i++) {" 15871 " pixels[i] = (i * 1.1);" 15872 "}" 15873 "pixels[1] + pixels[6];"); 15874 CHECK_EQ(8, result->Int32Value()); 15875 CheckElementValue(isolate, 0, jsobj, 0); 15876 CheckElementValue(isolate, 1, jsobj, 1); 15877 CheckElementValue(isolate, 2, jsobj, 2); 15878 CheckElementValue(isolate, 3, jsobj, 3); 15879 CheckElementValue(isolate, 4, jsobj, 4); 15880 CheckElementValue(isolate, 6, jsobj, 5); 15881 CheckElementValue(isolate, 7, jsobj, 6); 15882 CheckElementValue(isolate, 8, jsobj, 7); 15883 15884 result = CompileRun("for (var i = 0; i < 8; i++) {" 15885 " pixels[7] = undefined;" 15886 "}" 15887 "pixels[7];"); 15888 CHECK_EQ(0, result->Int32Value()); 15889 CheckElementValue(isolate, 0, jsobj, 7); 15890 15891 result = CompileRun("for (var i = 0; i < 8; i++) {" 15892 " pixels[6] = '2.3';" 15893 "}" 15894 "pixels[6];"); 15895 CHECK_EQ(2, result->Int32Value()); 15896 CheckElementValue(isolate, 2, jsobj, 6); 15897 15898 result = CompileRun("for (var i = 0; i < 8; i++) {" 15899 " pixels[5] = NaN;" 15900 "}" 15901 "pixels[5];"); 15902 CHECK_EQ(0, result->Int32Value()); 15903 CheckElementValue(isolate, 0, jsobj, 5); 15904 15905 result = CompileRun("for (var i = 0; i < 8; i++) {" 15906 " pixels[8] = Infinity;" 15907 "}" 15908 "pixels[8];"); 15909 CHECK_EQ(255, result->Int32Value()); 15910 CheckElementValue(isolate, 255, jsobj, 8); 15911 15912 result = CompileRun("for (var i = 0; i < 8; i++) {" 15913 " pixels[9] = -Infinity;" 15914 "}" 15915 "pixels[9];"); 15916 CHECK_EQ(0, result->Int32Value()); 15917 CheckElementValue(isolate, 0, jsobj, 9); 15918 15919 result = CompileRun("pixels[3] = 33;" 15920 "delete pixels[3];" 15921 "pixels[3];"); 15922 CHECK_EQ(33, result->Int32Value()); 15923 15924 result = CompileRun("pixels[0] = 10; pixels[1] = 11;" 15925 "pixels[2] = 12; pixels[3] = 13;" 15926 "pixels.__defineGetter__('2'," 15927 "function() { return 120; });" 15928 "pixels[2];"); 15929 CHECK_EQ(12, result->Int32Value()); 15930 15931 result = CompileRun("var js_array = new Array(40);" 15932 "js_array[0] = 77;" 15933 "js_array;"); 15934 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15935 15936 result = CompileRun("pixels[1] = 23;" 15937 "pixels.__proto__ = [];" 15938 "js_array.__proto__ = pixels;" 15939 "js_array.concat(pixels);"); 15940 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15941 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 15942 15943 result = CompileRun("pixels[1] = 23;"); 15944 CHECK_EQ(23, result->Int32Value()); 15945 15946 // Test for index greater than 255. Regression test for: 15947 // http://code.google.com/p/chromium/issues/detail?id=26337. 15948 result = CompileRun("pixels[256] = 255;"); 15949 CHECK_EQ(255, result->Int32Value()); 15950 result = CompileRun("var i = 0;" 15951 "for (var j = 0; j < 8; j++) { i = pixels[256]; }" 15952 "i"); 15953 CHECK_EQ(255, result->Int32Value()); 15954 15955 // Make sure that pixel array ICs recognize when a non-pixel array 15956 // is passed to it. 15957 result = CompileRun("function pa_load(p) {" 15958 " var sum = 0;" 15959 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15960 " return sum;" 15961 "}" 15962 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15963 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15964 "just_ints = new Object();" 15965 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15966 "for (var i = 0; i < 10; ++i) {" 15967 " result = pa_load(just_ints);" 15968 "}" 15969 "result"); 15970 CHECK_EQ(32640, result->Int32Value()); 15971 15972 // Make sure that pixel array ICs recognize out-of-bound accesses. 15973 result = CompileRun("function pa_load(p, start) {" 15974 " var sum = 0;" 15975 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15976 " return sum;" 15977 "}" 15978 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15979 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15980 "for (var i = 0; i < 10; ++i) {" 15981 " result = pa_load(pixels,-10);" 15982 "}" 15983 "result"); 15984 CHECK_EQ(0, result->Int32Value()); 15985 15986 // Make sure that generic ICs properly handles a pixel array. 15987 result = CompileRun("function pa_load(p) {" 15988 " var sum = 0;" 15989 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15990 " return sum;" 15991 "}" 15992 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15993 "just_ints = new Object();" 15994 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15995 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 15996 "for (var i = 0; i < 10; ++i) {" 15997 " result = pa_load(pixels);" 15998 "}" 15999 "result"); 16000 CHECK_EQ(32640, result->Int32Value()); 16001 16002 // Make sure that generic load ICs recognize out-of-bound accesses in 16003 // pixel arrays. 16004 result = CompileRun("function pa_load(p, start) {" 16005 " var sum = 0;" 16006 " for (var j = start; j < 256; j++) { sum += p[j]; }" 16007 " return sum;" 16008 "}" 16009 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16010 "just_ints = new Object();" 16011 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16012 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }" 16013 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 16014 "for (var i = 0; i < 10; ++i) {" 16015 " result = pa_load(pixels,-10);" 16016 "}" 16017 "result"); 16018 CHECK_EQ(0, result->Int32Value()); 16019 16020 // Make sure that generic ICs properly handles other types than pixel 16021 // arrays (that the inlined fast pixel array test leaves the right information 16022 // in the right registers). 16023 result = CompileRun("function pa_load(p) {" 16024 " var sum = 0;" 16025 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 16026 " return sum;" 16027 "}" 16028 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16029 "just_ints = new Object();" 16030 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16031 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 16032 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 16033 "sparse_array = new Object();" 16034 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }" 16035 "sparse_array[1000000] = 3;" 16036 "for (var i = 0; i < 10; ++i) {" 16037 " result = pa_load(sparse_array);" 16038 "}" 16039 "result"); 16040 CHECK_EQ(32640, result->Int32Value()); 16041 16042 // Make sure that pixel array store ICs clamp values correctly. 16043 result = CompileRun("function pa_store(p) {" 16044 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 16045 "}" 16046 "pa_store(pixels);" 16047 "var sum = 0;" 16048 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16049 "sum"); 16050 CHECK_EQ(48896, result->Int32Value()); 16051 16052 // Make sure that pixel array stores correctly handle accesses outside 16053 // of the pixel array.. 16054 result = CompileRun("function pa_store(p,start) {" 16055 " for (var j = 0; j < 256; j++) {" 16056 " p[j+start] = j * 2;" 16057 " }" 16058 "}" 16059 "pa_store(pixels,0);" 16060 "pa_store(pixels,-128);" 16061 "var sum = 0;" 16062 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16063 "sum"); 16064 CHECK_EQ(65280, result->Int32Value()); 16065 16066 // Make sure that the generic store stub correctly handle accesses outside 16067 // of the pixel array.. 16068 result = CompileRun("function pa_store(p,start) {" 16069 " for (var j = 0; j < 256; j++) {" 16070 " p[j+start] = j * 2;" 16071 " }" 16072 "}" 16073 "pa_store(pixels,0);" 16074 "just_ints = new Object();" 16075 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16076 "pa_store(just_ints, 0);" 16077 "pa_store(pixels,-128);" 16078 "var sum = 0;" 16079 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16080 "sum"); 16081 CHECK_EQ(65280, result->Int32Value()); 16082 16083 // Make sure that the generic keyed store stub clamps pixel array values 16084 // correctly. 16085 result = CompileRun("function pa_store(p) {" 16086 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 16087 "}" 16088 "pa_store(pixels);" 16089 "just_ints = new Object();" 16090 "pa_store(just_ints);" 16091 "pa_store(pixels);" 16092 "var sum = 0;" 16093 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16094 "sum"); 16095 CHECK_EQ(48896, result->Int32Value()); 16096 16097 // Make sure that pixel array loads are optimized by crankshaft. 16098 result = CompileRun("function pa_load(p) {" 16099 " var sum = 0;" 16100 " for (var i=0; i<256; ++i) {" 16101 " sum += p[i];" 16102 " }" 16103 " return sum; " 16104 "}" 16105 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16106 "for (var i = 0; i < 5000; ++i) {" 16107 " result = pa_load(pixels);" 16108 "}" 16109 "result"); 16110 CHECK_EQ(32640, result->Int32Value()); 16111 16112 // Make sure that pixel array stores are optimized by crankshaft. 16113 result = CompileRun("function pa_init(p) {" 16114 "for (var i = 0; i < 256; ++i) { p[i] = i; }" 16115 "}" 16116 "function pa_load(p) {" 16117 " var sum = 0;" 16118 " for (var i=0; i<256; ++i) {" 16119 " sum += p[i];" 16120 " }" 16121 " return sum; " 16122 "}" 16123 "for (var i = 0; i < 5000; ++i) {" 16124 " pa_init(pixels);" 16125 "}" 16126 "result = pa_load(pixels);" 16127 "result"); 16128 CHECK_EQ(32640, result->Int32Value()); 16129 16130 free(pixel_data); 16131 } 16132 16133 16134 THREADED_TEST(PixelArrayInfo) { 16135 LocalContext context; 16136 v8::HandleScope scope(context->GetIsolate()); 16137 for (int size = 0; size < 100; size += 10) { 16138 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size)); 16139 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16140 obj->SetIndexedPropertiesToPixelData(pixel_data, size); 16141 CHECK(obj->HasIndexedPropertiesInPixelData()); 16142 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData()); 16143 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength()); 16144 free(pixel_data); 16145 } 16146 } 16147 16148 16149 static void NotHandledIndexedPropertyGetter( 16150 uint32_t index, 16151 const v8::PropertyCallbackInfo<v8::Value>& info) { 16152 ApiTestFuzzer::Fuzz(); 16153 } 16154 16155 16156 static void NotHandledIndexedPropertySetter( 16157 uint32_t index, 16158 Local<Value> value, 16159 const v8::PropertyCallbackInfo<v8::Value>& info) { 16160 ApiTestFuzzer::Fuzz(); 16161 } 16162 16163 16164 THREADED_TEST(PixelArrayWithInterceptor) { 16165 LocalContext context; 16166 i::Factory* factory = CcTest::i_isolate()->factory(); 16167 v8::Isolate* isolate = context->GetIsolate(); 16168 v8::HandleScope scope(isolate); 16169 const int kElementCount = 260; 16170 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 16171 i::Handle<i::ExternalUint8ClampedArray> pixels = 16172 i::Handle<i::ExternalUint8ClampedArray>::cast( 16173 factory->NewExternalArray(kElementCount, 16174 v8::kExternalUint8ClampedArray, 16175 pixel_data)); 16176 for (int i = 0; i < kElementCount; i++) { 16177 pixels->set(i, i % 256); 16178 } 16179 v8::Handle<v8::ObjectTemplate> templ = 16180 v8::ObjectTemplate::New(context->GetIsolate()); 16181 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter, 16182 NotHandledIndexedPropertySetter); 16183 v8::Handle<v8::Object> obj = templ->NewInstance(); 16184 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 16185 context->Global()->Set(v8_str("pixels"), obj); 16186 v8::Handle<v8::Value> result = CompileRun("pixels[1]"); 16187 CHECK_EQ(1, result->Int32Value()); 16188 result = CompileRun("var sum = 0;" 16189 "for (var i = 0; i < 8; i++) {" 16190 " sum += pixels[i] = pixels[i] = -i;" 16191 "}" 16192 "sum;"); 16193 CHECK_EQ(-28, result->Int32Value()); 16194 result = CompileRun("pixels.hasOwnProperty('1')"); 16195 CHECK(result->BooleanValue()); 16196 free(pixel_data); 16197 } 16198 16199 16200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) { 16201 switch (array_type) { 16202 case v8::kExternalInt8Array: 16203 case v8::kExternalUint8Array: 16204 case v8::kExternalUint8ClampedArray: 16205 return 1; 16206 break; 16207 case v8::kExternalInt16Array: 16208 case v8::kExternalUint16Array: 16209 return 2; 16210 break; 16211 case v8::kExternalInt32Array: 16212 case v8::kExternalUint32Array: 16213 case v8::kExternalFloat32Array: 16214 return 4; 16215 break; 16216 case v8::kExternalFloat64Array: 16217 return 8; 16218 break; 16219 default: 16220 UNREACHABLE(); 16221 return -1; 16222 } 16223 UNREACHABLE(); 16224 return -1; 16225 } 16226 16227 16228 template <class ExternalArrayClass, class ElementType> 16229 static void ObjectWithExternalArrayTestHelper( 16230 Handle<Context> context, 16231 v8::Handle<Object> obj, 16232 int element_count, 16233 v8::ExternalArrayType array_type, 16234 int64_t low, int64_t high) { 16235 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16236 i::Isolate* isolate = jsobj->GetIsolate(); 16237 obj->Set(v8_str("field"), 16238 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503)); 16239 context->Global()->Set(v8_str("ext_array"), obj); 16240 v8::Handle<v8::Value> result = CompileRun("ext_array.field"); 16241 CHECK_EQ(1503, result->Int32Value()); 16242 result = CompileRun("ext_array[1]"); 16243 CHECK_EQ(1, result->Int32Value()); 16244 16245 // Check assigned smis 16246 result = CompileRun("for (var i = 0; i < 8; i++) {" 16247 " ext_array[i] = i;" 16248 "}" 16249 "var sum = 0;" 16250 "for (var i = 0; i < 8; i++) {" 16251 " sum += ext_array[i];" 16252 "}" 16253 "sum;"); 16254 16255 CHECK_EQ(28, result->Int32Value()); 16256 // Check pass through of assigned smis 16257 result = CompileRun("var sum = 0;" 16258 "for (var i = 0; i < 8; i++) {" 16259 " sum += ext_array[i] = ext_array[i] = -i;" 16260 "}" 16261 "sum;"); 16262 CHECK_EQ(-28, result->Int32Value()); 16263 16264 16265 // Check assigned smis in reverse order 16266 result = CompileRun("for (var i = 8; --i >= 0; ) {" 16267 " ext_array[i] = i;" 16268 "}" 16269 "var sum = 0;" 16270 "for (var i = 0; i < 8; i++) {" 16271 " sum += ext_array[i];" 16272 "}" 16273 "sum;"); 16274 CHECK_EQ(28, result->Int32Value()); 16275 16276 // Check pass through of assigned HeapNumbers 16277 result = CompileRun("var sum = 0;" 16278 "for (var i = 0; i < 16; i+=2) {" 16279 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 16280 "}" 16281 "sum;"); 16282 CHECK_EQ(-28, result->Int32Value()); 16283 16284 // Check assigned HeapNumbers 16285 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 16286 " ext_array[i] = (i * 0.5);" 16287 "}" 16288 "var sum = 0;" 16289 "for (var i = 0; i < 16; i+=2) {" 16290 " sum += ext_array[i];" 16291 "}" 16292 "sum;"); 16293 CHECK_EQ(28, result->Int32Value()); 16294 16295 // Check assigned HeapNumbers in reverse order 16296 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 16297 " ext_array[i] = (i * 0.5);" 16298 "}" 16299 "var sum = 0;" 16300 "for (var i = 0; i < 16; i+=2) {" 16301 " sum += ext_array[i];" 16302 "}" 16303 "sum;"); 16304 CHECK_EQ(28, result->Int32Value()); 16305 16306 i::ScopedVector<char> test_buf(1024); 16307 16308 // Check legal boundary conditions. 16309 // The repeated loads and stores ensure the ICs are exercised. 16310 const char* boundary_program = 16311 "var res = 0;" 16312 "for (var i = 0; i < 16; i++) {" 16313 " ext_array[i] = %lld;" 16314 " if (i > 8) {" 16315 " res = ext_array[i];" 16316 " }" 16317 "}" 16318 "res;"; 16319 i::SNPrintF(test_buf, 16320 boundary_program, 16321 low); 16322 result = CompileRun(test_buf.start()); 16323 CHECK_EQ(low, result->IntegerValue()); 16324 16325 i::SNPrintF(test_buf, 16326 boundary_program, 16327 high); 16328 result = CompileRun(test_buf.start()); 16329 CHECK_EQ(high, result->IntegerValue()); 16330 16331 // Check misprediction of type in IC. 16332 result = CompileRun("var tmp_array = ext_array;" 16333 "var sum = 0;" 16334 "for (var i = 0; i < 8; i++) {" 16335 " tmp_array[i] = i;" 16336 " sum += tmp_array[i];" 16337 " if (i == 4) {" 16338 " tmp_array = {};" 16339 " }" 16340 "}" 16341 "sum;"); 16342 // Force GC to trigger verification. 16343 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16344 CHECK_EQ(28, result->Int32Value()); 16345 16346 // Make sure out-of-range loads do not throw. 16347 i::SNPrintF(test_buf, 16348 "var caught_exception = false;" 16349 "try {" 16350 " ext_array[%d];" 16351 "} catch (e) {" 16352 " caught_exception = true;" 16353 "}" 16354 "caught_exception;", 16355 element_count); 16356 result = CompileRun(test_buf.start()); 16357 CHECK_EQ(false, result->BooleanValue()); 16358 16359 // Make sure out-of-range stores do not throw. 16360 i::SNPrintF(test_buf, 16361 "var caught_exception = false;" 16362 "try {" 16363 " ext_array[%d] = 1;" 16364 "} catch (e) {" 16365 " caught_exception = true;" 16366 "}" 16367 "caught_exception;", 16368 element_count); 16369 result = CompileRun(test_buf.start()); 16370 CHECK_EQ(false, result->BooleanValue()); 16371 16372 // Check other boundary conditions, values and operations. 16373 result = CompileRun("for (var i = 0; i < 8; i++) {" 16374 " ext_array[7] = undefined;" 16375 "}" 16376 "ext_array[7];"); 16377 CHECK_EQ(0, result->Int32Value()); 16378 if (array_type == v8::kExternalFloat64Array || 16379 array_type == v8::kExternalFloat32Array) { 16380 CHECK_EQ(static_cast<int>(i::OS::nan_value()), 16381 static_cast<int>( 16382 i::Object::GetElement( 16383 isolate, jsobj, 7).ToHandleChecked()->Number())); 16384 } else { 16385 CheckElementValue(isolate, 0, jsobj, 7); 16386 } 16387 16388 result = CompileRun("for (var i = 0; i < 8; i++) {" 16389 " ext_array[6] = '2.3';" 16390 "}" 16391 "ext_array[6];"); 16392 CHECK_EQ(2, result->Int32Value()); 16393 CHECK_EQ(2, 16394 static_cast<int>( 16395 i::Object::GetElement( 16396 isolate, jsobj, 6).ToHandleChecked()->Number())); 16397 16398 if (array_type != v8::kExternalFloat32Array && 16399 array_type != v8::kExternalFloat64Array) { 16400 // Though the specification doesn't state it, be explicit about 16401 // converting NaNs and +/-Infinity to zero. 16402 result = CompileRun("for (var i = 0; i < 8; i++) {" 16403 " ext_array[i] = 5;" 16404 "}" 16405 "for (var i = 0; i < 8; i++) {" 16406 " ext_array[i] = NaN;" 16407 "}" 16408 "ext_array[5];"); 16409 CHECK_EQ(0, result->Int32Value()); 16410 CheckElementValue(isolate, 0, jsobj, 5); 16411 16412 result = CompileRun("for (var i = 0; i < 8; i++) {" 16413 " ext_array[i] = 5;" 16414 "}" 16415 "for (var i = 0; i < 8; i++) {" 16416 " ext_array[i] = Infinity;" 16417 "}" 16418 "ext_array[5];"); 16419 int expected_value = 16420 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0; 16421 CHECK_EQ(expected_value, result->Int32Value()); 16422 CheckElementValue(isolate, expected_value, jsobj, 5); 16423 16424 result = CompileRun("for (var i = 0; i < 8; i++) {" 16425 " ext_array[i] = 5;" 16426 "}" 16427 "for (var i = 0; i < 8; i++) {" 16428 " ext_array[i] = -Infinity;" 16429 "}" 16430 "ext_array[5];"); 16431 CHECK_EQ(0, result->Int32Value()); 16432 CheckElementValue(isolate, 0, jsobj, 5); 16433 16434 // Check truncation behavior of integral arrays. 16435 const char* unsigned_data = 16436 "var source_data = [0.6, 10.6];" 16437 "var expected_results = [0, 10];"; 16438 const char* signed_data = 16439 "var source_data = [0.6, 10.6, -0.6, -10.6];" 16440 "var expected_results = [0, 10, 0, -10];"; 16441 const char* pixel_data = 16442 "var source_data = [0.6, 10.6];" 16443 "var expected_results = [1, 11];"; 16444 bool is_unsigned = 16445 (array_type == v8::kExternalUint8Array || 16446 array_type == v8::kExternalUint16Array || 16447 array_type == v8::kExternalUint32Array); 16448 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray; 16449 16450 i::SNPrintF(test_buf, 16451 "%s" 16452 "var all_passed = true;" 16453 "for (var i = 0; i < source_data.length; i++) {" 16454 " for (var j = 0; j < 8; j++) {" 16455 " ext_array[j] = source_data[i];" 16456 " }" 16457 " all_passed = all_passed &&" 16458 " (ext_array[5] == expected_results[i]);" 16459 "}" 16460 "all_passed;", 16461 (is_unsigned ? 16462 unsigned_data : 16463 (is_pixel_data ? pixel_data : signed_data))); 16464 result = CompileRun(test_buf.start()); 16465 CHECK_EQ(true, result->BooleanValue()); 16466 } 16467 16468 i::Handle<ExternalArrayClass> array( 16469 ExternalArrayClass::cast(jsobj->elements())); 16470 for (int i = 0; i < element_count; i++) { 16471 array->set(i, static_cast<ElementType>(i)); 16472 } 16473 16474 // Test complex assignments 16475 result = CompileRun("function ee_op_test_complex_func(sum) {" 16476 " for (var i = 0; i < 40; ++i) {" 16477 " sum += (ext_array[i] += 1);" 16478 " sum += (ext_array[i] -= 1);" 16479 " } " 16480 " return sum;" 16481 "}" 16482 "sum=0;" 16483 "for (var i=0;i<10000;++i) {" 16484 " sum=ee_op_test_complex_func(sum);" 16485 "}" 16486 "sum;"); 16487 CHECK_EQ(16000000, result->Int32Value()); 16488 16489 // Test count operations 16490 result = CompileRun("function ee_op_test_count_func(sum) {" 16491 " for (var i = 0; i < 40; ++i) {" 16492 " sum += (++ext_array[i]);" 16493 " sum += (--ext_array[i]);" 16494 " } " 16495 " return sum;" 16496 "}" 16497 "sum=0;" 16498 "for (var i=0;i<10000;++i) {" 16499 " sum=ee_op_test_count_func(sum);" 16500 "}" 16501 "sum;"); 16502 CHECK_EQ(16000000, result->Int32Value()); 16503 16504 result = CompileRun("ext_array[3] = 33;" 16505 "delete ext_array[3];" 16506 "ext_array[3];"); 16507 CHECK_EQ(33, result->Int32Value()); 16508 16509 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 16510 "ext_array[2] = 12; ext_array[3] = 13;" 16511 "ext_array.__defineGetter__('2'," 16512 "function() { return 120; });" 16513 "ext_array[2];"); 16514 CHECK_EQ(12, result->Int32Value()); 16515 16516 result = CompileRun("var js_array = new Array(40);" 16517 "js_array[0] = 77;" 16518 "js_array;"); 16519 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16520 16521 result = CompileRun("ext_array[1] = 23;" 16522 "ext_array.__proto__ = [];" 16523 "js_array.__proto__ = ext_array;" 16524 "js_array.concat(ext_array);"); 16525 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16526 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 16527 16528 result = CompileRun("ext_array[1] = 23;"); 16529 CHECK_EQ(23, result->Int32Value()); 16530 } 16531 16532 16533 template <class FixedTypedArrayClass, 16534 i::ElementsKind elements_kind, 16535 class ElementType> 16536 static void FixedTypedArrayTestHelper( 16537 v8::ExternalArrayType array_type, 16538 ElementType low, 16539 ElementType high) { 16540 i::FLAG_allow_natives_syntax = true; 16541 LocalContext context; 16542 i::Isolate* isolate = CcTest::i_isolate(); 16543 i::Factory* factory = isolate->factory(); 16544 v8::HandleScope scope(context->GetIsolate()); 16545 const int kElementCount = 260; 16546 i::Handle<FixedTypedArrayClass> fixed_array = 16547 i::Handle<FixedTypedArrayClass>::cast( 16548 factory->NewFixedTypedArray(kElementCount, array_type)); 16549 CHECK_EQ(FixedTypedArrayClass::kInstanceType, 16550 fixed_array->map()->instance_type()); 16551 CHECK_EQ(kElementCount, fixed_array->length()); 16552 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16553 for (int i = 0; i < kElementCount; i++) { 16554 fixed_array->set(i, static_cast<ElementType>(i)); 16555 } 16556 // Force GC to trigger verification. 16557 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16558 for (int i = 0; i < kElementCount; i++) { 16559 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)), 16560 static_cast<int64_t>(fixed_array->get_scalar(i))); 16561 } 16562 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate()); 16563 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16564 i::Handle<i::Map> fixed_array_map = 16565 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind); 16566 jsobj->set_map(*fixed_array_map); 16567 jsobj->set_elements(*fixed_array); 16568 16569 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>( 16570 context.local(), obj, kElementCount, array_type, 16571 static_cast<int64_t>(low), 16572 static_cast<int64_t>(high)); 16573 } 16574 16575 16576 THREADED_TEST(FixedUint8Array) { 16577 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>( 16578 v8::kExternalUint8Array, 16579 0x0, 0xFF); 16580 } 16581 16582 16583 THREADED_TEST(FixedUint8ClampedArray) { 16584 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray, 16585 i::UINT8_CLAMPED_ELEMENTS, uint8_t>( 16586 v8::kExternalUint8ClampedArray, 16587 0x0, 0xFF); 16588 } 16589 16590 16591 THREADED_TEST(FixedInt8Array) { 16592 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>( 16593 v8::kExternalInt8Array, 16594 -0x80, 0x7F); 16595 } 16596 16597 16598 THREADED_TEST(FixedUint16Array) { 16599 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>( 16600 v8::kExternalUint16Array, 16601 0x0, 0xFFFF); 16602 } 16603 16604 16605 THREADED_TEST(FixedInt16Array) { 16606 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>( 16607 v8::kExternalInt16Array, 16608 -0x8000, 0x7FFF); 16609 } 16610 16611 16612 THREADED_TEST(FixedUint32Array) { 16613 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>( 16614 v8::kExternalUint32Array, 16615 0x0, UINT_MAX); 16616 } 16617 16618 16619 THREADED_TEST(FixedInt32Array) { 16620 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>( 16621 v8::kExternalInt32Array, 16622 INT_MIN, INT_MAX); 16623 } 16624 16625 16626 THREADED_TEST(FixedFloat32Array) { 16627 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>( 16628 v8::kExternalFloat32Array, 16629 -500, 500); 16630 } 16631 16632 16633 THREADED_TEST(FixedFloat64Array) { 16634 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>( 16635 v8::kExternalFloat64Array, 16636 -500, 500); 16637 } 16638 16639 16640 template <class ExternalArrayClass, class ElementType> 16641 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, 16642 int64_t low, 16643 int64_t high) { 16644 LocalContext context; 16645 i::Isolate* isolate = CcTest::i_isolate(); 16646 i::Factory* factory = isolate->factory(); 16647 v8::HandleScope scope(context->GetIsolate()); 16648 const int kElementCount = 40; 16649 int element_size = ExternalArrayElementSize(array_type); 16650 ElementType* array_data = 16651 static_cast<ElementType*>(malloc(kElementCount * element_size)); 16652 i::Handle<ExternalArrayClass> array = 16653 i::Handle<ExternalArrayClass>::cast( 16654 factory->NewExternalArray(kElementCount, array_type, array_data)); 16655 // Force GC to trigger verification. 16656 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16657 for (int i = 0; i < kElementCount; i++) { 16658 array->set(i, static_cast<ElementType>(i)); 16659 } 16660 // Force GC to trigger verification. 16661 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16662 for (int i = 0; i < kElementCount; i++) { 16663 CHECK_EQ(static_cast<int64_t>(i), 16664 static_cast<int64_t>(array->get_scalar(i))); 16665 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); 16666 } 16667 16668 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16669 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16670 // Set the elements to be the external array. 16671 obj->SetIndexedPropertiesToExternalArrayData(array_data, 16672 array_type, 16673 kElementCount); 16674 CHECK_EQ(1, 16675 static_cast<int>( 16676 i::Object::GetElement( 16677 isolate, jsobj, 1).ToHandleChecked()->Number())); 16678 16679 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16680 context.local(), obj, kElementCount, array_type, low, high); 16681 16682 v8::Handle<v8::Value> result; 16683 16684 // Test more complex manipulations which cause eax to contain values 16685 // that won't be completely overwritten by loads from the arrays. 16686 // This catches bugs in the instructions used for the KeyedLoadIC 16687 // for byte and word types. 16688 { 16689 const int kXSize = 300; 16690 const int kYSize = 300; 16691 const int kLargeElementCount = kXSize * kYSize * 4; 16692 ElementType* large_array_data = 16693 static_cast<ElementType*>(malloc(kLargeElementCount * element_size)); 16694 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate()); 16695 // Set the elements to be the external array. 16696 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data, 16697 array_type, 16698 kLargeElementCount); 16699 context->Global()->Set(v8_str("large_array"), large_obj); 16700 // Initialize contents of a few rows. 16701 for (int x = 0; x < 300; x++) { 16702 int row = 0; 16703 int offset = row * 300 * 4; 16704 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16705 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16706 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16707 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16708 row = 150; 16709 offset = row * 300 * 4; 16710 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16711 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16712 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16713 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16714 row = 298; 16715 offset = row * 300 * 4; 16716 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16717 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16718 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16719 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16720 } 16721 // The goal of the code below is to make "offset" large enough 16722 // that the computation of the index (which goes into eax) has 16723 // high bits set which will not be overwritten by a byte or short 16724 // load. 16725 result = CompileRun("var failed = false;" 16726 "var offset = 0;" 16727 "for (var i = 0; i < 300; i++) {" 16728 " if (large_array[4 * i] != 127 ||" 16729 " large_array[4 * i + 1] != 0 ||" 16730 " large_array[4 * i + 2] != 0 ||" 16731 " large_array[4 * i + 3] != 127) {" 16732 " failed = true;" 16733 " }" 16734 "}" 16735 "offset = 150 * 300 * 4;" 16736 "for (var i = 0; i < 300; i++) {" 16737 " if (large_array[offset + 4 * i] != 127 ||" 16738 " large_array[offset + 4 * i + 1] != 0 ||" 16739 " large_array[offset + 4 * i + 2] != 0 ||" 16740 " large_array[offset + 4 * i + 3] != 127) {" 16741 " failed = true;" 16742 " }" 16743 "}" 16744 "offset = 298 * 300 * 4;" 16745 "for (var i = 0; i < 300; i++) {" 16746 " if (large_array[offset + 4 * i] != 127 ||" 16747 " large_array[offset + 4 * i + 1] != 0 ||" 16748 " large_array[offset + 4 * i + 2] != 0 ||" 16749 " large_array[offset + 4 * i + 3] != 127) {" 16750 " failed = true;" 16751 " }" 16752 "}" 16753 "!failed;"); 16754 CHECK_EQ(true, result->BooleanValue()); 16755 free(large_array_data); 16756 } 16757 16758 // The "" property descriptor is overloaded to store information about 16759 // the external array. Ensure that setting and accessing the "" property 16760 // works (it should overwrite the information cached about the external 16761 // array in the DescriptorArray) in various situations. 16762 result = CompileRun("ext_array[''] = 23; ext_array['']"); 16763 CHECK_EQ(23, result->Int32Value()); 16764 16765 // Property "" set after the external array is associated with the object. 16766 { 16767 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16768 obj2->Set(v8_str("ee_test_field"), 16769 v8::Int32::New(context->GetIsolate(), 256)); 16770 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503)); 16771 // Set the elements to be the external array. 16772 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16773 array_type, 16774 kElementCount); 16775 context->Global()->Set(v8_str("ext_array"), obj2); 16776 result = CompileRun("ext_array['']"); 16777 CHECK_EQ(1503, result->Int32Value()); 16778 } 16779 16780 // Property "" set after the external array is associated with the object. 16781 { 16782 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16783 obj2->Set(v8_str("ee_test_field_2"), 16784 v8::Int32::New(context->GetIsolate(), 256)); 16785 // Set the elements to be the external array. 16786 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16787 array_type, 16788 kElementCount); 16789 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503)); 16790 context->Global()->Set(v8_str("ext_array"), obj2); 16791 result = CompileRun("ext_array['']"); 16792 CHECK_EQ(1503, result->Int32Value()); 16793 } 16794 16795 // Should reuse the map from previous test. 16796 { 16797 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16798 obj2->Set(v8_str("ee_test_field_2"), 16799 v8::Int32::New(context->GetIsolate(), 256)); 16800 // Set the elements to be the external array. Should re-use the map 16801 // from previous test. 16802 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16803 array_type, 16804 kElementCount); 16805 context->Global()->Set(v8_str("ext_array"), obj2); 16806 result = CompileRun("ext_array['']"); 16807 } 16808 16809 // Property "" is a constant function that shouldn't not be interfered with 16810 // when an external array is set. 16811 { 16812 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16813 // Start 16814 obj2->Set(v8_str("ee_test_field3"), 16815 v8::Int32::New(context->GetIsolate(), 256)); 16816 16817 // Add a constant function to an object. 16818 context->Global()->Set(v8_str("ext_array"), obj2); 16819 result = CompileRun("ext_array[''] = function() {return 1503;};" 16820 "ext_array['']();"); 16821 16822 // Add an external array transition to the same map that 16823 // has the constant transition. 16824 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate()); 16825 obj3->Set(v8_str("ee_test_field3"), 16826 v8::Int32::New(context->GetIsolate(), 256)); 16827 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16828 array_type, 16829 kElementCount); 16830 context->Global()->Set(v8_str("ext_array"), obj3); 16831 } 16832 16833 // If a external array transition is in the map, it should get clobbered 16834 // by a constant function. 16835 { 16836 // Add an external array transition. 16837 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate()); 16838 obj3->Set(v8_str("ee_test_field4"), 16839 v8::Int32::New(context->GetIsolate(), 256)); 16840 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16841 array_type, 16842 kElementCount); 16843 16844 // Add a constant function to the same map that just got an external array 16845 // transition. 16846 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16847 obj2->Set(v8_str("ee_test_field4"), 16848 v8::Int32::New(context->GetIsolate(), 256)); 16849 context->Global()->Set(v8_str("ext_array"), obj2); 16850 result = CompileRun("ext_array[''] = function() {return 1503;};" 16851 "ext_array['']();"); 16852 } 16853 16854 free(array_data); 16855 } 16856 16857 16858 THREADED_TEST(ExternalInt8Array) { 16859 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>( 16860 v8::kExternalInt8Array, 16861 -128, 16862 127); 16863 } 16864 16865 16866 THREADED_TEST(ExternalUint8Array) { 16867 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>( 16868 v8::kExternalUint8Array, 16869 0, 16870 255); 16871 } 16872 16873 16874 THREADED_TEST(ExternalUint8ClampedArray) { 16875 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>( 16876 v8::kExternalUint8ClampedArray, 16877 0, 16878 255); 16879 } 16880 16881 16882 THREADED_TEST(ExternalInt16Array) { 16883 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>( 16884 v8::kExternalInt16Array, 16885 -32768, 16886 32767); 16887 } 16888 16889 16890 THREADED_TEST(ExternalUint16Array) { 16891 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>( 16892 v8::kExternalUint16Array, 16893 0, 16894 65535); 16895 } 16896 16897 16898 THREADED_TEST(ExternalInt32Array) { 16899 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>( 16900 v8::kExternalInt32Array, 16901 INT_MIN, // -2147483648 16902 INT_MAX); // 2147483647 16903 } 16904 16905 16906 THREADED_TEST(ExternalUint32Array) { 16907 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>( 16908 v8::kExternalUint32Array, 16909 0, 16910 UINT_MAX); // 4294967295 16911 } 16912 16913 16914 THREADED_TEST(ExternalFloat32Array) { 16915 ExternalArrayTestHelper<i::ExternalFloat32Array, float>( 16916 v8::kExternalFloat32Array, 16917 -500, 16918 500); 16919 } 16920 16921 16922 THREADED_TEST(ExternalFloat64Array) { 16923 ExternalArrayTestHelper<i::ExternalFloat64Array, double>( 16924 v8::kExternalFloat64Array, 16925 -500, 16926 500); 16927 } 16928 16929 16930 THREADED_TEST(ExternalArrays) { 16931 TestExternalInt8Array(); 16932 TestExternalUint8Array(); 16933 TestExternalInt16Array(); 16934 TestExternalUint16Array(); 16935 TestExternalInt32Array(); 16936 TestExternalUint32Array(); 16937 TestExternalFloat32Array(); 16938 } 16939 16940 16941 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) { 16942 LocalContext context; 16943 v8::HandleScope scope(context->GetIsolate()); 16944 for (int size = 0; size < 100; size += 10) { 16945 int element_size = ExternalArrayElementSize(array_type); 16946 void* external_data = malloc(size * element_size); 16947 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16948 obj->SetIndexedPropertiesToExternalArrayData( 16949 external_data, array_type, size); 16950 CHECK(obj->HasIndexedPropertiesInExternalArrayData()); 16951 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData()); 16952 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType()); 16953 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength()); 16954 free(external_data); 16955 } 16956 } 16957 16958 16959 THREADED_TEST(ExternalArrayInfo) { 16960 ExternalArrayInfoTestHelper(v8::kExternalInt8Array); 16961 ExternalArrayInfoTestHelper(v8::kExternalUint8Array); 16962 ExternalArrayInfoTestHelper(v8::kExternalInt16Array); 16963 ExternalArrayInfoTestHelper(v8::kExternalUint16Array); 16964 ExternalArrayInfoTestHelper(v8::kExternalInt32Array); 16965 ExternalArrayInfoTestHelper(v8::kExternalUint32Array); 16966 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array); 16967 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array); 16968 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray); 16969 } 16970 16971 16972 void ExtArrayLimitsHelper(v8::Isolate* isolate, 16973 v8::ExternalArrayType array_type, 16974 int size) { 16975 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 16976 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 16977 last_location = last_message = NULL; 16978 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size); 16979 CHECK(!obj->HasIndexedPropertiesInExternalArrayData()); 16980 CHECK_NE(NULL, last_location); 16981 CHECK_NE(NULL, last_message); 16982 } 16983 16984 16985 TEST(ExternalArrayLimits) { 16986 LocalContext context; 16987 v8::Isolate* isolate = context->GetIsolate(); 16988 v8::HandleScope scope(isolate); 16989 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000); 16990 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff); 16991 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000); 16992 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff); 16993 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000); 16994 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff); 16995 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000); 16996 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff); 16997 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000); 16998 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff); 16999 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000); 17000 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff); 17001 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000); 17002 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff); 17003 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000); 17004 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff); 17005 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000); 17006 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff); 17007 } 17008 17009 17010 template <typename ElementType, typename TypedArray, 17011 class ExternalArrayClass> 17012 void TypedArrayTestHelper(v8::ExternalArrayType array_type, 17013 int64_t low, int64_t high) { 17014 const int kElementCount = 50; 17015 17016 i::ScopedVector<ElementType> backing_store(kElementCount+2); 17017 17018 LocalContext env; 17019 v8::Isolate* isolate = env->GetIsolate(); 17020 v8::HandleScope handle_scope(isolate); 17021 17022 Local<v8::ArrayBuffer> ab = 17023 v8::ArrayBuffer::New(isolate, backing_store.start(), 17024 (kElementCount + 2) * sizeof(ElementType)); 17025 Local<TypedArray> ta = 17026 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 17027 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 17028 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 17029 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset())); 17030 CHECK_EQ(kElementCount*sizeof(ElementType), 17031 static_cast<int>(ta->ByteLength())); 17032 CHECK_EQ(ab, ta->Buffer()); 17033 17034 ElementType* data = backing_store.start() + 2; 17035 for (int i = 0; i < kElementCount; i++) { 17036 data[i] = static_cast<ElementType>(i); 17037 } 17038 17039 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 17040 env.local(), ta, kElementCount, array_type, low, high); 17041 } 17042 17043 17044 THREADED_TEST(Uint8Array) { 17045 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>( 17046 v8::kExternalUint8Array, 0, 0xFF); 17047 } 17048 17049 17050 THREADED_TEST(Int8Array) { 17051 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>( 17052 v8::kExternalInt8Array, -0x80, 0x7F); 17053 } 17054 17055 17056 THREADED_TEST(Uint16Array) { 17057 TypedArrayTestHelper<uint16_t, 17058 v8::Uint16Array, 17059 i::ExternalUint16Array>( 17060 v8::kExternalUint16Array, 0, 0xFFFF); 17061 } 17062 17063 17064 THREADED_TEST(Int16Array) { 17065 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>( 17066 v8::kExternalInt16Array, -0x8000, 0x7FFF); 17067 } 17068 17069 17070 THREADED_TEST(Uint32Array) { 17071 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>( 17072 v8::kExternalUint32Array, 0, UINT_MAX); 17073 } 17074 17075 17076 THREADED_TEST(Int32Array) { 17077 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>( 17078 v8::kExternalInt32Array, INT_MIN, INT_MAX); 17079 } 17080 17081 17082 THREADED_TEST(Float32Array) { 17083 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>( 17084 v8::kExternalFloat32Array, -500, 500); 17085 } 17086 17087 17088 THREADED_TEST(Float64Array) { 17089 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>( 17090 v8::kExternalFloat64Array, -500, 500); 17091 } 17092 17093 17094 THREADED_TEST(Uint8ClampedArray) { 17095 TypedArrayTestHelper<uint8_t, 17096 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>( 17097 v8::kExternalUint8ClampedArray, 0, 0xFF); 17098 } 17099 17100 17101 THREADED_TEST(DataView) { 17102 const int kSize = 50; 17103 17104 i::ScopedVector<uint8_t> backing_store(kSize+2); 17105 17106 LocalContext env; 17107 v8::Isolate* isolate = env->GetIsolate(); 17108 v8::HandleScope handle_scope(isolate); 17109 17110 Local<v8::ArrayBuffer> ab = 17111 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 17112 Local<v8::DataView> dv = 17113 v8::DataView::New(ab, 2, kSize); 17114 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 17115 CHECK_EQ(2, static_cast<int>(dv->ByteOffset())); 17116 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 17117 CHECK_EQ(ab, dv->Buffer()); 17118 } 17119 17120 17121 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 17122 THREADED_TEST(Is##View) { \ 17123 LocalContext env; \ 17124 v8::Isolate* isolate = env->GetIsolate(); \ 17125 v8::HandleScope handle_scope(isolate); \ 17126 \ 17127 Handle<Value> result = CompileRun( \ 17128 "var ab = new ArrayBuffer(128);" \ 17129 "new " #View "(ab)"); \ 17130 CHECK(result->IsArrayBufferView()); \ 17131 CHECK(result->Is##View()); \ 17132 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 17133 } 17134 17135 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 17136 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 17137 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 17138 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 17139 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 17140 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 17141 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 17142 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 17143 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 17144 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 17145 17146 #undef IS_ARRAY_BUFFER_VIEW_TEST 17147 17148 17149 17150 THREADED_TEST(ScriptContextDependence) { 17151 LocalContext c1; 17152 v8::HandleScope scope(c1->GetIsolate()); 17153 const char *source = "foo"; 17154 v8::Handle<v8::Script> dep = v8_compile(source); 17155 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8( 17156 c1->GetIsolate(), source)); 17157 v8::Handle<v8::UnboundScript> indep = 17158 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source); 17159 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"), 17160 v8::Integer::New(c1->GetIsolate(), 100)); 17161 CHECK_EQ(dep->Run()->Int32Value(), 100); 17162 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100); 17163 LocalContext c2; 17164 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"), 17165 v8::Integer::New(c2->GetIsolate(), 101)); 17166 CHECK_EQ(dep->Run()->Int32Value(), 100); 17167 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101); 17168 } 17169 17170 17171 THREADED_TEST(StackTrace) { 17172 LocalContext context; 17173 v8::HandleScope scope(context->GetIsolate()); 17174 v8::TryCatch try_catch; 17175 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 17176 v8::Handle<v8::String> src = 17177 v8::String::NewFromUtf8(context->GetIsolate(), source); 17178 v8::Handle<v8::String> origin = 17179 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test"); 17180 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin)); 17181 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source) 17182 ->BindToCurrentContext() 17183 ->Run(); 17184 CHECK(try_catch.HasCaught()); 17185 v8::String::Utf8Value stack(try_catch.StackTrace()); 17186 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 17187 } 17188 17189 17190 // Checks that a StackFrame has certain expected values. 17191 void checkStackFrame(const char* expected_script_name, 17192 const char* expected_func_name, int expected_line_number, 17193 int expected_column, bool is_eval, bool is_constructor, 17194 v8::Handle<v8::StackFrame> frame) { 17195 v8::HandleScope scope(CcTest::isolate()); 17196 v8::String::Utf8Value func_name(frame->GetFunctionName()); 17197 v8::String::Utf8Value script_name(frame->GetScriptName()); 17198 if (*script_name == NULL) { 17199 // The situation where there is no associated script, like for evals. 17200 CHECK(expected_script_name == NULL); 17201 } else { 17202 CHECK(strstr(*script_name, expected_script_name) != NULL); 17203 } 17204 CHECK(strstr(*func_name, expected_func_name) != NULL); 17205 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 17206 CHECK_EQ(expected_column, frame->GetColumn()); 17207 CHECK_EQ(is_eval, frame->IsEval()); 17208 CHECK_EQ(is_constructor, frame->IsConstructor()); 17209 } 17210 17211 17212 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 17213 v8::HandleScope scope(args.GetIsolate()); 17214 const char* origin = "capture-stack-trace-test"; 17215 const int kOverviewTest = 1; 17216 const int kDetailedTest = 2; 17217 17218 ASSERT(args.Length() == 1); 17219 17220 int testGroup = args[0]->Int32Value(); 17221 if (testGroup == kOverviewTest) { 17222 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17223 args.GetIsolate(), 10, v8::StackTrace::kOverview); 17224 CHECK_EQ(4, stackTrace->GetFrameCount()); 17225 checkStackFrame(origin, "bar", 2, 10, false, false, 17226 stackTrace->GetFrame(0)); 17227 checkStackFrame(origin, "foo", 6, 3, false, false, 17228 stackTrace->GetFrame(1)); 17229 // This is the source string inside the eval which has the call to foo. 17230 checkStackFrame(NULL, "", 1, 5, false, false, 17231 stackTrace->GetFrame(2)); 17232 // The last frame is an anonymous function which has the initial eval call. 17233 checkStackFrame(origin, "", 8, 7, false, false, 17234 stackTrace->GetFrame(3)); 17235 17236 CHECK(stackTrace->AsArray()->IsArray()); 17237 } else if (testGroup == kDetailedTest) { 17238 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17239 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17240 CHECK_EQ(4, stackTrace->GetFrameCount()); 17241 checkStackFrame(origin, "bat", 4, 22, false, false, 17242 stackTrace->GetFrame(0)); 17243 checkStackFrame(origin, "baz", 8, 3, false, true, 17244 stackTrace->GetFrame(1)); 17245 bool is_eval = true; 17246 // This is the source string inside the eval which has the call to baz. 17247 checkStackFrame(NULL, "", 1, 5, is_eval, false, 17248 stackTrace->GetFrame(2)); 17249 // The last frame is an anonymous function which has the initial eval call. 17250 checkStackFrame(origin, "", 10, 1, false, false, 17251 stackTrace->GetFrame(3)); 17252 17253 CHECK(stackTrace->AsArray()->IsArray()); 17254 } 17255 } 17256 17257 17258 // Tests the C++ StackTrace API. 17259 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 17260 // THREADED_TEST(CaptureStackTrace) { 17261 TEST(CaptureStackTrace) { 17262 v8::Isolate* isolate = CcTest::isolate(); 17263 v8::HandleScope scope(isolate); 17264 v8::Handle<v8::String> origin = 17265 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test"); 17266 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17267 templ->Set(v8_str("AnalyzeStackInNativeCode"), 17268 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode)); 17269 LocalContext context(0, templ); 17270 17271 // Test getting OVERVIEW information. Should ignore information that is not 17272 // script name, function name, line number, and column offset. 17273 const char *overview_source = 17274 "function bar() {\n" 17275 " var y; AnalyzeStackInNativeCode(1);\n" 17276 "}\n" 17277 "function foo() {\n" 17278 "\n" 17279 " bar();\n" 17280 "}\n" 17281 "var x;eval('new foo();');"; 17282 v8::Handle<v8::String> overview_src = 17283 v8::String::NewFromUtf8(isolate, overview_source); 17284 v8::ScriptCompiler::Source script_source(overview_src, 17285 v8::ScriptOrigin(origin)); 17286 v8::Handle<Value> overview_result( 17287 v8::ScriptCompiler::CompileUnbound(isolate, &script_source) 17288 ->BindToCurrentContext() 17289 ->Run()); 17290 CHECK(!overview_result.IsEmpty()); 17291 CHECK(overview_result->IsObject()); 17292 17293 // Test getting DETAILED information. 17294 const char *detailed_source = 17295 "function bat() {AnalyzeStackInNativeCode(2);\n" 17296 "}\n" 17297 "\n" 17298 "function baz() {\n" 17299 " bat();\n" 17300 "}\n" 17301 "eval('new baz();');"; 17302 v8::Handle<v8::String> detailed_src = 17303 v8::String::NewFromUtf8(isolate, detailed_source); 17304 // Make the script using a non-zero line and column offset. 17305 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3); 17306 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5); 17307 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 17308 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin); 17309 v8::Handle<v8::UnboundScript> detailed_script( 17310 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2)); 17311 v8::Handle<Value> detailed_result( 17312 detailed_script->BindToCurrentContext()->Run()); 17313 CHECK(!detailed_result.IsEmpty()); 17314 CHECK(detailed_result->IsObject()); 17315 } 17316 17317 17318 static void StackTraceForUncaughtExceptionListener( 17319 v8::Handle<v8::Message> message, 17320 v8::Handle<Value>) { 17321 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17322 CHECK_EQ(2, stack_trace->GetFrameCount()); 17323 checkStackFrame("origin", "foo", 2, 3, false, false, 17324 stack_trace->GetFrame(0)); 17325 checkStackFrame("origin", "bar", 5, 3, false, false, 17326 stack_trace->GetFrame(1)); 17327 } 17328 17329 17330 TEST(CaptureStackTraceForUncaughtException) { 17331 report_count = 0; 17332 LocalContext env; 17333 v8::HandleScope scope(env->GetIsolate()); 17334 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener); 17335 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17336 17337 CompileRunWithOrigin( 17338 "function foo() {\n" 17339 " throw 1;\n" 17340 "};\n" 17341 "function bar() {\n" 17342 " foo();\n" 17343 "};", 17344 "origin"); 17345 v8::Local<v8::Object> global = env->Global(); 17346 Local<Value> trouble = global->Get(v8_str("bar")); 17347 CHECK(trouble->IsFunction()); 17348 Function::Cast(*trouble)->Call(global, 0, NULL); 17349 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17350 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 17351 } 17352 17353 17354 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 17355 LocalContext env; 17356 v8::HandleScope scope(env->GetIsolate()); 17357 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, 17358 1024, 17359 v8::StackTrace::kDetailed); 17360 17361 CompileRun( 17362 "var setters = ['column', 'lineNumber', 'scriptName',\n" 17363 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 17364 " 'isConstructor'];\n" 17365 "for (var i = 0; i < setters.length; i++) {\n" 17366 " var prop = setters[i];\n" 17367 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 17368 "}\n"); 17369 CompileRun("throw 'exception';"); 17370 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17371 } 17372 17373 17374 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message, 17375 v8::Handle<v8::Value> data) { 17376 // Use the frame where JavaScript is called from. 17377 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17378 CHECK(!stack_trace.IsEmpty()); 17379 int frame_count = stack_trace->GetFrameCount(); 17380 CHECK_EQ(3, frame_count); 17381 int line_number[] = {1, 2, 5}; 17382 for (int i = 0; i < frame_count; i++) { 17383 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17384 } 17385 } 17386 17387 17388 // Test that we only return the stack trace at the site where the exception 17389 // is first thrown (not where it is rethrown). 17390 TEST(RethrowStackTrace) { 17391 LocalContext env; 17392 v8::HandleScope scope(env->GetIsolate()); 17393 // We make sure that 17394 // - the stack trace of the ReferenceError in g() is reported. 17395 // - the stack trace is not overwritten when e1 is rethrown by t(). 17396 // - the stack trace of e2 does not overwrite that of e1. 17397 const char* source = 17398 "function g() { error; } \n" 17399 "function f() { g(); } \n" 17400 "function t(e) { throw e; } \n" 17401 "try { \n" 17402 " f(); \n" 17403 "} catch (e1) { \n" 17404 " try { \n" 17405 " error; \n" 17406 " } catch (e2) { \n" 17407 " t(e1); \n" 17408 " } \n" 17409 "} \n"; 17410 v8::V8::AddMessageListener(RethrowStackTraceHandler); 17411 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17412 CompileRun(source); 17413 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17414 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler); 17415 } 17416 17417 17418 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message, 17419 v8::Handle<v8::Value> data) { 17420 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17421 CHECK(!stack_trace.IsEmpty()); 17422 int frame_count = stack_trace->GetFrameCount(); 17423 CHECK_EQ(2, frame_count); 17424 int line_number[] = {3, 7}; 17425 for (int i = 0; i < frame_count; i++) { 17426 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17427 } 17428 } 17429 17430 17431 // Test that we do not recognize identity for primitive exceptions. 17432 TEST(RethrowPrimitiveStackTrace) { 17433 LocalContext env; 17434 v8::HandleScope scope(env->GetIsolate()); 17435 // We do not capture stack trace for non Error objects on creation time. 17436 // Instead, we capture the stack trace on last throw. 17437 const char* source = 17438 "function g() { throw 404; } \n" 17439 "function f() { g(); } \n" 17440 "function t(e) { throw e; } \n" 17441 "try { \n" 17442 " f(); \n" 17443 "} catch (e1) { \n" 17444 " t(e1) \n" 17445 "} \n"; 17446 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler); 17447 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17448 CompileRun(source); 17449 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17450 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 17451 } 17452 17453 17454 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message, 17455 v8::Handle<v8::Value> data) { 17456 // Use the frame where JavaScript is called from. 17457 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17458 CHECK(!stack_trace.IsEmpty()); 17459 CHECK_EQ(1, stack_trace->GetFrameCount()); 17460 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 17461 } 17462 17463 17464 // Test that the stack trace is captured when the error object is created and 17465 // not where it is thrown. 17466 TEST(RethrowExistingStackTrace) { 17467 LocalContext env; 17468 v8::HandleScope scope(env->GetIsolate()); 17469 const char* source = 17470 "var e = new Error(); \n" 17471 "throw e; \n"; 17472 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler); 17473 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17474 CompileRun(source); 17475 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17476 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler); 17477 } 17478 17479 17480 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message, 17481 v8::Handle<v8::Value> data) { 17482 // Use the frame where JavaScript is called from. 17483 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17484 CHECK(!stack_trace.IsEmpty()); 17485 CHECK_EQ(1, stack_trace->GetFrameCount()); 17486 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 17487 } 17488 17489 17490 // Test that the stack trace is captured where the bogus Error object is thrown. 17491 TEST(RethrowBogusErrorStackTrace) { 17492 LocalContext env; 17493 v8::HandleScope scope(env->GetIsolate()); 17494 const char* source = 17495 "var e = {__proto__: new Error()} \n" 17496 "throw e; \n"; 17497 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler); 17498 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17499 CompileRun(source); 17500 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17501 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 17502 } 17503 17504 17505 void AnalyzeStackOfEvalWithSourceURL( 17506 const v8::FunctionCallbackInfo<v8::Value>& args) { 17507 v8::HandleScope scope(args.GetIsolate()); 17508 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17509 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17510 CHECK_EQ(5, stackTrace->GetFrameCount()); 17511 v8::Handle<v8::String> url = v8_str("eval_url"); 17512 for (int i = 0; i < 3; i++) { 17513 v8::Handle<v8::String> name = 17514 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17515 CHECK(!name.IsEmpty()); 17516 CHECK_EQ(url, name); 17517 } 17518 } 17519 17520 17521 TEST(SourceURLInStackTrace) { 17522 v8::Isolate* isolate = CcTest::isolate(); 17523 v8::HandleScope scope(isolate); 17524 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17525 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 17526 v8::FunctionTemplate::New(isolate, 17527 AnalyzeStackOfEvalWithSourceURL)); 17528 LocalContext context(0, templ); 17529 17530 const char *source = 17531 "function outer() {\n" 17532 "function bar() {\n" 17533 " AnalyzeStackOfEvalWithSourceURL();\n" 17534 "}\n" 17535 "function foo() {\n" 17536 "\n" 17537 " bar();\n" 17538 "}\n" 17539 "foo();\n" 17540 "}\n" 17541 "eval('(' + outer +')()%s');"; 17542 17543 i::ScopedVector<char> code(1024); 17544 i::SNPrintF(code, source, "//# sourceURL=eval_url"); 17545 CHECK(CompileRun(code.start())->IsUndefined()); 17546 i::SNPrintF(code, source, "//@ sourceURL=eval_url"); 17547 CHECK(CompileRun(code.start())->IsUndefined()); 17548 } 17549 17550 17551 static int scriptIdInStack[2]; 17552 17553 void AnalyzeScriptIdInStack( 17554 const v8::FunctionCallbackInfo<v8::Value>& args) { 17555 v8::HandleScope scope(args.GetIsolate()); 17556 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17557 args.GetIsolate(), 10, v8::StackTrace::kScriptId); 17558 CHECK_EQ(2, stackTrace->GetFrameCount()); 17559 for (int i = 0; i < 2; i++) { 17560 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId(); 17561 } 17562 } 17563 17564 17565 TEST(ScriptIdInStackTrace) { 17566 v8::Isolate* isolate = CcTest::isolate(); 17567 v8::HandleScope scope(isolate); 17568 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17569 templ->Set(v8_str("AnalyzeScriptIdInStack"), 17570 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack)); 17571 LocalContext context(0, templ); 17572 17573 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 17574 isolate, 17575 "function foo() {\n" 17576 " AnalyzeScriptIdInStack();" 17577 "}\n" 17578 "foo();\n"); 17579 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test"); 17580 script->Run(); 17581 for (int i = 0; i < 2; i++) { 17582 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); 17583 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId()); 17584 } 17585 } 17586 17587 17588 void AnalyzeStackOfInlineScriptWithSourceURL( 17589 const v8::FunctionCallbackInfo<v8::Value>& args) { 17590 v8::HandleScope scope(args.GetIsolate()); 17591 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17592 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17593 CHECK_EQ(4, stackTrace->GetFrameCount()); 17594 v8::Handle<v8::String> url = v8_str("url"); 17595 for (int i = 0; i < 3; i++) { 17596 v8::Handle<v8::String> name = 17597 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17598 CHECK(!name.IsEmpty()); 17599 CHECK_EQ(url, name); 17600 } 17601 } 17602 17603 17604 TEST(InlineScriptWithSourceURLInStackTrace) { 17605 v8::Isolate* isolate = CcTest::isolate(); 17606 v8::HandleScope scope(isolate); 17607 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17608 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 17609 v8::FunctionTemplate::New( 17610 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL)); 17611 LocalContext context(0, templ); 17612 17613 const char *source = 17614 "function outer() {\n" 17615 "function bar() {\n" 17616 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 17617 "}\n" 17618 "function foo() {\n" 17619 "\n" 17620 " bar();\n" 17621 "}\n" 17622 "foo();\n" 17623 "}\n" 17624 "outer()\n%s"; 17625 17626 i::ScopedVector<char> code(1024); 17627 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17628 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17629 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17630 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17631 } 17632 17633 17634 void AnalyzeStackOfDynamicScriptWithSourceURL( 17635 const v8::FunctionCallbackInfo<v8::Value>& args) { 17636 v8::HandleScope scope(args.GetIsolate()); 17637 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17638 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17639 CHECK_EQ(4, stackTrace->GetFrameCount()); 17640 v8::Handle<v8::String> url = v8_str("source_url"); 17641 for (int i = 0; i < 3; i++) { 17642 v8::Handle<v8::String> name = 17643 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17644 CHECK(!name.IsEmpty()); 17645 CHECK_EQ(url, name); 17646 } 17647 } 17648 17649 17650 TEST(DynamicWithSourceURLInStackTrace) { 17651 v8::Isolate* isolate = CcTest::isolate(); 17652 v8::HandleScope scope(isolate); 17653 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17654 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 17655 v8::FunctionTemplate::New( 17656 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL)); 17657 LocalContext context(0, templ); 17658 17659 const char *source = 17660 "function outer() {\n" 17661 "function bar() {\n" 17662 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 17663 "}\n" 17664 "function foo() {\n" 17665 "\n" 17666 " bar();\n" 17667 "}\n" 17668 "foo();\n" 17669 "}\n" 17670 "outer()\n%s"; 17671 17672 i::ScopedVector<char> code(1024); 17673 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17674 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17675 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17676 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17677 } 17678 17679 17680 TEST(DynamicWithSourceURLInStackTraceString) { 17681 LocalContext context; 17682 v8::HandleScope scope(context->GetIsolate()); 17683 17684 const char *source = 17685 "function outer() {\n" 17686 " function foo() {\n" 17687 " FAIL.FAIL;\n" 17688 " }\n" 17689 " foo();\n" 17690 "}\n" 17691 "outer()\n%s"; 17692 17693 i::ScopedVector<char> code(1024); 17694 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17695 v8::TryCatch try_catch; 17696 CompileRunWithOrigin(code.start(), "", 0, 0); 17697 CHECK(try_catch.HasCaught()); 17698 v8::String::Utf8Value stack(try_catch.StackTrace()); 17699 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL); 17700 } 17701 17702 17703 static void CreateGarbageInOldSpace() { 17704 i::Factory* factory = CcTest::i_isolate()->factory(); 17705 v8::HandleScope scope(CcTest::isolate()); 17706 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate()); 17707 for (int i = 0; i < 1000; i++) { 17708 factory->NewFixedArray(1000, i::TENURED); 17709 } 17710 } 17711 17712 17713 // Test that idle notification can be handled and eventually returns true. 17714 TEST(IdleNotification) { 17715 const intptr_t MB = 1024 * 1024; 17716 LocalContext env; 17717 v8::HandleScope scope(env->GetIsolate()); 17718 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17719 CreateGarbageInOldSpace(); 17720 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17721 CHECK_GT(size_with_garbage, initial_size + MB); 17722 bool finished = false; 17723 for (int i = 0; i < 200 && !finished; i++) { 17724 finished = v8::V8::IdleNotification(); 17725 } 17726 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17727 CHECK(finished); 17728 CHECK_LT(final_size, initial_size + 1); 17729 } 17730 17731 17732 // Test that idle notification can be handled and eventually collects garbage. 17733 TEST(IdleNotificationWithSmallHint) { 17734 const intptr_t MB = 1024 * 1024; 17735 const int IdlePauseInMs = 900; 17736 LocalContext env; 17737 v8::HandleScope scope(env->GetIsolate()); 17738 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17739 CreateGarbageInOldSpace(); 17740 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17741 CHECK_GT(size_with_garbage, initial_size + MB); 17742 bool finished = false; 17743 for (int i = 0; i < 200 && !finished; i++) { 17744 finished = v8::V8::IdleNotification(IdlePauseInMs); 17745 } 17746 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17747 CHECK(finished); 17748 CHECK_LT(final_size, initial_size + 1); 17749 } 17750 17751 17752 // Test that idle notification can be handled and eventually collects garbage. 17753 TEST(IdleNotificationWithLargeHint) { 17754 const intptr_t MB = 1024 * 1024; 17755 const int IdlePauseInMs = 900; 17756 LocalContext env; 17757 v8::HandleScope scope(env->GetIsolate()); 17758 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17759 CreateGarbageInOldSpace(); 17760 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17761 CHECK_GT(size_with_garbage, initial_size + MB); 17762 bool finished = false; 17763 for (int i = 0; i < 200 && !finished; i++) { 17764 finished = v8::V8::IdleNotification(IdlePauseInMs); 17765 } 17766 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17767 CHECK(finished); 17768 CHECK_LT(final_size, initial_size + 1); 17769 } 17770 17771 17772 TEST(Regress2107) { 17773 const intptr_t MB = 1024 * 1024; 17774 const int kShortIdlePauseInMs = 100; 17775 const int kLongIdlePauseInMs = 1000; 17776 LocalContext env; 17777 v8::Isolate* isolate = env->GetIsolate(); 17778 v8::HandleScope scope(env->GetIsolate()); 17779 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17780 // Send idle notification to start a round of incremental GCs. 17781 v8::V8::IdleNotification(kShortIdlePauseInMs); 17782 // Emulate 7 page reloads. 17783 for (int i = 0; i < 7; i++) { 17784 { 17785 v8::HandleScope inner_scope(env->GetIsolate()); 17786 v8::Local<v8::Context> ctx = v8::Context::New(isolate); 17787 ctx->Enter(); 17788 CreateGarbageInOldSpace(); 17789 ctx->Exit(); 17790 } 17791 v8::V8::ContextDisposedNotification(); 17792 v8::V8::IdleNotification(kLongIdlePauseInMs); 17793 } 17794 // Create garbage and check that idle notification still collects it. 17795 CreateGarbageInOldSpace(); 17796 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17797 CHECK_GT(size_with_garbage, initial_size + MB); 17798 bool finished = false; 17799 for (int i = 0; i < 200 && !finished; i++) { 17800 finished = v8::V8::IdleNotification(kShortIdlePauseInMs); 17801 } 17802 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17803 CHECK_LT(final_size, initial_size + 1); 17804 } 17805 17806 17807 TEST(Regress2333) { 17808 LocalContext env; 17809 for (int i = 0; i < 3; i++) { 17810 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 17811 } 17812 } 17813 17814 static uint32_t* stack_limit; 17815 17816 static void GetStackLimitCallback( 17817 const v8::FunctionCallbackInfo<v8::Value>& args) { 17818 stack_limit = reinterpret_cast<uint32_t*>( 17819 CcTest::i_isolate()->stack_guard()->real_climit()); 17820 } 17821 17822 17823 // Uses the address of a local variable to determine the stack top now. 17824 // Given a size, returns an address that is that far from the current 17825 // top of stack. 17826 static uint32_t* ComputeStackLimit(uint32_t size) { 17827 uint32_t* answer = &size - (size / sizeof(size)); 17828 // If the size is very large and the stack is very near the bottom of 17829 // memory then the calculation above may wrap around and give an address 17830 // that is above the (downwards-growing) stack. In that case we return 17831 // a very low address. 17832 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 17833 return answer; 17834 } 17835 17836 17837 // We need at least 165kB for an x64 debug build with clang and ASAN. 17838 static const int stack_breathing_room = 256 * i::KB; 17839 17840 17841 TEST(SetResourceConstraints) { 17842 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 17843 17844 // Set stack limit. 17845 v8::ResourceConstraints constraints; 17846 constraints.set_stack_limit(set_limit); 17847 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints)); 17848 17849 // Execute a script. 17850 LocalContext env; 17851 v8::HandleScope scope(env->GetIsolate()); 17852 Local<v8::FunctionTemplate> fun_templ = 17853 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback); 17854 Local<Function> fun = fun_templ->GetFunction(); 17855 env->Global()->Set(v8_str("get_stack_limit"), fun); 17856 CompileRun("get_stack_limit();"); 17857 17858 CHECK(stack_limit == set_limit); 17859 } 17860 17861 17862 TEST(SetResourceConstraintsInThread) { 17863 uint32_t* set_limit; 17864 { 17865 v8::Locker locker(CcTest::isolate()); 17866 set_limit = ComputeStackLimit(stack_breathing_room); 17867 17868 // Set stack limit. 17869 v8::ResourceConstraints constraints; 17870 constraints.set_stack_limit(set_limit); 17871 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints)); 17872 17873 // Execute a script. 17874 v8::HandleScope scope(CcTest::isolate()); 17875 LocalContext env; 17876 Local<v8::FunctionTemplate> fun_templ = 17877 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback); 17878 Local<Function> fun = fun_templ->GetFunction(); 17879 env->Global()->Set(v8_str("get_stack_limit"), fun); 17880 CompileRun("get_stack_limit();"); 17881 17882 CHECK(stack_limit == set_limit); 17883 } 17884 { 17885 v8::Locker locker(CcTest::isolate()); 17886 CHECK(stack_limit == set_limit); 17887 } 17888 } 17889 17890 17891 THREADED_TEST(GetHeapStatistics) { 17892 LocalContext c1; 17893 v8::HandleScope scope(c1->GetIsolate()); 17894 v8::HeapStatistics heap_statistics; 17895 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0); 17896 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0); 17897 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 17898 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 17899 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 17900 } 17901 17902 17903 class VisitorImpl : public v8::ExternalResourceVisitor { 17904 public: 17905 explicit VisitorImpl(TestResource** resource) { 17906 for (int i = 0; i < 4; i++) { 17907 resource_[i] = resource[i]; 17908 found_resource_[i] = false; 17909 } 17910 } 17911 virtual ~VisitorImpl() {} 17912 virtual void VisitExternalString(v8::Handle<v8::String> string) { 17913 if (!string->IsExternal()) { 17914 CHECK(string->IsExternalAscii()); 17915 return; 17916 } 17917 v8::String::ExternalStringResource* resource = 17918 string->GetExternalStringResource(); 17919 CHECK(resource); 17920 for (int i = 0; i < 4; i++) { 17921 if (resource_[i] == resource) { 17922 CHECK(!found_resource_[i]); 17923 found_resource_[i] = true; 17924 } 17925 } 17926 } 17927 void CheckVisitedResources() { 17928 for (int i = 0; i < 4; i++) { 17929 CHECK(found_resource_[i]); 17930 } 17931 } 17932 17933 private: 17934 v8::String::ExternalStringResource* resource_[4]; 17935 bool found_resource_[4]; 17936 }; 17937 17938 17939 TEST(ExternalizeOldSpaceTwoByteCons) { 17940 LocalContext env; 17941 v8::HandleScope scope(env->GetIsolate()); 17942 v8::Local<v8::String> cons = 17943 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(); 17944 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 17945 CcTest::heap()->CollectAllAvailableGarbage(); 17946 CHECK(CcTest::heap()->old_pointer_space()->Contains( 17947 *v8::Utils::OpenHandle(*cons))); 17948 17949 TestResource* resource = new TestResource( 17950 AsciiToTwoByteString("Romeo Montague Juliet Capulet")); 17951 cons->MakeExternal(resource); 17952 17953 CHECK(cons->IsExternal()); 17954 CHECK_EQ(resource, cons->GetExternalStringResource()); 17955 String::Encoding encoding; 17956 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 17957 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 17958 } 17959 17960 17961 TEST(ExternalizeOldSpaceOneByteCons) { 17962 LocalContext env; 17963 v8::HandleScope scope(env->GetIsolate()); 17964 v8::Local<v8::String> cons = 17965 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(); 17966 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 17967 CcTest::heap()->CollectAllAvailableGarbage(); 17968 CHECK(CcTest::heap()->old_pointer_space()->Contains( 17969 *v8::Utils::OpenHandle(*cons))); 17970 17971 TestAsciiResource* resource = 17972 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet")); 17973 cons->MakeExternal(resource); 17974 17975 CHECK(cons->IsExternalAscii()); 17976 CHECK_EQ(resource, cons->GetExternalAsciiStringResource()); 17977 String::Encoding encoding; 17978 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 17979 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 17980 } 17981 17982 17983 TEST(VisitExternalStrings) { 17984 LocalContext env; 17985 v8::HandleScope scope(env->GetIsolate()); 17986 const char* string = "Some string"; 17987 uint16_t* two_byte_string = AsciiToTwoByteString(string); 17988 TestResource* resource[4]; 17989 resource[0] = new TestResource(two_byte_string); 17990 v8::Local<v8::String> string0 = 17991 v8::String::NewExternal(env->GetIsolate(), resource[0]); 17992 resource[1] = new TestResource(two_byte_string, NULL, false); 17993 v8::Local<v8::String> string1 = 17994 v8::String::NewExternal(env->GetIsolate(), resource[1]); 17995 17996 // Externalized symbol. 17997 resource[2] = new TestResource(two_byte_string, NULL, false); 17998 v8::Local<v8::String> string2 = v8::String::NewFromUtf8( 17999 env->GetIsolate(), string, v8::String::kInternalizedString); 18000 CHECK(string2->MakeExternal(resource[2])); 18001 18002 // Symbolized External. 18003 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 18004 v8::Local<v8::String> string3 = 18005 v8::String::NewExternal(env->GetIsolate(), resource[3]); 18006 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. 18007 // Turn into a symbol. 18008 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 18009 CHECK(!CcTest::i_isolate()->factory()->InternalizeString( 18010 string3_i).is_null()); 18011 CHECK(string3_i->IsInternalizedString()); 18012 18013 // We need to add usages for string* to avoid warnings in GCC 4.7 18014 CHECK(string0->IsExternal()); 18015 CHECK(string1->IsExternal()); 18016 CHECK(string2->IsExternal()); 18017 CHECK(string3->IsExternal()); 18018 18019 VisitorImpl visitor(resource); 18020 v8::V8::VisitExternalResources(&visitor); 18021 visitor.CheckVisitedResources(); 18022 } 18023 18024 18025 TEST(ExternalStringCollectedAtTearDown) { 18026 int destroyed = 0; 18027 v8::Isolate* isolate = v8::Isolate::New(); 18028 { v8::Isolate::Scope isolate_scope(isolate); 18029 v8::HandleScope handle_scope(isolate); 18030 const char* s = "One string to test them all, one string to find them."; 18031 TestAsciiResource* inscription = 18032 new TestAsciiResource(i::StrDup(s), &destroyed); 18033 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription); 18034 // Ring is still alive. Orcs are roaming freely across our lands. 18035 CHECK_EQ(0, destroyed); 18036 USE(ring); 18037 } 18038 18039 isolate->Dispose(); 18040 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18041 CHECK_EQ(1, destroyed); 18042 } 18043 18044 18045 TEST(ExternalInternalizedStringCollectedAtTearDown) { 18046 int destroyed = 0; 18047 v8::Isolate* isolate = v8::Isolate::New(); 18048 { v8::Isolate::Scope isolate_scope(isolate); 18049 LocalContext env(isolate); 18050 v8::HandleScope handle_scope(isolate); 18051 CompileRun("var ring = 'One string to test them all';"); 18052 const char* s = "One string to test them all"; 18053 TestAsciiResource* inscription = 18054 new TestAsciiResource(i::StrDup(s), &destroyed); 18055 v8::Local<v8::String> ring = CompileRun("ring")->ToString(); 18056 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18057 ring->MakeExternal(inscription); 18058 // Ring is still alive. Orcs are roaming freely across our lands. 18059 CHECK_EQ(0, destroyed); 18060 USE(ring); 18061 } 18062 18063 isolate->Dispose(); 18064 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18065 CHECK_EQ(1, destroyed); 18066 } 18067 18068 18069 TEST(ExternalInternalizedStringCollectedAtGC) { 18070 int destroyed = 0; 18071 { LocalContext env; 18072 v8::HandleScope handle_scope(env->GetIsolate()); 18073 CompileRun("var ring = 'One string to test them all';"); 18074 const char* s = "One string to test them all"; 18075 TestAsciiResource* inscription = 18076 new TestAsciiResource(i::StrDup(s), &destroyed); 18077 v8::Local<v8::String> ring = CompileRun("ring")->ToString(); 18078 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18079 ring->MakeExternal(inscription); 18080 // Ring is still alive. Orcs are roaming freely across our lands. 18081 CHECK_EQ(0, destroyed); 18082 USE(ring); 18083 } 18084 18085 // Garbage collector deals swift blows to evil. 18086 CcTest::i_isolate()->compilation_cache()->Clear(); 18087 CcTest::heap()->CollectAllAvailableGarbage(); 18088 18089 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18090 CHECK_EQ(1, destroyed); 18091 } 18092 18093 18094 static double DoubleFromBits(uint64_t value) { 18095 double target; 18096 i::MemCopy(&target, &value, sizeof(target)); 18097 return target; 18098 } 18099 18100 18101 static uint64_t DoubleToBits(double value) { 18102 uint64_t target; 18103 i::MemCopy(&target, &value, sizeof(target)); 18104 return target; 18105 } 18106 18107 18108 static double DoubleToDateTime(double input) { 18109 double date_limit = 864e13; 18110 if (std::isnan(input) || input < -date_limit || input > date_limit) { 18111 return i::OS::nan_value(); 18112 } 18113 return (input < 0) ? -(std::floor(-input)) : std::floor(input); 18114 } 18115 18116 18117 // We don't have a consistent way to write 64-bit constants syntactically, so we 18118 // split them into two 32-bit constants and combine them programmatically. 18119 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 18120 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 18121 } 18122 18123 18124 THREADED_TEST(QuietSignalingNaNs) { 18125 LocalContext context; 18126 v8::Isolate* isolate = context->GetIsolate(); 18127 v8::HandleScope scope(isolate); 18128 v8::TryCatch try_catch; 18129 18130 // Special double values. 18131 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 18132 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 18133 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 18134 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 18135 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 18136 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 18137 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 18138 18139 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 18140 // on either side of the epoch. 18141 double date_limit = 864e13; 18142 18143 double test_values[] = { 18144 snan, 18145 qnan, 18146 infinity, 18147 max_normal, 18148 date_limit + 1, 18149 date_limit, 18150 min_normal, 18151 max_denormal, 18152 min_denormal, 18153 0, 18154 -0, 18155 -min_denormal, 18156 -max_denormal, 18157 -min_normal, 18158 -date_limit, 18159 -date_limit - 1, 18160 -max_normal, 18161 -infinity, 18162 -qnan, 18163 -snan 18164 }; 18165 int num_test_values = 20; 18166 18167 for (int i = 0; i < num_test_values; i++) { 18168 double test_value = test_values[i]; 18169 18170 // Check that Number::New preserves non-NaNs and quiets SNaNs. 18171 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value); 18172 double stored_number = number->NumberValue(); 18173 if (!std::isnan(test_value)) { 18174 CHECK_EQ(test_value, stored_number); 18175 } else { 18176 uint64_t stored_bits = DoubleToBits(stored_number); 18177 // Check if quiet nan (bits 51..62 all set). 18178 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 18179 // Most significant fraction bit for quiet nan is set to 0 18180 // on MIPS architecture. Allowed by IEEE-754. 18181 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18182 #else 18183 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18184 #endif 18185 } 18186 18187 // Check that Date::New preserves non-NaNs in the date range and 18188 // quiets SNaNs. 18189 v8::Handle<v8::Value> date = 18190 v8::Date::New(isolate, test_value); 18191 double expected_stored_date = DoubleToDateTime(test_value); 18192 double stored_date = date->NumberValue(); 18193 if (!std::isnan(expected_stored_date)) { 18194 CHECK_EQ(expected_stored_date, stored_date); 18195 } else { 18196 uint64_t stored_bits = DoubleToBits(stored_date); 18197 // Check if quiet nan (bits 51..62 all set). 18198 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 18199 // Most significant fraction bit for quiet nan is set to 0 18200 // on MIPS architecture. Allowed by IEEE-754. 18201 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18202 #else 18203 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18204 #endif 18205 } 18206 } 18207 } 18208 18209 18210 static void SpaghettiIncident( 18211 const v8::FunctionCallbackInfo<v8::Value>& args) { 18212 v8::HandleScope scope(args.GetIsolate()); 18213 v8::TryCatch tc; 18214 v8::Handle<v8::String> str(args[0]->ToString()); 18215 USE(str); 18216 if (tc.HasCaught()) 18217 tc.ReThrow(); 18218 } 18219 18220 18221 // Test that an exception can be propagated down through a spaghetti 18222 // stack using ReThrow. 18223 THREADED_TEST(SpaghettiStackReThrow) { 18224 v8::Isolate* isolate = CcTest::isolate(); 18225 v8::HandleScope scope(isolate); 18226 LocalContext context; 18227 context->Global()->Set( 18228 v8::String::NewFromUtf8(isolate, "s"), 18229 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction()); 18230 v8::TryCatch try_catch; 18231 CompileRun( 18232 "var i = 0;" 18233 "var o = {" 18234 " toString: function () {" 18235 " if (i == 10) {" 18236 " throw 'Hey!';" 18237 " } else {" 18238 " i++;" 18239 " return s(o);" 18240 " }" 18241 " }" 18242 "};" 18243 "s(o);"); 18244 CHECK(try_catch.HasCaught()); 18245 v8::String::Utf8Value value(try_catch.Exception()); 18246 CHECK_EQ(0, strcmp(*value, "Hey!")); 18247 } 18248 18249 18250 TEST(Regress528) { 18251 v8::V8::Initialize(); 18252 v8::Isolate* isolate = CcTest::isolate(); 18253 v8::HandleScope scope(isolate); 18254 v8::Local<Context> other_context; 18255 int gc_count; 18256 18257 // Create a context used to keep the code from aging in the compilation 18258 // cache. 18259 other_context = Context::New(isolate); 18260 18261 // Context-dependent context data creates reference from the compilation 18262 // cache to the global object. 18263 const char* source_simple = "1"; 18264 { 18265 v8::HandleScope scope(isolate); 18266 v8::Local<Context> context = Context::New(isolate); 18267 18268 context->Enter(); 18269 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, ""); 18270 context->SetEmbedderData(0, obj); 18271 CompileRun(source_simple); 18272 context->Exit(); 18273 } 18274 v8::V8::ContextDisposedNotification(); 18275 for (gc_count = 1; gc_count < 10; gc_count++) { 18276 other_context->Enter(); 18277 CompileRun(source_simple); 18278 other_context->Exit(); 18279 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18280 if (GetGlobalObjectsCount() == 1) break; 18281 } 18282 CHECK_GE(2, gc_count); 18283 CHECK_EQ(1, GetGlobalObjectsCount()); 18284 18285 // Eval in a function creates reference from the compilation cache to the 18286 // global object. 18287 const char* source_eval = "function f(){eval('1')}; f()"; 18288 { 18289 v8::HandleScope scope(isolate); 18290 v8::Local<Context> context = Context::New(isolate); 18291 18292 context->Enter(); 18293 CompileRun(source_eval); 18294 context->Exit(); 18295 } 18296 v8::V8::ContextDisposedNotification(); 18297 for (gc_count = 1; gc_count < 10; gc_count++) { 18298 other_context->Enter(); 18299 CompileRun(source_eval); 18300 other_context->Exit(); 18301 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18302 if (GetGlobalObjectsCount() == 1) break; 18303 } 18304 CHECK_GE(2, gc_count); 18305 CHECK_EQ(1, GetGlobalObjectsCount()); 18306 18307 // Looking up the line number for an exception creates reference from the 18308 // compilation cache to the global object. 18309 const char* source_exception = "function f(){throw 1;} f()"; 18310 { 18311 v8::HandleScope scope(isolate); 18312 v8::Local<Context> context = Context::New(isolate); 18313 18314 context->Enter(); 18315 v8::TryCatch try_catch; 18316 CompileRun(source_exception); 18317 CHECK(try_catch.HasCaught()); 18318 v8::Handle<v8::Message> message = try_catch.Message(); 18319 CHECK(!message.IsEmpty()); 18320 CHECK_EQ(1, message->GetLineNumber()); 18321 context->Exit(); 18322 } 18323 v8::V8::ContextDisposedNotification(); 18324 for (gc_count = 1; gc_count < 10; gc_count++) { 18325 other_context->Enter(); 18326 CompileRun(source_exception); 18327 other_context->Exit(); 18328 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18329 if (GetGlobalObjectsCount() == 1) break; 18330 } 18331 CHECK_GE(2, gc_count); 18332 CHECK_EQ(1, GetGlobalObjectsCount()); 18333 18334 v8::V8::ContextDisposedNotification(); 18335 } 18336 18337 18338 THREADED_TEST(ScriptOrigin) { 18339 LocalContext env; 18340 v8::HandleScope scope(env->GetIsolate()); 18341 v8::ScriptOrigin origin = 18342 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18343 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18344 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 18345 v8::Script::Compile(script, &origin)->Run(); 18346 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18347 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18348 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18349 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18350 18351 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 18352 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName())); 18353 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value()); 18354 18355 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 18356 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName())); 18357 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value()); 18358 } 18359 18360 18361 THREADED_TEST(FunctionGetInferredName) { 18362 LocalContext env; 18363 v8::HandleScope scope(env->GetIsolate()); 18364 v8::ScriptOrigin origin = 18365 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18366 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18367 env->GetIsolate(), 18368 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 18369 v8::Script::Compile(script, &origin)->Run(); 18370 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18371 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18372 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); 18373 } 18374 18375 18376 THREADED_TEST(FunctionGetDisplayName) { 18377 LocalContext env; 18378 v8::HandleScope scope(env->GetIsolate()); 18379 const char* code = "var error = false;" 18380 "function a() { this.x = 1; };" 18381 "a.displayName = 'display_a';" 18382 "var b = (function() {" 18383 " var f = function() { this.x = 2; };" 18384 " f.displayName = 'display_b';" 18385 " return f;" 18386 "})();" 18387 "var c = function() {};" 18388 "c.__defineGetter__('displayName', function() {" 18389 " error = true;" 18390 " throw new Error();" 18391 "});" 18392 "function d() {};" 18393 "d.__defineGetter__('displayName', function() {" 18394 " error = true;" 18395 " return 'wrong_display_name';" 18396 "});" 18397 "function e() {};" 18398 "e.displayName = 'wrong_display_name';" 18399 "e.__defineSetter__('displayName', function() {" 18400 " error = true;" 18401 " throw new Error();" 18402 "});" 18403 "function f() {};" 18404 "f.displayName = { 'foo': 6, toString: function() {" 18405 " error = true;" 18406 " return 'wrong_display_name';" 18407 "}};" 18408 "var g = function() {" 18409 " arguments.callee.displayName = 'set_in_runtime';" 18410 "}; g();" 18411 ; 18412 v8::ScriptOrigin origin = 18413 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18414 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin) 18415 ->Run(); 18416 v8::Local<v8::Value> error = 18417 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error")); 18418 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( 18419 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a"))); 18420 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( 18421 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b"))); 18422 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( 18423 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"))); 18424 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( 18425 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d"))); 18426 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( 18427 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e"))); 18428 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18429 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18430 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18431 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18432 CHECK_EQ(false, error->BooleanValue()); 18433 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName())); 18434 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName())); 18435 CHECK(c->GetDisplayName()->IsUndefined()); 18436 CHECK(d->GetDisplayName()->IsUndefined()); 18437 CHECK(e->GetDisplayName()->IsUndefined()); 18438 CHECK(f->GetDisplayName()->IsUndefined()); 18439 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())); 18440 } 18441 18442 18443 THREADED_TEST(ScriptLineNumber) { 18444 LocalContext env; 18445 v8::HandleScope scope(env->GetIsolate()); 18446 v8::ScriptOrigin origin = 18447 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18448 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18449 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 18450 v8::Script::Compile(script, &origin)->Run(); 18451 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18452 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18453 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18454 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18455 CHECK_EQ(0, f->GetScriptLineNumber()); 18456 CHECK_EQ(2, g->GetScriptLineNumber()); 18457 } 18458 18459 18460 THREADED_TEST(ScriptColumnNumber) { 18461 LocalContext env; 18462 v8::Isolate* isolate = env->GetIsolate(); 18463 v8::HandleScope scope(isolate); 18464 v8::ScriptOrigin origin = 18465 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"), 18466 v8::Integer::New(isolate, 3), 18467 v8::Integer::New(isolate, 2)); 18468 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18469 isolate, "function foo() {}\n\n function bar() {}"); 18470 v8::Script::Compile(script, &origin)->Run(); 18471 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18472 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"))); 18473 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18474 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar"))); 18475 CHECK_EQ(14, foo->GetScriptColumnNumber()); 18476 CHECK_EQ(17, bar->GetScriptColumnNumber()); 18477 } 18478 18479 18480 THREADED_TEST(FunctionIsBuiltin) { 18481 LocalContext env; 18482 v8::Isolate* isolate = env->GetIsolate(); 18483 v8::HandleScope scope(isolate); 18484 v8::Local<v8::Function> f; 18485 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); 18486 CHECK(f->IsBuiltin()); 18487 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); 18488 CHECK(f->IsBuiltin()); 18489 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); 18490 CHECK(f->IsBuiltin()); 18491 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); 18492 CHECK(f->IsBuiltin()); 18493 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); 18494 CHECK(!f->IsBuiltin()); 18495 } 18496 18497 18498 THREADED_TEST(FunctionGetScriptId) { 18499 LocalContext env; 18500 v8::Isolate* isolate = env->GetIsolate(); 18501 v8::HandleScope scope(isolate); 18502 v8::ScriptOrigin origin = 18503 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"), 18504 v8::Integer::New(isolate, 3), 18505 v8::Integer::New(isolate, 2)); 18506 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 18507 isolate, "function foo() {}\n\n function bar() {}"); 18508 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); 18509 script->Run(); 18510 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18511 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"))); 18512 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18513 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar"))); 18514 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId()); 18515 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId()); 18516 } 18517 18518 18519 THREADED_TEST(FunctionGetBoundFunction) { 18520 LocalContext env; 18521 v8::HandleScope scope(env->GetIsolate()); 18522 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8( 18523 env->GetIsolate(), "test")); 18524 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18525 env->GetIsolate(), 18526 "var a = new Object();\n" 18527 "a.x = 1;\n" 18528 "function f () { return this.x };\n" 18529 "var g = f.bind(a);\n" 18530 "var b = g();"); 18531 v8::Script::Compile(script, &origin)->Run(); 18532 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18533 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18534 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18535 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18536 CHECK(g->GetBoundFunction()->IsFunction()); 18537 Local<v8::Function> original_function = Local<v8::Function>::Cast( 18538 g->GetBoundFunction()); 18539 CHECK_EQ(f->GetName(), original_function->GetName()); 18540 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber()); 18541 CHECK_EQ(f->GetScriptColumnNumber(), 18542 original_function->GetScriptColumnNumber()); 18543 } 18544 18545 18546 static void GetterWhichReturns42( 18547 Local<String> name, 18548 const v8::PropertyCallbackInfo<v8::Value>& info) { 18549 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18550 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18551 info.GetReturnValue().Set(v8_num(42)); 18552 } 18553 18554 18555 static void SetterWhichSetsYOnThisTo23( 18556 Local<String> name, 18557 Local<Value> value, 18558 const v8::PropertyCallbackInfo<void>& info) { 18559 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18560 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18561 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18562 } 18563 18564 18565 void FooGetInterceptor(Local<String> name, 18566 const v8::PropertyCallbackInfo<v8::Value>& info) { 18567 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18568 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18569 if (!name->Equals(v8_str("foo"))) return; 18570 info.GetReturnValue().Set(v8_num(42)); 18571 } 18572 18573 18574 void FooSetInterceptor(Local<String> name, 18575 Local<Value> value, 18576 const v8::PropertyCallbackInfo<v8::Value>& info) { 18577 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18578 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18579 if (!name->Equals(v8_str("foo"))) return; 18580 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18581 info.GetReturnValue().Set(v8_num(23)); 18582 } 18583 18584 18585 TEST(SetterOnConstructorPrototype) { 18586 v8::Isolate* isolate = CcTest::isolate(); 18587 v8::HandleScope scope(isolate); 18588 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18589 templ->SetAccessor(v8_str("x"), 18590 GetterWhichReturns42, 18591 SetterWhichSetsYOnThisTo23); 18592 LocalContext context; 18593 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18594 CompileRun("function C1() {" 18595 " this.x = 23;" 18596 "};" 18597 "C1.prototype = P;" 18598 "function C2() {" 18599 " this.x = 23" 18600 "};" 18601 "C2.prototype = { };" 18602 "C2.prototype.__proto__ = P;"); 18603 18604 v8::Local<v8::Script> script; 18605 script = v8_compile("new C1();"); 18606 for (int i = 0; i < 10; i++) { 18607 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18608 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 18609 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 18610 } 18611 18612 script = v8_compile("new C2();"); 18613 for (int i = 0; i < 10; i++) { 18614 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 18615 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value()); 18616 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value()); 18617 } 18618 } 18619 18620 18621 static void NamedPropertyGetterWhichReturns42( 18622 Local<String> name, 18623 const v8::PropertyCallbackInfo<v8::Value>& info) { 18624 info.GetReturnValue().Set(v8_num(42)); 18625 } 18626 18627 18628 static void NamedPropertySetterWhichSetsYOnThisTo23( 18629 Local<String> name, 18630 Local<Value> value, 18631 const v8::PropertyCallbackInfo<v8::Value>& info) { 18632 if (name->Equals(v8_str("x"))) { 18633 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18634 } 18635 } 18636 18637 18638 THREADED_TEST(InterceptorOnConstructorPrototype) { 18639 v8::Isolate* isolate = CcTest::isolate(); 18640 v8::HandleScope scope(isolate); 18641 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18642 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42, 18643 NamedPropertySetterWhichSetsYOnThisTo23); 18644 LocalContext context; 18645 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18646 CompileRun("function C1() {" 18647 " this.x = 23;" 18648 "};" 18649 "C1.prototype = P;" 18650 "function C2() {" 18651 " this.x = 23" 18652 "};" 18653 "C2.prototype = { };" 18654 "C2.prototype.__proto__ = P;"); 18655 18656 v8::Local<v8::Script> script; 18657 script = v8_compile("new C1();"); 18658 for (int i = 0; i < 10; i++) { 18659 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18660 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 18661 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 18662 } 18663 18664 script = v8_compile("new C2();"); 18665 for (int i = 0; i < 10; i++) { 18666 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 18667 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value()); 18668 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value()); 18669 } 18670 } 18671 18672 18673 TEST(Regress618) { 18674 const char* source = "function C1() {" 18675 " this.x = 23;" 18676 "};" 18677 "C1.prototype = P;"; 18678 18679 LocalContext context; 18680 v8::Isolate* isolate = context->GetIsolate(); 18681 v8::HandleScope scope(isolate); 18682 v8::Local<v8::Script> script; 18683 18684 // Use a simple object as prototype. 18685 v8::Local<v8::Object> prototype = v8::Object::New(isolate); 18686 prototype->Set(v8_str("y"), v8_num(42)); 18687 context->Global()->Set(v8_str("P"), prototype); 18688 18689 // This compile will add the code to the compilation cache. 18690 CompileRun(source); 18691 18692 script = v8_compile("new C1();"); 18693 // Allow enough iterations for the inobject slack tracking logic 18694 // to finalize instance size and install the fast construct stub. 18695 for (int i = 0; i < 256; i++) { 18696 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18697 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 18698 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 18699 } 18700 18701 // Use an API object with accessors as prototype. 18702 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18703 templ->SetAccessor(v8_str("x"), 18704 GetterWhichReturns42, 18705 SetterWhichSetsYOnThisTo23); 18706 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18707 18708 // This compile will get the code from the compilation cache. 18709 CompileRun(source); 18710 18711 script = v8_compile("new C1();"); 18712 for (int i = 0; i < 10; i++) { 18713 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18714 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 18715 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 18716 } 18717 } 18718 18719 v8::Isolate* gc_callbacks_isolate = NULL; 18720 int prologue_call_count = 0; 18721 int epilogue_call_count = 0; 18722 int prologue_call_count_second = 0; 18723 int epilogue_call_count_second = 0; 18724 int prologue_call_count_alloc = 0; 18725 int epilogue_call_count_alloc = 0; 18726 18727 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) { 18728 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18729 ++prologue_call_count; 18730 } 18731 18732 18733 void PrologueCallback(v8::Isolate* isolate, 18734 v8::GCType, 18735 v8::GCCallbackFlags flags) { 18736 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18737 CHECK_EQ(gc_callbacks_isolate, isolate); 18738 ++prologue_call_count; 18739 } 18740 18741 18742 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) { 18743 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18744 ++epilogue_call_count; 18745 } 18746 18747 18748 void EpilogueCallback(v8::Isolate* isolate, 18749 v8::GCType, 18750 v8::GCCallbackFlags flags) { 18751 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18752 CHECK_EQ(gc_callbacks_isolate, isolate); 18753 ++epilogue_call_count; 18754 } 18755 18756 18757 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18758 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18759 ++prologue_call_count_second; 18760 } 18761 18762 18763 void PrologueCallbackSecond(v8::Isolate* isolate, 18764 v8::GCType, 18765 v8::GCCallbackFlags flags) { 18766 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18767 CHECK_EQ(gc_callbacks_isolate, isolate); 18768 ++prologue_call_count_second; 18769 } 18770 18771 18772 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18773 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18774 ++epilogue_call_count_second; 18775 } 18776 18777 18778 void EpilogueCallbackSecond(v8::Isolate* isolate, 18779 v8::GCType, 18780 v8::GCCallbackFlags flags) { 18781 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18782 CHECK_EQ(gc_callbacks_isolate, isolate); 18783 ++epilogue_call_count_second; 18784 } 18785 18786 18787 void PrologueCallbackAlloc(v8::Isolate* isolate, 18788 v8::GCType, 18789 v8::GCCallbackFlags flags) { 18790 v8::HandleScope scope(isolate); 18791 18792 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18793 CHECK_EQ(gc_callbacks_isolate, isolate); 18794 ++prologue_call_count_alloc; 18795 18796 // Simulate full heap to see if we will reenter this callback 18797 SimulateFullSpace(CcTest::heap()->new_space()); 18798 18799 Local<Object> obj = Object::New(isolate); 18800 CHECK(!obj.IsEmpty()); 18801 18802 CcTest::heap()->CollectAllGarbage( 18803 i::Heap::kAbortIncrementalMarkingMask); 18804 } 18805 18806 18807 void EpilogueCallbackAlloc(v8::Isolate* isolate, 18808 v8::GCType, 18809 v8::GCCallbackFlags flags) { 18810 v8::HandleScope scope(isolate); 18811 18812 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18813 CHECK_EQ(gc_callbacks_isolate, isolate); 18814 ++epilogue_call_count_alloc; 18815 18816 // Simulate full heap to see if we will reenter this callback 18817 SimulateFullSpace(CcTest::heap()->new_space()); 18818 18819 Local<Object> obj = Object::New(isolate); 18820 CHECK(!obj.IsEmpty()); 18821 18822 CcTest::heap()->CollectAllGarbage( 18823 i::Heap::kAbortIncrementalMarkingMask); 18824 } 18825 18826 18827 TEST(GCCallbacksOld) { 18828 LocalContext context; 18829 18830 v8::V8::AddGCPrologueCallback(PrologueCallback); 18831 v8::V8::AddGCEpilogueCallback(EpilogueCallback); 18832 CHECK_EQ(0, prologue_call_count); 18833 CHECK_EQ(0, epilogue_call_count); 18834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18835 CHECK_EQ(1, prologue_call_count); 18836 CHECK_EQ(1, epilogue_call_count); 18837 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); 18838 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); 18839 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18840 CHECK_EQ(2, prologue_call_count); 18841 CHECK_EQ(2, epilogue_call_count); 18842 CHECK_EQ(1, prologue_call_count_second); 18843 CHECK_EQ(1, epilogue_call_count_second); 18844 v8::V8::RemoveGCPrologueCallback(PrologueCallback); 18845 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); 18846 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18847 CHECK_EQ(2, prologue_call_count); 18848 CHECK_EQ(2, epilogue_call_count); 18849 CHECK_EQ(2, prologue_call_count_second); 18850 CHECK_EQ(2, epilogue_call_count_second); 18851 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); 18852 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18853 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18854 CHECK_EQ(2, prologue_call_count); 18855 CHECK_EQ(2, epilogue_call_count); 18856 CHECK_EQ(2, prologue_call_count_second); 18857 CHECK_EQ(2, epilogue_call_count_second); 18858 } 18859 18860 18861 TEST(GCCallbacks) { 18862 LocalContext context; 18863 v8::Isolate* isolate = context->GetIsolate(); 18864 gc_callbacks_isolate = isolate; 18865 isolate->AddGCPrologueCallback(PrologueCallback); 18866 isolate->AddGCEpilogueCallback(EpilogueCallback); 18867 CHECK_EQ(0, prologue_call_count); 18868 CHECK_EQ(0, epilogue_call_count); 18869 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18870 CHECK_EQ(1, prologue_call_count); 18871 CHECK_EQ(1, epilogue_call_count); 18872 isolate->AddGCPrologueCallback(PrologueCallbackSecond); 18873 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); 18874 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18875 CHECK_EQ(2, prologue_call_count); 18876 CHECK_EQ(2, epilogue_call_count); 18877 CHECK_EQ(1, prologue_call_count_second); 18878 CHECK_EQ(1, epilogue_call_count_second); 18879 isolate->RemoveGCPrologueCallback(PrologueCallback); 18880 isolate->RemoveGCEpilogueCallback(EpilogueCallback); 18881 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18882 CHECK_EQ(2, prologue_call_count); 18883 CHECK_EQ(2, epilogue_call_count); 18884 CHECK_EQ(2, prologue_call_count_second); 18885 CHECK_EQ(2, epilogue_call_count_second); 18886 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); 18887 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18888 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18889 CHECK_EQ(2, prologue_call_count); 18890 CHECK_EQ(2, epilogue_call_count); 18891 CHECK_EQ(2, prologue_call_count_second); 18892 CHECK_EQ(2, epilogue_call_count_second); 18893 18894 CHECK_EQ(0, prologue_call_count_alloc); 18895 CHECK_EQ(0, epilogue_call_count_alloc); 18896 isolate->AddGCPrologueCallback(PrologueCallbackAlloc); 18897 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc); 18898 CcTest::heap()->CollectAllGarbage( 18899 i::Heap::kAbortIncrementalMarkingMask); 18900 CHECK_EQ(1, prologue_call_count_alloc); 18901 CHECK_EQ(1, epilogue_call_count_alloc); 18902 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc); 18903 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc); 18904 } 18905 18906 18907 THREADED_TEST(AddToJSFunctionResultCache) { 18908 i::FLAG_stress_compaction = false; 18909 i::FLAG_allow_natives_syntax = true; 18910 v8::HandleScope scope(CcTest::isolate()); 18911 18912 LocalContext context; 18913 18914 const char* code = 18915 "(function() {" 18916 " var key0 = 'a';" 18917 " var key1 = 'b';" 18918 " var r0 = %_GetFromCache(0, key0);" 18919 " var r1 = %_GetFromCache(0, key1);" 18920 " var r0_ = %_GetFromCache(0, key0);" 18921 " if (r0 !== r0_)" 18922 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;" 18923 " var r1_ = %_GetFromCache(0, key1);" 18924 " if (r1 !== r1_)" 18925 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" 18926 " return 'PASSED';" 18927 "})()"; 18928 CcTest::heap()->ClearJSFunctionResultCaches(); 18929 ExpectString(code, "PASSED"); 18930 } 18931 18932 18933 THREADED_TEST(FillJSFunctionResultCache) { 18934 i::FLAG_allow_natives_syntax = true; 18935 LocalContext context; 18936 v8::HandleScope scope(context->GetIsolate()); 18937 18938 const char* code = 18939 "(function() {" 18940 " var k = 'a';" 18941 " var r = %_GetFromCache(0, k);" 18942 " for (var i = 0; i < 16; i++) {" 18943 " %_GetFromCache(0, 'a' + i);" 18944 " };" 18945 " if (r === %_GetFromCache(0, k))" 18946 " return 'FAILED: k0CacheSize is too small';" 18947 " return 'PASSED';" 18948 "})()"; 18949 CcTest::heap()->ClearJSFunctionResultCaches(); 18950 ExpectString(code, "PASSED"); 18951 } 18952 18953 18954 THREADED_TEST(RoundRobinGetFromCache) { 18955 i::FLAG_allow_natives_syntax = true; 18956 LocalContext context; 18957 v8::HandleScope scope(context->GetIsolate()); 18958 18959 const char* code = 18960 "(function() {" 18961 " var keys = [];" 18962 " for (var i = 0; i < 16; i++) keys.push(i);" 18963 " var values = [];" 18964 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 18965 " for (var i = 0; i < 16; i++) {" 18966 " var v = %_GetFromCache(0, keys[i]);" 18967 " if (v.toString() !== values[i].toString())" 18968 " return 'Wrong value for ' + " 18969 " keys[i] + ': ' + v + ' vs. ' + values[i];" 18970 " };" 18971 " return 'PASSED';" 18972 "})()"; 18973 CcTest::heap()->ClearJSFunctionResultCaches(); 18974 ExpectString(code, "PASSED"); 18975 } 18976 18977 18978 THREADED_TEST(ReverseGetFromCache) { 18979 i::FLAG_allow_natives_syntax = true; 18980 LocalContext context; 18981 v8::HandleScope scope(context->GetIsolate()); 18982 18983 const char* code = 18984 "(function() {" 18985 " var keys = [];" 18986 " for (var i = 0; i < 16; i++) keys.push(i);" 18987 " var values = [];" 18988 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 18989 " for (var i = 15; i >= 16; i--) {" 18990 " var v = %_GetFromCache(0, keys[i]);" 18991 " if (v !== values[i])" 18992 " return 'Wrong value for ' + " 18993 " keys[i] + ': ' + v + ' vs. ' + values[i];" 18994 " };" 18995 " return 'PASSED';" 18996 "})()"; 18997 CcTest::heap()->ClearJSFunctionResultCaches(); 18998 ExpectString(code, "PASSED"); 18999 } 19000 19001 19002 THREADED_TEST(TestEviction) { 19003 i::FLAG_allow_natives_syntax = true; 19004 LocalContext context; 19005 v8::HandleScope scope(context->GetIsolate()); 19006 19007 const char* code = 19008 "(function() {" 19009 " for (var i = 0; i < 2*16; i++) {" 19010 " %_GetFromCache(0, 'a' + i);" 19011 " };" 19012 " return 'PASSED';" 19013 "})()"; 19014 CcTest::heap()->ClearJSFunctionResultCaches(); 19015 ExpectString(code, "PASSED"); 19016 } 19017 19018 19019 THREADED_TEST(TwoByteStringInAsciiCons) { 19020 // See Chromium issue 47824. 19021 LocalContext context; 19022 v8::HandleScope scope(context->GetIsolate()); 19023 19024 const char* init_code = 19025 "var str1 = 'abelspendabel';" 19026 "var str2 = str1 + str1 + str1;" 19027 "str2;"; 19028 Local<Value> result = CompileRun(init_code); 19029 19030 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 19031 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 19032 19033 CHECK(result->IsString()); 19034 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 19035 int length = string->length(); 19036 CHECK(string->IsOneByteRepresentation()); 19037 19038 i::Handle<i::String> flat_string = i::String::Flatten(string); 19039 19040 CHECK(string->IsOneByteRepresentation()); 19041 CHECK(flat_string->IsOneByteRepresentation()); 19042 19043 // Create external resource. 19044 uint16_t* uc16_buffer = new uint16_t[length + 1]; 19045 19046 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 19047 uc16_buffer[length] = 0; 19048 19049 TestResource resource(uc16_buffer); 19050 19051 flat_string->MakeExternal(&resource); 19052 19053 CHECK(flat_string->IsTwoByteRepresentation()); 19054 19055 // If the cons string has been short-circuited, skip the following checks. 19056 if (!string.is_identical_to(flat_string)) { 19057 // At this point, we should have a Cons string which is flat and ASCII, 19058 // with a first half that is a two-byte string (although it only contains 19059 // ASCII characters). This is a valid sequence of steps, and it can happen 19060 // in real pages. 19061 CHECK(string->IsOneByteRepresentation()); 19062 i::ConsString* cons = i::ConsString::cast(*string); 19063 CHECK_EQ(0, cons->second()->length()); 19064 CHECK(cons->first()->IsTwoByteRepresentation()); 19065 } 19066 19067 // Check that some string operations work. 19068 19069 // Atom RegExp. 19070 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 19071 CHECK_EQ(6, reresult->Int32Value()); 19072 19073 // Nonatom RegExp. 19074 reresult = CompileRun("str2.match(/abe./g).length;"); 19075 CHECK_EQ(6, reresult->Int32Value()); 19076 19077 reresult = CompileRun("str2.search(/bel/g);"); 19078 CHECK_EQ(1, reresult->Int32Value()); 19079 19080 reresult = CompileRun("str2.search(/be./g);"); 19081 CHECK_EQ(1, reresult->Int32Value()); 19082 19083 ExpectTrue("/bel/g.test(str2);"); 19084 19085 ExpectTrue("/be./g.test(str2);"); 19086 19087 reresult = CompileRun("/bel/g.exec(str2);"); 19088 CHECK(!reresult->IsNull()); 19089 19090 reresult = CompileRun("/be./g.exec(str2);"); 19091 CHECK(!reresult->IsNull()); 19092 19093 ExpectString("str2.substring(2, 10);", "elspenda"); 19094 19095 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 19096 19097 ExpectString("str2.charAt(2);", "e"); 19098 19099 ExpectObject("str2.indexOf('els');", indexof); 19100 19101 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 19102 19103 reresult = CompileRun("str2.charCodeAt(2);"); 19104 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 19105 } 19106 19107 19108 TEST(ContainsOnlyOneByte) { 19109 v8::V8::Initialize(); 19110 v8::Isolate* isolate = CcTest::isolate(); 19111 v8::HandleScope scope(isolate); 19112 // Make a buffer long enough that it won't automatically be converted. 19113 const int length = 512; 19114 // Ensure word aligned assignment. 19115 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 19116 i::SmartArrayPointer<uintptr_t> 19117 aligned_contents(new uintptr_t[aligned_length]); 19118 uint16_t* string_contents = 19119 reinterpret_cast<uint16_t*>(aligned_contents.get()); 19120 // Set to contain only one byte. 19121 for (int i = 0; i < length-1; i++) { 19122 string_contents[i] = 0x41; 19123 } 19124 string_contents[length-1] = 0; 19125 // Simple case. 19126 Handle<String> string = 19127 String::NewExternal(isolate, 19128 new TestResource(string_contents, NULL, false)); 19129 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19130 // Counter example. 19131 string = String::NewFromTwoByte(isolate, string_contents); 19132 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19133 // Test left right and balanced cons strings. 19134 Handle<String> base = String::NewFromUtf8(isolate, "a"); 19135 Handle<String> left = base; 19136 Handle<String> right = base; 19137 for (int i = 0; i < 1000; i++) { 19138 left = String::Concat(base, left); 19139 right = String::Concat(right, base); 19140 } 19141 Handle<String> balanced = String::Concat(left, base); 19142 balanced = String::Concat(balanced, right); 19143 Handle<String> cons_strings[] = {left, balanced, right}; 19144 Handle<String> two_byte = 19145 String::NewExternal(isolate, 19146 new TestResource(string_contents, NULL, false)); 19147 USE(two_byte); USE(cons_strings); 19148 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) { 19149 // Base assumptions. 19150 string = cons_strings[i]; 19151 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19152 // Test left and right concatentation. 19153 string = String::Concat(two_byte, cons_strings[i]); 19154 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19155 string = String::Concat(cons_strings[i], two_byte); 19156 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19157 } 19158 // Set bits in different positions 19159 // for strings of different lengths and alignments. 19160 for (int alignment = 0; alignment < 7; alignment++) { 19161 for (int size = 2; alignment + size < length; size *= 2) { 19162 int zero_offset = size + alignment; 19163 string_contents[zero_offset] = 0; 19164 for (int i = 0; i < size; i++) { 19165 int shift = 8 + (i % 7); 19166 string_contents[alignment + i] = 1 << shift; 19167 string = String::NewExternal( 19168 isolate, 19169 new TestResource(string_contents + alignment, NULL, false)); 19170 CHECK_EQ(size, string->Length()); 19171 CHECK(!string->ContainsOnlyOneByte()); 19172 string_contents[alignment + i] = 0x41; 19173 } 19174 string_contents[zero_offset] = 0x41; 19175 } 19176 } 19177 } 19178 19179 19180 // Failed access check callback that performs a GC on each invocation. 19181 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 19182 v8::AccessType type, 19183 Local<v8::Value> data) { 19184 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19185 } 19186 19187 19188 TEST(GCInFailedAccessCheckCallback) { 19189 // Install a failed access check callback that performs a GC on each 19190 // invocation. Then force the callback to be called from va 19191 19192 v8::V8::Initialize(); 19193 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 19194 19195 v8::Isolate* isolate = CcTest::isolate(); 19196 v8::HandleScope scope(isolate); 19197 19198 // Create an ObjectTemplate for global objects and install access 19199 // check callbacks that will block access. 19200 v8::Handle<v8::ObjectTemplate> global_template = 19201 v8::ObjectTemplate::New(isolate); 19202 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 19203 IndexedGetAccessBlocker, 19204 v8::Handle<v8::Value>(), 19205 false); 19206 19207 // Create a context and set an x property on it's global object. 19208 LocalContext context0(NULL, global_template); 19209 context0->Global()->Set(v8_str("x"), v8_num(42)); 19210 v8::Handle<v8::Object> global0 = context0->Global(); 19211 19212 // Create a context with a different security token so that the 19213 // failed access check callback will be called on each access. 19214 LocalContext context1(NULL, global_template); 19215 context1->Global()->Set(v8_str("other"), global0); 19216 19217 // Get property with failed access check. 19218 ExpectUndefined("other.x"); 19219 19220 // Get element with failed access check. 19221 ExpectUndefined("other[0]"); 19222 19223 // Set property with failed access check. 19224 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); 19225 CHECK(result->IsObject()); 19226 19227 // Set element with failed access check. 19228 result = CompileRun("other[0] = new Object()"); 19229 CHECK(result->IsObject()); 19230 19231 // Get property attribute with failed access check. 19232 ExpectFalse("\'x\' in other"); 19233 19234 // Get property attribute for element with failed access check. 19235 ExpectFalse("0 in other"); 19236 19237 // Delete property. 19238 ExpectFalse("delete other.x"); 19239 19240 // Delete element. 19241 CHECK_EQ(false, global0->Delete(0)); 19242 19243 // DefineAccessor. 19244 CHECK_EQ(false, 19245 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); 19246 19247 // Define JavaScript accessor. 19248 ExpectUndefined("Object.prototype.__defineGetter__.call(" 19249 " other, \'x\', function() { return 42; })"); 19250 19251 // LookupAccessor. 19252 ExpectUndefined("Object.prototype.__lookupGetter__.call(" 19253 " other, \'x\')"); 19254 19255 // HasOwnElement. 19256 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); 19257 19258 CHECK_EQ(false, global0->HasRealIndexedProperty(0)); 19259 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); 19260 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); 19261 19262 // Reset the failed access check callback so it does not influence 19263 // the other tests. 19264 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 19265 } 19266 19267 19268 TEST(IsolateNewDispose) { 19269 v8::Isolate* current_isolate = CcTest::isolate(); 19270 v8::Isolate* isolate = v8::Isolate::New(); 19271 CHECK(isolate != NULL); 19272 CHECK(current_isolate != isolate); 19273 CHECK(current_isolate == CcTest::isolate()); 19274 19275 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19276 last_location = last_message = NULL; 19277 isolate->Dispose(); 19278 CHECK_EQ(last_location, NULL); 19279 CHECK_EQ(last_message, NULL); 19280 } 19281 19282 19283 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) { 19284 v8::Isolate* isolate = v8::Isolate::New(); 19285 { 19286 v8::Isolate::Scope i_scope(isolate); 19287 v8::HandleScope scope(isolate); 19288 LocalContext context(isolate); 19289 // Run something in this isolate. 19290 ExpectTrue("true"); 19291 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19292 last_location = last_message = NULL; 19293 // Still entered, should fail. 19294 isolate->Dispose(); 19295 CHECK_NE(last_location, NULL); 19296 CHECK_NE(last_message, NULL); 19297 } 19298 isolate->Dispose(); 19299 } 19300 19301 19302 TEST(RunTwoIsolatesOnSingleThread) { 19303 // Run isolate 1. 19304 v8::Isolate* isolate1 = v8::Isolate::New(); 19305 isolate1->Enter(); 19306 v8::Persistent<v8::Context> context1; 19307 { 19308 v8::HandleScope scope(isolate1); 19309 context1.Reset(isolate1, Context::New(isolate1)); 19310 } 19311 19312 { 19313 v8::HandleScope scope(isolate1); 19314 v8::Local<v8::Context> context = 19315 v8::Local<v8::Context>::New(isolate1, context1); 19316 v8::Context::Scope context_scope(context); 19317 // Run something in new isolate. 19318 CompileRun("var foo = 'isolate 1';"); 19319 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19320 } 19321 19322 // Run isolate 2. 19323 v8::Isolate* isolate2 = v8::Isolate::New(); 19324 v8::Persistent<v8::Context> context2; 19325 19326 { 19327 v8::Isolate::Scope iscope(isolate2); 19328 v8::HandleScope scope(isolate2); 19329 context2.Reset(isolate2, Context::New(isolate2)); 19330 v8::Local<v8::Context> context = 19331 v8::Local<v8::Context>::New(isolate2, context2); 19332 v8::Context::Scope context_scope(context); 19333 19334 // Run something in new isolate. 19335 CompileRun("var foo = 'isolate 2';"); 19336 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19337 } 19338 19339 { 19340 v8::HandleScope scope(isolate1); 19341 v8::Local<v8::Context> context = 19342 v8::Local<v8::Context>::New(isolate1, context1); 19343 v8::Context::Scope context_scope(context); 19344 // Now again in isolate 1 19345 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19346 } 19347 19348 isolate1->Exit(); 19349 19350 // Run some stuff in default isolate. 19351 v8::Persistent<v8::Context> context_default; 19352 { 19353 v8::Isolate* isolate = CcTest::isolate(); 19354 v8::Isolate::Scope iscope(isolate); 19355 v8::HandleScope scope(isolate); 19356 context_default.Reset(isolate, Context::New(isolate)); 19357 } 19358 19359 { 19360 v8::HandleScope scope(CcTest::isolate()); 19361 v8::Local<v8::Context> context = 19362 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19363 v8::Context::Scope context_scope(context); 19364 // Variables in other isolates should be not available, verify there 19365 // is an exception. 19366 ExpectTrue("function f() {" 19367 " try {" 19368 " foo;" 19369 " return false;" 19370 " } catch(e) {" 19371 " return true;" 19372 " }" 19373 "};" 19374 "var isDefaultIsolate = true;" 19375 "f()"); 19376 } 19377 19378 isolate1->Enter(); 19379 19380 { 19381 v8::Isolate::Scope iscope(isolate2); 19382 v8::HandleScope scope(isolate2); 19383 v8::Local<v8::Context> context = 19384 v8::Local<v8::Context>::New(isolate2, context2); 19385 v8::Context::Scope context_scope(context); 19386 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19387 } 19388 19389 { 19390 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19391 v8::Local<v8::Context> context = 19392 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 19393 v8::Context::Scope context_scope(context); 19394 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19395 } 19396 19397 { 19398 v8::Isolate::Scope iscope(isolate2); 19399 context2.Reset(); 19400 } 19401 19402 context1.Reset(); 19403 isolate1->Exit(); 19404 19405 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19406 last_location = last_message = NULL; 19407 19408 isolate1->Dispose(); 19409 CHECK_EQ(last_location, NULL); 19410 CHECK_EQ(last_message, NULL); 19411 19412 isolate2->Dispose(); 19413 CHECK_EQ(last_location, NULL); 19414 CHECK_EQ(last_message, NULL); 19415 19416 // Check that default isolate still runs. 19417 { 19418 v8::HandleScope scope(CcTest::isolate()); 19419 v8::Local<v8::Context> context = 19420 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19421 v8::Context::Scope context_scope(context); 19422 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 19423 } 19424 } 19425 19426 19427 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 19428 v8::Isolate::Scope isolate_scope(isolate); 19429 v8::HandleScope scope(isolate); 19430 LocalContext context(isolate); 19431 i::ScopedVector<char> code(1024); 19432 i::SNPrintF(code, "function fib(n) {" 19433 " if (n <= 2) return 1;" 19434 " return fib(n-1) + fib(n-2);" 19435 "}" 19436 "fib(%d)", limit); 19437 Local<Value> value = CompileRun(code.start()); 19438 CHECK(value->IsNumber()); 19439 return static_cast<int>(value->NumberValue()); 19440 } 19441 19442 class IsolateThread : public v8::internal::Thread { 19443 public: 19444 IsolateThread(v8::Isolate* isolate, int fib_limit) 19445 : Thread("IsolateThread"), 19446 isolate_(isolate), 19447 fib_limit_(fib_limit), 19448 result_(0) { } 19449 19450 void Run() { 19451 result_ = CalcFibonacci(isolate_, fib_limit_); 19452 } 19453 19454 int result() { return result_; } 19455 19456 private: 19457 v8::Isolate* isolate_; 19458 int fib_limit_; 19459 int result_; 19460 }; 19461 19462 19463 TEST(MultipleIsolatesOnIndividualThreads) { 19464 v8::Isolate* isolate1 = v8::Isolate::New(); 19465 v8::Isolate* isolate2 = v8::Isolate::New(); 19466 19467 IsolateThread thread1(isolate1, 21); 19468 IsolateThread thread2(isolate2, 12); 19469 19470 // Compute some fibonacci numbers on 3 threads in 3 isolates. 19471 thread1.Start(); 19472 thread2.Start(); 19473 19474 int result1 = CalcFibonacci(CcTest::isolate(), 21); 19475 int result2 = CalcFibonacci(CcTest::isolate(), 12); 19476 19477 thread1.Join(); 19478 thread2.Join(); 19479 19480 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 19481 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 19482 CHECK_EQ(result1, 10946); 19483 CHECK_EQ(result2, 144); 19484 CHECK_EQ(result1, thread1.result()); 19485 CHECK_EQ(result2, thread2.result()); 19486 19487 isolate1->Dispose(); 19488 isolate2->Dispose(); 19489 } 19490 19491 19492 TEST(IsolateDifferentContexts) { 19493 v8::Isolate* isolate = v8::Isolate::New(); 19494 Local<v8::Context> context; 19495 { 19496 v8::Isolate::Scope isolate_scope(isolate); 19497 v8::HandleScope handle_scope(isolate); 19498 context = v8::Context::New(isolate); 19499 v8::Context::Scope context_scope(context); 19500 Local<Value> v = CompileRun("2"); 19501 CHECK(v->IsNumber()); 19502 CHECK_EQ(2, static_cast<int>(v->NumberValue())); 19503 } 19504 { 19505 v8::Isolate::Scope isolate_scope(isolate); 19506 v8::HandleScope handle_scope(isolate); 19507 context = v8::Context::New(isolate); 19508 v8::Context::Scope context_scope(context); 19509 Local<Value> v = CompileRun("22"); 19510 CHECK(v->IsNumber()); 19511 CHECK_EQ(22, static_cast<int>(v->NumberValue())); 19512 } 19513 isolate->Dispose(); 19514 } 19515 19516 class InitDefaultIsolateThread : public v8::internal::Thread { 19517 public: 19518 enum TestCase { 19519 SetResourceConstraints, 19520 SetFatalHandler, 19521 SetCounterFunction, 19522 SetCreateHistogramFunction, 19523 SetAddHistogramSampleFunction 19524 }; 19525 19526 explicit InitDefaultIsolateThread(TestCase testCase) 19527 : Thread("InitDefaultIsolateThread"), 19528 testCase_(testCase), 19529 result_(false) { } 19530 19531 void Run() { 19532 v8::Isolate* isolate = v8::Isolate::New(); 19533 isolate->Enter(); 19534 switch (testCase_) { 19535 case SetResourceConstraints: { 19536 v8::ResourceConstraints constraints; 19537 constraints.set_max_semi_space_size(1); 19538 constraints.set_max_old_space_size(4); 19539 v8::SetResourceConstraints(CcTest::isolate(), &constraints); 19540 break; 19541 } 19542 19543 case SetFatalHandler: 19544 v8::V8::SetFatalErrorHandler(NULL); 19545 break; 19546 19547 case SetCounterFunction: 19548 CcTest::isolate()->SetCounterFunction(NULL); 19549 break; 19550 19551 case SetCreateHistogramFunction: 19552 CcTest::isolate()->SetCreateHistogramFunction(NULL); 19553 break; 19554 19555 case SetAddHistogramSampleFunction: 19556 CcTest::isolate()->SetAddHistogramSampleFunction(NULL); 19557 break; 19558 } 19559 isolate->Exit(); 19560 isolate->Dispose(); 19561 result_ = true; 19562 } 19563 19564 bool result() { return result_; } 19565 19566 private: 19567 TestCase testCase_; 19568 bool result_; 19569 }; 19570 19571 19572 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 19573 InitDefaultIsolateThread thread(testCase); 19574 thread.Start(); 19575 thread.Join(); 19576 CHECK_EQ(thread.result(), true); 19577 } 19578 19579 19580 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 19581 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 19582 } 19583 19584 19585 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 19586 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 19587 } 19588 19589 19590 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 19591 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 19592 } 19593 19594 19595 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 19596 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 19597 } 19598 19599 19600 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 19601 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 19602 } 19603 19604 19605 TEST(StringCheckMultipleContexts) { 19606 const char* code = 19607 "(function() { return \"a\".charAt(0); })()"; 19608 19609 { 19610 // Run the code twice in the first context to initialize the call IC. 19611 LocalContext context1; 19612 v8::HandleScope scope(context1->GetIsolate()); 19613 ExpectString(code, "a"); 19614 ExpectString(code, "a"); 19615 } 19616 19617 { 19618 // Change the String.prototype in the second context and check 19619 // that the right function gets called. 19620 LocalContext context2; 19621 v8::HandleScope scope(context2->GetIsolate()); 19622 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 19623 ExpectString(code, "not a"); 19624 } 19625 } 19626 19627 19628 TEST(NumberCheckMultipleContexts) { 19629 const char* code = 19630 "(function() { return (42).toString(); })()"; 19631 19632 { 19633 // Run the code twice in the first context to initialize the call IC. 19634 LocalContext context1; 19635 v8::HandleScope scope(context1->GetIsolate()); 19636 ExpectString(code, "42"); 19637 ExpectString(code, "42"); 19638 } 19639 19640 { 19641 // Change the Number.prototype in the second context and check 19642 // that the right function gets called. 19643 LocalContext context2; 19644 v8::HandleScope scope(context2->GetIsolate()); 19645 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 19646 ExpectString(code, "not 42"); 19647 } 19648 } 19649 19650 19651 TEST(BooleanCheckMultipleContexts) { 19652 const char* code = 19653 "(function() { return true.toString(); })()"; 19654 19655 { 19656 // Run the code twice in the first context to initialize the call IC. 19657 LocalContext context1; 19658 v8::HandleScope scope(context1->GetIsolate()); 19659 ExpectString(code, "true"); 19660 ExpectString(code, "true"); 19661 } 19662 19663 { 19664 // Change the Boolean.prototype in the second context and check 19665 // that the right function gets called. 19666 LocalContext context2; 19667 v8::HandleScope scope(context2->GetIsolate()); 19668 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 19669 ExpectString(code, ""); 19670 } 19671 } 19672 19673 19674 TEST(DontDeleteCellLoadIC) { 19675 const char* function_code = 19676 "function readCell() { while (true) { return cell; } }"; 19677 19678 { 19679 // Run the code twice in the first context to initialize the load 19680 // IC for a don't delete cell. 19681 LocalContext context1; 19682 v8::HandleScope scope(context1->GetIsolate()); 19683 CompileRun("var cell = \"first\";"); 19684 ExpectBoolean("delete cell", false); 19685 CompileRun(function_code); 19686 ExpectString("readCell()", "first"); 19687 ExpectString("readCell()", "first"); 19688 } 19689 19690 { 19691 // Use a deletable cell in the second context. 19692 LocalContext context2; 19693 v8::HandleScope scope(context2->GetIsolate()); 19694 CompileRun("cell = \"second\";"); 19695 CompileRun(function_code); 19696 ExpectString("readCell()", "second"); 19697 ExpectBoolean("delete cell", true); 19698 ExpectString("(function() {" 19699 " try {" 19700 " return readCell();" 19701 " } catch(e) {" 19702 " return e.toString();" 19703 " }" 19704 "})()", 19705 "ReferenceError: cell is not defined"); 19706 CompileRun("cell = \"new_second\";"); 19707 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19708 ExpectString("readCell()", "new_second"); 19709 ExpectString("readCell()", "new_second"); 19710 } 19711 } 19712 19713 19714 TEST(DontDeleteCellLoadICForceDelete) { 19715 const char* function_code = 19716 "function readCell() { while (true) { return cell; } }"; 19717 19718 // Run the code twice to initialize the load IC for a don't delete 19719 // cell. 19720 LocalContext context; 19721 v8::HandleScope scope(context->GetIsolate()); 19722 CompileRun("var cell = \"value\";"); 19723 ExpectBoolean("delete cell", false); 19724 CompileRun(function_code); 19725 ExpectString("readCell()", "value"); 19726 ExpectString("readCell()", "value"); 19727 19728 // Delete the cell using the API and check the inlined code works 19729 // correctly. 19730 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 19731 ExpectString("(function() {" 19732 " try {" 19733 " return readCell();" 19734 " } catch(e) {" 19735 " return e.toString();" 19736 " }" 19737 "})()", 19738 "ReferenceError: cell is not defined"); 19739 } 19740 19741 19742 TEST(DontDeleteCellLoadICAPI) { 19743 const char* function_code = 19744 "function readCell() { while (true) { return cell; } }"; 19745 19746 // Run the code twice to initialize the load IC for a don't delete 19747 // cell created using the API. 19748 LocalContext context; 19749 v8::HandleScope scope(context->GetIsolate()); 19750 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); 19751 ExpectBoolean("delete cell", false); 19752 CompileRun(function_code); 19753 ExpectString("readCell()", "value"); 19754 ExpectString("readCell()", "value"); 19755 19756 // Delete the cell using the API and check the inlined code works 19757 // correctly. 19758 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 19759 ExpectString("(function() {" 19760 " try {" 19761 " return readCell();" 19762 " } catch(e) {" 19763 " return e.toString();" 19764 " }" 19765 "})()", 19766 "ReferenceError: cell is not defined"); 19767 } 19768 19769 19770 class Visitor42 : public v8::PersistentHandleVisitor { 19771 public: 19772 explicit Visitor42(v8::Persistent<v8::Object>* object) 19773 : counter_(0), object_(object) { } 19774 19775 virtual void VisitPersistentHandle(Persistent<Value>* value, 19776 uint16_t class_id) { 19777 if (class_id != 42) return; 19778 CHECK_EQ(42, value->WrapperClassId()); 19779 v8::Isolate* isolate = CcTest::isolate(); 19780 v8::HandleScope handle_scope(isolate); 19781 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 19782 v8::Handle<v8::Value> object = 19783 v8::Local<v8::Object>::New(isolate, *object_); 19784 CHECK(handle->IsObject()); 19785 CHECK_EQ(Handle<Object>::Cast(handle), object); 19786 ++counter_; 19787 } 19788 19789 int counter_; 19790 v8::Persistent<v8::Object>* object_; 19791 }; 19792 19793 19794 TEST(PersistentHandleVisitor) { 19795 LocalContext context; 19796 v8::Isolate* isolate = context->GetIsolate(); 19797 v8::HandleScope scope(isolate); 19798 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19799 CHECK_EQ(0, object.WrapperClassId()); 19800 object.SetWrapperClassId(42); 19801 CHECK_EQ(42, object.WrapperClassId()); 19802 19803 Visitor42 visitor(&object); 19804 v8::V8::VisitHandlesWithClassIds(&visitor); 19805 CHECK_EQ(1, visitor.counter_); 19806 19807 object.Reset(); 19808 } 19809 19810 19811 TEST(WrapperClassId) { 19812 LocalContext context; 19813 v8::Isolate* isolate = context->GetIsolate(); 19814 v8::HandleScope scope(isolate); 19815 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19816 CHECK_EQ(0, object.WrapperClassId()); 19817 object.SetWrapperClassId(65535); 19818 CHECK_EQ(65535, object.WrapperClassId()); 19819 object.Reset(); 19820 } 19821 19822 19823 TEST(PersistentHandleInNewSpaceVisitor) { 19824 LocalContext context; 19825 v8::Isolate* isolate = context->GetIsolate(); 19826 v8::HandleScope scope(isolate); 19827 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate)); 19828 CHECK_EQ(0, object1.WrapperClassId()); 19829 object1.SetWrapperClassId(42); 19830 CHECK_EQ(42, object1.WrapperClassId()); 19831 19832 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19833 19834 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); 19835 CHECK_EQ(0, object2.WrapperClassId()); 19836 object2.SetWrapperClassId(42); 19837 CHECK_EQ(42, object2.WrapperClassId()); 19838 19839 Visitor42 visitor(&object2); 19840 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); 19841 CHECK_EQ(1, visitor.counter_); 19842 19843 object1.Reset(); 19844 object2.Reset(); 19845 } 19846 19847 19848 TEST(RegExp) { 19849 LocalContext context; 19850 v8::HandleScope scope(context->GetIsolate()); 19851 19852 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone); 19853 CHECK(re->IsRegExp()); 19854 CHECK(re->GetSource()->Equals(v8_str("foo"))); 19855 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19856 19857 re = v8::RegExp::New(v8_str("bar"), 19858 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19859 v8::RegExp::kGlobal)); 19860 CHECK(re->IsRegExp()); 19861 CHECK(re->GetSource()->Equals(v8_str("bar"))); 19862 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 19863 static_cast<int>(re->GetFlags())); 19864 19865 re = v8::RegExp::New(v8_str("baz"), 19866 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19867 v8::RegExp::kMultiline)); 19868 CHECK(re->IsRegExp()); 19869 CHECK(re->GetSource()->Equals(v8_str("baz"))); 19870 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19871 static_cast<int>(re->GetFlags())); 19872 19873 re = CompileRun("/quux/").As<v8::RegExp>(); 19874 CHECK(re->IsRegExp()); 19875 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19876 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19877 19878 re = CompileRun("/quux/gm").As<v8::RegExp>(); 19879 CHECK(re->IsRegExp()); 19880 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19881 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 19882 static_cast<int>(re->GetFlags())); 19883 19884 // Override the RegExp constructor and check the API constructor 19885 // still works. 19886 CompileRun("RegExp = function() {}"); 19887 19888 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone); 19889 CHECK(re->IsRegExp()); 19890 CHECK(re->GetSource()->Equals(v8_str("foobar"))); 19891 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19892 19893 re = v8::RegExp::New(v8_str("foobarbaz"), 19894 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19895 v8::RegExp::kMultiline)); 19896 CHECK(re->IsRegExp()); 19897 CHECK(re->GetSource()->Equals(v8_str("foobarbaz"))); 19898 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19899 static_cast<int>(re->GetFlags())); 19900 19901 context->Global()->Set(v8_str("re"), re); 19902 ExpectTrue("re.test('FoobarbaZ')"); 19903 19904 // RegExps are objects on which you can set properties. 19905 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32)); 19906 v8::Handle<v8::Value> value(CompileRun("re.property")); 19907 CHECK_EQ(32, value->Int32Value()); 19908 19909 v8::TryCatch try_catch; 19910 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); 19911 CHECK(re.IsEmpty()); 19912 CHECK(try_catch.HasCaught()); 19913 context->Global()->Set(v8_str("ex"), try_catch.Exception()); 19914 ExpectTrue("ex instanceof SyntaxError"); 19915 } 19916 19917 19918 THREADED_TEST(Equals) { 19919 LocalContext localContext; 19920 v8::HandleScope handleScope(localContext->GetIsolate()); 19921 19922 v8::Handle<v8::Object> globalProxy = localContext->Global(); 19923 v8::Handle<Value> global = globalProxy->GetPrototype(); 19924 19925 CHECK(global->StrictEquals(global)); 19926 CHECK(!global->StrictEquals(globalProxy)); 19927 CHECK(!globalProxy->StrictEquals(global)); 19928 CHECK(globalProxy->StrictEquals(globalProxy)); 19929 19930 CHECK(global->Equals(global)); 19931 CHECK(!global->Equals(globalProxy)); 19932 CHECK(!globalProxy->Equals(global)); 19933 CHECK(globalProxy->Equals(globalProxy)); 19934 } 19935 19936 19937 static void Getter(v8::Local<v8::String> property, 19938 const v8::PropertyCallbackInfo<v8::Value>& info ) { 19939 info.GetReturnValue().Set(v8_str("42!")); 19940 } 19941 19942 19943 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 19944 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate()); 19945 result->Set(0, v8_str("universalAnswer")); 19946 info.GetReturnValue().Set(result); 19947 } 19948 19949 19950 TEST(NamedEnumeratorAndForIn) { 19951 LocalContext context; 19952 v8::Isolate* isolate = context->GetIsolate(); 19953 v8::HandleScope handle_scope(isolate); 19954 v8::Context::Scope context_scope(context.local()); 19955 19956 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate); 19957 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); 19958 context->Global()->Set(v8_str("o"), tmpl->NewInstance()); 19959 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 19960 "var result = []; for (var k in o) result.push(k); result")); 19961 CHECK_EQ(1, result->Length()); 19962 CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); 19963 } 19964 19965 19966 TEST(DefinePropertyPostDetach) { 19967 LocalContext context; 19968 v8::HandleScope scope(context->GetIsolate()); 19969 v8::Handle<v8::Object> proxy = context->Global(); 19970 v8::Handle<v8::Function> define_property = 19971 CompileRun("(function() {" 19972 " Object.defineProperty(" 19973 " this," 19974 " 1," 19975 " { configurable: true, enumerable: true, value: 3 });" 19976 "})").As<Function>(); 19977 context->DetachGlobal(); 19978 define_property->Call(proxy, 0, NULL); 19979 } 19980 19981 19982 static void InstallContextId(v8::Handle<Context> context, int id) { 19983 Context::Scope scope(context); 19984 CompileRun("Object.prototype").As<Object>()-> 19985 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id)); 19986 } 19987 19988 19989 static void CheckContextId(v8::Handle<Object> object, int expected) { 19990 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value()); 19991 } 19992 19993 19994 THREADED_TEST(CreationContext) { 19995 v8::Isolate* isolate = CcTest::isolate(); 19996 HandleScope handle_scope(isolate); 19997 Handle<Context> context1 = Context::New(isolate); 19998 InstallContextId(context1, 1); 19999 Handle<Context> context2 = Context::New(isolate); 20000 InstallContextId(context2, 2); 20001 Handle<Context> context3 = Context::New(isolate); 20002 InstallContextId(context3, 3); 20003 20004 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate); 20005 20006 Local<Object> object1; 20007 Local<Function> func1; 20008 { 20009 Context::Scope scope(context1); 20010 object1 = Object::New(isolate); 20011 func1 = tmpl->GetFunction(); 20012 } 20013 20014 Local<Object> object2; 20015 Local<Function> func2; 20016 { 20017 Context::Scope scope(context2); 20018 object2 = Object::New(isolate); 20019 func2 = tmpl->GetFunction(); 20020 } 20021 20022 Local<Object> instance1; 20023 Local<Object> instance2; 20024 20025 { 20026 Context::Scope scope(context3); 20027 instance1 = func1->NewInstance(); 20028 instance2 = func2->NewInstance(); 20029 } 20030 20031 CHECK(object1->CreationContext() == context1); 20032 CheckContextId(object1, 1); 20033 CHECK(func1->CreationContext() == context1); 20034 CheckContextId(func1, 1); 20035 CHECK(instance1->CreationContext() == context1); 20036 CheckContextId(instance1, 1); 20037 CHECK(object2->CreationContext() == context2); 20038 CheckContextId(object2, 2); 20039 CHECK(func2->CreationContext() == context2); 20040 CheckContextId(func2, 2); 20041 CHECK(instance2->CreationContext() == context2); 20042 CheckContextId(instance2, 2); 20043 20044 { 20045 Context::Scope scope(context1); 20046 CHECK(object1->CreationContext() == context1); 20047 CheckContextId(object1, 1); 20048 CHECK(func1->CreationContext() == context1); 20049 CheckContextId(func1, 1); 20050 CHECK(instance1->CreationContext() == context1); 20051 CheckContextId(instance1, 1); 20052 CHECK(object2->CreationContext() == context2); 20053 CheckContextId(object2, 2); 20054 CHECK(func2->CreationContext() == context2); 20055 CheckContextId(func2, 2); 20056 CHECK(instance2->CreationContext() == context2); 20057 CheckContextId(instance2, 2); 20058 } 20059 20060 { 20061 Context::Scope scope(context2); 20062 CHECK(object1->CreationContext() == context1); 20063 CheckContextId(object1, 1); 20064 CHECK(func1->CreationContext() == context1); 20065 CheckContextId(func1, 1); 20066 CHECK(instance1->CreationContext() == context1); 20067 CheckContextId(instance1, 1); 20068 CHECK(object2->CreationContext() == context2); 20069 CheckContextId(object2, 2); 20070 CHECK(func2->CreationContext() == context2); 20071 CheckContextId(func2, 2); 20072 CHECK(instance2->CreationContext() == context2); 20073 CheckContextId(instance2, 2); 20074 } 20075 } 20076 20077 20078 THREADED_TEST(CreationContextOfJsFunction) { 20079 HandleScope handle_scope(CcTest::isolate()); 20080 Handle<Context> context = Context::New(CcTest::isolate()); 20081 InstallContextId(context, 1); 20082 20083 Local<Object> function; 20084 { 20085 Context::Scope scope(context); 20086 function = CompileRun("function foo() {}; foo").As<Object>(); 20087 } 20088 20089 CHECK(function->CreationContext() == context); 20090 CheckContextId(function, 1); 20091 } 20092 20093 20094 void HasOwnPropertyIndexedPropertyGetter( 20095 uint32_t index, 20096 const v8::PropertyCallbackInfo<v8::Value>& info) { 20097 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 20098 } 20099 20100 20101 void HasOwnPropertyNamedPropertyGetter( 20102 Local<String> property, 20103 const v8::PropertyCallbackInfo<v8::Value>& info) { 20104 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes")); 20105 } 20106 20107 20108 void HasOwnPropertyIndexedPropertyQuery( 20109 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 20110 if (index == 42) info.GetReturnValue().Set(1); 20111 } 20112 20113 20114 void HasOwnPropertyNamedPropertyQuery( 20115 Local<String> property, 20116 const v8::PropertyCallbackInfo<v8::Integer>& info) { 20117 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1); 20118 } 20119 20120 20121 void HasOwnPropertyNamedPropertyQuery2( 20122 Local<String> property, 20123 const v8::PropertyCallbackInfo<v8::Integer>& info) { 20124 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1); 20125 } 20126 20127 20128 void HasOwnPropertyAccessorGetter( 20129 Local<String> property, 20130 const v8::PropertyCallbackInfo<v8::Value>& info) { 20131 info.GetReturnValue().Set(v8_str("yes")); 20132 } 20133 20134 20135 TEST(HasOwnProperty) { 20136 LocalContext env; 20137 v8::Isolate* isolate = env->GetIsolate(); 20138 v8::HandleScope scope(isolate); 20139 { // Check normal properties and defined getters. 20140 Handle<Value> value = CompileRun( 20141 "function Foo() {" 20142 " this.foo = 11;" 20143 " this.__defineGetter__('baz', function() { return 1; });" 20144 "};" 20145 "function Bar() { " 20146 " this.bar = 13;" 20147 " this.__defineGetter__('bla', function() { return 2; });" 20148 "};" 20149 "Bar.prototype = new Foo();" 20150 "new Bar();"); 20151 CHECK(value->IsObject()); 20152 Handle<Object> object = value->ToObject(); 20153 CHECK(object->Has(v8_str("foo"))); 20154 CHECK(!object->HasOwnProperty(v8_str("foo"))); 20155 CHECK(object->HasOwnProperty(v8_str("bar"))); 20156 CHECK(object->Has(v8_str("baz"))); 20157 CHECK(!object->HasOwnProperty(v8_str("baz"))); 20158 CHECK(object->HasOwnProperty(v8_str("bla"))); 20159 } 20160 { // Check named getter interceptors. 20161 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20162 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter); 20163 Handle<Object> instance = templ->NewInstance(); 20164 CHECK(!instance->HasOwnProperty(v8_str("42"))); 20165 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20166 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20167 } 20168 { // Check indexed getter interceptors. 20169 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20170 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter); 20171 Handle<Object> instance = templ->NewInstance(); 20172 CHECK(instance->HasOwnProperty(v8_str("42"))); 20173 CHECK(!instance->HasOwnProperty(v8_str("43"))); 20174 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 20175 } 20176 { // Check named query interceptors. 20177 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20178 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery); 20179 Handle<Object> instance = templ->NewInstance(); 20180 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20181 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20182 } 20183 { // Check indexed query interceptors. 20184 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20185 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery); 20186 Handle<Object> instance = templ->NewInstance(); 20187 CHECK(instance->HasOwnProperty(v8_str("42"))); 20188 CHECK(!instance->HasOwnProperty(v8_str("41"))); 20189 } 20190 { // Check callbacks. 20191 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20192 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 20193 Handle<Object> instance = templ->NewInstance(); 20194 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20195 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20196 } 20197 { // Check that query wins on disagreement. 20198 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20199 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter, 20200 0, 20201 HasOwnPropertyNamedPropertyQuery2); 20202 Handle<Object> instance = templ->NewInstance(); 20203 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 20204 CHECK(instance->HasOwnProperty(v8_str("bar"))); 20205 } 20206 } 20207 20208 20209 TEST(IndexedInterceptorWithStringProto) { 20210 v8::Isolate* isolate = CcTest::isolate(); 20211 v8::HandleScope scope(isolate); 20212 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20213 templ->SetIndexedPropertyHandler(NULL, 20214 NULL, 20215 HasOwnPropertyIndexedPropertyQuery); 20216 LocalContext context; 20217 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 20218 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 20219 // These should be intercepted. 20220 CHECK(CompileRun("42 in obj")->BooleanValue()); 20221 CHECK(CompileRun("'42' in obj")->BooleanValue()); 20222 // These should fall through to the String prototype. 20223 CHECK(CompileRun("0 in obj")->BooleanValue()); 20224 CHECK(CompileRun("'0' in obj")->BooleanValue()); 20225 // And these should both fail. 20226 CHECK(!CompileRun("32 in obj")->BooleanValue()); 20227 CHECK(!CompileRun("'32' in obj")->BooleanValue()); 20228 } 20229 20230 20231 void CheckCodeGenerationAllowed() { 20232 Handle<Value> result = CompileRun("eval('42')"); 20233 CHECK_EQ(42, result->Int32Value()); 20234 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20235 CHECK_EQ(42, result->Int32Value()); 20236 result = CompileRun("var f = new Function('return 42'); f()"); 20237 CHECK_EQ(42, result->Int32Value()); 20238 } 20239 20240 20241 void CheckCodeGenerationDisallowed() { 20242 TryCatch try_catch; 20243 20244 Handle<Value> result = CompileRun("eval('42')"); 20245 CHECK(result.IsEmpty()); 20246 CHECK(try_catch.HasCaught()); 20247 try_catch.Reset(); 20248 20249 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20250 CHECK(result.IsEmpty()); 20251 CHECK(try_catch.HasCaught()); 20252 try_catch.Reset(); 20253 20254 result = CompileRun("var f = new Function('return 42'); f()"); 20255 CHECK(result.IsEmpty()); 20256 CHECK(try_catch.HasCaught()); 20257 } 20258 20259 20260 bool CodeGenerationAllowed(Local<Context> context) { 20261 ApiTestFuzzer::Fuzz(); 20262 return true; 20263 } 20264 20265 20266 bool CodeGenerationDisallowed(Local<Context> context) { 20267 ApiTestFuzzer::Fuzz(); 20268 return false; 20269 } 20270 20271 20272 THREADED_TEST(AllowCodeGenFromStrings) { 20273 LocalContext context; 20274 v8::HandleScope scope(context->GetIsolate()); 20275 20276 // eval and the Function constructor allowed by default. 20277 CHECK(context->IsCodeGenerationFromStringsAllowed()); 20278 CheckCodeGenerationAllowed(); 20279 20280 // Disallow eval and the Function constructor. 20281 context->AllowCodeGenerationFromStrings(false); 20282 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20283 CheckCodeGenerationDisallowed(); 20284 20285 // Allow again. 20286 context->AllowCodeGenerationFromStrings(true); 20287 CheckCodeGenerationAllowed(); 20288 20289 // Disallow but setting a global callback that will allow the calls. 20290 context->AllowCodeGenerationFromStrings(false); 20291 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed); 20292 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20293 CheckCodeGenerationAllowed(); 20294 20295 // Set a callback that disallows the code generation. 20296 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 20297 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20298 CheckCodeGenerationDisallowed(); 20299 } 20300 20301 20302 TEST(SetErrorMessageForCodeGenFromStrings) { 20303 LocalContext context; 20304 v8::HandleScope scope(context->GetIsolate()); 20305 TryCatch try_catch; 20306 20307 Handle<String> message = v8_str("Message") ; 20308 Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); 20309 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 20310 context->AllowCodeGenerationFromStrings(false); 20311 context->SetErrorMessageForCodeGenerationFromStrings(message); 20312 Handle<Value> result = CompileRun("eval('42')"); 20313 CHECK(result.IsEmpty()); 20314 CHECK(try_catch.HasCaught()); 20315 Handle<String> actual_message = try_catch.Message()->Get(); 20316 CHECK(expected_message->Equals(actual_message)); 20317 } 20318 20319 20320 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 20321 } 20322 20323 20324 THREADED_TEST(CallAPIFunctionOnNonObject) { 20325 LocalContext context; 20326 v8::Isolate* isolate = context->GetIsolate(); 20327 v8::HandleScope scope(isolate); 20328 Handle<FunctionTemplate> templ = 20329 v8::FunctionTemplate::New(isolate, NonObjectThis); 20330 Handle<Function> function = templ->GetFunction(); 20331 context->Global()->Set(v8_str("f"), function); 20332 TryCatch try_catch; 20333 CompileRun("f.call(2)"); 20334 } 20335 20336 20337 // Regression test for issue 1470. 20338 THREADED_TEST(ReadOnlyIndexedProperties) { 20339 v8::Isolate* isolate = CcTest::isolate(); 20340 v8::HandleScope scope(isolate); 20341 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20342 20343 LocalContext context; 20344 Local<v8::Object> obj = templ->NewInstance(); 20345 context->Global()->Set(v8_str("obj"), obj); 20346 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); 20347 obj->Set(v8_str("1"), v8_str("foobar")); 20348 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); 20349 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); 20350 obj->Set(v8_num(2), v8_str("foobar")); 20351 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); 20352 20353 // Test non-smi case. 20354 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); 20355 obj->Set(v8_str("2000000000"), v8_str("foobar")); 20356 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); 20357 } 20358 20359 20360 THREADED_TEST(Regress1516) { 20361 LocalContext context; 20362 v8::HandleScope scope(context->GetIsolate()); 20363 20364 { v8::HandleScope temp_scope(context->GetIsolate()); 20365 CompileRun("({'a': 0})"); 20366 } 20367 20368 int elements; 20369 { i::MapCache* map_cache = 20370 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache()); 20371 elements = map_cache->NumberOfElements(); 20372 CHECK_LE(1, elements); 20373 } 20374 20375 CcTest::heap()->CollectAllGarbage( 20376 i::Heap::kAbortIncrementalMarkingMask); 20377 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache(); 20378 if (raw_map_cache != CcTest::heap()->undefined_value()) { 20379 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache); 20380 CHECK_GT(elements, map_cache->NumberOfElements()); 20381 } 20382 } 20383 } 20384 20385 20386 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, 20387 Local<Value> name, 20388 v8::AccessType type, 20389 Local<Value> data) { 20390 // Only block read access to __proto__. 20391 if (type == v8::ACCESS_GET && 20392 name->IsString() && 20393 name->ToString()->Length() == 9 && 20394 name->ToString()->Utf8Length() == 9) { 20395 char buffer[10]; 20396 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); 20397 return strncmp(buffer, "__proto__", 9) != 0; 20398 } 20399 20400 return true; 20401 } 20402 20403 20404 THREADED_TEST(Regress93759) { 20405 v8::Isolate* isolate = CcTest::isolate(); 20406 HandleScope scope(isolate); 20407 20408 // Template for object with security check. 20409 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate); 20410 // We don't do indexing, so any callback can be used for that. 20411 no_proto_template->SetAccessCheckCallbacks( 20412 BlockProtoNamedSecurityTestCallback, 20413 IndexedSecurityTestCallback); 20414 20415 // Templates for objects with hidden prototypes and possibly security check. 20416 Local<FunctionTemplate> hidden_proto_template = 20417 v8::FunctionTemplate::New(isolate); 20418 hidden_proto_template->SetHiddenPrototype(true); 20419 20420 Local<FunctionTemplate> protected_hidden_proto_template = 20421 v8::FunctionTemplate::New(isolate); 20422 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( 20423 BlockProtoNamedSecurityTestCallback, 20424 IndexedSecurityTestCallback); 20425 protected_hidden_proto_template->SetHiddenPrototype(true); 20426 20427 // Context for "foreign" objects used in test. 20428 Local<Context> context = v8::Context::New(isolate); 20429 context->Enter(); 20430 20431 // Plain object, no security check. 20432 Local<Object> simple_object = Object::New(isolate); 20433 20434 // Object with explicit security check. 20435 Local<Object> protected_object = 20436 no_proto_template->NewInstance(); 20437 20438 // JSGlobalProxy object, always have security check. 20439 Local<Object> proxy_object = 20440 context->Global(); 20441 20442 // Global object, the prototype of proxy_object. No security checks. 20443 Local<Object> global_object = 20444 proxy_object->GetPrototype()->ToObject(); 20445 20446 // Hidden prototype without security check. 20447 Local<Object> hidden_prototype = 20448 hidden_proto_template->GetFunction()->NewInstance(); 20449 Local<Object> object_with_hidden = 20450 Object::New(isolate); 20451 object_with_hidden->SetPrototype(hidden_prototype); 20452 20453 // Hidden prototype with security check on the hidden prototype. 20454 Local<Object> protected_hidden_prototype = 20455 protected_hidden_proto_template->GetFunction()->NewInstance(); 20456 Local<Object> object_with_protected_hidden = 20457 Object::New(isolate); 20458 object_with_protected_hidden->SetPrototype(protected_hidden_prototype); 20459 20460 context->Exit(); 20461 20462 // Template for object for second context. Values to test are put on it as 20463 // properties. 20464 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 20465 global_template->Set(v8_str("simple"), simple_object); 20466 global_template->Set(v8_str("protected"), protected_object); 20467 global_template->Set(v8_str("global"), global_object); 20468 global_template->Set(v8_str("proxy"), proxy_object); 20469 global_template->Set(v8_str("hidden"), object_with_hidden); 20470 global_template->Set(v8_str("phidden"), object_with_protected_hidden); 20471 20472 LocalContext context2(NULL, global_template); 20473 20474 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 20475 CHECK(result1->Equals(simple_object->GetPrototype())); 20476 20477 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 20478 CHECK(result2->Equals(Undefined(isolate))); 20479 20480 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 20481 CHECK(result3->Equals(global_object->GetPrototype())); 20482 20483 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 20484 CHECK(result4->Equals(Undefined(isolate))); 20485 20486 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 20487 CHECK(result5->Equals( 20488 object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); 20489 20490 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); 20491 CHECK(result6->Equals(Undefined(isolate))); 20492 } 20493 20494 20495 THREADED_TEST(Regress125988) { 20496 v8::HandleScope scope(CcTest::isolate()); 20497 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate()); 20498 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter); 20499 LocalContext env; 20500 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction()); 20501 CompileRun("var a = new Object();" 20502 "var b = new Intercept();" 20503 "var c = new Object();" 20504 "c.__proto__ = b;" 20505 "b.__proto__ = a;" 20506 "a.x = 23;" 20507 "for (var i = 0; i < 3; i++) c.x;"); 20508 ExpectBoolean("c.hasOwnProperty('x')", false); 20509 ExpectInt32("c.x", 23); 20510 CompileRun("a.y = 42;" 20511 "for (var i = 0; i < 3; i++) c.x;"); 20512 ExpectBoolean("c.hasOwnProperty('x')", false); 20513 ExpectInt32("c.x", 23); 20514 ExpectBoolean("c.hasOwnProperty('y')", false); 20515 ExpectInt32("c.y", 42); 20516 } 20517 20518 20519 static void TestReceiver(Local<Value> expected_result, 20520 Local<Value> expected_receiver, 20521 const char* code) { 20522 Local<Value> result = CompileRun(code); 20523 CHECK(result->IsObject()); 20524 CHECK(expected_receiver->Equals(result->ToObject()->Get(1))); 20525 CHECK(expected_result->Equals(result->ToObject()->Get(0))); 20526 } 20527 20528 20529 THREADED_TEST(ForeignFunctionReceiver) { 20530 v8::Isolate* isolate = CcTest::isolate(); 20531 HandleScope scope(isolate); 20532 20533 // Create two contexts with different "id" properties ('i' and 'o'). 20534 // Call a function both from its own context and from a the foreign 20535 // context, and see what "this" is bound to (returning both "this" 20536 // and "this.id" for comparison). 20537 20538 Local<Context> foreign_context = v8::Context::New(isolate); 20539 foreign_context->Enter(); 20540 Local<Value> foreign_function = 20541 CompileRun("function func() { return { 0: this.id, " 20542 " 1: this, " 20543 " toString: function() { " 20544 " return this[0];" 20545 " }" 20546 " };" 20547 "}" 20548 "var id = 'i';" 20549 "func;"); 20550 CHECK(foreign_function->IsFunction()); 20551 foreign_context->Exit(); 20552 20553 LocalContext context; 20554 20555 Local<String> password = v8_str("Password"); 20556 // Don't get hit by security checks when accessing foreign_context's 20557 // global receiver (aka. global proxy). 20558 context->SetSecurityToken(password); 20559 foreign_context->SetSecurityToken(password); 20560 20561 Local<String> i = v8_str("i"); 20562 Local<String> o = v8_str("o"); 20563 Local<String> id = v8_str("id"); 20564 20565 CompileRun("function ownfunc() { return { 0: this.id, " 20566 " 1: this, " 20567 " toString: function() { " 20568 " return this[0];" 20569 " }" 20570 " };" 20571 "}" 20572 "var id = 'o';" 20573 "ownfunc"); 20574 context->Global()->Set(v8_str("func"), foreign_function); 20575 20576 // Sanity check the contexts. 20577 CHECK(i->Equals(foreign_context->Global()->Get(id))); 20578 CHECK(o->Equals(context->Global()->Get(id))); 20579 20580 // Checking local function's receiver. 20581 // Calling function using its call/apply methods. 20582 TestReceiver(o, context->Global(), "ownfunc.call()"); 20583 TestReceiver(o, context->Global(), "ownfunc.apply()"); 20584 // Making calls through built-in functions. 20585 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 20586 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))); 20587 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))); 20588 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))); 20589 // Calling with environment record as base. 20590 TestReceiver(o, context->Global(), "ownfunc()"); 20591 // Calling with no base. 20592 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 20593 20594 // Checking foreign function return value. 20595 // Calling function using its call/apply methods. 20596 TestReceiver(i, foreign_context->Global(), "func.call()"); 20597 TestReceiver(i, foreign_context->Global(), "func.apply()"); 20598 // Calling function using another context's call/apply methods. 20599 TestReceiver(i, foreign_context->Global(), 20600 "Function.prototype.call.call(func)"); 20601 TestReceiver(i, foreign_context->Global(), 20602 "Function.prototype.call.apply(func)"); 20603 TestReceiver(i, foreign_context->Global(), 20604 "Function.prototype.apply.call(func)"); 20605 TestReceiver(i, foreign_context->Global(), 20606 "Function.prototype.apply.apply(func)"); 20607 // Making calls through built-in functions. 20608 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 20609 // ToString(func()) is func()[0], i.e., the returned this.id. 20610 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]"))); 20611 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]"))); 20612 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]"))); 20613 20614 // Calling with environment record as base. 20615 TestReceiver(i, foreign_context->Global(), "func()"); 20616 // Calling with no base. 20617 TestReceiver(i, foreign_context->Global(), "(1,func)()"); 20618 } 20619 20620 20621 uint8_t callback_fired = 0; 20622 20623 20624 void CallCompletedCallback1() { 20625 i::OS::Print("Firing callback 1.\n"); 20626 callback_fired ^= 1; // Toggle first bit. 20627 } 20628 20629 20630 void CallCompletedCallback2() { 20631 i::OS::Print("Firing callback 2.\n"); 20632 callback_fired ^= 2; // Toggle second bit. 20633 } 20634 20635 20636 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 20637 int32_t level = args[0]->Int32Value(); 20638 if (level < 3) { 20639 level++; 20640 i::OS::Print("Entering recursion level %d.\n", level); 20641 char script[64]; 20642 i::Vector<char> script_vector(script, sizeof(script)); 20643 i::SNPrintF(script_vector, "recursion(%d)", level); 20644 CompileRun(script_vector.start()); 20645 i::OS::Print("Leaving recursion level %d.\n", level); 20646 CHECK_EQ(0, callback_fired); 20647 } else { 20648 i::OS::Print("Recursion ends.\n"); 20649 CHECK_EQ(0, callback_fired); 20650 } 20651 } 20652 20653 20654 TEST(CallCompletedCallback) { 20655 LocalContext env; 20656 v8::HandleScope scope(env->GetIsolate()); 20657 v8::Handle<v8::FunctionTemplate> recursive_runtime = 20658 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall); 20659 env->Global()->Set(v8_str("recursion"), 20660 recursive_runtime->GetFunction()); 20661 // Adding the same callback a second time has no effect. 20662 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20663 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20664 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); 20665 i::OS::Print("--- Script (1) ---\n"); 20666 Local<Script> script = v8::Script::Compile( 20667 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)")); 20668 script->Run(); 20669 CHECK_EQ(3, callback_fired); 20670 20671 i::OS::Print("\n--- Script (2) ---\n"); 20672 callback_fired = 0; 20673 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); 20674 script->Run(); 20675 CHECK_EQ(2, callback_fired); 20676 20677 i::OS::Print("\n--- Function ---\n"); 20678 callback_fired = 0; 20679 Local<Function> recursive_function = 20680 Local<Function>::Cast(env->Global()->Get(v8_str("recursion"))); 20681 v8::Handle<Value> args[] = { v8_num(0) }; 20682 recursive_function->Call(env->Global(), 1, args); 20683 CHECK_EQ(2, callback_fired); 20684 } 20685 20686 20687 void CallCompletedCallbackNoException() { 20688 v8::HandleScope scope(CcTest::isolate()); 20689 CompileRun("1+1;"); 20690 } 20691 20692 20693 void CallCompletedCallbackException() { 20694 v8::HandleScope scope(CcTest::isolate()); 20695 CompileRun("throw 'second exception';"); 20696 } 20697 20698 20699 TEST(CallCompletedCallbackOneException) { 20700 LocalContext env; 20701 v8::HandleScope scope(env->GetIsolate()); 20702 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException); 20703 CompileRun("throw 'exception';"); 20704 } 20705 20706 20707 TEST(CallCompletedCallbackTwoExceptions) { 20708 LocalContext env; 20709 v8::HandleScope scope(env->GetIsolate()); 20710 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException); 20711 CompileRun("throw 'first exception';"); 20712 } 20713 20714 20715 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) { 20716 v8::HandleScope scope(info.GetIsolate()); 20717 CompileRun("ext1Calls++;"); 20718 } 20719 20720 20721 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) { 20722 v8::HandleScope scope(info.GetIsolate()); 20723 CompileRun("ext2Calls++;"); 20724 } 20725 20726 20727 void* g_passed_to_three = NULL; 20728 20729 20730 static void MicrotaskThree(void* data) { 20731 g_passed_to_three = data; 20732 } 20733 20734 20735 TEST(EnqueueMicrotask) { 20736 LocalContext env; 20737 v8::HandleScope scope(env->GetIsolate()); 20738 CompileRun( 20739 "var ext1Calls = 0;" 20740 "var ext2Calls = 0;"); 20741 CompileRun("1+1;"); 20742 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); 20743 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20744 20745 env->GetIsolate()->EnqueueMicrotask( 20746 Function::New(env->GetIsolate(), MicrotaskOne)); 20747 CompileRun("1+1;"); 20748 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20749 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20750 20751 env->GetIsolate()->EnqueueMicrotask( 20752 Function::New(env->GetIsolate(), MicrotaskOne)); 20753 env->GetIsolate()->EnqueueMicrotask( 20754 Function::New(env->GetIsolate(), MicrotaskTwo)); 20755 CompileRun("1+1;"); 20756 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20757 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20758 20759 env->GetIsolate()->EnqueueMicrotask( 20760 Function::New(env->GetIsolate(), MicrotaskTwo)); 20761 CompileRun("1+1;"); 20762 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20763 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20764 20765 CompileRun("1+1;"); 20766 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20767 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20768 20769 g_passed_to_three = NULL; 20770 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree); 20771 CompileRun("1+1;"); 20772 CHECK_EQ(NULL, g_passed_to_three); 20773 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20774 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20775 20776 int dummy; 20777 env->GetIsolate()->EnqueueMicrotask( 20778 Function::New(env->GetIsolate(), MicrotaskOne)); 20779 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy); 20780 env->GetIsolate()->EnqueueMicrotask( 20781 Function::New(env->GetIsolate(), MicrotaskTwo)); 20782 CompileRun("1+1;"); 20783 CHECK_EQ(&dummy, g_passed_to_three); 20784 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value()); 20785 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20786 g_passed_to_three = NULL; 20787 } 20788 20789 20790 static void MicrotaskExceptionOne( 20791 const v8::FunctionCallbackInfo<Value>& info) { 20792 v8::HandleScope scope(info.GetIsolate()); 20793 CompileRun("exception1Calls++;"); 20794 info.GetIsolate()->ThrowException( 20795 v8::Exception::Error(v8_str("first"))); 20796 } 20797 20798 20799 static void MicrotaskExceptionTwo( 20800 const v8::FunctionCallbackInfo<Value>& info) { 20801 v8::HandleScope scope(info.GetIsolate()); 20802 CompileRun("exception2Calls++;"); 20803 info.GetIsolate()->ThrowException( 20804 v8::Exception::Error(v8_str("second"))); 20805 } 20806 20807 20808 TEST(RunMicrotasksIgnoresThrownExceptions) { 20809 LocalContext env; 20810 v8::Isolate* isolate = env->GetIsolate(); 20811 v8::HandleScope scope(isolate); 20812 CompileRun( 20813 "var exception1Calls = 0;" 20814 "var exception2Calls = 0;"); 20815 isolate->EnqueueMicrotask( 20816 Function::New(isolate, MicrotaskExceptionOne)); 20817 isolate->EnqueueMicrotask( 20818 Function::New(isolate, MicrotaskExceptionTwo)); 20819 TryCatch try_catch; 20820 CompileRun("1+1;"); 20821 CHECK(!try_catch.HasCaught()); 20822 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value()); 20823 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value()); 20824 } 20825 20826 20827 TEST(SetAutorunMicrotasks) { 20828 LocalContext env; 20829 v8::HandleScope scope(env->GetIsolate()); 20830 CompileRun( 20831 "var ext1Calls = 0;" 20832 "var ext2Calls = 0;"); 20833 CompileRun("1+1;"); 20834 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); 20835 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20836 20837 env->GetIsolate()->EnqueueMicrotask( 20838 Function::New(env->GetIsolate(), MicrotaskOne)); 20839 CompileRun("1+1;"); 20840 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20841 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20842 20843 env->GetIsolate()->SetAutorunMicrotasks(false); 20844 env->GetIsolate()->EnqueueMicrotask( 20845 Function::New(env->GetIsolate(), MicrotaskOne)); 20846 env->GetIsolate()->EnqueueMicrotask( 20847 Function::New(env->GetIsolate(), MicrotaskTwo)); 20848 CompileRun("1+1;"); 20849 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20850 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20851 20852 env->GetIsolate()->RunMicrotasks(); 20853 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20854 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20855 20856 env->GetIsolate()->EnqueueMicrotask( 20857 Function::New(env->GetIsolate(), MicrotaskTwo)); 20858 CompileRun("1+1;"); 20859 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20860 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20861 20862 env->GetIsolate()->RunMicrotasks(); 20863 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20864 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20865 20866 env->GetIsolate()->SetAutorunMicrotasks(true); 20867 env->GetIsolate()->EnqueueMicrotask( 20868 Function::New(env->GetIsolate(), MicrotaskTwo)); 20869 CompileRun("1+1;"); 20870 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20871 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20872 20873 env->GetIsolate()->EnqueueMicrotask( 20874 Function::New(env->GetIsolate(), MicrotaskTwo)); 20875 { 20876 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate()); 20877 CompileRun("1+1;"); 20878 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20879 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20880 } 20881 20882 CompileRun("1+1;"); 20883 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20884 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value()); 20885 } 20886 20887 20888 TEST(RunMicrotasksWithoutEnteringContext) { 20889 v8::Isolate* isolate = CcTest::isolate(); 20890 HandleScope handle_scope(isolate); 20891 isolate->SetAutorunMicrotasks(false); 20892 Handle<Context> context = Context::New(isolate); 20893 { 20894 Context::Scope context_scope(context); 20895 CompileRun("var ext1Calls = 0;"); 20896 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne)); 20897 } 20898 isolate->RunMicrotasks(); 20899 { 20900 Context::Scope context_scope(context); 20901 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20902 } 20903 isolate->SetAutorunMicrotasks(true); 20904 } 20905 20906 20907 #ifdef DEBUG 20908 static int probes_counter = 0; 20909 static int misses_counter = 0; 20910 static int updates_counter = 0; 20911 20912 20913 static int* LookupCounter(const char* name) { 20914 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 20915 return &probes_counter; 20916 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 20917 return &misses_counter; 20918 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 20919 return &updates_counter; 20920 } 20921 return NULL; 20922 } 20923 20924 20925 static const char* kMegamorphicTestProgram = 20926 "function ClassA() { };" 20927 "function ClassB() { };" 20928 "ClassA.prototype.foo = function() { };" 20929 "ClassB.prototype.foo = function() { };" 20930 "function fooify(obj) { obj.foo(); };" 20931 "var a = new ClassA();" 20932 "var b = new ClassB();" 20933 "for (var i = 0; i < 10000; i++) {" 20934 " fooify(a);" 20935 " fooify(b);" 20936 "}"; 20937 #endif 20938 20939 20940 static void StubCacheHelper(bool primary) { 20941 #ifdef DEBUG 20942 i::FLAG_native_code_counters = true; 20943 if (primary) { 20944 i::FLAG_test_primary_stub_cache = true; 20945 } else { 20946 i::FLAG_test_secondary_stub_cache = true; 20947 } 20948 i::FLAG_crankshaft = false; 20949 LocalContext env; 20950 env->GetIsolate()->SetCounterFunction(LookupCounter); 20951 v8::HandleScope scope(env->GetIsolate()); 20952 int initial_probes = probes_counter; 20953 int initial_misses = misses_counter; 20954 int initial_updates = updates_counter; 20955 CompileRun(kMegamorphicTestProgram); 20956 int probes = probes_counter - initial_probes; 20957 int misses = misses_counter - initial_misses; 20958 int updates = updates_counter - initial_updates; 20959 CHECK_LT(updates, 10); 20960 CHECK_LT(misses, 10); 20961 // TODO(verwaest): Update this test to overflow the degree of polymorphism 20962 // before megamorphism. The number of probes will only work once we teach the 20963 // serializer to embed references to counters in the stubs, given that the 20964 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub. 20965 CHECK_GE(probes, 0); 20966 #endif 20967 } 20968 20969 20970 TEST(SecondaryStubCache) { 20971 StubCacheHelper(true); 20972 } 20973 20974 20975 TEST(PrimaryStubCache) { 20976 StubCacheHelper(false); 20977 } 20978 20979 20980 #ifdef DEBUG 20981 static int cow_arrays_created_runtime = 0; 20982 20983 20984 static int* LookupCounterCOWArrays(const char* name) { 20985 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) { 20986 return &cow_arrays_created_runtime; 20987 } 20988 return NULL; 20989 } 20990 #endif 20991 20992 20993 TEST(CheckCOWArraysCreatedRuntimeCounter) { 20994 #ifdef DEBUG 20995 i::FLAG_native_code_counters = true; 20996 LocalContext env; 20997 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays); 20998 v8::HandleScope scope(env->GetIsolate()); 20999 int initial_cow_arrays = cow_arrays_created_runtime; 21000 CompileRun("var o = [1, 2, 3];"); 21001 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays); 21002 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};"); 21003 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays); 21004 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};"); 21005 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays); 21006 #endif 21007 } 21008 21009 21010 TEST(StaticGetters) { 21011 LocalContext context; 21012 i::Factory* factory = CcTest::i_isolate()->factory(); 21013 v8::Isolate* isolate = CcTest::isolate(); 21014 v8::HandleScope scope(isolate); 21015 i::Handle<i::Object> undefined_value = factory->undefined_value(); 21016 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 21017 i::Handle<i::Object> null_value = factory->null_value(); 21018 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 21019 i::Handle<i::Object> true_value = factory->true_value(); 21020 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 21021 i::Handle<i::Object> false_value = factory->false_value(); 21022 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 21023 } 21024 21025 21026 UNINITIALIZED_TEST(IsolateEmbedderData) { 21027 CcTest::DisableAutomaticDispose(); 21028 v8::Isolate* isolate = v8::Isolate::New(); 21029 isolate->Enter(); 21030 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 21031 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21032 CHECK_EQ(NULL, isolate->GetData(slot)); 21033 CHECK_EQ(NULL, i_isolate->GetData(slot)); 21034 } 21035 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21036 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21037 isolate->SetData(slot, data); 21038 } 21039 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21040 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21041 CHECK_EQ(data, isolate->GetData(slot)); 21042 CHECK_EQ(data, i_isolate->GetData(slot)); 21043 } 21044 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21045 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21046 isolate->SetData(slot, data); 21047 } 21048 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21049 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21050 CHECK_EQ(data, isolate->GetData(slot)); 21051 CHECK_EQ(data, i_isolate->GetData(slot)); 21052 } 21053 isolate->Exit(); 21054 isolate->Dispose(); 21055 } 21056 21057 21058 TEST(StringEmpty) { 21059 LocalContext context; 21060 i::Factory* factory = CcTest::i_isolate()->factory(); 21061 v8::Isolate* isolate = CcTest::isolate(); 21062 v8::HandleScope scope(isolate); 21063 i::Handle<i::Object> empty_string = factory->empty_string(); 21064 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 21065 } 21066 21067 21068 static int instance_checked_getter_count = 0; 21069 static void InstanceCheckedGetter( 21070 Local<String> name, 21071 const v8::PropertyCallbackInfo<v8::Value>& info) { 21072 CHECK_EQ(name, v8_str("foo")); 21073 instance_checked_getter_count++; 21074 info.GetReturnValue().Set(v8_num(11)); 21075 } 21076 21077 21078 static int instance_checked_setter_count = 0; 21079 static void InstanceCheckedSetter(Local<String> name, 21080 Local<Value> value, 21081 const v8::PropertyCallbackInfo<void>& info) { 21082 CHECK_EQ(name, v8_str("foo")); 21083 CHECK_EQ(value, v8_num(23)); 21084 instance_checked_setter_count++; 21085 } 21086 21087 21088 static void CheckInstanceCheckedResult(int getters, 21089 int setters, 21090 bool expects_callbacks, 21091 TryCatch* try_catch) { 21092 if (expects_callbacks) { 21093 CHECK(!try_catch->HasCaught()); 21094 CHECK_EQ(getters, instance_checked_getter_count); 21095 CHECK_EQ(setters, instance_checked_setter_count); 21096 } else { 21097 CHECK(try_catch->HasCaught()); 21098 CHECK_EQ(0, instance_checked_getter_count); 21099 CHECK_EQ(0, instance_checked_setter_count); 21100 } 21101 try_catch->Reset(); 21102 } 21103 21104 21105 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 21106 instance_checked_getter_count = 0; 21107 instance_checked_setter_count = 0; 21108 TryCatch try_catch; 21109 21110 // Test path through generic runtime code. 21111 CompileRun("obj.foo"); 21112 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 21113 CompileRun("obj.foo = 23"); 21114 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 21115 21116 // Test path through generated LoadIC and StoredIC. 21117 CompileRun("function test_get(o) { o.foo; }" 21118 "test_get(obj);"); 21119 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 21120 CompileRun("test_get(obj);"); 21121 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 21122 CompileRun("test_get(obj);"); 21123 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 21124 CompileRun("function test_set(o) { o.foo = 23; }" 21125 "test_set(obj);"); 21126 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 21127 CompileRun("test_set(obj);"); 21128 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 21129 CompileRun("test_set(obj);"); 21130 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 21131 21132 // Test path through optimized code. 21133 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 21134 "test_get(obj);"); 21135 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 21136 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 21137 "test_set(obj);"); 21138 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 21139 21140 // Cleanup so that closures start out fresh in next check. 21141 CompileRun("%DeoptimizeFunction(test_get);" 21142 "%ClearFunctionTypeFeedback(test_get);" 21143 "%DeoptimizeFunction(test_set);" 21144 "%ClearFunctionTypeFeedback(test_set);"); 21145 } 21146 21147 21148 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 21149 v8::internal::FLAG_allow_natives_syntax = true; 21150 LocalContext context; 21151 v8::HandleScope scope(context->GetIsolate()); 21152 21153 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21154 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21155 inst->SetAccessor(v8_str("foo"), 21156 InstanceCheckedGetter, InstanceCheckedSetter, 21157 Handle<Value>(), 21158 v8::DEFAULT, 21159 v8::None, 21160 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21161 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21162 21163 printf("Testing positive ...\n"); 21164 CompileRun("var obj = new f();"); 21165 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21166 CheckInstanceCheckedAccessors(true); 21167 21168 printf("Testing negative ...\n"); 21169 CompileRun("var obj = {};" 21170 "obj.__proto__ = new f();"); 21171 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21172 CheckInstanceCheckedAccessors(false); 21173 } 21174 21175 21176 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 21177 v8::internal::FLAG_allow_natives_syntax = true; 21178 LocalContext context; 21179 v8::HandleScope scope(context->GetIsolate()); 21180 21181 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21182 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21183 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21184 inst->SetAccessor(v8_str("foo"), 21185 InstanceCheckedGetter, InstanceCheckedSetter, 21186 Handle<Value>(), 21187 v8::DEFAULT, 21188 v8::None, 21189 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21190 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21191 21192 printf("Testing positive ...\n"); 21193 CompileRun("var obj = new f();"); 21194 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21195 CheckInstanceCheckedAccessors(true); 21196 21197 printf("Testing negative ...\n"); 21198 CompileRun("var obj = {};" 21199 "obj.__proto__ = new f();"); 21200 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21201 CheckInstanceCheckedAccessors(false); 21202 } 21203 21204 21205 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 21206 v8::internal::FLAG_allow_natives_syntax = true; 21207 LocalContext context; 21208 v8::HandleScope scope(context->GetIsolate()); 21209 21210 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21211 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 21212 proto->SetAccessor(v8_str("foo"), 21213 InstanceCheckedGetter, InstanceCheckedSetter, 21214 Handle<Value>(), 21215 v8::DEFAULT, 21216 v8::None, 21217 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21218 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21219 21220 printf("Testing positive ...\n"); 21221 CompileRun("var obj = new f();"); 21222 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21223 CheckInstanceCheckedAccessors(true); 21224 21225 printf("Testing negative ...\n"); 21226 CompileRun("var obj = {};" 21227 "obj.__proto__ = new f();"); 21228 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21229 CheckInstanceCheckedAccessors(false); 21230 21231 printf("Testing positive with modified prototype chain ...\n"); 21232 CompileRun("var obj = new f();" 21233 "var pro = {};" 21234 "pro.__proto__ = obj.__proto__;" 21235 "obj.__proto__ = pro;"); 21236 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21237 CheckInstanceCheckedAccessors(true); 21238 } 21239 21240 21241 TEST(TryFinallyMessage) { 21242 LocalContext context; 21243 v8::HandleScope scope(context->GetIsolate()); 21244 { 21245 // Test that the original error message is not lost if there is a 21246 // recursive call into Javascript is done in the finally block, e.g. to 21247 // initialize an IC. (crbug.com/129171) 21248 TryCatch try_catch; 21249 const char* trigger_ic = 21250 "try { \n" 21251 " throw new Error('test'); \n" 21252 "} finally { \n" 21253 " var x = 0; \n" 21254 " x++; \n" // Trigger an IC initialization here. 21255 "} \n"; 21256 CompileRun(trigger_ic); 21257 CHECK(try_catch.HasCaught()); 21258 Local<Message> message = try_catch.Message(); 21259 CHECK(!message.IsEmpty()); 21260 CHECK_EQ(2, message->GetLineNumber()); 21261 } 21262 21263 { 21264 // Test that the original exception message is indeed overwritten if 21265 // a new error is thrown in the finally block. 21266 TryCatch try_catch; 21267 const char* throw_again = 21268 "try { \n" 21269 " throw new Error('test'); \n" 21270 "} finally { \n" 21271 " var x = 0; \n" 21272 " x++; \n" 21273 " throw new Error('again'); \n" // This is the new uncaught error. 21274 "} \n"; 21275 CompileRun(throw_again); 21276 CHECK(try_catch.HasCaught()); 21277 Local<Message> message = try_catch.Message(); 21278 CHECK(!message.IsEmpty()); 21279 CHECK_EQ(6, message->GetLineNumber()); 21280 } 21281 } 21282 21283 21284 static void Helper137002(bool do_store, 21285 bool polymorphic, 21286 bool remove_accessor, 21287 bool interceptor) { 21288 LocalContext context; 21289 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate()); 21290 if (interceptor) { 21291 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor); 21292 } else { 21293 templ->SetAccessor(v8_str("foo"), 21294 GetterWhichReturns42, 21295 SetterWhichSetsYOnThisTo23); 21296 } 21297 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21298 21299 // Turn monomorphic on slow object with native accessor, then turn 21300 // polymorphic, finally optimize to create negative lookup and fail. 21301 CompileRun(do_store ? 21302 "function f(x) { x.foo = void 0; }" : 21303 "function f(x) { return x.foo; }"); 21304 CompileRun("obj.y = void 0;"); 21305 if (!interceptor) { 21306 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 21307 } 21308 CompileRun("obj.__proto__ = null;" 21309 "f(obj); f(obj); f(obj);"); 21310 if (polymorphic) { 21311 CompileRun("f({});"); 21312 } 21313 CompileRun("obj.y = void 0;" 21314 "%OptimizeFunctionOnNextCall(f);"); 21315 if (remove_accessor) { 21316 CompileRun("delete obj.foo;"); 21317 } 21318 CompileRun("var result = f(obj);"); 21319 if (do_store) { 21320 CompileRun("result = obj.y;"); 21321 } 21322 if (remove_accessor && !interceptor) { 21323 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); 21324 } else { 21325 CHECK_EQ(do_store ? 23 : 42, 21326 context->Global()->Get(v8_str("result"))->Int32Value()); 21327 } 21328 } 21329 21330 21331 THREADED_TEST(Regress137002a) { 21332 i::FLAG_allow_natives_syntax = true; 21333 i::FLAG_compilation_cache = false; 21334 v8::HandleScope scope(CcTest::isolate()); 21335 for (int i = 0; i < 16; i++) { 21336 Helper137002(i & 8, i & 4, i & 2, i & 1); 21337 } 21338 } 21339 21340 21341 THREADED_TEST(Regress137002b) { 21342 i::FLAG_allow_natives_syntax = true; 21343 LocalContext context; 21344 v8::Isolate* isolate = context->GetIsolate(); 21345 v8::HandleScope scope(isolate); 21346 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21347 templ->SetAccessor(v8_str("foo"), 21348 GetterWhichReturns42, 21349 SetterWhichSetsYOnThisTo23); 21350 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21351 21352 // Turn monomorphic on slow object with native accessor, then just 21353 // delete the property and fail. 21354 CompileRun("function load(x) { return x.foo; }" 21355 "function store(x) { x.foo = void 0; }" 21356 "function keyed_load(x, key) { return x[key]; }" 21357 // Second version of function has a different source (add void 0) 21358 // so that it does not share code with the first version. This 21359 // ensures that the ICs are monomorphic. 21360 "function load2(x) { void 0; return x.foo; }" 21361 "function store2(x) { void 0; x.foo = void 0; }" 21362 "function keyed_load2(x, key) { void 0; return x[key]; }" 21363 21364 "obj.y = void 0;" 21365 "obj.__proto__ = null;" 21366 "var subobj = {};" 21367 "subobj.y = void 0;" 21368 "subobj.__proto__ = obj;" 21369 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21370 21371 // Make the ICs monomorphic. 21372 "load(obj); load(obj);" 21373 "load2(subobj); load2(subobj);" 21374 "store(obj); store(obj);" 21375 "store2(subobj); store2(subobj);" 21376 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 21377 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 21378 21379 // Actually test the shiny new ICs and better not crash. This 21380 // serves as a regression test for issue 142088 as well. 21381 "load(obj);" 21382 "load2(subobj);" 21383 "store(obj);" 21384 "store2(subobj);" 21385 "keyed_load(obj, 'foo');" 21386 "keyed_load2(subobj, 'foo');" 21387 21388 // Delete the accessor. It better not be called any more now. 21389 "delete obj.foo;" 21390 "obj.y = void 0;" 21391 "subobj.y = void 0;" 21392 21393 "var load_result = load(obj);" 21394 "var load_result2 = load2(subobj);" 21395 "var keyed_load_result = keyed_load(obj, 'foo');" 21396 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 21397 "store(obj);" 21398 "store2(subobj);" 21399 "var y_from_obj = obj.y;" 21400 "var y_from_subobj = subobj.y;"); 21401 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); 21402 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); 21403 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); 21404 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); 21405 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); 21406 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); 21407 } 21408 21409 21410 THREADED_TEST(Regress142088) { 21411 i::FLAG_allow_natives_syntax = true; 21412 LocalContext context; 21413 v8::Isolate* isolate = context->GetIsolate(); 21414 v8::HandleScope scope(isolate); 21415 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21416 templ->SetAccessor(v8_str("foo"), 21417 GetterWhichReturns42, 21418 SetterWhichSetsYOnThisTo23); 21419 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21420 21421 CompileRun("function load(x) { return x.foo; }" 21422 "var o = Object.create(obj);" 21423 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21424 "load(o); load(o); load(o); load(o);"); 21425 } 21426 21427 21428 THREADED_TEST(Regress3337) { 21429 LocalContext context; 21430 v8::Isolate* isolate = context->GetIsolate(); 21431 v8::HandleScope scope(isolate); 21432 Local<v8::Object> o1 = Object::New(isolate); 21433 Local<v8::Object> o2 = Object::New(isolate); 21434 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1); 21435 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2); 21436 CHECK(io1->map() == io2->map()); 21437 o1->SetIndexedPropertiesToExternalArrayData( 21438 NULL, v8::kExternalUint32Array, 0); 21439 o2->SetIndexedPropertiesToExternalArrayData( 21440 NULL, v8::kExternalUint32Array, 0); 21441 CHECK(io1->map() == io2->map()); 21442 } 21443 21444 21445 THREADED_TEST(Regress137496) { 21446 i::FLAG_expose_gc = true; 21447 LocalContext context; 21448 v8::HandleScope scope(context->GetIsolate()); 21449 21450 // Compile a try-finally clause where the finally block causes a GC 21451 // while there still is a message pending for external reporting. 21452 TryCatch try_catch; 21453 try_catch.SetVerbose(true); 21454 CompileRun("try { throw new Error(); } finally { gc(); }"); 21455 CHECK(try_catch.HasCaught()); 21456 } 21457 21458 21459 THREADED_TEST(Regress149912) { 21460 LocalContext context; 21461 v8::HandleScope scope(context->GetIsolate()); 21462 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21463 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21464 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 21465 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();"); 21466 } 21467 21468 21469 THREADED_TEST(Regress157124) { 21470 LocalContext context; 21471 v8::Isolate* isolate = context->GetIsolate(); 21472 v8::HandleScope scope(isolate); 21473 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21474 Local<Object> obj = templ->NewInstance(); 21475 obj->GetIdentityHash(); 21476 obj->DeleteHiddenValue(v8_str("Bug")); 21477 } 21478 21479 21480 THREADED_TEST(Regress2535) { 21481 i::FLAG_harmony_collections = true; 21482 i::FLAG_harmony_symbols = true; 21483 LocalContext context; 21484 v8::HandleScope scope(context->GetIsolate()); 21485 Local<Value> set_value = CompileRun("new Set();"); 21486 Local<Object> set_object(Local<Object>::Cast(set_value)); 21487 CHECK_EQ(0, set_object->InternalFieldCount()); 21488 Local<Value> map_value = CompileRun("new Map();"); 21489 Local<Object> map_object(Local<Object>::Cast(map_value)); 21490 CHECK_EQ(0, map_object->InternalFieldCount()); 21491 } 21492 21493 21494 THREADED_TEST(Regress2746) { 21495 LocalContext context; 21496 v8::Isolate* isolate = context->GetIsolate(); 21497 v8::HandleScope scope(isolate); 21498 Local<Object> obj = Object::New(isolate); 21499 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key"); 21500 obj->SetHiddenValue(key, v8::Undefined(isolate)); 21501 Local<Value> value = obj->GetHiddenValue(key); 21502 CHECK(!value.IsEmpty()); 21503 CHECK(value->IsUndefined()); 21504 } 21505 21506 21507 THREADED_TEST(Regress260106) { 21508 LocalContext context; 21509 v8::Isolate* isolate = context->GetIsolate(); 21510 v8::HandleScope scope(isolate); 21511 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, 21512 DummyCallHandler); 21513 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 21514 Local<Function> function = templ->GetFunction(); 21515 CHECK(!function.IsEmpty()); 21516 CHECK(function->IsFunction()); 21517 } 21518 21519 21520 THREADED_TEST(JSONParseObject) { 21521 LocalContext context; 21522 HandleScope scope(context->GetIsolate()); 21523 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}")); 21524 Handle<Object> global = context->Global(); 21525 global->Set(v8_str("obj"), obj); 21526 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 21527 } 21528 21529 21530 THREADED_TEST(JSONParseNumber) { 21531 LocalContext context; 21532 HandleScope scope(context->GetIsolate()); 21533 Local<Value> obj = v8::JSON::Parse(v8_str("42")); 21534 Handle<Object> global = context->Global(); 21535 global->Set(v8_str("obj"), obj); 21536 ExpectString("JSON.stringify(obj)", "42"); 21537 } 21538 21539 21540 #if V8_OS_POSIX 21541 class ThreadInterruptTest { 21542 public: 21543 ThreadInterruptTest() : sem_(0), sem_value_(0) { } 21544 ~ThreadInterruptTest() {} 21545 21546 void RunTest() { 21547 InterruptThread i_thread(this); 21548 i_thread.Start(); 21549 21550 sem_.Wait(); 21551 CHECK_EQ(kExpectedValue, sem_value_); 21552 } 21553 21554 private: 21555 static const int kExpectedValue = 1; 21556 21557 class InterruptThread : public i::Thread { 21558 public: 21559 explicit InterruptThread(ThreadInterruptTest* test) 21560 : Thread("InterruptThread"), test_(test) {} 21561 21562 virtual void Run() { 21563 struct sigaction action; 21564 21565 // Ensure that we'll enter waiting condition 21566 i::OS::Sleep(100); 21567 21568 // Setup signal handler 21569 memset(&action, 0, sizeof(action)); 21570 action.sa_handler = SignalHandler; 21571 sigaction(SIGCHLD, &action, NULL); 21572 21573 // Send signal 21574 kill(getpid(), SIGCHLD); 21575 21576 // Ensure that if wait has returned because of error 21577 i::OS::Sleep(100); 21578 21579 // Set value and signal semaphore 21580 test_->sem_value_ = 1; 21581 test_->sem_.Signal(); 21582 } 21583 21584 static void SignalHandler(int signal) { 21585 } 21586 21587 private: 21588 ThreadInterruptTest* test_; 21589 }; 21590 21591 i::Semaphore sem_; 21592 volatile int sem_value_; 21593 }; 21594 21595 21596 THREADED_TEST(SemaphoreInterruption) { 21597 ThreadInterruptTest().RunTest(); 21598 } 21599 21600 21601 #endif // V8_OS_POSIX 21602 21603 21604 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global, 21605 Local<Value> name, 21606 v8::AccessType type, 21607 Local<Value> data) { 21608 i::PrintF("Named access blocked.\n"); 21609 return false; 21610 } 21611 21612 21613 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global, 21614 uint32_t key, 21615 v8::AccessType type, 21616 Local<Value> data) { 21617 i::PrintF("Indexed access blocked.\n"); 21618 return false; 21619 } 21620 21621 21622 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21623 CHECK(false); 21624 } 21625 21626 21627 TEST(JSONStringifyAccessCheck) { 21628 v8::V8::Initialize(); 21629 v8::Isolate* isolate = CcTest::isolate(); 21630 v8::HandleScope scope(isolate); 21631 21632 // Create an ObjectTemplate for global objects and install access 21633 // check callbacks that will block access. 21634 v8::Handle<v8::ObjectTemplate> global_template = 21635 v8::ObjectTemplate::New(isolate); 21636 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 21637 IndexAccessAlwaysBlocked); 21638 21639 // Create a context and set an x property on it's global object. 21640 LocalContext context0(NULL, global_template); 21641 v8::Handle<v8::Object> global0 = context0->Global(); 21642 global0->Set(v8_str("x"), v8_num(42)); 21643 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 21644 21645 for (int i = 0; i < 2; i++) { 21646 if (i == 1) { 21647 // Install a toJSON function on the second run. 21648 v8::Handle<v8::FunctionTemplate> toJSON = 21649 v8::FunctionTemplate::New(isolate, UnreachableCallback); 21650 21651 global0->Set(v8_str("toJSON"), toJSON->GetFunction()); 21652 } 21653 // Create a context with a different security token so that the 21654 // failed access check callback will be called on each access. 21655 LocalContext context1(NULL, global_template); 21656 context1->Global()->Set(v8_str("other"), global0); 21657 21658 ExpectString("JSON.stringify(other)", "{}"); 21659 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })", 21660 "{\"a\":{},\"b\":[\"c\"]}"); 21661 ExpectString("JSON.stringify([other, 'b', 'c'])", 21662 "[{},\"b\",\"c\"]"); 21663 21664 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2); 21665 array->Set(0, v8_str("a")); 21666 array->Set(1, v8_str("b")); 21667 context1->Global()->Set(v8_str("array"), array); 21668 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); 21669 array->TurnOnAccessCheck(); 21670 ExpectString("JSON.stringify(array)", "[]"); 21671 ExpectString("JSON.stringify([array])", "[[]]"); 21672 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}"); 21673 } 21674 } 21675 21676 21677 bool access_check_fail_thrown = false; 21678 bool catch_callback_called = false; 21679 21680 21681 // Failed access check callback that performs a GC on each invocation. 21682 void FailedAccessCheckThrows(Local<v8::Object> target, 21683 v8::AccessType type, 21684 Local<v8::Value> data) { 21685 access_check_fail_thrown = true; 21686 i::PrintF("Access check failed. Error thrown.\n"); 21687 CcTest::isolate()->ThrowException( 21688 v8::Exception::Error(v8_str("cross context"))); 21689 } 21690 21691 21692 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21693 for (int i = 0; i < args.Length(); i++) { 21694 i::PrintF("%s\n", *String::Utf8Value(args[i])); 21695 } 21696 catch_callback_called = true; 21697 } 21698 21699 21700 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21701 args[0]->ToObject()->HasOwnProperty(args[1]->ToString()); 21702 } 21703 21704 21705 void CheckCorrectThrow(const char* script) { 21706 // Test that the script, when wrapped into a try-catch, triggers the catch 21707 // clause due to failed access check throwing an exception. 21708 // The subsequent try-catch should run without any exception. 21709 access_check_fail_thrown = false; 21710 catch_callback_called = false; 21711 i::ScopedVector<char> source(1024); 21712 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 21713 CompileRun(source.start()); 21714 CHECK(access_check_fail_thrown); 21715 CHECK(catch_callback_called); 21716 21717 access_check_fail_thrown = false; 21718 catch_callback_called = false; 21719 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 21720 CHECK(!access_check_fail_thrown); 21721 CHECK(!catch_callback_called); 21722 } 21723 21724 21725 TEST(AccessCheckThrows) { 21726 i::FLAG_allow_natives_syntax = true; 21727 v8::V8::Initialize(); 21728 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 21729 v8::Isolate* isolate = CcTest::isolate(); 21730 v8::HandleScope scope(isolate); 21731 21732 // Create an ObjectTemplate for global objects and install access 21733 // check callbacks that will block access. 21734 v8::Handle<v8::ObjectTemplate> global_template = 21735 v8::ObjectTemplate::New(isolate); 21736 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 21737 IndexAccessAlwaysBlocked); 21738 21739 // Create a context and set an x property on it's global object. 21740 LocalContext context0(NULL, global_template); 21741 context0->Global()->Set(v8_str("x"), v8_num(42)); 21742 v8::Handle<v8::Object> global0 = context0->Global(); 21743 21744 // Create a context with a different security token so that the 21745 // failed access check callback will be called on each access. 21746 LocalContext context1(NULL, global_template); 21747 context1->Global()->Set(v8_str("other"), global0); 21748 21749 v8::Handle<v8::FunctionTemplate> catcher_fun = 21750 v8::FunctionTemplate::New(isolate, CatcherCallback); 21751 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction()); 21752 21753 v8::Handle<v8::FunctionTemplate> has_own_property_fun = 21754 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback); 21755 context1->Global()->Set(v8_str("has_own_property"), 21756 has_own_property_fun->GetFunction()); 21757 21758 { v8::TryCatch try_catch; 21759 access_check_fail_thrown = false; 21760 CompileRun("other.x;"); 21761 CHECK(access_check_fail_thrown); 21762 CHECK(try_catch.HasCaught()); 21763 } 21764 21765 CheckCorrectThrow("other.x"); 21766 CheckCorrectThrow("other[1]"); 21767 CheckCorrectThrow("JSON.stringify(other)"); 21768 CheckCorrectThrow("has_own_property(other, 'x')"); 21769 CheckCorrectThrow("%GetProperty(other, 'x')"); 21770 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)"); 21771 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')"); 21772 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); 21773 CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); 21774 CheckCorrectThrow("%HasOwnProperty(other, 'x')"); 21775 CheckCorrectThrow("%HasProperty(other, 'x')"); 21776 CheckCorrectThrow("%HasElement(other, 1)"); 21777 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); 21778 CheckCorrectThrow("%GetPropertyNames(other)"); 21779 // PROPERTY_ATTRIBUTES_NONE = 0 21780 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)"); 21781 CheckCorrectThrow("%DefineOrRedefineAccessorProperty(" 21782 "other, 'x', null, null, 1)"); 21783 21784 // Reset the failed access check callback so it does not influence 21785 // the other tests. 21786 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 21787 } 21788 21789 21790 THREADED_TEST(Regress256330) { 21791 i::FLAG_allow_natives_syntax = true; 21792 LocalContext context; 21793 v8::HandleScope scope(context->GetIsolate()); 21794 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21795 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21796 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 21797 CompileRun("\"use strict\"; var o = new Bug;" 21798 "function f(o) { o.x = 10; };" 21799 "f(o); f(o); f(o);" 21800 "%OptimizeFunctionOnNextCall(f);" 21801 "f(o);"); 21802 ExpectBoolean("%GetOptimizationStatus(f) != 2", true); 21803 } 21804 21805 21806 THREADED_TEST(CrankshaftInterceptorSetter) { 21807 i::FLAG_allow_natives_syntax = true; 21808 v8::HandleScope scope(CcTest::isolate()); 21809 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21810 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21811 LocalContext env; 21812 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21813 CompileRun("var obj = new Obj;" 21814 // Initialize fields to avoid transitions later. 21815 "obj.age = 0;" 21816 "obj.accessor_age = 42;" 21817 "function setter(i) { this.accessor_age = i; };" 21818 "function getter() { return this.accessor_age; };" 21819 "function setAge(i) { obj.age = i; };" 21820 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 21821 "setAge(1);" 21822 "setAge(2);" 21823 "setAge(3);" 21824 "%OptimizeFunctionOnNextCall(setAge);" 21825 "setAge(4);"); 21826 // All stores went through the interceptor. 21827 ExpectInt32("obj.interceptor_age", 4); 21828 ExpectInt32("obj.accessor_age", 42); 21829 } 21830 21831 21832 THREADED_TEST(CrankshaftInterceptorGetter) { 21833 i::FLAG_allow_natives_syntax = true; 21834 v8::HandleScope scope(CcTest::isolate()); 21835 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21836 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21837 LocalContext env; 21838 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21839 CompileRun("var obj = new Obj;" 21840 // Initialize fields to avoid transitions later. 21841 "obj.age = 1;" 21842 "obj.accessor_age = 42;" 21843 "function getter() { return this.accessor_age; };" 21844 "function getAge() { return obj.interceptor_age; };" 21845 "Object.defineProperty(obj, 'interceptor_age', { get:getter });" 21846 "getAge();" 21847 "getAge();" 21848 "getAge();" 21849 "%OptimizeFunctionOnNextCall(getAge);"); 21850 // Access through interceptor. 21851 ExpectInt32("getAge()", 1); 21852 } 21853 21854 21855 THREADED_TEST(CrankshaftInterceptorFieldRead) { 21856 i::FLAG_allow_natives_syntax = true; 21857 v8::HandleScope scope(CcTest::isolate()); 21858 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21859 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21860 LocalContext env; 21861 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21862 CompileRun("var obj = new Obj;" 21863 "obj.__proto__.interceptor_age = 42;" 21864 "obj.age = 100;" 21865 "function getAge() { return obj.interceptor_age; };"); 21866 ExpectInt32("getAge();", 100); 21867 ExpectInt32("getAge();", 100); 21868 ExpectInt32("getAge();", 100); 21869 CompileRun("%OptimizeFunctionOnNextCall(getAge);"); 21870 // Access through interceptor. 21871 ExpectInt32("getAge();", 100); 21872 } 21873 21874 21875 THREADED_TEST(CrankshaftInterceptorFieldWrite) { 21876 i::FLAG_allow_natives_syntax = true; 21877 v8::HandleScope scope(CcTest::isolate()); 21878 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21879 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21880 LocalContext env; 21881 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21882 CompileRun("var obj = new Obj;" 21883 "obj.age = 100000;" 21884 "function setAge(i) { obj.age = i };" 21885 "setAge(100);" 21886 "setAge(101);" 21887 "setAge(102);" 21888 "%OptimizeFunctionOnNextCall(setAge);" 21889 "setAge(103);"); 21890 ExpectInt32("obj.age", 100000); 21891 ExpectInt32("obj.interceptor_age", 103); 21892 } 21893 21894 21895 class RequestInterruptTestBase { 21896 public: 21897 RequestInterruptTestBase() 21898 : env_(), 21899 isolate_(env_->GetIsolate()), 21900 sem_(0), 21901 warmup_(20000), 21902 should_continue_(true) { 21903 } 21904 21905 virtual ~RequestInterruptTestBase() { } 21906 21907 virtual void StartInterruptThread() = 0; 21908 21909 virtual void TestBody() = 0; 21910 21911 void RunTest() { 21912 StartInterruptThread(); 21913 21914 v8::HandleScope handle_scope(isolate_); 21915 21916 TestBody(); 21917 21918 isolate_->ClearInterrupt(); 21919 21920 // Verify we arrived here because interruptor was called 21921 // not due to a bug causing us to exit the loop too early. 21922 CHECK(!should_continue()); 21923 } 21924 21925 void WakeUpInterruptor() { 21926 sem_.Signal(); 21927 } 21928 21929 bool should_continue() const { return should_continue_; } 21930 21931 bool ShouldContinue() { 21932 if (warmup_ > 0) { 21933 if (--warmup_ == 0) { 21934 WakeUpInterruptor(); 21935 } 21936 } 21937 21938 return should_continue_; 21939 } 21940 21941 static void ShouldContinueCallback( 21942 const v8::FunctionCallbackInfo<Value>& info) { 21943 RequestInterruptTestBase* test = 21944 reinterpret_cast<RequestInterruptTestBase*>( 21945 info.Data().As<v8::External>()->Value()); 21946 info.GetReturnValue().Set(test->ShouldContinue()); 21947 } 21948 21949 LocalContext env_; 21950 v8::Isolate* isolate_; 21951 i::Semaphore sem_; 21952 int warmup_; 21953 bool should_continue_; 21954 }; 21955 21956 21957 class RequestInterruptTestBaseWithSimpleInterrupt 21958 : public RequestInterruptTestBase { 21959 public: 21960 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { } 21961 21962 virtual void StartInterruptThread() { 21963 i_thread.Start(); 21964 } 21965 21966 private: 21967 class InterruptThread : public i::Thread { 21968 public: 21969 explicit InterruptThread(RequestInterruptTestBase* test) 21970 : Thread("RequestInterruptTest"), test_(test) {} 21971 21972 virtual void Run() { 21973 test_->sem_.Wait(); 21974 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 21975 } 21976 21977 static void OnInterrupt(v8::Isolate* isolate, void* data) { 21978 reinterpret_cast<RequestInterruptTestBase*>(data)-> 21979 should_continue_ = false; 21980 } 21981 21982 private: 21983 RequestInterruptTestBase* test_; 21984 }; 21985 21986 InterruptThread i_thread; 21987 }; 21988 21989 21990 class RequestInterruptTestWithFunctionCall 21991 : public RequestInterruptTestBaseWithSimpleInterrupt { 21992 public: 21993 virtual void TestBody() { 21994 Local<Function> func = Function::New( 21995 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); 21996 env_->Global()->Set(v8_str("ShouldContinue"), func); 21997 21998 CompileRun("while (ShouldContinue()) { }"); 21999 } 22000 }; 22001 22002 22003 class RequestInterruptTestWithMethodCall 22004 : public RequestInterruptTestBaseWithSimpleInterrupt { 22005 public: 22006 virtual void TestBody() { 22007 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22008 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22009 proto->Set(v8_str("shouldContinue"), Function::New( 22010 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22011 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22012 22013 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22014 } 22015 }; 22016 22017 22018 class RequestInterruptTestWithAccessor 22019 : public RequestInterruptTestBaseWithSimpleInterrupt { 22020 public: 22021 virtual void TestBody() { 22022 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22023 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22024 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New( 22025 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22026 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22027 22028 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22029 } 22030 }; 22031 22032 22033 class RequestInterruptTestWithNativeAccessor 22034 : public RequestInterruptTestBaseWithSimpleInterrupt { 22035 public: 22036 virtual void TestBody() { 22037 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22038 t->InstanceTemplate()->SetNativeDataProperty( 22039 v8_str("shouldContinue"), 22040 &ShouldContinueNativeGetter, 22041 NULL, 22042 v8::External::New(isolate_, this)); 22043 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22044 22045 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22046 } 22047 22048 private: 22049 static void ShouldContinueNativeGetter( 22050 Local<String> property, 22051 const v8::PropertyCallbackInfo<v8::Value>& info) { 22052 RequestInterruptTestBase* test = 22053 reinterpret_cast<RequestInterruptTestBase*>( 22054 info.Data().As<v8::External>()->Value()); 22055 info.GetReturnValue().Set(test->ShouldContinue()); 22056 } 22057 }; 22058 22059 22060 class RequestInterruptTestWithMethodCallAndInterceptor 22061 : public RequestInterruptTestBaseWithSimpleInterrupt { 22062 public: 22063 virtual void TestBody() { 22064 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22065 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22066 proto->Set(v8_str("shouldContinue"), Function::New( 22067 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22068 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate(); 22069 instance_template->SetNamedPropertyHandler(EmptyInterceptor); 22070 22071 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22072 22073 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22074 } 22075 22076 private: 22077 static void EmptyInterceptor( 22078 Local<String> property, 22079 const v8::PropertyCallbackInfo<v8::Value>& info) { 22080 } 22081 }; 22082 22083 22084 class RequestInterruptTestWithMathAbs 22085 : public RequestInterruptTestBaseWithSimpleInterrupt { 22086 public: 22087 virtual void TestBody() { 22088 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New( 22089 isolate_, 22090 WakeUpInterruptorCallback, 22091 v8::External::New(isolate_, this))); 22092 22093 env_->Global()->Set(v8_str("ShouldContinue"), Function::New( 22094 isolate_, 22095 ShouldContinueCallback, 22096 v8::External::New(isolate_, this))); 22097 22098 i::FLAG_allow_natives_syntax = true; 22099 CompileRun("function loopish(o) {" 22100 " var pre = 10;" 22101 " while (o.abs(1) > 0) {" 22102 " if (o.abs(1) >= 0 && !ShouldContinue()) break;" 22103 " if (pre > 0) {" 22104 " if (--pre === 0) WakeUpInterruptor(o === Math);" 22105 " }" 22106 " }" 22107 "}" 22108 "var i = 50;" 22109 "var obj = {abs: function () { return i-- }, x: null};" 22110 "delete obj.x;" 22111 "loopish(obj);" 22112 "%OptimizeFunctionOnNextCall(loopish);" 22113 "loopish(Math);"); 22114 22115 i::FLAG_allow_natives_syntax = false; 22116 } 22117 22118 private: 22119 static void WakeUpInterruptorCallback( 22120 const v8::FunctionCallbackInfo<Value>& info) { 22121 if (!info[0]->BooleanValue()) return; 22122 22123 RequestInterruptTestBase* test = 22124 reinterpret_cast<RequestInterruptTestBase*>( 22125 info.Data().As<v8::External>()->Value()); 22126 test->WakeUpInterruptor(); 22127 } 22128 22129 static void ShouldContinueCallback( 22130 const v8::FunctionCallbackInfo<Value>& info) { 22131 RequestInterruptTestBase* test = 22132 reinterpret_cast<RequestInterruptTestBase*>( 22133 info.Data().As<v8::External>()->Value()); 22134 info.GetReturnValue().Set(test->should_continue()); 22135 } 22136 }; 22137 22138 22139 TEST(RequestInterruptTestWithFunctionCall) { 22140 RequestInterruptTestWithFunctionCall().RunTest(); 22141 } 22142 22143 22144 TEST(RequestInterruptTestWithMethodCall) { 22145 RequestInterruptTestWithMethodCall().RunTest(); 22146 } 22147 22148 22149 TEST(RequestInterruptTestWithAccessor) { 22150 RequestInterruptTestWithAccessor().RunTest(); 22151 } 22152 22153 22154 TEST(RequestInterruptTestWithNativeAccessor) { 22155 RequestInterruptTestWithNativeAccessor().RunTest(); 22156 } 22157 22158 22159 TEST(RequestInterruptTestWithMethodCallAndInterceptor) { 22160 RequestInterruptTestWithMethodCallAndInterceptor().RunTest(); 22161 } 22162 22163 22164 TEST(RequestInterruptTestWithMathAbs) { 22165 RequestInterruptTestWithMathAbs().RunTest(); 22166 } 22167 22168 22169 class ClearInterruptFromAnotherThread 22170 : public RequestInterruptTestBase { 22171 public: 22172 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { } 22173 22174 virtual void StartInterruptThread() { 22175 i_thread.Start(); 22176 } 22177 22178 virtual void TestBody() { 22179 Local<Function> func = Function::New( 22180 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); 22181 env_->Global()->Set(v8_str("ShouldContinue"), func); 22182 22183 CompileRun("while (ShouldContinue()) { }"); 22184 } 22185 22186 private: 22187 class InterruptThread : public i::Thread { 22188 public: 22189 explicit InterruptThread(ClearInterruptFromAnotherThread* test) 22190 : Thread("RequestInterruptTest"), test_(test) {} 22191 22192 virtual void Run() { 22193 test_->sem_.Wait(); 22194 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 22195 test_->sem_.Wait(); 22196 test_->isolate_->ClearInterrupt(); 22197 test_->sem2_.Signal(); 22198 } 22199 22200 static void OnInterrupt(v8::Isolate* isolate, void* data) { 22201 ClearInterruptFromAnotherThread* test = 22202 reinterpret_cast<ClearInterruptFromAnotherThread*>(data); 22203 test->sem_.Signal(); 22204 bool success = test->sem2_.WaitFor(i::TimeDelta::FromSeconds(2)); 22205 // Crash instead of timeout to make this failure more prominent. 22206 CHECK(success); 22207 test->should_continue_ = false; 22208 } 22209 22210 private: 22211 ClearInterruptFromAnotherThread* test_; 22212 }; 22213 22214 InterruptThread i_thread; 22215 i::Semaphore sem2_; 22216 }; 22217 22218 22219 TEST(ClearInterruptFromAnotherThread) { 22220 ClearInterruptFromAnotherThread().RunTest(); 22221 } 22222 22223 22224 static Local<Value> function_new_expected_env; 22225 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { 22226 CHECK_EQ(function_new_expected_env, info.Data()); 22227 info.GetReturnValue().Set(17); 22228 } 22229 22230 22231 THREADED_TEST(FunctionNew) { 22232 LocalContext env; 22233 v8::Isolate* isolate = env->GetIsolate(); 22234 v8::HandleScope scope(isolate); 22235 Local<Object> data = v8::Object::New(isolate); 22236 function_new_expected_env = data; 22237 Local<Function> func = Function::New(isolate, FunctionNewCallback, data); 22238 env->Global()->Set(v8_str("func"), func); 22239 Local<Value> result = CompileRun("func();"); 22240 CHECK_EQ(v8::Integer::New(isolate, 17), result); 22241 // Verify function not cached 22242 int serial_number = 22243 i::Smi::cast(v8::Utils::OpenHandle(*func) 22244 ->shared()->get_api_func_data()->serial_number())->value(); 22245 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 22246 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache()); 22247 i::Handle<i::Object> elm = 22248 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked(); 22249 CHECK(elm->IsUndefined()); 22250 // Verify that each Function::New creates a new function instance 22251 Local<Object> data2 = v8::Object::New(isolate); 22252 function_new_expected_env = data2; 22253 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2); 22254 CHECK(!func2->IsNull()); 22255 CHECK_NE(func, func2); 22256 env->Global()->Set(v8_str("func2"), func2); 22257 Local<Value> result2 = CompileRun("func2();"); 22258 CHECK_EQ(v8::Integer::New(isolate, 17), result2); 22259 } 22260 22261 22262 TEST(EscapeableHandleScope) { 22263 HandleScope outer_scope(CcTest::isolate()); 22264 LocalContext context; 22265 const int runs = 10; 22266 Local<String> values[runs]; 22267 for (int i = 0; i < runs; i++) { 22268 v8::EscapableHandleScope inner_scope(CcTest::isolate()); 22269 Local<String> value; 22270 if (i != 0) value = v8_str("escape value"); 22271 values[i] = inner_scope.Escape(value); 22272 } 22273 for (int i = 0; i < runs; i++) { 22274 Local<String> expected; 22275 if (i != 0) { 22276 CHECK_EQ(v8_str("escape value"), values[i]); 22277 } else { 22278 CHECK(values[i].IsEmpty()); 22279 } 22280 } 22281 } 22282 22283 22284 static void SetterWhichExpectsThisAndHolderToDiffer( 22285 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) { 22286 CHECK(info.Holder() != info.This()); 22287 } 22288 22289 22290 TEST(Regress239669) { 22291 LocalContext context; 22292 v8::Isolate* isolate = context->GetIsolate(); 22293 v8::HandleScope scope(isolate); 22294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22295 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer); 22296 context->Global()->Set(v8_str("P"), templ->NewInstance()); 22297 CompileRun( 22298 "function C1() {" 22299 " this.x = 23;" 22300 "};" 22301 "C1.prototype = P;" 22302 "for (var i = 0; i < 4; i++ ) {" 22303 " new C1();" 22304 "}"); 22305 } 22306 22307 22308 class ApiCallOptimizationChecker { 22309 private: 22310 static Local<Object> data; 22311 static Local<Object> receiver; 22312 static Local<Object> holder; 22313 static Local<Object> callee; 22314 static int count; 22315 22316 static void OptimizationCallback( 22317 const v8::FunctionCallbackInfo<v8::Value>& info) { 22318 CHECK(callee == info.Callee()); 22319 CHECK(data == info.Data()); 22320 CHECK(receiver == info.This()); 22321 if (info.Length() == 1) { 22322 CHECK_EQ(v8_num(1), info[0]); 22323 } 22324 CHECK(holder == info.Holder()); 22325 count++; 22326 info.GetReturnValue().Set(v8_str("returned")); 22327 } 22328 22329 public: 22330 enum SignatureType { 22331 kNoSignature, 22332 kSignatureOnReceiver, 22333 kSignatureOnPrototype 22334 }; 22335 22336 void RunAll() { 22337 SignatureType signature_types[] = 22338 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; 22339 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) { 22340 SignatureType signature_type = signature_types[i]; 22341 for (int j = 0; j < 2; j++) { 22342 bool global = j == 0; 22343 int key = signature_type + 22344 ARRAY_SIZE(signature_types) * (global ? 1 : 0); 22345 Run(signature_type, global, key); 22346 } 22347 } 22348 } 22349 22350 void Run(SignatureType signature_type, bool global, int key) { 22351 v8::Isolate* isolate = CcTest::isolate(); 22352 v8::HandleScope scope(isolate); 22353 // Build a template for signature checks. 22354 Local<v8::ObjectTemplate> signature_template; 22355 Local<v8::Signature> signature; 22356 { 22357 Local<v8::FunctionTemplate> parent_template = 22358 FunctionTemplate::New(isolate); 22359 parent_template->SetHiddenPrototype(true); 22360 Local<v8::FunctionTemplate> function_template 22361 = FunctionTemplate::New(isolate); 22362 function_template->Inherit(parent_template); 22363 switch (signature_type) { 22364 case kNoSignature: 22365 break; 22366 case kSignatureOnReceiver: 22367 signature = v8::Signature::New(isolate, function_template); 22368 break; 22369 case kSignatureOnPrototype: 22370 signature = v8::Signature::New(isolate, parent_template); 22371 break; 22372 } 22373 signature_template = function_template->InstanceTemplate(); 22374 } 22375 // Global object must pass checks. 22376 Local<v8::Context> context = 22377 v8::Context::New(isolate, NULL, signature_template); 22378 v8::Context::Scope context_scope(context); 22379 // Install regular object that can pass signature checks. 22380 Local<Object> function_receiver = signature_template->NewInstance(); 22381 context->Global()->Set(v8_str("function_receiver"), function_receiver); 22382 // Get the holder objects. 22383 Local<Object> inner_global = 22384 Local<Object>::Cast(context->Global()->GetPrototype()); 22385 // Install functions on hidden prototype object if there is one. 22386 data = Object::New(isolate); 22387 Local<FunctionTemplate> function_template = FunctionTemplate::New( 22388 isolate, OptimizationCallback, data, signature); 22389 Local<Function> function = function_template->GetFunction(); 22390 Local<Object> global_holder = inner_global; 22391 Local<Object> function_holder = function_receiver; 22392 if (signature_type == kSignatureOnPrototype) { 22393 function_holder = Local<Object>::Cast(function_holder->GetPrototype()); 22394 global_holder = Local<Object>::Cast(global_holder->GetPrototype()); 22395 } 22396 global_holder->Set(v8_str("g_f"), function); 22397 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); 22398 function_holder->Set(v8_str("f"), function); 22399 function_holder->SetAccessorProperty(v8_str("acc"), function, function); 22400 // Initialize expected values. 22401 callee = function; 22402 count = 0; 22403 if (global) { 22404 receiver = context->Global(); 22405 holder = inner_global; 22406 } else { 22407 holder = function_receiver; 22408 // If not using a signature, add something else to the prototype chain 22409 // to test the case that holder != receiver 22410 if (signature_type == kNoSignature) { 22411 receiver = Local<Object>::Cast(CompileRun( 22412 "var receiver_subclass = {};\n" 22413 "receiver_subclass.__proto__ = function_receiver;\n" 22414 "receiver_subclass")); 22415 } else { 22416 receiver = Local<Object>::Cast(CompileRun( 22417 "var receiver_subclass = function_receiver;\n" 22418 "receiver_subclass")); 22419 } 22420 } 22421 // With no signature, the holder is not set. 22422 if (signature_type == kNoSignature) holder = receiver; 22423 // build wrap_function 22424 i::ScopedVector<char> wrap_function(200); 22425 if (global) { 22426 i::SNPrintF( 22427 wrap_function, 22428 "function wrap_f_%d() { var f = g_f; return f(); }\n" 22429 "function wrap_get_%d() { return this.g_acc; }\n" 22430 "function wrap_set_%d() { return this.g_acc = 1; }\n", 22431 key, key, key); 22432 } else { 22433 i::SNPrintF( 22434 wrap_function, 22435 "function wrap_f_%d() { return receiver_subclass.f(); }\n" 22436 "function wrap_get_%d() { return receiver_subclass.acc; }\n" 22437 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", 22438 key, key, key); 22439 } 22440 // build source string 22441 i::ScopedVector<char> source(1000); 22442 i::SNPrintF( 22443 source, 22444 "%s\n" // wrap functions 22445 "function wrap_f() { return wrap_f_%d(); }\n" 22446 "function wrap_get() { return wrap_get_%d(); }\n" 22447 "function wrap_set() { return wrap_set_%d(); }\n" 22448 "check = function(returned) {\n" 22449 " if (returned !== 'returned') { throw returned; }\n" 22450 "}\n" 22451 "\n" 22452 "check(wrap_f());\n" 22453 "check(wrap_f());\n" 22454 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" 22455 "check(wrap_f());\n" 22456 "\n" 22457 "check(wrap_get());\n" 22458 "check(wrap_get());\n" 22459 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" 22460 "check(wrap_get());\n" 22461 "\n" 22462 "check = function(returned) {\n" 22463 " if (returned !== 1) { throw returned; }\n" 22464 "}\n" 22465 "check(wrap_set());\n" 22466 "check(wrap_set());\n" 22467 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" 22468 "check(wrap_set());\n", 22469 wrap_function.start(), key, key, key, key, key, key); 22470 v8::TryCatch try_catch; 22471 CompileRun(source.start()); 22472 ASSERT(!try_catch.HasCaught()); 22473 CHECK_EQ(9, count); 22474 } 22475 }; 22476 22477 22478 Local<Object> ApiCallOptimizationChecker::data; 22479 Local<Object> ApiCallOptimizationChecker::receiver; 22480 Local<Object> ApiCallOptimizationChecker::holder; 22481 Local<Object> ApiCallOptimizationChecker::callee; 22482 int ApiCallOptimizationChecker::count = 0; 22483 22484 22485 TEST(TestFunctionCallOptimization) { 22486 i::FLAG_allow_natives_syntax = true; 22487 ApiCallOptimizationChecker checker; 22488 checker.RunAll(); 22489 } 22490 22491 22492 static const char* last_event_message; 22493 static int last_event_status; 22494 void StoringEventLoggerCallback(const char* message, int status) { 22495 last_event_message = message; 22496 last_event_status = status; 22497 } 22498 22499 22500 TEST(EventLogging) { 22501 v8::Isolate* isolate = CcTest::isolate(); 22502 isolate->SetEventLogger(StoringEventLoggerCallback); 22503 v8::internal::HistogramTimer histogramTimer( 22504 "V8.Test", 0, 10000, 50, 22505 reinterpret_cast<v8::internal::Isolate*>(isolate)); 22506 histogramTimer.Start(); 22507 CHECK_EQ("V8.Test", last_event_message); 22508 CHECK_EQ(0, last_event_status); 22509 histogramTimer.Stop(); 22510 CHECK_EQ("V8.Test", last_event_message); 22511 CHECK_EQ(1, last_event_status); 22512 } 22513 22514 22515 TEST(Promises) { 22516 LocalContext context; 22517 v8::Isolate* isolate = context->GetIsolate(); 22518 v8::HandleScope scope(isolate); 22519 Handle<Object> global = context->Global(); 22520 22521 // Creation. 22522 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate); 22523 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate); 22524 Handle<v8::Promise> p = pr->GetPromise(); 22525 Handle<v8::Promise> r = rr->GetPromise(); 22526 22527 // IsPromise predicate. 22528 CHECK(p->IsPromise()); 22529 CHECK(r->IsPromise()); 22530 Handle<Value> o = v8::Object::New(isolate); 22531 CHECK(!o->IsPromise()); 22532 22533 // Resolution and rejection. 22534 pr->Resolve(v8::Integer::New(isolate, 1)); 22535 CHECK(p->IsPromise()); 22536 rr->Reject(v8::Integer::New(isolate, 2)); 22537 CHECK(r->IsPromise()); 22538 22539 // Chaining non-pending promises. 22540 CompileRun( 22541 "var x1 = 0;\n" 22542 "var x2 = 0;\n" 22543 "function f1(x) { x1 = x; return x+1 };\n" 22544 "function f2(x) { x2 = x; return x+1 };\n"); 22545 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1"))); 22546 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2"))); 22547 22548 p->Chain(f1); 22549 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22550 isolate->RunMicrotasks(); 22551 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22552 22553 p->Catch(f2); 22554 isolate->RunMicrotasks(); 22555 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22556 22557 r->Catch(f2); 22558 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22559 isolate->RunMicrotasks(); 22560 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); 22561 22562 r->Chain(f1); 22563 isolate->RunMicrotasks(); 22564 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22565 22566 // Chaining pending promises. 22567 CompileRun("x1 = x2 = 0;"); 22568 pr = v8::Promise::Resolver::New(isolate); 22569 rr = v8::Promise::Resolver::New(isolate); 22570 22571 pr->GetPromise()->Chain(f1); 22572 rr->GetPromise()->Catch(f2); 22573 isolate->RunMicrotasks(); 22574 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22575 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22576 22577 pr->Resolve(v8::Integer::New(isolate, 1)); 22578 rr->Reject(v8::Integer::New(isolate, 2)); 22579 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22580 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22581 22582 isolate->RunMicrotasks(); 22583 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22584 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); 22585 22586 // Multi-chaining. 22587 CompileRun("x1 = x2 = 0;"); 22588 pr = v8::Promise::Resolver::New(isolate); 22589 pr->GetPromise()->Chain(f1)->Chain(f2); 22590 pr->Resolve(v8::Integer::New(isolate, 3)); 22591 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22592 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22593 isolate->RunMicrotasks(); 22594 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22595 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22596 22597 CompileRun("x1 = x2 = 0;"); 22598 rr = v8::Promise::Resolver::New(isolate); 22599 rr->GetPromise()->Catch(f1)->Chain(f2); 22600 rr->Reject(v8::Integer::New(isolate, 3)); 22601 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22602 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22603 isolate->RunMicrotasks(); 22604 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22605 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22606 } 22607 22608 22609 TEST(PromiseThen) { 22610 LocalContext context; 22611 v8::Isolate* isolate = context->GetIsolate(); 22612 v8::HandleScope scope(isolate); 22613 Handle<Object> global = context->Global(); 22614 22615 // Creation. 22616 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate); 22617 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate); 22618 Handle<v8::Promise> p = pr->GetPromise(); 22619 Handle<v8::Promise> q = qr->GetPromise(); 22620 22621 CHECK(p->IsPromise()); 22622 CHECK(q->IsPromise()); 22623 22624 pr->Resolve(v8::Integer::New(isolate, 1)); 22625 qr->Resolve(p); 22626 22627 // Chaining non-pending promises. 22628 CompileRun( 22629 "var x1 = 0;\n" 22630 "var x2 = 0;\n" 22631 "function f1(x) { x1 = x; return x+1 };\n" 22632 "function f2(x) { x2 = x; return x+1 };\n"); 22633 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1"))); 22634 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2"))); 22635 22636 // Chain 22637 q->Chain(f1); 22638 CHECK(global->Get(v8_str("x1"))->IsNumber()); 22639 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22640 isolate->RunMicrotasks(); 22641 CHECK(!global->Get(v8_str("x1"))->IsNumber()); 22642 CHECK_EQ(p, global->Get(v8_str("x1"))); 22643 22644 // Then 22645 CompileRun("x1 = x2 = 0;"); 22646 q->Then(f1); 22647 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22648 isolate->RunMicrotasks(); 22649 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22650 22651 // Then 22652 CompileRun("x1 = x2 = 0;"); 22653 pr = v8::Promise::Resolver::New(isolate); 22654 qr = v8::Promise::Resolver::New(isolate); 22655 22656 qr->Resolve(pr); 22657 qr->GetPromise()->Then(f1)->Then(f2); 22658 22659 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22660 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22661 isolate->RunMicrotasks(); 22662 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22663 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22664 22665 pr->Resolve(v8::Integer::New(isolate, 3)); 22666 22667 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22668 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22669 isolate->RunMicrotasks(); 22670 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22671 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22672 } 22673 22674 22675 TEST(DisallowJavascriptExecutionScope) { 22676 LocalContext context; 22677 v8::Isolate* isolate = context->GetIsolate(); 22678 v8::HandleScope scope(isolate); 22679 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22680 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22681 CompileRun("2+2"); 22682 } 22683 22684 22685 TEST(AllowJavascriptExecutionScope) { 22686 LocalContext context; 22687 v8::Isolate* isolate = context->GetIsolate(); 22688 v8::HandleScope scope(isolate); 22689 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22690 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22691 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22692 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22693 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate); 22694 CompileRun("1+1"); 22695 } 22696 } 22697 22698 22699 TEST(ThrowOnJavascriptExecution) { 22700 LocalContext context; 22701 v8::Isolate* isolate = context->GetIsolate(); 22702 v8::HandleScope scope(isolate); 22703 v8::TryCatch try_catch; 22704 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22705 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22706 CompileRun("1+1"); 22707 CHECK(try_catch.HasCaught()); 22708 } 22709 22710 22711 TEST(Regress354123) { 22712 LocalContext current; 22713 v8::Isolate* isolate = current->GetIsolate(); 22714 v8::HandleScope scope(isolate); 22715 22716 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 22717 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter); 22718 current->Global()->Set(v8_str("friend"), templ->NewInstance()); 22719 22720 // Test access using __proto__ from the prototype chain. 22721 named_access_count = 0; 22722 CompileRun("friend.__proto__ = {};"); 22723 CHECK_EQ(2, named_access_count); 22724 CompileRun("friend.__proto__;"); 22725 CHECK_EQ(4, named_access_count); 22726 22727 // Test access using __proto__ as a hijacked function (A). 22728 named_access_count = 0; 22729 CompileRun("var p = Object.prototype;" 22730 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;" 22731 "f.call(friend, {});"); 22732 CHECK_EQ(1, named_access_count); 22733 CompileRun("var p = Object.prototype;" 22734 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;" 22735 "f.call(friend);"); 22736 CHECK_EQ(2, named_access_count); 22737 22738 // Test access using __proto__ as a hijacked function (B). 22739 named_access_count = 0; 22740 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');" 22741 "f.call(friend, {});"); 22742 CHECK_EQ(1, named_access_count); 22743 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');" 22744 "f.call(friend);"); 22745 CHECK_EQ(2, named_access_count); 22746 22747 // Test access using Object.setPrototypeOf reflective method. 22748 named_access_count = 0; 22749 CompileRun("Object.setPrototypeOf(friend, {});"); 22750 CHECK_EQ(1, named_access_count); 22751 CompileRun("Object.getPrototypeOf(friend);"); 22752 CHECK_EQ(2, named_access_count); 22753 } 22754 22755 22756 TEST(CaptureStackTraceForStackOverflow) { 22757 v8::internal::FLAG_stack_size = 150; 22758 LocalContext current; 22759 v8::Isolate* isolate = current->GetIsolate(); 22760 v8::HandleScope scope(isolate); 22761 V8::SetCaptureStackTraceForUncaughtExceptions( 22762 true, 10, v8::StackTrace::kDetailed); 22763 v8::TryCatch try_catch; 22764 CompileRun("(function f(x) { f(x+1); })(0)"); 22765 CHECK(try_catch.HasCaught()); 22766 } 22767 22768 22769 TEST(ScriptNameAndLineNumber) { 22770 LocalContext env; 22771 v8::Isolate* isolate = env->GetIsolate(); 22772 v8::HandleScope scope(isolate); 22773 const char* url = "http://www.foo.com/foo.js"; 22774 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); 22775 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin); 22776 Local<Script> script = v8::ScriptCompiler::Compile( 22777 isolate, &script_source); 22778 Local<Value> script_name = script->GetUnboundScript()->GetScriptName(); 22779 CHECK(!script_name.IsEmpty()); 22780 CHECK(script_name->IsString()); 22781 String::Utf8Value utf8_name(script_name); 22782 CHECK_EQ(url, *utf8_name); 22783 int line_number = script->GetUnboundScript()->GetLineNumber(0); 22784 CHECK_EQ(13, line_number); 22785 } 22786 22787 22788 Local<v8::Context> call_eval_context; 22789 Local<v8::Function> call_eval_bound_function; 22790 static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) { 22791 v8::Context::Scope scope(call_eval_context); 22792 args.GetReturnValue().Set( 22793 call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL)); 22794 } 22795 22796 22797 TEST(CrossActivationEval) { 22798 LocalContext env; 22799 v8::Isolate* isolate = env->GetIsolate(); 22800 v8::HandleScope scope(isolate); 22801 { 22802 call_eval_context = v8::Context::New(isolate); 22803 v8::Context::Scope scope(call_eval_context); 22804 call_eval_bound_function = 22805 Local<Function>::Cast(CompileRun("eval.bind(this, '1')")); 22806 } 22807 env->Global()->Set(v8_str("CallEval"), 22808 v8::FunctionTemplate::New(isolate, CallEval)->GetFunction()); 22809 Local<Value> result = CompileRun("CallEval();"); 22810 CHECK_EQ(result, v8::Integer::New(isolate, 1)); 22811 } 22812