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 <map> 31 #include <string> 32 33 #include "test/cctest/test-api.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/base/platform/platform.h" 43 #include "src/base/smart-pointers.h" 44 #include "src/compilation-cache.h" 45 #include "src/debug/debug.h" 46 #include "src/execution.h" 47 #include "src/futex-emulation.h" 48 #include "src/objects.h" 49 #include "src/parsing/parser.h" 50 #include "src/unicode-inl.h" 51 #include "src/utils.h" 52 #include "src/vm-state.h" 53 #include "test/cctest/heap/heap-tester.h" 54 #include "test/cctest/heap/utils-inl.h" 55 56 static const bool kLogThreading = false; 57 58 using ::v8::Boolean; 59 using ::v8::BooleanObject; 60 using ::v8::Context; 61 using ::v8::Extension; 62 using ::v8::Function; 63 using ::v8::FunctionTemplate; 64 using ::v8::HandleScope; 65 using ::v8::Local; 66 using ::v8::Maybe; 67 using ::v8::Message; 68 using ::v8::MessageCallback; 69 using ::v8::Name; 70 using ::v8::None; 71 using ::v8::Object; 72 using ::v8::ObjectTemplate; 73 using ::v8::Persistent; 74 using ::v8::PropertyAttribute; 75 using ::v8::Script; 76 using ::v8::StackTrace; 77 using ::v8::String; 78 using ::v8::Symbol; 79 using ::v8::TryCatch; 80 using ::v8::Undefined; 81 using ::v8::UniqueId; 82 using ::v8::V8; 83 using ::v8::Value; 84 85 86 #define THREADED_PROFILED_TEST(Name) \ 87 static void Test##Name(); \ 88 TEST(Name##WithProfiler) { \ 89 RunWithProfiler(&Test##Name); \ 90 } \ 91 THREADED_TEST(Name) 92 93 94 void RunWithProfiler(void (*test)()) { 95 LocalContext env; 96 v8::HandleScope scope(env->GetIsolate()); 97 v8::Local<v8::String> profile_name = v8_str("my_profile1"); 98 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 99 100 cpu_profiler->StartProfiling(profile_name); 101 (*test)(); 102 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles(); 103 } 104 105 106 static int signature_callback_count; 107 static Local<Value> signature_expected_receiver; 108 static void IncrementingSignatureCallback( 109 const v8::FunctionCallbackInfo<v8::Value>& args) { 110 ApiTestFuzzer::Fuzz(); 111 signature_callback_count++; 112 CHECK(signature_expected_receiver->Equals( 113 args.GetIsolate()->GetCurrentContext(), 114 args.Holder()) 115 .FromJust()); 116 CHECK(signature_expected_receiver->Equals( 117 args.GetIsolate()->GetCurrentContext(), 118 args.This()) 119 .FromJust()); 120 v8::Local<v8::Array> result = 121 v8::Array::New(args.GetIsolate(), args.Length()); 122 for (int i = 0; i < args.Length(); i++) { 123 CHECK(result->Set(args.GetIsolate()->GetCurrentContext(), 124 v8::Integer::New(args.GetIsolate(), i), args[i]) 125 .FromJust()); 126 } 127 args.GetReturnValue().Set(result); 128 } 129 130 131 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) { 132 info.GetReturnValue().Set(42); 133 } 134 135 136 // Tests that call v8::V8::Dispose() cannot be threaded. 137 UNINITIALIZED_TEST(InitializeAndDisposeOnce) { 138 CHECK(v8::V8::Initialize()); 139 CHECK(v8::V8::Dispose()); 140 } 141 142 143 // Tests that call v8::V8::Dispose() cannot be threaded. 144 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) { 145 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 146 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 147 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 148 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 149 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 150 } 151 152 153 THREADED_TEST(Handles) { 154 v8::HandleScope scope(CcTest::isolate()); 155 Local<Context> local_env; 156 { 157 LocalContext env; 158 local_env = env.local(); 159 } 160 161 // Local context should still be live. 162 CHECK(!local_env.IsEmpty()); 163 local_env->Enter(); 164 165 v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); 166 CHECK(!undef.IsEmpty()); 167 CHECK(undef->IsUndefined()); 168 169 const char* source = "1 + 2 + 3"; 170 Local<Script> script = v8_compile(source); 171 CHECK_EQ(6, v8_run_int32value(script)); 172 173 local_env->Exit(); 174 } 175 176 177 THREADED_TEST(IsolateOfContext) { 178 v8::HandleScope scope(CcTest::isolate()); 179 v8::Local<Context> env = Context::New(CcTest::isolate()); 180 181 CHECK(!env->GetIsolate()->InContext()); 182 CHECK(env->GetIsolate() == CcTest::isolate()); 183 env->Enter(); 184 CHECK(env->GetIsolate()->InContext()); 185 CHECK(env->GetIsolate() == CcTest::isolate()); 186 env->Exit(); 187 CHECK(!env->GetIsolate()->InContext()); 188 CHECK(env->GetIsolate() == CcTest::isolate()); 189 } 190 191 192 static void TestSignature(const char* loop_js, Local<Value> receiver, 193 v8::Isolate* isolate) { 194 i::ScopedVector<char> source(200); 195 i::SNPrintF(source, 196 "for (var i = 0; i < 10; i++) {" 197 " %s" 198 "}", 199 loop_js); 200 signature_callback_count = 0; 201 signature_expected_receiver = receiver; 202 bool expected_to_throw = receiver.IsEmpty(); 203 v8::TryCatch try_catch(isolate); 204 CompileRun(source.start()); 205 CHECK_EQ(expected_to_throw, try_catch.HasCaught()); 206 if (!expected_to_throw) { 207 CHECK_EQ(10, signature_callback_count); 208 } else { 209 CHECK(v8_str("TypeError: Illegal invocation") 210 ->Equals(isolate->GetCurrentContext(), 211 try_catch.Exception() 212 ->ToString(isolate->GetCurrentContext()) 213 .ToLocalChecked()) 214 .FromJust()); 215 } 216 } 217 218 219 THREADED_TEST(ReceiverSignature) { 220 LocalContext env; 221 v8::Isolate* isolate = env->GetIsolate(); 222 v8::HandleScope scope(isolate); 223 // Setup templates. 224 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 225 v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun); 226 v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New( 227 isolate, IncrementingSignatureCallback, Local<Value>(), sig); 228 v8::Local<v8::FunctionTemplate> callback = 229 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback); 230 v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate); 231 sub_fun->Inherit(fun); 232 v8::Local<v8::FunctionTemplate> unrel_fun = 233 v8::FunctionTemplate::New(isolate); 234 // Install properties. 235 v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); 236 fun_proto->Set(v8_str("prop_sig"), callback_sig); 237 fun_proto->Set(v8_str("prop"), callback); 238 fun_proto->SetAccessorProperty( 239 v8_str("accessor_sig"), callback_sig, callback_sig); 240 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); 241 // Instantiate templates. 242 Local<Value> fun_instance = 243 fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 244 Local<Value> sub_fun_instance = 245 sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 246 // Setup global variables. 247 CHECK(env->Global() 248 ->Set(env.local(), v8_str("Fun"), 249 fun->GetFunction(env.local()).ToLocalChecked()) 250 .FromJust()); 251 CHECK(env->Global() 252 ->Set(env.local(), v8_str("UnrelFun"), 253 unrel_fun->GetFunction(env.local()).ToLocalChecked()) 254 .FromJust()); 255 CHECK(env->Global() 256 ->Set(env.local(), v8_str("fun_instance"), fun_instance) 257 .FromJust()); 258 CHECK(env->Global() 259 ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance) 260 .FromJust()); 261 CompileRun( 262 "var accessor_sig_key = 'accessor_sig';" 263 "var accessor_key = 'accessor';" 264 "var prop_sig_key = 'prop_sig';" 265 "var prop_key = 'prop';" 266 "" 267 "function copy_props(obj) {" 268 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" 269 " var source = Fun.prototype;" 270 " for (var i in keys) {" 271 " var key = keys[i];" 272 " var desc = Object.getOwnPropertyDescriptor(source, key);" 273 " Object.defineProperty(obj, key, desc);" 274 " }" 275 "}" 276 "" 277 "var obj = {};" 278 "copy_props(obj);" 279 "var unrel = new UnrelFun();" 280 "copy_props(unrel);"); 281 // Test with and without ICs 282 const char* test_objects[] = { 283 "fun_instance", "sub_fun_instance", "obj", "unrel" }; 284 unsigned bad_signature_start_offset = 2; 285 for (unsigned i = 0; i < arraysize(test_objects); i++) { 286 i::ScopedVector<char> source(200); 287 i::SNPrintF( 288 source, "var test_object = %s; test_object", test_objects[i]); 289 Local<Value> test_object = CompileRun(source.start()); 290 TestSignature("test_object.prop();", test_object, isolate); 291 TestSignature("test_object.accessor;", test_object, isolate); 292 TestSignature("test_object[accessor_key];", test_object, isolate); 293 TestSignature("test_object.accessor = 1;", test_object, isolate); 294 TestSignature("test_object[accessor_key] = 1;", test_object, isolate); 295 if (i >= bad_signature_start_offset) test_object = Local<Value>(); 296 TestSignature("test_object.prop_sig();", test_object, isolate); 297 TestSignature("test_object.accessor_sig;", test_object, isolate); 298 TestSignature("test_object[accessor_sig_key];", test_object, isolate); 299 TestSignature("test_object.accessor_sig = 1;", test_object, isolate); 300 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate); 301 } 302 } 303 304 305 THREADED_TEST(HulIgennem) { 306 LocalContext env; 307 v8::Isolate* isolate = env->GetIsolate(); 308 v8::HandleScope scope(isolate); 309 v8::Local<v8::Primitive> undef = v8::Undefined(isolate); 310 Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked(); 311 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 312 undef_str->WriteUtf8(value); 313 CHECK_EQ(0, strcmp(value, "undefined")); 314 i::DeleteArray(value); 315 } 316 317 318 THREADED_TEST(Access) { 319 LocalContext env; 320 v8::Isolate* isolate = env->GetIsolate(); 321 v8::HandleScope scope(isolate); 322 Local<v8::Object> obj = v8::Object::New(isolate); 323 Local<Value> foo_before = 324 obj->Get(env.local(), v8_str("foo")).ToLocalChecked(); 325 CHECK(foo_before->IsUndefined()); 326 Local<String> bar_str = v8_str("bar"); 327 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust()); 328 Local<Value> foo_after = 329 obj->Get(env.local(), v8_str("foo")).ToLocalChecked(); 330 CHECK(!foo_after->IsUndefined()); 331 CHECK(foo_after->IsString()); 332 CHECK(bar_str->Equals(env.local(), foo_after).FromJust()); 333 } 334 335 336 THREADED_TEST(AccessElement) { 337 LocalContext env; 338 v8::HandleScope scope(env->GetIsolate()); 339 Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 340 Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked(); 341 CHECK(before->IsUndefined()); 342 Local<String> bar_str = v8_str("bar"); 343 CHECK(obj->Set(env.local(), 1, bar_str).FromJust()); 344 Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked(); 345 CHECK(!after->IsUndefined()); 346 CHECK(after->IsString()); 347 CHECK(bar_str->Equals(env.local(), after).FromJust()); 348 349 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 350 CHECK(v8_str("a") 351 ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked()) 352 .FromJust()); 353 CHECK(v8_str("b") 354 ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked()) 355 .FromJust()); 356 } 357 358 359 THREADED_TEST(Script) { 360 LocalContext env; 361 v8::HandleScope scope(env->GetIsolate()); 362 const char* source = "1 + 2 + 3"; 363 Local<Script> script = v8_compile(source); 364 CHECK_EQ(6, v8_run_int32value(script)); 365 } 366 367 368 class TestResource: public String::ExternalStringResource { 369 public: 370 explicit TestResource(uint16_t* data, int* counter = NULL, 371 bool owning_data = true) 372 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { 373 while (data[length_]) ++length_; 374 } 375 376 ~TestResource() { 377 if (owning_data_) i::DeleteArray(data_); 378 if (counter_ != NULL) ++*counter_; 379 } 380 381 const uint16_t* data() const { 382 return data_; 383 } 384 385 size_t length() const { 386 return length_; 387 } 388 389 private: 390 uint16_t* data_; 391 size_t length_; 392 int* counter_; 393 bool owning_data_; 394 }; 395 396 397 class TestOneByteResource : public String::ExternalOneByteStringResource { 398 public: 399 explicit TestOneByteResource(const char* data, int* counter = NULL, 400 size_t offset = 0) 401 : orig_data_(data), 402 data_(data + offset), 403 length_(strlen(data) - offset), 404 counter_(counter) {} 405 406 ~TestOneByteResource() { 407 i::DeleteArray(orig_data_); 408 if (counter_ != NULL) ++*counter_; 409 } 410 411 const char* data() const { 412 return data_; 413 } 414 415 size_t length() const { 416 return length_; 417 } 418 419 private: 420 const char* orig_data_; 421 const char* data_; 422 size_t length_; 423 int* counter_; 424 }; 425 426 427 THREADED_TEST(ScriptUsingStringResource) { 428 int dispose_count = 0; 429 const char* c_source = "1 + 2 * 3"; 430 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 431 { 432 LocalContext env; 433 v8::HandleScope scope(env->GetIsolate()); 434 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 435 Local<String> source = 436 String::NewExternalTwoByte(env->GetIsolate(), resource) 437 .ToLocalChecked(); 438 Local<Script> script = v8_compile(source); 439 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 440 CHECK(value->IsNumber()); 441 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 442 CHECK(source->IsExternal()); 443 CHECK_EQ(resource, 444 static_cast<TestResource*>(source->GetExternalStringResource())); 445 String::Encoding encoding = String::UNKNOWN_ENCODING; 446 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 447 source->GetExternalStringResourceBase(&encoding)); 448 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 449 CcTest::heap()->CollectAllGarbage(); 450 CHECK_EQ(0, dispose_count); 451 } 452 CcTest::i_isolate()->compilation_cache()->Clear(); 453 CcTest::heap()->CollectAllAvailableGarbage(); 454 CHECK_EQ(1, dispose_count); 455 } 456 457 458 THREADED_TEST(ScriptUsingOneByteStringResource) { 459 int dispose_count = 0; 460 const char* c_source = "1 + 2 * 3"; 461 { 462 LocalContext env; 463 v8::HandleScope scope(env->GetIsolate()); 464 TestOneByteResource* resource = 465 new TestOneByteResource(i::StrDup(c_source), &dispose_count); 466 Local<String> source = 467 String::NewExternalOneByte(env->GetIsolate(), resource) 468 .ToLocalChecked(); 469 CHECK(source->IsExternalOneByte()); 470 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 471 source->GetExternalOneByteStringResource()); 472 String::Encoding encoding = String::UNKNOWN_ENCODING; 473 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 474 source->GetExternalStringResourceBase(&encoding)); 475 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 476 Local<Script> script = v8_compile(source); 477 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 478 CHECK(value->IsNumber()); 479 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 480 CcTest::heap()->CollectAllGarbage(); 481 CHECK_EQ(0, dispose_count); 482 } 483 CcTest::i_isolate()->compilation_cache()->Clear(); 484 CcTest::heap()->CollectAllAvailableGarbage(); 485 CHECK_EQ(1, dispose_count); 486 } 487 488 489 THREADED_TEST(ScriptMakingExternalString) { 490 int dispose_count = 0; 491 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 492 { 493 LocalContext env; 494 v8::HandleScope scope(env->GetIsolate()); 495 Local<String> source = 496 String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 497 v8::NewStringType::kNormal) 498 .ToLocalChecked(); 499 // Trigger GCs so that the newly allocated string moves to old gen. 500 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 501 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 502 CHECK_EQ(source->IsExternal(), false); 503 CHECK_EQ(source->IsExternalOneByte(), false); 504 String::Encoding encoding = String::UNKNOWN_ENCODING; 505 CHECK(!source->GetExternalStringResourceBase(&encoding)); 506 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 507 bool success = source->MakeExternal(new TestResource(two_byte_source, 508 &dispose_count)); 509 CHECK(success); 510 Local<Script> script = v8_compile(source); 511 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 512 CHECK(value->IsNumber()); 513 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 514 CcTest::heap()->CollectAllGarbage(); 515 CHECK_EQ(0, dispose_count); 516 } 517 CcTest::i_isolate()->compilation_cache()->Clear(); 518 CcTest::heap()->CollectAllGarbage(); 519 CHECK_EQ(1, dispose_count); 520 } 521 522 523 THREADED_TEST(ScriptMakingExternalOneByteString) { 524 int dispose_count = 0; 525 const char* c_source = "1 + 2 * 3"; 526 { 527 LocalContext env; 528 v8::HandleScope scope(env->GetIsolate()); 529 Local<String> source = v8_str(c_source); 530 // Trigger GCs so that the newly allocated string moves to old gen. 531 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 532 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 533 bool success = source->MakeExternal( 534 new TestOneByteResource(i::StrDup(c_source), &dispose_count)); 535 CHECK(success); 536 Local<Script> script = v8_compile(source); 537 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 538 CHECK(value->IsNumber()); 539 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 540 CcTest::heap()->CollectAllGarbage(); 541 CHECK_EQ(0, dispose_count); 542 } 543 CcTest::i_isolate()->compilation_cache()->Clear(); 544 CcTest::heap()->CollectAllGarbage(); 545 CHECK_EQ(1, dispose_count); 546 } 547 548 549 TEST(MakingExternalStringConditions) { 550 LocalContext env; 551 v8::HandleScope scope(env->GetIsolate()); 552 553 // Free some space in the new space so that we can check freshness. 554 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 555 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 556 557 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 558 Local<String> small_string = 559 String::NewFromTwoByte(env->GetIsolate(), two_byte_string, 560 v8::NewStringType::kNormal) 561 .ToLocalChecked(); 562 i::DeleteArray(two_byte_string); 563 564 // We should refuse to externalize small strings. 565 CHECK(!small_string->CanMakeExternal()); 566 // Trigger GCs so that the newly allocated string moves to old gen. 567 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 569 // Old space strings should be accepted. 570 CHECK(small_string->CanMakeExternal()); 571 572 two_byte_string = AsciiToTwoByteString("small string 2"); 573 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string, 574 v8::NewStringType::kNormal) 575 .ToLocalChecked(); 576 i::DeleteArray(two_byte_string); 577 578 const int buf_size = 10 * 1024; 579 char* buf = i::NewArray<char>(buf_size); 580 memset(buf, 'a', buf_size); 581 buf[buf_size - 1] = '\0'; 582 583 two_byte_string = AsciiToTwoByteString(buf); 584 Local<String> large_string = 585 String::NewFromTwoByte(env->GetIsolate(), two_byte_string, 586 v8::NewStringType::kNormal) 587 .ToLocalChecked(); 588 i::DeleteArray(buf); 589 i::DeleteArray(two_byte_string); 590 // Large strings should be immediately accepted. 591 CHECK(large_string->CanMakeExternal()); 592 } 593 594 595 TEST(MakingExternalOneByteStringConditions) { 596 LocalContext env; 597 v8::HandleScope scope(env->GetIsolate()); 598 599 // Free some space in the new space so that we can check freshness. 600 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 601 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 602 603 Local<String> small_string = v8_str("s1"); 604 // We should refuse to externalize small strings. 605 CHECK(!small_string->CanMakeExternal()); 606 // Trigger GCs so that the newly allocated string moves to old gen. 607 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 608 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 609 // Old space strings should be accepted. 610 CHECK(small_string->CanMakeExternal()); 611 612 const int buf_size = 10 * 1024; 613 char* buf = i::NewArray<char>(buf_size); 614 memset(buf, 'a', buf_size); 615 buf[buf_size - 1] = '\0'; 616 Local<String> large_string = v8_str(buf); 617 i::DeleteArray(buf); 618 // Large strings should be immediately accepted. 619 CHECK(large_string->CanMakeExternal()); 620 } 621 622 623 TEST(MakingExternalUnalignedOneByteString) { 624 LocalContext env; 625 v8::HandleScope scope(env->GetIsolate()); 626 627 CompileRun("function cons(a, b) { return a + b; }" 628 "function slice(a) { return a.substring(1); }"); 629 // Create a cons string that will land in old pointer space. 630 Local<String> cons = Local<String>::Cast(CompileRun( 631 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 632 // Create a sliced string that will land in old pointer space. 633 Local<String> slice = Local<String>::Cast(CompileRun( 634 "slice('abcdefghijklmnopqrstuvwxyz');")); 635 636 // Trigger GCs so that the newly allocated string moves to old gen. 637 SimulateFullSpace(CcTest::heap()->old_space()); 638 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 639 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 640 641 // Turn into external string with unaligned resource data. 642 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 643 bool success = 644 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1)); 645 CHECK(success); 646 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 647 success = 648 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1)); 649 CHECK(success); 650 651 // Trigger GCs and force evacuation. 652 CcTest::heap()->CollectAllGarbage(); 653 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 654 } 655 656 657 THREADED_TEST(UsingExternalString) { 658 i::Factory* factory = CcTest::i_isolate()->factory(); 659 { 660 v8::HandleScope scope(CcTest::isolate()); 661 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 662 Local<String> string = 663 String::NewExternalTwoByte(CcTest::isolate(), 664 new TestResource(two_byte_string)) 665 .ToLocalChecked(); 666 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 667 // Trigger GCs so that the newly allocated string moves to old gen. 668 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 669 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 670 i::Handle<i::String> isymbol = 671 factory->InternalizeString(istring); 672 CHECK(isymbol->IsInternalizedString()); 673 } 674 CcTest::heap()->CollectAllGarbage(); 675 CcTest::heap()->CollectAllGarbage(); 676 } 677 678 679 THREADED_TEST(UsingExternalOneByteString) { 680 i::Factory* factory = CcTest::i_isolate()->factory(); 681 { 682 v8::HandleScope scope(CcTest::isolate()); 683 const char* one_byte_string = "test string"; 684 Local<String> string = 685 String::NewExternalOneByte( 686 CcTest::isolate(), 687 new TestOneByteResource(i::StrDup(one_byte_string))) 688 .ToLocalChecked(); 689 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 690 // Trigger GCs so that the newly allocated string moves to old gen. 691 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 692 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 693 i::Handle<i::String> isymbol = 694 factory->InternalizeString(istring); 695 CHECK(isymbol->IsInternalizedString()); 696 } 697 CcTest::heap()->CollectAllGarbage(); 698 CcTest::heap()->CollectAllGarbage(); 699 } 700 701 702 class RandomLengthResource : public v8::String::ExternalStringResource { 703 public: 704 explicit RandomLengthResource(int length) : length_(length) {} 705 virtual const uint16_t* data() const { return string_; } 706 virtual size_t length() const { return length_; } 707 708 private: 709 uint16_t string_[10]; 710 int length_; 711 }; 712 713 714 class RandomLengthOneByteResource 715 : public v8::String::ExternalOneByteStringResource { 716 public: 717 explicit RandomLengthOneByteResource(int length) : length_(length) {} 718 virtual const char* data() const { return string_; } 719 virtual size_t length() const { return length_; } 720 721 private: 722 char string_[10]; 723 int length_; 724 }; 725 726 727 THREADED_TEST(NewExternalForVeryLongString) { 728 auto isolate = CcTest::isolate(); 729 { 730 v8::HandleScope scope(isolate); 731 v8::TryCatch try_catch(isolate); 732 RandomLengthOneByteResource r(1 << 30); 733 v8::MaybeLocal<v8::String> maybe_str = 734 v8::String::NewExternalOneByte(isolate, &r); 735 CHECK(maybe_str.IsEmpty()); 736 CHECK(!try_catch.HasCaught()); 737 } 738 739 { 740 v8::HandleScope scope(isolate); 741 v8::TryCatch try_catch(isolate); 742 RandomLengthResource r(1 << 30); 743 v8::MaybeLocal<v8::String> maybe_str = 744 v8::String::NewExternalTwoByte(isolate, &r); 745 CHECK(maybe_str.IsEmpty()); 746 CHECK(!try_catch.HasCaught()); 747 } 748 } 749 750 751 THREADED_TEST(ScavengeExternalString) { 752 i::FLAG_stress_compaction = false; 753 i::FLAG_gc_global = false; 754 int dispose_count = 0; 755 bool in_new_space = false; 756 { 757 v8::HandleScope scope(CcTest::isolate()); 758 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 759 Local<String> string = 760 String::NewExternalTwoByte( 761 CcTest::isolate(), 762 new TestResource(two_byte_string, &dispose_count)) 763 .ToLocalChecked(); 764 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 765 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 766 in_new_space = CcTest::heap()->InNewSpace(*istring); 767 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); 768 CHECK_EQ(0, dispose_count); 769 } 770 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); 771 CHECK_EQ(1, dispose_count); 772 } 773 774 775 THREADED_TEST(ScavengeExternalOneByteString) { 776 i::FLAG_stress_compaction = false; 777 i::FLAG_gc_global = false; 778 int dispose_count = 0; 779 bool in_new_space = false; 780 { 781 v8::HandleScope scope(CcTest::isolate()); 782 const char* one_byte_string = "test string"; 783 Local<String> string = 784 String::NewExternalOneByte( 785 CcTest::isolate(), 786 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count)) 787 .ToLocalChecked(); 788 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 789 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 790 in_new_space = CcTest::heap()->InNewSpace(*istring); 791 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); 792 CHECK_EQ(0, dispose_count); 793 } 794 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); 795 CHECK_EQ(1, dispose_count); 796 } 797 798 799 class TestOneByteResourceWithDisposeControl : public TestOneByteResource { 800 public: 801 // Only used by non-threaded tests, so it can use static fields. 802 static int dispose_calls; 803 static int dispose_count; 804 805 TestOneByteResourceWithDisposeControl(const char* data, bool dispose) 806 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {} 807 808 void Dispose() { 809 ++dispose_calls; 810 if (dispose_) delete this; 811 } 812 private: 813 bool dispose_; 814 }; 815 816 817 int TestOneByteResourceWithDisposeControl::dispose_count = 0; 818 int TestOneByteResourceWithDisposeControl::dispose_calls = 0; 819 820 821 TEST(ExternalStringWithDisposeHandling) { 822 const char* c_source = "1 + 2 * 3"; 823 824 // Use a stack allocated external string resource allocated object. 825 TestOneByteResourceWithDisposeControl::dispose_count = 0; 826 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 827 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 828 { 829 LocalContext env; 830 v8::HandleScope scope(env->GetIsolate()); 831 Local<String> source = 832 String::NewExternalOneByte(env->GetIsolate(), &res_stack) 833 .ToLocalChecked(); 834 Local<Script> script = v8_compile(source); 835 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 836 CHECK(value->IsNumber()); 837 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 838 CcTest::heap()->CollectAllAvailableGarbage(); 839 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 840 } 841 CcTest::i_isolate()->compilation_cache()->Clear(); 842 CcTest::heap()->CollectAllAvailableGarbage(); 843 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 844 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 845 846 // Use a heap allocated external string resource allocated object. 847 TestOneByteResourceWithDisposeControl::dispose_count = 0; 848 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 849 TestOneByteResource* res_heap = 850 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true); 851 { 852 LocalContext env; 853 v8::HandleScope scope(env->GetIsolate()); 854 Local<String> source = 855 String::NewExternalOneByte(env->GetIsolate(), res_heap) 856 .ToLocalChecked(); 857 Local<Script> script = v8_compile(source); 858 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 859 CHECK(value->IsNumber()); 860 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 861 CcTest::heap()->CollectAllAvailableGarbage(); 862 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 863 } 864 CcTest::i_isolate()->compilation_cache()->Clear(); 865 CcTest::heap()->CollectAllAvailableGarbage(); 866 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 867 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count); 868 } 869 870 871 THREADED_TEST(StringConcat) { 872 { 873 LocalContext env; 874 v8::HandleScope scope(env->GetIsolate()); 875 const char* one_byte_string_1 = "function a_times_t"; 876 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 877 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 878 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 879 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 880 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 881 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 882 Local<String> left = v8_str(one_byte_string_1); 883 884 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 885 Local<String> right = 886 String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 887 v8::NewStringType::kNormal) 888 .ToLocalChecked(); 889 i::DeleteArray(two_byte_source); 890 891 Local<String> source = String::Concat(left, right); 892 right = String::NewExternalOneByte( 893 env->GetIsolate(), 894 new TestOneByteResource(i::StrDup(one_byte_extern_1))) 895 .ToLocalChecked(); 896 source = String::Concat(source, right); 897 right = String::NewExternalTwoByte( 898 env->GetIsolate(), 899 new TestResource(AsciiToTwoByteString(two_byte_extern_1))) 900 .ToLocalChecked(); 901 source = String::Concat(source, right); 902 right = v8_str(one_byte_string_2); 903 source = String::Concat(source, right); 904 905 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 906 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 907 v8::NewStringType::kNormal) 908 .ToLocalChecked(); 909 i::DeleteArray(two_byte_source); 910 911 source = String::Concat(source, right); 912 right = String::NewExternalTwoByte( 913 env->GetIsolate(), 914 new TestResource(AsciiToTwoByteString(two_byte_extern_2))) 915 .ToLocalChecked(); 916 source = String::Concat(source, right); 917 Local<Script> script = v8_compile(source); 918 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 919 CHECK(value->IsNumber()); 920 CHECK_EQ(68, value->Int32Value(env.local()).FromJust()); 921 } 922 CcTest::i_isolate()->compilation_cache()->Clear(); 923 CcTest::heap()->CollectAllGarbage(); 924 CcTest::heap()->CollectAllGarbage(); 925 } 926 927 928 THREADED_TEST(GlobalProperties) { 929 LocalContext env; 930 v8::HandleScope scope(env->GetIsolate()); 931 v8::Local<v8::Object> global = env->Global(); 932 CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust()); 933 Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked(); 934 CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust()); 935 } 936 937 938 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 939 i::Address callback) { 940 ApiTestFuzzer::Fuzz(); 941 CheckReturnValue(info, callback); 942 info.GetReturnValue().Set(v8_str("bad value")); 943 info.GetReturnValue().Set(v8_num(102)); 944 } 945 946 947 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 948 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 949 } 950 951 952 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 953 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 954 } 955 956 static void construct_callback( 957 const v8::FunctionCallbackInfo<Value>& info) { 958 ApiTestFuzzer::Fuzz(); 959 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 960 CHECK( 961 info.This() 962 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1)) 963 .FromJust()); 964 CHECK( 965 info.This() 966 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2)) 967 .FromJust()); 968 info.GetReturnValue().Set(v8_str("bad value")); 969 info.GetReturnValue().Set(info.This()); 970 } 971 972 973 static void Return239Callback( 974 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 975 ApiTestFuzzer::Fuzz(); 976 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 977 info.GetReturnValue().Set(v8_str("bad value")); 978 info.GetReturnValue().Set(v8_num(239)); 979 } 980 981 982 template<typename Handler> 983 static void TestFunctionTemplateInitializer(Handler handler, 984 Handler handler_2) { 985 // Test constructor calls. 986 { 987 LocalContext env; 988 v8::Isolate* isolate = env->GetIsolate(); 989 v8::HandleScope scope(isolate); 990 991 Local<v8::FunctionTemplate> fun_templ = 992 v8::FunctionTemplate::New(isolate, handler); 993 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 994 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 995 Local<Script> script = v8_compile("obj()"); 996 for (int i = 0; i < 30; i++) { 997 CHECK_EQ(102, v8_run_int32value(script)); 998 } 999 } 1000 // Use SetCallHandler to initialize a function template, should work like 1001 // the previous one. 1002 { 1003 LocalContext env; 1004 v8::Isolate* isolate = env->GetIsolate(); 1005 v8::HandleScope scope(isolate); 1006 1007 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 1008 fun_templ->SetCallHandler(handler_2); 1009 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1010 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1011 Local<Script> script = v8_compile("obj()"); 1012 for (int i = 0; i < 30; i++) { 1013 CHECK_EQ(102, v8_run_int32value(script)); 1014 } 1015 } 1016 } 1017 1018 1019 template<typename Constructor, typename Accessor> 1020 static void TestFunctionTemplateAccessor(Constructor constructor, 1021 Accessor accessor) { 1022 LocalContext env; 1023 v8::HandleScope scope(env->GetIsolate()); 1024 1025 Local<v8::FunctionTemplate> fun_templ = 1026 v8::FunctionTemplate::New(env->GetIsolate(), constructor); 1027 fun_templ->SetClassName(v8_str("funky")); 1028 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 1029 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1030 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1031 Local<Value> result = 1032 v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked(); 1033 CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust()); 1034 CompileRun("var obj_instance = new obj();"); 1035 Local<Script> script; 1036 script = v8_compile("obj_instance.x"); 1037 for (int i = 0; i < 30; i++) { 1038 CHECK_EQ(1, v8_run_int32value(script)); 1039 } 1040 script = v8_compile("obj_instance.m"); 1041 for (int i = 0; i < 30; i++) { 1042 CHECK_EQ(239, v8_run_int32value(script)); 1043 } 1044 } 1045 1046 1047 THREADED_PROFILED_TEST(FunctionTemplate) { 1048 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 1049 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 1050 } 1051 1052 1053 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1054 ApiTestFuzzer::Fuzz(); 1055 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1056 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1057 } 1058 1059 1060 template<typename Callback> 1061 static void TestSimpleCallback(Callback callback) { 1062 LocalContext env; 1063 v8::Isolate* isolate = env->GetIsolate(); 1064 v8::HandleScope scope(isolate); 1065 1066 v8::Local<v8::ObjectTemplate> object_template = 1067 v8::ObjectTemplate::New(isolate); 1068 object_template->Set(isolate, "callback", 1069 v8::FunctionTemplate::New(isolate, callback)); 1070 v8::Local<v8::Object> object = 1071 object_template->NewInstance(env.local()).ToLocalChecked(); 1072 CHECK((*env) 1073 ->Global() 1074 ->Set(env.local(), v8_str("callback_object"), object) 1075 .FromJust()); 1076 v8::Local<v8::Script> script; 1077 script = v8_compile("callback_object.callback(17)"); 1078 for (int i = 0; i < 30; i++) { 1079 CHECK_EQ(51424, v8_run_int32value(script)); 1080 } 1081 script = v8_compile("callback_object.callback(17, 24)"); 1082 for (int i = 0; i < 30; i++) { 1083 CHECK_EQ(51425, v8_run_int32value(script)); 1084 } 1085 } 1086 1087 1088 THREADED_PROFILED_TEST(SimpleCallback) { 1089 TestSimpleCallback(SimpleCallback); 1090 } 1091 1092 1093 template<typename T> 1094 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1095 1096 // constant return values 1097 static int32_t fast_return_value_int32 = 471; 1098 static uint32_t fast_return_value_uint32 = 571; 1099 static const double kFastReturnValueDouble = 2.7; 1100 // variable return values 1101 static bool fast_return_value_bool = false; 1102 enum ReturnValueOddball { 1103 kNullReturnValue, 1104 kUndefinedReturnValue, 1105 kEmptyStringReturnValue 1106 }; 1107 static ReturnValueOddball fast_return_value_void; 1108 static bool fast_return_value_object_is_empty = false; 1109 1110 // Helper function to avoid compiler error: insufficient contextual information 1111 // to determine type when applying FUNCTION_ADDR to a template function. 1112 static i::Address address_of(v8::FunctionCallback callback) { 1113 return FUNCTION_ADDR(callback); 1114 } 1115 1116 template<> 1117 void FastReturnValueCallback<int32_t>( 1118 const v8::FunctionCallbackInfo<v8::Value>& info) { 1119 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1120 info.GetReturnValue().Set(fast_return_value_int32); 1121 } 1122 1123 template<> 1124 void FastReturnValueCallback<uint32_t>( 1125 const v8::FunctionCallbackInfo<v8::Value>& info) { 1126 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1127 info.GetReturnValue().Set(fast_return_value_uint32); 1128 } 1129 1130 template<> 1131 void FastReturnValueCallback<double>( 1132 const v8::FunctionCallbackInfo<v8::Value>& info) { 1133 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1134 info.GetReturnValue().Set(kFastReturnValueDouble); 1135 } 1136 1137 template<> 1138 void FastReturnValueCallback<bool>( 1139 const v8::FunctionCallbackInfo<v8::Value>& info) { 1140 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1141 info.GetReturnValue().Set(fast_return_value_bool); 1142 } 1143 1144 template<> 1145 void FastReturnValueCallback<void>( 1146 const v8::FunctionCallbackInfo<v8::Value>& info) { 1147 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1148 switch (fast_return_value_void) { 1149 case kNullReturnValue: 1150 info.GetReturnValue().SetNull(); 1151 break; 1152 case kUndefinedReturnValue: 1153 info.GetReturnValue().SetUndefined(); 1154 break; 1155 case kEmptyStringReturnValue: 1156 info.GetReturnValue().SetEmptyString(); 1157 break; 1158 } 1159 } 1160 1161 template<> 1162 void FastReturnValueCallback<Object>( 1163 const v8::FunctionCallbackInfo<v8::Value>& info) { 1164 v8::Local<v8::Object> object; 1165 if (!fast_return_value_object_is_empty) { 1166 object = Object::New(info.GetIsolate()); 1167 } 1168 info.GetReturnValue().Set(object); 1169 } 1170 1171 template <typename T> 1172 Local<Value> TestFastReturnValues() { 1173 LocalContext env; 1174 v8::Isolate* isolate = env->GetIsolate(); 1175 v8::EscapableHandleScope scope(isolate); 1176 v8::Local<v8::ObjectTemplate> object_template = 1177 v8::ObjectTemplate::New(isolate); 1178 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1179 object_template->Set(isolate, "callback", 1180 v8::FunctionTemplate::New(isolate, callback)); 1181 v8::Local<v8::Object> object = 1182 object_template->NewInstance(env.local()).ToLocalChecked(); 1183 CHECK((*env) 1184 ->Global() 1185 ->Set(env.local(), v8_str("callback_object"), object) 1186 .FromJust()); 1187 return scope.Escape(CompileRun("callback_object.callback()")); 1188 } 1189 1190 1191 THREADED_PROFILED_TEST(FastReturnValues) { 1192 LocalContext env; 1193 v8::Isolate* isolate = env->GetIsolate(); 1194 v8::HandleScope scope(isolate); 1195 v8::Local<v8::Value> value; 1196 // check int32_t and uint32_t 1197 int32_t int_values[] = { 1198 0, 234, -723, 1199 i::Smi::kMinValue, i::Smi::kMaxValue 1200 }; 1201 for (size_t i = 0; i < arraysize(int_values); i++) { 1202 for (int modifier = -1; modifier <= 1; modifier++) { 1203 int int_value = int_values[i] + modifier; 1204 // check int32_t 1205 fast_return_value_int32 = int_value; 1206 value = TestFastReturnValues<int32_t>(); 1207 CHECK(value->IsInt32()); 1208 CHECK_EQ(fast_return_value_int32, 1209 value->Int32Value(env.local()).FromJust()); 1210 // check uint32_t 1211 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1212 value = TestFastReturnValues<uint32_t>(); 1213 CHECK(value->IsUint32()); 1214 CHECK_EQ(fast_return_value_uint32, 1215 value->Uint32Value(env.local()).FromJust()); 1216 } 1217 } 1218 // check double 1219 value = TestFastReturnValues<double>(); 1220 CHECK(value->IsNumber()); 1221 CHECK_EQ(kFastReturnValueDouble, 1222 value->ToNumber(env.local()).ToLocalChecked()->Value()); 1223 // check bool values 1224 for (int i = 0; i < 2; i++) { 1225 fast_return_value_bool = i == 0; 1226 value = TestFastReturnValues<bool>(); 1227 CHECK(value->IsBoolean()); 1228 CHECK_EQ(fast_return_value_bool, 1229 value->ToBoolean(env.local()).ToLocalChecked()->Value()); 1230 } 1231 // check oddballs 1232 ReturnValueOddball oddballs[] = { 1233 kNullReturnValue, 1234 kUndefinedReturnValue, 1235 kEmptyStringReturnValue 1236 }; 1237 for (size_t i = 0; i < arraysize(oddballs); i++) { 1238 fast_return_value_void = oddballs[i]; 1239 value = TestFastReturnValues<void>(); 1240 switch (fast_return_value_void) { 1241 case kNullReturnValue: 1242 CHECK(value->IsNull()); 1243 break; 1244 case kUndefinedReturnValue: 1245 CHECK(value->IsUndefined()); 1246 break; 1247 case kEmptyStringReturnValue: 1248 CHECK(value->IsString()); 1249 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1250 break; 1251 } 1252 } 1253 // check handles 1254 fast_return_value_object_is_empty = false; 1255 value = TestFastReturnValues<Object>(); 1256 CHECK(value->IsObject()); 1257 fast_return_value_object_is_empty = true; 1258 value = TestFastReturnValues<Object>(); 1259 CHECK(value->IsUndefined()); 1260 } 1261 1262 1263 THREADED_TEST(FunctionTemplateSetLength) { 1264 LocalContext env; 1265 v8::Isolate* isolate = env->GetIsolate(); 1266 v8::HandleScope scope(isolate); 1267 { 1268 Local<v8::FunctionTemplate> fun_templ = 1269 v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(), 1270 Local<v8::Signature>(), 23); 1271 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1272 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1273 Local<Script> script = v8_compile("obj.length"); 1274 CHECK_EQ(23, v8_run_int32value(script)); 1275 } 1276 { 1277 Local<v8::FunctionTemplate> fun_templ = 1278 v8::FunctionTemplate::New(isolate, handle_callback); 1279 fun_templ->SetLength(22); 1280 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1281 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1282 Local<Script> script = v8_compile("obj.length"); 1283 CHECK_EQ(22, v8_run_int32value(script)); 1284 } 1285 { 1286 // Without setting length it defaults to 0. 1287 Local<v8::FunctionTemplate> fun_templ = 1288 v8::FunctionTemplate::New(isolate, handle_callback); 1289 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1290 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1291 Local<Script> script = v8_compile("obj.length"); 1292 CHECK_EQ(0, v8_run_int32value(script)); 1293 } 1294 } 1295 1296 1297 static void* expected_ptr; 1298 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1299 void* ptr = v8::External::Cast(*args.Data())->Value(); 1300 CHECK_EQ(expected_ptr, ptr); 1301 args.GetReturnValue().Set(true); 1302 } 1303 1304 1305 static void TestExternalPointerWrapping() { 1306 LocalContext env; 1307 v8::Isolate* isolate = env->GetIsolate(); 1308 v8::HandleScope scope(isolate); 1309 1310 v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr); 1311 1312 v8::Local<v8::Object> obj = v8::Object::New(isolate); 1313 CHECK(obj->Set(env.local(), v8_str("func"), 1314 v8::FunctionTemplate::New(isolate, callback, data) 1315 ->GetFunction(env.local()) 1316 .ToLocalChecked()) 1317 .FromJust()); 1318 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust()); 1319 1320 CHECK(CompileRun("function foo() {\n" 1321 " for (var i = 0; i < 13; i++) obj.func();\n" 1322 "}\n" 1323 "foo(), true") 1324 ->BooleanValue(env.local()) 1325 .FromJust()); 1326 } 1327 1328 1329 THREADED_TEST(ExternalWrap) { 1330 // Check heap allocated object. 1331 int* ptr = new int; 1332 expected_ptr = ptr; 1333 TestExternalPointerWrapping(); 1334 delete ptr; 1335 1336 // Check stack allocated object. 1337 int foo; 1338 expected_ptr = &foo; 1339 TestExternalPointerWrapping(); 1340 1341 // Check not aligned addresses. 1342 const int n = 100; 1343 char* s = new char[n]; 1344 for (int i = 0; i < n; i++) { 1345 expected_ptr = s + i; 1346 TestExternalPointerWrapping(); 1347 } 1348 1349 delete[] s; 1350 1351 // Check several invalid addresses. 1352 expected_ptr = reinterpret_cast<void*>(1); 1353 TestExternalPointerWrapping(); 1354 1355 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1356 TestExternalPointerWrapping(); 1357 1358 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1359 TestExternalPointerWrapping(); 1360 1361 #if defined(V8_HOST_ARCH_X64) 1362 // Check a value with a leading 1 bit in x64 Smi encoding. 1363 expected_ptr = reinterpret_cast<void*>(0x400000000); 1364 TestExternalPointerWrapping(); 1365 1366 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1367 TestExternalPointerWrapping(); 1368 1369 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1370 TestExternalPointerWrapping(); 1371 #endif 1372 } 1373 1374 1375 THREADED_TEST(FindInstanceInPrototypeChain) { 1376 LocalContext env; 1377 v8::Isolate* isolate = env->GetIsolate(); 1378 v8::HandleScope scope(isolate); 1379 1380 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate); 1381 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate); 1382 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate); 1383 derived->Inherit(base); 1384 1385 Local<v8::Function> base_function = 1386 base->GetFunction(env.local()).ToLocalChecked(); 1387 Local<v8::Function> derived_function = 1388 derived->GetFunction(env.local()).ToLocalChecked(); 1389 Local<v8::Function> other_function = 1390 other->GetFunction(env.local()).ToLocalChecked(); 1391 1392 Local<v8::Object> base_instance = 1393 base_function->NewInstance(env.local()).ToLocalChecked(); 1394 Local<v8::Object> derived_instance = 1395 derived_function->NewInstance(env.local()).ToLocalChecked(); 1396 Local<v8::Object> derived_instance2 = 1397 derived_function->NewInstance(env.local()).ToLocalChecked(); 1398 Local<v8::Object> other_instance = 1399 other_function->NewInstance(env.local()).ToLocalChecked(); 1400 CHECK( 1401 derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance) 1402 .FromJust()); 1403 CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2) 1404 .FromJust()); 1405 1406 // base_instance is only an instance of base. 1407 CHECK(base_instance->Equals(env.local(), 1408 base_instance->FindInstanceInPrototypeChain(base)) 1409 .FromJust()); 1410 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1411 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1412 1413 // derived_instance is an instance of base and derived. 1414 CHECK(derived_instance->Equals(env.local(), 1415 derived_instance->FindInstanceInPrototypeChain( 1416 base)) 1417 .FromJust()); 1418 CHECK(derived_instance->Equals(env.local(), 1419 derived_instance->FindInstanceInPrototypeChain( 1420 derived)) 1421 .FromJust()); 1422 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1423 1424 // other_instance is an instance of other and its immediate 1425 // prototype derived_instance2 is an instance of base and derived. 1426 // Note, derived_instance is an instance of base and derived too, 1427 // but it comes after derived_instance2 in the prototype chain of 1428 // other_instance. 1429 CHECK(derived_instance2->Equals( 1430 env.local(), 1431 other_instance->FindInstanceInPrototypeChain(base)) 1432 .FromJust()); 1433 CHECK(derived_instance2->Equals(env.local(), 1434 other_instance->FindInstanceInPrototypeChain( 1435 derived)) 1436 .FromJust()); 1437 CHECK(other_instance->Equals( 1438 env.local(), 1439 other_instance->FindInstanceInPrototypeChain(other)) 1440 .FromJust()); 1441 } 1442 1443 1444 THREADED_TEST(TinyInteger) { 1445 LocalContext env; 1446 v8::Isolate* isolate = env->GetIsolate(); 1447 v8::HandleScope scope(isolate); 1448 1449 int32_t value = 239; 1450 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1451 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1452 1453 value_obj = v8::Integer::New(isolate, value); 1454 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1455 } 1456 1457 1458 THREADED_TEST(BigSmiInteger) { 1459 LocalContext env; 1460 v8::HandleScope scope(env->GetIsolate()); 1461 v8::Isolate* isolate = CcTest::isolate(); 1462 1463 int32_t value = i::Smi::kMaxValue; 1464 // We cannot add one to a Smi::kMaxValue without wrapping. 1465 if (i::SmiValuesAre31Bits()) { 1466 CHECK(i::Smi::IsValid(value)); 1467 CHECK(!i::Smi::IsValid(value + 1)); 1468 1469 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1470 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1471 1472 value_obj = v8::Integer::New(isolate, value); 1473 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1474 } 1475 } 1476 1477 1478 THREADED_TEST(BigInteger) { 1479 LocalContext env; 1480 v8::HandleScope scope(env->GetIsolate()); 1481 v8::Isolate* isolate = CcTest::isolate(); 1482 1483 // We cannot add one to a Smi::kMaxValue without wrapping. 1484 if (i::SmiValuesAre31Bits()) { 1485 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1486 // The code will not be run in that case, due to the "if" guard. 1487 int32_t value = 1488 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1489 CHECK(value > i::Smi::kMaxValue); 1490 CHECK(!i::Smi::IsValid(value)); 1491 1492 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1493 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1494 1495 value_obj = v8::Integer::New(isolate, value); 1496 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1497 } 1498 } 1499 1500 1501 THREADED_TEST(TinyUnsignedInteger) { 1502 LocalContext env; 1503 v8::HandleScope scope(env->GetIsolate()); 1504 v8::Isolate* isolate = CcTest::isolate(); 1505 1506 uint32_t value = 239; 1507 1508 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1509 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1510 1511 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1512 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1513 } 1514 1515 1516 THREADED_TEST(BigUnsignedSmiInteger) { 1517 LocalContext env; 1518 v8::HandleScope scope(env->GetIsolate()); 1519 v8::Isolate* isolate = CcTest::isolate(); 1520 1521 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1522 CHECK(i::Smi::IsValid(value)); 1523 CHECK(!i::Smi::IsValid(value + 1)); 1524 1525 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1526 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1527 1528 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1529 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1530 } 1531 1532 1533 THREADED_TEST(BigUnsignedInteger) { 1534 LocalContext env; 1535 v8::HandleScope scope(env->GetIsolate()); 1536 v8::Isolate* isolate = CcTest::isolate(); 1537 1538 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1539 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1540 CHECK(!i::Smi::IsValid(value)); 1541 1542 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1543 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1544 1545 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1546 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1547 } 1548 1549 1550 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1551 LocalContext env; 1552 v8::HandleScope scope(env->GetIsolate()); 1553 v8::Isolate* isolate = CcTest::isolate(); 1554 1555 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1556 uint32_t value = INT32_MAX_AS_UINT + 1; 1557 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1558 1559 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1560 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1561 1562 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1563 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1564 } 1565 1566 1567 THREADED_TEST(IsNativeError) { 1568 LocalContext env; 1569 v8::HandleScope scope(env->GetIsolate()); 1570 v8::Local<Value> syntax_error = CompileRun( 1571 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1572 CHECK(syntax_error->IsNativeError()); 1573 v8::Local<Value> not_error = CompileRun("{a:42}"); 1574 CHECK(!not_error->IsNativeError()); 1575 v8::Local<Value> not_object = CompileRun("42"); 1576 CHECK(!not_object->IsNativeError()); 1577 } 1578 1579 1580 THREADED_TEST(IsGeneratorFunctionOrObject) { 1581 LocalContext env; 1582 v8::HandleScope scope(env->GetIsolate()); 1583 1584 CompileRun("function *gen() { yield 1; }\nfunction func() {}"); 1585 v8::Local<Value> gen = CompileRun("gen"); 1586 v8::Local<Value> genObj = CompileRun("gen()"); 1587 v8::Local<Value> object = CompileRun("{a:42}"); 1588 v8::Local<Value> func = CompileRun("func"); 1589 1590 CHECK(gen->IsGeneratorFunction()); 1591 CHECK(gen->IsFunction()); 1592 CHECK(!gen->IsGeneratorObject()); 1593 1594 CHECK(!genObj->IsGeneratorFunction()); 1595 CHECK(!genObj->IsFunction()); 1596 CHECK(genObj->IsGeneratorObject()); 1597 1598 CHECK(!object->IsGeneratorFunction()); 1599 CHECK(!object->IsFunction()); 1600 CHECK(!object->IsGeneratorObject()); 1601 1602 CHECK(!func->IsGeneratorFunction()); 1603 CHECK(func->IsFunction()); 1604 CHECK(!func->IsGeneratorObject()); 1605 } 1606 1607 1608 THREADED_TEST(ArgumentsObject) { 1609 LocalContext env; 1610 v8::HandleScope scope(env->GetIsolate()); 1611 v8::Local<Value> arguments_object = 1612 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;"); 1613 CHECK(arguments_object->IsArgumentsObject()); 1614 v8::Local<Value> array = CompileRun("[1,2,3]"); 1615 CHECK(!array->IsArgumentsObject()); 1616 v8::Local<Value> object = CompileRun("{a:42}"); 1617 CHECK(!object->IsArgumentsObject()); 1618 } 1619 1620 1621 THREADED_TEST(IsMapOrSet) { 1622 LocalContext env; 1623 v8::HandleScope scope(env->GetIsolate()); 1624 v8::Local<Value> map = CompileRun("new Map()"); 1625 v8::Local<Value> set = CompileRun("new Set()"); 1626 v8::Local<Value> weak_map = CompileRun("new WeakMap()"); 1627 v8::Local<Value> weak_set = CompileRun("new WeakSet()"); 1628 CHECK(map->IsMap()); 1629 CHECK(set->IsSet()); 1630 CHECK(weak_map->IsWeakMap()); 1631 CHECK(weak_set->IsWeakSet()); 1632 1633 CHECK(!map->IsSet()); 1634 CHECK(!map->IsWeakMap()); 1635 CHECK(!map->IsWeakSet()); 1636 1637 CHECK(!set->IsMap()); 1638 CHECK(!set->IsWeakMap()); 1639 CHECK(!set->IsWeakSet()); 1640 1641 CHECK(!weak_map->IsMap()); 1642 CHECK(!weak_map->IsSet()); 1643 CHECK(!weak_map->IsWeakSet()); 1644 1645 CHECK(!weak_set->IsMap()); 1646 CHECK(!weak_set->IsSet()); 1647 CHECK(!weak_set->IsWeakMap()); 1648 1649 v8::Local<Value> object = CompileRun("{a:42}"); 1650 CHECK(!object->IsMap()); 1651 CHECK(!object->IsSet()); 1652 CHECK(!object->IsWeakMap()); 1653 CHECK(!object->IsWeakSet()); 1654 } 1655 1656 1657 THREADED_TEST(StringObject) { 1658 LocalContext env; 1659 v8::HandleScope scope(env->GetIsolate()); 1660 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")"); 1661 CHECK(boxed_string->IsStringObject()); 1662 v8::Local<Value> unboxed_string = CompileRun("\"test\""); 1663 CHECK(!unboxed_string->IsStringObject()); 1664 v8::Local<Value> boxed_not_string = CompileRun("new Number(42)"); 1665 CHECK(!boxed_not_string->IsStringObject()); 1666 v8::Local<Value> not_object = CompileRun("0"); 1667 CHECK(!not_object->IsStringObject()); 1668 v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1669 CHECK(!as_boxed.IsEmpty()); 1670 Local<v8::String> the_string = as_boxed->ValueOf(); 1671 CHECK(!the_string.IsEmpty()); 1672 ExpectObject("\"test\"", the_string); 1673 v8::Local<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1674 CHECK(new_boxed_string->IsStringObject()); 1675 as_boxed = new_boxed_string.As<v8::StringObject>(); 1676 the_string = as_boxed->ValueOf(); 1677 CHECK(!the_string.IsEmpty()); 1678 ExpectObject("\"test\"", the_string); 1679 } 1680 1681 1682 TEST(StringObjectDelete) { 1683 LocalContext context; 1684 v8::HandleScope scope(context->GetIsolate()); 1685 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")"); 1686 CHECK(boxed_string->IsStringObject()); 1687 v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>(); 1688 CHECK(!str_obj->Delete(context.local(), 2).FromJust()); 1689 CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust()); 1690 } 1691 1692 1693 THREADED_TEST(NumberObject) { 1694 LocalContext env; 1695 v8::HandleScope scope(env->GetIsolate()); 1696 v8::Local<Value> boxed_number = CompileRun("new Number(42)"); 1697 CHECK(boxed_number->IsNumberObject()); 1698 v8::Local<Value> unboxed_number = CompileRun("42"); 1699 CHECK(!unboxed_number->IsNumberObject()); 1700 v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1701 CHECK(!boxed_not_number->IsNumberObject()); 1702 v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1703 CHECK(!as_boxed.IsEmpty()); 1704 double the_number = as_boxed->ValueOf(); 1705 CHECK_EQ(42.0, the_number); 1706 v8::Local<v8::Value> new_boxed_number = 1707 v8::NumberObject::New(env->GetIsolate(), 43); 1708 CHECK(new_boxed_number->IsNumberObject()); 1709 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1710 the_number = as_boxed->ValueOf(); 1711 CHECK_EQ(43.0, the_number); 1712 } 1713 1714 1715 THREADED_TEST(BooleanObject) { 1716 LocalContext env; 1717 v8::HandleScope scope(env->GetIsolate()); 1718 v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1719 CHECK(boxed_boolean->IsBooleanObject()); 1720 v8::Local<Value> unboxed_boolean = CompileRun("true"); 1721 CHECK(!unboxed_boolean->IsBooleanObject()); 1722 v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1723 CHECK(!boxed_not_boolean->IsBooleanObject()); 1724 v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>(); 1725 CHECK(!as_boxed.IsEmpty()); 1726 bool the_boolean = as_boxed->ValueOf(); 1727 CHECK_EQ(true, the_boolean); 1728 v8::Local<v8::Value> boxed_true = 1729 v8::BooleanObject::New(env->GetIsolate(), true); 1730 v8::Local<v8::Value> boxed_false = 1731 v8::BooleanObject::New(env->GetIsolate(), false); 1732 CHECK(boxed_true->IsBooleanObject()); 1733 CHECK(boxed_false->IsBooleanObject()); 1734 as_boxed = boxed_true.As<v8::BooleanObject>(); 1735 CHECK_EQ(true, as_boxed->ValueOf()); 1736 as_boxed = boxed_false.As<v8::BooleanObject>(); 1737 CHECK_EQ(false, as_boxed->ValueOf()); 1738 } 1739 1740 1741 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1742 LocalContext env; 1743 v8::HandleScope scope(env->GetIsolate()); 1744 1745 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); 1746 CHECK(primitive_false->IsBoolean()); 1747 CHECK(!primitive_false->IsBooleanObject()); 1748 CHECK(!primitive_false->BooleanValue(env.local()).FromJust()); 1749 CHECK(!primitive_false->IsTrue()); 1750 CHECK(primitive_false->IsFalse()); 1751 1752 Local<Value> false_value = BooleanObject::New(env->GetIsolate(), false); 1753 CHECK(!false_value->IsBoolean()); 1754 CHECK(false_value->IsBooleanObject()); 1755 CHECK(false_value->BooleanValue(env.local()).FromJust()); 1756 CHECK(!false_value->IsTrue()); 1757 CHECK(!false_value->IsFalse()); 1758 1759 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1760 CHECK(!false_boolean_object->IsBoolean()); 1761 CHECK(false_boolean_object->IsBooleanObject()); 1762 CHECK(false_boolean_object->BooleanValue(env.local()).FromJust()); 1763 CHECK(!false_boolean_object->ValueOf()); 1764 CHECK(!false_boolean_object->IsTrue()); 1765 CHECK(!false_boolean_object->IsFalse()); 1766 1767 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); 1768 CHECK(primitive_true->IsBoolean()); 1769 CHECK(!primitive_true->IsBooleanObject()); 1770 CHECK(primitive_true->BooleanValue(env.local()).FromJust()); 1771 CHECK(primitive_true->IsTrue()); 1772 CHECK(!primitive_true->IsFalse()); 1773 1774 Local<Value> true_value = BooleanObject::New(env->GetIsolate(), true); 1775 CHECK(!true_value->IsBoolean()); 1776 CHECK(true_value->IsBooleanObject()); 1777 CHECK(true_value->BooleanValue(env.local()).FromJust()); 1778 CHECK(!true_value->IsTrue()); 1779 CHECK(!true_value->IsFalse()); 1780 1781 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1782 CHECK(!true_boolean_object->IsBoolean()); 1783 CHECK(true_boolean_object->IsBooleanObject()); 1784 CHECK(true_boolean_object->BooleanValue(env.local()).FromJust()); 1785 CHECK(true_boolean_object->ValueOf()); 1786 CHECK(!true_boolean_object->IsTrue()); 1787 CHECK(!true_boolean_object->IsFalse()); 1788 } 1789 1790 1791 THREADED_TEST(Number) { 1792 LocalContext env; 1793 v8::HandleScope scope(env->GetIsolate()); 1794 double PI = 3.1415926; 1795 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI); 1796 CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust()); 1797 } 1798 1799 1800 THREADED_TEST(ToNumber) { 1801 LocalContext env; 1802 v8::Isolate* isolate = CcTest::isolate(); 1803 v8::HandleScope scope(isolate); 1804 Local<String> str = v8_str("3.1415926"); 1805 CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust()); 1806 v8::Local<v8::Boolean> t = v8::True(isolate); 1807 CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust()); 1808 v8::Local<v8::Boolean> f = v8::False(isolate); 1809 CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust()); 1810 } 1811 1812 1813 THREADED_TEST(Date) { 1814 LocalContext env; 1815 v8::HandleScope scope(env->GetIsolate()); 1816 double PI = 3.1415926; 1817 Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked(); 1818 CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust()); 1819 CHECK(date.As<v8::Date>() 1820 ->Set(env.local(), v8_str("property"), 1821 v8::Integer::New(env->GetIsolate(), 42)) 1822 .FromJust()); 1823 CHECK_EQ(42, date.As<v8::Date>() 1824 ->Get(env.local(), v8_str("property")) 1825 .ToLocalChecked() 1826 ->Int32Value(env.local()) 1827 .FromJust()); 1828 } 1829 1830 1831 THREADED_TEST(Boolean) { 1832 LocalContext env; 1833 v8::Isolate* isolate = env->GetIsolate(); 1834 v8::HandleScope scope(isolate); 1835 v8::Local<v8::Boolean> t = v8::True(isolate); 1836 CHECK(t->Value()); 1837 v8::Local<v8::Boolean> f = v8::False(isolate); 1838 CHECK(!f->Value()); 1839 v8::Local<v8::Primitive> u = v8::Undefined(isolate); 1840 CHECK(!u->BooleanValue(env.local()).FromJust()); 1841 v8::Local<v8::Primitive> n = v8::Null(isolate); 1842 CHECK(!n->BooleanValue(env.local()).FromJust()); 1843 v8::Local<String> str1 = v8_str(""); 1844 CHECK(!str1->BooleanValue(env.local()).FromJust()); 1845 v8::Local<String> str2 = v8_str("x"); 1846 CHECK(str2->BooleanValue(env.local()).FromJust()); 1847 CHECK(!v8::Number::New(isolate, 0)->BooleanValue(env.local()).FromJust()); 1848 CHECK(v8::Number::New(isolate, -1)->BooleanValue(env.local()).FromJust()); 1849 CHECK(v8::Number::New(isolate, 1)->BooleanValue(env.local()).FromJust()); 1850 CHECK(v8::Number::New(isolate, 42)->BooleanValue(env.local()).FromJust()); 1851 CHECK(!v8_compile("NaN") 1852 ->Run(env.local()) 1853 .ToLocalChecked() 1854 ->BooleanValue(env.local()) 1855 .FromJust()); 1856 } 1857 1858 1859 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1860 ApiTestFuzzer::Fuzz(); 1861 args.GetReturnValue().Set(v8_num(13.4)); 1862 } 1863 1864 1865 static void GetM(Local<String> name, 1866 const v8::PropertyCallbackInfo<v8::Value>& info) { 1867 ApiTestFuzzer::Fuzz(); 1868 info.GetReturnValue().Set(v8_num(876)); 1869 } 1870 1871 1872 THREADED_TEST(GlobalPrototype) { 1873 v8::Isolate* isolate = CcTest::isolate(); 1874 v8::HandleScope scope(isolate); 1875 v8::Local<v8::FunctionTemplate> func_templ = 1876 v8::FunctionTemplate::New(isolate); 1877 func_templ->PrototypeTemplate()->Set( 1878 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler)); 1879 v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1880 templ->Set(isolate, "x", v8_num(200)); 1881 templ->SetAccessor(v8_str("m"), GetM); 1882 LocalContext env(0, templ); 1883 v8::Local<Script> script(v8_compile("dummy()")); 1884 v8::Local<Value> result(script->Run(env.local()).ToLocalChecked()); 1885 CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust()); 1886 CHECK_EQ(200, v8_run_int32value(v8_compile("x"))); 1887 CHECK_EQ(876, v8_run_int32value(v8_compile("m"))); 1888 } 1889 1890 1891 THREADED_TEST(ObjectTemplate) { 1892 v8::Isolate* isolate = CcTest::isolate(); 1893 v8::HandleScope scope(isolate); 1894 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 1895 v8::Local<v8::String> class_name = v8_str("the_class_name"); 1896 fun->SetClassName(class_name); 1897 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun); 1898 templ1->Set(isolate, "x", v8_num(10)); 1899 templ1->Set(isolate, "y", v8_num(13)); 1900 LocalContext env; 1901 Local<v8::Object> instance1 = 1902 templ1->NewInstance(env.local()).ToLocalChecked(); 1903 CHECK(class_name->StrictEquals(instance1->GetConstructorName())); 1904 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust()); 1905 CHECK(v8_compile("(p.x == 10)") 1906 ->Run(env.local()) 1907 .ToLocalChecked() 1908 ->BooleanValue(env.local()) 1909 .FromJust()); 1910 CHECK(v8_compile("(p.y == 13)") 1911 ->Run(env.local()) 1912 .ToLocalChecked() 1913 ->BooleanValue(env.local()) 1914 .FromJust()); 1915 Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate); 1916 fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); 1917 Local<ObjectTemplate> templ2 = fun2->InstanceTemplate(); 1918 templ2->Set(isolate, "a", v8_num(12)); 1919 templ2->Set(isolate, "b", templ1); 1920 Local<v8::Object> instance2 = 1921 templ2->NewInstance(env.local()).ToLocalChecked(); 1922 CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust()); 1923 CHECK(v8_compile("(q.nirk == 123)") 1924 ->Run(env.local()) 1925 .ToLocalChecked() 1926 ->BooleanValue(env.local()) 1927 .FromJust()); 1928 CHECK(v8_compile("(q.a == 12)") 1929 ->Run(env.local()) 1930 .ToLocalChecked() 1931 ->BooleanValue(env.local()) 1932 .FromJust()); 1933 CHECK(v8_compile("(q.b.x == 10)") 1934 ->Run(env.local()) 1935 .ToLocalChecked() 1936 ->BooleanValue(env.local()) 1937 .FromJust()); 1938 CHECK(v8_compile("(q.b.y == 13)") 1939 ->Run(env.local()) 1940 .ToLocalChecked() 1941 ->BooleanValue(env.local()) 1942 .FromJust()); 1943 } 1944 1945 1946 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 1947 ApiTestFuzzer::Fuzz(); 1948 args.GetReturnValue().Set(v8_num(17.2)); 1949 } 1950 1951 1952 static void GetKnurd(Local<String> property, 1953 const v8::PropertyCallbackInfo<v8::Value>& info) { 1954 ApiTestFuzzer::Fuzz(); 1955 info.GetReturnValue().Set(v8_num(15.2)); 1956 } 1957 1958 1959 THREADED_TEST(DescriptorInheritance) { 1960 v8::Isolate* isolate = CcTest::isolate(); 1961 v8::HandleScope scope(isolate); 1962 v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate); 1963 super->PrototypeTemplate()->Set(isolate, "flabby", 1964 v8::FunctionTemplate::New(isolate, 1965 GetFlabby)); 1966 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14)); 1967 1968 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1969 1970 v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate); 1971 base1->Inherit(super); 1972 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1)); 1973 1974 v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate); 1975 base2->Inherit(super); 1976 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1)); 1977 1978 LocalContext env; 1979 1980 CHECK(env->Global() 1981 ->Set(env.local(), v8_str("s"), 1982 super->GetFunction(env.local()).ToLocalChecked()) 1983 .FromJust()); 1984 CHECK(env->Global() 1985 ->Set(env.local(), v8_str("base1"), 1986 base1->GetFunction(env.local()).ToLocalChecked()) 1987 .FromJust()); 1988 CHECK(env->Global() 1989 ->Set(env.local(), v8_str("base2"), 1990 base2->GetFunction(env.local()).ToLocalChecked()) 1991 .FromJust()); 1992 1993 // Checks right __proto__ chain. 1994 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype") 1995 ->BooleanValue(env.local()) 1996 .FromJust()); 1997 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype") 1998 ->BooleanValue(env.local()) 1999 .FromJust()); 2000 2001 CHECK(v8_compile("s.prototype.PI == 3.14") 2002 ->Run(env.local()) 2003 .ToLocalChecked() 2004 ->BooleanValue(env.local()) 2005 .FromJust()); 2006 2007 // Instance accessor should not be visible on function object or its prototype 2008 CHECK( 2009 CompileRun("s.knurd == undefined")->BooleanValue(env.local()).FromJust()); 2010 CHECK(CompileRun("s.prototype.knurd == undefined") 2011 ->BooleanValue(env.local()) 2012 .FromJust()); 2013 CHECK(CompileRun("base1.prototype.knurd == undefined") 2014 ->BooleanValue(env.local()) 2015 .FromJust()); 2016 2017 CHECK(env->Global() 2018 ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local()) 2019 .ToLocalChecked() 2020 ->NewInstance(env.local()) 2021 .ToLocalChecked()) 2022 .FromJust()); 2023 CHECK_EQ(17.2, v8_compile("obj.flabby()") 2024 ->Run(env.local()) 2025 .ToLocalChecked() 2026 ->NumberValue(env.local()) 2027 .FromJust()); 2028 CHECK(v8_compile("'flabby' in obj") 2029 ->Run(env.local()) 2030 .ToLocalChecked() 2031 ->BooleanValue(env.local()) 2032 .FromJust()); 2033 CHECK_EQ(15.2, v8_compile("obj.knurd") 2034 ->Run(env.local()) 2035 .ToLocalChecked() 2036 ->NumberValue(env.local()) 2037 .FromJust()); 2038 CHECK(v8_compile("'knurd' in obj") 2039 ->Run(env.local()) 2040 .ToLocalChecked() 2041 ->BooleanValue(env.local()) 2042 .FromJust()); 2043 CHECK_EQ(20.1, v8_compile("obj.v1") 2044 ->Run(env.local()) 2045 .ToLocalChecked() 2046 ->NumberValue(env.local()) 2047 .FromJust()); 2048 2049 CHECK(env->Global() 2050 ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local()) 2051 .ToLocalChecked() 2052 ->NewInstance(env.local()) 2053 .ToLocalChecked()) 2054 .FromJust()); 2055 CHECK_EQ(17.2, v8_compile("obj2.flabby()") 2056 ->Run(env.local()) 2057 .ToLocalChecked() 2058 ->NumberValue(env.local()) 2059 .FromJust()); 2060 CHECK(v8_compile("'flabby' in obj2") 2061 ->Run(env.local()) 2062 .ToLocalChecked() 2063 ->BooleanValue(env.local()) 2064 .FromJust()); 2065 CHECK_EQ(15.2, v8_compile("obj2.knurd") 2066 ->Run(env.local()) 2067 .ToLocalChecked() 2068 ->NumberValue(env.local()) 2069 .FromJust()); 2070 CHECK(v8_compile("'knurd' in obj2") 2071 ->Run(env.local()) 2072 .ToLocalChecked() 2073 ->BooleanValue(env.local()) 2074 .FromJust()); 2075 CHECK_EQ(10.1, v8_compile("obj2.v2") 2076 ->Run(env.local()) 2077 .ToLocalChecked() 2078 ->NumberValue(env.local()) 2079 .FromJust()); 2080 2081 // base1 and base2 cannot cross reference to each's prototype 2082 CHECK(v8_compile("obj.v2")->Run(env.local()).ToLocalChecked()->IsUndefined()); 2083 CHECK( 2084 v8_compile("obj2.v1")->Run(env.local()).ToLocalChecked()->IsUndefined()); 2085 } 2086 2087 2088 // Helper functions for Interceptor/Accessor interaction tests 2089 2090 void SimpleAccessorGetter(Local<String> name, 2091 const v8::PropertyCallbackInfo<v8::Value>& info) { 2092 Local<Object> self = Local<Object>::Cast(info.This()); 2093 info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(), 2094 String::Concat(v8_str("accessor_"), name)) 2095 .ToLocalChecked()); 2096 } 2097 2098 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 2099 const v8::PropertyCallbackInfo<void>& info) { 2100 Local<Object> self = Local<Object>::Cast(info.This()); 2101 CHECK(self->Set(info.GetIsolate()->GetCurrentContext(), 2102 String::Concat(v8_str("accessor_"), name), value) 2103 .FromJust()); 2104 } 2105 2106 void SymbolAccessorGetter(Local<Name> name, 2107 const v8::PropertyCallbackInfo<v8::Value>& info) { 2108 CHECK(name->IsSymbol()); 2109 Local<Symbol> sym = Local<Symbol>::Cast(name); 2110 if (sym->Name()->IsUndefined()) 2111 return; 2112 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info); 2113 } 2114 2115 void SymbolAccessorSetter(Local<Name> name, Local<Value> value, 2116 const v8::PropertyCallbackInfo<void>& info) { 2117 CHECK(name->IsSymbol()); 2118 Local<Symbol> sym = Local<Symbol>::Cast(name); 2119 if (sym->Name()->IsUndefined()) 2120 return; 2121 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info); 2122 } 2123 2124 void SymbolAccessorGetterReturnsDefault( 2125 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 2126 CHECK(name->IsSymbol()); 2127 Local<Symbol> sym = Local<Symbol>::Cast(name); 2128 if (sym->Name()->IsUndefined()) return; 2129 info.GetReturnValue().Set(info.Data()); 2130 } 2131 2132 static void ThrowingSymbolAccessorGetter( 2133 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 2134 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name)); 2135 } 2136 2137 2138 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { 2139 v8::Isolate* isolate = CcTest::isolate(); 2140 v8::HandleScope scope(isolate); 2141 LocalContext env; 2142 v8::Local<v8::Value> res = CompileRun("var a = []; a;"); 2143 i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); 2144 CHECK(a->map()->instance_descriptors()->IsFixedArray()); 2145 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2146 CompileRun("Object.defineProperty(a, 'length', { writable: false });"); 2147 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2148 // But we should still have an ExecutableAccessorInfo. 2149 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); 2150 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR); 2151 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state()); 2152 CHECK(it.GetAccessors()->IsExecutableAccessorInfo()); 2153 } 2154 2155 2156 THREADED_TEST(UndefinedIsNotEnumerable) { 2157 LocalContext env; 2158 v8::HandleScope scope(env->GetIsolate()); 2159 v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)"); 2160 CHECK(result->IsFalse()); 2161 } 2162 2163 2164 v8::Local<Script> call_recursively_script; 2165 static const int kTargetRecursionDepth = 150; // near maximum 2166 2167 2168 static void CallScriptRecursivelyCall( 2169 const v8::FunctionCallbackInfo<v8::Value>& args) { 2170 ApiTestFuzzer::Fuzz(); 2171 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 2172 int depth = args.This() 2173 ->Get(context, v8_str("depth")) 2174 .ToLocalChecked() 2175 ->Int32Value(context) 2176 .FromJust(); 2177 if (depth == kTargetRecursionDepth) return; 2178 CHECK(args.This() 2179 ->Set(context, v8_str("depth"), 2180 v8::Integer::New(args.GetIsolate(), depth + 1)) 2181 .FromJust()); 2182 args.GetReturnValue().Set( 2183 call_recursively_script->Run(context).ToLocalChecked()); 2184 } 2185 2186 2187 static void CallFunctionRecursivelyCall( 2188 const v8::FunctionCallbackInfo<v8::Value>& args) { 2189 ApiTestFuzzer::Fuzz(); 2190 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 2191 int depth = args.This() 2192 ->Get(context, v8_str("depth")) 2193 .ToLocalChecked() 2194 ->Int32Value(context) 2195 .FromJust(); 2196 if (depth == kTargetRecursionDepth) { 2197 printf("[depth = %d]\n", depth); 2198 return; 2199 } 2200 CHECK(args.This() 2201 ->Set(context, v8_str("depth"), 2202 v8::Integer::New(args.GetIsolate(), depth + 1)) 2203 .FromJust()); 2204 v8::Local<Value> function = 2205 args.This() 2206 ->Get(context, v8_str("callFunctionRecursively")) 2207 .ToLocalChecked(); 2208 args.GetReturnValue().Set(function.As<Function>() 2209 ->Call(context, args.This(), 0, NULL) 2210 .ToLocalChecked()); 2211 } 2212 2213 2214 THREADED_TEST(DeepCrossLanguageRecursion) { 2215 v8::Isolate* isolate = CcTest::isolate(); 2216 v8::HandleScope scope(isolate); 2217 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 2218 global->Set(v8_str("callScriptRecursively"), 2219 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall)); 2220 global->Set(v8_str("callFunctionRecursively"), 2221 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall)); 2222 LocalContext env(NULL, global); 2223 2224 CHECK(env->Global() 2225 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0)) 2226 .FromJust()); 2227 call_recursively_script = v8_compile("callScriptRecursively()"); 2228 call_recursively_script->Run(env.local()).ToLocalChecked(); 2229 call_recursively_script = v8::Local<Script>(); 2230 2231 CHECK(env->Global() 2232 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0)) 2233 .FromJust()); 2234 CompileRun("callFunctionRecursively()"); 2235 } 2236 2237 2238 static void ThrowingPropertyHandlerGet( 2239 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { 2240 // Since this interceptor is used on "with" objects, the runtime will look up 2241 // @@unscopables. Punt. 2242 if (key->IsSymbol()) return; 2243 ApiTestFuzzer::Fuzz(); 2244 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key)); 2245 } 2246 2247 2248 static void ThrowingPropertyHandlerSet( 2249 Local<Name> key, Local<Value>, 2250 const v8::PropertyCallbackInfo<v8::Value>& info) { 2251 info.GetIsolate()->ThrowException(key); 2252 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2253 } 2254 2255 2256 THREADED_TEST(CallbackExceptionRegression) { 2257 v8::Isolate* isolate = CcTest::isolate(); 2258 v8::HandleScope scope(isolate); 2259 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 2260 obj->SetHandler(v8::NamedPropertyHandlerConfiguration( 2261 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet)); 2262 LocalContext env; 2263 CHECK(env->Global() 2264 ->Set(env.local(), v8_str("obj"), 2265 obj->NewInstance(env.local()).ToLocalChecked()) 2266 .FromJust()); 2267 v8::Local<Value> otto = 2268 CompileRun("try { with (obj) { otto; } } catch (e) { e; }"); 2269 CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust()); 2270 v8::Local<Value> netto = 2271 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }"); 2272 CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust()); 2273 } 2274 2275 2276 THREADED_TEST(FunctionPrototype) { 2277 v8::Isolate* isolate = CcTest::isolate(); 2278 v8::HandleScope scope(isolate); 2279 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate); 2280 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2281 LocalContext env; 2282 CHECK(env->Global() 2283 ->Set(env.local(), v8_str("Foo"), 2284 Foo->GetFunction(env.local()).ToLocalChecked()) 2285 .FromJust()); 2286 Local<Script> script = v8_compile("Foo.prototype.plak"); 2287 CHECK_EQ(v8_run_int32value(script), 321); 2288 } 2289 2290 2291 THREADED_TEST(InternalFields) { 2292 LocalContext env; 2293 v8::Isolate* isolate = env->GetIsolate(); 2294 v8::HandleScope scope(isolate); 2295 2296 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2297 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2298 instance_templ->SetInternalFieldCount(1); 2299 Local<v8::Object> obj = templ->GetFunction(env.local()) 2300 .ToLocalChecked() 2301 ->NewInstance(env.local()) 2302 .ToLocalChecked(); 2303 CHECK_EQ(1, obj->InternalFieldCount()); 2304 CHECK(obj->GetInternalField(0)->IsUndefined()); 2305 obj->SetInternalField(0, v8_num(17)); 2306 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust()); 2307 } 2308 2309 2310 THREADED_TEST(GlobalObjectInternalFields) { 2311 v8::Isolate* isolate = CcTest::isolate(); 2312 v8::HandleScope scope(isolate); 2313 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 2314 global_template->SetInternalFieldCount(1); 2315 LocalContext env(NULL, global_template); 2316 v8::Local<v8::Object> global_proxy = env->Global(); 2317 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2318 CHECK_EQ(1, global->InternalFieldCount()); 2319 CHECK(global->GetInternalField(0)->IsUndefined()); 2320 global->SetInternalField(0, v8_num(17)); 2321 CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust()); 2322 } 2323 2324 2325 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2326 LocalContext env; 2327 v8::HandleScope scope(CcTest::isolate()); 2328 2329 v8::Local<v8::Object> global = env->Global(); 2330 CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust()); 2331 CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust()); 2332 } 2333 2334 2335 static void CheckAlignedPointerInInternalField(Local<v8::Object> obj, 2336 void* value) { 2337 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2338 obj->SetAlignedPointerInInternalField(0, value); 2339 CcTest::heap()->CollectAllGarbage(); 2340 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2341 } 2342 2343 2344 THREADED_TEST(InternalFieldsAlignedPointers) { 2345 LocalContext env; 2346 v8::Isolate* isolate = env->GetIsolate(); 2347 v8::HandleScope scope(isolate); 2348 2349 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2350 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2351 instance_templ->SetInternalFieldCount(1); 2352 Local<v8::Object> obj = templ->GetFunction(env.local()) 2353 .ToLocalChecked() 2354 ->NewInstance(env.local()) 2355 .ToLocalChecked(); 2356 CHECK_EQ(1, obj->InternalFieldCount()); 2357 2358 CheckAlignedPointerInInternalField(obj, NULL); 2359 2360 int* heap_allocated = new int[100]; 2361 CheckAlignedPointerInInternalField(obj, heap_allocated); 2362 delete[] heap_allocated; 2363 2364 int stack_allocated[100]; 2365 CheckAlignedPointerInInternalField(obj, stack_allocated); 2366 2367 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2368 CheckAlignedPointerInInternalField(obj, huge); 2369 2370 v8::Global<v8::Object> persistent(isolate, obj); 2371 CHECK_EQ(1, Object::InternalFieldCount(persistent)); 2372 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0)); 2373 } 2374 2375 2376 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index, 2377 void* value) { 2378 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2379 (*env)->SetAlignedPointerInEmbedderData(index, value); 2380 CcTest::heap()->CollectAllGarbage(); 2381 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2382 } 2383 2384 2385 static void* AlignedTestPointer(int i) { 2386 return reinterpret_cast<void*>(i * 1234); 2387 } 2388 2389 2390 THREADED_TEST(EmbedderDataAlignedPointers) { 2391 LocalContext env; 2392 v8::HandleScope scope(env->GetIsolate()); 2393 2394 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2395 2396 int* heap_allocated = new int[100]; 2397 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2398 delete[] heap_allocated; 2399 2400 int stack_allocated[100]; 2401 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2402 2403 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2404 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2405 2406 // Test growing of the embedder data's backing store. 2407 for (int i = 0; i < 100; i++) { 2408 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2409 } 2410 CcTest::heap()->CollectAllGarbage(); 2411 for (int i = 0; i < 100; i++) { 2412 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2413 } 2414 } 2415 2416 2417 static void CheckEmbedderData(LocalContext* env, int index, 2418 v8::Local<Value> data) { 2419 (*env)->SetEmbedderData(index, data); 2420 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2421 } 2422 2423 2424 THREADED_TEST(EmbedderData) { 2425 LocalContext env; 2426 v8::Isolate* isolate = env->GetIsolate(); 2427 v8::HandleScope scope(isolate); 2428 2429 CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps")); 2430 CheckEmbedderData(&env, 2, v8_str("over the lazy dog.")); 2431 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345)); 2432 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true)); 2433 } 2434 2435 2436 THREADED_TEST(IdentityHash) { 2437 LocalContext env; 2438 v8::Isolate* isolate = env->GetIsolate(); 2439 v8::HandleScope scope(isolate); 2440 2441 // Ensure that the test starts with an fresh heap to test whether the hash 2442 // code is based on the address. 2443 CcTest::heap()->CollectAllGarbage(); 2444 Local<v8::Object> obj = v8::Object::New(isolate); 2445 int hash = obj->GetIdentityHash(); 2446 int hash1 = obj->GetIdentityHash(); 2447 CHECK_EQ(hash, hash1); 2448 int hash2 = v8::Object::New(isolate)->GetIdentityHash(); 2449 // Since the identity hash is essentially a random number two consecutive 2450 // objects should not be assigned the same hash code. If the test below fails 2451 // the random number generator should be evaluated. 2452 CHECK_NE(hash, hash2); 2453 CcTest::heap()->CollectAllGarbage(); 2454 int hash3 = v8::Object::New(isolate)->GetIdentityHash(); 2455 // Make sure that the identity hash is not based on the initial address of 2456 // the object alone. If the test below fails the random number generator 2457 // should be evaluated. 2458 CHECK_NE(hash, hash3); 2459 int hash4 = obj->GetIdentityHash(); 2460 CHECK_EQ(hash, hash4); 2461 2462 // Check identity hashes behaviour in the presence of JS accessors. 2463 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2464 { 2465 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2466 Local<v8::Object> o1 = v8::Object::New(isolate); 2467 Local<v8::Object> o2 = v8::Object::New(isolate); 2468 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2469 } 2470 { 2471 CompileRun( 2472 "function cnst() { return 42; };\n" 2473 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2474 Local<v8::Object> o1 = v8::Object::New(isolate); 2475 Local<v8::Object> o2 = v8::Object::New(isolate); 2476 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2477 } 2478 } 2479 2480 2481 void GlobalProxyIdentityHash(bool set_in_js) { 2482 LocalContext env; 2483 v8::Isolate* isolate = env->GetIsolate(); 2484 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 2485 v8::HandleScope scope(isolate); 2486 Local<Object> global_proxy = env->Global(); 2487 i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy); 2488 CHECK(env->Global() 2489 ->Set(env.local(), v8_str("global"), global_proxy) 2490 .FromJust()); 2491 i::Handle<i::Object> original_hash; 2492 if (set_in_js) { 2493 CompileRun("var m = new Set(); m.add(global);"); 2494 original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate); 2495 } else { 2496 original_hash = i::Handle<i::Object>( 2497 i::Object::GetOrCreateHash(i_isolate, i_global_proxy)); 2498 } 2499 CHECK(original_hash->IsSmi()); 2500 int32_t hash1 = i::Handle<i::Smi>::cast(original_hash)->value(); 2501 // Hash should be retained after being detached. 2502 env->DetachGlobal(); 2503 int hash2 = global_proxy->GetIdentityHash(); 2504 CHECK_EQ(hash1, hash2); 2505 { 2506 // Re-attach global proxy to a new context, hash should stay the same. 2507 LocalContext env2(NULL, Local<ObjectTemplate>(), global_proxy); 2508 int hash3 = global_proxy->GetIdentityHash(); 2509 CHECK_EQ(hash1, hash3); 2510 } 2511 } 2512 2513 2514 THREADED_TEST(GlobalProxyIdentityHash) { 2515 GlobalProxyIdentityHash(true); 2516 GlobalProxyIdentityHash(false); 2517 } 2518 2519 2520 TEST(SymbolIdentityHash) { 2521 LocalContext env; 2522 v8::Isolate* isolate = env->GetIsolate(); 2523 v8::HandleScope scope(isolate); 2524 2525 { 2526 Local<v8::Symbol> symbol = v8::Symbol::New(isolate); 2527 int hash = symbol->GetIdentityHash(); 2528 int hash1 = symbol->GetIdentityHash(); 2529 CHECK_EQ(hash, hash1); 2530 CcTest::heap()->CollectAllGarbage(); 2531 int hash3 = symbol->GetIdentityHash(); 2532 CHECK_EQ(hash, hash3); 2533 } 2534 2535 { 2536 v8::Local<v8::Symbol> js_symbol = 2537 CompileRun("Symbol('foo')").As<v8::Symbol>(); 2538 int hash = js_symbol->GetIdentityHash(); 2539 int hash1 = js_symbol->GetIdentityHash(); 2540 CHECK_EQ(hash, hash1); 2541 CcTest::heap()->CollectAllGarbage(); 2542 int hash3 = js_symbol->GetIdentityHash(); 2543 CHECK_EQ(hash, hash3); 2544 } 2545 } 2546 2547 2548 TEST(StringIdentityHash) { 2549 LocalContext env; 2550 v8::Isolate* isolate = env->GetIsolate(); 2551 v8::HandleScope scope(isolate); 2552 2553 Local<v8::String> str = v8_str("str1"); 2554 int hash = str->GetIdentityHash(); 2555 int hash1 = str->GetIdentityHash(); 2556 CHECK_EQ(hash, hash1); 2557 CcTest::heap()->CollectAllGarbage(); 2558 int hash3 = str->GetIdentityHash(); 2559 CHECK_EQ(hash, hash3); 2560 2561 Local<v8::String> str2 = v8_str("str1"); 2562 int hash4 = str2->GetIdentityHash(); 2563 CHECK_EQ(hash, hash4); 2564 } 2565 2566 2567 THREADED_TEST(SymbolProperties) { 2568 LocalContext env; 2569 v8::Isolate* isolate = env->GetIsolate(); 2570 v8::HandleScope scope(isolate); 2571 2572 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2573 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2574 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol")); 2575 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3")); 2576 2577 CcTest::heap()->CollectAllGarbage(); 2578 2579 // Check basic symbol functionality. 2580 CHECK(sym1->IsSymbol()); 2581 CHECK(sym2->IsSymbol()); 2582 CHECK(!obj->IsSymbol()); 2583 2584 CHECK(sym1->Equals(env.local(), sym1).FromJust()); 2585 CHECK(sym2->Equals(env.local(), sym2).FromJust()); 2586 CHECK(!sym1->Equals(env.local(), sym2).FromJust()); 2587 CHECK(!sym2->Equals(env.local(), sym1).FromJust()); 2588 CHECK(sym1->StrictEquals(sym1)); 2589 CHECK(sym2->StrictEquals(sym2)); 2590 CHECK(!sym1->StrictEquals(sym2)); 2591 CHECK(!sym2->StrictEquals(sym1)); 2592 2593 CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust()); 2594 2595 v8::Local<v8::Value> sym_val = sym2; 2596 CHECK(sym_val->IsSymbol()); 2597 CHECK(sym_val->Equals(env.local(), sym2).FromJust()); 2598 CHECK(sym_val->StrictEquals(sym2)); 2599 CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust()); 2600 2601 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2602 CHECK(sym_obj->IsSymbolObject()); 2603 CHECK(!sym2->IsSymbolObject()); 2604 CHECK(!obj->IsSymbolObject()); 2605 CHECK(sym_obj->Equals(env.local(), sym2).FromJust()); 2606 CHECK(!sym_obj->StrictEquals(sym2)); 2607 CHECK(v8::SymbolObject::Cast(*sym_obj) 2608 ->Equals(env.local(), sym_obj) 2609 .FromJust()); 2610 CHECK(v8::SymbolObject::Cast(*sym_obj) 2611 ->ValueOf() 2612 ->Equals(env.local(), sym2) 2613 .FromJust()); 2614 2615 // Make sure delete of a non-existent symbol property works. 2616 CHECK(obj->Delete(env.local(), sym1).FromJust()); 2617 CHECK(!obj->Has(env.local(), sym1).FromJust()); 2618 2619 CHECK( 2620 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust()); 2621 CHECK(obj->Has(env.local(), sym1).FromJust()); 2622 CHECK_EQ(1503, obj->Get(env.local(), sym1) 2623 .ToLocalChecked() 2624 ->Int32Value(env.local()) 2625 .FromJust()); 2626 CHECK( 2627 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust()); 2628 CHECK(obj->Has(env.local(), sym1).FromJust()); 2629 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2630 .ToLocalChecked() 2631 ->Int32Value(env.local()) 2632 .FromJust()); 2633 CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust()); 2634 2635 CHECK_EQ(0u, 2636 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2637 unsigned num_props = 2638 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 2639 CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20)) 2640 .FromJust()); 2641 CHECK_EQ(1u, 2642 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2643 CHECK_EQ(num_props + 1, 2644 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 2645 2646 CcTest::heap()->CollectAllGarbage(); 2647 2648 CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter, 2649 SymbolAccessorSetter) 2650 .FromJust()); 2651 CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined()); 2652 CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust()); 2653 CHECK(obj->Get(env.local(), sym3) 2654 .ToLocalChecked() 2655 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2656 .FromJust()); 2657 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 2658 .ToLocalChecked() 2659 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2660 .FromJust()); 2661 2662 // Add another property and delete it afterwards to force the object in 2663 // slow case. 2664 CHECK( 2665 obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust()); 2666 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2667 .ToLocalChecked() 2668 ->Int32Value(env.local()) 2669 .FromJust()); 2670 CHECK_EQ(2008, obj->Get(env.local(), sym2) 2671 .ToLocalChecked() 2672 ->Int32Value(env.local()) 2673 .FromJust()); 2674 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2675 .ToLocalChecked() 2676 ->Int32Value(env.local()) 2677 .FromJust()); 2678 CHECK_EQ(2u, 2679 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2680 2681 CHECK(obj->Has(env.local(), sym1).FromJust()); 2682 CHECK(obj->Has(env.local(), sym2).FromJust()); 2683 CHECK(obj->Has(env.local(), sym3).FromJust()); 2684 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust()); 2685 CHECK(obj->Delete(env.local(), sym2).FromJust()); 2686 CHECK(obj->Has(env.local(), sym1).FromJust()); 2687 CHECK(!obj->Has(env.local(), sym2).FromJust()); 2688 CHECK(obj->Has(env.local(), sym3).FromJust()); 2689 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust()); 2690 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2691 .ToLocalChecked() 2692 ->Int32Value(env.local()) 2693 .FromJust()); 2694 CHECK(obj->Get(env.local(), sym3) 2695 .ToLocalChecked() 2696 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2697 .FromJust()); 2698 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 2699 .ToLocalChecked() 2700 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2701 .FromJust()); 2702 CHECK_EQ(2u, 2703 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2704 2705 // Symbol properties are inherited. 2706 v8::Local<v8::Object> child = v8::Object::New(isolate); 2707 CHECK(child->SetPrototype(env.local(), obj).FromJust()); 2708 CHECK(child->Has(env.local(), sym1).FromJust()); 2709 CHECK_EQ(2002, child->Get(env.local(), sym1) 2710 .ToLocalChecked() 2711 ->Int32Value(env.local()) 2712 .FromJust()); 2713 CHECK(obj->Get(env.local(), sym3) 2714 .ToLocalChecked() 2715 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2716 .FromJust()); 2717 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 2718 .ToLocalChecked() 2719 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2720 .FromJust()); 2721 CHECK_EQ(0u, 2722 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2723 } 2724 2725 2726 THREADED_TEST(SymbolTemplateProperties) { 2727 LocalContext env; 2728 v8::Isolate* isolate = env->GetIsolate(); 2729 v8::HandleScope scope(isolate); 2730 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate); 2731 v8::Local<v8::Name> name = v8::Symbol::New(isolate); 2732 CHECK(!name.IsEmpty()); 2733 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate)); 2734 v8::Local<v8::Object> new_instance = 2735 foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 2736 CHECK(!new_instance.IsEmpty()); 2737 CHECK(new_instance->Has(env.local(), name).FromJust()); 2738 } 2739 2740 2741 THREADED_TEST(PrivatePropertiesOnProxies) { 2742 i::FLAG_harmony_proxies = true; 2743 LocalContext env; 2744 v8::Isolate* isolate = env->GetIsolate(); 2745 v8::HandleScope scope(isolate); 2746 2747 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>(); 2748 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>(); 2749 2750 v8::Local<v8::Proxy> proxy = 2751 v8::Proxy::New(env.local(), target, handler).ToLocalChecked(); 2752 2753 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 2754 v8::Local<v8::Private> priv2 = 2755 v8::Private::New(isolate, v8_str("my-private")); 2756 2757 CcTest::heap()->CollectAllGarbage(); 2758 2759 CHECK(priv2->Name() 2760 ->Equals(env.local(), 2761 v8::String::NewFromUtf8(isolate, "my-private", 2762 v8::NewStringType::kNormal) 2763 .ToLocalChecked()) 2764 .FromJust()); 2765 2766 // Make sure delete of a non-existent private symbol property works. 2767 proxy->DeletePrivate(env.local(), priv1).FromJust(); 2768 CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust()); 2769 2770 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503)) 2771 .FromJust()); 2772 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 2773 CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1) 2774 .ToLocalChecked() 2775 ->Int32Value(env.local()) 2776 .FromJust()); 2777 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002)) 2778 .FromJust()); 2779 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 2780 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 2781 .ToLocalChecked() 2782 ->Int32Value(env.local()) 2783 .FromJust()); 2784 2785 CHECK_EQ(0u, 2786 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2787 unsigned num_props = 2788 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 2789 CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8( 2790 isolate, "bla", v8::NewStringType::kNormal) 2791 .ToLocalChecked(), 2792 v8::Integer::New(isolate, 20)) 2793 .FromJust()); 2794 CHECK_EQ(1u, 2795 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2796 CHECK_EQ(num_props + 1, 2797 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 2798 2799 CcTest::heap()->CollectAllGarbage(); 2800 2801 // Add another property and delete it afterwards to force the object in 2802 // slow case. 2803 CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008)) 2804 .FromJust()); 2805 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 2806 .ToLocalChecked() 2807 ->Int32Value(env.local()) 2808 .FromJust()); 2809 CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2) 2810 .ToLocalChecked() 2811 ->Int32Value(env.local()) 2812 .FromJust()); 2813 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 2814 .ToLocalChecked() 2815 ->Int32Value(env.local()) 2816 .FromJust()); 2817 CHECK_EQ(1u, 2818 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2819 2820 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 2821 CHECK(proxy->HasPrivate(env.local(), priv2).FromJust()); 2822 CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust()); 2823 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 2824 CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust()); 2825 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 2826 .ToLocalChecked() 2827 ->Int32Value(env.local()) 2828 .FromJust()); 2829 CHECK_EQ(1u, 2830 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2831 2832 // Private properties are not inherited (for the time being). 2833 v8::Local<v8::Object> child = v8::Object::New(isolate); 2834 CHECK(child->SetPrototype(env.local(), proxy).FromJust()); 2835 CHECK(!child->HasPrivate(env.local(), priv1).FromJust()); 2836 CHECK_EQ(0u, 2837 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2838 } 2839 2840 2841 THREADED_TEST(PrivateProperties) { 2842 LocalContext env; 2843 v8::Isolate* isolate = env->GetIsolate(); 2844 v8::HandleScope scope(isolate); 2845 2846 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2847 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 2848 v8::Local<v8::Private> priv2 = 2849 v8::Private::New(isolate, v8_str("my-private")); 2850 2851 CcTest::heap()->CollectAllGarbage(); 2852 2853 CHECK(priv2->Name() 2854 ->Equals(env.local(), 2855 v8::String::NewFromUtf8(isolate, "my-private", 2856 v8::NewStringType::kNormal) 2857 .ToLocalChecked()) 2858 .FromJust()); 2859 2860 // Make sure delete of a non-existent private symbol property works. 2861 obj->DeletePrivate(env.local(), priv1).FromJust(); 2862 CHECK(!obj->HasPrivate(env.local(), priv1).FromJust()); 2863 2864 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503)) 2865 .FromJust()); 2866 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 2867 CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1) 2868 .ToLocalChecked() 2869 ->Int32Value(env.local()) 2870 .FromJust()); 2871 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002)) 2872 .FromJust()); 2873 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 2874 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 2875 .ToLocalChecked() 2876 ->Int32Value(env.local()) 2877 .FromJust()); 2878 2879 CHECK_EQ(0u, 2880 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2881 unsigned num_props = 2882 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 2883 CHECK(obj->Set(env.local(), v8::String::NewFromUtf8( 2884 isolate, "bla", v8::NewStringType::kNormal) 2885 .ToLocalChecked(), 2886 v8::Integer::New(isolate, 20)) 2887 .FromJust()); 2888 CHECK_EQ(1u, 2889 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2890 CHECK_EQ(num_props + 1, 2891 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 2892 2893 CcTest::heap()->CollectAllGarbage(); 2894 2895 // Add another property and delete it afterwards to force the object in 2896 // slow case. 2897 CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008)) 2898 .FromJust()); 2899 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 2900 .ToLocalChecked() 2901 ->Int32Value(env.local()) 2902 .FromJust()); 2903 CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2) 2904 .ToLocalChecked() 2905 ->Int32Value(env.local()) 2906 .FromJust()); 2907 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 2908 .ToLocalChecked() 2909 ->Int32Value(env.local()) 2910 .FromJust()); 2911 CHECK_EQ(1u, 2912 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2913 2914 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 2915 CHECK(obj->HasPrivate(env.local(), priv2).FromJust()); 2916 CHECK(obj->DeletePrivate(env.local(), priv2).FromJust()); 2917 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 2918 CHECK(!obj->HasPrivate(env.local(), priv2).FromJust()); 2919 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 2920 .ToLocalChecked() 2921 ->Int32Value(env.local()) 2922 .FromJust()); 2923 CHECK_EQ(1u, 2924 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2925 2926 // Private properties are not inherited (for the time being). 2927 v8::Local<v8::Object> child = v8::Object::New(isolate); 2928 CHECK(child->SetPrototype(env.local(), obj).FromJust()); 2929 CHECK(!child->HasPrivate(env.local(), priv1).FromJust()); 2930 CHECK_EQ(0u, 2931 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2932 } 2933 2934 2935 THREADED_TEST(GlobalSymbols) { 2936 LocalContext env; 2937 v8::Isolate* isolate = env->GetIsolate(); 2938 v8::HandleScope scope(isolate); 2939 2940 v8::Local<String> name = v8_str("my-symbol"); 2941 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name); 2942 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name); 2943 CHECK(glob2->SameValue(glob)); 2944 2945 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name); 2946 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name); 2947 CHECK(glob_api2->SameValue(glob_api)); 2948 CHECK(!glob_api->SameValue(glob)); 2949 2950 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name); 2951 CHECK(!sym->SameValue(glob)); 2952 2953 CompileRun("var sym2 = Symbol.for('my-symbol')"); 2954 v8::Local<Value> sym2 = 2955 env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked(); 2956 CHECK(sym2->SameValue(glob)); 2957 CHECK(!sym2->SameValue(glob_api)); 2958 } 2959 2960 2961 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*), 2962 const char* name) { 2963 LocalContext env; 2964 v8::Isolate* isolate = env->GetIsolate(); 2965 v8::HandleScope scope(isolate); 2966 2967 v8::Local<v8::Symbol> symbol = getter(isolate); 2968 std::string script = std::string("var sym = ") + name; 2969 CompileRun(script.c_str()); 2970 v8::Local<Value> value = 2971 env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked(); 2972 2973 CHECK(!value.IsEmpty()); 2974 CHECK(!symbol.IsEmpty()); 2975 CHECK(value->SameValue(symbol)); 2976 } 2977 2978 2979 THREADED_TEST(WellKnownSymbols) { 2980 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator"); 2981 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables"); 2982 } 2983 2984 2985 THREADED_TEST(GlobalPrivates) { 2986 i::FLAG_allow_natives_syntax = true; 2987 LocalContext env; 2988 v8::Isolate* isolate = env->GetIsolate(); 2989 v8::HandleScope scope(isolate); 2990 2991 v8::Local<String> name = v8_str("my-private"); 2992 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name); 2993 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2994 CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3)) 2995 .FromJust()); 2996 2997 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name); 2998 CHECK(obj->HasPrivate(env.local(), glob2).FromJust()); 2999 3000 v8::Local<v8::Private> priv = v8::Private::New(isolate, name); 3001 CHECK(!obj->HasPrivate(env.local(), priv).FromJust()); 3002 3003 CompileRun("var intern = %CreatePrivateSymbol('my-private')"); 3004 v8::Local<Value> intern = 3005 env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked(); 3006 CHECK(!obj->Has(env.local(), intern).FromJust()); 3007 } 3008 3009 3010 class ScopedArrayBufferContents { 3011 public: 3012 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents) 3013 : contents_(contents) {} 3014 ~ScopedArrayBufferContents() { free(contents_.Data()); } 3015 void* Data() const { return contents_.Data(); } 3016 size_t ByteLength() const { return contents_.ByteLength(); } 3017 3018 private: 3019 const v8::ArrayBuffer::Contents contents_; 3020 }; 3021 3022 template <typename T> 3023 static void CheckInternalFieldsAreZero(v8::Local<T> value) { 3024 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 3025 for (int i = 0; i < value->InternalFieldCount(); i++) { 3026 CHECK_EQ(0, value->GetInternalField(i) 3027 ->Int32Value(CcTest::isolate()->GetCurrentContext()) 3028 .FromJust()); 3029 } 3030 } 3031 3032 3033 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 3034 LocalContext env; 3035 v8::Isolate* isolate = env->GetIsolate(); 3036 v8::HandleScope handle_scope(isolate); 3037 3038 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024); 3039 CheckInternalFieldsAreZero(ab); 3040 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 3041 CHECK(!ab->IsExternal()); 3042 CcTest::heap()->CollectAllGarbage(); 3043 3044 ScopedArrayBufferContents ab_contents(ab->Externalize()); 3045 CHECK(ab->IsExternal()); 3046 3047 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 3048 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 3049 CHECK(data != NULL); 3050 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust()); 3051 3052 v8::Local<v8::Value> result = CompileRun("ab.byteLength"); 3053 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3054 3055 result = CompileRun( 3056 "var u8 = new Uint8Array(ab);" 3057 "u8[0] = 0xFF;" 3058 "u8[1] = 0xAA;" 3059 "u8.length"); 3060 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3061 CHECK_EQ(0xFF, data[0]); 3062 CHECK_EQ(0xAA, data[1]); 3063 data[0] = 0xCC; 3064 data[1] = 0x11; 3065 result = CompileRun("u8[0] + u8[1]"); 3066 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3067 } 3068 3069 3070 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 3071 LocalContext env; 3072 v8::Isolate* isolate = env->GetIsolate(); 3073 v8::HandleScope handle_scope(isolate); 3074 3075 3076 v8::Local<v8::Value> result = CompileRun( 3077 "var ab1 = new ArrayBuffer(2);" 3078 "var u8_a = new Uint8Array(ab1);" 3079 "u8_a[0] = 0xAA;" 3080 "u8_a[1] = 0xFF; u8_a.buffer"); 3081 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 3082 CheckInternalFieldsAreZero(ab1); 3083 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3084 CHECK(!ab1->IsExternal()); 3085 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 3086 CHECK(ab1->IsExternal()); 3087 3088 result = CompileRun("ab1.byteLength"); 3089 CHECK_EQ(2, result->Int32Value(env.local()).FromJust()); 3090 result = CompileRun("u8_a[0]"); 3091 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust()); 3092 result = CompileRun("u8_a[1]"); 3093 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3094 result = CompileRun( 3095 "var u8_b = new Uint8Array(ab1);" 3096 "u8_b[0] = 0xBB;" 3097 "u8_a[0]"); 3098 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust()); 3099 result = CompileRun("u8_b[1]"); 3100 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3101 3102 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3103 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3104 CHECK_EQ(0xBB, ab1_data[0]); 3105 CHECK_EQ(0xFF, ab1_data[1]); 3106 ab1_data[0] = 0xCC; 3107 ab1_data[1] = 0x11; 3108 result = CompileRun("u8_a[0] + u8_a[1]"); 3109 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3110 } 3111 3112 3113 THREADED_TEST(ArrayBuffer_External) { 3114 LocalContext env; 3115 v8::Isolate* isolate = env->GetIsolate(); 3116 v8::HandleScope handle_scope(isolate); 3117 3118 i::ScopedVector<uint8_t> my_data(100); 3119 memset(my_data.start(), 0, 100); 3120 Local<v8::ArrayBuffer> ab3 = 3121 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3122 CheckInternalFieldsAreZero(ab3); 3123 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3124 CHECK(ab3->IsExternal()); 3125 3126 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust()); 3127 3128 v8::Local<v8::Value> result = CompileRun("ab3.byteLength"); 3129 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3130 3131 result = CompileRun( 3132 "var u8_b = new Uint8Array(ab3);" 3133 "u8_b[0] = 0xBB;" 3134 "u8_b[1] = 0xCC;" 3135 "u8_b.length"); 3136 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3137 CHECK_EQ(0xBB, my_data[0]); 3138 CHECK_EQ(0xCC, my_data[1]); 3139 my_data[0] = 0xCC; 3140 my_data[1] = 0x11; 3141 result = CompileRun("u8_b[0] + u8_b[1]"); 3142 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3143 } 3144 3145 3146 THREADED_TEST(ArrayBuffer_DisableNeuter) { 3147 LocalContext env; 3148 v8::Isolate* isolate = env->GetIsolate(); 3149 v8::HandleScope handle_scope(isolate); 3150 3151 i::ScopedVector<uint8_t> my_data(100); 3152 memset(my_data.start(), 0, 100); 3153 Local<v8::ArrayBuffer> ab = 3154 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3155 CHECK(ab->IsNeuterable()); 3156 3157 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); 3158 buf->set_is_neuterable(false); 3159 3160 CHECK(!ab->IsNeuterable()); 3161 } 3162 3163 3164 static void CheckDataViewIsNeutered(v8::Local<v8::DataView> dv) { 3165 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 3166 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 3167 } 3168 3169 3170 static void CheckIsNeutered(v8::Local<v8::TypedArray> ta) { 3171 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 3172 CHECK_EQ(0, static_cast<int>(ta->Length())); 3173 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 3174 } 3175 3176 3177 static void CheckIsTypedArrayVarNeutered(const char* name) { 3178 i::ScopedVector<char> source(1024); 3179 i::SNPrintF(source, 3180 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 3181 name, name, name); 3182 CHECK(CompileRun(source.start())->IsTrue()); 3183 v8::Local<v8::TypedArray> ta = 3184 v8::Local<v8::TypedArray>::Cast(CompileRun(name)); 3185 CheckIsNeutered(ta); 3186 } 3187 3188 3189 template <typename TypedArray, int kElementSize> 3190 static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab, 3191 int byteOffset, int length) { 3192 v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 3193 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 3194 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 3195 CHECK_EQ(length, static_cast<int>(ta->Length())); 3196 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 3197 return ta; 3198 } 3199 3200 3201 THREADED_TEST(ArrayBuffer_NeuteringApi) { 3202 LocalContext env; 3203 v8::Isolate* isolate = env->GetIsolate(); 3204 v8::HandleScope handle_scope(isolate); 3205 3206 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024); 3207 3208 v8::Local<v8::Uint8Array> u8a = 3209 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 3210 v8::Local<v8::Uint8ClampedArray> u8c = 3211 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 3212 v8::Local<v8::Int8Array> i8a = 3213 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 3214 3215 v8::Local<v8::Uint16Array> u16a = 3216 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 3217 v8::Local<v8::Int16Array> i16a = 3218 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 3219 3220 v8::Local<v8::Uint32Array> u32a = 3221 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 3222 v8::Local<v8::Int32Array> i32a = 3223 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 3224 3225 v8::Local<v8::Float32Array> f32a = 3226 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 3227 v8::Local<v8::Float64Array> f64a = 3228 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 3229 3230 v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 3231 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 3232 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 3233 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 3234 3235 ScopedArrayBufferContents contents(buffer->Externalize()); 3236 buffer->Neuter(); 3237 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 3238 CheckIsNeutered(u8a); 3239 CheckIsNeutered(u8c); 3240 CheckIsNeutered(i8a); 3241 CheckIsNeutered(u16a); 3242 CheckIsNeutered(i16a); 3243 CheckIsNeutered(u32a); 3244 CheckIsNeutered(i32a); 3245 CheckIsNeutered(f32a); 3246 CheckIsNeutered(f64a); 3247 CheckDataViewIsNeutered(dv); 3248 } 3249 3250 3251 THREADED_TEST(ArrayBuffer_NeuteringScript) { 3252 LocalContext env; 3253 v8::Isolate* isolate = env->GetIsolate(); 3254 v8::HandleScope handle_scope(isolate); 3255 3256 CompileRun( 3257 "var ab = new ArrayBuffer(1024);" 3258 "var u8a = new Uint8Array(ab, 1, 1023);" 3259 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 3260 "var i8a = new Int8Array(ab, 1, 1023);" 3261 "var u16a = new Uint16Array(ab, 2, 511);" 3262 "var i16a = new Int16Array(ab, 2, 511);" 3263 "var u32a = new Uint32Array(ab, 4, 255);" 3264 "var i32a = new Int32Array(ab, 4, 255);" 3265 "var f32a = new Float32Array(ab, 4, 255);" 3266 "var f64a = new Float64Array(ab, 8, 127);" 3267 "var dv = new DataView(ab, 1, 1023);"); 3268 3269 v8::Local<v8::ArrayBuffer> ab = 3270 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 3271 3272 v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv")); 3273 3274 ScopedArrayBufferContents contents(ab->Externalize()); 3275 ab->Neuter(); 3276 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 3277 CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength"))); 3278 3279 CheckIsTypedArrayVarNeutered("u8a"); 3280 CheckIsTypedArrayVarNeutered("u8c"); 3281 CheckIsTypedArrayVarNeutered("i8a"); 3282 CheckIsTypedArrayVarNeutered("u16a"); 3283 CheckIsTypedArrayVarNeutered("i16a"); 3284 CheckIsTypedArrayVarNeutered("u32a"); 3285 CheckIsTypedArrayVarNeutered("i32a"); 3286 CheckIsTypedArrayVarNeutered("f32a"); 3287 CheckIsTypedArrayVarNeutered("f64a"); 3288 3289 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 3290 CheckDataViewIsNeutered(dv); 3291 } 3292 3293 3294 class ScopedSharedArrayBufferContents { 3295 public: 3296 explicit ScopedSharedArrayBufferContents( 3297 const v8::SharedArrayBuffer::Contents& contents) 3298 : contents_(contents) {} 3299 ~ScopedSharedArrayBufferContents() { free(contents_.Data()); } 3300 void* Data() const { return contents_.Data(); } 3301 size_t ByteLength() const { return contents_.ByteLength(); } 3302 3303 private: 3304 const v8::SharedArrayBuffer::Contents contents_; 3305 }; 3306 3307 3308 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) { 3309 i::FLAG_harmony_sharedarraybuffer = true; 3310 LocalContext env; 3311 v8::Isolate* isolate = env->GetIsolate(); 3312 v8::HandleScope handle_scope(isolate); 3313 3314 Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024); 3315 CheckInternalFieldsAreZero(ab); 3316 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 3317 CHECK(!ab->IsExternal()); 3318 CcTest::heap()->CollectAllGarbage(); 3319 3320 ScopedSharedArrayBufferContents ab_contents(ab->Externalize()); 3321 CHECK(ab->IsExternal()); 3322 3323 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 3324 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 3325 CHECK(data != NULL); 3326 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust()); 3327 3328 v8::Local<v8::Value> result = CompileRun("ab.byteLength"); 3329 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3330 3331 result = CompileRun( 3332 "var u8 = new Uint8Array(ab);" 3333 "u8[0] = 0xFF;" 3334 "u8[1] = 0xAA;" 3335 "u8.length"); 3336 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3337 CHECK_EQ(0xFF, data[0]); 3338 CHECK_EQ(0xAA, data[1]); 3339 data[0] = 0xCC; 3340 data[1] = 0x11; 3341 result = CompileRun("u8[0] + u8[1]"); 3342 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3343 } 3344 3345 3346 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) { 3347 i::FLAG_harmony_sharedarraybuffer = true; 3348 LocalContext env; 3349 v8::Isolate* isolate = env->GetIsolate(); 3350 v8::HandleScope handle_scope(isolate); 3351 3352 3353 v8::Local<v8::Value> result = CompileRun( 3354 "var ab1 = new SharedArrayBuffer(2);" 3355 "var u8_a = new Uint8Array(ab1);" 3356 "u8_a[0] = 0xAA;" 3357 "u8_a[1] = 0xFF; u8_a.buffer"); 3358 Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result); 3359 CheckInternalFieldsAreZero(ab1); 3360 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3361 CHECK(!ab1->IsExternal()); 3362 ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize()); 3363 CHECK(ab1->IsExternal()); 3364 3365 result = CompileRun("ab1.byteLength"); 3366 CHECK_EQ(2, result->Int32Value(env.local()).FromJust()); 3367 result = CompileRun("u8_a[0]"); 3368 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust()); 3369 result = CompileRun("u8_a[1]"); 3370 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3371 result = CompileRun( 3372 "var u8_b = new Uint8Array(ab1);" 3373 "u8_b[0] = 0xBB;" 3374 "u8_a[0]"); 3375 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust()); 3376 result = CompileRun("u8_b[1]"); 3377 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3378 3379 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3380 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3381 CHECK_EQ(0xBB, ab1_data[0]); 3382 CHECK_EQ(0xFF, ab1_data[1]); 3383 ab1_data[0] = 0xCC; 3384 ab1_data[1] = 0x11; 3385 result = CompileRun("u8_a[0] + u8_a[1]"); 3386 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3387 } 3388 3389 3390 THREADED_TEST(SharedArrayBuffer_External) { 3391 i::FLAG_harmony_sharedarraybuffer = true; 3392 LocalContext env; 3393 v8::Isolate* isolate = env->GetIsolate(); 3394 v8::HandleScope handle_scope(isolate); 3395 3396 i::ScopedVector<uint8_t> my_data(100); 3397 memset(my_data.start(), 0, 100); 3398 Local<v8::SharedArrayBuffer> ab3 = 3399 v8::SharedArrayBuffer::New(isolate, my_data.start(), 100); 3400 CheckInternalFieldsAreZero(ab3); 3401 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3402 CHECK(ab3->IsExternal()); 3403 3404 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust()); 3405 3406 v8::Local<v8::Value> result = CompileRun("ab3.byteLength"); 3407 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3408 3409 result = CompileRun( 3410 "var u8_b = new Uint8Array(ab3);" 3411 "u8_b[0] = 0xBB;" 3412 "u8_b[1] = 0xCC;" 3413 "u8_b.length"); 3414 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3415 CHECK_EQ(0xBB, my_data[0]); 3416 CHECK_EQ(0xCC, my_data[1]); 3417 my_data[0] = 0xCC; 3418 my_data[1] = 0x11; 3419 result = CompileRun("u8_b[0] + u8_b[1]"); 3420 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3421 } 3422 3423 3424 THREADED_TEST(HiddenProperties) { 3425 LocalContext env; 3426 v8::Isolate* isolate = env->GetIsolate(); 3427 v8::HandleScope scope(isolate); 3428 3429 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3430 v8::Local<v8::Private> key = 3431 v8::Private::ForApi(isolate, v8_str("api-test::hidden-key")); 3432 v8::Local<v8::String> empty = v8_str(""); 3433 v8::Local<v8::String> prop_name = v8_str("prop_name"); 3434 3435 CcTest::heap()->CollectAllGarbage(); 3436 3437 // Make sure delete of a non-existent hidden value works 3438 obj->DeletePrivate(env.local(), key).FromJust(); 3439 3440 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503)) 3441 .FromJust()); 3442 CHECK_EQ(1503, obj->GetPrivate(env.local(), key) 3443 .ToLocalChecked() 3444 ->Int32Value(env.local()) 3445 .FromJust()); 3446 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002)) 3447 .FromJust()); 3448 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3449 .ToLocalChecked() 3450 ->Int32Value(env.local()) 3451 .FromJust()); 3452 3453 CcTest::heap()->CollectAllGarbage(); 3454 3455 // Make sure we do not find the hidden property. 3456 CHECK(!obj->Has(env.local(), empty).FromJust()); 3457 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3458 .ToLocalChecked() 3459 ->Int32Value(env.local()) 3460 .FromJust()); 3461 CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined()); 3462 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3463 .ToLocalChecked() 3464 ->Int32Value(env.local()) 3465 .FromJust()); 3466 CHECK( 3467 obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust()); 3468 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3469 .ToLocalChecked() 3470 ->Int32Value(env.local()) 3471 .FromJust()); 3472 CHECK_EQ(2003, obj->Get(env.local(), empty) 3473 .ToLocalChecked() 3474 ->Int32Value(env.local()) 3475 .FromJust()); 3476 3477 CcTest::heap()->CollectAllGarbage(); 3478 3479 // Add another property and delete it afterwards to force the object in 3480 // slow case. 3481 CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008)) 3482 .FromJust()); 3483 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3484 .ToLocalChecked() 3485 ->Int32Value(env.local()) 3486 .FromJust()); 3487 CHECK_EQ(2008, obj->Get(env.local(), prop_name) 3488 .ToLocalChecked() 3489 ->Int32Value(env.local()) 3490 .FromJust()); 3491 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3492 .ToLocalChecked() 3493 ->Int32Value(env.local()) 3494 .FromJust()); 3495 CHECK(obj->Delete(env.local(), prop_name).FromJust()); 3496 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3497 .ToLocalChecked() 3498 ->Int32Value(env.local()) 3499 .FromJust()); 3500 3501 CcTest::heap()->CollectAllGarbage(); 3502 3503 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002)) 3504 .FromJust()); 3505 CHECK(obj->DeletePrivate(env.local(), key).FromJust()); 3506 CHECK(!obj->HasPrivate(env.local(), key).FromJust()); 3507 } 3508 3509 3510 THREADED_TEST(Regress97784) { 3511 // Regression test for crbug.com/97784 3512 // Messing with the Object.prototype should not have effect on 3513 // hidden properties. 3514 LocalContext env; 3515 v8::HandleScope scope(env->GetIsolate()); 3516 3517 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3518 v8::Local<v8::Private> key = 3519 v8::Private::New(env->GetIsolate(), v8_str("hidden")); 3520 3521 CompileRun( 3522 "set_called = false;" 3523 "Object.defineProperty(" 3524 " Object.prototype," 3525 " 'hidden'," 3526 " {get: function() { return 45; }," 3527 " set: function() { set_called = true; }})"); 3528 3529 CHECK(!obj->HasPrivate(env.local(), key).FromJust()); 3530 // Make sure that the getter and setter from Object.prototype is not invoked. 3531 // If it did we would have full access to the hidden properties in 3532 // the accessor. 3533 CHECK( 3534 obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42)) 3535 .FromJust()); 3536 ExpectFalse("set_called"); 3537 CHECK_EQ(42, obj->GetPrivate(env.local(), key) 3538 .ToLocalChecked() 3539 ->Int32Value(env.local()) 3540 .FromJust()); 3541 } 3542 3543 3544 THREADED_TEST(External) { 3545 v8::HandleScope scope(CcTest::isolate()); 3546 int x = 3; 3547 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x); 3548 LocalContext env; 3549 CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust()); 3550 Local<Value> reext_obj = CompileRun("this.ext"); 3551 v8::Local<v8::External> reext = reext_obj.As<v8::External>(); 3552 int* ptr = static_cast<int*>(reext->Value()); 3553 CHECK_EQ(x, 3); 3554 *ptr = 10; 3555 CHECK_EQ(x, 10); 3556 3557 // Make sure unaligned pointers are wrapped properly. 3558 char* data = i::StrDup("0123456789"); 3559 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]); 3560 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]); 3561 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]); 3562 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]); 3563 3564 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3565 CHECK_EQ('0', *char_ptr); 3566 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3567 CHECK_EQ('1', *char_ptr); 3568 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3569 CHECK_EQ('2', *char_ptr); 3570 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3571 CHECK_EQ('3', *char_ptr); 3572 i::DeleteArray(data); 3573 } 3574 3575 3576 THREADED_TEST(GlobalHandle) { 3577 v8::Isolate* isolate = CcTest::isolate(); 3578 v8::Persistent<String> global; 3579 { 3580 v8::HandleScope scope(isolate); 3581 global.Reset(isolate, v8_str("str")); 3582 } 3583 { 3584 v8::HandleScope scope(isolate); 3585 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3586 } 3587 global.Reset(); 3588 { 3589 v8::HandleScope scope(isolate); 3590 global.Reset(isolate, v8_str("str")); 3591 } 3592 { 3593 v8::HandleScope scope(isolate); 3594 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3595 } 3596 global.Reset(); 3597 } 3598 3599 3600 THREADED_TEST(ResettingGlobalHandle) { 3601 v8::Isolate* isolate = CcTest::isolate(); 3602 v8::Persistent<String> global; 3603 { 3604 v8::HandleScope scope(isolate); 3605 global.Reset(isolate, v8_str("str")); 3606 } 3607 v8::internal::GlobalHandles* global_handles = 3608 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3609 int initial_handle_count = global_handles->global_handles_count(); 3610 { 3611 v8::HandleScope scope(isolate); 3612 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3613 } 3614 { 3615 v8::HandleScope scope(isolate); 3616 global.Reset(isolate, v8_str("longer")); 3617 } 3618 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3619 { 3620 v8::HandleScope scope(isolate); 3621 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3622 } 3623 global.Reset(); 3624 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3625 } 3626 3627 3628 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3629 v8::Isolate* isolate = CcTest::isolate(); 3630 v8::Persistent<String> global; 3631 { 3632 v8::HandleScope scope(isolate); 3633 global.Reset(isolate, v8_str("str")); 3634 } 3635 v8::internal::GlobalHandles* global_handles = 3636 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3637 int initial_handle_count = global_handles->global_handles_count(); 3638 { 3639 v8::HandleScope scope(isolate); 3640 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3641 } 3642 { 3643 v8::HandleScope scope(isolate); 3644 Local<String> empty; 3645 global.Reset(isolate, empty); 3646 } 3647 CHECK(global.IsEmpty()); 3648 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3649 } 3650 3651 3652 template <class T> 3653 static v8::Global<T> PassUnique(v8::Global<T> unique) { 3654 return unique.Pass(); 3655 } 3656 3657 3658 template <class T> 3659 static v8::Global<T> ReturnUnique(v8::Isolate* isolate, 3660 const v8::Persistent<T>& global) { 3661 v8::Global<String> unique(isolate, global); 3662 return unique.Pass(); 3663 } 3664 3665 3666 THREADED_TEST(Global) { 3667 v8::Isolate* isolate = CcTest::isolate(); 3668 v8::Persistent<String> global; 3669 { 3670 v8::HandleScope scope(isolate); 3671 global.Reset(isolate, v8_str("str")); 3672 } 3673 v8::internal::GlobalHandles* global_handles = 3674 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3675 int initial_handle_count = global_handles->global_handles_count(); 3676 { 3677 v8::Global<String> unique(isolate, global); 3678 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3679 // Test assignment via Pass 3680 { 3681 v8::Global<String> copy = unique.Pass(); 3682 CHECK(unique.IsEmpty()); 3683 CHECK(copy == global); 3684 CHECK_EQ(initial_handle_count + 1, 3685 global_handles->global_handles_count()); 3686 unique = copy.Pass(); 3687 } 3688 // Test ctor via Pass 3689 { 3690 v8::Global<String> copy(unique.Pass()); 3691 CHECK(unique.IsEmpty()); 3692 CHECK(copy == global); 3693 CHECK_EQ(initial_handle_count + 1, 3694 global_handles->global_handles_count()); 3695 unique = copy.Pass(); 3696 } 3697 // Test pass through function call 3698 { 3699 v8::Global<String> copy = PassUnique(unique.Pass()); 3700 CHECK(unique.IsEmpty()); 3701 CHECK(copy == global); 3702 CHECK_EQ(initial_handle_count + 1, 3703 global_handles->global_handles_count()); 3704 unique = copy.Pass(); 3705 } 3706 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3707 } 3708 // Test pass from function call 3709 { 3710 v8::Global<String> unique = ReturnUnique(isolate, global); 3711 CHECK(unique == global); 3712 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3713 } 3714 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3715 global.Reset(); 3716 } 3717 3718 3719 namespace { 3720 3721 class TwoPassCallbackData; 3722 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); 3723 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); 3724 3725 3726 class TwoPassCallbackData { 3727 public: 3728 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter) 3729 : first_pass_called_(false), 3730 second_pass_called_(false), 3731 trigger_gc_(false), 3732 instance_counter_(instance_counter) { 3733 HandleScope scope(isolate); 3734 i::ScopedVector<char> buffer(40); 3735 i::SNPrintF(buffer, "%p", static_cast<void*>(this)); 3736 auto string = 3737 v8::String::NewFromUtf8(isolate, buffer.start(), 3738 v8::NewStringType::kNormal).ToLocalChecked(); 3739 cell_.Reset(isolate, string); 3740 (*instance_counter_)++; 3741 } 3742 3743 ~TwoPassCallbackData() { 3744 CHECK(first_pass_called_); 3745 CHECK(second_pass_called_); 3746 CHECK(cell_.IsEmpty()); 3747 (*instance_counter_)--; 3748 } 3749 3750 void FirstPass() { 3751 CHECK(!first_pass_called_); 3752 CHECK(!second_pass_called_); 3753 CHECK(!cell_.IsEmpty()); 3754 cell_.Reset(); 3755 first_pass_called_ = true; 3756 } 3757 3758 void SecondPass() { 3759 CHECK(first_pass_called_); 3760 CHECK(!second_pass_called_); 3761 CHECK(cell_.IsEmpty()); 3762 second_pass_called_ = true; 3763 delete this; 3764 } 3765 3766 void SetWeak() { 3767 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter); 3768 } 3769 3770 void MarkTriggerGc() { trigger_gc_ = true; } 3771 bool trigger_gc() { return trigger_gc_; } 3772 3773 int* instance_counter() { return instance_counter_; } 3774 3775 private: 3776 bool first_pass_called_; 3777 bool second_pass_called_; 3778 bool trigger_gc_; 3779 v8::Global<v8::String> cell_; 3780 int* instance_counter_; 3781 }; 3782 3783 3784 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { 3785 ApiTestFuzzer::Fuzz(); 3786 bool trigger_gc = data.GetParameter()->trigger_gc(); 3787 int* instance_counter = data.GetParameter()->instance_counter(); 3788 data.GetParameter()->SecondPass(); 3789 if (!trigger_gc) return; 3790 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter); 3791 data_2->SetWeak(); 3792 CcTest::heap()->CollectAllGarbage(); 3793 } 3794 3795 3796 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { 3797 data.GetParameter()->FirstPass(); 3798 data.SetSecondPassCallback(SecondPassCallback); 3799 } 3800 3801 } // namespace 3802 3803 3804 TEST(TwoPassPhantomCallbacks) { 3805 auto isolate = CcTest::isolate(); 3806 const size_t kLength = 20; 3807 int instance_counter = 0; 3808 for (size_t i = 0; i < kLength; ++i) { 3809 auto data = new TwoPassCallbackData(isolate, &instance_counter); 3810 data->SetWeak(); 3811 } 3812 CHECK_EQ(static_cast<int>(kLength), instance_counter); 3813 CcTest::heap()->CollectAllGarbage(); 3814 EmptyMessageQueues(isolate); 3815 CHECK_EQ(0, instance_counter); 3816 } 3817 3818 3819 TEST(TwoPassPhantomCallbacksNestedGc) { 3820 auto isolate = CcTest::isolate(); 3821 const size_t kLength = 20; 3822 TwoPassCallbackData* array[kLength]; 3823 int instance_counter = 0; 3824 for (size_t i = 0; i < kLength; ++i) { 3825 array[i] = new TwoPassCallbackData(isolate, &instance_counter); 3826 array[i]->SetWeak(); 3827 } 3828 array[5]->MarkTriggerGc(); 3829 array[10]->MarkTriggerGc(); 3830 array[15]->MarkTriggerGc(); 3831 CHECK_EQ(static_cast<int>(kLength), instance_counter); 3832 CcTest::heap()->CollectAllGarbage(); 3833 EmptyMessageQueues(isolate); 3834 CHECK_EQ(0, instance_counter); 3835 } 3836 3837 3838 namespace { 3839 3840 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); } 3841 3842 3843 Local<v8::Object> NewObjectForIntKey( 3844 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ, 3845 int key) { 3846 auto local = Local<v8::ObjectTemplate>::New(isolate, templ); 3847 auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); 3848 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key)); 3849 return obj; 3850 } 3851 3852 3853 template <typename K, typename V> 3854 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> { 3855 public: 3856 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType; 3857 static const v8::PersistentContainerCallbackType kCallbackType = 3858 v8::kWeakWithInternalFields; 3859 struct WeakCallbackDataType { 3860 MapType* map; 3861 K key; 3862 }; 3863 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, 3864 Local<V> value) { 3865 WeakCallbackDataType* data = new WeakCallbackDataType; 3866 data->map = map; 3867 data->key = key; 3868 return data; 3869 } 3870 static MapType* MapFromWeakCallbackInfo( 3871 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { 3872 return data.GetParameter()->map; 3873 } 3874 static K KeyFromWeakCallbackInfo( 3875 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { 3876 return data.GetParameter()->key; 3877 } 3878 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; } 3879 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) { 3880 CHECK_EQ(IntKeyToVoidPointer(key), 3881 v8::Object::GetAlignedPointerFromInternalField(value, 0)); 3882 } 3883 static void OnWeakCallback( 3884 const v8::WeakCallbackInfo<WeakCallbackDataType>&) {} 3885 static void DisposeWeak( 3886 const v8::WeakCallbackInfo<WeakCallbackDataType>& info) { 3887 K key = KeyFromWeakCallbackInfo(info); 3888 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0)); 3889 DisposeCallbackData(info.GetParameter()); 3890 } 3891 }; 3892 3893 3894 template <typename Map> 3895 void TestGlobalValueMap() { 3896 LocalContext env; 3897 v8::Isolate* isolate = env->GetIsolate(); 3898 v8::Global<ObjectTemplate> templ; 3899 { 3900 HandleScope scope(isolate); 3901 auto t = ObjectTemplate::New(isolate); 3902 t->SetInternalFieldCount(1); 3903 templ.Reset(isolate, t); 3904 } 3905 Map map(isolate); 3906 v8::internal::GlobalHandles* global_handles = 3907 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3908 int initial_handle_count = global_handles->global_handles_count(); 3909 CHECK_EQ(0, static_cast<int>(map.Size())); 3910 { 3911 HandleScope scope(isolate); 3912 Local<v8::Object> obj = map.Get(7); 3913 CHECK(obj.IsEmpty()); 3914 Local<v8::Object> expected = v8::Object::New(isolate); 3915 map.Set(7, expected); 3916 CHECK_EQ(1, static_cast<int>(map.Size())); 3917 obj = map.Get(7); 3918 CHECK(expected->Equals(env.local(), obj).FromJust()); 3919 { 3920 typename Map::PersistentValueReference ref = map.GetReference(7); 3921 CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust()); 3922 } 3923 v8::Global<v8::Object> removed = map.Remove(7); 3924 CHECK_EQ(0, static_cast<int>(map.Size())); 3925 CHECK(expected == removed); 3926 removed = map.Remove(7); 3927 CHECK(removed.IsEmpty()); 3928 map.Set(8, expected); 3929 CHECK_EQ(1, static_cast<int>(map.Size())); 3930 map.Set(8, expected); 3931 CHECK_EQ(1, static_cast<int>(map.Size())); 3932 { 3933 typename Map::PersistentValueReference ref; 3934 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8); 3935 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref); 3936 CHECK_EQ(1, static_cast<int>(map.Size())); 3937 CHECK(expected == removed); 3938 CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust()); 3939 } 3940 } 3941 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3942 if (map.IsWeak()) { 3943 CcTest::i_isolate()->heap()->CollectAllGarbage( 3944 i::Heap::kAbortIncrementalMarkingMask); 3945 } else { 3946 map.Clear(); 3947 } 3948 CHECK_EQ(0, static_cast<int>(map.Size())); 3949 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3950 { 3951 HandleScope scope(isolate); 3952 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9); 3953 map.Set(9, value); 3954 map.Clear(); 3955 } 3956 CHECK_EQ(0, static_cast<int>(map.Size())); 3957 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3958 } 3959 3960 } // namespace 3961 3962 3963 TEST(GlobalValueMap) { 3964 // Default case, w/o weak callbacks: 3965 TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>(); 3966 3967 // Custom traits with weak callbacks: 3968 typedef v8::GlobalValueMap<int, v8::Object, 3969 PhantomStdMapTraits<int, v8::Object>> WeakMap; 3970 TestGlobalValueMap<WeakMap>(); 3971 } 3972 3973 3974 TEST(PersistentValueVector) { 3975 LocalContext env; 3976 v8::Isolate* isolate = env->GetIsolate(); 3977 v8::internal::GlobalHandles* global_handles = 3978 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3979 int handle_count = global_handles->global_handles_count(); 3980 HandleScope scope(isolate); 3981 3982 v8::PersistentValueVector<v8::Object> vector(isolate); 3983 3984 Local<v8::Object> obj1 = v8::Object::New(isolate); 3985 Local<v8::Object> obj2 = v8::Object::New(isolate); 3986 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate)); 3987 3988 CHECK(vector.IsEmpty()); 3989 CHECK_EQ(0, static_cast<int>(vector.Size())); 3990 3991 vector.ReserveCapacity(3); 3992 CHECK(vector.IsEmpty()); 3993 3994 vector.Append(obj1); 3995 vector.Append(obj2); 3996 vector.Append(obj1); 3997 vector.Append(obj3.Pass()); 3998 vector.Append(obj1); 3999 4000 CHECK(!vector.IsEmpty()); 4001 CHECK_EQ(5, static_cast<int>(vector.Size())); 4002 CHECK(obj3.IsEmpty()); 4003 CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust()); 4004 CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust()); 4005 CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust()); 4006 CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust()); 4007 4008 CHECK_EQ(5 + handle_count, global_handles->global_handles_count()); 4009 4010 vector.Clear(); 4011 CHECK(vector.IsEmpty()); 4012 CHECK_EQ(0, static_cast<int>(vector.Size())); 4013 CHECK_EQ(handle_count, global_handles->global_handles_count()); 4014 } 4015 4016 4017 THREADED_TEST(GlobalHandleUpcast) { 4018 v8::Isolate* isolate = CcTest::isolate(); 4019 v8::HandleScope scope(isolate); 4020 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str")); 4021 v8::Persistent<String> global_string(isolate, local); 4022 v8::Persistent<Value>& global_value = 4023 v8::Persistent<Value>::Cast(global_string); 4024 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 4025 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 4026 global_string.Reset(); 4027 } 4028 4029 4030 THREADED_TEST(HandleEquality) { 4031 v8::Isolate* isolate = CcTest::isolate(); 4032 v8::Persistent<String> global1; 4033 v8::Persistent<String> global2; 4034 { 4035 v8::HandleScope scope(isolate); 4036 global1.Reset(isolate, v8_str("str")); 4037 global2.Reset(isolate, v8_str("str2")); 4038 } 4039 CHECK_EQ(global1 == global1, true); 4040 CHECK_EQ(global1 != global1, false); 4041 { 4042 v8::HandleScope scope(isolate); 4043 Local<String> local1 = Local<String>::New(isolate, global1); 4044 Local<String> local2 = Local<String>::New(isolate, global2); 4045 4046 CHECK_EQ(global1 == local1, true); 4047 CHECK_EQ(global1 != local1, false); 4048 CHECK_EQ(local1 == global1, true); 4049 CHECK_EQ(local1 != global1, false); 4050 4051 CHECK_EQ(global1 == local2, false); 4052 CHECK_EQ(global1 != local2, true); 4053 CHECK_EQ(local2 == global1, false); 4054 CHECK_EQ(local2 != global1, true); 4055 4056 CHECK_EQ(local1 == local2, false); 4057 CHECK_EQ(local1 != local2, true); 4058 4059 Local<String> anotherLocal1 = Local<String>::New(isolate, global1); 4060 CHECK_EQ(local1 == anotherLocal1, true); 4061 CHECK_EQ(local1 != anotherLocal1, false); 4062 } 4063 global1.Reset(); 4064 global2.Reset(); 4065 } 4066 4067 4068 THREADED_TEST(LocalHandle) { 4069 v8::HandleScope scope(CcTest::isolate()); 4070 v8::Local<String> local = 4071 v8::Local<String>::New(CcTest::isolate(), v8_str("str")); 4072 CHECK_EQ(local->Length(), 3); 4073 } 4074 4075 4076 class WeakCallCounter { 4077 public: 4078 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {} 4079 int id() { return id_; } 4080 void increment() { number_of_weak_calls_++; } 4081 int NumberOfWeakCalls() { return number_of_weak_calls_; } 4082 4083 private: 4084 int id_; 4085 int number_of_weak_calls_; 4086 }; 4087 4088 4089 template <typename T> 4090 struct WeakCallCounterAndPersistent { 4091 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) 4092 : counter(counter) {} 4093 WeakCallCounter* counter; 4094 v8::Persistent<T> handle; 4095 }; 4096 4097 4098 template <typename T> 4099 static void WeakPointerCallback( 4100 const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) { 4101 CHECK_EQ(1234, data.GetParameter()->counter->id()); 4102 data.GetParameter()->counter->increment(); 4103 data.GetParameter()->handle.Reset(); 4104 } 4105 4106 4107 template <typename T> 4108 static UniqueId MakeUniqueId(const Persistent<T>& p) { 4109 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 4110 } 4111 4112 4113 THREADED_TEST(ApiObjectGroups) { 4114 LocalContext env; 4115 v8::Isolate* iso = env->GetIsolate(); 4116 HandleScope scope(iso); 4117 4118 WeakCallCounter counter(1234); 4119 4120 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4121 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4122 WeakCallCounterAndPersistent<Value> g1c1(&counter); 4123 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4124 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4125 WeakCallCounterAndPersistent<Value> g2c1(&counter); 4126 4127 { 4128 HandleScope scope(iso); 4129 g1s1.handle.Reset(iso, Object::New(iso)); 4130 g1s2.handle.Reset(iso, Object::New(iso)); 4131 g1c1.handle.Reset(iso, Object::New(iso)); 4132 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4133 v8::WeakCallbackType::kParameter); 4134 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4135 v8::WeakCallbackType::kParameter); 4136 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4137 v8::WeakCallbackType::kParameter); 4138 4139 g2s1.handle.Reset(iso, Object::New(iso)); 4140 g2s2.handle.Reset(iso, Object::New(iso)); 4141 g2c1.handle.Reset(iso, Object::New(iso)); 4142 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4143 v8::WeakCallbackType::kParameter); 4144 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4145 v8::WeakCallbackType::kParameter); 4146 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4147 v8::WeakCallbackType::kParameter); 4148 } 4149 4150 WeakCallCounterAndPersistent<Value> root(&counter); 4151 root.handle.Reset(iso, g1s1.handle); // make a root. 4152 4153 // Connect group 1 and 2, make a cycle. 4154 { 4155 HandleScope scope(iso); 4156 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>()) 4157 ->Set(env.local(), 0, Local<Value>::New(iso, g2s2.handle)) 4158 .FromJust()); 4159 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>()) 4160 ->Set(env.local(), 0, Local<Value>::New(iso, g1s1.handle)) 4161 .FromJust()); 4162 } 4163 4164 { 4165 UniqueId id1 = MakeUniqueId(g1s1.handle); 4166 UniqueId id2 = MakeUniqueId(g2s2.handle); 4167 iso->SetObjectGroupId(g1s1.handle, id1); 4168 iso->SetObjectGroupId(g1s2.handle, id1); 4169 iso->SetReferenceFromGroup(id1, g1c1.handle); 4170 iso->SetObjectGroupId(g2s1.handle, id2); 4171 iso->SetObjectGroupId(g2s2.handle, id2); 4172 iso->SetReferenceFromGroup(id2, g2c1.handle); 4173 } 4174 // Do a single full GC, ensure incremental marking is stopped. 4175 v8::internal::Heap* heap = 4176 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4177 heap->CollectAllGarbage(); 4178 4179 // All object should be alive. 4180 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4181 4182 // Weaken the root. 4183 root.handle.SetWeak(&root, &WeakPointerCallback, 4184 v8::WeakCallbackType::kParameter); 4185 // But make children strong roots---all the objects (except for children) 4186 // should be collectable now. 4187 g1c1.handle.ClearWeak(); 4188 g2c1.handle.ClearWeak(); 4189 4190 // Groups are deleted, rebuild groups. 4191 { 4192 UniqueId id1 = MakeUniqueId(g1s1.handle); 4193 UniqueId id2 = MakeUniqueId(g2s2.handle); 4194 iso->SetObjectGroupId(g1s1.handle, id1); 4195 iso->SetObjectGroupId(g1s2.handle, id1); 4196 iso->SetReferenceFromGroup(id1, g1c1.handle); 4197 iso->SetObjectGroupId(g2s1.handle, id2); 4198 iso->SetObjectGroupId(g2s2.handle, id2); 4199 iso->SetReferenceFromGroup(id2, g2c1.handle); 4200 } 4201 4202 heap->CollectAllGarbage(); 4203 4204 // All objects should be gone. 5 global handles in total. 4205 CHECK_EQ(5, counter.NumberOfWeakCalls()); 4206 4207 // And now make children weak again and collect them. 4208 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4209 v8::WeakCallbackType::kParameter); 4210 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4211 v8::WeakCallbackType::kParameter); 4212 4213 heap->CollectAllGarbage(); 4214 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4215 } 4216 4217 4218 THREADED_TEST(ApiObjectGroupsForSubtypes) { 4219 LocalContext env; 4220 v8::Isolate* iso = env->GetIsolate(); 4221 HandleScope scope(iso); 4222 4223 WeakCallCounter counter(1234); 4224 4225 WeakCallCounterAndPersistent<Object> g1s1(&counter); 4226 WeakCallCounterAndPersistent<String> g1s2(&counter); 4227 WeakCallCounterAndPersistent<String> g1c1(&counter); 4228 WeakCallCounterAndPersistent<Object> g2s1(&counter); 4229 WeakCallCounterAndPersistent<String> g2s2(&counter); 4230 WeakCallCounterAndPersistent<String> g2c1(&counter); 4231 4232 { 4233 HandleScope scope(iso); 4234 g1s1.handle.Reset(iso, Object::New(iso)); 4235 g1s2.handle.Reset(iso, v8_str("foo1")); 4236 g1c1.handle.Reset(iso, v8_str("foo2")); 4237 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4238 v8::WeakCallbackType::kParameter); 4239 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4240 v8::WeakCallbackType::kParameter); 4241 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4242 v8::WeakCallbackType::kParameter); 4243 4244 g2s1.handle.Reset(iso, Object::New(iso)); 4245 g2s2.handle.Reset(iso, v8_str("foo3")); 4246 g2c1.handle.Reset(iso, v8_str("foo4")); 4247 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4248 v8::WeakCallbackType::kParameter); 4249 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4250 v8::WeakCallbackType::kParameter); 4251 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4252 v8::WeakCallbackType::kParameter); 4253 } 4254 4255 WeakCallCounterAndPersistent<Value> root(&counter); 4256 root.handle.Reset(iso, g1s1.handle); // make a root. 4257 4258 // Connect group 1 and 2, make a cycle. 4259 { 4260 HandleScope scope(iso); 4261 CHECK(Local<Object>::New(iso, g1s1.handle) 4262 ->Set(env.local(), 0, Local<Object>::New(iso, g2s1.handle)) 4263 .FromJust()); 4264 CHECK(Local<Object>::New(iso, g2s1.handle) 4265 ->Set(env.local(), 0, Local<Object>::New(iso, g1s1.handle)) 4266 .FromJust()); 4267 } 4268 4269 { 4270 UniqueId id1 = MakeUniqueId(g1s1.handle); 4271 UniqueId id2 = MakeUniqueId(g2s2.handle); 4272 iso->SetObjectGroupId(g1s1.handle, id1); 4273 iso->SetObjectGroupId(g1s2.handle, id1); 4274 iso->SetReference(g1s1.handle, g1c1.handle); 4275 iso->SetObjectGroupId(g2s1.handle, id2); 4276 iso->SetObjectGroupId(g2s2.handle, id2); 4277 iso->SetReferenceFromGroup(id2, g2c1.handle); 4278 } 4279 // Do a single full GC, ensure incremental marking is stopped. 4280 v8::internal::Heap* heap = 4281 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4282 heap->CollectAllGarbage(); 4283 4284 // All object should be alive. 4285 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4286 4287 // Weaken the root. 4288 root.handle.SetWeak(&root, &WeakPointerCallback, 4289 v8::WeakCallbackType::kParameter); 4290 // But make children strong roots---all the objects (except for children) 4291 // should be collectable now. 4292 g1c1.handle.ClearWeak(); 4293 g2c1.handle.ClearWeak(); 4294 4295 // Groups are deleted, rebuild groups. 4296 { 4297 UniqueId id1 = MakeUniqueId(g1s1.handle); 4298 UniqueId id2 = MakeUniqueId(g2s2.handle); 4299 iso->SetObjectGroupId(g1s1.handle, id1); 4300 iso->SetObjectGroupId(g1s2.handle, id1); 4301 iso->SetReference(g1s1.handle, g1c1.handle); 4302 iso->SetObjectGroupId(g2s1.handle, id2); 4303 iso->SetObjectGroupId(g2s2.handle, id2); 4304 iso->SetReferenceFromGroup(id2, g2c1.handle); 4305 } 4306 4307 heap->CollectAllGarbage(); 4308 4309 // All objects should be gone. 5 global handles in total. 4310 CHECK_EQ(5, counter.NumberOfWeakCalls()); 4311 4312 // And now make children weak again and collect them. 4313 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4314 v8::WeakCallbackType::kParameter); 4315 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4316 v8::WeakCallbackType::kParameter); 4317 4318 heap->CollectAllGarbage(); 4319 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4320 } 4321 4322 4323 THREADED_TEST(ApiObjectGroupsCycle) { 4324 LocalContext env; 4325 v8::Isolate* iso = env->GetIsolate(); 4326 HandleScope scope(iso); 4327 4328 WeakCallCounter counter(1234); 4329 4330 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4331 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4332 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4333 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4334 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4335 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4336 WeakCallCounterAndPersistent<Value> g4s1(&counter); 4337 WeakCallCounterAndPersistent<Value> g4s2(&counter); 4338 4339 { 4340 HandleScope scope(iso); 4341 g1s1.handle.Reset(iso, Object::New(iso)); 4342 g1s2.handle.Reset(iso, Object::New(iso)); 4343 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4344 v8::WeakCallbackType::kParameter); 4345 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4346 v8::WeakCallbackType::kParameter); 4347 CHECK(g1s1.handle.IsWeak()); 4348 CHECK(g1s2.handle.IsWeak()); 4349 4350 g2s1.handle.Reset(iso, Object::New(iso)); 4351 g2s2.handle.Reset(iso, Object::New(iso)); 4352 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4353 v8::WeakCallbackType::kParameter); 4354 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4355 v8::WeakCallbackType::kParameter); 4356 CHECK(g2s1.handle.IsWeak()); 4357 CHECK(g2s2.handle.IsWeak()); 4358 4359 g3s1.handle.Reset(iso, Object::New(iso)); 4360 g3s2.handle.Reset(iso, Object::New(iso)); 4361 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback, 4362 v8::WeakCallbackType::kParameter); 4363 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback, 4364 v8::WeakCallbackType::kParameter); 4365 CHECK(g3s1.handle.IsWeak()); 4366 CHECK(g3s2.handle.IsWeak()); 4367 4368 g4s1.handle.Reset(iso, Object::New(iso)); 4369 g4s2.handle.Reset(iso, Object::New(iso)); 4370 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback, 4371 v8::WeakCallbackType::kParameter); 4372 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback, 4373 v8::WeakCallbackType::kParameter); 4374 CHECK(g4s1.handle.IsWeak()); 4375 CHECK(g4s2.handle.IsWeak()); 4376 } 4377 4378 WeakCallCounterAndPersistent<Value> root(&counter); 4379 root.handle.Reset(iso, g1s1.handle); // make a root. 4380 4381 // Connect groups. We're building the following cycle: 4382 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4383 // groups. 4384 { 4385 UniqueId id1 = MakeUniqueId(g1s1.handle); 4386 UniqueId id2 = MakeUniqueId(g2s1.handle); 4387 UniqueId id3 = MakeUniqueId(g3s1.handle); 4388 UniqueId id4 = MakeUniqueId(g4s1.handle); 4389 iso->SetObjectGroupId(g1s1.handle, id1); 4390 iso->SetObjectGroupId(g1s2.handle, id1); 4391 iso->SetReferenceFromGroup(id1, g2s1.handle); 4392 iso->SetObjectGroupId(g2s1.handle, id2); 4393 iso->SetObjectGroupId(g2s2.handle, id2); 4394 iso->SetReferenceFromGroup(id2, g3s1.handle); 4395 iso->SetObjectGroupId(g3s1.handle, id3); 4396 iso->SetObjectGroupId(g3s2.handle, id3); 4397 iso->SetReferenceFromGroup(id3, g4s1.handle); 4398 iso->SetObjectGroupId(g4s1.handle, id4); 4399 iso->SetObjectGroupId(g4s2.handle, id4); 4400 iso->SetReferenceFromGroup(id4, g1s1.handle); 4401 } 4402 // Do a single full GC 4403 v8::internal::Heap* heap = 4404 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4405 heap->CollectAllGarbage(); 4406 4407 // All object should be alive. 4408 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4409 4410 // Weaken the root. 4411 root.handle.SetWeak(&root, &WeakPointerCallback, 4412 v8::WeakCallbackType::kParameter); 4413 4414 // Groups are deleted, rebuild groups. 4415 { 4416 UniqueId id1 = MakeUniqueId(g1s1.handle); 4417 UniqueId id2 = MakeUniqueId(g2s1.handle); 4418 UniqueId id3 = MakeUniqueId(g3s1.handle); 4419 UniqueId id4 = MakeUniqueId(g4s1.handle); 4420 iso->SetObjectGroupId(g1s1.handle, id1); 4421 iso->SetObjectGroupId(g1s2.handle, id1); 4422 iso->SetReferenceFromGroup(id1, g2s1.handle); 4423 iso->SetObjectGroupId(g2s1.handle, id2); 4424 iso->SetObjectGroupId(g2s2.handle, id2); 4425 iso->SetReferenceFromGroup(id2, g3s1.handle); 4426 iso->SetObjectGroupId(g3s1.handle, id3); 4427 iso->SetObjectGroupId(g3s2.handle, id3); 4428 iso->SetReferenceFromGroup(id3, g4s1.handle); 4429 iso->SetObjectGroupId(g4s1.handle, id4); 4430 iso->SetObjectGroupId(g4s2.handle, id4); 4431 iso->SetReferenceFromGroup(id4, g1s1.handle); 4432 } 4433 4434 heap->CollectAllGarbage(); 4435 4436 // All objects should be gone. 9 global handles in total. 4437 CHECK_EQ(9, counter.NumberOfWeakCalls()); 4438 } 4439 4440 4441 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures 4442 // on the buildbots, so was made non-threaded for the time being. 4443 TEST(ApiObjectGroupsCycleForScavenger) { 4444 i::FLAG_stress_compaction = false; 4445 i::FLAG_gc_global = false; 4446 LocalContext env; 4447 v8::Isolate* iso = env->GetIsolate(); 4448 HandleScope scope(iso); 4449 4450 WeakCallCounter counter(1234); 4451 4452 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4453 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4454 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4455 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4456 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4457 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4458 4459 { 4460 HandleScope scope(iso); 4461 g1s1.handle.Reset(iso, Object::New(iso)); 4462 g1s2.handle.Reset(iso, Object::New(iso)); 4463 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4464 v8::WeakCallbackType::kParameter); 4465 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4466 v8::WeakCallbackType::kParameter); 4467 4468 g2s1.handle.Reset(iso, Object::New(iso)); 4469 g2s2.handle.Reset(iso, Object::New(iso)); 4470 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4471 v8::WeakCallbackType::kParameter); 4472 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4473 v8::WeakCallbackType::kParameter); 4474 4475 g3s1.handle.Reset(iso, Object::New(iso)); 4476 g3s2.handle.Reset(iso, Object::New(iso)); 4477 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback, 4478 v8::WeakCallbackType::kParameter); 4479 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback, 4480 v8::WeakCallbackType::kParameter); 4481 } 4482 4483 // Make a root. 4484 WeakCallCounterAndPersistent<Value> root(&counter); 4485 root.handle.Reset(iso, g1s1.handle); 4486 root.handle.MarkPartiallyDependent(); 4487 4488 // Connect groups. We're building the following cycle: 4489 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4490 // groups. 4491 { 4492 HandleScope handle_scope(iso); 4493 g1s1.handle.MarkPartiallyDependent(); 4494 g1s2.handle.MarkPartiallyDependent(); 4495 g2s1.handle.MarkPartiallyDependent(); 4496 g2s2.handle.MarkPartiallyDependent(); 4497 g3s1.handle.MarkPartiallyDependent(); 4498 g3s2.handle.MarkPartiallyDependent(); 4499 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4500 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4501 Local<Object>::New(iso, g1s1.handle.As<Object>()) 4502 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g2s1.handle)) 4503 .FromJust(); 4504 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4505 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4506 Local<Object>::New(iso, g2s1.handle.As<Object>()) 4507 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g3s1.handle)) 4508 .FromJust(); 4509 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4510 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4511 Local<Object>::New(iso, g3s1.handle.As<Object>()) 4512 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g1s1.handle)) 4513 .FromJust(); 4514 } 4515 4516 v8::internal::Heap* heap = 4517 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4518 heap->CollectAllGarbage(); 4519 4520 // All objects should be alive. 4521 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4522 4523 // Weaken the root. 4524 root.handle.SetWeak(&root, &WeakPointerCallback, 4525 v8::WeakCallbackType::kParameter); 4526 root.handle.MarkPartiallyDependent(); 4527 4528 // Groups are deleted, rebuild groups. 4529 { 4530 HandleScope handle_scope(iso); 4531 g1s1.handle.MarkPartiallyDependent(); 4532 g1s2.handle.MarkPartiallyDependent(); 4533 g2s1.handle.MarkPartiallyDependent(); 4534 g2s2.handle.MarkPartiallyDependent(); 4535 g3s1.handle.MarkPartiallyDependent(); 4536 g3s2.handle.MarkPartiallyDependent(); 4537 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4538 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4539 Local<Object>::New(iso, g1s1.handle.As<Object>()) 4540 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g2s1.handle)) 4541 .FromJust(); 4542 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4543 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4544 Local<Object>::New(iso, g2s1.handle.As<Object>()) 4545 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g3s1.handle)) 4546 .FromJust(); 4547 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4548 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4549 Local<Object>::New(iso, g3s1.handle.As<Object>()) 4550 ->Set(env.local(), v8_str("x"), Local<Value>::New(iso, g1s1.handle)) 4551 .FromJust(); 4552 } 4553 4554 heap->CollectAllGarbage(); 4555 4556 // All objects should be gone. 7 global handles in total. 4557 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4558 } 4559 4560 4561 THREADED_TEST(ScriptException) { 4562 LocalContext env; 4563 v8::HandleScope scope(env->GetIsolate()); 4564 Local<Script> script = v8_compile("throw 'panama!';"); 4565 v8::TryCatch try_catch(env->GetIsolate()); 4566 v8::MaybeLocal<Value> result = script->Run(env.local()); 4567 CHECK(result.IsEmpty()); 4568 CHECK(try_catch.HasCaught()); 4569 String::Utf8Value exception_value(try_catch.Exception()); 4570 CHECK_EQ(0, strcmp(*exception_value, "panama!")); 4571 } 4572 4573 4574 TEST(TryCatchCustomException) { 4575 LocalContext env; 4576 v8::Isolate* isolate = env->GetIsolate(); 4577 v8::HandleScope scope(isolate); 4578 v8::TryCatch try_catch(isolate); 4579 CompileRun( 4580 "function CustomError() { this.a = 'b'; }" 4581 "(function f() { throw new CustomError(); })();"); 4582 CHECK(try_catch.HasCaught()); 4583 CHECK(try_catch.Exception() 4584 ->ToObject(env.local()) 4585 .ToLocalChecked() 4586 ->Get(env.local(), v8_str("a")) 4587 .ToLocalChecked() 4588 ->Equals(env.local(), v8_str("b")) 4589 .FromJust()); 4590 } 4591 4592 4593 bool message_received; 4594 4595 4596 static void check_message_0(v8::Local<v8::Message> message, 4597 v8::Local<Value> data) { 4598 CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext()) 4599 .FromJust()); 4600 CHECK_EQ(6.75, message->GetScriptOrigin() 4601 .ResourceName() 4602 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4603 .FromJust()); 4604 CHECK(!message->IsSharedCrossOrigin()); 4605 message_received = true; 4606 } 4607 4608 4609 THREADED_TEST(MessageHandler0) { 4610 message_received = false; 4611 v8::HandleScope scope(CcTest::isolate()); 4612 CHECK(!message_received); 4613 LocalContext context; 4614 CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76)); 4615 v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75"); 4616 CHECK(script->Run(context.local()).IsEmpty()); 4617 CHECK(message_received); 4618 // clear out the message listener 4619 CcTest::isolate()->RemoveMessageListeners(check_message_0); 4620 } 4621 4622 4623 static void check_message_1(v8::Local<v8::Message> message, 4624 v8::Local<Value> data) { 4625 CHECK(data->IsNumber()); 4626 CHECK_EQ(1337, 4627 data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust()); 4628 CHECK(!message->IsSharedCrossOrigin()); 4629 message_received = true; 4630 } 4631 4632 4633 TEST(MessageHandler1) { 4634 message_received = false; 4635 v8::HandleScope scope(CcTest::isolate()); 4636 CHECK(!message_received); 4637 CcTest::isolate()->AddMessageListener(check_message_1); 4638 LocalContext context; 4639 CompileRun("throw 1337;"); 4640 CHECK(message_received); 4641 // clear out the message listener 4642 CcTest::isolate()->RemoveMessageListeners(check_message_1); 4643 } 4644 4645 4646 static void check_message_2(v8::Local<v8::Message> message, 4647 v8::Local<Value> data) { 4648 LocalContext context; 4649 CHECK(data->IsObject()); 4650 v8::Local<v8::Value> hidden_property = 4651 v8::Object::Cast(*data) 4652 ->GetPrivate( 4653 context.local(), 4654 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key"))) 4655 .ToLocalChecked(); 4656 CHECK(v8_str("hidden value") 4657 ->Equals(context.local(), hidden_property) 4658 .FromJust()); 4659 CHECK(!message->IsSharedCrossOrigin()); 4660 message_received = true; 4661 } 4662 4663 4664 TEST(MessageHandler2) { 4665 message_received = false; 4666 v8::HandleScope scope(CcTest::isolate()); 4667 CHECK(!message_received); 4668 CcTest::isolate()->AddMessageListener(check_message_2); 4669 LocalContext context; 4670 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 4671 v8::Object::Cast(*error) 4672 ->SetPrivate(context.local(), 4673 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")), 4674 v8_str("hidden value")) 4675 .FromJust(); 4676 CHECK(context->Global() 4677 ->Set(context.local(), v8_str("error"), error) 4678 .FromJust()); 4679 CompileRun("throw error;"); 4680 CHECK(message_received); 4681 // clear out the message listener 4682 CcTest::isolate()->RemoveMessageListeners(check_message_2); 4683 } 4684 4685 4686 static void check_message_3(v8::Local<v8::Message> message, 4687 v8::Local<Value> data) { 4688 CHECK(message->IsSharedCrossOrigin()); 4689 CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin()); 4690 CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript()); 4691 CHECK(message->GetScriptOrigin().Options().IsOpaque()); 4692 CHECK_EQ(6.75, message->GetScriptOrigin() 4693 .ResourceName() 4694 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4695 .FromJust()); 4696 CHECK_EQ(7.40, message->GetScriptOrigin() 4697 .SourceMapUrl() 4698 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4699 .FromJust()); 4700 message_received = true; 4701 } 4702 4703 4704 TEST(MessageHandler3) { 4705 message_received = false; 4706 v8::Isolate* isolate = CcTest::isolate(); 4707 v8::HandleScope scope(isolate); 4708 CHECK(!message_received); 4709 isolate->AddMessageListener(check_message_3); 4710 LocalContext context; 4711 v8::ScriptOrigin origin = v8::ScriptOrigin( 4712 v8_str("6.75"), v8::Integer::New(isolate, 1), 4713 v8::Integer::New(isolate, 2), v8::True(isolate), Local<v8::Integer>(), 4714 v8::True(isolate), v8_str("7.40"), v8::True(isolate)); 4715 v8::Local<v8::Script> script = 4716 Script::Compile(context.local(), v8_str("throw 'error'"), &origin) 4717 .ToLocalChecked(); 4718 CHECK(script->Run(context.local()).IsEmpty()); 4719 CHECK(message_received); 4720 // clear out the message listener 4721 isolate->RemoveMessageListeners(check_message_3); 4722 } 4723 4724 4725 static void check_message_4(v8::Local<v8::Message> message, 4726 v8::Local<Value> data) { 4727 CHECK(!message->IsSharedCrossOrigin()); 4728 CHECK_EQ(6.75, message->GetScriptOrigin() 4729 .ResourceName() 4730 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4731 .FromJust()); 4732 message_received = true; 4733 } 4734 4735 4736 TEST(MessageHandler4) { 4737 message_received = false; 4738 v8::Isolate* isolate = CcTest::isolate(); 4739 v8::HandleScope scope(isolate); 4740 CHECK(!message_received); 4741 isolate->AddMessageListener(check_message_4); 4742 LocalContext context; 4743 v8::ScriptOrigin origin = 4744 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4745 v8::Integer::New(isolate, 2), v8::False(isolate)); 4746 v8::Local<v8::Script> script = 4747 Script::Compile(context.local(), v8_str("throw 'error'"), &origin) 4748 .ToLocalChecked(); 4749 CHECK(script->Run(context.local()).IsEmpty()); 4750 CHECK(message_received); 4751 // clear out the message listener 4752 isolate->RemoveMessageListeners(check_message_4); 4753 } 4754 4755 4756 static void check_message_5a(v8::Local<v8::Message> message, 4757 v8::Local<Value> data) { 4758 CHECK(message->IsSharedCrossOrigin()); 4759 CHECK_EQ(6.75, message->GetScriptOrigin() 4760 .ResourceName() 4761 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4762 .FromJust()); 4763 message_received = true; 4764 } 4765 4766 4767 static void check_message_5b(v8::Local<v8::Message> message, 4768 v8::Local<Value> data) { 4769 CHECK(!message->IsSharedCrossOrigin()); 4770 CHECK_EQ(6.75, message->GetScriptOrigin() 4771 .ResourceName() 4772 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4773 .FromJust()); 4774 message_received = true; 4775 } 4776 4777 4778 TEST(MessageHandler5) { 4779 message_received = false; 4780 v8::Isolate* isolate = CcTest::isolate(); 4781 v8::HandleScope scope(isolate); 4782 CHECK(!message_received); 4783 isolate->AddMessageListener(check_message_5a); 4784 LocalContext context; 4785 v8::ScriptOrigin origin1 = 4786 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4787 v8::Integer::New(isolate, 2), v8::True(isolate)); 4788 v8::Local<v8::Script> script = 4789 Script::Compile(context.local(), v8_str("throw 'error'"), &origin1) 4790 .ToLocalChecked(); 4791 CHECK(script->Run(context.local()).IsEmpty()); 4792 CHECK(message_received); 4793 // clear out the message listener 4794 isolate->RemoveMessageListeners(check_message_5a); 4795 4796 message_received = false; 4797 isolate->AddMessageListener(check_message_5b); 4798 v8::ScriptOrigin origin2 = 4799 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4800 v8::Integer::New(isolate, 2), v8::False(isolate)); 4801 script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2) 4802 .ToLocalChecked(); 4803 CHECK(script->Run(context.local()).IsEmpty()); 4804 CHECK(message_received); 4805 // clear out the message listener 4806 isolate->RemoveMessageListeners(check_message_5b); 4807 } 4808 4809 4810 TEST(NativeWeakMap) { 4811 v8::Isolate* isolate = CcTest::isolate(); 4812 HandleScope scope(isolate); 4813 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate)); 4814 CHECK(!weak_map.IsEmpty()); 4815 4816 LocalContext env; 4817 Local<Object> value = v8::Object::New(isolate); 4818 4819 Local<Object> local1 = v8::Object::New(isolate); 4820 CHECK(!weak_map->Has(local1)); 4821 CHECK(weak_map->Get(local1)->IsUndefined()); 4822 weak_map->Set(local1, value); 4823 CHECK(weak_map->Has(local1)); 4824 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 4825 4826 WeakCallCounter counter(1234); 4827 WeakCallCounterAndPersistent<Value> o1(&counter); 4828 WeakCallCounterAndPersistent<Value> o2(&counter); 4829 WeakCallCounterAndPersistent<Value> s1(&counter); 4830 { 4831 HandleScope scope(isolate); 4832 Local<v8::Object> obj1 = v8::Object::New(isolate); 4833 Local<v8::Object> obj2 = v8::Object::New(isolate); 4834 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 4835 4836 weak_map->Set(obj1, value); 4837 weak_map->Set(obj2, value); 4838 weak_map->Set(sym1, value); 4839 4840 o1.handle.Reset(isolate, obj1); 4841 o2.handle.Reset(isolate, obj2); 4842 s1.handle.Reset(isolate, sym1); 4843 4844 CHECK(weak_map->Has(local1)); 4845 CHECK(weak_map->Has(obj1)); 4846 CHECK(weak_map->Has(obj2)); 4847 CHECK(weak_map->Has(sym1)); 4848 4849 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 4850 CHECK(value->Equals(env.local(), weak_map->Get(obj1)).FromJust()); 4851 CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust()); 4852 CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust()); 4853 } 4854 CcTest::heap()->CollectAllGarbage(); 4855 { 4856 HandleScope scope(isolate); 4857 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 4858 CHECK(value->Equals(env.local(), 4859 weak_map->Get(Local<Value>::New(isolate, o1.handle))) 4860 .FromJust()); 4861 CHECK(value->Equals(env.local(), 4862 weak_map->Get(Local<Value>::New(isolate, o2.handle))) 4863 .FromJust()); 4864 CHECK(value->Equals(env.local(), 4865 weak_map->Get(Local<Value>::New(isolate, s1.handle))) 4866 .FromJust()); 4867 } 4868 4869 o1.handle.SetWeak(&o1, &WeakPointerCallback, 4870 v8::WeakCallbackType::kParameter); 4871 o2.handle.SetWeak(&o2, &WeakPointerCallback, 4872 v8::WeakCallbackType::kParameter); 4873 s1.handle.SetWeak(&s1, &WeakPointerCallback, 4874 v8::WeakCallbackType::kParameter); 4875 4876 CcTest::heap()->CollectAllGarbage(); 4877 CHECK_EQ(3, counter.NumberOfWeakCalls()); 4878 4879 CHECK(o1.handle.IsEmpty()); 4880 CHECK(o2.handle.IsEmpty()); 4881 CHECK(s1.handle.IsEmpty()); 4882 4883 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 4884 CHECK(weak_map->Delete(local1)); 4885 CHECK(!weak_map->Has(local1)); 4886 CHECK(weak_map->Get(local1)->IsUndefined()); 4887 } 4888 4889 4890 THREADED_TEST(GetSetProperty) { 4891 LocalContext context; 4892 v8::Isolate* isolate = context->GetIsolate(); 4893 v8::HandleScope scope(isolate); 4894 CHECK(context->Global() 4895 ->Set(context.local(), v8_str("foo"), v8_num(14)) 4896 .FromJust()); 4897 CHECK(context->Global() 4898 ->Set(context.local(), v8_str("12"), v8_num(92)) 4899 .FromJust()); 4900 CHECK(context->Global() 4901 ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32)) 4902 .FromJust()); 4903 CHECK(context->Global() 4904 ->Set(context.local(), v8_num(13), v8_num(56)) 4905 .FromJust()); 4906 Local<Value> foo = CompileRun("this.foo"); 4907 CHECK_EQ(14, foo->Int32Value(context.local()).FromJust()); 4908 Local<Value> twelve = CompileRun("this[12]"); 4909 CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust()); 4910 Local<Value> sixteen = CompileRun("this[16]"); 4911 CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust()); 4912 Local<Value> thirteen = CompileRun("this[13]"); 4913 CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust()); 4914 CHECK_EQ(92, context->Global() 4915 ->Get(context.local(), v8::Integer::New(isolate, 12)) 4916 .ToLocalChecked() 4917 ->Int32Value(context.local()) 4918 .FromJust()); 4919 CHECK_EQ(92, context->Global() 4920 ->Get(context.local(), v8_str("12")) 4921 .ToLocalChecked() 4922 ->Int32Value(context.local()) 4923 .FromJust()); 4924 CHECK_EQ(92, context->Global() 4925 ->Get(context.local(), v8_num(12)) 4926 .ToLocalChecked() 4927 ->Int32Value(context.local()) 4928 .FromJust()); 4929 CHECK_EQ(32, context->Global() 4930 ->Get(context.local(), v8::Integer::New(isolate, 16)) 4931 .ToLocalChecked() 4932 ->Int32Value(context.local()) 4933 .FromJust()); 4934 CHECK_EQ(32, context->Global() 4935 ->Get(context.local(), v8_str("16")) 4936 .ToLocalChecked() 4937 ->Int32Value(context.local()) 4938 .FromJust()); 4939 CHECK_EQ(32, context->Global() 4940 ->Get(context.local(), v8_num(16)) 4941 .ToLocalChecked() 4942 ->Int32Value(context.local()) 4943 .FromJust()); 4944 CHECK_EQ(56, context->Global() 4945 ->Get(context.local(), v8::Integer::New(isolate, 13)) 4946 .ToLocalChecked() 4947 ->Int32Value(context.local()) 4948 .FromJust()); 4949 CHECK_EQ(56, context->Global() 4950 ->Get(context.local(), v8_str("13")) 4951 .ToLocalChecked() 4952 ->Int32Value(context.local()) 4953 .FromJust()); 4954 CHECK_EQ(56, context->Global() 4955 ->Get(context.local(), v8_num(13)) 4956 .ToLocalChecked() 4957 ->Int32Value(context.local()) 4958 .FromJust()); 4959 } 4960 4961 4962 THREADED_TEST(PropertyAttributes) { 4963 LocalContext context; 4964 v8::HandleScope scope(context->GetIsolate()); 4965 // none 4966 Local<String> prop = v8_str("none"); 4967 CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust()); 4968 CHECK_EQ(v8::None, context->Global() 4969 ->GetPropertyAttributes(context.local(), prop) 4970 .FromJust()); 4971 // read-only 4972 prop = v8_str("read_only"); 4973 context->Global() 4974 ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly) 4975 .FromJust(); 4976 CHECK_EQ(7, context->Global() 4977 ->Get(context.local(), prop) 4978 .ToLocalChecked() 4979 ->Int32Value(context.local()) 4980 .FromJust()); 4981 CHECK_EQ(v8::ReadOnly, context->Global() 4982 ->GetPropertyAttributes(context.local(), prop) 4983 .FromJust()); 4984 CompileRun("read_only = 9"); 4985 CHECK_EQ(7, context->Global() 4986 ->Get(context.local(), prop) 4987 .ToLocalChecked() 4988 ->Int32Value(context.local()) 4989 .FromJust()); 4990 CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust()); 4991 CHECK_EQ(7, context->Global() 4992 ->Get(context.local(), prop) 4993 .ToLocalChecked() 4994 ->Int32Value(context.local()) 4995 .FromJust()); 4996 // dont-delete 4997 prop = v8_str("dont_delete"); 4998 context->Global() 4999 ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete) 5000 .FromJust(); 5001 CHECK_EQ(13, context->Global() 5002 ->Get(context.local(), prop) 5003 .ToLocalChecked() 5004 ->Int32Value(context.local()) 5005 .FromJust()); 5006 CompileRun("delete dont_delete"); 5007 CHECK_EQ(13, context->Global() 5008 ->Get(context.local(), prop) 5009 .ToLocalChecked() 5010 ->Int32Value(context.local()) 5011 .FromJust()); 5012 CHECK_EQ(v8::DontDelete, context->Global() 5013 ->GetPropertyAttributes(context.local(), prop) 5014 .FromJust()); 5015 // dont-enum 5016 prop = v8_str("dont_enum"); 5017 context->Global() 5018 ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum) 5019 .FromJust(); 5020 CHECK_EQ(v8::DontEnum, context->Global() 5021 ->GetPropertyAttributes(context.local(), prop) 5022 .FromJust()); 5023 // absent 5024 prop = v8_str("absent"); 5025 CHECK_EQ(v8::None, context->Global() 5026 ->GetPropertyAttributes(context.local(), prop) 5027 .FromJust()); 5028 Local<Value> fake_prop = v8_num(1); 5029 CHECK_EQ(v8::None, context->Global() 5030 ->GetPropertyAttributes(context.local(), fake_prop) 5031 .FromJust()); 5032 // exception 5033 TryCatch try_catch(context->GetIsolate()); 5034 Local<Value> exception = 5035 CompileRun("({ toString: function() { throw 'exception';} })"); 5036 CHECK(context->Global() 5037 ->GetPropertyAttributes(context.local(), exception) 5038 .IsNothing()); 5039 CHECK(try_catch.HasCaught()); 5040 String::Utf8Value exception_value(try_catch.Exception()); 5041 CHECK_EQ(0, strcmp("exception", *exception_value)); 5042 try_catch.Reset(); 5043 } 5044 5045 5046 THREADED_TEST(Array) { 5047 LocalContext context; 5048 v8::HandleScope scope(context->GetIsolate()); 5049 Local<v8::Array> array = v8::Array::New(context->GetIsolate()); 5050 CHECK_EQ(0u, array->Length()); 5051 CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined()); 5052 CHECK(!array->Has(context.local(), 0).FromJust()); 5053 CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined()); 5054 CHECK(!array->Has(context.local(), 100).FromJust()); 5055 CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust()); 5056 CHECK_EQ(3u, array->Length()); 5057 CHECK(!array->Has(context.local(), 0).FromJust()); 5058 CHECK(!array->Has(context.local(), 1).FromJust()); 5059 CHECK(array->Has(context.local(), 2).FromJust()); 5060 CHECK_EQ(7, array->Get(context.local(), 2) 5061 .ToLocalChecked() 5062 ->Int32Value(context.local()) 5063 .FromJust()); 5064 Local<Value> obj = CompileRun("[1, 2, 3]"); 5065 Local<v8::Array> arr = obj.As<v8::Array>(); 5066 CHECK_EQ(3u, arr->Length()); 5067 CHECK_EQ(1, arr->Get(context.local(), 0) 5068 .ToLocalChecked() 5069 ->Int32Value(context.local()) 5070 .FromJust()); 5071 CHECK_EQ(2, arr->Get(context.local(), 1) 5072 .ToLocalChecked() 5073 ->Int32Value(context.local()) 5074 .FromJust()); 5075 CHECK_EQ(3, arr->Get(context.local(), 2) 5076 .ToLocalChecked() 5077 ->Int32Value(context.local()) 5078 .FromJust()); 5079 array = v8::Array::New(context->GetIsolate(), 27); 5080 CHECK_EQ(27u, array->Length()); 5081 array = v8::Array::New(context->GetIsolate(), -27); 5082 CHECK_EQ(0u, array->Length()); 5083 } 5084 5085 5086 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 5087 v8::EscapableHandleScope scope(args.GetIsolate()); 5088 ApiTestFuzzer::Fuzz(); 5089 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); 5090 for (int i = 0; i < args.Length(); i++) { 5091 CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i]) 5092 .FromJust()); 5093 } 5094 args.GetReturnValue().Set(scope.Escape(result)); 5095 } 5096 5097 5098 THREADED_TEST(Vector) { 5099 v8::Isolate* isolate = CcTest::isolate(); 5100 v8::HandleScope scope(isolate); 5101 Local<ObjectTemplate> global = ObjectTemplate::New(isolate); 5102 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF)); 5103 LocalContext context(0, global); 5104 5105 const char* fun = "f()"; 5106 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 5107 CHECK_EQ(0u, a0->Length()); 5108 5109 const char* fun2 = "f(11)"; 5110 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 5111 CHECK_EQ(1u, a1->Length()); 5112 CHECK_EQ(11, a1->Get(context.local(), 0) 5113 .ToLocalChecked() 5114 ->Int32Value(context.local()) 5115 .FromJust()); 5116 5117 const char* fun3 = "f(12, 13)"; 5118 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 5119 CHECK_EQ(2u, a2->Length()); 5120 CHECK_EQ(12, a2->Get(context.local(), 0) 5121 .ToLocalChecked() 5122 ->Int32Value(context.local()) 5123 .FromJust()); 5124 CHECK_EQ(13, a2->Get(context.local(), 1) 5125 .ToLocalChecked() 5126 ->Int32Value(context.local()) 5127 .FromJust()); 5128 5129 const char* fun4 = "f(14, 15, 16)"; 5130 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 5131 CHECK_EQ(3u, a3->Length()); 5132 CHECK_EQ(14, a3->Get(context.local(), 0) 5133 .ToLocalChecked() 5134 ->Int32Value(context.local()) 5135 .FromJust()); 5136 CHECK_EQ(15, a3->Get(context.local(), 1) 5137 .ToLocalChecked() 5138 ->Int32Value(context.local()) 5139 .FromJust()); 5140 CHECK_EQ(16, a3->Get(context.local(), 2) 5141 .ToLocalChecked() 5142 ->Int32Value(context.local()) 5143 .FromJust()); 5144 5145 const char* fun5 = "f(17, 18, 19, 20)"; 5146 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 5147 CHECK_EQ(4u, a4->Length()); 5148 CHECK_EQ(17, a4->Get(context.local(), 0) 5149 .ToLocalChecked() 5150 ->Int32Value(context.local()) 5151 .FromJust()); 5152 CHECK_EQ(18, a4->Get(context.local(), 1) 5153 .ToLocalChecked() 5154 ->Int32Value(context.local()) 5155 .FromJust()); 5156 CHECK_EQ(19, a4->Get(context.local(), 2) 5157 .ToLocalChecked() 5158 ->Int32Value(context.local()) 5159 .FromJust()); 5160 CHECK_EQ(20, a4->Get(context.local(), 3) 5161 .ToLocalChecked() 5162 ->Int32Value(context.local()) 5163 .FromJust()); 5164 } 5165 5166 5167 THREADED_TEST(FunctionCall) { 5168 LocalContext context; 5169 v8::Isolate* isolate = context->GetIsolate(); 5170 v8::HandleScope scope(isolate); 5171 CompileRun( 5172 "function Foo() {" 5173 " var result = [];" 5174 " for (var i = 0; i < arguments.length; i++) {" 5175 " result.push(arguments[i]);" 5176 " }" 5177 " return result;" 5178 "}" 5179 "function ReturnThisSloppy() {" 5180 " return this;" 5181 "}" 5182 "function ReturnThisStrict() {" 5183 " 'use strict';" 5184 " return this;" 5185 "}"); 5186 Local<Function> Foo = Local<Function>::Cast( 5187 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked()); 5188 Local<Function> ReturnThisSloppy = Local<Function>::Cast( 5189 context->Global() 5190 ->Get(context.local(), v8_str("ReturnThisSloppy")) 5191 .ToLocalChecked()); 5192 Local<Function> ReturnThisStrict = Local<Function>::Cast( 5193 context->Global() 5194 ->Get(context.local(), v8_str("ReturnThisStrict")) 5195 .ToLocalChecked()); 5196 5197 v8::Local<Value>* args0 = NULL; 5198 Local<v8::Array> a0 = Local<v8::Array>::Cast( 5199 Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked()); 5200 CHECK_EQ(0u, a0->Length()); 5201 5202 v8::Local<Value> args1[] = {v8_num(1.1)}; 5203 Local<v8::Array> a1 = Local<v8::Array>::Cast( 5204 Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked()); 5205 CHECK_EQ(1u, a1->Length()); 5206 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0)) 5207 .ToLocalChecked() 5208 ->NumberValue(context.local()) 5209 .FromJust()); 5210 5211 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)}; 5212 Local<v8::Array> a2 = Local<v8::Array>::Cast( 5213 Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked()); 5214 CHECK_EQ(2u, a2->Length()); 5215 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0)) 5216 .ToLocalChecked() 5217 ->NumberValue(context.local()) 5218 .FromJust()); 5219 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1)) 5220 .ToLocalChecked() 5221 ->NumberValue(context.local()) 5222 .FromJust()); 5223 5224 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)}; 5225 Local<v8::Array> a3 = Local<v8::Array>::Cast( 5226 Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked()); 5227 CHECK_EQ(3u, a3->Length()); 5228 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0)) 5229 .ToLocalChecked() 5230 ->NumberValue(context.local()) 5231 .FromJust()); 5232 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1)) 5233 .ToLocalChecked() 5234 ->NumberValue(context.local()) 5235 .FromJust()); 5236 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2)) 5237 .ToLocalChecked() 5238 ->NumberValue(context.local()) 5239 .FromJust()); 5240 5241 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9), 5242 v8_num(10.11)}; 5243 Local<v8::Array> a4 = Local<v8::Array>::Cast( 5244 Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked()); 5245 CHECK_EQ(4u, a4->Length()); 5246 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0)) 5247 .ToLocalChecked() 5248 ->NumberValue(context.local()) 5249 .FromJust()); 5250 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1)) 5251 .ToLocalChecked() 5252 ->NumberValue(context.local()) 5253 .FromJust()); 5254 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2)) 5255 .ToLocalChecked() 5256 ->NumberValue(context.local()) 5257 .FromJust()); 5258 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3)) 5259 .ToLocalChecked() 5260 ->NumberValue(context.local()) 5261 .FromJust()); 5262 5263 Local<v8::Value> r1 = 5264 ReturnThisSloppy->Call(context.local(), v8::Undefined(isolate), 0, NULL) 5265 .ToLocalChecked(); 5266 CHECK(r1->StrictEquals(context->Global())); 5267 Local<v8::Value> r2 = 5268 ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, NULL) 5269 .ToLocalChecked(); 5270 CHECK(r2->StrictEquals(context->Global())); 5271 Local<v8::Value> r3 = 5272 ReturnThisSloppy->Call(context.local(), v8_num(42), 0, NULL) 5273 .ToLocalChecked(); 5274 CHECK(r3->IsNumberObject()); 5275 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf()); 5276 Local<v8::Value> r4 = 5277 ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, NULL) 5278 .ToLocalChecked(); 5279 CHECK(r4->IsStringObject()); 5280 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 5281 Local<v8::Value> r5 = 5282 ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, NULL) 5283 .ToLocalChecked(); 5284 CHECK(r5->IsBooleanObject()); 5285 CHECK(r5.As<v8::BooleanObject>()->ValueOf()); 5286 5287 Local<v8::Value> r6 = 5288 ReturnThisStrict->Call(context.local(), v8::Undefined(isolate), 0, NULL) 5289 .ToLocalChecked(); 5290 CHECK(r6->IsUndefined()); 5291 Local<v8::Value> r7 = 5292 ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, NULL) 5293 .ToLocalChecked(); 5294 CHECK(r7->IsNull()); 5295 Local<v8::Value> r8 = 5296 ReturnThisStrict->Call(context.local(), v8_num(42), 0, NULL) 5297 .ToLocalChecked(); 5298 CHECK(r8->StrictEquals(v8_num(42))); 5299 Local<v8::Value> r9 = 5300 ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, NULL) 5301 .ToLocalChecked(); 5302 CHECK(r9->StrictEquals(v8_str("hello"))); 5303 Local<v8::Value> r10 = 5304 ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, NULL) 5305 .ToLocalChecked(); 5306 CHECK(r10->StrictEquals(v8::True(isolate))); 5307 } 5308 5309 5310 THREADED_TEST(ConstructCall) { 5311 LocalContext context; 5312 v8::Isolate* isolate = context->GetIsolate(); 5313 v8::HandleScope scope(isolate); 5314 CompileRun( 5315 "function Foo() {" 5316 " var result = [];" 5317 " for (var i = 0; i < arguments.length; i++) {" 5318 " result.push(arguments[i]);" 5319 " }" 5320 " return result;" 5321 "}"); 5322 Local<Function> Foo = Local<Function>::Cast( 5323 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked()); 5324 5325 v8::Local<Value>* args0 = NULL; 5326 Local<v8::Array> a0 = Local<v8::Array>::Cast( 5327 Foo->NewInstance(context.local(), 0, args0).ToLocalChecked()); 5328 CHECK_EQ(0u, a0->Length()); 5329 5330 v8::Local<Value> args1[] = {v8_num(1.1)}; 5331 Local<v8::Array> a1 = Local<v8::Array>::Cast( 5332 Foo->NewInstance(context.local(), 1, args1).ToLocalChecked()); 5333 CHECK_EQ(1u, a1->Length()); 5334 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0)) 5335 .ToLocalChecked() 5336 ->NumberValue(context.local()) 5337 .FromJust()); 5338 5339 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)}; 5340 Local<v8::Array> a2 = Local<v8::Array>::Cast( 5341 Foo->NewInstance(context.local(), 2, args2).ToLocalChecked()); 5342 CHECK_EQ(2u, a2->Length()); 5343 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0)) 5344 .ToLocalChecked() 5345 ->NumberValue(context.local()) 5346 .FromJust()); 5347 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1)) 5348 .ToLocalChecked() 5349 ->NumberValue(context.local()) 5350 .FromJust()); 5351 5352 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)}; 5353 Local<v8::Array> a3 = Local<v8::Array>::Cast( 5354 Foo->NewInstance(context.local(), 3, args3).ToLocalChecked()); 5355 CHECK_EQ(3u, a3->Length()); 5356 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0)) 5357 .ToLocalChecked() 5358 ->NumberValue(context.local()) 5359 .FromJust()); 5360 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1)) 5361 .ToLocalChecked() 5362 ->NumberValue(context.local()) 5363 .FromJust()); 5364 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2)) 5365 .ToLocalChecked() 5366 ->NumberValue(context.local()) 5367 .FromJust()); 5368 5369 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9), 5370 v8_num(10.11)}; 5371 Local<v8::Array> a4 = Local<v8::Array>::Cast( 5372 Foo->NewInstance(context.local(), 4, args4).ToLocalChecked()); 5373 CHECK_EQ(4u, a4->Length()); 5374 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0)) 5375 .ToLocalChecked() 5376 ->NumberValue(context.local()) 5377 .FromJust()); 5378 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1)) 5379 .ToLocalChecked() 5380 ->NumberValue(context.local()) 5381 .FromJust()); 5382 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2)) 5383 .ToLocalChecked() 5384 ->NumberValue(context.local()) 5385 .FromJust()); 5386 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3)) 5387 .ToLocalChecked() 5388 ->NumberValue(context.local()) 5389 .FromJust()); 5390 } 5391 5392 5393 THREADED_TEST(ConversionNumber) { 5394 LocalContext env; 5395 v8::Isolate* isolate = env->GetIsolate(); 5396 v8::HandleScope scope(isolate); 5397 // Very large number. 5398 CompileRun("var obj = Math.pow(2,32) * 1237;"); 5399 Local<Value> obj = 5400 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5401 CHECK_EQ(5312874545152.0, 5402 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5403 CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5404 CHECK(0u == 5405 obj->ToUint32(env.local()) 5406 .ToLocalChecked() 5407 ->Value()); // NOLINT - no CHECK_EQ for unsigned. 5408 // Large number. 5409 CompileRun("var obj = -1234567890123;"); 5410 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5411 CHECK_EQ(-1234567890123.0, 5412 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5413 CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5414 CHECK(2382691125u == 5415 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5416 // Small positive integer. 5417 CompileRun("var obj = 42;"); 5418 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5419 CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5420 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5421 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5422 // Negative integer. 5423 CompileRun("var obj = -37;"); 5424 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5425 CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5426 CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5427 CHECK(4294967259u == 5428 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5429 // Positive non-int32 integer. 5430 CompileRun("var obj = 0x81234567;"); 5431 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5432 CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5433 CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5434 CHECK(2166572391u == 5435 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5436 // Fraction. 5437 CompileRun("var obj = 42.3;"); 5438 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5439 CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5440 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5441 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5442 // Large negative fraction. 5443 CompileRun("var obj = -5726623061.75;"); 5444 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5445 CHECK_EQ(-5726623061.75, 5446 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5447 CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5448 CHECK(2863311531u == 5449 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5450 } 5451 5452 5453 THREADED_TEST(isNumberType) { 5454 LocalContext env; 5455 v8::HandleScope scope(env->GetIsolate()); 5456 // Very large number. 5457 CompileRun("var obj = Math.pow(2,32) * 1237;"); 5458 Local<Value> obj = 5459 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5460 CHECK(!obj->IsInt32()); 5461 CHECK(!obj->IsUint32()); 5462 // Large negative number. 5463 CompileRun("var obj = -1234567890123;"); 5464 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5465 CHECK(!obj->IsInt32()); 5466 CHECK(!obj->IsUint32()); 5467 // Small positive integer. 5468 CompileRun("var obj = 42;"); 5469 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5470 CHECK(obj->IsInt32()); 5471 CHECK(obj->IsUint32()); 5472 // Negative integer. 5473 CompileRun("var obj = -37;"); 5474 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5475 CHECK(obj->IsInt32()); 5476 CHECK(!obj->IsUint32()); 5477 // Positive non-int32 integer. 5478 CompileRun("var obj = 0x81234567;"); 5479 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5480 CHECK(!obj->IsInt32()); 5481 CHECK(obj->IsUint32()); 5482 // Fraction. 5483 CompileRun("var obj = 42.3;"); 5484 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5485 CHECK(!obj->IsInt32()); 5486 CHECK(!obj->IsUint32()); 5487 // Large negative fraction. 5488 CompileRun("var obj = -5726623061.75;"); 5489 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5490 CHECK(!obj->IsInt32()); 5491 CHECK(!obj->IsUint32()); 5492 // Positive zero 5493 CompileRun("var obj = 0.0;"); 5494 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5495 CHECK(obj->IsInt32()); 5496 CHECK(obj->IsUint32()); 5497 // Positive zero 5498 CompileRun("var obj = -0.0;"); 5499 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5500 CHECK(!obj->IsInt32()); 5501 CHECK(!obj->IsUint32()); 5502 } 5503 5504 5505 static void CheckUncle(v8::TryCatch* try_catch) { 5506 CHECK(try_catch->HasCaught()); 5507 String::Utf8Value str_value(try_catch->Exception()); 5508 CHECK_EQ(0, strcmp(*str_value, "uncle?")); 5509 try_catch->Reset(); 5510 } 5511 5512 5513 THREADED_TEST(ConversionException) { 5514 LocalContext env; 5515 v8::Isolate* isolate = env->GetIsolate(); 5516 v8::HandleScope scope(isolate); 5517 CompileRun( 5518 "function TestClass() { };" 5519 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 5520 "var obj = new TestClass();"); 5521 Local<Value> obj = 5522 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5523 5524 v8::TryCatch try_catch(isolate); 5525 5526 CHECK(obj->ToString(env.local()).IsEmpty()); 5527 CheckUncle(&try_catch); 5528 5529 CHECK(obj->ToNumber(env.local()).IsEmpty()); 5530 CheckUncle(&try_catch); 5531 5532 CHECK(obj->ToInteger(env.local()).IsEmpty()); 5533 CheckUncle(&try_catch); 5534 5535 CHECK(obj->ToUint32(env.local()).IsEmpty()); 5536 CheckUncle(&try_catch); 5537 5538 CHECK(obj->ToInt32(env.local()).IsEmpty()); 5539 CheckUncle(&try_catch); 5540 5541 CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty()); 5542 CHECK(try_catch.HasCaught()); 5543 try_catch.Reset(); 5544 5545 CHECK(obj->Int32Value(env.local()).IsNothing()); 5546 CheckUncle(&try_catch); 5547 5548 CHECK(obj->Uint32Value(env.local()).IsNothing()); 5549 CheckUncle(&try_catch); 5550 5551 CHECK(obj->NumberValue(env.local()).IsNothing()); 5552 CheckUncle(&try_catch); 5553 5554 CHECK(obj->IntegerValue(env.local()).IsNothing()); 5555 CheckUncle(&try_catch); 5556 } 5557 5558 5559 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 5560 ApiTestFuzzer::Fuzz(); 5561 args.GetIsolate()->ThrowException(v8_str("konto")); 5562 } 5563 5564 5565 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 5566 if (args.Length() < 1) { 5567 args.GetReturnValue().Set(false); 5568 return; 5569 } 5570 v8::HandleScope scope(args.GetIsolate()); 5571 v8::TryCatch try_catch(args.GetIsolate()); 5572 Local<Value> result = 5573 CompileRun(args[0] 5574 ->ToString(args.GetIsolate()->GetCurrentContext()) 5575 .ToLocalChecked()); 5576 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 5577 args.GetReturnValue().Set(try_catch.HasCaught()); 5578 } 5579 5580 5581 THREADED_TEST(APICatch) { 5582 v8::Isolate* isolate = CcTest::isolate(); 5583 v8::HandleScope scope(isolate); 5584 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5585 templ->Set(v8_str("ThrowFromC"), 5586 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5587 LocalContext context(0, templ); 5588 CompileRun( 5589 "var thrown = false;" 5590 "try {" 5591 " ThrowFromC();" 5592 "} catch (e) {" 5593 " thrown = true;" 5594 "}"); 5595 Local<Value> thrown = context->Global() 5596 ->Get(context.local(), v8_str("thrown")) 5597 .ToLocalChecked(); 5598 CHECK(thrown->BooleanValue(context.local()).FromJust()); 5599 } 5600 5601 5602 THREADED_TEST(APIThrowTryCatch) { 5603 v8::Isolate* isolate = CcTest::isolate(); 5604 v8::HandleScope scope(isolate); 5605 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5606 templ->Set(v8_str("ThrowFromC"), 5607 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5608 LocalContext context(0, templ); 5609 v8::TryCatch try_catch(isolate); 5610 CompileRun("ThrowFromC();"); 5611 CHECK(try_catch.HasCaught()); 5612 } 5613 5614 5615 // Test that a try-finally block doesn't shadow a try-catch block 5616 // when setting up an external handler. 5617 // 5618 // BUG(271): Some of the exception propagation does not work on the 5619 // ARM simulator because the simulator separates the C++ stack and the 5620 // JS stack. This test therefore fails on the simulator. The test is 5621 // not threaded to allow the threading tests to run on the simulator. 5622 TEST(TryCatchInTryFinally) { 5623 v8::Isolate* isolate = CcTest::isolate(); 5624 v8::HandleScope scope(isolate); 5625 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5626 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher)); 5627 LocalContext context(0, templ); 5628 Local<Value> result = CompileRun( 5629 "try {" 5630 " try {" 5631 " CCatcher('throw 7;');" 5632 " } finally {" 5633 " }" 5634 "} catch (e) {" 5635 "}"); 5636 CHECK(result->IsTrue()); 5637 } 5638 5639 5640 static void check_custom_error_tostring(v8::Local<v8::Message> message, 5641 v8::Local<v8::Value> data) { 5642 const char* uncaught_error = "Uncaught MyError toString"; 5643 CHECK(message->Get() 5644 ->Equals(CcTest::isolate()->GetCurrentContext(), 5645 v8_str(uncaught_error)) 5646 .FromJust()); 5647 } 5648 5649 5650 TEST(CustomErrorToString) { 5651 LocalContext context; 5652 v8::HandleScope scope(context->GetIsolate()); 5653 context->GetIsolate()->AddMessageListener(check_custom_error_tostring); 5654 CompileRun( 5655 "function MyError(name, message) { " 5656 " this.name = name; " 5657 " this.message = message; " 5658 "} " 5659 "MyError.prototype = Object.create(Error.prototype); " 5660 "MyError.prototype.toString = function() { " 5661 " return 'MyError toString'; " 5662 "}; " 5663 "throw new MyError('my name', 'my message'); "); 5664 context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring); 5665 } 5666 5667 5668 static void check_custom_error_message(v8::Local<v8::Message> message, 5669 v8::Local<v8::Value> data) { 5670 const char* uncaught_error = "Uncaught MyError: my message"; 5671 printf("%s\n", *v8::String::Utf8Value(message->Get())); 5672 CHECK(message->Get() 5673 ->Equals(CcTest::isolate()->GetCurrentContext(), 5674 v8_str(uncaught_error)) 5675 .FromJust()); 5676 } 5677 5678 5679 TEST(CustomErrorMessage) { 5680 LocalContext context; 5681 v8::HandleScope scope(context->GetIsolate()); 5682 context->GetIsolate()->AddMessageListener(check_custom_error_message); 5683 5684 // Handlebars. 5685 CompileRun( 5686 "function MyError(msg) { " 5687 " this.name = 'MyError'; " 5688 " this.message = msg; " 5689 "} " 5690 "MyError.prototype = new Error(); " 5691 "throw new MyError('my message'); "); 5692 5693 // Closure. 5694 CompileRun( 5695 "function MyError(msg) { " 5696 " this.name = 'MyError'; " 5697 " this.message = msg; " 5698 "} " 5699 "inherits = function(childCtor, parentCtor) { " 5700 " function tempCtor() {}; " 5701 " tempCtor.prototype = parentCtor.prototype; " 5702 " childCtor.superClass_ = parentCtor.prototype; " 5703 " childCtor.prototype = new tempCtor(); " 5704 " childCtor.prototype.constructor = childCtor; " 5705 "}; " 5706 "inherits(MyError, Error); " 5707 "throw new MyError('my message'); "); 5708 5709 // Object.create. 5710 CompileRun( 5711 "function MyError(msg) { " 5712 " this.name = 'MyError'; " 5713 " this.message = msg; " 5714 "} " 5715 "MyError.prototype = Object.create(Error.prototype); " 5716 "throw new MyError('my message'); "); 5717 5718 context->GetIsolate()->RemoveMessageListeners(check_custom_error_message); 5719 } 5720 5721 5722 static void check_custom_rethrowing_message(v8::Local<v8::Message> message, 5723 v8::Local<v8::Value> data) { 5724 const char* uncaught_error = "Uncaught exception"; 5725 CHECK(message->Get() 5726 ->Equals(CcTest::isolate()->GetCurrentContext(), 5727 v8_str(uncaught_error)) 5728 .FromJust()); 5729 } 5730 5731 5732 TEST(CustomErrorRethrowsOnToString) { 5733 LocalContext context; 5734 v8::HandleScope scope(context->GetIsolate()); 5735 context->GetIsolate()->AddMessageListener(check_custom_rethrowing_message); 5736 5737 CompileRun( 5738 "var e = { toString: function() { throw e; } };" 5739 "try { throw e; } finally {}"); 5740 5741 context->GetIsolate()->RemoveMessageListeners( 5742 check_custom_rethrowing_message); 5743 } 5744 5745 5746 static void receive_message(v8::Local<v8::Message> message, 5747 v8::Local<v8::Value> data) { 5748 message->Get(); 5749 message_received = true; 5750 } 5751 5752 5753 TEST(APIThrowMessage) { 5754 message_received = false; 5755 v8::Isolate* isolate = CcTest::isolate(); 5756 v8::HandleScope scope(isolate); 5757 isolate->AddMessageListener(receive_message); 5758 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5759 templ->Set(v8_str("ThrowFromC"), 5760 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5761 LocalContext context(0, templ); 5762 CompileRun("ThrowFromC();"); 5763 CHECK(message_received); 5764 isolate->RemoveMessageListeners(receive_message); 5765 } 5766 5767 5768 TEST(APIThrowMessageAndVerboseTryCatch) { 5769 message_received = false; 5770 v8::Isolate* isolate = CcTest::isolate(); 5771 v8::HandleScope scope(isolate); 5772 isolate->AddMessageListener(receive_message); 5773 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5774 templ->Set(v8_str("ThrowFromC"), 5775 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5776 LocalContext context(0, templ); 5777 v8::TryCatch try_catch(isolate); 5778 try_catch.SetVerbose(true); 5779 Local<Value> result = CompileRun("ThrowFromC();"); 5780 CHECK(try_catch.HasCaught()); 5781 CHECK(result.IsEmpty()); 5782 CHECK(message_received); 5783 isolate->RemoveMessageListeners(receive_message); 5784 } 5785 5786 5787 TEST(APIStackOverflowAndVerboseTryCatch) { 5788 message_received = false; 5789 LocalContext context; 5790 v8::HandleScope scope(context->GetIsolate()); 5791 context->GetIsolate()->AddMessageListener(receive_message); 5792 v8::TryCatch try_catch(context->GetIsolate()); 5793 try_catch.SetVerbose(true); 5794 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 5795 CHECK(try_catch.HasCaught()); 5796 CHECK(result.IsEmpty()); 5797 CHECK(message_received); 5798 context->GetIsolate()->RemoveMessageListeners(receive_message); 5799 } 5800 5801 5802 THREADED_TEST(ExternalScriptException) { 5803 v8::Isolate* isolate = CcTest::isolate(); 5804 v8::HandleScope scope(isolate); 5805 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5806 templ->Set(v8_str("ThrowFromC"), 5807 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5808 LocalContext context(0, templ); 5809 5810 v8::TryCatch try_catch(isolate); 5811 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';"); 5812 CHECK(result.IsEmpty()); 5813 CHECK(try_catch.HasCaught()); 5814 String::Utf8Value exception_value(try_catch.Exception()); 5815 CHECK_EQ(0, strcmp("konto", *exception_value)); 5816 } 5817 5818 5819 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 5820 ApiTestFuzzer::Fuzz(); 5821 CHECK_EQ(4, args.Length()); 5822 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 5823 int count = args[0]->Int32Value(context).FromJust(); 5824 int cInterval = args[2]->Int32Value(context).FromJust(); 5825 if (count == 0) { 5826 args.GetIsolate()->ThrowException(v8_str("FromC")); 5827 return; 5828 } else { 5829 Local<v8::Object> global = context->Global(); 5830 Local<Value> fun = 5831 global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked(); 5832 v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]}; 5833 if (count % cInterval == 0) { 5834 v8::TryCatch try_catch(args.GetIsolate()); 5835 Local<Value> result = fun.As<Function>() 5836 ->Call(context, global, 4, argv) 5837 .FromMaybe(Local<Value>()); 5838 int expected = args[3]->Int32Value(context).FromJust(); 5839 if (try_catch.HasCaught()) { 5840 CHECK_EQ(expected, count); 5841 CHECK(result.IsEmpty()); 5842 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 5843 } else { 5844 CHECK_NE(expected, count); 5845 } 5846 args.GetReturnValue().Set(result); 5847 return; 5848 } else { 5849 args.GetReturnValue().Set(fun.As<Function>() 5850 ->Call(context, global, 4, argv) 5851 .FromMaybe(v8::Local<v8::Value>())); 5852 return; 5853 } 5854 } 5855 } 5856 5857 5858 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 5859 ApiTestFuzzer::Fuzz(); 5860 CHECK_EQ(3, args.Length()); 5861 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 5862 bool equality = args[0]->BooleanValue(context).FromJust(); 5863 int count = args[1]->Int32Value(context).FromJust(); 5864 int expected = args[2]->Int32Value(context).FromJust(); 5865 if (equality) { 5866 CHECK_EQ(count, expected); 5867 } else { 5868 CHECK_NE(count, expected); 5869 } 5870 } 5871 5872 5873 THREADED_TEST(EvalInTryFinally) { 5874 LocalContext context; 5875 v8::HandleScope scope(context->GetIsolate()); 5876 v8::TryCatch try_catch(context->GetIsolate()); 5877 CompileRun( 5878 "(function() {" 5879 " try {" 5880 " eval('asldkf (*&^&*^');" 5881 " } finally {" 5882 " return;" 5883 " }" 5884 "})()"); 5885 CHECK(!try_catch.HasCaught()); 5886 } 5887 5888 5889 // This test works by making a stack of alternating JavaScript and C 5890 // activations. These activations set up exception handlers with regular 5891 // intervals, one interval for C activations and another for JavaScript 5892 // activations. When enough activations have been created an exception is 5893 // thrown and we check that the right activation catches the exception and that 5894 // no other activations do. The right activation is always the topmost one with 5895 // a handler, regardless of whether it is in JavaScript or C. 5896 // 5897 // The notation used to describe a test case looks like this: 5898 // 5899 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5900 // 5901 // Each entry is an activation, either JS or C. The index is the count at that 5902 // level. Stars identify activations with exception handlers, the @ identifies 5903 // the exception handler that should catch the exception. 5904 // 5905 // BUG(271): Some of the exception propagation does not work on the 5906 // ARM simulator because the simulator separates the C++ stack and the 5907 // JS stack. This test therefore fails on the simulator. The test is 5908 // not threaded to allow the threading tests to run on the simulator. 5909 TEST(ExceptionOrder) { 5910 v8::Isolate* isolate = CcTest::isolate(); 5911 v8::HandleScope scope(isolate); 5912 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5913 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck)); 5914 templ->Set(v8_str("CThrowCountDown"), 5915 v8::FunctionTemplate::New(isolate, CThrowCountDown)); 5916 LocalContext context(0, templ); 5917 CompileRun( 5918 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 5919 " if (count == 0) throw 'FromJS';" 5920 " if (count % jsInterval == 0) {" 5921 " try {" 5922 " var value = CThrowCountDown(count - 1," 5923 " jsInterval," 5924 " cInterval," 5925 " expected);" 5926 " check(false, count, expected);" 5927 " return value;" 5928 " } catch (e) {" 5929 " check(true, count, expected);" 5930 " }" 5931 " } else {" 5932 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 5933 " }" 5934 "}"); 5935 Local<Function> fun = Local<Function>::Cast( 5936 context->Global() 5937 ->Get(context.local(), v8_str("JSThrowCountDown")) 5938 .ToLocalChecked()); 5939 5940 const int argc = 4; 5941 // count jsInterval cInterval expected 5942 5943 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5944 v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)}; 5945 fun->Call(context.local(), fun, argc, a0).ToLocalChecked(); 5946 5947 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 5948 v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)}; 5949 fun->Call(context.local(), fun, argc, a1).ToLocalChecked(); 5950 5951 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 5952 v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)}; 5953 fun->Call(context.local(), fun, argc, a2).ToLocalChecked(); 5954 5955 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 5956 v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)}; 5957 fun->Call(context.local(), fun, argc, a3).ToLocalChecked(); 5958 5959 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 5960 v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)}; 5961 fun->Call(context.local(), fun, argc, a4).ToLocalChecked(); 5962 5963 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 5964 v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)}; 5965 fun->Call(context.local(), fun, argc, a5).ToLocalChecked(); 5966 } 5967 5968 5969 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 5970 ApiTestFuzzer::Fuzz(); 5971 CHECK_EQ(1, args.Length()); 5972 args.GetIsolate()->ThrowException(args[0]); 5973 } 5974 5975 5976 THREADED_TEST(ThrowValues) { 5977 v8::Isolate* isolate = CcTest::isolate(); 5978 v8::HandleScope scope(isolate); 5979 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5980 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue)); 5981 LocalContext context(0, templ); 5982 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast( 5983 CompileRun("function Run(obj) {" 5984 " try {" 5985 " Throw(obj);" 5986 " } catch (e) {" 5987 " return e;" 5988 " }" 5989 " return 'no exception';" 5990 "}" 5991 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 5992 CHECK_EQ(5u, result->Length()); 5993 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0)) 5994 .ToLocalChecked() 5995 ->IsString()); 5996 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1)) 5997 .ToLocalChecked() 5998 ->IsNumber()); 5999 CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1)) 6000 .ToLocalChecked() 6001 ->Int32Value(context.local()) 6002 .FromJust()); 6003 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2)) 6004 .ToLocalChecked() 6005 ->IsNumber()); 6006 CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2)) 6007 .ToLocalChecked() 6008 ->Int32Value(context.local()) 6009 .FromJust()); 6010 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3)) 6011 .ToLocalChecked() 6012 ->IsNull()); 6013 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4)) 6014 .ToLocalChecked() 6015 ->IsUndefined()); 6016 } 6017 6018 6019 THREADED_TEST(CatchZero) { 6020 LocalContext context; 6021 v8::HandleScope scope(context->GetIsolate()); 6022 v8::TryCatch try_catch(context->GetIsolate()); 6023 CHECK(!try_catch.HasCaught()); 6024 CompileRun("throw 10"); 6025 CHECK(try_catch.HasCaught()); 6026 CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust()); 6027 try_catch.Reset(); 6028 CHECK(!try_catch.HasCaught()); 6029 CompileRun("throw 0"); 6030 CHECK(try_catch.HasCaught()); 6031 CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust()); 6032 } 6033 6034 6035 THREADED_TEST(CatchExceptionFromWith) { 6036 LocalContext context; 6037 v8::HandleScope scope(context->GetIsolate()); 6038 v8::TryCatch try_catch(context->GetIsolate()); 6039 CHECK(!try_catch.HasCaught()); 6040 CompileRun("var o = {}; with (o) { throw 42; }"); 6041 CHECK(try_catch.HasCaught()); 6042 } 6043 6044 6045 THREADED_TEST(TryCatchAndFinallyHidingException) { 6046 LocalContext context; 6047 v8::HandleScope scope(context->GetIsolate()); 6048 v8::TryCatch try_catch(context->GetIsolate()); 6049 CHECK(!try_catch.HasCaught()); 6050 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 6051 CompileRun("f({toString: function() { throw 42; }});"); 6052 CHECK(!try_catch.HasCaught()); 6053 } 6054 6055 6056 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 6057 v8::TryCatch try_catch(args.GetIsolate()); 6058 } 6059 6060 6061 THREADED_TEST(TryCatchAndFinally) { 6062 LocalContext context; 6063 v8::Isolate* isolate = context->GetIsolate(); 6064 v8::HandleScope scope(isolate); 6065 CHECK(context->Global() 6066 ->Set(context.local(), v8_str("native_with_try_catch"), 6067 v8::FunctionTemplate::New(isolate, WithTryCatch) 6068 ->GetFunction(context.local()) 6069 .ToLocalChecked()) 6070 .FromJust()); 6071 v8::TryCatch try_catch(isolate); 6072 CHECK(!try_catch.HasCaught()); 6073 CompileRun( 6074 "try {\n" 6075 " throw new Error('a');\n" 6076 "} finally {\n" 6077 " native_with_try_catch();\n" 6078 "}\n"); 6079 CHECK(try_catch.HasCaught()); 6080 } 6081 6082 6083 static void TryCatchNested1Helper(int depth) { 6084 if (depth > 0) { 6085 v8::TryCatch try_catch(CcTest::isolate()); 6086 try_catch.SetVerbose(true); 6087 TryCatchNested1Helper(depth - 1); 6088 CHECK(try_catch.HasCaught()); 6089 try_catch.ReThrow(); 6090 } else { 6091 CcTest::isolate()->ThrowException(v8_str("E1")); 6092 } 6093 } 6094 6095 6096 static void TryCatchNested2Helper(int depth) { 6097 if (depth > 0) { 6098 v8::TryCatch try_catch(CcTest::isolate()); 6099 try_catch.SetVerbose(true); 6100 TryCatchNested2Helper(depth - 1); 6101 CHECK(try_catch.HasCaught()); 6102 try_catch.ReThrow(); 6103 } else { 6104 CompileRun("throw 'E2';"); 6105 } 6106 } 6107 6108 6109 TEST(TryCatchNested) { 6110 v8::V8::Initialize(); 6111 LocalContext context; 6112 v8::HandleScope scope(context->GetIsolate()); 6113 6114 { 6115 // Test nested try-catch with a native throw in the end. 6116 v8::TryCatch try_catch(context->GetIsolate()); 6117 TryCatchNested1Helper(5); 6118 CHECK(try_catch.HasCaught()); 6119 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1")); 6120 } 6121 6122 { 6123 // Test nested try-catch with a JavaScript throw in the end. 6124 v8::TryCatch try_catch(context->GetIsolate()); 6125 TryCatchNested2Helper(5); 6126 CHECK(try_catch.HasCaught()); 6127 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2")); 6128 } 6129 } 6130 6131 6132 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 6133 CHECK(try_catch->HasCaught()); 6134 Local<Message> message = try_catch->Message(); 6135 Local<Value> resource = message->GetScriptOrigin().ResourceName(); 6136 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 6137 CHECK_EQ(0, 6138 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a")); 6139 CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext()) 6140 .FromJust()); 6141 CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext()) 6142 .FromJust()); 6143 } 6144 6145 6146 void TryCatchMixedNestingHelper( 6147 const v8::FunctionCallbackInfo<v8::Value>& args) { 6148 ApiTestFuzzer::Fuzz(); 6149 v8::TryCatch try_catch(args.GetIsolate()); 6150 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 6151 CHECK(try_catch.HasCaught()); 6152 TryCatchMixedNestingCheck(&try_catch); 6153 try_catch.ReThrow(); 6154 } 6155 6156 6157 // This test ensures that an outer TryCatch in the following situation: 6158 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 6159 // does not clobber the Message object generated for the inner TryCatch. 6160 // This exercises the ability of TryCatch.ReThrow() to restore the 6161 // inner pending Message before throwing the exception again. 6162 TEST(TryCatchMixedNesting) { 6163 v8::Isolate* isolate = CcTest::isolate(); 6164 v8::HandleScope scope(isolate); 6165 v8::V8::Initialize(); 6166 v8::TryCatch try_catch(isolate); 6167 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6168 templ->Set(v8_str("TryCatchMixedNestingHelper"), 6169 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper)); 6170 LocalContext context(0, templ); 6171 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 6172 TryCatchMixedNestingCheck(&try_catch); 6173 } 6174 6175 6176 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) { 6177 ApiTestFuzzer::Fuzz(); 6178 v8::TryCatch try_catch(args.GetIsolate()); 6179 args.GetIsolate()->ThrowException(v8_str("boom")); 6180 CHECK(try_catch.HasCaught()); 6181 } 6182 6183 6184 TEST(TryCatchNative) { 6185 v8::Isolate* isolate = CcTest::isolate(); 6186 v8::HandleScope scope(isolate); 6187 v8::V8::Initialize(); 6188 v8::TryCatch try_catch(isolate); 6189 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6190 templ->Set(v8_str("TryCatchNativeHelper"), 6191 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper)); 6192 LocalContext context(0, templ); 6193 CompileRun("TryCatchNativeHelper();"); 6194 CHECK(!try_catch.HasCaught()); 6195 } 6196 6197 6198 void TryCatchNativeResetHelper( 6199 const v8::FunctionCallbackInfo<v8::Value>& args) { 6200 ApiTestFuzzer::Fuzz(); 6201 v8::TryCatch try_catch(args.GetIsolate()); 6202 args.GetIsolate()->ThrowException(v8_str("boom")); 6203 CHECK(try_catch.HasCaught()); 6204 try_catch.Reset(); 6205 CHECK(!try_catch.HasCaught()); 6206 } 6207 6208 6209 TEST(TryCatchNativeReset) { 6210 v8::Isolate* isolate = CcTest::isolate(); 6211 v8::HandleScope scope(isolate); 6212 v8::V8::Initialize(); 6213 v8::TryCatch try_catch(isolate); 6214 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6215 templ->Set(v8_str("TryCatchNativeResetHelper"), 6216 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper)); 6217 LocalContext context(0, templ); 6218 CompileRun("TryCatchNativeResetHelper();"); 6219 CHECK(!try_catch.HasCaught()); 6220 } 6221 6222 6223 THREADED_TEST(Equality) { 6224 LocalContext context; 6225 v8::Isolate* isolate = context->GetIsolate(); 6226 v8::HandleScope scope(context->GetIsolate()); 6227 // Check that equality works at all before relying on CHECK_EQ 6228 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust()); 6229 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust()); 6230 6231 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust()); 6232 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust()); 6233 CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust()); 6234 CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust()); 6235 CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust()); 6236 6237 // Assume String is not internalized. 6238 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 6239 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 6240 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 6241 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 6242 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 6243 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); 6244 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN()); 6245 CHECK(!not_a_number->StrictEquals(not_a_number)); 6246 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); 6247 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); 6248 6249 v8::Local<v8::Object> obj = v8::Object::New(isolate); 6250 v8::Persistent<v8::Object> alias(isolate, obj); 6251 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 6252 alias.Reset(); 6253 6254 CHECK(v8_str("a")->SameValue(v8_str("a"))); 6255 CHECK(!v8_str("a")->SameValue(v8_str("b"))); 6256 CHECK(!v8_str("5")->SameValue(v8_num(5))); 6257 CHECK(v8_num(1)->SameValue(v8_num(1))); 6258 CHECK(!v8_num(1)->SameValue(v8_num(2))); 6259 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0))); 6260 CHECK(not_a_number->SameValue(not_a_number)); 6261 CHECK(v8::False(isolate)->SameValue(v8::False(isolate))); 6262 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate))); 6263 } 6264 6265 6266 THREADED_TEST(MultiRun) { 6267 LocalContext context; 6268 v8::HandleScope scope(context->GetIsolate()); 6269 Local<Script> script = v8_compile("x"); 6270 for (int i = 0; i < 10; i++) { 6271 script->Run(context.local()).IsEmpty(); 6272 } 6273 } 6274 6275 6276 static void GetXValue(Local<Name> name, 6277 const v8::PropertyCallbackInfo<v8::Value>& info) { 6278 ApiTestFuzzer::Fuzz(); 6279 CHECK(info.Data() 6280 ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut")) 6281 .FromJust()); 6282 CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x")) 6283 .FromJust()); 6284 info.GetReturnValue().Set(name); 6285 } 6286 6287 6288 THREADED_TEST(SimplePropertyRead) { 6289 LocalContext context; 6290 v8::Isolate* isolate = context->GetIsolate(); 6291 v8::HandleScope scope(isolate); 6292 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6293 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6294 CHECK(context->Global() 6295 ->Set(context.local(), v8_str("obj"), 6296 templ->NewInstance(context.local()).ToLocalChecked()) 6297 .FromJust()); 6298 Local<Script> script = v8_compile("obj.x"); 6299 for (int i = 0; i < 10; i++) { 6300 Local<Value> result = script->Run(context.local()).ToLocalChecked(); 6301 CHECK(result->Equals(context.local(), v8_str("x")).FromJust()); 6302 } 6303 } 6304 6305 6306 THREADED_TEST(DefinePropertyOnAPIAccessor) { 6307 LocalContext context; 6308 v8::Isolate* isolate = context->GetIsolate(); 6309 v8::HandleScope scope(isolate); 6310 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6311 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6312 CHECK(context->Global() 6313 ->Set(context.local(), v8_str("obj"), 6314 templ->NewInstance(context.local()).ToLocalChecked()) 6315 .FromJust()); 6316 6317 // Uses getOwnPropertyDescriptor to check the configurable status 6318 Local<Script> script_desc = v8_compile( 6319 "var prop = Object.getOwnPropertyDescriptor( " 6320 "obj, 'x');" 6321 "prop.configurable;"); 6322 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked(); 6323 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6324 6325 // Redefine get - but still configurable 6326 Local<Script> script_define = v8_compile( 6327 "var desc = { get: function(){return 42; }," 6328 " configurable: true };" 6329 "Object.defineProperty(obj, 'x', desc);" 6330 "obj.x"); 6331 result = script_define->Run(context.local()).ToLocalChecked(); 6332 CHECK(result->Equals(context.local(), v8_num(42)).FromJust()); 6333 6334 // Check that the accessor is still configurable 6335 result = script_desc->Run(context.local()).ToLocalChecked(); 6336 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6337 6338 // Redefine to a non-configurable 6339 script_define = v8_compile( 6340 "var desc = { get: function(){return 43; }," 6341 " configurable: false };" 6342 "Object.defineProperty(obj, 'x', desc);" 6343 "obj.x"); 6344 result = script_define->Run(context.local()).ToLocalChecked(); 6345 CHECK(result->Equals(context.local(), v8_num(43)).FromJust()); 6346 result = script_desc->Run(context.local()).ToLocalChecked(); 6347 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false); 6348 6349 // Make sure that it is not possible to redefine again 6350 v8::TryCatch try_catch(isolate); 6351 CHECK(script_define->Run(context.local()).IsEmpty()); 6352 CHECK(try_catch.HasCaught()); 6353 String::Utf8Value exception_value(try_catch.Exception()); 6354 CHECK_EQ(0, 6355 strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6356 } 6357 6358 6359 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 6360 v8::Isolate* isolate = CcTest::isolate(); 6361 v8::HandleScope scope(isolate); 6362 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6363 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6364 LocalContext context; 6365 CHECK(context->Global() 6366 ->Set(context.local(), v8_str("obj"), 6367 templ->NewInstance(context.local()).ToLocalChecked()) 6368 .FromJust()); 6369 6370 Local<Script> script_desc = v8_compile( 6371 "var prop =" 6372 "Object.getOwnPropertyDescriptor( " 6373 "obj, 'x');" 6374 "prop.configurable;"); 6375 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked(); 6376 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6377 6378 Local<Script> script_define = v8_compile( 6379 "var desc = {get: function(){return 42; }," 6380 " configurable: true };" 6381 "Object.defineProperty(obj, 'x', desc);" 6382 "obj.x"); 6383 result = script_define->Run(context.local()).ToLocalChecked(); 6384 CHECK(result->Equals(context.local(), v8_num(42)).FromJust()); 6385 6386 result = script_desc->Run(context.local()).ToLocalChecked(); 6387 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6388 6389 script_define = v8_compile( 6390 "var desc = {get: function(){return 43; }," 6391 " configurable: false };" 6392 "Object.defineProperty(obj, 'x', desc);" 6393 "obj.x"); 6394 result = script_define->Run(context.local()).ToLocalChecked(); 6395 CHECK(result->Equals(context.local(), v8_num(43)).FromJust()); 6396 6397 result = script_desc->Run(context.local()).ToLocalChecked(); 6398 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false); 6399 6400 v8::TryCatch try_catch(isolate); 6401 CHECK(script_define->Run(context.local()).IsEmpty()); 6402 CHECK(try_catch.HasCaught()); 6403 String::Utf8Value exception_value(try_catch.Exception()); 6404 CHECK_EQ(0, 6405 strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6406 } 6407 6408 6409 static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context, 6410 char const* name) { 6411 return v8::Local<v8::Object>::Cast( 6412 (*context) 6413 ->Global() 6414 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name)) 6415 .ToLocalChecked()); 6416 } 6417 6418 6419 THREADED_TEST(DefineAPIAccessorOnObject) { 6420 v8::Isolate* isolate = CcTest::isolate(); 6421 v8::HandleScope scope(isolate); 6422 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6423 LocalContext context; 6424 6425 CHECK(context->Global() 6426 ->Set(context.local(), v8_str("obj1"), 6427 templ->NewInstance(context.local()).ToLocalChecked()) 6428 .FromJust()); 6429 CompileRun("var obj2 = {};"); 6430 6431 CHECK(CompileRun("obj1.x")->IsUndefined()); 6432 CHECK(CompileRun("obj2.x")->IsUndefined()); 6433 6434 CHECK(GetGlobalProperty(&context, "obj1") 6435 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6436 v8_str("donut")) 6437 .FromJust()); 6438 6439 ExpectString("obj1.x", "x"); 6440 CHECK(CompileRun("obj2.x")->IsUndefined()); 6441 6442 CHECK(GetGlobalProperty(&context, "obj2") 6443 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6444 v8_str("donut")) 6445 .FromJust()); 6446 6447 ExpectString("obj1.x", "x"); 6448 ExpectString("obj2.x", "x"); 6449 6450 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6451 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6452 6453 CompileRun( 6454 "Object.defineProperty(obj1, 'x'," 6455 "{ get: function() { return 'y'; }, configurable: true })"); 6456 6457 ExpectString("obj1.x", "y"); 6458 ExpectString("obj2.x", "x"); 6459 6460 CompileRun( 6461 "Object.defineProperty(obj2, 'x'," 6462 "{ get: function() { return 'y'; }, configurable: true })"); 6463 6464 ExpectString("obj1.x", "y"); 6465 ExpectString("obj2.x", "y"); 6466 6467 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6468 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6469 6470 CHECK(GetGlobalProperty(&context, "obj1") 6471 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6472 v8_str("donut")) 6473 .FromJust()); 6474 CHECK(GetGlobalProperty(&context, "obj2") 6475 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6476 v8_str("donut")) 6477 .FromJust()); 6478 6479 ExpectString("obj1.x", "x"); 6480 ExpectString("obj2.x", "x"); 6481 6482 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6483 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6484 6485 // Define getters/setters, but now make them not configurable. 6486 CompileRun( 6487 "Object.defineProperty(obj1, 'x'," 6488 "{ get: function() { return 'z'; }, configurable: false })"); 6489 CompileRun( 6490 "Object.defineProperty(obj2, 'x'," 6491 "{ get: function() { return 'z'; }, configurable: false })"); 6492 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6493 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6494 6495 ExpectString("obj1.x", "z"); 6496 ExpectString("obj2.x", "z"); 6497 6498 CHECK(GetGlobalProperty(&context, "obj1") 6499 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6500 v8_str("donut")) 6501 .IsNothing()); 6502 CHECK(GetGlobalProperty(&context, "obj2") 6503 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6504 v8_str("donut")) 6505 .IsNothing()); 6506 6507 ExpectString("obj1.x", "z"); 6508 ExpectString("obj2.x", "z"); 6509 } 6510 6511 6512 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 6513 v8::Isolate* isolate = CcTest::isolate(); 6514 v8::HandleScope scope(isolate); 6515 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6516 LocalContext context; 6517 6518 CHECK(context->Global() 6519 ->Set(context.local(), v8_str("obj1"), 6520 templ->NewInstance(context.local()).ToLocalChecked()) 6521 .FromJust()); 6522 CompileRun("var obj2 = {};"); 6523 6524 CHECK(GetGlobalProperty(&context, "obj1") 6525 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6526 v8_str("donut"), v8::DEFAULT, v8::DontDelete) 6527 .FromJust()); 6528 CHECK(GetGlobalProperty(&context, "obj2") 6529 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6530 v8_str("donut"), v8::DEFAULT, v8::DontDelete) 6531 .FromJust()); 6532 6533 ExpectString("obj1.x", "x"); 6534 ExpectString("obj2.x", "x"); 6535 6536 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6537 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6538 6539 CHECK(GetGlobalProperty(&context, "obj1") 6540 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6541 v8_str("donut")) 6542 .IsNothing()); 6543 CHECK(GetGlobalProperty(&context, "obj2") 6544 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6545 v8_str("donut")) 6546 .IsNothing()); 6547 6548 { 6549 v8::TryCatch try_catch(isolate); 6550 CompileRun( 6551 "Object.defineProperty(obj1, 'x'," 6552 "{get: function() { return 'func'; }})"); 6553 CHECK(try_catch.HasCaught()); 6554 String::Utf8Value exception_value(try_catch.Exception()); 6555 CHECK_EQ( 6556 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6557 } 6558 { 6559 v8::TryCatch try_catch(isolate); 6560 CompileRun( 6561 "Object.defineProperty(obj2, 'x'," 6562 "{get: function() { return 'func'; }})"); 6563 CHECK(try_catch.HasCaught()); 6564 String::Utf8Value exception_value(try_catch.Exception()); 6565 CHECK_EQ( 6566 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6567 } 6568 } 6569 6570 6571 static void Get239Value(Local<Name> name, 6572 const v8::PropertyCallbackInfo<v8::Value>& info) { 6573 ApiTestFuzzer::Fuzz(); 6574 CHECK(info.Data() 6575 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut")) 6576 .FromJust()); 6577 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239")) 6578 .FromJust()); 6579 info.GetReturnValue().Set(name); 6580 } 6581 6582 6583 THREADED_TEST(ElementAPIAccessor) { 6584 v8::Isolate* isolate = CcTest::isolate(); 6585 v8::HandleScope scope(isolate); 6586 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6587 LocalContext context; 6588 6589 CHECK(context->Global() 6590 ->Set(context.local(), v8_str("obj1"), 6591 templ->NewInstance(context.local()).ToLocalChecked()) 6592 .FromJust()); 6593 CompileRun("var obj2 = {};"); 6594 6595 CHECK(GetGlobalProperty(&context, "obj1") 6596 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL, 6597 v8_str("donut")) 6598 .FromJust()); 6599 CHECK(GetGlobalProperty(&context, "obj2") 6600 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL, 6601 v8_str("donut")) 6602 .FromJust()); 6603 6604 ExpectString("obj1[239]", "239"); 6605 ExpectString("obj2[239]", "239"); 6606 ExpectString("obj1['239']", "239"); 6607 ExpectString("obj2['239']", "239"); 6608 } 6609 6610 6611 v8::Persistent<Value> xValue; 6612 6613 6614 static void SetXValue(Local<Name> name, Local<Value> value, 6615 const v8::PropertyCallbackInfo<void>& info) { 6616 Local<Context> context = info.GetIsolate()->GetCurrentContext(); 6617 CHECK(value->Equals(context, v8_num(4)).FromJust()); 6618 CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust()); 6619 CHECK(name->Equals(context, v8_str("x")).FromJust()); 6620 CHECK(xValue.IsEmpty()); 6621 xValue.Reset(info.GetIsolate(), value); 6622 } 6623 6624 6625 THREADED_TEST(SimplePropertyWrite) { 6626 v8::Isolate* isolate = CcTest::isolate(); 6627 v8::HandleScope scope(isolate); 6628 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6629 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 6630 LocalContext context; 6631 CHECK(context->Global() 6632 ->Set(context.local(), v8_str("obj"), 6633 templ->NewInstance(context.local()).ToLocalChecked()) 6634 .FromJust()); 6635 Local<Script> script = v8_compile("obj.x = 4"); 6636 for (int i = 0; i < 10; i++) { 6637 CHECK(xValue.IsEmpty()); 6638 script->Run(context.local()).ToLocalChecked(); 6639 CHECK(v8_num(4) 6640 ->Equals(context.local(), 6641 Local<Value>::New(CcTest::isolate(), xValue)) 6642 .FromJust()); 6643 xValue.Reset(); 6644 } 6645 } 6646 6647 6648 THREADED_TEST(SetterOnly) { 6649 v8::Isolate* isolate = CcTest::isolate(); 6650 v8::HandleScope scope(isolate); 6651 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6652 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 6653 LocalContext context; 6654 CHECK(context->Global() 6655 ->Set(context.local(), v8_str("obj"), 6656 templ->NewInstance(context.local()).ToLocalChecked()) 6657 .FromJust()); 6658 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 6659 for (int i = 0; i < 10; i++) { 6660 CHECK(xValue.IsEmpty()); 6661 script->Run(context.local()).ToLocalChecked(); 6662 CHECK(v8_num(4) 6663 ->Equals(context.local(), 6664 Local<Value>::New(CcTest::isolate(), xValue)) 6665 .FromJust()); 6666 xValue.Reset(); 6667 } 6668 } 6669 6670 6671 THREADED_TEST(NoAccessors) { 6672 v8::Isolate* isolate = CcTest::isolate(); 6673 v8::HandleScope scope(isolate); 6674 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6675 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL), 6676 NULL, v8_str("donut")); 6677 LocalContext context; 6678 CHECK(context->Global() 6679 ->Set(context.local(), v8_str("obj"), 6680 templ->NewInstance(context.local()).ToLocalChecked()) 6681 .FromJust()); 6682 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 6683 for (int i = 0; i < 10; i++) { 6684 script->Run(context.local()).ToLocalChecked(); 6685 } 6686 } 6687 6688 6689 THREADED_TEST(MultiContexts) { 6690 v8::Isolate* isolate = CcTest::isolate(); 6691 v8::HandleScope scope(isolate); 6692 v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6693 templ->Set(v8_str("dummy"), 6694 v8::FunctionTemplate::New(isolate, DummyCallHandler)); 6695 6696 Local<String> password = v8_str("Password"); 6697 6698 // Create an environment 6699 LocalContext context0(0, templ); 6700 context0->SetSecurityToken(password); 6701 v8::Local<v8::Object> global0 = context0->Global(); 6702 CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234)) 6703 .FromJust()); 6704 CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom")) 6705 .ToLocalChecked() 6706 ->Int32Value(context0.local()) 6707 .FromJust()); 6708 6709 // Create an independent environment 6710 LocalContext context1(0, templ); 6711 context1->SetSecurityToken(password); 6712 v8::Local<v8::Object> global1 = context1->Global(); 6713 CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234)) 6714 .FromJust()); 6715 CHECK(!global0->Equals(context1.local(), global1).FromJust()); 6716 CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom")) 6717 .ToLocalChecked() 6718 ->Int32Value(context0.local()) 6719 .FromJust()); 6720 CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom")) 6721 .ToLocalChecked() 6722 ->Int32Value(context1.local()) 6723 .FromJust()); 6724 6725 // Now create a new context with the old global 6726 LocalContext context2(0, templ, global1); 6727 context2->SetSecurityToken(password); 6728 v8::Local<v8::Object> global2 = context2->Global(); 6729 CHECK(global1->Equals(context2.local(), global2).FromJust()); 6730 CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom")) 6731 .ToLocalChecked() 6732 ->Int32Value(context1.local()) 6733 .FromJust()); 6734 CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom")) 6735 .ToLocalChecked() 6736 ->Int32Value(context2.local()) 6737 .FromJust()); 6738 } 6739 6740 6741 THREADED_TEST(FunctionPrototypeAcrossContexts) { 6742 // Make sure that functions created by cloning boilerplates cannot 6743 // communicate through their __proto__ field. 6744 6745 v8::HandleScope scope(CcTest::isolate()); 6746 6747 LocalContext env0; 6748 v8::Local<v8::Object> global0 = env0->Global(); 6749 v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object")) 6750 .ToLocalChecked() 6751 .As<v8::Object>(); 6752 v8::Local<v8::Object> tostring0 = 6753 object0->Get(env0.local(), v8_str("toString")) 6754 .ToLocalChecked() 6755 .As<v8::Object>(); 6756 v8::Local<v8::Object> proto0 = 6757 tostring0->Get(env0.local(), v8_str("__proto__")) 6758 .ToLocalChecked() 6759 .As<v8::Object>(); 6760 CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust()); 6761 6762 LocalContext env1; 6763 v8::Local<v8::Object> global1 = env1->Global(); 6764 v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object")) 6765 .ToLocalChecked() 6766 .As<v8::Object>(); 6767 v8::Local<v8::Object> tostring1 = 6768 object1->Get(env1.local(), v8_str("toString")) 6769 .ToLocalChecked() 6770 .As<v8::Object>(); 6771 v8::Local<v8::Object> proto1 = 6772 tostring1->Get(env1.local(), v8_str("__proto__")) 6773 .ToLocalChecked() 6774 .As<v8::Object>(); 6775 CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust()); 6776 } 6777 6778 6779 THREADED_TEST(Regress892105) { 6780 // Make sure that object and array literals created by cloning 6781 // boilerplates cannot communicate through their __proto__ 6782 // field. This is rather difficult to check, but we try to add stuff 6783 // to Object.prototype and Array.prototype and create a new 6784 // environment. This should succeed. 6785 6786 v8::HandleScope scope(CcTest::isolate()); 6787 6788 Local<String> source = v8_str( 6789 "Object.prototype.obj = 1234;" 6790 "Array.prototype.arr = 4567;" 6791 "8901"); 6792 6793 LocalContext env0; 6794 Local<Script> script0 = v8_compile(source); 6795 CHECK_EQ(8901.0, script0->Run(env0.local()) 6796 .ToLocalChecked() 6797 ->NumberValue(env0.local()) 6798 .FromJust()); 6799 6800 LocalContext env1; 6801 Local<Script> script1 = v8_compile(source); 6802 CHECK_EQ(8901.0, script1->Run(env1.local()) 6803 .ToLocalChecked() 6804 ->NumberValue(env1.local()) 6805 .FromJust()); 6806 } 6807 6808 6809 THREADED_TEST(UndetectableObject) { 6810 LocalContext env; 6811 v8::HandleScope scope(env->GetIsolate()); 6812 6813 Local<v8::FunctionTemplate> desc = 6814 v8::FunctionTemplate::New(env->GetIsolate()); 6815 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6816 6817 Local<v8::Object> obj = desc->GetFunction(env.local()) 6818 .ToLocalChecked() 6819 ->NewInstance(env.local()) 6820 .ToLocalChecked(); 6821 CHECK( 6822 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 6823 6824 ExpectString("undetectable.toString()", "[object Object]"); 6825 ExpectString("typeof undetectable", "undefined"); 6826 ExpectString("typeof(undetectable)", "undefined"); 6827 ExpectBoolean("typeof undetectable == 'undefined'", true); 6828 ExpectBoolean("typeof undetectable == 'object'", false); 6829 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6830 ExpectBoolean("!undetectable", true); 6831 6832 ExpectObject("true&&undetectable", obj); 6833 ExpectBoolean("false&&undetectable", false); 6834 ExpectBoolean("true||undetectable", true); 6835 ExpectObject("false||undetectable", obj); 6836 6837 ExpectObject("undetectable&&true", obj); 6838 ExpectObject("undetectable&&false", obj); 6839 ExpectBoolean("undetectable||true", true); 6840 ExpectBoolean("undetectable||false", false); 6841 6842 ExpectBoolean("undetectable==null", true); 6843 ExpectBoolean("null==undetectable", true); 6844 ExpectBoolean("undetectable==undefined", true); 6845 ExpectBoolean("undefined==undetectable", true); 6846 ExpectBoolean("undetectable==undetectable", true); 6847 6848 6849 ExpectBoolean("undetectable===null", false); 6850 ExpectBoolean("null===undetectable", false); 6851 ExpectBoolean("undetectable===undefined", false); 6852 ExpectBoolean("undefined===undetectable", false); 6853 ExpectBoolean("undetectable===undetectable", true); 6854 } 6855 6856 6857 THREADED_TEST(VoidLiteral) { 6858 LocalContext env; 6859 v8::Isolate* isolate = env->GetIsolate(); 6860 v8::HandleScope scope(isolate); 6861 6862 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6863 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6864 6865 Local<v8::Object> obj = desc->GetFunction(env.local()) 6866 .ToLocalChecked() 6867 ->NewInstance(env.local()) 6868 .ToLocalChecked(); 6869 CHECK( 6870 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 6871 6872 ExpectBoolean("undefined == void 0", true); 6873 ExpectBoolean("undetectable == void 0", true); 6874 ExpectBoolean("null == void 0", true); 6875 ExpectBoolean("undefined === void 0", true); 6876 ExpectBoolean("undetectable === void 0", false); 6877 ExpectBoolean("null === void 0", false); 6878 6879 ExpectBoolean("void 0 == undefined", true); 6880 ExpectBoolean("void 0 == undetectable", true); 6881 ExpectBoolean("void 0 == null", true); 6882 ExpectBoolean("void 0 === undefined", true); 6883 ExpectBoolean("void 0 === undetectable", false); 6884 ExpectBoolean("void 0 === null", false); 6885 6886 ExpectString( 6887 "(function() {" 6888 " try {" 6889 " return x === void 0;" 6890 " } catch(e) {" 6891 " return e.toString();" 6892 " }" 6893 "})()", 6894 "ReferenceError: x is not defined"); 6895 ExpectString( 6896 "(function() {" 6897 " try {" 6898 " return void 0 === x;" 6899 " } catch(e) {" 6900 " return e.toString();" 6901 " }" 6902 "})()", 6903 "ReferenceError: x is not defined"); 6904 } 6905 6906 6907 THREADED_TEST(ExtensibleOnUndetectable) { 6908 LocalContext env; 6909 v8::Isolate* isolate = env->GetIsolate(); 6910 v8::HandleScope scope(isolate); 6911 6912 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6913 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6914 6915 Local<v8::Object> obj = desc->GetFunction(env.local()) 6916 .ToLocalChecked() 6917 ->NewInstance(env.local()) 6918 .ToLocalChecked(); 6919 CHECK( 6920 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 6921 6922 Local<String> source = v8_str( 6923 "undetectable.x = 42;" 6924 "undetectable.x"); 6925 6926 Local<Script> script = v8_compile(source); 6927 6928 CHECK(v8::Integer::New(isolate, 42) 6929 ->Equals(env.local(), script->Run(env.local()).ToLocalChecked()) 6930 .FromJust()); 6931 6932 ExpectBoolean("Object.isExtensible(undetectable)", true); 6933 6934 source = v8_str("Object.preventExtensions(undetectable);"); 6935 script = v8_compile(source); 6936 script->Run(env.local()).ToLocalChecked(); 6937 ExpectBoolean("Object.isExtensible(undetectable)", false); 6938 6939 source = v8_str("undetectable.y = 2000;"); 6940 script = v8_compile(source); 6941 script->Run(env.local()).ToLocalChecked(); 6942 ExpectBoolean("undetectable.y == undefined", true); 6943 } 6944 6945 6946 // The point of this test is type checking. We run it only so compilers 6947 // don't complain about an unused function. 6948 TEST(PersistentHandles) { 6949 LocalContext env; 6950 v8::Isolate* isolate = CcTest::isolate(); 6951 v8::HandleScope scope(isolate); 6952 Local<String> str = v8_str("foo"); 6953 v8::Persistent<String> p_str(isolate, str); 6954 p_str.Reset(); 6955 Local<Script> scr = v8_compile(""); 6956 v8::Persistent<Script> p_scr(isolate, scr); 6957 p_scr.Reset(); 6958 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6959 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 6960 p_templ.Reset(); 6961 } 6962 6963 6964 static void HandleLogDelegator( 6965 const v8::FunctionCallbackInfo<v8::Value>& args) { 6966 ApiTestFuzzer::Fuzz(); 6967 } 6968 6969 6970 THREADED_TEST(GlobalObjectTemplate) { 6971 v8::Isolate* isolate = CcTest::isolate(); 6972 v8::HandleScope handle_scope(isolate); 6973 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 6974 global_template->Set(v8_str("JSNI_Log"), 6975 v8::FunctionTemplate::New(isolate, HandleLogDelegator)); 6976 v8::Local<Context> context = Context::New(isolate, 0, global_template); 6977 Context::Scope context_scope(context); 6978 CompileRun("JSNI_Log('LOG')"); 6979 } 6980 6981 6982 static const char* kSimpleExtensionSource = 6983 "function Foo() {" 6984 " return 4;" 6985 "}"; 6986 6987 6988 TEST(SimpleExtensions) { 6989 v8::HandleScope handle_scope(CcTest::isolate()); 6990 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 6991 const char* extension_names[] = {"simpletest"}; 6992 v8::ExtensionConfiguration extensions(1, extension_names); 6993 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 6994 Context::Scope lock(context); 6995 v8::Local<Value> result = CompileRun("Foo()"); 6996 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 6997 .FromJust()); 6998 } 6999 7000 7001 static const char* kStackTraceFromExtensionSource = 7002 "function foo() {" 7003 " throw new Error();" 7004 "}" 7005 "function bar() {" 7006 " foo();" 7007 "}"; 7008 7009 7010 TEST(StackTraceInExtension) { 7011 v8::HandleScope handle_scope(CcTest::isolate()); 7012 v8::RegisterExtension( 7013 new Extension("stacktracetest", kStackTraceFromExtensionSource)); 7014 const char* extension_names[] = {"stacktracetest"}; 7015 v8::ExtensionConfiguration extensions(1, extension_names); 7016 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7017 Context::Scope lock(context); 7018 CompileRun( 7019 "function user() { bar(); }" 7020 "var error;" 7021 "try{ user(); } catch (e) { error = e; }"); 7022 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')"))); 7023 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')"))); 7024 CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')"))); 7025 } 7026 7027 7028 TEST(NullExtensions) { 7029 v8::HandleScope handle_scope(CcTest::isolate()); 7030 v8::RegisterExtension(new Extension("nulltest", NULL)); 7031 const char* extension_names[] = {"nulltest"}; 7032 v8::ExtensionConfiguration extensions(1, extension_names); 7033 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7034 Context::Scope lock(context); 7035 v8::Local<Value> result = CompileRun("1+3"); 7036 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 7037 .FromJust()); 7038 } 7039 7040 7041 static const char* kEmbeddedExtensionSource = 7042 "function Ret54321(){return 54321;}~~@@$" 7043 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 7044 static const int kEmbeddedExtensionSourceValidLen = 34; 7045 7046 7047 TEST(ExtensionMissingSourceLength) { 7048 v8::HandleScope handle_scope(CcTest::isolate()); 7049 v8::RegisterExtension( 7050 new Extension("srclentest_fail", kEmbeddedExtensionSource)); 7051 const char* extension_names[] = {"srclentest_fail"}; 7052 v8::ExtensionConfiguration extensions(1, extension_names); 7053 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7054 CHECK(0 == *context); 7055 } 7056 7057 7058 TEST(ExtensionWithSourceLength) { 7059 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 7060 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 7061 v8::HandleScope handle_scope(CcTest::isolate()); 7062 i::ScopedVector<char> extension_name(32); 7063 i::SNPrintF(extension_name, "ext #%d", source_len); 7064 v8::RegisterExtension(new Extension( 7065 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len)); 7066 const char* extension_names[1] = {extension_name.start()}; 7067 v8::ExtensionConfiguration extensions(1, extension_names); 7068 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7069 if (source_len == kEmbeddedExtensionSourceValidLen) { 7070 Context::Scope lock(context); 7071 v8::Local<Value> result = CompileRun("Ret54321()"); 7072 CHECK(v8::Integer::New(CcTest::isolate(), 54321) 7073 ->Equals(context, result) 7074 .FromJust()); 7075 } else { 7076 // Anything but exactly the right length should fail to compile. 7077 CHECK(0 == *context); 7078 } 7079 } 7080 } 7081 7082 7083 static const char* kEvalExtensionSource1 = 7084 "function UseEval1() {" 7085 " var x = 42;" 7086 " return eval('x');" 7087 "}"; 7088 7089 7090 static const char* kEvalExtensionSource2 = 7091 "(function() {" 7092 " var x = 42;" 7093 " function e() {" 7094 " return eval('x');" 7095 " }" 7096 " this.UseEval2 = e;" 7097 "})()"; 7098 7099 7100 TEST(UseEvalFromExtension) { 7101 v8::HandleScope handle_scope(CcTest::isolate()); 7102 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 7103 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 7104 const char* extension_names[] = {"evaltest1", "evaltest2"}; 7105 v8::ExtensionConfiguration extensions(2, extension_names); 7106 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7107 Context::Scope lock(context); 7108 v8::Local<Value> result = CompileRun("UseEval1()"); 7109 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7110 .FromJust()); 7111 result = CompileRun("UseEval2()"); 7112 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7113 .FromJust()); 7114 } 7115 7116 7117 static const char* kWithExtensionSource1 = 7118 "function UseWith1() {" 7119 " var x = 42;" 7120 " with({x:87}) { return x; }" 7121 "}"; 7122 7123 7124 static const char* kWithExtensionSource2 = 7125 "(function() {" 7126 " var x = 42;" 7127 " function e() {" 7128 " with ({x:87}) { return x; }" 7129 " }" 7130 " this.UseWith2 = e;" 7131 "})()"; 7132 7133 7134 TEST(UseWithFromExtension) { 7135 v8::HandleScope handle_scope(CcTest::isolate()); 7136 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 7137 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 7138 const char* extension_names[] = {"withtest1", "withtest2"}; 7139 v8::ExtensionConfiguration extensions(2, extension_names); 7140 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7141 Context::Scope lock(context); 7142 v8::Local<Value> result = CompileRun("UseWith1()"); 7143 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87)) 7144 .FromJust()); 7145 result = CompileRun("UseWith2()"); 7146 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87)) 7147 .FromJust()); 7148 } 7149 7150 7151 TEST(AutoExtensions) { 7152 v8::HandleScope handle_scope(CcTest::isolate()); 7153 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 7154 extension->set_auto_enable(true); 7155 v8::RegisterExtension(extension); 7156 v8::Local<Context> context = Context::New(CcTest::isolate()); 7157 Context::Scope lock(context); 7158 v8::Local<Value> result = CompileRun("Foo()"); 7159 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 7160 .FromJust()); 7161 } 7162 7163 7164 static const char* kSyntaxErrorInExtensionSource = "["; 7165 7166 7167 // Test that a syntax error in an extension does not cause a fatal 7168 // error but results in an empty context. 7169 TEST(SyntaxErrorExtensions) { 7170 v8::HandleScope handle_scope(CcTest::isolate()); 7171 v8::RegisterExtension( 7172 new Extension("syntaxerror", kSyntaxErrorInExtensionSource)); 7173 const char* extension_names[] = {"syntaxerror"}; 7174 v8::ExtensionConfiguration extensions(1, extension_names); 7175 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7176 CHECK(context.IsEmpty()); 7177 } 7178 7179 7180 static const char* kExceptionInExtensionSource = "throw 42"; 7181 7182 7183 // Test that an exception when installing an extension does not cause 7184 // a fatal error but results in an empty context. 7185 TEST(ExceptionExtensions) { 7186 v8::HandleScope handle_scope(CcTest::isolate()); 7187 v8::RegisterExtension( 7188 new Extension("exception", kExceptionInExtensionSource)); 7189 const char* extension_names[] = {"exception"}; 7190 v8::ExtensionConfiguration extensions(1, extension_names); 7191 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7192 CHECK(context.IsEmpty()); 7193 } 7194 7195 7196 static const char* kNativeCallInExtensionSource = 7197 "function call_runtime_last_index_of(x) {" 7198 " return %StringLastIndexOf(x, 'bob', 10);" 7199 "}"; 7200 7201 7202 static const char* kNativeCallTest = 7203 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 7204 7205 // Test that a native runtime calls are supported in extensions. 7206 TEST(NativeCallInExtensions) { 7207 v8::HandleScope handle_scope(CcTest::isolate()); 7208 v8::RegisterExtension( 7209 new Extension("nativecall", kNativeCallInExtensionSource)); 7210 const char* extension_names[] = {"nativecall"}; 7211 v8::ExtensionConfiguration extensions(1, extension_names); 7212 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7213 Context::Scope lock(context); 7214 v8::Local<Value> result = CompileRun(kNativeCallTest); 7215 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 3)) 7216 .FromJust()); 7217 } 7218 7219 7220 class NativeFunctionExtension : public Extension { 7221 public: 7222 NativeFunctionExtension(const char* name, const char* source, 7223 v8::FunctionCallback fun = &Echo) 7224 : Extension(name, source), function_(fun) {} 7225 7226 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( 7227 v8::Isolate* isolate, v8::Local<v8::String> name) { 7228 return v8::FunctionTemplate::New(isolate, function_); 7229 } 7230 7231 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 7232 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 7233 } 7234 7235 private: 7236 v8::FunctionCallback function_; 7237 }; 7238 7239 7240 TEST(NativeFunctionDeclaration) { 7241 v8::HandleScope handle_scope(CcTest::isolate()); 7242 const char* name = "nativedecl"; 7243 v8::RegisterExtension( 7244 new NativeFunctionExtension(name, "native function foo();")); 7245 const char* extension_names[] = {name}; 7246 v8::ExtensionConfiguration extensions(1, extension_names); 7247 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7248 Context::Scope lock(context); 7249 v8::Local<Value> result = CompileRun("foo(42);"); 7250 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7251 .FromJust()); 7252 } 7253 7254 7255 TEST(NativeFunctionDeclarationError) { 7256 v8::HandleScope handle_scope(CcTest::isolate()); 7257 const char* name = "nativedeclerr"; 7258 // Syntax error in extension code. 7259 v8::RegisterExtension( 7260 new NativeFunctionExtension(name, "native\nfunction foo();")); 7261 const char* extension_names[] = {name}; 7262 v8::ExtensionConfiguration extensions(1, extension_names); 7263 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7264 CHECK(context.IsEmpty()); 7265 } 7266 7267 7268 TEST(NativeFunctionDeclarationErrorEscape) { 7269 v8::HandleScope handle_scope(CcTest::isolate()); 7270 const char* name = "nativedeclerresc"; 7271 // Syntax error in extension code - escape code in "native" means that 7272 // it's not treated as a keyword. 7273 v8::RegisterExtension( 7274 new NativeFunctionExtension(name, "nativ\\u0065 function foo();")); 7275 const char* extension_names[] = {name}; 7276 v8::ExtensionConfiguration extensions(1, extension_names); 7277 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7278 CHECK(context.IsEmpty()); 7279 } 7280 7281 7282 static void CheckDependencies(const char* name, const char* expected) { 7283 v8::HandleScope handle_scope(CcTest::isolate()); 7284 v8::ExtensionConfiguration config(1, &name); 7285 LocalContext context(&config); 7286 CHECK( 7287 v8_str(expected) 7288 ->Equals(context.local(), context->Global() 7289 ->Get(context.local(), v8_str("loaded")) 7290 .ToLocalChecked()) 7291 .FromJust()); 7292 } 7293 7294 7295 /* 7296 * Configuration: 7297 * 7298 * /-- B <--\ 7299 * A <- -- D <-- E 7300 * \-- C <--/ 7301 */ 7302 THREADED_TEST(ExtensionDependency) { 7303 static const char* kEDeps[] = {"D"}; 7304 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 7305 static const char* kDDeps[] = {"B", "C"}; 7306 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 7307 static const char* kBCDeps[] = {"A"}; 7308 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 7309 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 7310 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 7311 CheckDependencies("A", "undefinedA"); 7312 CheckDependencies("B", "undefinedAB"); 7313 CheckDependencies("C", "undefinedAC"); 7314 CheckDependencies("D", "undefinedABCD"); 7315 CheckDependencies("E", "undefinedABCDE"); 7316 v8::HandleScope handle_scope(CcTest::isolate()); 7317 static const char* exts[2] = {"C", "E"}; 7318 v8::ExtensionConfiguration config(2, exts); 7319 LocalContext context(&config); 7320 CHECK( 7321 v8_str("undefinedACBDE") 7322 ->Equals(context.local(), context->Global() 7323 ->Get(context.local(), v8_str("loaded")) 7324 .ToLocalChecked()) 7325 .FromJust()); 7326 } 7327 7328 7329 static const char* kExtensionTestScript = 7330 "native function A();" 7331 "native function B();" 7332 "native function C();" 7333 "function Foo(i) {" 7334 " if (i == 0) return A();" 7335 " if (i == 1) return B();" 7336 " if (i == 2) return C();" 7337 "}"; 7338 7339 7340 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 7341 ApiTestFuzzer::Fuzz(); 7342 if (args.IsConstructCall()) { 7343 CHECK(args.This() 7344 ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"), 7345 args.Data()) 7346 .FromJust()); 7347 args.GetReturnValue().SetNull(); 7348 return; 7349 } 7350 args.GetReturnValue().Set(args.Data()); 7351 } 7352 7353 7354 class FunctionExtension : public Extension { 7355 public: 7356 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {} 7357 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( 7358 v8::Isolate* isolate, v8::Local<String> name); 7359 }; 7360 7361 7362 static int lookup_count = 0; 7363 v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate( 7364 v8::Isolate* isolate, v8::Local<String> name) { 7365 lookup_count++; 7366 if (name->Equals(isolate->GetCurrentContext(), v8_str("A")).FromJust()) { 7367 return v8::FunctionTemplate::New(isolate, CallFun, 7368 v8::Integer::New(isolate, 8)); 7369 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("B")) 7370 .FromJust()) { 7371 return v8::FunctionTemplate::New(isolate, CallFun, 7372 v8::Integer::New(isolate, 7)); 7373 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("C")) 7374 .FromJust()) { 7375 return v8::FunctionTemplate::New(isolate, CallFun, 7376 v8::Integer::New(isolate, 6)); 7377 } else { 7378 return v8::Local<v8::FunctionTemplate>(); 7379 } 7380 } 7381 7382 7383 THREADED_TEST(FunctionLookup) { 7384 v8::RegisterExtension(new FunctionExtension()); 7385 v8::HandleScope handle_scope(CcTest::isolate()); 7386 static const char* exts[1] = {"functiontest"}; 7387 v8::ExtensionConfiguration config(1, exts); 7388 LocalContext context(&config); 7389 CHECK_EQ(3, lookup_count); 7390 CHECK(v8::Integer::New(CcTest::isolate(), 8) 7391 ->Equals(context.local(), CompileRun("Foo(0)")) 7392 .FromJust()); 7393 CHECK(v8::Integer::New(CcTest::isolate(), 7) 7394 ->Equals(context.local(), CompileRun("Foo(1)")) 7395 .FromJust()); 7396 CHECK(v8::Integer::New(CcTest::isolate(), 6) 7397 ->Equals(context.local(), CompileRun("Foo(2)")) 7398 .FromJust()); 7399 } 7400 7401 7402 THREADED_TEST(NativeFunctionConstructCall) { 7403 v8::RegisterExtension(new FunctionExtension()); 7404 v8::HandleScope handle_scope(CcTest::isolate()); 7405 static const char* exts[1] = {"functiontest"}; 7406 v8::ExtensionConfiguration config(1, exts); 7407 LocalContext context(&config); 7408 for (int i = 0; i < 10; i++) { 7409 // Run a few times to ensure that allocation of objects doesn't 7410 // change behavior of a constructor function. 7411 CHECK(v8::Integer::New(CcTest::isolate(), 8) 7412 ->Equals(context.local(), CompileRun("(new A()).data")) 7413 .FromJust()); 7414 CHECK(v8::Integer::New(CcTest::isolate(), 7) 7415 ->Equals(context.local(), CompileRun("(new B()).data")) 7416 .FromJust()); 7417 CHECK(v8::Integer::New(CcTest::isolate(), 6) 7418 ->Equals(context.local(), CompileRun("(new C()).data")) 7419 .FromJust()); 7420 } 7421 } 7422 7423 7424 static const char* last_location; 7425 static const char* last_message; 7426 void StoringErrorCallback(const char* location, const char* message) { 7427 if (last_location == NULL) { 7428 last_location = location; 7429 last_message = message; 7430 } 7431 } 7432 7433 7434 // ErrorReporting creates a circular extensions configuration and 7435 // tests that the fatal error handler gets called. This renders V8 7436 // unusable and therefore this test cannot be run in parallel. 7437 TEST(ErrorReporting) { 7438 CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback); 7439 static const char* aDeps[] = {"B"}; 7440 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 7441 static const char* bDeps[] = {"A"}; 7442 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 7443 last_location = NULL; 7444 v8::ExtensionConfiguration config(1, bDeps); 7445 v8::Local<Context> context = Context::New(CcTest::isolate(), &config); 7446 CHECK(context.IsEmpty()); 7447 CHECK(last_location); 7448 } 7449 7450 7451 static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message, 7452 v8::Local<Value> data) { 7453 v8::Isolate* isolate = CcTest::isolate(); 7454 Local<Context> context = isolate->GetCurrentContext(); 7455 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined()); 7456 CHECK(v8::Undefined(isolate) 7457 ->Equals(context, message->GetScriptOrigin().ResourceName()) 7458 .FromJust()); 7459 message->GetLineNumber(context).FromJust(); 7460 message->GetSourceLine(context).ToLocalChecked(); 7461 } 7462 7463 7464 THREADED_TEST(ErrorWithMissingScriptInfo) { 7465 LocalContext context; 7466 v8::HandleScope scope(context->GetIsolate()); 7467 context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener); 7468 CompileRun("throw Error()"); 7469 context->GetIsolate()->RemoveMessageListeners( 7470 MissingScriptInfoMessageListener); 7471 } 7472 7473 7474 struct FlagAndPersistent { 7475 bool flag; 7476 v8::Global<v8::Object> handle; 7477 }; 7478 7479 7480 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7481 data.GetParameter()->flag = true; 7482 data.GetParameter()->handle.Reset(); 7483 } 7484 7485 7486 static void IndependentWeakHandle(bool global_gc, bool interlinked) { 7487 v8::Isolate* iso = CcTest::isolate(); 7488 v8::HandleScope scope(iso); 7489 v8::Local<Context> context = Context::New(iso); 7490 Context::Scope context_scope(context); 7491 7492 FlagAndPersistent object_a, object_b; 7493 7494 intptr_t big_heap_size; 7495 7496 { 7497 v8::HandleScope handle_scope(iso); 7498 Local<Object> a(v8::Object::New(iso)); 7499 Local<Object> b(v8::Object::New(iso)); 7500 object_a.handle.Reset(iso, a); 7501 object_b.handle.Reset(iso, b); 7502 if (interlinked) { 7503 a->Set(context, v8_str("x"), b).FromJust(); 7504 b->Set(context, v8_str("x"), a).FromJust(); 7505 } 7506 if (global_gc) { 7507 CcTest::heap()->CollectAllGarbage(); 7508 } else { 7509 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7510 } 7511 // We are relying on this creating a big flag array and reserving the space 7512 // up front. 7513 v8::Local<Value> big_array = CompileRun("new Array(5000)"); 7514 a->Set(context, v8_str("y"), big_array).FromJust(); 7515 big_heap_size = CcTest::heap()->SizeOfObjects(); 7516 } 7517 7518 object_a.flag = false; 7519 object_b.flag = false; 7520 object_a.handle.SetWeak(&object_a, &SetFlag, 7521 v8::WeakCallbackType::kParameter); 7522 object_b.handle.SetWeak(&object_b, &SetFlag, 7523 v8::WeakCallbackType::kParameter); 7524 CHECK(!object_b.handle.IsIndependent()); 7525 object_a.handle.MarkIndependent(); 7526 object_b.handle.MarkIndependent(); 7527 CHECK(object_b.handle.IsIndependent()); 7528 if (global_gc) { 7529 CcTest::heap()->CollectAllGarbage(); 7530 } else { 7531 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7532 } 7533 // A single GC should be enough to reclaim the memory, since we are using 7534 // phantom handles. 7535 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 20000); 7536 CHECK(object_a.flag); 7537 CHECK(object_b.flag); 7538 } 7539 7540 7541 TEST(IndependentWeakHandle) { 7542 IndependentWeakHandle(false, false); 7543 IndependentWeakHandle(false, true); 7544 IndependentWeakHandle(true, false); 7545 IndependentWeakHandle(true, true); 7546 } 7547 7548 7549 class Trivial { 7550 public: 7551 explicit Trivial(int x) : x_(x) {} 7552 7553 int x() { return x_; } 7554 void set_x(int x) { x_ = x; } 7555 7556 private: 7557 int x_; 7558 }; 7559 7560 7561 class Trivial2 { 7562 public: 7563 Trivial2(int x, int y) : y_(y), x_(x) {} 7564 7565 int x() { return x_; } 7566 void set_x(int x) { x_ = x; } 7567 7568 int y() { return y_; } 7569 void set_y(int y) { y_ = y; } 7570 7571 private: 7572 int y_; 7573 int x_; 7574 }; 7575 7576 7577 void CheckInternalFields( 7578 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 7579 v8::Persistent<v8::Object>* handle = data.GetParameter(); 7580 handle->Reset(); 7581 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0)); 7582 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1)); 7583 CHECK_EQ(42, t1->x()); 7584 CHECK_EQ(103, t2->x()); 7585 t1->set_x(1729); 7586 t2->set_x(33550336); 7587 } 7588 7589 7590 void InternalFieldCallback(bool global_gc) { 7591 LocalContext env; 7592 v8::Isolate* isolate = env->GetIsolate(); 7593 v8::HandleScope scope(isolate); 7594 7595 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 7596 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 7597 Trivial* t1; 7598 Trivial2* t2; 7599 instance_templ->SetInternalFieldCount(2); 7600 { 7601 v8::HandleScope scope(isolate); 7602 Local<v8::Object> obj = templ->GetFunction(env.local()) 7603 .ToLocalChecked() 7604 ->NewInstance(env.local()) 7605 .ToLocalChecked(); 7606 v8::Persistent<v8::Object> handle(isolate, obj); 7607 CHECK_EQ(2, obj->InternalFieldCount()); 7608 CHECK(obj->GetInternalField(0)->IsUndefined()); 7609 t1 = new Trivial(42); 7610 t2 = new Trivial2(103, 9); 7611 7612 obj->SetAlignedPointerInInternalField(0, t1); 7613 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0)); 7614 CHECK_EQ(42, t1->x()); 7615 7616 obj->SetAlignedPointerInInternalField(1, t2); 7617 t2 = 7618 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1)); 7619 CHECK_EQ(103, t2->x()); 7620 7621 handle.SetWeak<v8::Persistent<v8::Object>>( 7622 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields); 7623 if (!global_gc) { 7624 handle.MarkIndependent(); 7625 } 7626 } 7627 if (global_gc) { 7628 CcTest::heap()->CollectAllGarbage(); 7629 } else { 7630 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7631 } 7632 7633 CHECK_EQ(1729, t1->x()); 7634 CHECK_EQ(33550336, t2->x()); 7635 7636 delete t1; 7637 delete t2; 7638 } 7639 7640 7641 THREADED_TEST(InternalFieldCallback) { 7642 InternalFieldCallback(false); 7643 InternalFieldCallback(true); 7644 } 7645 7646 7647 static void ResetUseValueAndSetFlag( 7648 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7649 // Blink will reset the handle, and then use the other handle, so they 7650 // can't use the same backing slot. 7651 data.GetParameter()->handle.Reset(); 7652 data.GetParameter()->flag = true; 7653 } 7654 7655 7656 void v8::internal::HeapTester::ResetWeakHandle(bool global_gc) { 7657 using v8::Context; 7658 using v8::Local; 7659 using v8::Object; 7660 7661 v8::Isolate* iso = CcTest::isolate(); 7662 v8::HandleScope scope(iso); 7663 v8::Local<Context> context = Context::New(iso); 7664 Context::Scope context_scope(context); 7665 7666 FlagAndPersistent object_a, object_b; 7667 7668 { 7669 v8::HandleScope handle_scope(iso); 7670 Local<Object> a(v8::Object::New(iso)); 7671 Local<Object> b(v8::Object::New(iso)); 7672 object_a.handle.Reset(iso, a); 7673 object_b.handle.Reset(iso, b); 7674 if (global_gc) { 7675 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 7676 } else { 7677 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7678 } 7679 } 7680 7681 object_a.flag = false; 7682 object_b.flag = false; 7683 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag, 7684 v8::WeakCallbackType::kParameter); 7685 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag, 7686 v8::WeakCallbackType::kParameter); 7687 if (!global_gc) { 7688 object_a.handle.MarkIndependent(); 7689 object_b.handle.MarkIndependent(); 7690 CHECK(object_b.handle.IsIndependent()); 7691 } 7692 if (global_gc) { 7693 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 7694 } else { 7695 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7696 } 7697 CHECK(object_a.flag); 7698 CHECK(object_b.flag); 7699 } 7700 7701 7702 THREADED_HEAP_TEST(ResetWeakHandle) { 7703 v8::internal::HeapTester::ResetWeakHandle(false); 7704 v8::internal::HeapTester::ResetWeakHandle(true); 7705 } 7706 7707 7708 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); } 7709 7710 7711 static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); } 7712 7713 7714 static void ForceScavenge2( 7715 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7716 data.GetParameter()->flag = true; 7717 InvokeScavenge(); 7718 } 7719 7720 static void ForceScavenge1( 7721 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7722 data.GetParameter()->handle.Reset(); 7723 data.SetSecondPassCallback(ForceScavenge2); 7724 } 7725 7726 7727 static void ForceMarkSweep2( 7728 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7729 data.GetParameter()->flag = true; 7730 InvokeMarkSweep(); 7731 } 7732 7733 static void ForceMarkSweep1( 7734 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7735 data.GetParameter()->handle.Reset(); 7736 data.SetSecondPassCallback(ForceMarkSweep2); 7737 } 7738 7739 7740 THREADED_TEST(GCFromWeakCallbacks) { 7741 v8::Isolate* isolate = CcTest::isolate(); 7742 v8::Locker locker(CcTest::isolate()); 7743 v8::HandleScope scope(isolate); 7744 v8::Local<Context> context = Context::New(isolate); 7745 Context::Scope context_scope(context); 7746 7747 static const int kNumberOfGCTypes = 2; 7748 typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback; 7749 Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1, 7750 &ForceMarkSweep1}; 7751 7752 typedef void (*GCInvoker)(); 7753 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 7754 7755 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 7756 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 7757 FlagAndPersistent object; 7758 { 7759 v8::HandleScope handle_scope(isolate); 7760 object.handle.Reset(isolate, v8::Object::New(isolate)); 7761 } 7762 object.flag = false; 7763 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc], 7764 v8::WeakCallbackType::kParameter); 7765 object.handle.MarkIndependent(); 7766 invoke_gc[outer_gc](); 7767 EmptyMessageQueues(isolate); 7768 CHECK(object.flag); 7769 } 7770 } 7771 } 7772 7773 7774 v8::Local<Function> args_fun; 7775 7776 7777 static void ArgumentsTestCallback( 7778 const v8::FunctionCallbackInfo<v8::Value>& args) { 7779 ApiTestFuzzer::Fuzz(); 7780 v8::Isolate* isolate = args.GetIsolate(); 7781 Local<Context> context = isolate->GetCurrentContext(); 7782 CHECK(args_fun->Equals(context, args.Callee()).FromJust()); 7783 CHECK_EQ(3, args.Length()); 7784 CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust()); 7785 CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust()); 7786 CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust()); 7787 CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust()); 7788 v8::HandleScope scope(args.GetIsolate()); 7789 CcTest::heap()->CollectAllGarbage(); 7790 } 7791 7792 7793 THREADED_TEST(Arguments) { 7794 v8::Isolate* isolate = CcTest::isolate(); 7795 v8::HandleScope scope(isolate); 7796 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 7797 global->Set(v8_str("f"), 7798 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback)); 7799 LocalContext context(NULL, global); 7800 args_fun = context->Global() 7801 ->Get(context.local(), v8_str("f")) 7802 .ToLocalChecked() 7803 .As<Function>(); 7804 v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked(); 7805 } 7806 7807 7808 static int p_getter_count; 7809 static int p_getter_count2; 7810 7811 7812 static void PGetter(Local<Name> name, 7813 const v8::PropertyCallbackInfo<v8::Value>& info) { 7814 ApiTestFuzzer::Fuzz(); 7815 p_getter_count++; 7816 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 7817 v8::Local<v8::Object> global = context->Global(); 7818 CHECK( 7819 info.Holder() 7820 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked()) 7821 .FromJust()); 7822 if (name->Equals(context, v8_str("p1")).FromJust()) { 7823 CHECK(info.This() 7824 ->Equals(context, 7825 global->Get(context, v8_str("o1")).ToLocalChecked()) 7826 .FromJust()); 7827 } else if (name->Equals(context, v8_str("p2")).FromJust()) { 7828 CHECK(info.This() 7829 ->Equals(context, 7830 global->Get(context, v8_str("o2")).ToLocalChecked()) 7831 .FromJust()); 7832 } else if (name->Equals(context, v8_str("p3")).FromJust()) { 7833 CHECK(info.This() 7834 ->Equals(context, 7835 global->Get(context, v8_str("o3")).ToLocalChecked()) 7836 .FromJust()); 7837 } else if (name->Equals(context, v8_str("p4")).FromJust()) { 7838 CHECK(info.This() 7839 ->Equals(context, 7840 global->Get(context, v8_str("o4")).ToLocalChecked()) 7841 .FromJust()); 7842 } 7843 } 7844 7845 7846 static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) { 7847 ApiTestFuzzer::Fuzz(); 7848 LocalContext context; 7849 CHECK(context->Global() 7850 ->Set(context.local(), v8_str("o1"), 7851 obj->NewInstance(context.local()).ToLocalChecked()) 7852 .FromJust()); 7853 CompileRun( 7854 "o1.__proto__ = { };" 7855 "var o2 = { __proto__: o1 };" 7856 "var o3 = { __proto__: o2 };" 7857 "var o4 = { __proto__: o3 };" 7858 "for (var i = 0; i < 10; i++) o4.p4;" 7859 "for (var i = 0; i < 10; i++) o3.p3;" 7860 "for (var i = 0; i < 10; i++) o2.p2;" 7861 "for (var i = 0; i < 10; i++) o1.p1;"); 7862 } 7863 7864 7865 static void PGetter2(Local<Name> name, 7866 const v8::PropertyCallbackInfo<v8::Value>& info) { 7867 ApiTestFuzzer::Fuzz(); 7868 p_getter_count2++; 7869 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 7870 v8::Local<v8::Object> global = context->Global(); 7871 CHECK( 7872 info.Holder() 7873 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked()) 7874 .FromJust()); 7875 if (name->Equals(context, v8_str("p1")).FromJust()) { 7876 CHECK(info.This() 7877 ->Equals(context, 7878 global->Get(context, v8_str("o1")).ToLocalChecked()) 7879 .FromJust()); 7880 } else if (name->Equals(context, v8_str("p2")).FromJust()) { 7881 CHECK(info.This() 7882 ->Equals(context, 7883 global->Get(context, v8_str("o2")).ToLocalChecked()) 7884 .FromJust()); 7885 } else if (name->Equals(context, v8_str("p3")).FromJust()) { 7886 CHECK(info.This() 7887 ->Equals(context, 7888 global->Get(context, v8_str("o3")).ToLocalChecked()) 7889 .FromJust()); 7890 } else if (name->Equals(context, v8_str("p4")).FromJust()) { 7891 CHECK(info.This() 7892 ->Equals(context, 7893 global->Get(context, v8_str("o4")).ToLocalChecked()) 7894 .FromJust()); 7895 } 7896 } 7897 7898 7899 THREADED_TEST(GetterHolders) { 7900 v8::Isolate* isolate = CcTest::isolate(); 7901 v8::HandleScope scope(isolate); 7902 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7903 obj->SetAccessor(v8_str("p1"), PGetter); 7904 obj->SetAccessor(v8_str("p2"), PGetter); 7905 obj->SetAccessor(v8_str("p3"), PGetter); 7906 obj->SetAccessor(v8_str("p4"), PGetter); 7907 p_getter_count = 0; 7908 RunHolderTest(obj); 7909 CHECK_EQ(40, p_getter_count); 7910 } 7911 7912 7913 THREADED_TEST(PreInterceptorHolders) { 7914 v8::Isolate* isolate = CcTest::isolate(); 7915 v8::HandleScope scope(isolate); 7916 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7917 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2)); 7918 p_getter_count2 = 0; 7919 RunHolderTest(obj); 7920 CHECK_EQ(40, p_getter_count2); 7921 } 7922 7923 7924 THREADED_TEST(ObjectInstantiation) { 7925 v8::Isolate* isolate = CcTest::isolate(); 7926 v8::HandleScope scope(isolate); 7927 v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 7928 templ->SetAccessor(v8_str("t"), PGetter2); 7929 LocalContext context; 7930 CHECK(context->Global() 7931 ->Set(context.local(), v8_str("o"), 7932 templ->NewInstance(context.local()).ToLocalChecked()) 7933 .FromJust()); 7934 for (int i = 0; i < 100; i++) { 7935 v8::HandleScope inner_scope(CcTest::isolate()); 7936 v8::Local<v8::Object> obj = 7937 templ->NewInstance(context.local()).ToLocalChecked(); 7938 CHECK(!obj->Equals(context.local(), context->Global() 7939 ->Get(context.local(), v8_str("o")) 7940 .ToLocalChecked()) 7941 .FromJust()); 7942 CHECK( 7943 context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust()); 7944 v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__"); 7945 CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust()); 7946 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust()); 7947 } 7948 } 7949 7950 7951 static int StrCmp16(uint16_t* a, uint16_t* b) { 7952 while (true) { 7953 if (*a == 0 && *b == 0) return 0; 7954 if (*a != *b) return 0 + *a - *b; 7955 a++; 7956 b++; 7957 } 7958 } 7959 7960 7961 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 7962 while (true) { 7963 if (n-- == 0) return 0; 7964 if (*a == 0 && *b == 0) return 0; 7965 if (*a != *b) return 0 + *a - *b; 7966 a++; 7967 b++; 7968 } 7969 } 7970 7971 7972 int GetUtf8Length(Local<String> str) { 7973 int len = str->Utf8Length(); 7974 if (len < 0) { 7975 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 7976 i::String::Flatten(istr); 7977 len = str->Utf8Length(); 7978 } 7979 return len; 7980 } 7981 7982 7983 THREADED_TEST(StringWrite) { 7984 LocalContext context; 7985 v8::HandleScope scope(context->GetIsolate()); 7986 v8::Local<String> str = v8_str("abcde"); 7987 // abc<Icelandic eth><Unicode snowman>. 7988 v8::Local<String> str2 = v8_str("abc\303\260\342\230\203"); 7989 v8::Local<String> str3 = 7990 v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def", 7991 v8::NewStringType::kNormal, 7) 7992 .ToLocalChecked(); 7993 // "ab" + lead surrogate + "cd" + trail surrogate + "ef" 7994 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 }; 7995 v8::Local<String> orphans_str = 7996 v8::String::NewFromTwoByte(context->GetIsolate(), orphans, 7997 v8::NewStringType::kNormal, 8) 7998 .ToLocalChecked(); 7999 // single lead surrogate 8000 uint16_t lead[1] = { 0xd800 }; 8001 v8::Local<String> lead_str = 8002 v8::String::NewFromTwoByte(context->GetIsolate(), lead, 8003 v8::NewStringType::kNormal, 1) 8004 .ToLocalChecked(); 8005 // single trail surrogate 8006 uint16_t trail[1] = { 0xdc00 }; 8007 v8::Local<String> trail_str = 8008 v8::String::NewFromTwoByte(context->GetIsolate(), trail, 8009 v8::NewStringType::kNormal, 1) 8010 .ToLocalChecked(); 8011 // surrogate pair 8012 uint16_t pair[2] = { 0xd800, 0xdc00 }; 8013 v8::Local<String> pair_str = 8014 v8::String::NewFromTwoByte(context->GetIsolate(), pair, 8015 v8::NewStringType::kNormal, 2) 8016 .ToLocalChecked(); 8017 const int kStride = 4; // Must match stride in for loops in JS below. 8018 CompileRun( 8019 "var left = '';" 8020 "for (var i = 0; i < 0xd800; i += 4) {" 8021 " left = left + String.fromCharCode(i);" 8022 "}"); 8023 CompileRun( 8024 "var right = '';" 8025 "for (var i = 0; i < 0xd800; i += 4) {" 8026 " right = String.fromCharCode(i) + right;" 8027 "}"); 8028 v8::Local<v8::Object> global = context->Global(); 8029 Local<String> left_tree = global->Get(context.local(), v8_str("left")) 8030 .ToLocalChecked() 8031 .As<String>(); 8032 Local<String> right_tree = global->Get(context.local(), v8_str("right")) 8033 .ToLocalChecked() 8034 .As<String>(); 8035 8036 CHECK_EQ(5, str2->Length()); 8037 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 8038 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 8039 8040 char buf[100]; 8041 char utf8buf[0xd800 * 3]; 8042 uint16_t wbuf[100]; 8043 int len; 8044 int charlen; 8045 8046 memset(utf8buf, 0x1, 1000); 8047 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 8048 CHECK_EQ(9, len); 8049 CHECK_EQ(5, charlen); 8050 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8051 8052 memset(utf8buf, 0x1, 1000); 8053 len = str2->WriteUtf8(utf8buf, 8, &charlen); 8054 CHECK_EQ(8, len); 8055 CHECK_EQ(5, charlen); 8056 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 8057 8058 memset(utf8buf, 0x1, 1000); 8059 len = str2->WriteUtf8(utf8buf, 7, &charlen); 8060 CHECK_EQ(5, len); 8061 CHECK_EQ(4, charlen); 8062 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8063 8064 memset(utf8buf, 0x1, 1000); 8065 len = str2->WriteUtf8(utf8buf, 6, &charlen); 8066 CHECK_EQ(5, len); 8067 CHECK_EQ(4, charlen); 8068 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8069 8070 memset(utf8buf, 0x1, 1000); 8071 len = str2->WriteUtf8(utf8buf, 5, &charlen); 8072 CHECK_EQ(5, len); 8073 CHECK_EQ(4, charlen); 8074 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8075 8076 memset(utf8buf, 0x1, 1000); 8077 len = str2->WriteUtf8(utf8buf, 4, &charlen); 8078 CHECK_EQ(3, len); 8079 CHECK_EQ(3, charlen); 8080 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 8081 8082 memset(utf8buf, 0x1, 1000); 8083 len = str2->WriteUtf8(utf8buf, 3, &charlen); 8084 CHECK_EQ(3, len); 8085 CHECK_EQ(3, charlen); 8086 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 8087 8088 memset(utf8buf, 0x1, 1000); 8089 len = str2->WriteUtf8(utf8buf, 2, &charlen); 8090 CHECK_EQ(2, len); 8091 CHECK_EQ(2, charlen); 8092 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 8093 8094 // allow orphan surrogates by default 8095 memset(utf8buf, 0x1, 1000); 8096 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 8097 CHECK_EQ(13, len); 8098 CHECK_EQ(8, charlen); 8099 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef")); 8100 8101 // replace orphan surrogates with unicode replacement character 8102 memset(utf8buf, 0x1, 1000); 8103 len = orphans_str->WriteUtf8(utf8buf, 8104 sizeof(utf8buf), 8105 &charlen, 8106 String::REPLACE_INVALID_UTF8); 8107 CHECK_EQ(13, len); 8108 CHECK_EQ(8, charlen); 8109 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef")); 8110 8111 // replace single lead surrogate with unicode replacement character 8112 memset(utf8buf, 0x1, 1000); 8113 len = lead_str->WriteUtf8(utf8buf, 8114 sizeof(utf8buf), 8115 &charlen, 8116 String::REPLACE_INVALID_UTF8); 8117 CHECK_EQ(4, len); 8118 CHECK_EQ(1, charlen); 8119 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 8120 8121 // replace single trail surrogate with unicode replacement character 8122 memset(utf8buf, 0x1, 1000); 8123 len = trail_str->WriteUtf8(utf8buf, 8124 sizeof(utf8buf), 8125 &charlen, 8126 String::REPLACE_INVALID_UTF8); 8127 CHECK_EQ(4, len); 8128 CHECK_EQ(1, charlen); 8129 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 8130 8131 // do not replace / write anything if surrogate pair does not fit the buffer 8132 // space 8133 memset(utf8buf, 0x1, 1000); 8134 len = pair_str->WriteUtf8(utf8buf, 8135 3, 8136 &charlen, 8137 String::REPLACE_INVALID_UTF8); 8138 CHECK_EQ(0, len); 8139 CHECK_EQ(0, charlen); 8140 8141 memset(utf8buf, 0x1, sizeof(utf8buf)); 8142 len = GetUtf8Length(left_tree); 8143 int utf8_expected = 8144 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 8145 CHECK_EQ(utf8_expected, len); 8146 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 8147 CHECK_EQ(utf8_expected, len); 8148 CHECK_EQ(0xd800 / kStride, charlen); 8149 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 8150 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 8151 CHECK_EQ(0xc0 - kStride, 8152 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 8153 CHECK_EQ(1, utf8buf[utf8_expected]); 8154 8155 memset(utf8buf, 0x1, sizeof(utf8buf)); 8156 len = GetUtf8Length(right_tree); 8157 CHECK_EQ(utf8_expected, len); 8158 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 8159 CHECK_EQ(utf8_expected, len); 8160 CHECK_EQ(0xd800 / kStride, charlen); 8161 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 8162 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 8163 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 8164 CHECK_EQ(1, utf8buf[utf8_expected]); 8165 8166 memset(buf, 0x1, sizeof(buf)); 8167 memset(wbuf, 0x1, sizeof(wbuf)); 8168 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8169 CHECK_EQ(5, len); 8170 len = str->Write(wbuf); 8171 CHECK_EQ(5, len); 8172 CHECK_EQ(0, strcmp("abcde", buf)); 8173 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8174 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 8175 8176 memset(buf, 0x1, sizeof(buf)); 8177 memset(wbuf, 0x1, sizeof(wbuf)); 8178 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 8179 CHECK_EQ(4, len); 8180 len = str->Write(wbuf, 0, 4); 8181 CHECK_EQ(4, len); 8182 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 8183 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 8184 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 8185 8186 memset(buf, 0x1, sizeof(buf)); 8187 memset(wbuf, 0x1, sizeof(wbuf)); 8188 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 8189 CHECK_EQ(5, len); 8190 len = str->Write(wbuf, 0, 5); 8191 CHECK_EQ(5, len); 8192 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 8193 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 8194 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 8195 8196 memset(buf, 0x1, sizeof(buf)); 8197 memset(wbuf, 0x1, sizeof(wbuf)); 8198 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 8199 CHECK_EQ(5, len); 8200 len = str->Write(wbuf, 0, 6); 8201 CHECK_EQ(5, len); 8202 CHECK_EQ(0, strcmp("abcde", buf)); 8203 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8204 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 8205 8206 memset(buf, 0x1, sizeof(buf)); 8207 memset(wbuf, 0x1, sizeof(wbuf)); 8208 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 8209 CHECK_EQ(1, len); 8210 len = str->Write(wbuf, 4, -1); 8211 CHECK_EQ(1, len); 8212 CHECK_EQ(0, strcmp("e", buf)); 8213 uint16_t answer5[] = {'e', '\0'}; 8214 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8215 8216 memset(buf, 0x1, sizeof(buf)); 8217 memset(wbuf, 0x1, sizeof(wbuf)); 8218 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 8219 CHECK_EQ(1, len); 8220 len = str->Write(wbuf, 4, 6); 8221 CHECK_EQ(1, len); 8222 CHECK_EQ(0, strcmp("e", buf)); 8223 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8224 8225 memset(buf, 0x1, sizeof(buf)); 8226 memset(wbuf, 0x1, sizeof(wbuf)); 8227 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 8228 CHECK_EQ(1, len); 8229 len = str->Write(wbuf, 4, 1); 8230 CHECK_EQ(1, len); 8231 CHECK_EQ(0, strncmp("e\1", buf, 2)); 8232 uint16_t answer6[] = {'e', 0x101}; 8233 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 8234 8235 memset(buf, 0x1, sizeof(buf)); 8236 memset(wbuf, 0x1, sizeof(wbuf)); 8237 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 8238 CHECK_EQ(1, len); 8239 len = str->Write(wbuf, 3, 1); 8240 CHECK_EQ(1, len); 8241 CHECK_EQ(0, strncmp("d\1", buf, 2)); 8242 uint16_t answer7[] = {'d', 0x101}; 8243 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 8244 8245 memset(wbuf, 0x1, sizeof(wbuf)); 8246 wbuf[5] = 'X'; 8247 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 8248 CHECK_EQ(5, len); 8249 CHECK_EQ('X', wbuf[5]); 8250 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 8251 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8252 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 8253 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 8254 wbuf[5] = '\0'; 8255 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 8256 8257 memset(buf, 0x1, sizeof(buf)); 8258 buf[5] = 'X'; 8259 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 8260 0, 8261 6, 8262 String::NO_NULL_TERMINATION); 8263 CHECK_EQ(5, len); 8264 CHECK_EQ('X', buf[5]); 8265 CHECK_EQ(0, strncmp("abcde", buf, 5)); 8266 CHECK_NE(0, strcmp("abcde", buf)); 8267 buf[5] = '\0'; 8268 CHECK_EQ(0, strcmp("abcde", buf)); 8269 8270 memset(utf8buf, 0x1, sizeof(utf8buf)); 8271 utf8buf[8] = 'X'; 8272 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8273 String::NO_NULL_TERMINATION); 8274 CHECK_EQ(8, len); 8275 CHECK_EQ('X', utf8buf[8]); 8276 CHECK_EQ(5, charlen); 8277 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 8278 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8279 utf8buf[8] = '\0'; 8280 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8281 8282 memset(utf8buf, 0x1, sizeof(utf8buf)); 8283 utf8buf[5] = 'X'; 8284 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8285 String::NO_NULL_TERMINATION); 8286 CHECK_EQ(5, len); 8287 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 8288 CHECK_EQ(5, charlen); 8289 utf8buf[5] = '\0'; 8290 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 8291 8292 memset(buf, 0x1, sizeof(buf)); 8293 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8294 CHECK_EQ(7, len); 8295 CHECK_EQ(0, strcmp("abc", buf)); 8296 CHECK_EQ(0, buf[3]); 8297 CHECK_EQ(0, strcmp("def", buf + 4)); 8298 8299 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8300 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8301 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8302 } 8303 8304 8305 static void Utf16Helper( 8306 LocalContext& context, // NOLINT 8307 const char* name, 8308 const char* lengths_name, 8309 int len) { 8310 Local<v8::Array> a = Local<v8::Array>::Cast( 8311 context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked()); 8312 Local<v8::Array> alens = 8313 Local<v8::Array>::Cast(context->Global() 8314 ->Get(context.local(), v8_str(lengths_name)) 8315 .ToLocalChecked()); 8316 for (int i = 0; i < len; i++) { 8317 Local<v8::String> string = 8318 Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked()); 8319 Local<v8::Number> expected_len = Local<v8::Number>::Cast( 8320 alens->Get(context.local(), i).ToLocalChecked()); 8321 int length = GetUtf8Length(string); 8322 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 8323 } 8324 } 8325 8326 8327 THREADED_TEST(Utf16) { 8328 LocalContext context; 8329 v8::HandleScope scope(context->GetIsolate()); 8330 CompileRun( 8331 "var pad = '01234567890123456789';" 8332 "var p = [];" 8333 "var plens = [20, 3, 3];" 8334 "p.push('01234567890123456789');" 8335 "var lead = 0xd800;" 8336 "var trail = 0xdc00;" 8337 "p.push(String.fromCharCode(0xd800));" 8338 "p.push(String.fromCharCode(0xdc00));" 8339 "var a = [];" 8340 "var b = [];" 8341 "var c = [];" 8342 "var alens = [];" 8343 "for (var i = 0; i < 3; i++) {" 8344 " p[1] = String.fromCharCode(lead++);" 8345 " for (var j = 0; j < 3; j++) {" 8346 " p[2] = String.fromCharCode(trail++);" 8347 " a.push(p[i] + p[j]);" 8348 " b.push(p[i] + p[j]);" 8349 " c.push(p[i] + p[j]);" 8350 " alens.push(plens[i] + plens[j]);" 8351 " }" 8352 "}" 8353 "alens[5] -= 2;" // Here the surrogate pairs match up. 8354 "var a2 = [];" 8355 "var b2 = [];" 8356 "var c2 = [];" 8357 "var a2lens = [];" 8358 "for (var m = 0; m < 9; m++) {" 8359 " for (var n = 0; n < 9; n++) {" 8360 " a2.push(a[m] + a[n]);" 8361 " b2.push(b[m] + b[n]);" 8362 " var newc = 'x' + c[m] + c[n] + 'y';" 8363 " c2.push(newc.substring(1, newc.length - 1));" 8364 " var utf = alens[m] + alens[n];" // And here. 8365 // The 'n's that start with 0xdc.. are 6-8 8366 // The 'm's that end with 0xd8.. are 1, 4 and 7 8367 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 8368 " a2lens.push(utf);" 8369 " }" 8370 "}"); 8371 Utf16Helper(context, "a", "alens", 9); 8372 Utf16Helper(context, "a2", "a2lens", 81); 8373 } 8374 8375 8376 static bool SameSymbol(Local<String> s1, Local<String> s2) { 8377 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 8378 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 8379 return *is1 == *is2; 8380 } 8381 8382 8383 THREADED_TEST(Utf16Symbol) { 8384 LocalContext context; 8385 v8::HandleScope scope(context->GetIsolate()); 8386 8387 Local<String> symbol1 = 8388 v8::String::NewFromUtf8(context->GetIsolate(), "abc", 8389 v8::NewStringType::kInternalized) 8390 .ToLocalChecked(); 8391 Local<String> symbol2 = 8392 v8::String::NewFromUtf8(context->GetIsolate(), "abc", 8393 v8::NewStringType::kInternalized) 8394 .ToLocalChecked(); 8395 CHECK(SameSymbol(symbol1, symbol2)); 8396 8397 CompileRun( 8398 "var sym0 = 'benedictus';" 8399 "var sym0b = 'S\303\270ren';" 8400 "var sym1 = '\355\240\201\355\260\207';" 8401 "var sym2 = '\360\220\220\210';" 8402 "var sym3 = 'x\355\240\201\355\260\207';" 8403 "var sym4 = 'x\360\220\220\210';" 8404 "if (sym1.length != 2) throw sym1;" 8405 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 8406 "if (sym2.length != 2) throw sym2;" 8407 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 8408 "if (sym3.length != 3) throw sym3;" 8409 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 8410 "if (sym4.length != 3) throw sym4;" 8411 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 8412 Local<String> sym0 = 8413 v8::String::NewFromUtf8(context->GetIsolate(), "benedictus", 8414 v8::NewStringType::kInternalized) 8415 .ToLocalChecked(); 8416 Local<String> sym0b = 8417 v8::String::NewFromUtf8(context->GetIsolate(), "S\303\270ren", 8418 v8::NewStringType::kInternalized) 8419 .ToLocalChecked(); 8420 Local<String> sym1 = 8421 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207", 8422 v8::NewStringType::kInternalized) 8423 .ToLocalChecked(); 8424 Local<String> sym2 = 8425 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210", 8426 v8::NewStringType::kInternalized) 8427 .ToLocalChecked(); 8428 Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(), 8429 "x\355\240\201\355\260\207", 8430 v8::NewStringType::kInternalized) 8431 .ToLocalChecked(); 8432 Local<String> sym4 = 8433 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210", 8434 v8::NewStringType::kInternalized) 8435 .ToLocalChecked(); 8436 v8::Local<v8::Object> global = context->Global(); 8437 Local<Value> s0 = 8438 global->Get(context.local(), v8_str("sym0")).ToLocalChecked(); 8439 Local<Value> s0b = 8440 global->Get(context.local(), v8_str("sym0b")).ToLocalChecked(); 8441 Local<Value> s1 = 8442 global->Get(context.local(), v8_str("sym1")).ToLocalChecked(); 8443 Local<Value> s2 = 8444 global->Get(context.local(), v8_str("sym2")).ToLocalChecked(); 8445 Local<Value> s3 = 8446 global->Get(context.local(), v8_str("sym3")).ToLocalChecked(); 8447 Local<Value> s4 = 8448 global->Get(context.local(), v8_str("sym4")).ToLocalChecked(); 8449 CHECK(SameSymbol(sym0, Local<String>::Cast(s0))); 8450 CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b))); 8451 CHECK(SameSymbol(sym1, Local<String>::Cast(s1))); 8452 CHECK(SameSymbol(sym2, Local<String>::Cast(s2))); 8453 CHECK(SameSymbol(sym3, Local<String>::Cast(s3))); 8454 CHECK(SameSymbol(sym4, Local<String>::Cast(s4))); 8455 } 8456 8457 8458 THREADED_TEST(Utf16MissingTrailing) { 8459 LocalContext context; 8460 v8::HandleScope scope(context->GetIsolate()); 8461 8462 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow` 8463 int size = 1024 * 64; 8464 uint8_t* buffer = new uint8_t[size]; 8465 for (int i = 0; i < size; i += 4) { 8466 buffer[i] = 0xf0; 8467 buffer[i + 1] = 0x9d; 8468 buffer[i + 2] = 0x80; 8469 buffer[i + 3] = 0x9e; 8470 } 8471 8472 // Now invoke the decoder without last 3 bytes 8473 v8::Local<v8::String> str = 8474 v8::String::NewFromUtf8( 8475 context->GetIsolate(), reinterpret_cast<char*>(buffer), 8476 v8::NewStringType::kNormal, size - 3).ToLocalChecked(); 8477 USE(str); 8478 delete[] buffer; 8479 } 8480 8481 8482 THREADED_TEST(Utf16Trailing3Byte) { 8483 LocalContext context; 8484 v8::HandleScope scope(context->GetIsolate()); 8485 8486 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow` 8487 int size = 1024 * 63; 8488 uint8_t* buffer = new uint8_t[size]; 8489 for (int i = 0; i < size; i += 3) { 8490 buffer[i] = 0xe2; 8491 buffer[i + 1] = 0x80; 8492 buffer[i + 2] = 0xa6; 8493 } 8494 8495 // Now invoke the decoder without last 3 bytes 8496 v8::Local<v8::String> str = 8497 v8::String::NewFromUtf8( 8498 context->GetIsolate(), reinterpret_cast<char*>(buffer), 8499 v8::NewStringType::kNormal, size).ToLocalChecked(); 8500 8501 v8::String::Value value(str); 8502 CHECK_EQ(value.length(), size / 3); 8503 CHECK_EQ((*value)[value.length() - 1], 0x2026); 8504 8505 delete[] buffer; 8506 } 8507 8508 8509 THREADED_TEST(ToArrayIndex) { 8510 LocalContext context; 8511 v8::Isolate* isolate = context->GetIsolate(); 8512 v8::HandleScope scope(isolate); 8513 8514 v8::Local<String> str = v8_str("42"); 8515 v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local()); 8516 CHECK(!index.IsEmpty()); 8517 CHECK_EQ(42.0, 8518 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8519 str = v8_str("42asdf"); 8520 index = str->ToArrayIndex(context.local()); 8521 CHECK(index.IsEmpty()); 8522 str = v8_str("-42"); 8523 index = str->ToArrayIndex(context.local()); 8524 CHECK(index.IsEmpty()); 8525 str = v8_str("4294967294"); 8526 index = str->ToArrayIndex(context.local()); 8527 CHECK(!index.IsEmpty()); 8528 CHECK_EQ(4294967294.0, 8529 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8530 v8::Local<v8::Number> num = v8::Number::New(isolate, 1); 8531 index = num->ToArrayIndex(context.local()); 8532 CHECK(!index.IsEmpty()); 8533 CHECK_EQ(1.0, 8534 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8535 num = v8::Number::New(isolate, -1); 8536 index = num->ToArrayIndex(context.local()); 8537 CHECK(index.IsEmpty()); 8538 v8::Local<v8::Object> obj = v8::Object::New(isolate); 8539 index = obj->ToArrayIndex(context.local()); 8540 CHECK(index.IsEmpty()); 8541 } 8542 8543 8544 THREADED_TEST(ErrorConstruction) { 8545 LocalContext context; 8546 v8::HandleScope scope(context->GetIsolate()); 8547 8548 v8::Local<String> foo = v8_str("foo"); 8549 v8::Local<String> message = v8_str("message"); 8550 v8::Local<Value> range_error = v8::Exception::RangeError(foo); 8551 CHECK(range_error->IsObject()); 8552 CHECK(range_error.As<v8::Object>() 8553 ->Get(context.local(), message) 8554 .ToLocalChecked() 8555 ->Equals(context.local(), foo) 8556 .FromJust()); 8557 v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo); 8558 CHECK(reference_error->IsObject()); 8559 CHECK(reference_error.As<v8::Object>() 8560 ->Get(context.local(), message) 8561 .ToLocalChecked() 8562 ->Equals(context.local(), foo) 8563 .FromJust()); 8564 v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo); 8565 CHECK(syntax_error->IsObject()); 8566 CHECK(syntax_error.As<v8::Object>() 8567 ->Get(context.local(), message) 8568 .ToLocalChecked() 8569 ->Equals(context.local(), foo) 8570 .FromJust()); 8571 v8::Local<Value> type_error = v8::Exception::TypeError(foo); 8572 CHECK(type_error->IsObject()); 8573 CHECK(type_error.As<v8::Object>() 8574 ->Get(context.local(), message) 8575 .ToLocalChecked() 8576 ->Equals(context.local(), foo) 8577 .FromJust()); 8578 v8::Local<Value> error = v8::Exception::Error(foo); 8579 CHECK(error->IsObject()); 8580 CHECK(error.As<v8::Object>() 8581 ->Get(context.local(), message) 8582 .ToLocalChecked() 8583 ->Equals(context.local(), foo) 8584 .FromJust()); 8585 } 8586 8587 8588 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) { 8589 ApiTestFuzzer::Fuzz(); 8590 v8::Local<String> foo = v8_str("foo"); 8591 v8::Local<String> message = v8_str("message"); 8592 v8::Local<Value> error = v8::Exception::Error(foo); 8593 CHECK(error->IsObject()); 8594 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8595 CHECK(error.As<v8::Object>() 8596 ->Get(context, message) 8597 .ToLocalChecked() 8598 ->Equals(context, foo) 8599 .FromJust()); 8600 info.GetIsolate()->ThrowException(error); 8601 info.GetReturnValue().SetUndefined(); 8602 } 8603 8604 8605 THREADED_TEST(ExceptionCreateMessage) { 8606 LocalContext context; 8607 v8::HandleScope scope(context->GetIsolate()); 8608 v8::Local<String> foo_str = v8_str("foo"); 8609 v8::Local<String> message_str = v8_str("message"); 8610 8611 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true); 8612 8613 Local<v8::FunctionTemplate> fun = 8614 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception); 8615 v8::Local<v8::Object> global = context->Global(); 8616 CHECK(global->Set(context.local(), v8_str("throwV8Exception"), 8617 fun->GetFunction(context.local()).ToLocalChecked()) 8618 .FromJust()); 8619 8620 TryCatch try_catch(context->GetIsolate()); 8621 CompileRun( 8622 "function f1() {\n" 8623 " throwV8Exception();\n" 8624 "};\n" 8625 "f1();"); 8626 CHECK(try_catch.HasCaught()); 8627 8628 v8::Local<v8::Value> error = try_catch.Exception(); 8629 CHECK(error->IsObject()); 8630 CHECK(error.As<v8::Object>() 8631 ->Get(context.local(), message_str) 8632 .ToLocalChecked() 8633 ->Equals(context.local(), foo_str) 8634 .FromJust()); 8635 8636 v8::Local<v8::Message> message = 8637 v8::Exception::CreateMessage(context->GetIsolate(), error); 8638 CHECK(!message.IsEmpty()); 8639 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 8640 CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust()); 8641 8642 v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace(); 8643 CHECK(!stackTrace.IsEmpty()); 8644 CHECK_EQ(2, stackTrace->GetFrameCount()); 8645 8646 stackTrace = v8::Exception::GetStackTrace(error); 8647 CHECK(!stackTrace.IsEmpty()); 8648 CHECK_EQ(2, stackTrace->GetFrameCount()); 8649 8650 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false); 8651 8652 // Now check message location when SetCaptureStackTraceForUncaughtExceptions 8653 // is false. 8654 try_catch.Reset(); 8655 8656 CompileRun( 8657 "function f2() {\n" 8658 " return throwV8Exception();\n" 8659 "};\n" 8660 "f2();"); 8661 CHECK(try_catch.HasCaught()); 8662 8663 error = try_catch.Exception(); 8664 CHECK(error->IsObject()); 8665 CHECK(error.As<v8::Object>() 8666 ->Get(context.local(), message_str) 8667 .ToLocalChecked() 8668 ->Equals(context.local(), foo_str) 8669 .FromJust()); 8670 8671 message = v8::Exception::CreateMessage(context->GetIsolate(), error); 8672 CHECK(!message.IsEmpty()); 8673 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 8674 CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust()); 8675 8676 // Should be empty stack trace. 8677 stackTrace = message->GetStackTrace(); 8678 CHECK(stackTrace.IsEmpty()); 8679 CHECK(v8::Exception::GetStackTrace(error).IsEmpty()); 8680 } 8681 8682 8683 THREADED_TEST(ExceptionCreateMessageLength) { 8684 LocalContext context; 8685 v8::HandleScope scope(context->GetIsolate()); 8686 8687 // Test that the message is not truncated. 8688 TryCatch try_catch(context->GetIsolate()); 8689 CompileRun( 8690 "var message = 'm';" 8691 "while (message.length < 1000) message += message;" 8692 "throw message;"); 8693 CHECK(try_catch.HasCaught()); 8694 8695 CHECK_LT(1000, try_catch.Message()->Get()->Length()); 8696 } 8697 8698 8699 static void YGetter(Local<String> name, 8700 const v8::PropertyCallbackInfo<v8::Value>& info) { 8701 ApiTestFuzzer::Fuzz(); 8702 info.GetReturnValue().Set(v8_num(10)); 8703 } 8704 8705 8706 static void YSetter(Local<String> name, 8707 Local<Value> value, 8708 const v8::PropertyCallbackInfo<void>& info) { 8709 Local<Object> this_obj = Local<Object>::Cast(info.This()); 8710 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8711 if (this_obj->Has(context, name).FromJust()) 8712 this_obj->Delete(context, name).FromJust(); 8713 CHECK(this_obj->Set(context, name, value).FromJust()); 8714 } 8715 8716 8717 THREADED_TEST(DeleteAccessor) { 8718 v8::Isolate* isolate = CcTest::isolate(); 8719 v8::HandleScope scope(isolate); 8720 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8721 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 8722 LocalContext context; 8723 v8::Local<v8::Object> holder = 8724 obj->NewInstance(context.local()).ToLocalChecked(); 8725 CHECK(context->Global() 8726 ->Set(context.local(), v8_str("holder"), holder) 8727 .FromJust()); 8728 v8::Local<Value> result = 8729 CompileRun("holder.y = 11; holder.y = 12; holder.y"); 8730 CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust()); 8731 } 8732 8733 8734 static int trouble_nesting = 0; 8735 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 8736 ApiTestFuzzer::Fuzz(); 8737 trouble_nesting++; 8738 8739 // Call a JS function that throws an uncaught exception. 8740 Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 8741 Local<v8::Object> arg_this = context->Global(); 8742 Local<Value> trouble_callee = 8743 (trouble_nesting == 3) 8744 ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked() 8745 : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked(); 8746 CHECK(trouble_callee->IsFunction()); 8747 args.GetReturnValue().Set(Function::Cast(*trouble_callee) 8748 ->Call(context, arg_this, 0, NULL) 8749 .FromMaybe(v8::Local<v8::Value>())); 8750 } 8751 8752 8753 static int report_count = 0; 8754 static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>, 8755 v8::Local<Value>) { 8756 report_count++; 8757 } 8758 8759 8760 // Counts uncaught exceptions, but other tests running in parallel 8761 // also have uncaught exceptions. 8762 TEST(ApiUncaughtException) { 8763 report_count = 0; 8764 LocalContext env; 8765 v8::Isolate* isolate = env->GetIsolate(); 8766 v8::HandleScope scope(isolate); 8767 isolate->AddMessageListener(ApiUncaughtExceptionTestListener); 8768 8769 Local<v8::FunctionTemplate> fun = 8770 v8::FunctionTemplate::New(isolate, TroubleCallback); 8771 v8::Local<v8::Object> global = env->Global(); 8772 CHECK(global->Set(env.local(), v8_str("trouble"), 8773 fun->GetFunction(env.local()).ToLocalChecked()) 8774 .FromJust()); 8775 8776 CompileRun( 8777 "function trouble_callee() {" 8778 " var x = null;" 8779 " return x.foo;" 8780 "};" 8781 "function trouble_caller() {" 8782 " trouble();" 8783 "};"); 8784 Local<Value> trouble = 8785 global->Get(env.local(), v8_str("trouble")).ToLocalChecked(); 8786 CHECK(trouble->IsFunction()); 8787 Local<Value> trouble_callee = 8788 global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked(); 8789 CHECK(trouble_callee->IsFunction()); 8790 Local<Value> trouble_caller = 8791 global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked(); 8792 CHECK(trouble_caller->IsFunction()); 8793 Function::Cast(*trouble_caller) 8794 ->Call(env.local(), global, 0, NULL) 8795 .FromMaybe(v8::Local<v8::Value>()); 8796 CHECK_EQ(1, report_count); 8797 isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener); 8798 } 8799 8800 8801 TEST(ApiUncaughtExceptionInObjectObserve) { 8802 v8::internal::FLAG_harmony_object_observe = true; 8803 v8::internal::FLAG_stack_size = 150; 8804 report_count = 0; 8805 LocalContext env; 8806 v8::Isolate* isolate = env->GetIsolate(); 8807 v8::HandleScope scope(isolate); 8808 isolate->AddMessageListener(ApiUncaughtExceptionTestListener); 8809 CompileRun( 8810 "var obj = {};" 8811 "var observe_count = 0;" 8812 "function observer1() { ++observe_count; };" 8813 "function observer2() { ++observe_count; };" 8814 "function observer_throws() { throw new Error(); };" 8815 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };" 8816 "Object.observe(obj, observer_throws.bind());" 8817 "Object.observe(obj, observer1);" 8818 "Object.observe(obj, stack_overflow);" 8819 "Object.observe(obj, observer2);" 8820 "Object.observe(obj, observer_throws.bind());" 8821 "obj.foo = 'bar';"); 8822 CHECK_EQ(3, report_count); 8823 ExpectInt32("observe_count", 2); 8824 isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener); 8825 } 8826 8827 8828 static const char* script_resource_name = "ExceptionInNativeScript.js"; 8829 static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message, 8830 v8::Local<Value>) { 8831 v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName(); 8832 CHECK(!name_val.IsEmpty() && name_val->IsString()); 8833 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 8834 CHECK_EQ(0, strcmp(script_resource_name, *name)); 8835 v8::Local<v8::Context> context = 8836 v8::Isolate::GetCurrent()->GetCurrentContext(); 8837 CHECK_EQ(3, message->GetLineNumber(context).FromJust()); 8838 v8::String::Utf8Value source_line( 8839 message->GetSourceLine(context).ToLocalChecked()); 8840 CHECK_EQ(0, strcmp(" new o.foo();", *source_line)); 8841 } 8842 8843 8844 TEST(ExceptionInNativeScript) { 8845 LocalContext env; 8846 v8::Isolate* isolate = env->GetIsolate(); 8847 v8::HandleScope scope(isolate); 8848 isolate->AddMessageListener(ExceptionInNativeScriptTestListener); 8849 8850 Local<v8::FunctionTemplate> fun = 8851 v8::FunctionTemplate::New(isolate, TroubleCallback); 8852 v8::Local<v8::Object> global = env->Global(); 8853 CHECK(global->Set(env.local(), v8_str("trouble"), 8854 fun->GetFunction(env.local()).ToLocalChecked()) 8855 .FromJust()); 8856 8857 CompileRunWithOrigin( 8858 "function trouble() {\n" 8859 " var o = {};\n" 8860 " new o.foo();\n" 8861 "};", 8862 script_resource_name); 8863 Local<Value> trouble = 8864 global->Get(env.local(), v8_str("trouble")).ToLocalChecked(); 8865 CHECK(trouble->IsFunction()); 8866 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty()); 8867 isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener); 8868 } 8869 8870 8871 TEST(CompilationErrorUsingTryCatchHandler) { 8872 LocalContext env; 8873 v8::HandleScope scope(env->GetIsolate()); 8874 v8::TryCatch try_catch(env->GetIsolate()); 8875 v8_compile("This doesn't &*&@#$&*^ compile."); 8876 CHECK(*try_catch.Exception()); 8877 CHECK(try_catch.HasCaught()); 8878 } 8879 8880 8881 TEST(TryCatchFinallyUsingTryCatchHandler) { 8882 LocalContext env; 8883 v8::HandleScope scope(env->GetIsolate()); 8884 v8::TryCatch try_catch(env->GetIsolate()); 8885 CompileRun("try { throw ''; } catch (e) {}"); 8886 CHECK(!try_catch.HasCaught()); 8887 CompileRun("try { throw ''; } finally {}"); 8888 CHECK(try_catch.HasCaught()); 8889 try_catch.Reset(); 8890 CompileRun( 8891 "(function() {" 8892 "try { throw ''; } finally { return; }" 8893 "})()"); 8894 CHECK(!try_catch.HasCaught()); 8895 CompileRun( 8896 "(function()" 8897 " { try { throw ''; } finally { throw 0; }" 8898 "})()"); 8899 CHECK(try_catch.HasCaught()); 8900 } 8901 8902 8903 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) { 8904 v8::HandleScope scope(args.GetIsolate()); 8905 CompileRun(args[0] 8906 ->ToString(args.GetIsolate()->GetCurrentContext()) 8907 .ToLocalChecked()); 8908 } 8909 8910 8911 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { 8912 v8::Isolate* isolate = CcTest::isolate(); 8913 v8::HandleScope scope(isolate); 8914 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 8915 templ->Set(v8_str("CEvaluate"), 8916 v8::FunctionTemplate::New(isolate, CEvaluate)); 8917 LocalContext context(0, templ); 8918 v8::TryCatch try_catch(isolate); 8919 CompileRun("try {" 8920 " CEvaluate('throw 1;');" 8921 "} finally {" 8922 "}"); 8923 CHECK(try_catch.HasCaught()); 8924 CHECK(!try_catch.Message().IsEmpty()); 8925 String::Utf8Value exception_value(try_catch.Exception()); 8926 CHECK_EQ(0, strcmp(*exception_value, "1")); 8927 try_catch.Reset(); 8928 CompileRun("try {" 8929 " CEvaluate('throw 1;');" 8930 "} finally {" 8931 " throw 2;" 8932 "}"); 8933 CHECK(try_catch.HasCaught()); 8934 CHECK(!try_catch.Message().IsEmpty()); 8935 String::Utf8Value finally_exception_value(try_catch.Exception()); 8936 CHECK_EQ(0, strcmp(*finally_exception_value, "2")); 8937 } 8938 8939 8940 // For use within the TestSecurityHandler() test. 8941 static bool g_security_callback_result = false; 8942 static bool SecurityTestCallback(Local<v8::Context> accessing_context, 8943 Local<v8::Object> accessed_object) { 8944 printf("a\n"); 8945 return g_security_callback_result; 8946 } 8947 8948 8949 // SecurityHandler can't be run twice 8950 TEST(SecurityHandler) { 8951 v8::Isolate* isolate = CcTest::isolate(); 8952 v8::HandleScope scope0(isolate); 8953 v8::Local<v8::ObjectTemplate> global_template = 8954 v8::ObjectTemplate::New(isolate); 8955 global_template->SetAccessCheckCallback(SecurityTestCallback); 8956 // Create an environment 8957 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 8958 context0->Enter(); 8959 8960 v8::Local<v8::Object> global0 = context0->Global(); 8961 v8::Local<Script> script0 = v8_compile("foo = 111"); 8962 script0->Run(context0).ToLocalChecked(); 8963 CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust()); 8964 v8::Local<Value> foo0 = 8965 global0->Get(context0, v8_str("foo")).ToLocalChecked(); 8966 CHECK_EQ(111, foo0->Int32Value(context0).FromJust()); 8967 v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked(); 8968 CHECK_EQ(999, z0->Int32Value(context0).FromJust()); 8969 8970 // Create another environment, should fail security checks. 8971 v8::HandleScope scope1(isolate); 8972 8973 v8::Local<Context> context1 = Context::New(isolate, NULL, global_template); 8974 context1->Enter(); 8975 8976 v8::Local<v8::Object> global1 = context1->Global(); 8977 global1->Set(context1, v8_str("othercontext"), global0).FromJust(); 8978 // This set will fail the security check. 8979 v8::Local<Script> script1 = 8980 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 8981 CHECK(script1->Run(context1).IsEmpty()); 8982 g_security_callback_result = true; 8983 // This read will pass the security check. 8984 v8::Local<Value> foo1 = 8985 global0->Get(context1, v8_str("foo")).ToLocalChecked(); 8986 CHECK_EQ(111, foo1->Int32Value(context0).FromJust()); 8987 // This read will pass the security check. 8988 v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked(); 8989 CHECK_EQ(999, z1->Int32Value(context1).FromJust()); 8990 8991 // Create another environment, should pass security checks. 8992 { 8993 v8::HandleScope scope2(isolate); 8994 LocalContext context2; 8995 v8::Local<v8::Object> global2 = context2->Global(); 8996 CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0) 8997 .FromJust()); 8998 v8::Local<Script> script2 = 8999 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 9000 script2->Run(context2.local()).ToLocalChecked(); 9001 v8::Local<Value> foo2 = 9002 global0->Get(context2.local(), v8_str("foo")).ToLocalChecked(); 9003 CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust()); 9004 v8::Local<Value> z2 = 9005 global0->Get(context2.local(), v8_str("0")).ToLocalChecked(); 9006 CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust()); 9007 } 9008 9009 context1->Exit(); 9010 context0->Exit(); 9011 } 9012 9013 9014 THREADED_TEST(SecurityChecks) { 9015 LocalContext env1; 9016 v8::HandleScope handle_scope(env1->GetIsolate()); 9017 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9018 9019 Local<Value> foo = v8_str("foo"); 9020 Local<Value> bar = v8_str("bar"); 9021 9022 // Set to the same domain. 9023 env1->SetSecurityToken(foo); 9024 9025 // Create a function in env1. 9026 CompileRun("spy=function(){return spy;}"); 9027 Local<Value> spy = 9028 env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked(); 9029 CHECK(spy->IsFunction()); 9030 9031 // Create another function accessing global objects. 9032 CompileRun("spy2=function(){return new this.Array();}"); 9033 Local<Value> spy2 = 9034 env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked(); 9035 CHECK(spy2->IsFunction()); 9036 9037 // Switch to env2 in the same domain and invoke spy on env2. 9038 { 9039 env2->SetSecurityToken(foo); 9040 // Enter env2 9041 Context::Scope scope_env2(env2); 9042 Local<Value> result = Function::Cast(*spy) 9043 ->Call(env2, env2->Global(), 0, NULL) 9044 .ToLocalChecked(); 9045 CHECK(result->IsFunction()); 9046 } 9047 9048 { 9049 env2->SetSecurityToken(bar); 9050 Context::Scope scope_env2(env2); 9051 9052 // Call cross_domain_call, it should throw an exception 9053 v8::TryCatch try_catch(env1->GetIsolate()); 9054 CHECK(Function::Cast(*spy2)->Call(env2, env2->Global(), 0, NULL).IsEmpty()); 9055 CHECK(try_catch.HasCaught()); 9056 } 9057 } 9058 9059 9060 // Regression test case for issue 1183439. 9061 THREADED_TEST(SecurityChecksForPrototypeChain) { 9062 LocalContext current; 9063 v8::HandleScope scope(current->GetIsolate()); 9064 v8::Local<Context> other = Context::New(current->GetIsolate()); 9065 9066 // Change context to be able to get to the Object function in the 9067 // other context without hitting the security checks. 9068 v8::Local<Value> other_object; 9069 { Context::Scope scope(other); 9070 other_object = 9071 other->Global()->Get(other, v8_str("Object")).ToLocalChecked(); 9072 CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust()); 9073 } 9074 9075 CHECK(current->Global() 9076 ->Set(current.local(), v8_str("other"), other->Global()) 9077 .FromJust()); 9078 CHECK(v8_compile("other") 9079 ->Run(current.local()) 9080 .ToLocalChecked() 9081 ->Equals(current.local(), other->Global()) 9082 .FromJust()); 9083 9084 // Make sure the security check fails here and we get an undefined 9085 // result instead of getting the Object function. Repeat in a loop 9086 // to make sure to exercise the IC code. 9087 v8::Local<Script> access_other0 = v8_compile("other.Object"); 9088 v8::Local<Script> access_other1 = v8_compile("other[42]"); 9089 for (int i = 0; i < 5; i++) { 9090 CHECK(access_other0->Run(current.local()).IsEmpty()); 9091 CHECK(access_other1->Run(current.local()).IsEmpty()); 9092 } 9093 9094 // Create an object that has 'other' in its prototype chain and make 9095 // sure we cannot access the Object function indirectly through 9096 // that. Repeat in a loop to make sure to exercise the IC code. 9097 v8_compile( 9098 "function F() { };" 9099 "F.prototype = other;" 9100 "var f = new F();") 9101 ->Run(current.local()) 9102 .ToLocalChecked(); 9103 v8::Local<Script> access_f0 = v8_compile("f.Object"); 9104 v8::Local<Script> access_f1 = v8_compile("f[42]"); 9105 for (int j = 0; j < 5; j++) { 9106 CHECK(access_f0->Run(current.local()).IsEmpty()); 9107 CHECK(access_f1->Run(current.local()).IsEmpty()); 9108 } 9109 9110 // Now it gets hairy: Set the prototype for the other global object 9111 // to be the current global object. The prototype chain for 'f' now 9112 // goes through 'other' but ends up in the current global object. 9113 { Context::Scope scope(other); 9114 CHECK(other->Global() 9115 ->Set(other, v8_str("__proto__"), current->Global()) 9116 .FromJust()); 9117 } 9118 // Set a named and an index property on the current global 9119 // object. To force the lookup to go through the other global object, 9120 // the properties must not exist in the other global object. 9121 CHECK(current->Global() 9122 ->Set(current.local(), v8_str("foo"), v8_num(100)) 9123 .FromJust()); 9124 CHECK(current->Global() 9125 ->Set(current.local(), v8_num(99), v8_num(101)) 9126 .FromJust()); 9127 // Try to read the properties from f and make sure that the access 9128 // gets stopped by the security checks on the other global object. 9129 Local<Script> access_f2 = v8_compile("f.foo"); 9130 Local<Script> access_f3 = v8_compile("f[99]"); 9131 for (int k = 0; k < 5; k++) { 9132 CHECK(access_f2->Run(current.local()).IsEmpty()); 9133 CHECK(access_f3->Run(current.local()).IsEmpty()); 9134 } 9135 } 9136 9137 9138 static bool security_check_with_gc_called; 9139 9140 static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context, 9141 Local<v8::Object> accessed_object) { 9142 CcTest::heap()->CollectAllGarbage(); 9143 security_check_with_gc_called = true; 9144 return true; 9145 } 9146 9147 9148 TEST(SecurityTestGCAllowed) { 9149 v8::Isolate* isolate = CcTest::isolate(); 9150 v8::HandleScope handle_scope(isolate); 9151 v8::Local<v8::ObjectTemplate> object_template = 9152 v8::ObjectTemplate::New(isolate); 9153 object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC); 9154 9155 v8::Local<Context> context = Context::New(isolate); 9156 v8::Context::Scope context_scope(context); 9157 9158 CHECK(context->Global() 9159 ->Set(context, v8_str("obj"), 9160 object_template->NewInstance(context).ToLocalChecked()) 9161 .FromJust()); 9162 9163 security_check_with_gc_called = false; 9164 CompileRun("obj[0] = new String(1002);"); 9165 CHECK(security_check_with_gc_called); 9166 9167 security_check_with_gc_called = false; 9168 CHECK(CompileRun("obj[0]") 9169 ->ToString(context) 9170 .ToLocalChecked() 9171 ->Equals(context, v8_str("1002")) 9172 .FromJust()); 9173 CHECK(security_check_with_gc_called); 9174 } 9175 9176 9177 THREADED_TEST(CrossDomainDelete) { 9178 LocalContext env1; 9179 v8::HandleScope handle_scope(env1->GetIsolate()); 9180 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9181 9182 Local<Value> foo = v8_str("foo"); 9183 Local<Value> bar = v8_str("bar"); 9184 9185 // Set to the same domain. 9186 env1->SetSecurityToken(foo); 9187 env2->SetSecurityToken(foo); 9188 9189 CHECK( 9190 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9191 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9192 9193 // Change env2 to a different domain and delete env1.prop. 9194 env2->SetSecurityToken(bar); 9195 { 9196 Context::Scope scope_env2(env2); 9197 Local<Value> result = 9198 CompileRun("delete env1.prop"); 9199 CHECK(result.IsEmpty()); 9200 } 9201 9202 // Check that env1.prop still exists. 9203 Local<Value> v = 9204 env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked(); 9205 CHECK(v->IsNumber()); 9206 CHECK_EQ(3, v->Int32Value(env1.local()).FromJust()); 9207 } 9208 9209 9210 THREADED_TEST(CrossDomainPropertyIsEnumerable) { 9211 LocalContext env1; 9212 v8::HandleScope handle_scope(env1->GetIsolate()); 9213 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9214 9215 Local<Value> foo = v8_str("foo"); 9216 Local<Value> bar = v8_str("bar"); 9217 9218 // Set to the same domain. 9219 env1->SetSecurityToken(foo); 9220 env2->SetSecurityToken(foo); 9221 9222 CHECK( 9223 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9224 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9225 9226 // env1.prop is enumerable in env2. 9227 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 9228 { 9229 Context::Scope scope_env2(env2); 9230 Local<Value> result = CompileRun(test); 9231 CHECK(result->IsTrue()); 9232 } 9233 9234 // Change env2 to a different domain and test again. 9235 env2->SetSecurityToken(bar); 9236 { 9237 Context::Scope scope_env2(env2); 9238 Local<Value> result = CompileRun(test); 9239 CHECK(result.IsEmpty()); 9240 } 9241 } 9242 9243 9244 THREADED_TEST(CrossDomainFor) { 9245 LocalContext env1; 9246 v8::HandleScope handle_scope(env1->GetIsolate()); 9247 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9248 9249 Local<Value> foo = v8_str("foo"); 9250 Local<Value> bar = v8_str("bar"); 9251 9252 // Set to the same domain. 9253 env1->SetSecurityToken(foo); 9254 env2->SetSecurityToken(foo); 9255 9256 CHECK( 9257 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9258 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9259 9260 // Change env2 to a different domain and set env1's global object 9261 // as the __proto__ of an object in env2 and enumerate properties 9262 // in for-in. It shouldn't enumerate properties on env1's global 9263 // object. It shouldn't throw either, just silently ignore them. 9264 env2->SetSecurityToken(bar); 9265 { 9266 Context::Scope scope_env2(env2); 9267 Local<Value> result = CompileRun( 9268 "(function() {" 9269 " try {" 9270 " for (var p in env1) {" 9271 " if (p == 'prop') return false;" 9272 " }" 9273 " return true;" 9274 " } catch (e) {" 9275 " return false;" 9276 " }" 9277 "})()"); 9278 CHECK(result->IsTrue()); 9279 } 9280 } 9281 9282 9283 THREADED_TEST(CrossDomainForInOnPrototype) { 9284 LocalContext env1; 9285 v8::HandleScope handle_scope(env1->GetIsolate()); 9286 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9287 9288 Local<Value> foo = v8_str("foo"); 9289 Local<Value> bar = v8_str("bar"); 9290 9291 // Set to the same domain. 9292 env1->SetSecurityToken(foo); 9293 env2->SetSecurityToken(foo); 9294 9295 CHECK( 9296 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9297 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9298 9299 // Change env2 to a different domain and set env1's global object 9300 // as the __proto__ of an object in env2 and enumerate properties 9301 // in for-in. It shouldn't enumerate properties on env1's global 9302 // object. 9303 env2->SetSecurityToken(bar); 9304 { 9305 Context::Scope scope_env2(env2); 9306 Local<Value> result = CompileRun( 9307 "(function() {" 9308 " var obj = { '__proto__': env1 };" 9309 " try {" 9310 " for (var p in obj) {" 9311 " if (p == 'prop') return false;" 9312 " }" 9313 " return true;" 9314 " } catch (e) {" 9315 " return false;" 9316 " }" 9317 "})()"); 9318 CHECK(result->IsTrue()); 9319 } 9320 } 9321 9322 9323 TEST(ContextDetachGlobal) { 9324 LocalContext env1; 9325 v8::HandleScope handle_scope(env1->GetIsolate()); 9326 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9327 9328 9329 Local<Value> foo = v8_str("foo"); 9330 9331 // Set to the same domain. 9332 env1->SetSecurityToken(foo); 9333 env2->SetSecurityToken(foo); 9334 9335 // Enter env2 9336 env2->Enter(); 9337 9338 // Create a function in env2 and add a reference to it in env1. 9339 Local<v8::Object> global2 = env2->Global(); 9340 CHECK(global2->Set(env2, v8_str("prop"), 9341 v8::Integer::New(env2->GetIsolate(), 1)) 9342 .FromJust()); 9343 CompileRun("function getProp() {return prop;}"); 9344 9345 CHECK(env1->Global() 9346 ->Set(env1.local(), v8_str("getProp"), 9347 global2->Get(env2, v8_str("getProp")).ToLocalChecked()) 9348 .FromJust()); 9349 9350 // Detach env2's global, and reuse the global object of env2 9351 env2->Exit(); 9352 env2->DetachGlobal(); 9353 9354 v8::Local<Context> env3 = Context::New( 9355 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2); 9356 env3->SetSecurityToken(v8_str("bar")); 9357 9358 env3->Enter(); 9359 Local<v8::Object> global3 = env3->Global(); 9360 CHECK(global2->Equals(env3, global3).FromJust()); 9361 CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined()); 9362 CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined()); 9363 CHECK(global3->Set(env3, v8_str("prop"), 9364 v8::Integer::New(env3->GetIsolate(), -1)) 9365 .FromJust()); 9366 CHECK(global3->Set(env3, v8_str("prop2"), 9367 v8::Integer::New(env3->GetIsolate(), 2)) 9368 .FromJust()); 9369 env3->Exit(); 9370 9371 // Call getProp in env1, and it should return the value 1 9372 { 9373 Local<v8::Object> global1 = env1->Global(); 9374 Local<Value> get_prop = 9375 global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked(); 9376 CHECK(get_prop->IsFunction()); 9377 v8::TryCatch try_catch(env1->GetIsolate()); 9378 Local<Value> r = Function::Cast(*get_prop) 9379 ->Call(env1.local(), global1, 0, NULL) 9380 .ToLocalChecked(); 9381 CHECK(!try_catch.HasCaught()); 9382 CHECK_EQ(1, r->Int32Value(env1.local()).FromJust()); 9383 } 9384 9385 // Check that env3 is not accessible from env1 9386 { 9387 v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2")); 9388 CHECK(r.IsEmpty()); 9389 } 9390 } 9391 9392 9393 TEST(DetachGlobal) { 9394 LocalContext env1; 9395 v8::HandleScope scope(env1->GetIsolate()); 9396 9397 // Create second environment. 9398 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9399 9400 Local<Value> foo = v8_str("foo"); 9401 9402 // Set same security token for env1 and env2. 9403 env1->SetSecurityToken(foo); 9404 env2->SetSecurityToken(foo); 9405 9406 // Create a property on the global object in env2. 9407 { 9408 v8::Context::Scope scope(env2); 9409 CHECK(env2->Global() 9410 ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42)) 9411 .FromJust()); 9412 } 9413 9414 // Create a reference to env2 global from env1 global. 9415 CHECK(env1->Global() 9416 ->Set(env1.local(), v8_str("other"), env2->Global()) 9417 .FromJust()); 9418 9419 // Check that we have access to other.p in env2 from env1. 9420 Local<Value> result = CompileRun("other.p"); 9421 CHECK(result->IsInt32()); 9422 CHECK_EQ(42, result->Int32Value(env1.local()).FromJust()); 9423 9424 // Hold on to global from env2 and detach global from env2. 9425 Local<v8::Object> global2 = env2->Global(); 9426 env2->DetachGlobal(); 9427 9428 // Check that the global has been detached. No other.p property can 9429 // be found. 9430 result = CompileRun("other.p"); 9431 CHECK(result.IsEmpty()); 9432 9433 // Reuse global2 for env3. 9434 v8::Local<Context> env3 = Context::New( 9435 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2); 9436 CHECK(global2->Equals(env1.local(), env3->Global()).FromJust()); 9437 9438 // Start by using the same security token for env3 as for env1 and env2. 9439 env3->SetSecurityToken(foo); 9440 9441 // Create a property on the global object in env3. 9442 { 9443 v8::Context::Scope scope(env3); 9444 CHECK(env3->Global() 9445 ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24)) 9446 .FromJust()); 9447 } 9448 9449 // Check that other.p is now the property in env3 and that we have access. 9450 result = CompileRun("other.p"); 9451 CHECK(result->IsInt32()); 9452 CHECK_EQ(24, result->Int32Value(env3).FromJust()); 9453 9454 // Change security token for env3 to something different from env1 and env2. 9455 env3->SetSecurityToken(v8_str("bar")); 9456 9457 // Check that we do not have access to other.p in env1. |other| is now 9458 // the global object for env3 which has a different security token, 9459 // so access should be blocked. 9460 result = CompileRun("other.p"); 9461 CHECK(result.IsEmpty()); 9462 } 9463 9464 9465 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) { 9466 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 9467 info.GetReturnValue().Set( 9468 context->Global()->Get(context, v8_str("x")).ToLocalChecked()); 9469 } 9470 9471 9472 TEST(DetachedAccesses) { 9473 LocalContext env1; 9474 v8::HandleScope scope(env1->GetIsolate()); 9475 9476 // Create second environment. 9477 Local<ObjectTemplate> inner_global_template = 9478 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate(); 9479 inner_global_template ->SetAccessorProperty( 9480 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX)); 9481 v8::Local<Context> env2 = 9482 Context::New(env1->GetIsolate(), NULL, inner_global_template); 9483 9484 Local<Value> foo = v8_str("foo"); 9485 9486 // Set same security token for env1 and env2. 9487 env1->SetSecurityToken(foo); 9488 env2->SetSecurityToken(foo); 9489 9490 CHECK(env1->Global() 9491 ->Set(env1.local(), v8_str("x"), v8_str("env1_x")) 9492 .FromJust()); 9493 9494 { 9495 v8::Context::Scope scope(env2); 9496 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust()); 9497 CompileRun( 9498 "function bound_x() { return x; }" 9499 "function get_x() { return this.x; }" 9500 "function get_x_w() { return (function() {return this.x;})(); }"); 9501 CHECK(env1->Global() 9502 ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x")) 9503 .FromJust()); 9504 CHECK(env1->Global() 9505 ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x")) 9506 .FromJust()); 9507 CHECK(env1->Global() 9508 ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w")) 9509 .FromJust()); 9510 env1->Global() 9511 ->Set(env1.local(), v8_str("this_x"), 9512 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get")) 9513 .FromJust(); 9514 } 9515 9516 Local<Object> env2_global = env2->Global(); 9517 env2->DetachGlobal(); 9518 9519 Local<Value> result; 9520 result = CompileRun("bound_x()"); 9521 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust()); 9522 result = CompileRun("get_x()"); 9523 CHECK(result.IsEmpty()); 9524 result = CompileRun("get_x_w()"); 9525 CHECK(result.IsEmpty()); 9526 result = CompileRun("this_x()"); 9527 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust()); 9528 9529 // Reattach env2's proxy 9530 env2 = Context::New(env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), 9531 env2_global); 9532 env2->SetSecurityToken(foo); 9533 { 9534 v8::Context::Scope scope(env2); 9535 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust()); 9536 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9537 result = CompileRun( 9538 "results = [];" 9539 "for (var i = 0; i < 4; i++ ) {" 9540 " results.push(env1.bound_x());" 9541 " results.push(env1.get_x());" 9542 " results.push(env1.get_x_w());" 9543 " results.push(env1.this_x());" 9544 "}" 9545 "results"); 9546 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9547 CHECK_EQ(16u, results->Length()); 9548 for (int i = 0; i < 16; i += 4) { 9549 CHECK(v8_str("env2_x") 9550 ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked()) 9551 .FromJust()); 9552 CHECK(v8_str("env1_x") 9553 ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked()) 9554 .FromJust()); 9555 CHECK(v8_str("env3_x") 9556 ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked()) 9557 .FromJust()); 9558 CHECK(v8_str("env2_x") 9559 ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked()) 9560 .FromJust()); 9561 } 9562 } 9563 9564 result = CompileRun( 9565 "results = [];" 9566 "for (var i = 0; i < 4; i++ ) {" 9567 " results.push(bound_x());" 9568 " results.push(get_x());" 9569 " results.push(get_x_w());" 9570 " results.push(this_x());" 9571 "}" 9572 "results"); 9573 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9574 CHECK_EQ(16u, results->Length()); 9575 for (int i = 0; i < 16; i += 4) { 9576 CHECK(v8_str("env2_x") 9577 ->Equals(env1.local(), 9578 results->Get(env1.local(), i + 0).ToLocalChecked()) 9579 .FromJust()); 9580 CHECK(v8_str("env3_x") 9581 ->Equals(env1.local(), 9582 results->Get(env1.local(), i + 1).ToLocalChecked()) 9583 .FromJust()); 9584 CHECK(v8_str("env3_x") 9585 ->Equals(env1.local(), 9586 results->Get(env1.local(), i + 2).ToLocalChecked()) 9587 .FromJust()); 9588 CHECK(v8_str("env2_x") 9589 ->Equals(env1.local(), 9590 results->Get(env1.local(), i + 3).ToLocalChecked()) 9591 .FromJust()); 9592 } 9593 9594 result = CompileRun( 9595 "results = [];" 9596 "for (var i = 0; i < 4; i++ ) {" 9597 " results.push(this.bound_x());" 9598 " results.push(this.get_x());" 9599 " results.push(this.get_x_w());" 9600 " results.push(this.this_x());" 9601 "}" 9602 "results"); 9603 results = Local<v8::Array>::Cast(result); 9604 CHECK_EQ(16u, results->Length()); 9605 for (int i = 0; i < 16; i += 4) { 9606 CHECK(v8_str("env2_x") 9607 ->Equals(env1.local(), 9608 results->Get(env1.local(), i + 0).ToLocalChecked()) 9609 .FromJust()); 9610 CHECK(v8_str("env1_x") 9611 ->Equals(env1.local(), 9612 results->Get(env1.local(), i + 1).ToLocalChecked()) 9613 .FromJust()); 9614 CHECK(v8_str("env3_x") 9615 ->Equals(env1.local(), 9616 results->Get(env1.local(), i + 2).ToLocalChecked()) 9617 .FromJust()); 9618 CHECK(v8_str("env2_x") 9619 ->Equals(env1.local(), 9620 results->Get(env1.local(), i + 3).ToLocalChecked()) 9621 .FromJust()); 9622 } 9623 } 9624 9625 9626 static bool allowed_access = false; 9627 static bool AccessBlocker(Local<v8::Context> accessing_context, 9628 Local<v8::Object> accessed_object) { 9629 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 9630 return context->Global()->Equals(context, accessed_object).FromJust() || 9631 allowed_access; 9632 } 9633 9634 9635 static int g_echo_value = -1; 9636 9637 9638 static void EchoGetter( 9639 Local<String> name, 9640 const v8::PropertyCallbackInfo<v8::Value>& info) { 9641 info.GetReturnValue().Set(v8_num(g_echo_value)); 9642 } 9643 9644 9645 static void EchoSetter(Local<String> name, Local<Value> value, 9646 const v8::PropertyCallbackInfo<void>& args) { 9647 if (value->IsNumber()) 9648 g_echo_value = 9649 value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust(); 9650 } 9651 9652 9653 static void UnreachableGetter( 9654 Local<String> name, 9655 const v8::PropertyCallbackInfo<v8::Value>& info) { 9656 CHECK(false); // This function should not be called.. 9657 } 9658 9659 9660 static void UnreachableSetter(Local<String>, 9661 Local<Value>, 9662 const v8::PropertyCallbackInfo<void>&) { 9663 CHECK(false); // This function should nto be called. 9664 } 9665 9666 9667 static void UnreachableFunction( 9668 const v8::FunctionCallbackInfo<v8::Value>& info) { 9669 CHECK(false); // This function should not be called.. 9670 } 9671 9672 9673 TEST(AccessControl) { 9674 v8::Isolate* isolate = CcTest::isolate(); 9675 v8::HandleScope handle_scope(isolate); 9676 v8::Local<v8::ObjectTemplate> global_template = 9677 v8::ObjectTemplate::New(isolate); 9678 9679 global_template->SetAccessCheckCallback(AccessBlocker); 9680 9681 // Add an accessor accessible by cross-domain JS code. 9682 global_template->SetAccessor( 9683 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 9684 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9685 9686 9687 // Add an accessor that is not accessible by cross-domain JS code. 9688 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter, 9689 UnreachableSetter, v8::Local<Value>(), 9690 v8::DEFAULT); 9691 9692 global_template->SetAccessorProperty( 9693 v8_str("blocked_js_prop"), 9694 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9695 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9696 v8::None, 9697 v8::DEFAULT); 9698 9699 // Create an environment 9700 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9701 context0->Enter(); 9702 9703 v8::Local<v8::Object> global0 = context0->Global(); 9704 9705 // Define a property with JS getter and setter. 9706 CompileRun( 9707 "function getter() { return 'getter'; };\n" 9708 "function setter() { return 'setter'; }\n" 9709 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 9710 9711 Local<Value> getter = 9712 global0->Get(context0, v8_str("getter")).ToLocalChecked(); 9713 Local<Value> setter = 9714 global0->Get(context0, v8_str("setter")).ToLocalChecked(); 9715 9716 // And define normal element. 9717 CHECK(global0->Set(context0, 239, v8_str("239")).FromJust()); 9718 9719 // Define an element with JS getter and setter. 9720 CompileRun( 9721 "function el_getter() { return 'el_getter'; };\n" 9722 "function el_setter() { return 'el_setter'; };\n" 9723 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 9724 9725 Local<Value> el_getter = 9726 global0->Get(context0, v8_str("el_getter")).ToLocalChecked(); 9727 Local<Value> el_setter = 9728 global0->Get(context0, v8_str("el_setter")).ToLocalChecked(); 9729 9730 v8::HandleScope scope1(isolate); 9731 9732 v8::Local<Context> context1 = Context::New(isolate); 9733 context1->Enter(); 9734 9735 v8::Local<v8::Object> global1 = context1->Global(); 9736 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 9737 9738 // Access blocked property. 9739 CompileRun("other.blocked_prop = 1"); 9740 9741 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9742 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 9743 .IsEmpty()); 9744 CHECK( 9745 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty()); 9746 9747 // Access blocked element. 9748 CHECK(CompileRun("other[239] = 1").IsEmpty()); 9749 9750 CHECK(CompileRun("other[239]").IsEmpty()); 9751 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty()); 9752 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty()); 9753 9754 allowed_access = true; 9755 // Now we can enumerate the property. 9756 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 9757 allowed_access = false; 9758 9759 // Access a property with JS accessor. 9760 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty()); 9761 9762 CHECK(CompileRun("other.js_accessor_p").IsEmpty()); 9763 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')") 9764 .IsEmpty()); 9765 9766 allowed_access = true; 9767 9768 ExpectString("other.js_accessor_p", "getter"); 9769 ExpectObject( 9770 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 9771 ExpectObject( 9772 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 9773 ExpectUndefined( 9774 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9775 9776 allowed_access = false; 9777 9778 // Access an element with JS accessor. 9779 CHECK(CompileRun("other[42] = 2").IsEmpty()); 9780 9781 CHECK(CompileRun("other[42]").IsEmpty()); 9782 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty()); 9783 9784 allowed_access = true; 9785 9786 ExpectString("other[42]", "el_getter"); 9787 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 9788 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 9789 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9790 9791 allowed_access = false; 9792 9793 v8::Local<Value> value; 9794 9795 // Access accessible property 9796 value = CompileRun("other.accessible_prop = 3"); 9797 CHECK(value->IsNumber()); 9798 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 9799 CHECK_EQ(3, g_echo_value); 9800 9801 value = CompileRun("other.accessible_prop"); 9802 CHECK(value->IsNumber()); 9803 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 9804 9805 value = CompileRun( 9806 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 9807 CHECK(value->IsNumber()); 9808 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 9809 9810 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 9811 CHECK(value->IsTrue()); 9812 9813 // Enumeration doesn't enumerate accessors from inaccessible objects in 9814 // the prototype chain even if the accessors are in themselves accessible. 9815 // Enumeration doesn't throw, it silently ignores what it can't access. 9816 value = CompileRun( 9817 "(function() {" 9818 " var obj = { '__proto__': other };" 9819 " try {" 9820 " for (var p in obj) {" 9821 " if (p == 'accessible_prop' ||" 9822 " p == 'blocked_js_prop' ||" 9823 " p == 'blocked_js_prop') {" 9824 " return false;" 9825 " }" 9826 " }" 9827 " return true;" 9828 " } catch (e) {" 9829 " return false;" 9830 " }" 9831 "})()"); 9832 CHECK(value->IsTrue()); 9833 9834 // Test that preventExtensions fails on a non-accessible object even if that 9835 // object is already non-extensible. 9836 CHECK(global1->Set(context1, v8_str("checked_object"), 9837 global_template->NewInstance(context1).ToLocalChecked()) 9838 .FromJust()); 9839 allowed_access = true; 9840 CompileRun("Object.preventExtensions(checked_object)"); 9841 ExpectFalse("Object.isExtensible(checked_object)"); 9842 allowed_access = false; 9843 CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty()); 9844 9845 context1->Exit(); 9846 context0->Exit(); 9847 } 9848 9849 9850 TEST(AccessControlES5) { 9851 v8::Isolate* isolate = CcTest::isolate(); 9852 v8::HandleScope handle_scope(isolate); 9853 v8::Local<v8::ObjectTemplate> global_template = 9854 v8::ObjectTemplate::New(isolate); 9855 9856 global_template->SetAccessCheckCallback(AccessBlocker); 9857 9858 // Add accessible accessor. 9859 global_template->SetAccessor( 9860 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 9861 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9862 9863 9864 // Add an accessor that is not accessible by cross-domain JS code. 9865 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter, 9866 UnreachableSetter, v8::Local<Value>(), 9867 v8::DEFAULT); 9868 9869 // Create an environment 9870 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9871 context0->Enter(); 9872 9873 v8::Local<v8::Object> global0 = context0->Global(); 9874 9875 v8::Local<Context> context1 = Context::New(isolate); 9876 context1->Enter(); 9877 v8::Local<v8::Object> global1 = context1->Global(); 9878 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 9879 9880 // Regression test for issue 1154. 9881 CHECK(CompileRun("Object.keys(other).length == 1") 9882 ->BooleanValue(context1) 9883 .FromJust()); 9884 CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'") 9885 ->BooleanValue(context1) 9886 .FromJust()); 9887 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9888 9889 // Regression test for issue 1027. 9890 CompileRun("Object.defineProperty(\n" 9891 " other, 'blocked_prop', {configurable: false})"); 9892 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9893 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 9894 .IsEmpty()); 9895 9896 // Regression test for issue 1171. 9897 ExpectTrue("Object.isExtensible(other)"); 9898 CompileRun("Object.preventExtensions(other)"); 9899 ExpectTrue("Object.isExtensible(other)"); 9900 9901 // Object.seal and Object.freeze. 9902 CompileRun("Object.freeze(other)"); 9903 ExpectTrue("Object.isExtensible(other)"); 9904 9905 CompileRun("Object.seal(other)"); 9906 ExpectTrue("Object.isExtensible(other)"); 9907 9908 // Regression test for issue 1250. 9909 // Make sure that we can set the accessible accessors value using normal 9910 // assignment. 9911 CompileRun("other.accessible_prop = 42"); 9912 CHECK_EQ(42, g_echo_value); 9913 9914 // [[DefineOwnProperty]] always throws for access-checked objects. 9915 CHECK( 9916 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})") 9917 .IsEmpty()); 9918 CHECK(CompileRun("other.accessible_prop == 42")->IsTrue()); 9919 CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter. 9920 } 9921 9922 9923 static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context, 9924 Local<v8::Object> global) { 9925 i::PrintF("Access blocked.\n"); 9926 return false; 9927 } 9928 9929 9930 THREADED_TEST(AccessControlGetOwnPropertyNames) { 9931 v8::Isolate* isolate = CcTest::isolate(); 9932 v8::HandleScope handle_scope(isolate); 9933 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 9934 9935 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 9936 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 9937 9938 // Add an accessor accessible by cross-domain JS code. 9939 obj_template->SetAccessor( 9940 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 9941 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9942 9943 // Create an environment 9944 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 9945 context0->Enter(); 9946 9947 v8::Local<v8::Object> global0 = context0->Global(); 9948 9949 v8::HandleScope scope1(CcTest::isolate()); 9950 9951 v8::Local<Context> context1 = Context::New(isolate); 9952 context1->Enter(); 9953 9954 v8::Local<v8::Object> global1 = context1->Global(); 9955 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 9956 CHECK(global1->Set(context1, v8_str("object"), 9957 obj_template->NewInstance(context1).ToLocalChecked()) 9958 .FromJust()); 9959 9960 v8::Local<Value> value; 9961 9962 // Attempt to get the property names of the other global object and 9963 // of an object that requires access checks. Accessing the other 9964 // global object should be blocked by access checks on the global 9965 // proxy object. Accessing the object that requires access checks 9966 // is blocked by the access checks on the object itself. 9967 value = CompileRun( 9968 "var names = Object.getOwnPropertyNames(other);" 9969 "names.length == 1 && names[0] == 'accessible_prop';"); 9970 CHECK(value->BooleanValue(context1).FromJust()); 9971 9972 value = CompileRun( 9973 "var names = Object.getOwnPropertyNames(object);" 9974 "names.length == 1 && names[0] == 'accessible_prop';"); 9975 CHECK(value->BooleanValue(context1).FromJust()); 9976 9977 context1->Exit(); 9978 context0->Exit(); 9979 } 9980 9981 9982 TEST(Regress470113) { 9983 v8::Isolate* isolate = CcTest::isolate(); 9984 v8::HandleScope handle_scope(isolate); 9985 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 9986 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 9987 LocalContext env; 9988 CHECK(env->Global() 9989 ->Set(env.local(), v8_str("prohibited"), 9990 obj_template->NewInstance(env.local()).ToLocalChecked()) 9991 .FromJust()); 9992 9993 { 9994 v8::TryCatch try_catch(isolate); 9995 CompileRun( 9996 "'use strict';\n" 9997 "class C extends Object {\n" 9998 " m() { super.powned = 'Powned!'; }\n" 9999 "}\n" 10000 "let c = new C();\n" 10001 "c.m.call(prohibited)"); 10002 10003 CHECK(try_catch.HasCaught()); 10004 } 10005 } 10006 10007 10008 static void ConstTenGetter(Local<String> name, 10009 const v8::PropertyCallbackInfo<v8::Value>& info) { 10010 info.GetReturnValue().Set(v8_num(10)); 10011 } 10012 10013 10014 THREADED_TEST(CrossDomainAccessors) { 10015 v8::Isolate* isolate = CcTest::isolate(); 10016 v8::HandleScope handle_scope(isolate); 10017 10018 v8::Local<v8::FunctionTemplate> func_template = 10019 v8::FunctionTemplate::New(isolate); 10020 10021 v8::Local<v8::ObjectTemplate> global_template = 10022 func_template->InstanceTemplate(); 10023 10024 v8::Local<v8::ObjectTemplate> proto_template = 10025 func_template->PrototypeTemplate(); 10026 10027 // Add an accessor to proto that's accessible by cross-domain JS code. 10028 proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, 0, 10029 v8::Local<Value>(), v8::ALL_CAN_READ); 10030 10031 // Add an accessor that is not accessible by cross-domain JS code. 10032 global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter, 0, 10033 v8::Local<Value>(), v8::DEFAULT); 10034 10035 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 10036 context0->Enter(); 10037 10038 Local<v8::Object> global = context0->Global(); 10039 // Add a normal property that shadows 'accessible' 10040 CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust()); 10041 10042 // Enter a new context. 10043 v8::HandleScope scope1(CcTest::isolate()); 10044 v8::Local<Context> context1 = Context::New(isolate); 10045 context1->Enter(); 10046 10047 v8::Local<v8::Object> global1 = context1->Global(); 10048 CHECK(global1->Set(context1, v8_str("other"), global).FromJust()); 10049 10050 // Should return 10, instead of 11 10051 v8::Local<Value> value = 10052 v8_compile("other.accessible")->Run(context1).ToLocalChecked(); 10053 CHECK(value->IsNumber()); 10054 CHECK_EQ(10, value->Int32Value(context1).FromJust()); 10055 10056 v8::MaybeLocal<v8::Value> maybe_value = 10057 v8_compile("other.unreachable")->Run(context1); 10058 CHECK(maybe_value.IsEmpty()); 10059 10060 context1->Exit(); 10061 context0->Exit(); 10062 } 10063 10064 10065 static int access_count = 0; 10066 10067 static bool AccessCounter(Local<v8::Context> accessing_context, 10068 Local<v8::Object> accessed_object) { 10069 access_count++; 10070 return true; 10071 } 10072 10073 10074 // This one is too easily disturbed by other tests. 10075 TEST(AccessControlIC) { 10076 access_count = 0; 10077 10078 v8::Isolate* isolate = CcTest::isolate(); 10079 v8::HandleScope handle_scope(isolate); 10080 10081 // Create an environment. 10082 v8::Local<Context> context0 = Context::New(isolate); 10083 context0->Enter(); 10084 10085 // Create an object that requires access-check functions to be 10086 // called for cross-domain access. 10087 v8::Local<v8::ObjectTemplate> object_template = 10088 v8::ObjectTemplate::New(isolate); 10089 object_template->SetAccessCheckCallback(AccessCounter); 10090 Local<v8::Object> object = 10091 object_template->NewInstance(context0).ToLocalChecked(); 10092 10093 v8::HandleScope scope1(isolate); 10094 10095 // Create another environment. 10096 v8::Local<Context> context1 = Context::New(isolate); 10097 context1->Enter(); 10098 10099 // Make easy access to the object from the other environment. 10100 v8::Local<v8::Object> global1 = context1->Global(); 10101 CHECK(global1->Set(context1, v8_str("obj"), object).FromJust()); 10102 10103 v8::Local<Value> value; 10104 10105 // Check that the named access-control function is called every time. 10106 CompileRun("function testProp(obj) {" 10107 " for (var i = 0; i < 10; i++) obj.prop = 1;" 10108 " for (var j = 0; j < 10; j++) obj.prop;" 10109 " return obj.prop" 10110 "}"); 10111 value = CompileRun("testProp(obj)"); 10112 CHECK(value->IsNumber()); 10113 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10114 CHECK_EQ(21, access_count); 10115 10116 // Check that the named access-control function is called every time. 10117 CompileRun("var p = 'prop';" 10118 "function testKeyed(obj) {" 10119 " for (var i = 0; i < 10; i++) obj[p] = 1;" 10120 " for (var j = 0; j < 10; j++) obj[p];" 10121 " return obj[p];" 10122 "}"); 10123 // Use obj which requires access checks. No inline caching is used 10124 // in that case. 10125 value = CompileRun("testKeyed(obj)"); 10126 CHECK(value->IsNumber()); 10127 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10128 CHECK_EQ(42, access_count); 10129 // Force the inline caches into generic state and try again. 10130 CompileRun("testKeyed({ a: 0 })"); 10131 CompileRun("testKeyed({ b: 0 })"); 10132 value = CompileRun("testKeyed(obj)"); 10133 CHECK(value->IsNumber()); 10134 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10135 CHECK_EQ(63, access_count); 10136 10137 // Check that the indexed access-control function is called every time. 10138 access_count = 0; 10139 10140 CompileRun("function testIndexed(obj) {" 10141 " for (var i = 0; i < 10; i++) obj[0] = 1;" 10142 " for (var j = 0; j < 10; j++) obj[0];" 10143 " return obj[0]" 10144 "}"); 10145 value = CompileRun("testIndexed(obj)"); 10146 CHECK(value->IsNumber()); 10147 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10148 CHECK_EQ(21, access_count); 10149 // Force the inline caches into generic state. 10150 CompileRun("testIndexed(new Array(1))"); 10151 // Test that the indexed access check is called. 10152 value = CompileRun("testIndexed(obj)"); 10153 CHECK(value->IsNumber()); 10154 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10155 CHECK_EQ(42, access_count); 10156 10157 access_count = 0; 10158 // Check that the named access check is called when invoking 10159 // functions on an object that requires access checks. 10160 CompileRun("obj.f = function() {}"); 10161 CompileRun("function testCallNormal(obj) {" 10162 " for (var i = 0; i < 10; i++) obj.f();" 10163 "}"); 10164 CompileRun("testCallNormal(obj)"); 10165 printf("%i\n", access_count); 10166 CHECK_EQ(11, access_count); 10167 10168 // Force obj into slow case. 10169 value = CompileRun("delete obj.prop"); 10170 CHECK(value->BooleanValue(context1).FromJust()); 10171 // Force inline caches into dictionary probing mode. 10172 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 10173 // Test that the named access check is called. 10174 value = CompileRun("testProp(obj);"); 10175 CHECK(value->IsNumber()); 10176 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10177 CHECK_EQ(33, access_count); 10178 10179 // Force the call inline cache into dictionary probing mode. 10180 CompileRun("o.f = function() {}; testCallNormal(o)"); 10181 // Test that the named access check is still called for each 10182 // invocation of the function. 10183 value = CompileRun("testCallNormal(obj)"); 10184 CHECK_EQ(43, access_count); 10185 10186 context1->Exit(); 10187 context0->Exit(); 10188 } 10189 10190 10191 THREADED_TEST(Version) { v8::V8::GetVersion(); } 10192 10193 10194 static void InstanceFunctionCallback( 10195 const v8::FunctionCallbackInfo<v8::Value>& args) { 10196 ApiTestFuzzer::Fuzz(); 10197 args.GetReturnValue().Set(v8_num(12)); 10198 } 10199 10200 10201 THREADED_TEST(InstanceProperties) { 10202 LocalContext context; 10203 v8::Isolate* isolate = context->GetIsolate(); 10204 v8::HandleScope handle_scope(isolate); 10205 10206 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10207 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10208 10209 instance->Set(v8_str("x"), v8_num(42)); 10210 instance->Set(v8_str("f"), 10211 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback)); 10212 10213 Local<Value> o = t->GetFunction(context.local()) 10214 .ToLocalChecked() 10215 ->NewInstance(context.local()) 10216 .ToLocalChecked(); 10217 10218 CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust()); 10219 Local<Value> value = CompileRun("i.x"); 10220 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10221 10222 value = CompileRun("i.f()"); 10223 CHECK_EQ(12, value->Int32Value(context.local()).FromJust()); 10224 } 10225 10226 10227 static void GlobalObjectInstancePropertiesGet( 10228 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) { 10229 ApiTestFuzzer::Fuzz(); 10230 } 10231 10232 10233 THREADED_TEST(GlobalObjectInstanceProperties) { 10234 v8::Isolate* isolate = CcTest::isolate(); 10235 v8::HandleScope handle_scope(isolate); 10236 10237 Local<Value> global_object; 10238 10239 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10240 t->InstanceTemplate()->SetHandler( 10241 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet)); 10242 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10243 instance_template->Set(v8_str("x"), v8_num(42)); 10244 instance_template->Set(v8_str("f"), 10245 v8::FunctionTemplate::New(isolate, 10246 InstanceFunctionCallback)); 10247 10248 // The script to check how Crankshaft compiles missing global function 10249 // invocations. function g is not defined and should throw on call. 10250 const char* script = 10251 "function wrapper(call) {" 10252 " var x = 0, y = 1;" 10253 " for (var i = 0; i < 1000; i++) {" 10254 " x += i * 100;" 10255 " y += i * 100;" 10256 " }" 10257 " if (call) g();" 10258 "}" 10259 "for (var i = 0; i < 17; i++) wrapper(false);" 10260 "var thrown = 0;" 10261 "try { wrapper(true); } catch (e) { thrown = 1; };" 10262 "thrown"; 10263 10264 { 10265 LocalContext env(NULL, instance_template); 10266 // Hold on to the global object so it can be used again in another 10267 // environment initialization. 10268 global_object = env->Global(); 10269 10270 Local<Value> value = CompileRun("x"); 10271 CHECK_EQ(42, value->Int32Value(env.local()).FromJust()); 10272 value = CompileRun("f()"); 10273 CHECK_EQ(12, value->Int32Value(env.local()).FromJust()); 10274 value = CompileRun(script); 10275 CHECK_EQ(1, value->Int32Value(env.local()).FromJust()); 10276 } 10277 10278 { 10279 // Create new environment reusing the global object. 10280 LocalContext env(NULL, instance_template, global_object); 10281 Local<Value> value = CompileRun("x"); 10282 CHECK_EQ(42, value->Int32Value(env.local()).FromJust()); 10283 value = CompileRun("f()"); 10284 CHECK_EQ(12, value->Int32Value(env.local()).FromJust()); 10285 value = CompileRun(script); 10286 CHECK_EQ(1, value->Int32Value(env.local()).FromJust()); 10287 } 10288 } 10289 10290 10291 THREADED_TEST(CallKnownGlobalReceiver) { 10292 v8::Isolate* isolate = CcTest::isolate(); 10293 v8::HandleScope handle_scope(isolate); 10294 10295 Local<Value> global_object; 10296 10297 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10298 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10299 10300 // The script to check that we leave global object not 10301 // global object proxy on stack when we deoptimize from inside 10302 // arguments evaluation. 10303 // To provoke error we need to both force deoptimization 10304 // from arguments evaluation and to force CallIC to take 10305 // CallIC_Miss code path that can't cope with global proxy. 10306 const char* script = 10307 "function bar(x, y) { try { } finally { } }" 10308 "function baz(x) { try { } finally { } }" 10309 "function bom(x) { try { } finally { } }" 10310 "function foo(x) { bar([x], bom(2)); }" 10311 "for (var i = 0; i < 10000; i++) foo(1);" 10312 "foo"; 10313 10314 Local<Value> foo; 10315 { 10316 LocalContext env(NULL, instance_template); 10317 // Hold on to the global object so it can be used again in another 10318 // environment initialization. 10319 global_object = env->Global(); 10320 foo = CompileRun(script); 10321 } 10322 10323 { 10324 // Create new environment reusing the global object. 10325 LocalContext env(NULL, instance_template, global_object); 10326 CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust()); 10327 CompileRun("foo()"); 10328 } 10329 } 10330 10331 10332 static void ShadowFunctionCallback( 10333 const v8::FunctionCallbackInfo<v8::Value>& args) { 10334 ApiTestFuzzer::Fuzz(); 10335 args.GetReturnValue().Set(v8_num(42)); 10336 } 10337 10338 10339 static int shadow_y; 10340 static int shadow_y_setter_call_count; 10341 static int shadow_y_getter_call_count; 10342 10343 10344 static void ShadowYSetter(Local<String>, 10345 Local<Value>, 10346 const v8::PropertyCallbackInfo<void>&) { 10347 shadow_y_setter_call_count++; 10348 shadow_y = 42; 10349 } 10350 10351 10352 static void ShadowYGetter(Local<String> name, 10353 const v8::PropertyCallbackInfo<v8::Value>& info) { 10354 ApiTestFuzzer::Fuzz(); 10355 shadow_y_getter_call_count++; 10356 info.GetReturnValue().Set(v8_num(shadow_y)); 10357 } 10358 10359 10360 static void ShadowIndexedGet(uint32_t index, 10361 const v8::PropertyCallbackInfo<v8::Value>&) { 10362 } 10363 10364 10365 static void ShadowNamedGet(Local<Name> key, 10366 const v8::PropertyCallbackInfo<v8::Value>&) {} 10367 10368 10369 THREADED_TEST(ShadowObject) { 10370 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 10371 v8::Isolate* isolate = CcTest::isolate(); 10372 v8::HandleScope handle_scope(isolate); 10373 10374 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 10375 LocalContext context(NULL, global_template); 10376 10377 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10378 t->InstanceTemplate()->SetHandler( 10379 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet)); 10380 t->InstanceTemplate()->SetHandler( 10381 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet)); 10382 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 10383 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10384 10385 proto->Set(v8_str("f"), 10386 v8::FunctionTemplate::New(isolate, 10387 ShadowFunctionCallback, 10388 Local<Value>())); 10389 proto->Set(v8_str("x"), v8_num(12)); 10390 10391 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 10392 10393 Local<Value> o = t->GetFunction(context.local()) 10394 .ToLocalChecked() 10395 ->NewInstance(context.local()) 10396 .ToLocalChecked(); 10397 CHECK(context->Global() 10398 ->Set(context.local(), v8_str("__proto__"), o) 10399 .FromJust()); 10400 10401 Local<Value> value = 10402 CompileRun("this.propertyIsEnumerable(0)"); 10403 CHECK(value->IsBoolean()); 10404 CHECK(!value->BooleanValue(context.local()).FromJust()); 10405 10406 value = CompileRun("x"); 10407 CHECK_EQ(12, value->Int32Value(context.local()).FromJust()); 10408 10409 value = CompileRun("f()"); 10410 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10411 10412 CompileRun("y = 43"); 10413 CHECK_EQ(1, shadow_y_setter_call_count); 10414 value = CompileRun("y"); 10415 CHECK_EQ(1, shadow_y_getter_call_count); 10416 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10417 } 10418 10419 10420 THREADED_TEST(HiddenPrototype) { 10421 LocalContext context; 10422 v8::Isolate* isolate = context->GetIsolate(); 10423 v8::HandleScope handle_scope(isolate); 10424 10425 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10426 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10427 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10428 t1->SetHiddenPrototype(true); 10429 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10430 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10431 t2->SetHiddenPrototype(true); 10432 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10433 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10434 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10435 10436 Local<v8::Object> o0 = t0->GetFunction(context.local()) 10437 .ToLocalChecked() 10438 ->NewInstance(context.local()) 10439 .ToLocalChecked(); 10440 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10441 .ToLocalChecked() 10442 ->NewInstance(context.local()) 10443 .ToLocalChecked(); 10444 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10445 .ToLocalChecked() 10446 ->NewInstance(context.local()) 10447 .ToLocalChecked(); 10448 Local<v8::Object> o3 = t3->GetFunction(context.local()) 10449 .ToLocalChecked() 10450 ->NewInstance(context.local()) 10451 .ToLocalChecked(); 10452 10453 // Setting the prototype on an object skips hidden prototypes. 10454 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10455 .ToLocalChecked() 10456 ->Int32Value(context.local()) 10457 .FromJust()); 10458 CHECK(o0->Set(context.local(), v8_str("__proto__"), o1).FromJust()); 10459 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10460 .ToLocalChecked() 10461 ->Int32Value(context.local()) 10462 .FromJust()); 10463 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10464 .ToLocalChecked() 10465 ->Int32Value(context.local()) 10466 .FromJust()); 10467 CHECK(o0->Set(context.local(), v8_str("__proto__"), o2).FromJust()); 10468 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10469 .ToLocalChecked() 10470 ->Int32Value(context.local()) 10471 .FromJust()); 10472 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10473 .ToLocalChecked() 10474 ->Int32Value(context.local()) 10475 .FromJust()); 10476 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10477 .ToLocalChecked() 10478 ->Int32Value(context.local()) 10479 .FromJust()); 10480 CHECK(o0->Set(context.local(), v8_str("__proto__"), o3).FromJust()); 10481 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10482 .ToLocalChecked() 10483 ->Int32Value(context.local()) 10484 .FromJust()); 10485 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10486 .ToLocalChecked() 10487 ->Int32Value(context.local()) 10488 .FromJust()); 10489 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10490 .ToLocalChecked() 10491 ->Int32Value(context.local()) 10492 .FromJust()); 10493 CHECK_EQ(3, o0->Get(context.local(), v8_str("u")) 10494 .ToLocalChecked() 10495 ->Int32Value(context.local()) 10496 .FromJust()); 10497 10498 // Getting the prototype of o0 should get the first visible one 10499 // which is o3. Therefore, z should not be defined on the prototype 10500 // object. 10501 Local<Value> proto = 10502 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked(); 10503 CHECK(proto->IsObject()); 10504 CHECK(proto.As<v8::Object>() 10505 ->Get(context.local(), v8_str("z")) 10506 .ToLocalChecked() 10507 ->IsUndefined()); 10508 } 10509 10510 10511 THREADED_TEST(HiddenPrototypeSet) { 10512 LocalContext context; 10513 v8::Isolate* isolate = context->GetIsolate(); 10514 v8::HandleScope handle_scope(isolate); 10515 10516 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate); 10517 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate); 10518 ht->SetHiddenPrototype(true); 10519 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate); 10520 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10521 10522 Local<v8::Object> o = ot->GetFunction(context.local()) 10523 .ToLocalChecked() 10524 ->NewInstance(context.local()) 10525 .ToLocalChecked(); 10526 Local<v8::Object> h = ht->GetFunction(context.local()) 10527 .ToLocalChecked() 10528 ->NewInstance(context.local()) 10529 .ToLocalChecked(); 10530 Local<v8::Object> p = pt->GetFunction(context.local()) 10531 .ToLocalChecked() 10532 ->NewInstance(context.local()) 10533 .ToLocalChecked(); 10534 CHECK(o->Set(context.local(), v8_str("__proto__"), h).FromJust()); 10535 CHECK(h->Set(context.local(), v8_str("__proto__"), p).FromJust()); 10536 10537 // Setting a property that exists on the hidden prototype goes there. 10538 CHECK(o->Set(context.local(), v8_str("x"), v8_num(7)).FromJust()); 10539 CHECK_EQ(7, o->Get(context.local(), v8_str("x")) 10540 .ToLocalChecked() 10541 ->Int32Value(context.local()) 10542 .FromJust()); 10543 CHECK_EQ(7, h->Get(context.local(), v8_str("x")) 10544 .ToLocalChecked() 10545 ->Int32Value(context.local()) 10546 .FromJust()); 10547 CHECK(p->Get(context.local(), v8_str("x")).ToLocalChecked()->IsUndefined()); 10548 10549 // Setting a new property should not be forwarded to the hidden prototype. 10550 CHECK(o->Set(context.local(), v8_str("y"), v8_num(6)).FromJust()); 10551 CHECK_EQ(6, o->Get(context.local(), v8_str("y")) 10552 .ToLocalChecked() 10553 ->Int32Value(context.local()) 10554 .FromJust()); 10555 CHECK(h->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined()); 10556 CHECK(p->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined()); 10557 10558 // Setting a property that only exists on a prototype of the hidden prototype 10559 // is treated normally again. 10560 CHECK(p->Set(context.local(), v8_str("z"), v8_num(8)).FromJust()); 10561 CHECK_EQ(8, o->Get(context.local(), v8_str("z")) 10562 .ToLocalChecked() 10563 ->Int32Value(context.local()) 10564 .FromJust()); 10565 CHECK_EQ(8, h->Get(context.local(), v8_str("z")) 10566 .ToLocalChecked() 10567 ->Int32Value(context.local()) 10568 .FromJust()); 10569 CHECK_EQ(8, p->Get(context.local(), v8_str("z")) 10570 .ToLocalChecked() 10571 ->Int32Value(context.local()) 10572 .FromJust()); 10573 CHECK(o->Set(context.local(), v8_str("z"), v8_num(9)).FromJust()); 10574 CHECK_EQ(9, o->Get(context.local(), v8_str("z")) 10575 .ToLocalChecked() 10576 ->Int32Value(context.local()) 10577 .FromJust()); 10578 CHECK_EQ(8, h->Get(context.local(), v8_str("z")) 10579 .ToLocalChecked() 10580 ->Int32Value(context.local()) 10581 .FromJust()); 10582 CHECK_EQ(8, p->Get(context.local(), v8_str("z")) 10583 .ToLocalChecked() 10584 ->Int32Value(context.local()) 10585 .FromJust()); 10586 } 10587 10588 10589 // Regression test for issue 2457. 10590 THREADED_TEST(HiddenPrototypeIdentityHash) { 10591 LocalContext context; 10592 v8::HandleScope handle_scope(context->GetIsolate()); 10593 10594 Local<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate()); 10595 t->SetHiddenPrototype(true); 10596 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 10597 Local<Object> p = t->GetFunction(context.local()) 10598 .ToLocalChecked() 10599 ->NewInstance(context.local()) 10600 .ToLocalChecked(); 10601 Local<Object> o = Object::New(context->GetIsolate()); 10602 CHECK(o->SetPrototype(context.local(), p).FromJust()); 10603 10604 int hash = o->GetIdentityHash(); 10605 USE(hash); 10606 CHECK(o->Set(context.local(), v8_str("foo"), v8_num(42)).FromJust()); 10607 CHECK_EQ(hash, o->GetIdentityHash()); 10608 } 10609 10610 10611 THREADED_TEST(SetPrototype) { 10612 LocalContext context; 10613 v8::Isolate* isolate = context->GetIsolate(); 10614 v8::HandleScope handle_scope(isolate); 10615 10616 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10617 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10618 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10619 t1->SetHiddenPrototype(true); 10620 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10621 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10622 t2->SetHiddenPrototype(true); 10623 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10624 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10625 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10626 10627 Local<v8::Object> o0 = t0->GetFunction(context.local()) 10628 .ToLocalChecked() 10629 ->NewInstance(context.local()) 10630 .ToLocalChecked(); 10631 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10632 .ToLocalChecked() 10633 ->NewInstance(context.local()) 10634 .ToLocalChecked(); 10635 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10636 .ToLocalChecked() 10637 ->NewInstance(context.local()) 10638 .ToLocalChecked(); 10639 Local<v8::Object> o3 = t3->GetFunction(context.local()) 10640 .ToLocalChecked() 10641 ->NewInstance(context.local()) 10642 .ToLocalChecked(); 10643 10644 // Setting the prototype on an object does not skip hidden prototypes. 10645 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10646 .ToLocalChecked() 10647 ->Int32Value(context.local()) 10648 .FromJust()); 10649 CHECK(o0->SetPrototype(context.local(), o1).FromJust()); 10650 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10651 .ToLocalChecked() 10652 ->Int32Value(context.local()) 10653 .FromJust()); 10654 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10655 .ToLocalChecked() 10656 ->Int32Value(context.local()) 10657 .FromJust()); 10658 CHECK(o1->SetPrototype(context.local(), o2).FromJust()); 10659 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10660 .ToLocalChecked() 10661 ->Int32Value(context.local()) 10662 .FromJust()); 10663 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10664 .ToLocalChecked() 10665 ->Int32Value(context.local()) 10666 .FromJust()); 10667 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10668 .ToLocalChecked() 10669 ->Int32Value(context.local()) 10670 .FromJust()); 10671 CHECK(o2->SetPrototype(context.local(), o3).FromJust()); 10672 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10673 .ToLocalChecked() 10674 ->Int32Value(context.local()) 10675 .FromJust()); 10676 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10677 .ToLocalChecked() 10678 ->Int32Value(context.local()) 10679 .FromJust()); 10680 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10681 .ToLocalChecked() 10682 ->Int32Value(context.local()) 10683 .FromJust()); 10684 CHECK_EQ(3, o0->Get(context.local(), v8_str("u")) 10685 .ToLocalChecked() 10686 ->Int32Value(context.local()) 10687 .FromJust()); 10688 10689 // Getting the prototype of o0 should get the first visible one 10690 // which is o3. Therefore, z should not be defined on the prototype 10691 // object. 10692 Local<Value> proto = 10693 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked(); 10694 CHECK(proto->IsObject()); 10695 CHECK(proto.As<v8::Object>()->Equals(context.local(), o3).FromJust()); 10696 10697 // However, Object::GetPrototype ignores hidden prototype. 10698 Local<Value> proto0 = o0->GetPrototype(); 10699 CHECK(proto0->IsObject()); 10700 CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust()); 10701 10702 Local<Value> proto1 = o1->GetPrototype(); 10703 CHECK(proto1->IsObject()); 10704 CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust()); 10705 10706 Local<Value> proto2 = o2->GetPrototype(); 10707 CHECK(proto2->IsObject()); 10708 CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust()); 10709 } 10710 10711 10712 // Getting property names of an object with a prototype chain that 10713 // triggers dictionary elements in GetOwnPropertyNames() shouldn't 10714 // crash the runtime. 10715 THREADED_TEST(Regress91517) { 10716 i::FLAG_allow_natives_syntax = true; 10717 LocalContext context; 10718 v8::Isolate* isolate = context->GetIsolate(); 10719 v8::HandleScope handle_scope(isolate); 10720 10721 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10722 t1->SetHiddenPrototype(true); 10723 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 10724 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10725 t2->SetHiddenPrototype(true); 10726 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 10727 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate)); 10728 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 10729 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10730 t3->SetHiddenPrototype(true); 10731 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 10732 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate); 10733 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 10734 10735 // Force dictionary-based properties. 10736 i::ScopedVector<char> name_buf(1024); 10737 for (int i = 1; i <= 1000; i++) { 10738 i::SNPrintF(name_buf, "sdf%d", i); 10739 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 10740 } 10741 10742 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10743 .ToLocalChecked() 10744 ->NewInstance(context.local()) 10745 .ToLocalChecked(); 10746 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10747 .ToLocalChecked() 10748 ->NewInstance(context.local()) 10749 .ToLocalChecked(); 10750 Local<v8::Object> o3 = t3->GetFunction(context.local()) 10751 .ToLocalChecked() 10752 ->NewInstance(context.local()) 10753 .ToLocalChecked(); 10754 Local<v8::Object> o4 = t4->GetFunction(context.local()) 10755 .ToLocalChecked() 10756 ->NewInstance(context.local()) 10757 .ToLocalChecked(); 10758 10759 // Create prototype chain of hidden prototypes. 10760 CHECK(o4->SetPrototype(context.local(), o3).FromJust()); 10761 CHECK(o3->SetPrototype(context.local(), o2).FromJust()); 10762 CHECK(o2->SetPrototype(context.local(), o1).FromJust()); 10763 10764 // Call the runtime version of GetOwnPropertyNames() on the natively 10765 // created object through JavaScript. 10766 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust()); 10767 // PROPERTY_FILTER_NONE = 0 10768 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);"); 10769 10770 ExpectInt32("names.length", 1006); 10771 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10772 ExpectTrue("names.indexOf(\"boo\") >= 0"); 10773 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10774 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 10775 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 10776 ExpectFalse("names[1005] == undefined"); 10777 } 10778 10779 10780 // Getting property names of an object with a hidden and inherited 10781 // prototype should not duplicate the accessor properties inherited. 10782 THREADED_TEST(Regress269562) { 10783 i::FLAG_allow_natives_syntax = true; 10784 LocalContext context; 10785 v8::HandleScope handle_scope(context->GetIsolate()); 10786 10787 Local<v8::FunctionTemplate> t1 = 10788 v8::FunctionTemplate::New(context->GetIsolate()); 10789 t1->SetHiddenPrototype(true); 10790 10791 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate(); 10792 i1->SetAccessor(v8_str("foo"), 10793 SimpleAccessorGetter, SimpleAccessorSetter); 10794 i1->SetAccessor(v8_str("bar"), 10795 SimpleAccessorGetter, SimpleAccessorSetter); 10796 i1->SetAccessor(v8_str("baz"), 10797 SimpleAccessorGetter, SimpleAccessorSetter); 10798 i1->Set(v8_str("n1"), v8_num(1)); 10799 i1->Set(v8_str("n2"), v8_num(2)); 10800 10801 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10802 .ToLocalChecked() 10803 ->NewInstance(context.local()) 10804 .ToLocalChecked(); 10805 Local<v8::FunctionTemplate> t2 = 10806 v8::FunctionTemplate::New(context->GetIsolate()); 10807 t2->SetHiddenPrototype(true); 10808 10809 // Inherit from t1 and mark prototype as hidden. 10810 t2->Inherit(t1); 10811 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4)); 10812 10813 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10814 .ToLocalChecked() 10815 ->NewInstance(context.local()) 10816 .ToLocalChecked(); 10817 CHECK(o2->SetPrototype(context.local(), o1).FromJust()); 10818 10819 v8::Local<v8::Symbol> sym = 10820 v8::Symbol::New(context->GetIsolate(), v8_str("s1")); 10821 CHECK(o1->Set(context.local(), sym, v8_num(3)).FromJust()); 10822 o1->SetPrivate(context.local(), 10823 v8::Private::New(context->GetIsolate(), v8_str("h1")), 10824 v8::Integer::New(context->GetIsolate(), 2013)) 10825 .FromJust(); 10826 10827 // Call the runtime version of GetOwnPropertyNames() on 10828 // the natively created object through JavaScript. 10829 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o2).FromJust()); 10830 CHECK(context->Global()->Set(context.local(), v8_str("sym"), sym).FromJust()); 10831 // PROPERTY_FILTER_NONE = 0 10832 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);"); 10833 10834 ExpectInt32("names.length", 7); 10835 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10836 ExpectTrue("names.indexOf(\"bar\") >= 0"); 10837 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10838 ExpectTrue("names.indexOf(\"n1\") >= 0"); 10839 ExpectTrue("names.indexOf(\"n2\") >= 0"); 10840 ExpectTrue("names.indexOf(sym) >= 0"); 10841 ExpectTrue("names.indexOf(\"mine\") >= 0"); 10842 } 10843 10844 10845 THREADED_TEST(FunctionReadOnlyPrototype) { 10846 LocalContext context; 10847 v8::Isolate* isolate = context->GetIsolate(); 10848 v8::HandleScope handle_scope(isolate); 10849 10850 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10851 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10852 t1->ReadOnlyPrototype(); 10853 CHECK(context->Global() 10854 ->Set(context.local(), v8_str("func1"), 10855 t1->GetFunction(context.local()).ToLocalChecked()) 10856 .FromJust()); 10857 // Configured value of ReadOnly flag. 10858 CHECK( 10859 CompileRun( 10860 "(function() {" 10861 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 10862 " return (descriptor['writable'] == false);" 10863 "})()") 10864 ->BooleanValue(context.local()) 10865 .FromJust()); 10866 CHECK_EQ( 10867 42, 10868 CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust()); 10869 CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x") 10870 ->Int32Value(context.local()) 10871 .FromJust()); 10872 10873 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10874 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10875 CHECK(context->Global() 10876 ->Set(context.local(), v8_str("func2"), 10877 t2->GetFunction(context.local()).ToLocalChecked()) 10878 .FromJust()); 10879 // Default value of ReadOnly flag. 10880 CHECK( 10881 CompileRun( 10882 "(function() {" 10883 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 10884 " return (descriptor['writable'] == true);" 10885 "})()") 10886 ->BooleanValue(context.local()) 10887 .FromJust()); 10888 CHECK_EQ( 10889 42, 10890 CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust()); 10891 } 10892 10893 10894 THREADED_TEST(SetPrototypeThrows) { 10895 LocalContext context; 10896 v8::Isolate* isolate = context->GetIsolate(); 10897 v8::HandleScope handle_scope(isolate); 10898 10899 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10900 10901 Local<v8::Object> o0 = t->GetFunction(context.local()) 10902 .ToLocalChecked() 10903 ->NewInstance(context.local()) 10904 .ToLocalChecked(); 10905 Local<v8::Object> o1 = t->GetFunction(context.local()) 10906 .ToLocalChecked() 10907 ->NewInstance(context.local()) 10908 .ToLocalChecked(); 10909 10910 CHECK(o0->SetPrototype(context.local(), o1).FromJust()); 10911 // If setting the prototype leads to the cycle, SetPrototype should 10912 // return false and keep VM in sane state. 10913 v8::TryCatch try_catch(isolate); 10914 CHECK(o1->SetPrototype(context.local(), o0).IsNothing()); 10915 CHECK(!try_catch.HasCaught()); 10916 CHECK(!CcTest::i_isolate()->has_pending_exception()); 10917 10918 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()") 10919 ->Int32Value(context.local()) 10920 .FromJust()); 10921 } 10922 10923 10924 THREADED_TEST(FunctionRemovePrototype) { 10925 LocalContext context; 10926 v8::Isolate* isolate = context->GetIsolate(); 10927 v8::HandleScope handle_scope(isolate); 10928 10929 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10930 t1->RemovePrototype(); 10931 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked(); 10932 CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust()); 10933 CHECK(!CompileRun("'prototype' in fun") 10934 ->BooleanValue(context.local()) 10935 .FromJust()); 10936 10937 v8::TryCatch try_catch(isolate); 10938 CompileRun("new fun()"); 10939 CHECK(try_catch.HasCaught()); 10940 10941 try_catch.Reset(); 10942 CHECK(fun->NewInstance(context.local()).IsEmpty()); 10943 CHECK(try_catch.HasCaught()); 10944 } 10945 10946 10947 THREADED_TEST(GetterSetterExceptions) { 10948 LocalContext context; 10949 v8::Isolate* isolate = context->GetIsolate(); 10950 v8::HandleScope handle_scope(isolate); 10951 CompileRun( 10952 "function Foo() { };" 10953 "function Throw() { throw 5; };" 10954 "var x = { };" 10955 "x.__defineSetter__('set', Throw);" 10956 "x.__defineGetter__('get', Throw);"); 10957 Local<v8::Object> x = Local<v8::Object>::Cast( 10958 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked()); 10959 v8::TryCatch try_catch(isolate); 10960 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 10961 .IsNothing()); 10962 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 10963 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 10964 .IsNothing()); 10965 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 10966 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 10967 .IsNothing()); 10968 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 10969 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 10970 .IsNothing()); 10971 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 10972 } 10973 10974 10975 THREADED_TEST(Constructor) { 10976 LocalContext context; 10977 v8::Isolate* isolate = context->GetIsolate(); 10978 v8::HandleScope handle_scope(isolate); 10979 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 10980 templ->SetClassName(v8_str("Fun")); 10981 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked(); 10982 CHECK( 10983 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust()); 10984 Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked(); 10985 i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst)); 10986 CHECK(obj->IsJSObject()); 10987 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 10988 CHECK(value->BooleanValue(context.local()).FromJust()); 10989 } 10990 10991 10992 static void ConstructorCallback( 10993 const v8::FunctionCallbackInfo<v8::Value>& args) { 10994 ApiTestFuzzer::Fuzz(); 10995 Local<Object> This; 10996 10997 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 10998 if (args.IsConstructCall()) { 10999 Local<Object> Holder = args.Holder(); 11000 This = Object::New(args.GetIsolate()); 11001 Local<Value> proto = Holder->GetPrototype(); 11002 if (proto->IsObject()) { 11003 This->SetPrototype(context, proto).FromJust(); 11004 } 11005 } else { 11006 This = args.This(); 11007 } 11008 11009 This->Set(context, v8_str("a"), args[0]).FromJust(); 11010 args.GetReturnValue().Set(This); 11011 } 11012 11013 11014 static void FakeConstructorCallback( 11015 const v8::FunctionCallbackInfo<v8::Value>& args) { 11016 ApiTestFuzzer::Fuzz(); 11017 args.GetReturnValue().Set(args[0]); 11018 } 11019 11020 11021 THREADED_TEST(ConstructorForObject) { 11022 LocalContext context; 11023 v8::Isolate* isolate = context->GetIsolate(); 11024 v8::HandleScope handle_scope(isolate); 11025 11026 { 11027 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11028 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 11029 Local<Object> instance = 11030 instance_template->NewInstance(context.local()).ToLocalChecked(); 11031 CHECK(context->Global() 11032 ->Set(context.local(), v8_str("obj"), instance) 11033 .FromJust()); 11034 v8::TryCatch try_catch(isolate); 11035 Local<Value> value; 11036 CHECK(!try_catch.HasCaught()); 11037 11038 // Call the Object's constructor with a 32-bit signed integer. 11039 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 11040 CHECK(!try_catch.HasCaught()); 11041 CHECK(value->IsInt32()); 11042 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11043 11044 Local<Value> args1[] = {v8_num(28)}; 11045 Local<Value> value_obj1 = 11046 instance->CallAsConstructor(context.local(), 1, args1).ToLocalChecked(); 11047 CHECK(value_obj1->IsObject()); 11048 Local<Object> object1 = Local<Object>::Cast(value_obj1); 11049 value = object1->Get(context.local(), v8_str("a")).ToLocalChecked(); 11050 CHECK(value->IsInt32()); 11051 CHECK(!try_catch.HasCaught()); 11052 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11053 11054 // Call the Object's constructor with a String. 11055 value = 11056 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()"); 11057 CHECK(!try_catch.HasCaught()); 11058 CHECK(value->IsString()); 11059 String::Utf8Value string_value1( 11060 value->ToString(context.local()).ToLocalChecked()); 11061 CHECK_EQ(0, strcmp("tipli", *string_value1)); 11062 11063 Local<Value> args2[] = {v8_str("tipli")}; 11064 Local<Value> value_obj2 = 11065 instance->CallAsConstructor(context.local(), 1, args2).ToLocalChecked(); 11066 CHECK(value_obj2->IsObject()); 11067 Local<Object> object2 = Local<Object>::Cast(value_obj2); 11068 value = object2->Get(context.local(), v8_str("a")).ToLocalChecked(); 11069 CHECK(!try_catch.HasCaught()); 11070 CHECK(value->IsString()); 11071 String::Utf8Value string_value2( 11072 value->ToString(context.local()).ToLocalChecked()); 11073 CHECK_EQ(0, strcmp("tipli", *string_value2)); 11074 11075 // Call the Object's constructor with a Boolean. 11076 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 11077 CHECK(!try_catch.HasCaught()); 11078 CHECK(value->IsBoolean()); 11079 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust()); 11080 11081 Local<Value> args3[] = {v8::True(isolate)}; 11082 Local<Value> value_obj3 = 11083 instance->CallAsConstructor(context.local(), 1, args3).ToLocalChecked(); 11084 CHECK(value_obj3->IsObject()); 11085 Local<Object> object3 = Local<Object>::Cast(value_obj3); 11086 value = object3->Get(context.local(), v8_str("a")).ToLocalChecked(); 11087 CHECK(!try_catch.HasCaught()); 11088 CHECK(value->IsBoolean()); 11089 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust()); 11090 11091 // Call the Object's constructor with undefined. 11092 Local<Value> args4[] = {v8::Undefined(isolate)}; 11093 Local<Value> value_obj4 = 11094 instance->CallAsConstructor(context.local(), 1, args4).ToLocalChecked(); 11095 CHECK(value_obj4->IsObject()); 11096 Local<Object> object4 = Local<Object>::Cast(value_obj4); 11097 value = object4->Get(context.local(), v8_str("a")).ToLocalChecked(); 11098 CHECK(!try_catch.HasCaught()); 11099 CHECK(value->IsUndefined()); 11100 11101 // Call the Object's constructor with null. 11102 Local<Value> args5[] = {v8::Null(isolate)}; 11103 Local<Value> value_obj5 = 11104 instance->CallAsConstructor(context.local(), 1, args5).ToLocalChecked(); 11105 CHECK(value_obj5->IsObject()); 11106 Local<Object> object5 = Local<Object>::Cast(value_obj5); 11107 value = object5->Get(context.local(), v8_str("a")).ToLocalChecked(); 11108 CHECK(!try_catch.HasCaught()); 11109 CHECK(value->IsNull()); 11110 } 11111 11112 // Check exception handling when there is no constructor set for the Object. 11113 { 11114 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11115 Local<Object> instance = 11116 instance_template->NewInstance(context.local()).ToLocalChecked(); 11117 CHECK(context->Global() 11118 ->Set(context.local(), v8_str("obj2"), instance) 11119 .FromJust()); 11120 v8::TryCatch try_catch(isolate); 11121 Local<Value> value; 11122 CHECK(!try_catch.HasCaught()); 11123 11124 value = CompileRun("new obj2(28)"); 11125 CHECK(try_catch.HasCaught()); 11126 String::Utf8Value exception_value1(try_catch.Exception()); 11127 CHECK_EQ(0, 11128 strcmp("TypeError: obj2 is not a constructor", *exception_value1)); 11129 try_catch.Reset(); 11130 11131 Local<Value> args[] = {v8_num(29)}; 11132 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty()); 11133 CHECK(try_catch.HasCaught()); 11134 String::Utf8Value exception_value2(try_catch.Exception()); 11135 CHECK_EQ( 11136 0, strcmp("TypeError: object is not a constructor", *exception_value2)); 11137 try_catch.Reset(); 11138 } 11139 11140 // Check the case when constructor throws exception. 11141 { 11142 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11143 instance_template->SetCallAsFunctionHandler(ThrowValue); 11144 Local<Object> instance = 11145 instance_template->NewInstance(context.local()).ToLocalChecked(); 11146 CHECK(context->Global() 11147 ->Set(context.local(), v8_str("obj3"), instance) 11148 .FromJust()); 11149 v8::TryCatch try_catch(isolate); 11150 Local<Value> value; 11151 CHECK(!try_catch.HasCaught()); 11152 11153 value = CompileRun("new obj3(22)"); 11154 CHECK(try_catch.HasCaught()); 11155 String::Utf8Value exception_value1(try_catch.Exception()); 11156 CHECK_EQ(0, strcmp("22", *exception_value1)); 11157 try_catch.Reset(); 11158 11159 Local<Value> args[] = {v8_num(23)}; 11160 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty()); 11161 CHECK(try_catch.HasCaught()); 11162 String::Utf8Value exception_value2(try_catch.Exception()); 11163 CHECK_EQ(0, strcmp("23", *exception_value2)); 11164 try_catch.Reset(); 11165 } 11166 11167 // Check whether constructor returns with an object or non-object. 11168 { 11169 Local<FunctionTemplate> function_template = 11170 FunctionTemplate::New(isolate, FakeConstructorCallback); 11171 Local<Function> function = 11172 function_template->GetFunction(context.local()).ToLocalChecked(); 11173 Local<Object> instance1 = function; 11174 CHECK(context->Global() 11175 ->Set(context.local(), v8_str("obj4"), instance1) 11176 .FromJust()); 11177 v8::TryCatch try_catch(isolate); 11178 Local<Value> value; 11179 CHECK(!try_catch.HasCaught()); 11180 11181 CHECK(instance1->IsObject()); 11182 CHECK(instance1->IsFunction()); 11183 11184 value = CompileRun("new obj4(28)"); 11185 CHECK(!try_catch.HasCaught()); 11186 CHECK(value->IsObject()); 11187 11188 Local<Value> args1[] = {v8_num(28)}; 11189 value = instance1->CallAsConstructor(context.local(), 1, args1) 11190 .ToLocalChecked(); 11191 CHECK(!try_catch.HasCaught()); 11192 CHECK(value->IsObject()); 11193 11194 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11195 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 11196 Local<Object> instance2 = 11197 instance_template->NewInstance(context.local()).ToLocalChecked(); 11198 CHECK(context->Global() 11199 ->Set(context.local(), v8_str("obj5"), instance2) 11200 .FromJust()); 11201 CHECK(!try_catch.HasCaught()); 11202 11203 CHECK(instance2->IsObject()); 11204 CHECK(instance2->IsFunction()); 11205 11206 value = CompileRun("new obj5(28)"); 11207 CHECK(!try_catch.HasCaught()); 11208 CHECK(!value->IsObject()); 11209 11210 Local<Value> args2[] = {v8_num(28)}; 11211 value = instance2->CallAsConstructor(context.local(), 1, args2) 11212 .ToLocalChecked(); 11213 CHECK(!try_catch.HasCaught()); 11214 CHECK(!value->IsObject()); 11215 } 11216 } 11217 11218 11219 THREADED_TEST(FunctionDescriptorException) { 11220 LocalContext context; 11221 v8::Isolate* isolate = context->GetIsolate(); 11222 v8::HandleScope handle_scope(isolate); 11223 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 11224 templ->SetClassName(v8_str("Fun")); 11225 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked(); 11226 CHECK( 11227 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust()); 11228 Local<Value> value = CompileRun( 11229 "function test() {" 11230 " try {" 11231 " (new Fun()).blah()" 11232 " } catch (e) {" 11233 " var str = String(e);" 11234 // " if (str.indexOf('TypeError') == -1) return 1;" 11235 // " if (str.indexOf('[object Fun]') != -1) return 2;" 11236 // " if (str.indexOf('#<Fun>') == -1) return 3;" 11237 " return 0;" 11238 " }" 11239 " return 4;" 11240 "}" 11241 "test();"); 11242 CHECK_EQ(0, value->Int32Value(context.local()).FromJust()); 11243 } 11244 11245 11246 THREADED_TEST(EvalAliasedDynamic) { 11247 LocalContext current; 11248 v8::HandleScope scope(current->GetIsolate()); 11249 11250 // Tests where aliased eval can only be resolved dynamically. 11251 Local<Script> script = v8_compile( 11252 "function f(x) { " 11253 " var foo = 2;" 11254 " with (x) { return eval('foo'); }" 11255 "}" 11256 "foo = 0;" 11257 "result1 = f(new Object());" 11258 "result2 = f(this);" 11259 "var x = new Object();" 11260 "x.eval = function(x) { return 1; };" 11261 "result3 = f(x);"); 11262 script->Run(current.local()).ToLocalChecked(); 11263 CHECK_EQ(2, current->Global() 11264 ->Get(current.local(), v8_str("result1")) 11265 .ToLocalChecked() 11266 ->Int32Value(current.local()) 11267 .FromJust()); 11268 CHECK_EQ(0, current->Global() 11269 ->Get(current.local(), v8_str("result2")) 11270 .ToLocalChecked() 11271 ->Int32Value(current.local()) 11272 .FromJust()); 11273 CHECK_EQ(1, current->Global() 11274 ->Get(current.local(), v8_str("result3")) 11275 .ToLocalChecked() 11276 ->Int32Value(current.local()) 11277 .FromJust()); 11278 11279 v8::TryCatch try_catch(current->GetIsolate()); 11280 script = v8_compile( 11281 "function f(x) { " 11282 " var bar = 2;" 11283 " with (x) { return eval('bar'); }" 11284 "}" 11285 "result4 = f(this)"); 11286 script->Run(current.local()).ToLocalChecked(); 11287 CHECK(!try_catch.HasCaught()); 11288 CHECK_EQ(2, current->Global() 11289 ->Get(current.local(), v8_str("result4")) 11290 .ToLocalChecked() 11291 ->Int32Value(current.local()) 11292 .FromJust()); 11293 11294 try_catch.Reset(); 11295 } 11296 11297 11298 THREADED_TEST(CrossEval) { 11299 v8::HandleScope scope(CcTest::isolate()); 11300 LocalContext other; 11301 LocalContext current; 11302 11303 Local<String> token = v8_str("<security token>"); 11304 other->SetSecurityToken(token); 11305 current->SetSecurityToken(token); 11306 11307 // Set up reference from current to other. 11308 CHECK(current->Global() 11309 ->Set(current.local(), v8_str("other"), other->Global()) 11310 .FromJust()); 11311 11312 // Check that new variables are introduced in other context. 11313 Local<Script> script = v8_compile("other.eval('var foo = 1234')"); 11314 script->Run(current.local()).ToLocalChecked(); 11315 Local<Value> foo = 11316 other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked(); 11317 CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust()); 11318 CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust()); 11319 11320 // Check that writing to non-existing properties introduces them in 11321 // the other context. 11322 script = v8_compile("other.eval('na = 1234')"); 11323 script->Run(current.local()).ToLocalChecked(); 11324 CHECK_EQ(1234, other->Global() 11325 ->Get(current.local(), v8_str("na")) 11326 .ToLocalChecked() 11327 ->Int32Value(other.local()) 11328 .FromJust()); 11329 CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust()); 11330 11331 // Check that global variables in current context are not visible in other 11332 // context. 11333 v8::TryCatch try_catch(CcTest::isolate()); 11334 script = v8_compile("var bar = 42; other.eval('bar');"); 11335 CHECK(script->Run(current.local()).IsEmpty()); 11336 CHECK(try_catch.HasCaught()); 11337 try_catch.Reset(); 11338 11339 // Check that local variables in current context are not visible in other 11340 // context. 11341 script = v8_compile( 11342 "(function() { " 11343 " var baz = 87;" 11344 " return other.eval('baz');" 11345 "})();"); 11346 CHECK(script->Run(current.local()).IsEmpty()); 11347 CHECK(try_catch.HasCaught()); 11348 try_catch.Reset(); 11349 11350 // Check that global variables in the other environment are visible 11351 // when evaluting code. 11352 CHECK(other->Global() 11353 ->Set(other.local(), v8_str("bis"), v8_num(1234)) 11354 .FromJust()); 11355 script = v8_compile("other.eval('bis')"); 11356 CHECK_EQ(1234, script->Run(current.local()) 11357 .ToLocalChecked() 11358 ->Int32Value(current.local()) 11359 .FromJust()); 11360 CHECK(!try_catch.HasCaught()); 11361 11362 // Check that the 'this' pointer points to the global object evaluating 11363 // code. 11364 CHECK(other->Global() 11365 ->Set(current.local(), v8_str("t"), other->Global()) 11366 .FromJust()); 11367 script = v8_compile("other.eval('this == t')"); 11368 Local<Value> result = script->Run(current.local()).ToLocalChecked(); 11369 CHECK(result->IsTrue()); 11370 CHECK(!try_catch.HasCaught()); 11371 11372 // Check that variables introduced in with-statement are not visible in 11373 // other context. 11374 script = v8_compile("with({x:2}){other.eval('x')}"); 11375 CHECK(script->Run(current.local()).IsEmpty()); 11376 CHECK(try_catch.HasCaught()); 11377 try_catch.Reset(); 11378 11379 // Check that you cannot use 'eval.call' with another object than the 11380 // current global object. 11381 script = v8_compile("other.y = 1; eval.call(other, 'y')"); 11382 CHECK(script->Run(current.local()).IsEmpty()); 11383 CHECK(try_catch.HasCaught()); 11384 } 11385 11386 11387 // Test that calling eval in a context which has been detached from 11388 // its global proxy works. 11389 THREADED_TEST(EvalInDetachedGlobal) { 11390 v8::Isolate* isolate = CcTest::isolate(); 11391 v8::HandleScope scope(isolate); 11392 11393 v8::Local<Context> context0 = Context::New(isolate); 11394 v8::Local<Context> context1 = Context::New(isolate); 11395 11396 // Set up function in context0 that uses eval from context0. 11397 context0->Enter(); 11398 v8::Local<v8::Value> fun = CompileRun( 11399 "var x = 42;" 11400 "(function() {" 11401 " var e = eval;" 11402 " return function(s) { return e(s); }" 11403 "})()"); 11404 context0->Exit(); 11405 11406 // Put the function into context1 and call it before and after 11407 // detaching the global. Before detaching, the call succeeds and 11408 // after detaching and exception is thrown. 11409 context1->Enter(); 11410 CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust()); 11411 v8::Local<v8::Value> x_value = CompileRun("fun('x')"); 11412 CHECK_EQ(42, x_value->Int32Value(context1).FromJust()); 11413 context0->DetachGlobal(); 11414 v8::TryCatch catcher(isolate); 11415 x_value = CompileRun("fun('x')"); 11416 CHECK_EQ(42, x_value->Int32Value(context1).FromJust()); 11417 context1->Exit(); 11418 } 11419 11420 11421 THREADED_TEST(CrossLazyLoad) { 11422 v8::HandleScope scope(CcTest::isolate()); 11423 LocalContext other; 11424 LocalContext current; 11425 11426 Local<String> token = v8_str("<security token>"); 11427 other->SetSecurityToken(token); 11428 current->SetSecurityToken(token); 11429 11430 // Set up reference from current to other. 11431 CHECK(current->Global() 11432 ->Set(current.local(), v8_str("other"), other->Global()) 11433 .FromJust()); 11434 11435 // Trigger lazy loading in other context. 11436 Local<Script> script = v8_compile("other.eval('new Date(42)')"); 11437 Local<Value> value = script->Run(current.local()).ToLocalChecked(); 11438 CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust()); 11439 } 11440 11441 11442 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 11443 ApiTestFuzzer::Fuzz(); 11444 if (args.IsConstructCall()) { 11445 if (args[0]->IsInt32()) { 11446 args.GetReturnValue().Set( 11447 v8_num(-args[0] 11448 ->Int32Value(args.GetIsolate()->GetCurrentContext()) 11449 .FromJust())); 11450 return; 11451 } 11452 } 11453 11454 args.GetReturnValue().Set(args[0]); 11455 } 11456 11457 11458 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 11459 args.GetReturnValue().Set(args.This()); 11460 } 11461 11462 11463 // Test that a call handler can be set for objects which will allow 11464 // non-function objects created through the API to be called as 11465 // functions. 11466 THREADED_TEST(CallAsFunction) { 11467 LocalContext context; 11468 v8::Isolate* isolate = context->GetIsolate(); 11469 v8::HandleScope scope(isolate); 11470 11471 { 11472 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11473 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11474 instance_template->SetCallAsFunctionHandler(call_as_function); 11475 Local<v8::Object> instance = t->GetFunction(context.local()) 11476 .ToLocalChecked() 11477 ->NewInstance(context.local()) 11478 .ToLocalChecked(); 11479 CHECK(context->Global() 11480 ->Set(context.local(), v8_str("obj"), instance) 11481 .FromJust()); 11482 v8::TryCatch try_catch(isolate); 11483 Local<Value> value; 11484 CHECK(!try_catch.HasCaught()); 11485 11486 value = CompileRun("obj(42)"); 11487 CHECK(!try_catch.HasCaught()); 11488 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 11489 11490 value = CompileRun("(function(o){return o(49)})(obj)"); 11491 CHECK(!try_catch.HasCaught()); 11492 CHECK_EQ(49, value->Int32Value(context.local()).FromJust()); 11493 11494 // test special case of call as function 11495 value = CompileRun("[obj]['0'](45)"); 11496 CHECK(!try_catch.HasCaught()); 11497 CHECK_EQ(45, value->Int32Value(context.local()).FromJust()); 11498 11499 value = CompileRun( 11500 "obj.call = Function.prototype.call;" 11501 "obj.call(null, 87)"); 11502 CHECK(!try_catch.HasCaught()); 11503 CHECK_EQ(87, value->Int32Value(context.local()).FromJust()); 11504 11505 // Regression tests for bug #1116356: Calling call through call/apply 11506 // must work for non-function receivers. 11507 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 11508 value = CompileRun(apply_99); 11509 CHECK(!try_catch.HasCaught()); 11510 CHECK_EQ(99, value->Int32Value(context.local()).FromJust()); 11511 11512 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 11513 value = CompileRun(call_17); 11514 CHECK(!try_catch.HasCaught()); 11515 CHECK_EQ(17, value->Int32Value(context.local()).FromJust()); 11516 11517 // Check that the call-as-function handler can be called through 11518 // new. 11519 value = CompileRun("new obj(43)"); 11520 CHECK(!try_catch.HasCaught()); 11521 CHECK_EQ(-43, value->Int32Value(context.local()).FromJust()); 11522 11523 // Check that the call-as-function handler can be called through 11524 // the API. 11525 v8::Local<Value> args[] = {v8_num(28)}; 11526 value = instance->CallAsFunction(context.local(), instance, 1, args) 11527 .ToLocalChecked(); 11528 CHECK(!try_catch.HasCaught()); 11529 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11530 } 11531 11532 { 11533 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11534 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 11535 USE(instance_template); 11536 Local<v8::Object> instance = t->GetFunction(context.local()) 11537 .ToLocalChecked() 11538 ->NewInstance(context.local()) 11539 .ToLocalChecked(); 11540 CHECK(context->Global() 11541 ->Set(context.local(), v8_str("obj2"), instance) 11542 .FromJust()); 11543 v8::TryCatch try_catch(isolate); 11544 Local<Value> value; 11545 CHECK(!try_catch.HasCaught()); 11546 11547 // Call an object without call-as-function handler through the JS 11548 value = CompileRun("obj2(28)"); 11549 CHECK(value.IsEmpty()); 11550 CHECK(try_catch.HasCaught()); 11551 String::Utf8Value exception_value1(try_catch.Exception()); 11552 // TODO(verwaest): Better message 11553 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1)); 11554 try_catch.Reset(); 11555 11556 // Call an object without call-as-function handler through the API 11557 value = CompileRun("obj2(28)"); 11558 v8::Local<Value> args[] = {v8_num(28)}; 11559 CHECK( 11560 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty()); 11561 CHECK(try_catch.HasCaught()); 11562 String::Utf8Value exception_value2(try_catch.Exception()); 11563 CHECK_EQ(0, 11564 strcmp("TypeError: object is not a function", *exception_value2)); 11565 try_catch.Reset(); 11566 } 11567 11568 { 11569 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11570 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11571 instance_template->SetCallAsFunctionHandler(ThrowValue); 11572 Local<v8::Object> instance = t->GetFunction(context.local()) 11573 .ToLocalChecked() 11574 ->NewInstance(context.local()) 11575 .ToLocalChecked(); 11576 CHECK(context->Global() 11577 ->Set(context.local(), v8_str("obj3"), instance) 11578 .FromJust()); 11579 v8::TryCatch try_catch(isolate); 11580 Local<Value> value; 11581 CHECK(!try_catch.HasCaught()); 11582 11583 // Catch the exception which is thrown by call-as-function handler 11584 value = CompileRun("obj3(22)"); 11585 CHECK(try_catch.HasCaught()); 11586 String::Utf8Value exception_value1(try_catch.Exception()); 11587 CHECK_EQ(0, strcmp("22", *exception_value1)); 11588 try_catch.Reset(); 11589 11590 v8::Local<Value> args[] = {v8_num(23)}; 11591 CHECK( 11592 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty()); 11593 CHECK(try_catch.HasCaught()); 11594 String::Utf8Value exception_value2(try_catch.Exception()); 11595 CHECK_EQ(0, strcmp("23", *exception_value2)); 11596 try_catch.Reset(); 11597 } 11598 11599 { 11600 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11601 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11602 instance_template->SetCallAsFunctionHandler(ReturnThis); 11603 Local<v8::Object> instance = t->GetFunction(context.local()) 11604 .ToLocalChecked() 11605 ->NewInstance(context.local()) 11606 .ToLocalChecked(); 11607 11608 Local<v8::Value> a1 = 11609 instance->CallAsFunction(context.local(), v8::Undefined(isolate), 0, 11610 NULL) 11611 .ToLocalChecked(); 11612 CHECK(a1->StrictEquals(instance)); 11613 Local<v8::Value> a2 = 11614 instance->CallAsFunction(context.local(), v8::Null(isolate), 0, NULL) 11615 .ToLocalChecked(); 11616 CHECK(a2->StrictEquals(instance)); 11617 Local<v8::Value> a3 = 11618 instance->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11619 .ToLocalChecked(); 11620 CHECK(a3->StrictEquals(instance)); 11621 Local<v8::Value> a4 = 11622 instance->CallAsFunction(context.local(), v8_str("hello"), 0, NULL) 11623 .ToLocalChecked(); 11624 CHECK(a4->StrictEquals(instance)); 11625 Local<v8::Value> a5 = 11626 instance->CallAsFunction(context.local(), v8::True(isolate), 0, NULL) 11627 .ToLocalChecked(); 11628 CHECK(a5->StrictEquals(instance)); 11629 } 11630 11631 { 11632 CompileRun( 11633 "function ReturnThisSloppy() {" 11634 " return this;" 11635 "}" 11636 "function ReturnThisStrict() {" 11637 " 'use strict';" 11638 " return this;" 11639 "}"); 11640 Local<Function> ReturnThisSloppy = Local<Function>::Cast( 11641 context->Global() 11642 ->Get(context.local(), v8_str("ReturnThisSloppy")) 11643 .ToLocalChecked()); 11644 Local<Function> ReturnThisStrict = Local<Function>::Cast( 11645 context->Global() 11646 ->Get(context.local(), v8_str("ReturnThisStrict")) 11647 .ToLocalChecked()); 11648 11649 Local<v8::Value> a1 = 11650 ReturnThisSloppy->CallAsFunction(context.local(), 11651 v8::Undefined(isolate), 0, NULL) 11652 .ToLocalChecked(); 11653 CHECK(a1->StrictEquals(context->Global())); 11654 Local<v8::Value> a2 = 11655 ReturnThisSloppy->CallAsFunction(context.local(), v8::Null(isolate), 0, 11656 NULL) 11657 .ToLocalChecked(); 11658 CHECK(a2->StrictEquals(context->Global())); 11659 Local<v8::Value> a3 = 11660 ReturnThisSloppy->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11661 .ToLocalChecked(); 11662 CHECK(a3->IsNumberObject()); 11663 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf()); 11664 Local<v8::Value> a4 = 11665 ReturnThisSloppy->CallAsFunction(context.local(), v8_str("hello"), 0, 11666 NULL) 11667 .ToLocalChecked(); 11668 CHECK(a4->IsStringObject()); 11669 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 11670 Local<v8::Value> a5 = 11671 ReturnThisSloppy->CallAsFunction(context.local(), v8::True(isolate), 0, 11672 NULL) 11673 .ToLocalChecked(); 11674 CHECK(a5->IsBooleanObject()); 11675 CHECK(a5.As<v8::BooleanObject>()->ValueOf()); 11676 11677 Local<v8::Value> a6 = 11678 ReturnThisStrict->CallAsFunction(context.local(), 11679 v8::Undefined(isolate), 0, NULL) 11680 .ToLocalChecked(); 11681 CHECK(a6->IsUndefined()); 11682 Local<v8::Value> a7 = 11683 ReturnThisStrict->CallAsFunction(context.local(), v8::Null(isolate), 0, 11684 NULL) 11685 .ToLocalChecked(); 11686 CHECK(a7->IsNull()); 11687 Local<v8::Value> a8 = 11688 ReturnThisStrict->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11689 .ToLocalChecked(); 11690 CHECK(a8->StrictEquals(v8_num(42))); 11691 Local<v8::Value> a9 = 11692 ReturnThisStrict->CallAsFunction(context.local(), v8_str("hello"), 0, 11693 NULL) 11694 .ToLocalChecked(); 11695 CHECK(a9->StrictEquals(v8_str("hello"))); 11696 Local<v8::Value> a10 = 11697 ReturnThisStrict->CallAsFunction(context.local(), v8::True(isolate), 0, 11698 NULL) 11699 .ToLocalChecked(); 11700 CHECK(a10->StrictEquals(v8::True(isolate))); 11701 } 11702 } 11703 11704 11705 // Check whether a non-function object is callable. 11706 THREADED_TEST(CallableObject) { 11707 LocalContext context; 11708 v8::Isolate* isolate = context->GetIsolate(); 11709 v8::HandleScope scope(isolate); 11710 11711 { 11712 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11713 instance_template->SetCallAsFunctionHandler(call_as_function); 11714 Local<Object> instance = 11715 instance_template->NewInstance(context.local()).ToLocalChecked(); 11716 v8::TryCatch try_catch(isolate); 11717 11718 CHECK(instance->IsCallable()); 11719 CHECK(!try_catch.HasCaught()); 11720 } 11721 11722 { 11723 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11724 Local<Object> instance = 11725 instance_template->NewInstance(context.local()).ToLocalChecked(); 11726 v8::TryCatch try_catch(isolate); 11727 11728 CHECK(!instance->IsCallable()); 11729 CHECK(!try_catch.HasCaught()); 11730 } 11731 11732 { 11733 Local<FunctionTemplate> function_template = 11734 FunctionTemplate::New(isolate, call_as_function); 11735 Local<Function> function = 11736 function_template->GetFunction(context.local()).ToLocalChecked(); 11737 Local<Object> instance = function; 11738 v8::TryCatch try_catch(isolate); 11739 11740 CHECK(instance->IsCallable()); 11741 CHECK(!try_catch.HasCaught()); 11742 } 11743 11744 { 11745 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate); 11746 Local<Function> function = 11747 function_template->GetFunction(context.local()).ToLocalChecked(); 11748 Local<Object> instance = function; 11749 v8::TryCatch try_catch(isolate); 11750 11751 CHECK(instance->IsCallable()); 11752 CHECK(!try_catch.HasCaught()); 11753 } 11754 } 11755 11756 11757 THREADED_TEST(Regress567998) { 11758 LocalContext env; 11759 v8::HandleScope scope(env->GetIsolate()); 11760 11761 Local<v8::FunctionTemplate> desc = 11762 v8::FunctionTemplate::New(env->GetIsolate()); 11763 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 11764 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable 11765 11766 Local<v8::Object> obj = desc->GetFunction(env.local()) 11767 .ToLocalChecked() 11768 ->NewInstance(env.local()) 11769 .ToLocalChecked(); 11770 CHECK( 11771 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 11772 11773 ExpectString("undetectable.toString()", "[object Object]"); 11774 ExpectString("typeof undetectable", "undefined"); 11775 ExpectString("typeof(undetectable)", "undefined"); 11776 ExpectBoolean("typeof undetectable == 'undefined'", true); 11777 ExpectBoolean("typeof undetectable == 'object'", false); 11778 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 11779 ExpectBoolean("!undetectable", true); 11780 11781 ExpectObject("true&&undetectable", obj); 11782 ExpectBoolean("false&&undetectable", false); 11783 ExpectBoolean("true||undetectable", true); 11784 ExpectObject("false||undetectable", obj); 11785 11786 ExpectObject("undetectable&&true", obj); 11787 ExpectObject("undetectable&&false", obj); 11788 ExpectBoolean("undetectable||true", true); 11789 ExpectBoolean("undetectable||false", false); 11790 11791 ExpectBoolean("undetectable==null", true); 11792 ExpectBoolean("null==undetectable", true); 11793 ExpectBoolean("undetectable==undefined", true); 11794 ExpectBoolean("undefined==undetectable", true); 11795 ExpectBoolean("undetectable==undetectable", true); 11796 11797 ExpectBoolean("undetectable===null", false); 11798 ExpectBoolean("null===undetectable", false); 11799 ExpectBoolean("undetectable===undefined", false); 11800 ExpectBoolean("undefined===undetectable", false); 11801 ExpectBoolean("undetectable===undetectable", true); 11802 } 11803 11804 11805 static int Recurse(v8::Isolate* isolate, int depth, int iterations) { 11806 v8::HandleScope scope(isolate); 11807 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate); 11808 for (int i = 0; i < iterations; i++) { 11809 Local<v8::Number> n(v8::Integer::New(isolate, 42)); 11810 } 11811 return Recurse(isolate, depth - 1, iterations); 11812 } 11813 11814 11815 THREADED_TEST(HandleIteration) { 11816 static const int kIterations = 500; 11817 static const int kNesting = 200; 11818 LocalContext context; 11819 v8::Isolate* isolate = context->GetIsolate(); 11820 v8::HandleScope scope0(isolate); 11821 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11822 { 11823 v8::HandleScope scope1(isolate); 11824 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11825 for (int i = 0; i < kIterations; i++) { 11826 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11827 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate)); 11828 } 11829 11830 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11831 { 11832 v8::HandleScope scope2(CcTest::isolate()); 11833 for (int j = 0; j < kIterations; j++) { 11834 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11835 CHECK_EQ(j + 1 + kIterations, 11836 v8::HandleScope::NumberOfHandles(isolate)); 11837 } 11838 } 11839 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11840 } 11841 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11842 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations)); 11843 } 11844 11845 11846 static void InterceptorCallICFastApi( 11847 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 11848 ApiTestFuzzer::Fuzz(); 11849 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 11850 int* call_count = 11851 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 11852 ++(*call_count); 11853 if ((*call_count) % 20 == 0) { 11854 CcTest::heap()->CollectAllGarbage(); 11855 } 11856 } 11857 11858 static void FastApiCallback_TrivialSignature( 11859 const v8::FunctionCallbackInfo<v8::Value>& args) { 11860 ApiTestFuzzer::Fuzz(); 11861 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 11862 v8::Isolate* isolate = CcTest::isolate(); 11863 CHECK_EQ(isolate, args.GetIsolate()); 11864 CHECK(args.This() 11865 ->Equals(isolate->GetCurrentContext(), args.Holder()) 11866 .FromJust()); 11867 CHECK(args.Data() 11868 ->Equals(isolate->GetCurrentContext(), v8_str("method_data")) 11869 .FromJust()); 11870 args.GetReturnValue().Set( 11871 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1); 11872 } 11873 11874 static void FastApiCallback_SimpleSignature( 11875 const v8::FunctionCallbackInfo<v8::Value>& args) { 11876 ApiTestFuzzer::Fuzz(); 11877 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 11878 v8::Isolate* isolate = CcTest::isolate(); 11879 CHECK_EQ(isolate, args.GetIsolate()); 11880 CHECK(args.This() 11881 ->GetPrototype() 11882 ->Equals(isolate->GetCurrentContext(), args.Holder()) 11883 .FromJust()); 11884 CHECK(args.Data() 11885 ->Equals(isolate->GetCurrentContext(), v8_str("method_data")) 11886 .FromJust()); 11887 // Note, we're using HasRealNamedProperty instead of Has to avoid 11888 // invoking the interceptor again. 11889 CHECK(args.Holder() 11890 ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo")) 11891 .FromJust()); 11892 args.GetReturnValue().Set( 11893 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1); 11894 } 11895 11896 11897 // Helper to maximize the odds of object moving. 11898 static void GenerateSomeGarbage() { 11899 CompileRun( 11900 "var garbage;" 11901 "for (var i = 0; i < 1000; i++) {" 11902 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 11903 "}" 11904 "garbage = undefined;"); 11905 } 11906 11907 11908 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 11909 static int count = 0; 11910 if (count++ % 3 == 0) { 11911 CcTest::heap()->CollectAllGarbage(); 11912 // This should move the stub 11913 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 11914 } 11915 } 11916 11917 11918 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 11919 LocalContext context; 11920 v8::Isolate* isolate = context->GetIsolate(); 11921 v8::HandleScope scope(isolate); 11922 v8::Local<v8::ObjectTemplate> nativeobject_templ = 11923 v8::ObjectTemplate::New(isolate); 11924 nativeobject_templ->Set(isolate, "callback", 11925 v8::FunctionTemplate::New(isolate, 11926 DirectApiCallback)); 11927 v8::Local<v8::Object> nativeobject_obj = 11928 nativeobject_templ->NewInstance(context.local()).ToLocalChecked(); 11929 CHECK(context->Global() 11930 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj) 11931 .FromJust()); 11932 // call the api function multiple times to ensure direct call stub creation. 11933 CompileRun( 11934 "function f() {" 11935 " for (var i = 1; i <= 30; i++) {" 11936 " nativeobject.callback();" 11937 " }" 11938 "}" 11939 "f();"); 11940 } 11941 11942 11943 void ThrowingDirectApiCallback( 11944 const v8::FunctionCallbackInfo<v8::Value>& args) { 11945 args.GetIsolate()->ThrowException(v8_str("g")); 11946 } 11947 11948 11949 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 11950 LocalContext context; 11951 v8::Isolate* isolate = context->GetIsolate(); 11952 v8::HandleScope scope(isolate); 11953 v8::Local<v8::ObjectTemplate> nativeobject_templ = 11954 v8::ObjectTemplate::New(isolate); 11955 nativeobject_templ->Set(isolate, "callback", 11956 v8::FunctionTemplate::New(isolate, 11957 ThrowingDirectApiCallback)); 11958 v8::Local<v8::Object> nativeobject_obj = 11959 nativeobject_templ->NewInstance(context.local()).ToLocalChecked(); 11960 CHECK(context->Global() 11961 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj) 11962 .FromJust()); 11963 // call the api function multiple times to ensure direct call stub creation. 11964 v8::Local<Value> result = CompileRun( 11965 "var result = '';" 11966 "function f() {" 11967 " for (var i = 1; i <= 5; i++) {" 11968 " try { nativeobject.callback(); } catch (e) { result += e; }" 11969 " }" 11970 "}" 11971 "f(); result;"); 11972 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust()); 11973 } 11974 11975 11976 static int p_getter_count_3; 11977 11978 11979 static Local<Value> DoDirectGetter() { 11980 if (++p_getter_count_3 % 3 == 0) { 11981 CcTest::heap()->CollectAllGarbage(); 11982 GenerateSomeGarbage(); 11983 } 11984 return v8_str("Direct Getter Result"); 11985 } 11986 11987 11988 static void DirectGetterCallback( 11989 Local<String> name, 11990 const v8::PropertyCallbackInfo<v8::Value>& info) { 11991 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 11992 info.GetReturnValue().Set(DoDirectGetter()); 11993 } 11994 11995 11996 template<typename Accessor> 11997 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 11998 LocalContext context; 11999 v8::Isolate* isolate = context->GetIsolate(); 12000 v8::HandleScope scope(isolate); 12001 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12002 obj->SetAccessor(v8_str("p1"), accessor); 12003 CHECK(context->Global() 12004 ->Set(context.local(), v8_str("o1"), 12005 obj->NewInstance(context.local()).ToLocalChecked()) 12006 .FromJust()); 12007 p_getter_count_3 = 0; 12008 v8::Local<v8::Value> result = CompileRun( 12009 "function f() {" 12010 " for (var i = 0; i < 30; i++) o1.p1;" 12011 " return o1.p1" 12012 "}" 12013 "f();"); 12014 CHECK(v8_str("Direct Getter Result") 12015 ->Equals(context.local(), result) 12016 .FromJust()); 12017 CHECK_EQ(31, p_getter_count_3); 12018 } 12019 12020 12021 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 12022 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 12023 } 12024 12025 12026 void ThrowingDirectGetterCallback( 12027 Local<String> name, 12028 const v8::PropertyCallbackInfo<v8::Value>& info) { 12029 info.GetIsolate()->ThrowException(v8_str("g")); 12030 } 12031 12032 12033 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 12034 LocalContext context; 12035 v8::Isolate* isolate = context->GetIsolate(); 12036 v8::HandleScope scope(isolate); 12037 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12038 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 12039 CHECK(context->Global() 12040 ->Set(context.local(), v8_str("o1"), 12041 obj->NewInstance(context.local()).ToLocalChecked()) 12042 .FromJust()); 12043 v8::Local<Value> result = CompileRun( 12044 "var result = '';" 12045 "for (var i = 0; i < 5; i++) {" 12046 " try { o1.p1; } catch (e) { result += e; }" 12047 "}" 12048 "result;"); 12049 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust()); 12050 } 12051 12052 12053 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 12054 int interceptor_call_count = 0; 12055 v8::Isolate* isolate = CcTest::isolate(); 12056 v8::HandleScope scope(isolate); 12057 v8::Local<v8::FunctionTemplate> fun_templ = 12058 v8::FunctionTemplate::New(isolate); 12059 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12060 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"), 12061 v8::Local<v8::Signature>()); 12062 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12063 proto_templ->Set(v8_str("method"), method_templ); 12064 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12065 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12066 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12067 v8::External::New(isolate, &interceptor_call_count))); 12068 LocalContext context; 12069 v8::Local<v8::Function> fun = 12070 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12071 GenerateSomeGarbage(); 12072 CHECK(context->Global() 12073 ->Set(context.local(), v8_str("o"), 12074 fun->NewInstance(context.local()).ToLocalChecked()) 12075 .FromJust()); 12076 CompileRun( 12077 "var result = 0;" 12078 "for (var i = 0; i < 100; i++) {" 12079 " result = o.method(41);" 12080 "}"); 12081 CHECK_EQ(42, context->Global() 12082 ->Get(context.local(), v8_str("result")) 12083 .ToLocalChecked() 12084 ->Int32Value(context.local()) 12085 .FromJust()); 12086 CHECK_EQ(100, interceptor_call_count); 12087 } 12088 12089 12090 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 12091 int interceptor_call_count = 0; 12092 v8::Isolate* isolate = CcTest::isolate(); 12093 v8::HandleScope scope(isolate); 12094 v8::Local<v8::FunctionTemplate> fun_templ = 12095 v8::FunctionTemplate::New(isolate); 12096 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12097 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12098 v8::Signature::New(isolate, fun_templ)); 12099 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12100 proto_templ->Set(v8_str("method"), method_templ); 12101 fun_templ->SetHiddenPrototype(true); 12102 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12103 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12104 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12105 v8::External::New(isolate, &interceptor_call_count))); 12106 LocalContext context; 12107 v8::Local<v8::Function> fun = 12108 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12109 GenerateSomeGarbage(); 12110 CHECK(context->Global() 12111 ->Set(context.local(), v8_str("o"), 12112 fun->NewInstance(context.local()).ToLocalChecked()) 12113 .FromJust()); 12114 CompileRun( 12115 "o.foo = 17;" 12116 "var receiver = {};" 12117 "receiver.__proto__ = o;" 12118 "var result = 0;" 12119 "for (var i = 0; i < 100; i++) {" 12120 " result = receiver.method(41);" 12121 "}"); 12122 CHECK_EQ(42, context->Global() 12123 ->Get(context.local(), v8_str("result")) 12124 .ToLocalChecked() 12125 ->Int32Value(context.local()) 12126 .FromJust()); 12127 CHECK_EQ(100, interceptor_call_count); 12128 } 12129 12130 12131 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 12132 int interceptor_call_count = 0; 12133 v8::Isolate* isolate = CcTest::isolate(); 12134 v8::HandleScope scope(isolate); 12135 v8::Local<v8::FunctionTemplate> fun_templ = 12136 v8::FunctionTemplate::New(isolate); 12137 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12138 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12139 v8::Signature::New(isolate, fun_templ)); 12140 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12141 proto_templ->Set(v8_str("method"), method_templ); 12142 fun_templ->SetHiddenPrototype(true); 12143 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12144 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12145 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12146 v8::External::New(isolate, &interceptor_call_count))); 12147 LocalContext context; 12148 v8::Local<v8::Function> fun = 12149 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12150 GenerateSomeGarbage(); 12151 CHECK(context->Global() 12152 ->Set(context.local(), v8_str("o"), 12153 fun->NewInstance(context.local()).ToLocalChecked()) 12154 .FromJust()); 12155 CompileRun( 12156 "o.foo = 17;" 12157 "var receiver = {};" 12158 "receiver.__proto__ = o;" 12159 "var result = 0;" 12160 "var saved_result = 0;" 12161 "for (var i = 0; i < 100; i++) {" 12162 " result = receiver.method(41);" 12163 " if (i == 50) {" 12164 " saved_result = result;" 12165 " receiver = {method: function(x) { return x - 1 }};" 12166 " }" 12167 "}"); 12168 CHECK_EQ(40, context->Global() 12169 ->Get(context.local(), v8_str("result")) 12170 .ToLocalChecked() 12171 ->Int32Value(context.local()) 12172 .FromJust()); 12173 CHECK_EQ(42, context->Global() 12174 ->Get(context.local(), v8_str("saved_result")) 12175 .ToLocalChecked() 12176 ->Int32Value(context.local()) 12177 .FromJust()); 12178 CHECK_GE(interceptor_call_count, 50); 12179 } 12180 12181 12182 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 12183 int interceptor_call_count = 0; 12184 v8::Isolate* isolate = CcTest::isolate(); 12185 v8::HandleScope scope(isolate); 12186 v8::Local<v8::FunctionTemplate> fun_templ = 12187 v8::FunctionTemplate::New(isolate); 12188 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12189 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12190 v8::Signature::New(isolate, fun_templ)); 12191 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12192 proto_templ->Set(v8_str("method"), method_templ); 12193 fun_templ->SetHiddenPrototype(true); 12194 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12195 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12196 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12197 v8::External::New(isolate, &interceptor_call_count))); 12198 LocalContext context; 12199 v8::Local<v8::Function> fun = 12200 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12201 GenerateSomeGarbage(); 12202 CHECK(context->Global() 12203 ->Set(context.local(), v8_str("o"), 12204 fun->NewInstance(context.local()).ToLocalChecked()) 12205 .FromJust()); 12206 CompileRun( 12207 "o.foo = 17;" 12208 "var receiver = {};" 12209 "receiver.__proto__ = o;" 12210 "var result = 0;" 12211 "var saved_result = 0;" 12212 "for (var i = 0; i < 100; i++) {" 12213 " result = receiver.method(41);" 12214 " if (i == 50) {" 12215 " saved_result = result;" 12216 " o.method = function(x) { return x - 1 };" 12217 " }" 12218 "}"); 12219 CHECK_EQ(40, context->Global() 12220 ->Get(context.local(), v8_str("result")) 12221 .ToLocalChecked() 12222 ->Int32Value(context.local()) 12223 .FromJust()); 12224 CHECK_EQ(42, context->Global() 12225 ->Get(context.local(), v8_str("saved_result")) 12226 .ToLocalChecked() 12227 ->Int32Value(context.local()) 12228 .FromJust()); 12229 CHECK_GE(interceptor_call_count, 50); 12230 } 12231 12232 12233 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 12234 int interceptor_call_count = 0; 12235 v8::Isolate* isolate = CcTest::isolate(); 12236 v8::HandleScope scope(isolate); 12237 v8::Local<v8::FunctionTemplate> fun_templ = 12238 v8::FunctionTemplate::New(isolate); 12239 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12240 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12241 v8::Signature::New(isolate, fun_templ)); 12242 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12243 proto_templ->Set(v8_str("method"), method_templ); 12244 fun_templ->SetHiddenPrototype(true); 12245 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12246 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12247 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12248 v8::External::New(isolate, &interceptor_call_count))); 12249 LocalContext context; 12250 v8::Local<v8::Function> fun = 12251 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12252 GenerateSomeGarbage(); 12253 CHECK(context->Global() 12254 ->Set(context.local(), v8_str("o"), 12255 fun->NewInstance(context.local()).ToLocalChecked()) 12256 .FromJust()); 12257 v8::TryCatch try_catch(isolate); 12258 CompileRun( 12259 "o.foo = 17;" 12260 "var receiver = {};" 12261 "receiver.__proto__ = o;" 12262 "var result = 0;" 12263 "var saved_result = 0;" 12264 "for (var i = 0; i < 100; i++) {" 12265 " result = receiver.method(41);" 12266 " if (i == 50) {" 12267 " saved_result = result;" 12268 " receiver = 333;" 12269 " }" 12270 "}"); 12271 CHECK(try_catch.HasCaught()); 12272 // TODO(verwaest): Adjust message. 12273 CHECK( 12274 v8_str("TypeError: receiver.method is not a function") 12275 ->Equals( 12276 context.local(), 12277 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12278 .FromJust()); 12279 CHECK_EQ(42, context->Global() 12280 ->Get(context.local(), v8_str("saved_result")) 12281 .ToLocalChecked() 12282 ->Int32Value(context.local()) 12283 .FromJust()); 12284 CHECK_GE(interceptor_call_count, 50); 12285 } 12286 12287 12288 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 12289 int interceptor_call_count = 0; 12290 v8::Isolate* isolate = CcTest::isolate(); 12291 v8::HandleScope scope(isolate); 12292 v8::Local<v8::FunctionTemplate> fun_templ = 12293 v8::FunctionTemplate::New(isolate); 12294 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12295 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12296 v8::Signature::New(isolate, fun_templ)); 12297 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12298 proto_templ->Set(v8_str("method"), method_templ); 12299 fun_templ->SetHiddenPrototype(true); 12300 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12301 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12302 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12303 v8::External::New(isolate, &interceptor_call_count))); 12304 LocalContext context; 12305 v8::Local<v8::Function> fun = 12306 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12307 GenerateSomeGarbage(); 12308 CHECK(context->Global() 12309 ->Set(context.local(), v8_str("o"), 12310 fun->NewInstance(context.local()).ToLocalChecked()) 12311 .FromJust()); 12312 v8::TryCatch try_catch(isolate); 12313 CompileRun( 12314 "o.foo = 17;" 12315 "var receiver = {};" 12316 "receiver.__proto__ = o;" 12317 "var result = 0;" 12318 "var saved_result = 0;" 12319 "for (var i = 0; i < 100; i++) {" 12320 " result = receiver.method(41);" 12321 " if (i == 50) {" 12322 " saved_result = result;" 12323 " receiver = {method: receiver.method};" 12324 " }" 12325 "}"); 12326 CHECK(try_catch.HasCaught()); 12327 CHECK( 12328 v8_str("TypeError: Illegal invocation") 12329 ->Equals( 12330 context.local(), 12331 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12332 .FromJust()); 12333 CHECK_EQ(42, context->Global() 12334 ->Get(context.local(), v8_str("saved_result")) 12335 .ToLocalChecked() 12336 ->Int32Value(context.local()) 12337 .FromJust()); 12338 CHECK_GE(interceptor_call_count, 50); 12339 } 12340 12341 12342 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 12343 v8::Isolate* isolate = CcTest::isolate(); 12344 v8::HandleScope scope(isolate); 12345 v8::Local<v8::FunctionTemplate> fun_templ = 12346 v8::FunctionTemplate::New(isolate); 12347 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12348 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"), 12349 v8::Local<v8::Signature>()); 12350 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12351 proto_templ->Set(v8_str("method"), method_templ); 12352 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12353 USE(templ); 12354 LocalContext context; 12355 v8::Local<v8::Function> fun = 12356 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12357 GenerateSomeGarbage(); 12358 CHECK(context->Global() 12359 ->Set(context.local(), v8_str("o"), 12360 fun->NewInstance(context.local()).ToLocalChecked()) 12361 .FromJust()); 12362 CompileRun( 12363 "var result = 0;" 12364 "for (var i = 0; i < 100; i++) {" 12365 " result = o.method(41);" 12366 "}"); 12367 12368 CHECK_EQ(42, context->Global() 12369 ->Get(context.local(), v8_str("result")) 12370 .ToLocalChecked() 12371 ->Int32Value(context.local()) 12372 .FromJust()); 12373 } 12374 12375 12376 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 12377 v8::Isolate* isolate = CcTest::isolate(); 12378 v8::HandleScope scope(isolate); 12379 v8::Local<v8::FunctionTemplate> fun_templ = 12380 v8::FunctionTemplate::New(isolate); 12381 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12382 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12383 v8::Signature::New(isolate, fun_templ)); 12384 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12385 proto_templ->Set(v8_str("method"), method_templ); 12386 fun_templ->SetHiddenPrototype(true); 12387 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12388 CHECK(!templ.IsEmpty()); 12389 LocalContext context; 12390 v8::Local<v8::Function> fun = 12391 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12392 GenerateSomeGarbage(); 12393 CHECK(context->Global() 12394 ->Set(context.local(), v8_str("o"), 12395 fun->NewInstance(context.local()).ToLocalChecked()) 12396 .FromJust()); 12397 CompileRun( 12398 "o.foo = 17;" 12399 "var receiver = {};" 12400 "receiver.__proto__ = o;" 12401 "var result = 0;" 12402 "for (var i = 0; i < 100; i++) {" 12403 " result = receiver.method(41);" 12404 "}"); 12405 12406 CHECK_EQ(42, context->Global() 12407 ->Get(context.local(), v8_str("result")) 12408 .ToLocalChecked() 12409 ->Int32Value(context.local()) 12410 .FromJust()); 12411 } 12412 12413 12414 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 12415 v8::Isolate* isolate = CcTest::isolate(); 12416 v8::HandleScope scope(isolate); 12417 v8::Local<v8::FunctionTemplate> fun_templ = 12418 v8::FunctionTemplate::New(isolate); 12419 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12420 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12421 v8::Signature::New(isolate, fun_templ)); 12422 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12423 proto_templ->Set(v8_str("method"), method_templ); 12424 fun_templ->SetHiddenPrototype(true); 12425 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12426 CHECK(!templ.IsEmpty()); 12427 LocalContext context; 12428 v8::Local<v8::Function> fun = 12429 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12430 GenerateSomeGarbage(); 12431 CHECK(context->Global() 12432 ->Set(context.local(), v8_str("o"), 12433 fun->NewInstance(context.local()).ToLocalChecked()) 12434 .FromJust()); 12435 CompileRun( 12436 "o.foo = 17;" 12437 "var receiver = {};" 12438 "receiver.__proto__ = o;" 12439 "var result = 0;" 12440 "var saved_result = 0;" 12441 "for (var i = 0; i < 100; i++) {" 12442 " result = receiver.method(41);" 12443 " if (i == 50) {" 12444 " saved_result = result;" 12445 " receiver = {method: function(x) { return x - 1 }};" 12446 " }" 12447 "}"); 12448 CHECK_EQ(40, context->Global() 12449 ->Get(context.local(), v8_str("result")) 12450 .ToLocalChecked() 12451 ->Int32Value(context.local()) 12452 .FromJust()); 12453 CHECK_EQ(42, context->Global() 12454 ->Get(context.local(), v8_str("saved_result")) 12455 .ToLocalChecked() 12456 ->Int32Value(context.local()) 12457 .FromJust()); 12458 } 12459 12460 12461 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 12462 v8::Isolate* isolate = CcTest::isolate(); 12463 v8::HandleScope scope(isolate); 12464 v8::Local<v8::FunctionTemplate> fun_templ = 12465 v8::FunctionTemplate::New(isolate); 12466 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12467 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12468 v8::Signature::New(isolate, fun_templ)); 12469 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12470 proto_templ->Set(v8_str("method"), method_templ); 12471 fun_templ->SetHiddenPrototype(true); 12472 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12473 CHECK(!templ.IsEmpty()); 12474 LocalContext context; 12475 v8::Local<v8::Function> fun = 12476 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12477 GenerateSomeGarbage(); 12478 CHECK(context->Global() 12479 ->Set(context.local(), v8_str("o"), 12480 fun->NewInstance(context.local()).ToLocalChecked()) 12481 .FromJust()); 12482 v8::TryCatch try_catch(isolate); 12483 CompileRun( 12484 "o.foo = 17;" 12485 "var receiver = {};" 12486 "receiver.__proto__ = o;" 12487 "var result = 0;" 12488 "var saved_result = 0;" 12489 "for (var i = 0; i < 100; i++) {" 12490 " result = receiver.method(41);" 12491 " if (i == 50) {" 12492 " saved_result = result;" 12493 " receiver = 333;" 12494 " }" 12495 "}"); 12496 CHECK(try_catch.HasCaught()); 12497 // TODO(verwaest): Adjust message. 12498 CHECK( 12499 v8_str("TypeError: receiver.method is not a function") 12500 ->Equals( 12501 context.local(), 12502 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12503 .FromJust()); 12504 CHECK_EQ(42, context->Global() 12505 ->Get(context.local(), v8_str("saved_result")) 12506 .ToLocalChecked() 12507 ->Int32Value(context.local()) 12508 .FromJust()); 12509 } 12510 12511 12512 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 12513 v8::Isolate* isolate = CcTest::isolate(); 12514 v8::HandleScope scope(isolate); 12515 v8::Local<v8::FunctionTemplate> fun_templ = 12516 v8::FunctionTemplate::New(isolate); 12517 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12518 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12519 v8::Signature::New(isolate, fun_templ)); 12520 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12521 proto_templ->Set(v8_str("method"), method_templ); 12522 fun_templ->SetHiddenPrototype(true); 12523 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12524 CHECK(!templ.IsEmpty()); 12525 LocalContext context; 12526 v8::Local<v8::Function> fun = 12527 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12528 GenerateSomeGarbage(); 12529 CHECK(context->Global() 12530 ->Set(context.local(), v8_str("o"), 12531 fun->NewInstance(context.local()).ToLocalChecked()) 12532 .FromJust()); 12533 v8::TryCatch try_catch(isolate); 12534 CompileRun( 12535 "o.foo = 17;" 12536 "var receiver = {};" 12537 "receiver.__proto__ = o;" 12538 "var result = 0;" 12539 "var saved_result = 0;" 12540 "for (var i = 0; i < 100; i++) {" 12541 " result = receiver.method(41);" 12542 " if (i == 50) {" 12543 " saved_result = result;" 12544 " receiver = Object.create(receiver);" 12545 " }" 12546 "}"); 12547 CHECK(try_catch.HasCaught()); 12548 CHECK( 12549 v8_str("TypeError: Illegal invocation") 12550 ->Equals( 12551 context.local(), 12552 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12553 .FromJust()); 12554 CHECK_EQ(42, context->Global() 12555 ->Get(context.local(), v8_str("saved_result")) 12556 .ToLocalChecked() 12557 ->Int32Value(context.local()) 12558 .FromJust()); 12559 } 12560 12561 12562 static void ThrowingGetter(Local<String> name, 12563 const v8::PropertyCallbackInfo<v8::Value>& info) { 12564 ApiTestFuzzer::Fuzz(); 12565 info.GetIsolate()->ThrowException(Local<Value>()); 12566 info.GetReturnValue().SetUndefined(); 12567 } 12568 12569 12570 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 12571 LocalContext context; 12572 HandleScope scope(context->GetIsolate()); 12573 12574 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 12575 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 12576 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 12577 12578 Local<Object> instance = templ->GetFunction(context.local()) 12579 .ToLocalChecked() 12580 ->NewInstance(context.local()) 12581 .ToLocalChecked(); 12582 12583 Local<Object> another = Object::New(context->GetIsolate()); 12584 CHECK(another->SetPrototype(context.local(), instance).FromJust()); 12585 12586 Local<Object> with_js_getter = CompileRun( 12587 "o = {};\n" 12588 "o.__defineGetter__('f', function() { throw undefined; });\n" 12589 "o\n").As<Object>(); 12590 CHECK(!with_js_getter.IsEmpty()); 12591 12592 TryCatch try_catch(context->GetIsolate()); 12593 12594 v8::MaybeLocal<Value> result = 12595 instance->GetRealNamedProperty(context.local(), v8_str("f")); 12596 CHECK(try_catch.HasCaught()); 12597 try_catch.Reset(); 12598 CHECK(result.IsEmpty()); 12599 12600 Maybe<PropertyAttribute> attr = 12601 instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f")); 12602 CHECK(!try_catch.HasCaught()); 12603 CHECK(Just(None) == attr); 12604 12605 result = another->GetRealNamedProperty(context.local(), v8_str("f")); 12606 CHECK(try_catch.HasCaught()); 12607 try_catch.Reset(); 12608 CHECK(result.IsEmpty()); 12609 12610 attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f")); 12611 CHECK(!try_catch.HasCaught()); 12612 CHECK(Just(None) == attr); 12613 12614 result = another->GetRealNamedPropertyInPrototypeChain(context.local(), 12615 v8_str("f")); 12616 CHECK(try_catch.HasCaught()); 12617 try_catch.Reset(); 12618 CHECK(result.IsEmpty()); 12619 12620 attr = another->GetRealNamedPropertyAttributesInPrototypeChain( 12621 context.local(), v8_str("f")); 12622 CHECK(!try_catch.HasCaught()); 12623 CHECK(Just(None) == attr); 12624 12625 result = another->Get(context.local(), v8_str("f")); 12626 CHECK(try_catch.HasCaught()); 12627 try_catch.Reset(); 12628 CHECK(result.IsEmpty()); 12629 12630 result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f")); 12631 CHECK(try_catch.HasCaught()); 12632 try_catch.Reset(); 12633 CHECK(result.IsEmpty()); 12634 12635 attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(), 12636 v8_str("f")); 12637 CHECK(!try_catch.HasCaught()); 12638 CHECK(Just(None) == attr); 12639 12640 result = with_js_getter->Get(context.local(), v8_str("f")); 12641 CHECK(try_catch.HasCaught()); 12642 try_catch.Reset(); 12643 CHECK(result.IsEmpty()); 12644 } 12645 12646 12647 static void ThrowingCallbackWithTryCatch( 12648 const v8::FunctionCallbackInfo<v8::Value>& args) { 12649 TryCatch try_catch(args.GetIsolate()); 12650 // Verboseness is important: it triggers message delivery which can call into 12651 // external code. 12652 try_catch.SetVerbose(true); 12653 CompileRun("throw 'from JS';"); 12654 CHECK(try_catch.HasCaught()); 12655 CHECK(!CcTest::i_isolate()->has_pending_exception()); 12656 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 12657 } 12658 12659 12660 static int call_depth; 12661 12662 12663 static void WithTryCatch(Local<Message> message, Local<Value> data) { 12664 TryCatch try_catch(CcTest::isolate()); 12665 } 12666 12667 12668 static void ThrowFromJS(Local<Message> message, Local<Value> data) { 12669 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 12670 } 12671 12672 12673 static void ThrowViaApi(Local<Message> message, Local<Value> data) { 12674 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi")); 12675 } 12676 12677 12678 static void WebKitLike(Local<Message> message, Local<Value> data) { 12679 Local<String> errorMessageString = message->Get(); 12680 CHECK(!errorMessageString.IsEmpty()); 12681 message->GetStackTrace(); 12682 message->GetScriptOrigin().ResourceName(); 12683 } 12684 12685 12686 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 12687 LocalContext context; 12688 v8::Isolate* isolate = context->GetIsolate(); 12689 HandleScope scope(isolate); 12690 12691 Local<Function> func = 12692 FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch) 12693 ->GetFunction(context.local()) 12694 .ToLocalChecked(); 12695 CHECK( 12696 context->Global()->Set(context.local(), v8_str("func"), func).FromJust()); 12697 12698 MessageCallback callbacks[] = 12699 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 12700 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 12701 MessageCallback callback = callbacks[i]; 12702 if (callback != NULL) { 12703 isolate->AddMessageListener(callback); 12704 } 12705 // Some small number to control number of times message handler should 12706 // throw an exception. 12707 call_depth = 5; 12708 ExpectFalse( 12709 "var thrown = false;\n" 12710 "try { func(); } catch(e) { thrown = true; }\n" 12711 "thrown\n"); 12712 if (callback != NULL) { 12713 isolate->RemoveMessageListeners(callback); 12714 } 12715 } 12716 } 12717 12718 12719 static void ParentGetter(Local<String> name, 12720 const v8::PropertyCallbackInfo<v8::Value>& info) { 12721 ApiTestFuzzer::Fuzz(); 12722 info.GetReturnValue().Set(v8_num(1)); 12723 } 12724 12725 12726 static void ChildGetter(Local<String> name, 12727 const v8::PropertyCallbackInfo<v8::Value>& info) { 12728 ApiTestFuzzer::Fuzz(); 12729 info.GetReturnValue().Set(v8_num(42)); 12730 } 12731 12732 12733 THREADED_TEST(Overriding) { 12734 LocalContext context; 12735 v8::Isolate* isolate = context->GetIsolate(); 12736 v8::HandleScope scope(isolate); 12737 12738 // Parent template. 12739 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate); 12740 Local<ObjectTemplate> parent_instance_templ = 12741 parent_templ->InstanceTemplate(); 12742 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 12743 12744 // Template that inherits from the parent template. 12745 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate); 12746 Local<ObjectTemplate> child_instance_templ = 12747 child_templ->InstanceTemplate(); 12748 child_templ->Inherit(parent_templ); 12749 // Override 'f'. The child version of 'f' should get called for child 12750 // instances. 12751 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 12752 // Add 'g' twice. The 'g' added last should get called for instances. 12753 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 12754 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 12755 12756 // Add 'h' as an accessor to the proto template with ReadOnly attributes 12757 // so 'h' can be shadowed on the instance object. 12758 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 12759 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 12760 v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly); 12761 12762 // Add 'i' as an accessor to the instance template with ReadOnly attributes 12763 // but the attribute does not have effect because it is duplicated with 12764 // NULL setter. 12765 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 12766 v8::Local<Value>(), v8::DEFAULT, 12767 v8::ReadOnly); 12768 12769 12770 // Instantiate the child template. 12771 Local<v8::Object> instance = child_templ->GetFunction(context.local()) 12772 .ToLocalChecked() 12773 ->NewInstance(context.local()) 12774 .ToLocalChecked(); 12775 12776 // Check that the child function overrides the parent one. 12777 CHECK(context->Global() 12778 ->Set(context.local(), v8_str("o"), instance) 12779 .FromJust()); 12780 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); 12781 // Check that the 'g' that was added last is hit. 12782 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 12783 value = v8_compile("o.g")->Run(context.local()).ToLocalChecked(); 12784 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 12785 12786 // Check that 'h' cannot be shadowed. 12787 value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked(); 12788 CHECK_EQ(1, value->Int32Value(context.local()).FromJust()); 12789 12790 // Check that 'i' cannot be shadowed or changed. 12791 value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked(); 12792 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 12793 } 12794 12795 12796 static void IsConstructHandler( 12797 const v8::FunctionCallbackInfo<v8::Value>& args) { 12798 ApiTestFuzzer::Fuzz(); 12799 args.GetReturnValue().Set(args.IsConstructCall()); 12800 } 12801 12802 12803 THREADED_TEST(IsConstructCall) { 12804 v8::Isolate* isolate = CcTest::isolate(); 12805 v8::HandleScope scope(isolate); 12806 12807 // Function template with call handler. 12808 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 12809 templ->SetCallHandler(IsConstructHandler); 12810 12811 LocalContext context; 12812 12813 CHECK(context->Global() 12814 ->Set(context.local(), v8_str("f"), 12815 templ->GetFunction(context.local()).ToLocalChecked()) 12816 .FromJust()); 12817 Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked(); 12818 CHECK(!value->BooleanValue(context.local()).FromJust()); 12819 value = v8_compile("new f()")->Run(context.local()).ToLocalChecked(); 12820 CHECK(value->BooleanValue(context.local()).FromJust()); 12821 } 12822 12823 12824 THREADED_TEST(ObjectProtoToString) { 12825 v8::Isolate* isolate = CcTest::isolate(); 12826 v8::HandleScope scope(isolate); 12827 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 12828 templ->SetClassName(v8_str("MyClass")); 12829 12830 LocalContext context; 12831 12832 Local<String> customized_tostring = v8_str("customized toString"); 12833 12834 // Replace Object.prototype.toString 12835 v8_compile( 12836 "Object.prototype.toString = function() {" 12837 " return 'customized toString';" 12838 "}") 12839 ->Run(context.local()) 12840 .ToLocalChecked(); 12841 12842 // Normal ToString call should call replaced Object.prototype.toString 12843 Local<v8::Object> instance = templ->GetFunction(context.local()) 12844 .ToLocalChecked() 12845 ->NewInstance(context.local()) 12846 .ToLocalChecked(); 12847 Local<String> value = instance->ToString(context.local()).ToLocalChecked(); 12848 CHECK(value->IsString() && 12849 value->Equals(context.local(), customized_tostring).FromJust()); 12850 12851 // ObjectProtoToString should not call replace toString function. 12852 value = instance->ObjectProtoToString(context.local()).ToLocalChecked(); 12853 CHECK(value->IsString() && 12854 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust()); 12855 12856 // Check global 12857 value = 12858 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked(); 12859 CHECK(value->IsString() && 12860 value->Equals(context.local(), v8_str("[object global]")).FromJust()); 12861 12862 // Check ordinary object 12863 Local<Value> object = 12864 v8_compile("new Object()")->Run(context.local()).ToLocalChecked(); 12865 value = object.As<v8::Object>() 12866 ->ObjectProtoToString(context.local()) 12867 .ToLocalChecked(); 12868 CHECK(value->IsString() && 12869 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 12870 } 12871 12872 12873 TEST(ObjectProtoToStringES6) { 12874 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped. 12875 i::FLAG_harmony_tostring = true; 12876 LocalContext context; 12877 v8::Isolate* isolate = CcTest::isolate(); 12878 v8::HandleScope scope(isolate); 12879 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 12880 templ->SetClassName(v8_str("MyClass")); 12881 12882 Local<String> customized_tostring = v8_str("customized toString"); 12883 12884 // Replace Object.prototype.toString 12885 CompileRun( 12886 "Object.prototype.toString = function() {" 12887 " return 'customized toString';" 12888 "}"); 12889 12890 // Normal ToString call should call replaced Object.prototype.toString 12891 Local<v8::Object> instance = templ->GetFunction(context.local()) 12892 .ToLocalChecked() 12893 ->NewInstance(context.local()) 12894 .ToLocalChecked(); 12895 Local<String> value = instance->ToString(context.local()).ToLocalChecked(); 12896 CHECK(value->IsString() && 12897 value->Equals(context.local(), customized_tostring).FromJust()); 12898 12899 // ObjectProtoToString should not call replace toString function. 12900 value = instance->ObjectProtoToString(context.local()).ToLocalChecked(); 12901 CHECK(value->IsString() && 12902 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust()); 12903 12904 // Check global 12905 value = 12906 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked(); 12907 CHECK(value->IsString() && 12908 value->Equals(context.local(), v8_str("[object global]")).FromJust()); 12909 12910 // Check ordinary object 12911 Local<Value> object = CompileRun("new Object()"); 12912 value = object.As<v8::Object>() 12913 ->ObjectProtoToString(context.local()) 12914 .ToLocalChecked(); 12915 CHECK(value->IsString() && 12916 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 12917 12918 // Check that ES6 semantics using @@toStringTag work 12919 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate); 12920 12921 #define TEST_TOSTRINGTAG(type, tag, expected) \ 12922 do { \ 12923 object = CompileRun("new " #type "()"); \ 12924 CHECK(object.As<v8::Object>() \ 12925 ->Set(context.local(), toStringTag, v8_str(#tag)) \ 12926 .FromJust()); \ 12927 value = object.As<v8::Object>() \ 12928 ->ObjectProtoToString(context.local()) \ 12929 .ToLocalChecked(); \ 12930 CHECK(value->IsString() && \ 12931 value->Equals(context.local(), v8_str("[object " #expected "]")) \ 12932 .FromJust()); \ 12933 } while (0) 12934 12935 TEST_TOSTRINGTAG(Array, Object, Object); 12936 TEST_TOSTRINGTAG(Object, Arguments, Arguments); 12937 TEST_TOSTRINGTAG(Object, Array, Array); 12938 TEST_TOSTRINGTAG(Object, Boolean, Boolean); 12939 TEST_TOSTRINGTAG(Object, Date, Date); 12940 TEST_TOSTRINGTAG(Object, Error, Error); 12941 TEST_TOSTRINGTAG(Object, Function, Function); 12942 TEST_TOSTRINGTAG(Object, Number, Number); 12943 TEST_TOSTRINGTAG(Object, RegExp, RegExp); 12944 TEST_TOSTRINGTAG(Object, String, String); 12945 TEST_TOSTRINGTAG(Object, Foo, Foo); 12946 12947 #undef TEST_TOSTRINGTAG 12948 12949 Local<v8::RegExp> valueRegExp = 12950 v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone) 12951 .ToLocalChecked(); 12952 Local<Value> valueNumber = v8_num(123); 12953 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol"); 12954 Local<v8::Function> valueFunction = 12955 CompileRun("(function fn() {})").As<v8::Function>(); 12956 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent()); 12957 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent()); 12958 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent()); 12959 12960 #define TEST_TOSTRINGTAG(type, tagValue, expected) \ 12961 do { \ 12962 object = CompileRun("new " #type "()"); \ 12963 CHECK(object.As<v8::Object>() \ 12964 ->Set(context.local(), toStringTag, tagValue) \ 12965 .FromJust()); \ 12966 value = object.As<v8::Object>() \ 12967 ->ObjectProtoToString(context.local()) \ 12968 .ToLocalChecked(); \ 12969 CHECK(value->IsString() && \ 12970 value->Equals(context.local(), v8_str("[object " #expected "]")) \ 12971 .FromJust()); \ 12972 } while (0) 12973 12974 #define TEST_TOSTRINGTAG_TYPES(tagValue) \ 12975 TEST_TOSTRINGTAG(Array, tagValue, Array); \ 12976 TEST_TOSTRINGTAG(Object, tagValue, Object); \ 12977 TEST_TOSTRINGTAG(Function, tagValue, Function); \ 12978 TEST_TOSTRINGTAG(Date, tagValue, Date); \ 12979 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \ 12980 TEST_TOSTRINGTAG(Error, tagValue, Error); \ 12981 12982 // Test non-String-valued @@toStringTag 12983 TEST_TOSTRINGTAG_TYPES(valueRegExp); 12984 TEST_TOSTRINGTAG_TYPES(valueNumber); 12985 TEST_TOSTRINGTAG_TYPES(valueSymbol); 12986 TEST_TOSTRINGTAG_TYPES(valueFunction); 12987 TEST_TOSTRINGTAG_TYPES(valueObject); 12988 TEST_TOSTRINGTAG_TYPES(valueNull); 12989 TEST_TOSTRINGTAG_TYPES(valueUndef); 12990 12991 #undef TEST_TOSTRINGTAG 12992 #undef TEST_TOSTRINGTAG_TYPES 12993 12994 // @@toStringTag getter throws 12995 Local<Value> obj = v8::Object::New(isolate); 12996 obj.As<v8::Object>() 12997 ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter) 12998 .FromJust(); 12999 { 13000 TryCatch try_catch(isolate); 13001 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty()); 13002 CHECK(try_catch.HasCaught()); 13003 } 13004 13005 // @@toStringTag getter does not throw 13006 obj = v8::Object::New(isolate); 13007 obj.As<v8::Object>() 13008 ->SetAccessor(context.local(), toStringTag, 13009 SymbolAccessorGetterReturnsDefault, 0, v8_str("Test")) 13010 .FromJust(); 13011 { 13012 TryCatch try_catch(isolate); 13013 value = obj.As<v8::Object>() 13014 ->ObjectProtoToString(context.local()) 13015 .ToLocalChecked(); 13016 CHECK(value->IsString() && 13017 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13018 CHECK(!try_catch.HasCaught()); 13019 } 13020 13021 // JS @@toStringTag value 13022 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj"); 13023 { 13024 TryCatch try_catch(isolate); 13025 value = obj.As<v8::Object>() 13026 ->ObjectProtoToString(context.local()) 13027 .ToLocalChecked(); 13028 CHECK(value->IsString() && 13029 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13030 CHECK(!try_catch.HasCaught()); 13031 } 13032 13033 // JS @@toStringTag getter throws 13034 obj = CompileRun( 13035 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {" 13036 " get: function() { throw 'Test'; }" 13037 "}); obj"); 13038 { 13039 TryCatch try_catch(isolate); 13040 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty()); 13041 CHECK(try_catch.HasCaught()); 13042 } 13043 13044 // JS @@toStringTag getter does not throw 13045 obj = CompileRun( 13046 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {" 13047 " get: function() { return 'Test'; }" 13048 "}); obj"); 13049 { 13050 TryCatch try_catch(isolate); 13051 value = obj.As<v8::Object>() 13052 ->ObjectProtoToString(context.local()) 13053 .ToLocalChecked(); 13054 CHECK(value->IsString() && 13055 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13056 CHECK(!try_catch.HasCaught()); 13057 } 13058 } 13059 13060 13061 THREADED_TEST(ObjectGetConstructorName) { 13062 v8::Isolate* isolate = CcTest::isolate(); 13063 LocalContext context; 13064 v8::HandleScope scope(isolate); 13065 v8_compile( 13066 "function Parent() {};" 13067 "function Child() {};" 13068 "Child.prototype = new Parent();" 13069 "Child.prototype.constructor = Child;" 13070 "var outer = { inner: function() { } };" 13071 "var p = new Parent();" 13072 "var c = new Child();" 13073 "var x = new outer.inner();" 13074 "var proto = Child.prototype;") 13075 ->Run(context.local()) 13076 .ToLocalChecked(); 13077 13078 Local<v8::Value> p = 13079 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked(); 13080 CHECK(p->IsObject() && 13081 p->ToObject(context.local()) 13082 .ToLocalChecked() 13083 ->GetConstructorName() 13084 ->Equals(context.local(), v8_str("Parent")) 13085 .FromJust()); 13086 13087 Local<v8::Value> c = 13088 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked(); 13089 CHECK(c->IsObject() && 13090 c->ToObject(context.local()) 13091 .ToLocalChecked() 13092 ->GetConstructorName() 13093 ->Equals(context.local(), v8_str("Child")) 13094 .FromJust()); 13095 13096 Local<v8::Value> x = 13097 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked(); 13098 CHECK(x->IsObject() && 13099 x->ToObject(context.local()) 13100 .ToLocalChecked() 13101 ->GetConstructorName() 13102 ->Equals(context.local(), v8_str("outer.inner")) 13103 .FromJust()); 13104 13105 Local<v8::Value> child_prototype = 13106 context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked(); 13107 CHECK(child_prototype->IsObject() && 13108 child_prototype->ToObject(context.local()) 13109 .ToLocalChecked() 13110 ->GetConstructorName() 13111 ->Equals(context.local(), v8_str("Parent")) 13112 .FromJust()); 13113 } 13114 13115 13116 THREADED_TEST(SubclassGetConstructorName) { 13117 v8::Isolate* isolate = CcTest::isolate(); 13118 LocalContext context; 13119 v8::HandleScope scope(isolate); 13120 v8_compile( 13121 "\"use strict\";" 13122 "class Parent {}" 13123 "class Child extends Parent {}" 13124 "var p = new Parent();" 13125 "var c = new Child();") 13126 ->Run(context.local()) 13127 .ToLocalChecked(); 13128 13129 Local<v8::Value> p = 13130 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked(); 13131 CHECK(p->IsObject() && 13132 p->ToObject(context.local()) 13133 .ToLocalChecked() 13134 ->GetConstructorName() 13135 ->Equals(context.local(), v8_str("Parent")) 13136 .FromJust()); 13137 13138 Local<v8::Value> c = 13139 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked(); 13140 CHECK(c->IsObject() && 13141 c->ToObject(context.local()) 13142 .ToLocalChecked() 13143 ->GetConstructorName() 13144 ->Equals(context.local(), v8_str("Child")) 13145 .FromJust()); 13146 } 13147 13148 13149 bool ApiTestFuzzer::fuzzing_ = false; 13150 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0); 13151 int ApiTestFuzzer::active_tests_; 13152 int ApiTestFuzzer::tests_being_run_; 13153 int ApiTestFuzzer::current_; 13154 13155 13156 // We are in a callback and want to switch to another thread (if we 13157 // are currently running the thread fuzzing test). 13158 void ApiTestFuzzer::Fuzz() { 13159 if (!fuzzing_) return; 13160 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 13161 test->ContextSwitch(); 13162 } 13163 13164 13165 // Let the next thread go. Since it is also waiting on the V8 lock it may 13166 // not start immediately. 13167 bool ApiTestFuzzer::NextThread() { 13168 int test_position = GetNextTestNumber(); 13169 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 13170 if (test_position == current_) { 13171 if (kLogThreading) 13172 printf("Stay with %s\n", test_name); 13173 return false; 13174 } 13175 if (kLogThreading) { 13176 printf("Switch from %s to %s\n", 13177 test_name, 13178 RegisterThreadedTest::nth(test_position)->name()); 13179 } 13180 current_ = test_position; 13181 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal(); 13182 return true; 13183 } 13184 13185 13186 void ApiTestFuzzer::Run() { 13187 // When it is our turn... 13188 gate_.Wait(); 13189 { 13190 // ... get the V8 lock and start running the test. 13191 v8::Locker locker(CcTest::isolate()); 13192 CallTest(); 13193 } 13194 // This test finished. 13195 active_ = false; 13196 active_tests_--; 13197 // If it was the last then signal that fact. 13198 if (active_tests_ == 0) { 13199 all_tests_done_.Signal(); 13200 } else { 13201 // Otherwise select a new test and start that. 13202 NextThread(); 13203 } 13204 } 13205 13206 13207 static unsigned linear_congruential_generator; 13208 13209 13210 void ApiTestFuzzer::SetUp(PartOfTest part) { 13211 linear_congruential_generator = i::FLAG_testing_prng_seed; 13212 fuzzing_ = true; 13213 int count = RegisterThreadedTest::count(); 13214 int start = count * part / (LAST_PART + 1); 13215 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 13216 active_tests_ = tests_being_run_ = end - start + 1; 13217 for (int i = 0; i < tests_being_run_; i++) { 13218 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 13219 } 13220 for (int i = 0; i < active_tests_; i++) { 13221 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 13222 } 13223 } 13224 13225 13226 static void CallTestNumber(int test_number) { 13227 (RegisterThreadedTest::nth(test_number)->callback())(); 13228 } 13229 13230 13231 void ApiTestFuzzer::RunAllTests() { 13232 // Set off the first test. 13233 current_ = -1; 13234 NextThread(); 13235 // Wait till they are all done. 13236 all_tests_done_.Wait(); 13237 } 13238 13239 13240 int ApiTestFuzzer::GetNextTestNumber() { 13241 int next_test; 13242 do { 13243 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 13244 linear_congruential_generator *= 1664525u; 13245 linear_congruential_generator += 1013904223u; 13246 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 13247 return next_test; 13248 } 13249 13250 13251 void ApiTestFuzzer::ContextSwitch() { 13252 // If the new thread is the same as the current thread there is nothing to do. 13253 if (NextThread()) { 13254 // Now it can start. 13255 v8::Unlocker unlocker(CcTest::isolate()); 13256 // Wait till someone starts us again. 13257 gate_.Wait(); 13258 // And we're off. 13259 } 13260 } 13261 13262 13263 void ApiTestFuzzer::TearDown() { 13264 fuzzing_ = false; 13265 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 13266 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 13267 if (fuzzer != NULL) fuzzer->Join(); 13268 } 13269 } 13270 13271 13272 // Lets not be needlessly self-referential. 13273 TEST(Threading1) { 13274 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 13275 ApiTestFuzzer::RunAllTests(); 13276 ApiTestFuzzer::TearDown(); 13277 } 13278 13279 13280 TEST(Threading2) { 13281 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 13282 ApiTestFuzzer::RunAllTests(); 13283 ApiTestFuzzer::TearDown(); 13284 } 13285 13286 13287 TEST(Threading3) { 13288 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 13289 ApiTestFuzzer::RunAllTests(); 13290 ApiTestFuzzer::TearDown(); 13291 } 13292 13293 13294 TEST(Threading4) { 13295 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 13296 ApiTestFuzzer::RunAllTests(); 13297 ApiTestFuzzer::TearDown(); 13298 } 13299 13300 13301 void ApiTestFuzzer::CallTest() { 13302 v8::Isolate::Scope scope(CcTest::isolate()); 13303 if (kLogThreading) 13304 printf("Start test %d\n", test_number_); 13305 CallTestNumber(test_number_); 13306 if (kLogThreading) 13307 printf("End test %d\n", test_number_); 13308 } 13309 13310 13311 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 13312 v8::Isolate* isolate = args.GetIsolate(); 13313 CHECK(v8::Locker::IsLocked(isolate)); 13314 ApiTestFuzzer::Fuzz(); 13315 v8::Unlocker unlocker(isolate); 13316 const char* code = "throw 7;"; 13317 { 13318 v8::Locker nested_locker(isolate); 13319 v8::HandleScope scope(isolate); 13320 v8::Local<Value> exception; 13321 { 13322 v8::TryCatch try_catch(isolate); 13323 v8::Local<Value> value = CompileRun(code); 13324 CHECK(value.IsEmpty()); 13325 CHECK(try_catch.HasCaught()); 13326 // Make sure to wrap the exception in a new handle because 13327 // the handle returned from the TryCatch is destroyed 13328 // when the TryCatch is destroyed. 13329 exception = Local<Value>::New(isolate, try_catch.Exception()); 13330 } 13331 args.GetIsolate()->ThrowException(exception); 13332 } 13333 } 13334 13335 13336 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 13337 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13338 ApiTestFuzzer::Fuzz(); 13339 v8::Unlocker unlocker(CcTest::isolate()); 13340 const char* code = "throw 7;"; 13341 { 13342 v8::Locker nested_locker(CcTest::isolate()); 13343 v8::HandleScope scope(args.GetIsolate()); 13344 v8::Local<Value> value = CompileRun(code); 13345 CHECK(value.IsEmpty()); 13346 args.GetReturnValue().Set(v8_str("foo")); 13347 } 13348 } 13349 13350 13351 // These are locking tests that don't need to be run again 13352 // as part of the locking aggregation tests. 13353 TEST(NestedLockers) { 13354 v8::Isolate* isolate = CcTest::isolate(); 13355 v8::Locker locker(isolate); 13356 CHECK(v8::Locker::IsLocked(isolate)); 13357 LocalContext env; 13358 v8::HandleScope scope(env->GetIsolate()); 13359 Local<v8::FunctionTemplate> fun_templ = 13360 v8::FunctionTemplate::New(isolate, ThrowInJS); 13361 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13362 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust()); 13363 Local<Script> script = v8_compile("(function () {" 13364 " try {" 13365 " throw_in_js();" 13366 " return 42;" 13367 " } catch (e) {" 13368 " return e * 13;" 13369 " }" 13370 "})();"); 13371 CHECK_EQ(91, script->Run(env.local()) 13372 .ToLocalChecked() 13373 ->Int32Value(env.local()) 13374 .FromJust()); 13375 } 13376 13377 13378 // These are locking tests that don't need to be run again 13379 // as part of the locking aggregation tests. 13380 TEST(NestedLockersNoTryCatch) { 13381 v8::Locker locker(CcTest::isolate()); 13382 LocalContext env; 13383 v8::HandleScope scope(env->GetIsolate()); 13384 Local<v8::FunctionTemplate> fun_templ = 13385 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch); 13386 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13387 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust()); 13388 Local<Script> script = v8_compile("(function () {" 13389 " try {" 13390 " throw_in_js();" 13391 " return 42;" 13392 " } catch (e) {" 13393 " return e * 13;" 13394 " }" 13395 "})();"); 13396 CHECK_EQ(91, script->Run(env.local()) 13397 .ToLocalChecked() 13398 ->Int32Value(env.local()) 13399 .FromJust()); 13400 } 13401 13402 13403 THREADED_TEST(RecursiveLocking) { 13404 v8::Locker locker(CcTest::isolate()); 13405 { 13406 v8::Locker locker2(CcTest::isolate()); 13407 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13408 } 13409 } 13410 13411 13412 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 13413 ApiTestFuzzer::Fuzz(); 13414 v8::Unlocker unlocker(CcTest::isolate()); 13415 } 13416 13417 13418 THREADED_TEST(LockUnlockLock) { 13419 { 13420 v8::Locker locker(CcTest::isolate()); 13421 v8::HandleScope scope(CcTest::isolate()); 13422 LocalContext env; 13423 Local<v8::FunctionTemplate> fun_templ = 13424 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13425 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13426 CHECK(env->Global() 13427 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun) 13428 .FromJust()); 13429 Local<Script> script = v8_compile("(function () {" 13430 " unlock_for_a_moment();" 13431 " return 42;" 13432 "})();"); 13433 CHECK_EQ(42, script->Run(env.local()) 13434 .ToLocalChecked() 13435 ->Int32Value(env.local()) 13436 .FromJust()); 13437 } 13438 { 13439 v8::Locker locker(CcTest::isolate()); 13440 v8::HandleScope scope(CcTest::isolate()); 13441 LocalContext env; 13442 Local<v8::FunctionTemplate> fun_templ = 13443 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13444 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13445 CHECK(env->Global() 13446 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun) 13447 .FromJust()); 13448 Local<Script> script = v8_compile("(function () {" 13449 " unlock_for_a_moment();" 13450 " return 42;" 13451 "})();"); 13452 CHECK_EQ(42, script->Run(env.local()) 13453 .ToLocalChecked() 13454 ->Int32Value(env.local()) 13455 .FromJust()); 13456 } 13457 } 13458 13459 13460 static int GetGlobalObjectsCount() { 13461 int count = 0; 13462 i::HeapIterator it(CcTest::heap()); 13463 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 13464 if (object->IsJSGlobalObject()) { 13465 i::JSGlobalObject* g = i::JSGlobalObject::cast(object); 13466 // Skip dummy global object. 13467 if (i::GlobalDictionary::cast(g->properties())->NumberOfElements() != 0) { 13468 count++; 13469 } 13470 } 13471 return count; 13472 } 13473 13474 13475 static void CheckSurvivingGlobalObjectsCount(int expected) { 13476 // We need to collect all garbage twice to be sure that everything 13477 // has been collected. This is because inline caches are cleared in 13478 // the first garbage collection but some of the maps have already 13479 // been marked at that point. Therefore some of the maps are not 13480 // collected until the second garbage collection. 13481 CcTest::heap()->CollectAllGarbage(); 13482 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 13483 int count = GetGlobalObjectsCount(); 13484 #ifdef DEBUG 13485 if (count != expected) CcTest::heap()->TracePathToGlobal(); 13486 #endif 13487 CHECK_EQ(expected, count); 13488 } 13489 13490 13491 TEST(DontLeakGlobalObjects) { 13492 // Regression test for issues 1139850 and 1174891. 13493 13494 i::FLAG_expose_gc = true; 13495 v8::V8::Initialize(); 13496 13497 for (int i = 0; i < 5; i++) { 13498 { v8::HandleScope scope(CcTest::isolate()); 13499 LocalContext context; 13500 } 13501 CcTest::isolate()->ContextDisposedNotification(); 13502 CheckSurvivingGlobalObjectsCount(0); 13503 13504 { v8::HandleScope scope(CcTest::isolate()); 13505 LocalContext context; 13506 v8_compile("Date")->Run(context.local()).ToLocalChecked(); 13507 } 13508 CcTest::isolate()->ContextDisposedNotification(); 13509 CheckSurvivingGlobalObjectsCount(0); 13510 13511 { v8::HandleScope scope(CcTest::isolate()); 13512 LocalContext context; 13513 v8_compile("/aaa/")->Run(context.local()).ToLocalChecked(); 13514 } 13515 CcTest::isolate()->ContextDisposedNotification(); 13516 CheckSurvivingGlobalObjectsCount(0); 13517 13518 { v8::HandleScope scope(CcTest::isolate()); 13519 const char* extension_list[] = { "v8/gc" }; 13520 v8::ExtensionConfiguration extensions(1, extension_list); 13521 LocalContext context(&extensions); 13522 v8_compile("gc();")->Run(context.local()).ToLocalChecked(); 13523 } 13524 CcTest::isolate()->ContextDisposedNotification(); 13525 CheckSurvivingGlobalObjectsCount(0); 13526 } 13527 } 13528 13529 13530 TEST(CopyablePersistent) { 13531 LocalContext context; 13532 v8::Isolate* isolate = context->GetIsolate(); 13533 i::GlobalHandles* globals = 13534 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13535 int initial_handles = globals->global_handles_count(); 13536 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > 13537 CopyableObject; 13538 { 13539 CopyableObject handle1; 13540 { 13541 v8::HandleScope scope(isolate); 13542 handle1.Reset(isolate, v8::Object::New(isolate)); 13543 } 13544 CHECK_EQ(initial_handles + 1, globals->global_handles_count()); 13545 CopyableObject handle2; 13546 handle2 = handle1; 13547 CHECK(handle1 == handle2); 13548 CHECK_EQ(initial_handles + 2, globals->global_handles_count()); 13549 CopyableObject handle3(handle2); 13550 CHECK(handle1 == handle3); 13551 CHECK_EQ(initial_handles + 3, globals->global_handles_count()); 13552 } 13553 // Verify autodispose 13554 CHECK_EQ(initial_handles, globals->global_handles_count()); 13555 } 13556 13557 13558 static void WeakApiCallback( 13559 const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) { 13560 data.GetParameter()->Reset(); 13561 delete data.GetParameter(); 13562 } 13563 13564 13565 TEST(WeakCallbackApi) { 13566 LocalContext context; 13567 v8::Isolate* isolate = context->GetIsolate(); 13568 i::GlobalHandles* globals = 13569 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13570 int initial_handles = globals->global_handles_count(); 13571 { 13572 v8::HandleScope scope(isolate); 13573 v8::Local<v8::Object> obj = v8::Object::New(isolate); 13574 CHECK( 13575 obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231)) 13576 .FromJust()); 13577 v8::Persistent<v8::Object>* handle = 13578 new v8::Persistent<v8::Object>(isolate, obj); 13579 handle->SetWeak<v8::Persistent<v8::Object>>( 13580 handle, WeakApiCallback, v8::WeakCallbackType::kParameter); 13581 } 13582 reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage( 13583 i::Heap::kAbortIncrementalMarkingMask); 13584 // Verify disposed. 13585 CHECK_EQ(initial_handles, globals->global_handles_count()); 13586 } 13587 13588 13589 v8::Persistent<v8::Object> some_object; 13590 v8::Persistent<v8::Object> bad_handle; 13591 13592 13593 void NewPersistentHandleCallback2( 13594 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13595 v8::HandleScope scope(data.GetIsolate()); 13596 bad_handle.Reset(data.GetIsolate(), some_object); 13597 } 13598 13599 13600 void NewPersistentHandleCallback1( 13601 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13602 data.GetParameter()->Reset(); 13603 data.SetSecondPassCallback(NewPersistentHandleCallback2); 13604 } 13605 13606 13607 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 13608 LocalContext context; 13609 v8::Isolate* isolate = context->GetIsolate(); 13610 13611 v8::Persistent<v8::Object> handle1, handle2; 13612 { 13613 v8::HandleScope scope(isolate); 13614 some_object.Reset(isolate, v8::Object::New(isolate)); 13615 handle1.Reset(isolate, v8::Object::New(isolate)); 13616 handle2.Reset(isolate, v8::Object::New(isolate)); 13617 } 13618 // Note: order is implementation dependent alas: currently 13619 // global handle nodes are processed by PostGarbageCollectionProcessing 13620 // in reverse allocation order, so if second allocated handle is deleted, 13621 // weak callback of the first handle would be able to 'reallocate' it. 13622 handle1.SetWeak(&handle1, NewPersistentHandleCallback1, 13623 v8::WeakCallbackType::kParameter); 13624 handle2.Reset(); 13625 CcTest::heap()->CollectAllGarbage(); 13626 } 13627 13628 13629 v8::Persistent<v8::Object> to_be_disposed; 13630 13631 13632 void DisposeAndForceGcCallback2( 13633 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13634 to_be_disposed.Reset(); 13635 CcTest::heap()->CollectAllGarbage(); 13636 } 13637 13638 13639 void DisposeAndForceGcCallback1( 13640 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13641 data.GetParameter()->Reset(); 13642 data.SetSecondPassCallback(DisposeAndForceGcCallback2); 13643 } 13644 13645 13646 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 13647 LocalContext context; 13648 v8::Isolate* isolate = context->GetIsolate(); 13649 13650 v8::Persistent<v8::Object> handle1, handle2; 13651 { 13652 v8::HandleScope scope(isolate); 13653 handle1.Reset(isolate, v8::Object::New(isolate)); 13654 handle2.Reset(isolate, v8::Object::New(isolate)); 13655 } 13656 handle1.SetWeak(&handle1, DisposeAndForceGcCallback1, 13657 v8::WeakCallbackType::kParameter); 13658 to_be_disposed.Reset(isolate, handle2); 13659 CcTest::heap()->CollectAllGarbage(); 13660 } 13661 13662 void DisposingCallback( 13663 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13664 data.GetParameter()->Reset(); 13665 } 13666 13667 void HandleCreatingCallback2( 13668 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13669 v8::HandleScope scope(data.GetIsolate()); 13670 v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate())); 13671 } 13672 13673 13674 void HandleCreatingCallback1( 13675 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 13676 data.GetParameter()->Reset(); 13677 data.SetSecondPassCallback(HandleCreatingCallback2); 13678 } 13679 13680 13681 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 13682 v8::Locker locker(CcTest::isolate()); 13683 LocalContext context; 13684 v8::Isolate* isolate = context->GetIsolate(); 13685 13686 v8::Persistent<v8::Object> handle1, handle2, handle3; 13687 { 13688 v8::HandleScope scope(isolate); 13689 handle3.Reset(isolate, v8::Object::New(isolate)); 13690 handle2.Reset(isolate, v8::Object::New(isolate)); 13691 handle1.Reset(isolate, v8::Object::New(isolate)); 13692 } 13693 handle2.SetWeak(&handle2, DisposingCallback, 13694 v8::WeakCallbackType::kParameter); 13695 handle3.SetWeak(&handle3, HandleCreatingCallback1, 13696 v8::WeakCallbackType::kParameter); 13697 CcTest::heap()->CollectAllGarbage(); 13698 EmptyMessageQueues(isolate); 13699 } 13700 13701 13702 THREADED_TEST(CheckForCrossContextObjectLiterals) { 13703 v8::V8::Initialize(); 13704 13705 const int nof = 2; 13706 const char* sources[nof] = { 13707 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 13708 "Object()" 13709 }; 13710 13711 for (int i = 0; i < nof; i++) { 13712 const char* source = sources[i]; 13713 { v8::HandleScope scope(CcTest::isolate()); 13714 LocalContext context; 13715 CompileRun(source); 13716 } 13717 { v8::HandleScope scope(CcTest::isolate()); 13718 LocalContext context; 13719 CompileRun(source); 13720 } 13721 } 13722 } 13723 13724 13725 static v8::Local<Value> NestedScope(v8::Local<Context> env) { 13726 v8::EscapableHandleScope inner(env->GetIsolate()); 13727 env->Enter(); 13728 v8::Local<Value> three = v8_num(3); 13729 v8::Local<Value> value = inner.Escape(three); 13730 env->Exit(); 13731 return value; 13732 } 13733 13734 13735 THREADED_TEST(NestedHandleScopeAndContexts) { 13736 v8::Isolate* isolate = CcTest::isolate(); 13737 v8::HandleScope outer(isolate); 13738 v8::Local<Context> env = Context::New(isolate); 13739 env->Enter(); 13740 v8::Local<Value> value = NestedScope(env); 13741 v8::Local<String> str(value->ToString(env).ToLocalChecked()); 13742 CHECK(!str.IsEmpty()); 13743 env->Exit(); 13744 } 13745 13746 13747 static bool MatchPointers(void* key1, void* key2) { 13748 return key1 == key2; 13749 } 13750 13751 13752 struct SymbolInfo { 13753 size_t id; 13754 size_t size; 13755 std::string name; 13756 }; 13757 13758 13759 class SetFunctionEntryHookTest { 13760 public: 13761 SetFunctionEntryHookTest() { 13762 CHECK(instance_ == NULL); 13763 instance_ = this; 13764 } 13765 ~SetFunctionEntryHookTest() { 13766 CHECK(instance_ == this); 13767 instance_ = NULL; 13768 } 13769 void Reset() { 13770 symbols_.clear(); 13771 symbol_locations_.clear(); 13772 invocations_.clear(); 13773 } 13774 void RunTest(); 13775 void OnJitEvent(const v8::JitCodeEvent* event); 13776 static void JitEvent(const v8::JitCodeEvent* event) { 13777 CHECK(instance_ != NULL); 13778 instance_->OnJitEvent(event); 13779 } 13780 13781 void OnEntryHook(uintptr_t function, 13782 uintptr_t return_addr_location); 13783 static void EntryHook(uintptr_t function, 13784 uintptr_t return_addr_location) { 13785 CHECK(instance_ != NULL); 13786 instance_->OnEntryHook(function, return_addr_location); 13787 } 13788 13789 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 13790 CHECK(instance_ != NULL); 13791 args.GetReturnValue().Set(v8_num(42)); 13792 } 13793 void RunLoopInNewEnv(v8::Isolate* isolate); 13794 13795 // Records addr as location of symbol. 13796 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 13797 13798 // Finds the symbol containing addr 13799 SymbolInfo* FindSymbolForAddr(i::Address addr); 13800 // Returns the number of invocations where the caller name contains 13801 // \p caller_name and the function name contains \p function_name. 13802 int CountInvocations(const char* caller_name, 13803 const char* function_name); 13804 13805 i::Handle<i::JSFunction> foo_func_; 13806 i::Handle<i::JSFunction> bar_func_; 13807 13808 typedef std::map<size_t, SymbolInfo> SymbolMap; 13809 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 13810 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 13811 SymbolMap symbols_; 13812 SymbolLocationMap symbol_locations_; 13813 InvocationMap invocations_; 13814 13815 static SetFunctionEntryHookTest* instance_; 13816 }; 13817 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 13818 13819 13820 // Returns true if addr is in the range [start, start+len). 13821 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 13822 if (start <= addr && start + len > addr) 13823 return true; 13824 13825 return false; 13826 } 13827 13828 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 13829 SymbolInfo* symbol) { 13830 // Insert the symbol at the new location. 13831 SymbolLocationMap::iterator it = 13832 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 13833 // Now erase symbols to the left and right that overlap this one. 13834 while (it != symbol_locations_.begin()) { 13835 SymbolLocationMap::iterator left = it; 13836 --left; 13837 if (!Overlaps(left->first, left->second->size, addr)) 13838 break; 13839 symbol_locations_.erase(left); 13840 } 13841 13842 // Now erase symbols to the left and right that overlap this one. 13843 while (true) { 13844 SymbolLocationMap::iterator right = it; 13845 ++right; 13846 if (right == symbol_locations_.end()) 13847 break; 13848 if (!Overlaps(addr, symbol->size, right->first)) 13849 break; 13850 symbol_locations_.erase(right); 13851 } 13852 } 13853 13854 13855 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 13856 switch (event->type) { 13857 case v8::JitCodeEvent::CODE_ADDED: { 13858 CHECK(event->code_start != NULL); 13859 CHECK_NE(0, static_cast<int>(event->code_len)); 13860 CHECK(event->name.str != NULL); 13861 size_t symbol_id = symbols_.size(); 13862 13863 // Record the new symbol. 13864 SymbolInfo& info = symbols_[symbol_id]; 13865 info.id = symbol_id; 13866 info.size = event->code_len; 13867 info.name.assign(event->name.str, event->name.str + event->name.len); 13868 13869 // And record it's location. 13870 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 13871 } 13872 break; 13873 13874 case v8::JitCodeEvent::CODE_MOVED: { 13875 // We would like to never see code move that we haven't seen before, 13876 // but the code creation event does not happen until the line endings 13877 // have been calculated (this is so that we can report the line in the 13878 // script at which the function source is found, see 13879 // Compiler::RecordFunctionCompilation) and the line endings 13880 // calculations can cause a GC, which can move the newly created code 13881 // before its existence can be logged. 13882 SymbolLocationMap::iterator it( 13883 symbol_locations_.find( 13884 reinterpret_cast<i::Address>(event->code_start))); 13885 if (it != symbol_locations_.end()) { 13886 // Found a symbol at this location, move it. 13887 SymbolInfo* info = it->second; 13888 symbol_locations_.erase(it); 13889 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 13890 info); 13891 } 13892 } 13893 default: 13894 break; 13895 } 13896 } 13897 13898 void SetFunctionEntryHookTest::OnEntryHook( 13899 uintptr_t function, uintptr_t return_addr_location) { 13900 // Get the function's code object. 13901 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 13902 reinterpret_cast<i::Address>(function)); 13903 CHECK(function_code != NULL); 13904 13905 // Then try and look up the caller's code object. 13906 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 13907 13908 // Count the invocation. 13909 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 13910 SymbolInfo* function_symbol = 13911 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 13912 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 13913 13914 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 13915 // Check that we have a symbol for the "bar" function at the right location. 13916 SymbolLocationMap::iterator it( 13917 symbol_locations_.find(function_code->instruction_start())); 13918 CHECK(it != symbol_locations_.end()); 13919 } 13920 13921 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 13922 // Check that we have a symbol for "foo" at the right location. 13923 SymbolLocationMap::iterator it( 13924 symbol_locations_.find(function_code->instruction_start())); 13925 CHECK(it != symbol_locations_.end()); 13926 } 13927 } 13928 13929 13930 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 13931 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 13932 // Do we have a direct hit on a symbol? 13933 if (it != symbol_locations_.end()) { 13934 if (it->first == addr) 13935 return it->second; 13936 } 13937 13938 // If not a direct hit, it'll have to be the previous symbol. 13939 if (it == symbol_locations_.begin()) 13940 return NULL; 13941 13942 --it; 13943 size_t offs = addr - it->first; 13944 if (offs < it->second->size) 13945 return it->second; 13946 13947 return NULL; 13948 } 13949 13950 13951 int SetFunctionEntryHookTest::CountInvocations( 13952 const char* caller_name, const char* function_name) { 13953 InvocationMap::iterator it(invocations_.begin()); 13954 int invocations = 0; 13955 for (; it != invocations_.end(); ++it) { 13956 SymbolInfo* caller = it->first.first; 13957 SymbolInfo* function = it->first.second; 13958 13959 // Filter out non-matching functions. 13960 if (function_name != NULL) { 13961 if (function->name.find(function_name) == std::string::npos) 13962 continue; 13963 } 13964 13965 // Filter out non-matching callers. 13966 if (caller_name != NULL) { 13967 if (caller == NULL) 13968 continue; 13969 if (caller->name.find(caller_name) == std::string::npos) 13970 continue; 13971 } 13972 13973 // It matches add the invocation count to the tally. 13974 invocations += it->second; 13975 } 13976 13977 return invocations; 13978 } 13979 13980 13981 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 13982 v8::HandleScope outer(isolate); 13983 v8::Local<Context> env = Context::New(isolate); 13984 env->Enter(); 13985 13986 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 13987 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback)); 13988 CHECK(env->Global() 13989 ->Set(env, v8_str("obj"), t->NewInstance(env).ToLocalChecked()) 13990 .FromJust()); 13991 13992 const char* script = 13993 "function bar() {\n" 13994 " var sum = 0;\n" 13995 " for (i = 0; i < 100; ++i)\n" 13996 " sum = foo(i);\n" 13997 " return sum;\n" 13998 "}\n" 13999 "function foo(i) { return i * i; }\n" 14000 "// Invoke on the runtime function.\n" 14001 "obj.asdf()"; 14002 CompileRun(script); 14003 bar_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle( 14004 *env->Global()->Get(env, v8_str("bar")).ToLocalChecked())); 14005 CHECK(!bar_func_.is_null()); 14006 14007 foo_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle( 14008 *env->Global()->Get(env, v8_str("foo")).ToLocalChecked())); 14009 CHECK(!foo_func_.is_null()); 14010 14011 v8::Local<v8::Value> value = CompileRun("bar();"); 14012 CHECK(value->IsNumber()); 14013 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14014 14015 // Test the optimized codegen path. 14016 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 14017 "bar();"); 14018 CHECK(value->IsNumber()); 14019 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14020 14021 env->Exit(); 14022 } 14023 14024 14025 void SetFunctionEntryHookTest::RunTest() { 14026 // Work in a new isolate throughout. 14027 v8::Isolate::CreateParams create_params; 14028 create_params.entry_hook = EntryHook; 14029 create_params.code_event_handler = JitEvent; 14030 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14031 v8::Isolate* isolate = v8::Isolate::New(create_params); 14032 14033 { 14034 v8::Isolate::Scope scope(isolate); 14035 14036 RunLoopInNewEnv(isolate); 14037 14038 // Check the exepected invocation counts. 14039 CHECK_EQ(2, CountInvocations(NULL, "bar")); 14040 CHECK_EQ(200, CountInvocations("bar", "foo")); 14041 CHECK_EQ(200, CountInvocations(NULL, "foo")); 14042 14043 // Verify that we have an entry hook on some specific stubs. 14044 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 14045 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 14046 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 14047 } 14048 isolate->Dispose(); 14049 14050 Reset(); 14051 14052 // Make sure a second isolate is unaffected by the previous entry hook. 14053 create_params = v8::Isolate::CreateParams(); 14054 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14055 isolate = v8::Isolate::New(create_params); 14056 { 14057 v8::Isolate::Scope scope(isolate); 14058 14059 // Reset the entry count to zero and set the entry hook. 14060 RunLoopInNewEnv(isolate); 14061 14062 // We should record no invocations in this isolate. 14063 CHECK_EQ(0, static_cast<int>(invocations_.size())); 14064 } 14065 14066 isolate->Dispose(); 14067 } 14068 14069 14070 TEST(SetFunctionEntryHook) { 14071 // FunctionEntryHook does not work well with experimental natives. 14072 // Experimental natives are compiled during snapshot deserialization. 14073 // This test breaks because InstallGetter (function from snapshot that 14074 // only gets called from experimental natives) is compiled with entry hooks. 14075 i::FLAG_allow_natives_syntax = true; 14076 i::FLAG_turbo_inlining = false; 14077 i::FLAG_use_inlining = false; 14078 14079 SetFunctionEntryHookTest test; 14080 test.RunTest(); 14081 } 14082 14083 14084 static i::HashMap* code_map = NULL; 14085 static i::HashMap* jitcode_line_info = NULL; 14086 static int saw_bar = 0; 14087 static int move_events = 0; 14088 14089 14090 static bool FunctionNameIs(const char* expected, 14091 const v8::JitCodeEvent* event) { 14092 // Log lines for functions are of the general form: 14093 // "LazyCompile:<type><function_name>", where the type is one of 14094 // "*", "~" or "". 14095 static const char kPreamble[] = "LazyCompile:"; 14096 static size_t kPreambleLen = sizeof(kPreamble) - 1; 14097 14098 if (event->name.len < sizeof(kPreamble) - 1 || 14099 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 14100 return false; 14101 } 14102 14103 const char* tail = event->name.str + kPreambleLen; 14104 size_t tail_len = event->name.len - kPreambleLen; 14105 size_t expected_len = strlen(expected); 14106 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 14107 --tail_len; 14108 ++tail; 14109 } 14110 14111 // Check for tails like 'bar :1'. 14112 if (tail_len > expected_len + 2 && 14113 tail[expected_len] == ' ' && 14114 tail[expected_len + 1] == ':' && 14115 tail[expected_len + 2] && 14116 !strncmp(tail, expected, expected_len)) { 14117 return true; 14118 } 14119 14120 if (tail_len != expected_len) 14121 return false; 14122 14123 return strncmp(tail, expected, expected_len) == 0; 14124 } 14125 14126 14127 static void event_handler(const v8::JitCodeEvent* event) { 14128 CHECK(event != NULL); 14129 CHECK(code_map != NULL); 14130 CHECK(jitcode_line_info != NULL); 14131 14132 class DummyJitCodeLineInfo { 14133 }; 14134 14135 switch (event->type) { 14136 case v8::JitCodeEvent::CODE_ADDED: { 14137 CHECK(event->code_start != NULL); 14138 CHECK_NE(0, static_cast<int>(event->code_len)); 14139 CHECK(event->name.str != NULL); 14140 i::HashMap::Entry* entry = code_map->LookupOrInsert( 14141 event->code_start, i::ComputePointerHash(event->code_start)); 14142 entry->value = reinterpret_cast<void*>(event->code_len); 14143 14144 if (FunctionNameIs("bar", event)) { 14145 ++saw_bar; 14146 } 14147 } 14148 break; 14149 14150 case v8::JitCodeEvent::CODE_MOVED: { 14151 uint32_t hash = i::ComputePointerHash(event->code_start); 14152 // We would like to never see code move that we haven't seen before, 14153 // but the code creation event does not happen until the line endings 14154 // have been calculated (this is so that we can report the line in the 14155 // script at which the function source is found, see 14156 // Compiler::RecordFunctionCompilation) and the line endings 14157 // calculations can cause a GC, which can move the newly created code 14158 // before its existence can be logged. 14159 i::HashMap::Entry* entry = code_map->Lookup(event->code_start, hash); 14160 if (entry != NULL) { 14161 ++move_events; 14162 14163 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 14164 code_map->Remove(event->code_start, hash); 14165 14166 entry = code_map->LookupOrInsert( 14167 event->new_code_start, 14168 i::ComputePointerHash(event->new_code_start)); 14169 entry->value = reinterpret_cast<void*>(event->code_len); 14170 } 14171 } 14172 break; 14173 14174 case v8::JitCodeEvent::CODE_REMOVED: 14175 // Object/code removal events are currently not dispatched from the GC. 14176 CHECK(false); 14177 break; 14178 14179 // For CODE_START_LINE_INFO_RECORDING event, we will create one 14180 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 14181 // record it in jitcode_line_info. 14182 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 14183 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 14184 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 14185 temp_event->user_data = line_info; 14186 i::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert( 14187 line_info, i::ComputePointerHash(line_info)); 14188 entry->value = reinterpret_cast<void*>(line_info); 14189 } 14190 break; 14191 // For these two events, we will check whether the event->user_data 14192 // data structure is created before during CODE_START_LINE_INFO_RECORDING 14193 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 14194 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 14195 CHECK(event->user_data != NULL); 14196 uint32_t hash = i::ComputePointerHash(event->user_data); 14197 i::HashMap::Entry* entry = 14198 jitcode_line_info->Lookup(event->user_data, hash); 14199 CHECK(entry != NULL); 14200 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 14201 } 14202 break; 14203 14204 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 14205 CHECK(event->user_data != NULL); 14206 uint32_t hash = i::ComputePointerHash(event->user_data); 14207 i::HashMap::Entry* entry = 14208 jitcode_line_info->Lookup(event->user_data, hash); 14209 CHECK(entry != NULL); 14210 } 14211 break; 14212 14213 default: 14214 // Impossible event. 14215 CHECK(false); 14216 break; 14217 } 14218 } 14219 14220 14221 UNINITIALIZED_TEST(SetJitCodeEventHandler) { 14222 i::FLAG_stress_compaction = true; 14223 i::FLAG_incremental_marking = false; 14224 if (i::FLAG_never_compact) return; 14225 const char* script = 14226 "function bar() {" 14227 " var sum = 0;" 14228 " for (i = 0; i < 10; ++i)" 14229 " sum = foo(i);" 14230 " return sum;" 14231 "}" 14232 "function foo(i) { return i; };" 14233 "bar();"; 14234 14235 // Run this test in a new isolate to make sure we don't 14236 // have remnants of state from other code. 14237 v8::Isolate::CreateParams create_params; 14238 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14239 v8::Isolate* isolate = v8::Isolate::New(create_params); 14240 isolate->Enter(); 14241 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 14242 i::Heap* heap = i_isolate->heap(); 14243 14244 // Start with a clean slate. 14245 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare"); 14246 14247 { 14248 v8::HandleScope scope(isolate); 14249 i::HashMap code(MatchPointers); 14250 code_map = &code; 14251 14252 i::HashMap lineinfo(MatchPointers); 14253 jitcode_line_info = &lineinfo; 14254 14255 saw_bar = 0; 14256 move_events = 0; 14257 14258 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 14259 14260 // Generate new code objects sparsely distributed across several 14261 // different fragmented code-space pages. 14262 const int kIterations = 10; 14263 for (int i = 0; i < kIterations; ++i) { 14264 LocalContext env(isolate); 14265 i::AlwaysAllocateScope always_allocate(i_isolate); 14266 SimulateFullSpace(heap->code_space()); 14267 CompileRun(script); 14268 14269 // Keep a strong reference to the code object in the handle scope. 14270 i::Handle<i::Code> bar_code( 14271 i::Handle<i::JSFunction>::cast( 14272 v8::Utils::OpenHandle(*env->Global() 14273 ->Get(env.local(), v8_str("bar")) 14274 .ToLocalChecked())) 14275 ->code()); 14276 i::Handle<i::Code> foo_code( 14277 i::Handle<i::JSFunction>::cast( 14278 v8::Utils::OpenHandle(*env->Global() 14279 ->Get(env.local(), v8_str("foo")) 14280 .ToLocalChecked())) 14281 ->code()); 14282 14283 // Clear the compilation cache to get more wastage. 14284 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear(); 14285 } 14286 14287 // Force code movement. 14288 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move"); 14289 14290 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14291 14292 CHECK_LE(kIterations, saw_bar); 14293 CHECK_LT(0, move_events); 14294 14295 code_map = NULL; 14296 jitcode_line_info = NULL; 14297 } 14298 14299 isolate->Exit(); 14300 isolate->Dispose(); 14301 14302 // Do this in a new isolate. 14303 isolate = v8::Isolate::New(create_params); 14304 isolate->Enter(); 14305 14306 // Verify that we get callbacks for existing code objects when we 14307 // request enumeration of existing code. 14308 { 14309 v8::HandleScope scope(isolate); 14310 LocalContext env(isolate); 14311 CompileRun(script); 14312 14313 // Now get code through initial iteration. 14314 i::HashMap code(MatchPointers); 14315 code_map = &code; 14316 14317 i::HashMap lineinfo(MatchPointers); 14318 jitcode_line_info = &lineinfo; 14319 14320 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, 14321 event_handler); 14322 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14323 14324 jitcode_line_info = NULL; 14325 // We expect that we got some events. Note that if we could get code removal 14326 // notifications, we could compare two collections, one created by listening 14327 // from the time of creation of an isolate, and the other by subscribing 14328 // with EnumExisting. 14329 CHECK_LT(0u, code.occupancy()); 14330 14331 code_map = NULL; 14332 } 14333 14334 isolate->Exit(); 14335 isolate->Dispose(); 14336 } 14337 14338 14339 THREADED_TEST(ExternalAllocatedMemory) { 14340 v8::Isolate* isolate = CcTest::isolate(); 14341 v8::HandleScope outer(isolate); 14342 v8::Local<Context> env(Context::New(isolate)); 14343 CHECK(!env.IsEmpty()); 14344 const int64_t kSize = 1024*1024; 14345 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0); 14346 CHECK_EQ(baseline + kSize, 14347 isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); 14348 CHECK_EQ(baseline, 14349 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); 14350 const int64_t kTriggerGCSize = 14351 v8::internal::Internals::kExternalAllocationLimit + 1; 14352 CHECK_EQ(baseline + kTriggerGCSize, 14353 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize)); 14354 CHECK_EQ(baseline, 14355 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize)); 14356 } 14357 14358 14359 TEST(Regress51719) { 14360 i::FLAG_incremental_marking = false; 14361 CcTest::InitializeVM(); 14362 14363 const int64_t kTriggerGCSize = 14364 v8::internal::Internals::kExternalAllocationLimit + 1; 14365 v8::Isolate* isolate = CcTest::isolate(); 14366 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize); 14367 } 14368 14369 14370 // Regression test for issue 54, object templates with internal fields 14371 // but no accessors or interceptors did not get their internal field 14372 // count set on instances. 14373 THREADED_TEST(Regress54) { 14374 LocalContext context; 14375 v8::Isolate* isolate = context->GetIsolate(); 14376 v8::HandleScope outer(isolate); 14377 static v8::Persistent<v8::ObjectTemplate> templ; 14378 if (templ.IsEmpty()) { 14379 v8::EscapableHandleScope inner(isolate); 14380 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate); 14381 local->SetInternalFieldCount(1); 14382 templ.Reset(isolate, inner.Escape(local)); 14383 } 14384 v8::Local<v8::Object> result = 14385 v8::Local<v8::ObjectTemplate>::New(isolate, templ) 14386 ->NewInstance(context.local()) 14387 .ToLocalChecked(); 14388 CHECK_EQ(1, result->InternalFieldCount()); 14389 } 14390 14391 14392 // If part of the threaded tests, this test makes ThreadingTest fail 14393 // on mac. 14394 TEST(CatchStackOverflow) { 14395 LocalContext context; 14396 v8::HandleScope scope(context->GetIsolate()); 14397 v8::TryCatch try_catch(context->GetIsolate()); 14398 v8::Local<v8::Value> result = CompileRun( 14399 "function f() {" 14400 " return f();" 14401 "}" 14402 "" 14403 "f();"); 14404 CHECK(result.IsEmpty()); 14405 } 14406 14407 14408 static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script, 14409 const char* resource_name, 14410 int line_offset) { 14411 v8::HandleScope scope(CcTest::isolate()); 14412 v8::TryCatch try_catch(CcTest::isolate()); 14413 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 14414 CHECK(script->Run(context).IsEmpty()); 14415 CHECK(try_catch.HasCaught()); 14416 v8::Local<v8::Message> message = try_catch.Message(); 14417 CHECK(!message.IsEmpty()); 14418 CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust()); 14419 CHECK_EQ(91, message->GetStartPosition()); 14420 CHECK_EQ(92, message->GetEndPosition()); 14421 CHECK_EQ(2, message->GetStartColumn(context).FromJust()); 14422 CHECK_EQ(3, message->GetEndColumn(context).FromJust()); 14423 v8::String::Utf8Value line(message->GetSourceLine(context).ToLocalChecked()); 14424 CHECK_EQ(0, strcmp(" throw 'nirk';", *line)); 14425 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 14426 CHECK_EQ(0, strcmp(resource_name, *name)); 14427 } 14428 14429 14430 THREADED_TEST(TryCatchSourceInfo) { 14431 LocalContext context; 14432 v8::HandleScope scope(context->GetIsolate()); 14433 v8::Local<v8::String> source = v8_str( 14434 "function Foo() {\n" 14435 " return Bar();\n" 14436 "}\n" 14437 "\n" 14438 "function Bar() {\n" 14439 " return Baz();\n" 14440 "}\n" 14441 "\n" 14442 "function Baz() {\n" 14443 " throw 'nirk';\n" 14444 "}\n" 14445 "\n" 14446 "Foo();\n"); 14447 14448 const char* resource_name; 14449 v8::Local<v8::Script> script; 14450 resource_name = "test.js"; 14451 script = CompileWithOrigin(source, resource_name); 14452 CheckTryCatchSourceInfo(script, resource_name, 0); 14453 14454 resource_name = "test1.js"; 14455 v8::ScriptOrigin origin1(v8_str(resource_name)); 14456 script = 14457 v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked(); 14458 CheckTryCatchSourceInfo(script, resource_name, 0); 14459 14460 resource_name = "test2.js"; 14461 v8::ScriptOrigin origin2(v8_str(resource_name), 14462 v8::Integer::New(context->GetIsolate(), 7)); 14463 script = 14464 v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked(); 14465 CheckTryCatchSourceInfo(script, resource_name, 7); 14466 } 14467 14468 14469 THREADED_TEST(TryCatchSourceInfoForEOSError) { 14470 LocalContext context; 14471 v8::HandleScope scope(context->GetIsolate()); 14472 v8::TryCatch try_catch(context->GetIsolate()); 14473 CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty()); 14474 CHECK(try_catch.HasCaught()); 14475 v8::Local<v8::Message> message = try_catch.Message(); 14476 CHECK_EQ(1, message->GetLineNumber(context.local()).FromJust()); 14477 CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust()); 14478 } 14479 14480 14481 THREADED_TEST(CompilationCache) { 14482 LocalContext context; 14483 v8::HandleScope scope(context->GetIsolate()); 14484 v8::Local<v8::String> source0 = v8_str("1234"); 14485 v8::Local<v8::String> source1 = v8_str("1234"); 14486 v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js"); 14487 v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js"); 14488 v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0) 14489 .ToLocalChecked(); // different origin 14490 CHECK_EQ(1234, script0->Run(context.local()) 14491 .ToLocalChecked() 14492 ->Int32Value(context.local()) 14493 .FromJust()); 14494 CHECK_EQ(1234, script1->Run(context.local()) 14495 .ToLocalChecked() 14496 ->Int32Value(context.local()) 14497 .FromJust()); 14498 CHECK_EQ(1234, script2->Run(context.local()) 14499 .ToLocalChecked() 14500 ->Int32Value(context.local()) 14501 .FromJust()); 14502 } 14503 14504 14505 static void FunctionNameCallback( 14506 const v8::FunctionCallbackInfo<v8::Value>& args) { 14507 ApiTestFuzzer::Fuzz(); 14508 args.GetReturnValue().Set(v8_num(42)); 14509 } 14510 14511 14512 THREADED_TEST(CallbackFunctionName) { 14513 LocalContext context; 14514 v8::Isolate* isolate = context->GetIsolate(); 14515 v8::HandleScope scope(isolate); 14516 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14517 t->Set(v8_str("asdf"), 14518 v8::FunctionTemplate::New(isolate, FunctionNameCallback)); 14519 CHECK(context->Global() 14520 ->Set(context.local(), v8_str("obj"), 14521 t->NewInstance(context.local()).ToLocalChecked()) 14522 .FromJust()); 14523 v8::Local<v8::Value> value = CompileRun("obj.asdf.name"); 14524 CHECK(value->IsString()); 14525 v8::String::Utf8Value name(value); 14526 CHECK_EQ(0, strcmp("asdf", *name)); 14527 } 14528 14529 14530 THREADED_TEST(DateAccess) { 14531 LocalContext context; 14532 v8::HandleScope scope(context->GetIsolate()); 14533 v8::Local<v8::Value> date = 14534 v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked(); 14535 CHECK(date->IsDate()); 14536 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 14537 } 14538 14539 14540 void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val, 14541 unsigned elmc, const char* elmv[]) { 14542 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 14543 v8::Local<v8::Object> obj = val.As<v8::Object>(); 14544 v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked(); 14545 CHECK_EQ(elmc, props->Length()); 14546 for (unsigned i = 0; i < elmc; i++) { 14547 v8::String::Utf8Value elm( 14548 props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked()); 14549 CHECK_EQ(0, strcmp(elmv[i], *elm)); 14550 } 14551 } 14552 14553 14554 void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val, 14555 unsigned elmc, const char* elmv[]) { 14556 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 14557 v8::Local<v8::Object> obj = val.As<v8::Object>(); 14558 v8::Local<v8::Array> props = 14559 obj->GetOwnPropertyNames(context).ToLocalChecked(); 14560 CHECK_EQ(elmc, props->Length()); 14561 for (unsigned i = 0; i < elmc; i++) { 14562 v8::String::Utf8Value elm( 14563 props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked()); 14564 CHECK_EQ(0, strcmp(elmv[i], *elm)); 14565 } 14566 } 14567 14568 14569 THREADED_TEST(PropertyEnumeration) { 14570 LocalContext context; 14571 v8::Isolate* isolate = context->GetIsolate(); 14572 v8::HandleScope scope(isolate); 14573 v8::Local<v8::Value> obj = CompileRun( 14574 "var result = [];" 14575 "result[0] = {};" 14576 "result[1] = {a: 1, b: 2};" 14577 "result[2] = [1, 2, 3];" 14578 "var proto = {x: 1, y: 2, z: 3};" 14579 "var x = { __proto__: proto, w: 0, z: 1 };" 14580 "result[3] = x;" 14581 "result;"); 14582 v8::Local<v8::Array> elms = obj.As<v8::Array>(); 14583 CHECK_EQ(4u, elms->Length()); 14584 int elmc0 = 0; 14585 const char** elmv0 = NULL; 14586 CheckProperties( 14587 isolate, 14588 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 14589 elmc0, elmv0); 14590 CheckOwnProperties( 14591 isolate, 14592 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 14593 elmc0, elmv0); 14594 int elmc1 = 2; 14595 const char* elmv1[] = {"a", "b"}; 14596 CheckProperties( 14597 isolate, 14598 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(), 14599 elmc1, elmv1); 14600 CheckOwnProperties( 14601 isolate, 14602 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(), 14603 elmc1, elmv1); 14604 int elmc2 = 3; 14605 const char* elmv2[] = {"0", "1", "2"}; 14606 CheckProperties( 14607 isolate, 14608 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(), 14609 elmc2, elmv2); 14610 CheckOwnProperties( 14611 isolate, 14612 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(), 14613 elmc2, elmv2); 14614 int elmc3 = 4; 14615 const char* elmv3[] = {"w", "z", "x", "y"}; 14616 CheckProperties( 14617 isolate, 14618 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(), 14619 elmc3, elmv3); 14620 int elmc4 = 2; 14621 const char* elmv4[] = {"w", "z"}; 14622 CheckOwnProperties( 14623 isolate, 14624 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(), 14625 elmc4, elmv4); 14626 } 14627 14628 14629 THREADED_TEST(PropertyEnumeration2) { 14630 LocalContext context; 14631 v8::Isolate* isolate = context->GetIsolate(); 14632 v8::HandleScope scope(isolate); 14633 v8::Local<v8::Value> obj = CompileRun( 14634 "var result = [];" 14635 "result[0] = {};" 14636 "result[1] = {a: 1, b: 2};" 14637 "result[2] = [1, 2, 3];" 14638 "var proto = {x: 1, y: 2, z: 3};" 14639 "var x = { __proto__: proto, w: 0, z: 1 };" 14640 "result[3] = x;" 14641 "result;"); 14642 v8::Local<v8::Array> elms = obj.As<v8::Array>(); 14643 CHECK_EQ(4u, elms->Length()); 14644 int elmc0 = 0; 14645 const char** elmv0 = NULL; 14646 CheckProperties( 14647 isolate, 14648 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 14649 elmc0, elmv0); 14650 14651 v8::Local<v8::Value> val = 14652 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(); 14653 v8::Local<v8::Array> props = 14654 val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked(); 14655 CHECK_EQ(0u, props->Length()); 14656 for (uint32_t i = 0; i < props->Length(); i++) { 14657 printf("p[%u]\n", i); 14658 } 14659 } 14660 14661 14662 THREADED_TEST(AccessChecksReenabledCorrectly) { 14663 LocalContext context; 14664 v8::Isolate* isolate = context->GetIsolate(); 14665 v8::HandleScope scope(isolate); 14666 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 14667 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 14668 templ->Set(v8_str("a"), v8_str("a")); 14669 // Add more than 8 (see kMaxFastProperties) properties 14670 // so that the constructor will force copying map. 14671 // Cannot sprintf, gcc complains unsafety. 14672 char buf[4]; 14673 for (char i = '0'; i <= '9' ; i++) { 14674 buf[0] = i; 14675 for (char j = '0'; j <= '9'; j++) { 14676 buf[1] = j; 14677 for (char k = '0'; k <= '9'; k++) { 14678 buf[2] = k; 14679 buf[3] = 0; 14680 templ->Set(v8_str(buf), v8::Number::New(isolate, k)); 14681 } 14682 } 14683 } 14684 14685 Local<v8::Object> instance_1 = 14686 templ->NewInstance(context.local()).ToLocalChecked(); 14687 CHECK(context->Global() 14688 ->Set(context.local(), v8_str("obj_1"), instance_1) 14689 .FromJust()); 14690 14691 Local<Value> value_1 = CompileRun("obj_1.a"); 14692 CHECK(value_1.IsEmpty()); 14693 14694 Local<v8::Object> instance_2 = 14695 templ->NewInstance(context.local()).ToLocalChecked(); 14696 CHECK(context->Global() 14697 ->Set(context.local(), v8_str("obj_2"), instance_2) 14698 .FromJust()); 14699 14700 Local<Value> value_2 = CompileRun("obj_2.a"); 14701 CHECK(value_2.IsEmpty()); 14702 } 14703 14704 14705 // Tests that ScriptData can be serialized and deserialized. 14706 TEST(PreCompileSerialization) { 14707 v8::V8::Initialize(); 14708 LocalContext env; 14709 v8::Isolate* isolate = env->GetIsolate(); 14710 HandleScope handle_scope(isolate); 14711 14712 i::FLAG_min_preparse_length = 0; 14713 const char* script = "function foo(a) { return a+1; }"; 14714 v8::ScriptCompiler::Source source(v8_str(script)); 14715 v8::ScriptCompiler::Compile(env.local(), &source, 14716 v8::ScriptCompiler::kProduceParserCache) 14717 .ToLocalChecked(); 14718 // Serialize. 14719 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); 14720 i::byte* serialized_data = i::NewArray<i::byte>(cd->length); 14721 i::MemCopy(serialized_data, cd->data, cd->length); 14722 14723 // Deserialize. 14724 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length); 14725 14726 // Verify that the original is the same as the deserialized. 14727 CHECK_EQ(cd->length, deserialized->length()); 14728 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length)); 14729 14730 delete deserialized; 14731 i::DeleteArray(serialized_data); 14732 } 14733 14734 14735 // This tests that we do not allow dictionary load/call inline caches 14736 // to use functions that have not yet been compiled. The potential 14737 // problem of loading a function that has not yet been compiled can 14738 // arise because we share code between contexts via the compilation 14739 // cache. 14740 THREADED_TEST(DictionaryICLoadedFunction) { 14741 v8::HandleScope scope(CcTest::isolate()); 14742 // Test LoadIC. 14743 for (int i = 0; i < 2; i++) { 14744 LocalContext context; 14745 CHECK(context->Global() 14746 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate())) 14747 .FromJust()); 14748 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust(); 14749 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 14750 } 14751 // Test CallIC. 14752 for (int i = 0; i < 2; i++) { 14753 LocalContext context; 14754 CHECK(context->Global() 14755 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate())) 14756 .FromJust()); 14757 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust(); 14758 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 14759 } 14760 } 14761 14762 14763 // Test that cross-context new calls use the context of the callee to 14764 // create the new JavaScript object. 14765 THREADED_TEST(CrossContextNew) { 14766 v8::Isolate* isolate = CcTest::isolate(); 14767 v8::HandleScope scope(isolate); 14768 v8::Local<Context> context0 = Context::New(isolate); 14769 v8::Local<Context> context1 = Context::New(isolate); 14770 14771 // Allow cross-domain access. 14772 Local<String> token = v8_str("<security token>"); 14773 context0->SetSecurityToken(token); 14774 context1->SetSecurityToken(token); 14775 14776 // Set an 'x' property on the Object prototype and define a 14777 // constructor function in context0. 14778 context0->Enter(); 14779 CompileRun("Object.prototype.x = 42; function C() {};"); 14780 context0->Exit(); 14781 14782 // Call the constructor function from context0 and check that the 14783 // result has the 'x' property. 14784 context1->Enter(); 14785 CHECK(context1->Global() 14786 ->Set(context1, v8_str("other"), context0->Global()) 14787 .FromJust()); 14788 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 14789 CHECK(value->IsInt32()); 14790 CHECK_EQ(42, value->Int32Value(context1).FromJust()); 14791 context1->Exit(); 14792 } 14793 14794 14795 // Verify that we can clone an object 14796 TEST(ObjectClone) { 14797 LocalContext env; 14798 v8::Isolate* isolate = env->GetIsolate(); 14799 v8::HandleScope scope(isolate); 14800 14801 const char* sample = 14802 "var rv = {};" \ 14803 "rv.alpha = 'hello';" \ 14804 "rv.beta = 123;" \ 14805 "rv;"; 14806 14807 // Create an object, verify basics. 14808 Local<Value> val = CompileRun(sample); 14809 CHECK(val->IsObject()); 14810 Local<v8::Object> obj = val.As<v8::Object>(); 14811 obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust(); 14812 14813 CHECK(v8_str("hello") 14814 ->Equals(env.local(), 14815 obj->Get(env.local(), v8_str("alpha")).ToLocalChecked()) 14816 .FromJust()); 14817 CHECK(v8::Integer::New(isolate, 123) 14818 ->Equals(env.local(), 14819 obj->Get(env.local(), v8_str("beta")).ToLocalChecked()) 14820 .FromJust()); 14821 CHECK(v8_str("cloneme") 14822 ->Equals(env.local(), 14823 obj->Get(env.local(), v8_str("gamma")).ToLocalChecked()) 14824 .FromJust()); 14825 14826 // Clone it. 14827 Local<v8::Object> clone = obj->Clone(); 14828 CHECK(v8_str("hello") 14829 ->Equals(env.local(), 14830 clone->Get(env.local(), v8_str("alpha")).ToLocalChecked()) 14831 .FromJust()); 14832 CHECK(v8::Integer::New(isolate, 123) 14833 ->Equals(env.local(), 14834 clone->Get(env.local(), v8_str("beta")).ToLocalChecked()) 14835 .FromJust()); 14836 CHECK(v8_str("cloneme") 14837 ->Equals(env.local(), 14838 clone->Get(env.local(), v8_str("gamma")).ToLocalChecked()) 14839 .FromJust()); 14840 14841 // Set a property on the clone, verify each object. 14842 CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456)) 14843 .FromJust()); 14844 CHECK(v8::Integer::New(isolate, 123) 14845 ->Equals(env.local(), 14846 obj->Get(env.local(), v8_str("beta")).ToLocalChecked()) 14847 .FromJust()); 14848 CHECK(v8::Integer::New(isolate, 456) 14849 ->Equals(env.local(), 14850 clone->Get(env.local(), v8_str("beta")).ToLocalChecked()) 14851 .FromJust()); 14852 } 14853 14854 14855 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource { 14856 public: 14857 explicit OneByteVectorResource(i::Vector<const char> vector) 14858 : data_(vector) {} 14859 virtual ~OneByteVectorResource() {} 14860 virtual size_t length() const { return data_.length(); } 14861 virtual const char* data() const { return data_.start(); } 14862 private: 14863 i::Vector<const char> data_; 14864 }; 14865 14866 14867 class UC16VectorResource : public v8::String::ExternalStringResource { 14868 public: 14869 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 14870 : data_(vector) {} 14871 virtual ~UC16VectorResource() {} 14872 virtual size_t length() const { return data_.length(); } 14873 virtual const i::uc16* data() const { return data_.start(); } 14874 private: 14875 i::Vector<const i::uc16> data_; 14876 }; 14877 14878 14879 static void MorphAString(i::String* string, 14880 OneByteVectorResource* one_byte_resource, 14881 UC16VectorResource* uc16_resource) { 14882 CHECK(i::StringShape(string).IsExternal()); 14883 if (string->IsOneByteRepresentation()) { 14884 // Check old map is not internalized or long. 14885 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map()); 14886 // Morph external string to be TwoByte string. 14887 string->set_map(CcTest::heap()->external_string_map()); 14888 i::ExternalTwoByteString* morphed = 14889 i::ExternalTwoByteString::cast(string); 14890 morphed->set_resource(uc16_resource); 14891 } else { 14892 // Check old map is not internalized or long. 14893 CHECK(string->map() == CcTest::heap()->external_string_map()); 14894 // Morph external string to be one-byte string. 14895 string->set_map(CcTest::heap()->external_one_byte_string_map()); 14896 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string); 14897 morphed->set_resource(one_byte_resource); 14898 } 14899 } 14900 14901 14902 // Test that we can still flatten a string if the components it is built up 14903 // from have been turned into 16 bit strings in the mean time. 14904 THREADED_TEST(MorphCompositeStringTest) { 14905 char utf_buffer[129]; 14906 const char* c_string = "Now is the time for all good men" 14907 " to come to the aid of the party"; 14908 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 14909 { 14910 LocalContext env; 14911 i::Factory* factory = CcTest::i_isolate()->factory(); 14912 v8::HandleScope scope(env->GetIsolate()); 14913 OneByteVectorResource one_byte_resource( 14914 i::Vector<const char>(c_string, i::StrLength(c_string))); 14915 UC16VectorResource uc16_resource( 14916 i::Vector<const uint16_t>(two_byte_string, 14917 i::StrLength(c_string))); 14918 14919 Local<String> lhs( 14920 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 14921 &one_byte_resource).ToHandleChecked())); 14922 Local<String> rhs( 14923 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 14924 &one_byte_resource).ToHandleChecked())); 14925 14926 CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust()); 14927 CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust()); 14928 14929 CompileRun( 14930 "var cons = lhs + rhs;" 14931 "var slice = lhs.substring(1, lhs.length - 1);" 14932 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 14933 14934 CHECK(lhs->IsOneByte()); 14935 CHECK(rhs->IsOneByte()); 14936 14937 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource, 14938 &uc16_resource); 14939 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource, 14940 &uc16_resource); 14941 14942 // This should UTF-8 without flattening, since everything is ASCII. 14943 Local<String> cons = 14944 v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>(); 14945 CHECK_EQ(128, cons->Utf8Length()); 14946 int nchars = -1; 14947 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 14948 CHECK_EQ(128, nchars); 14949 CHECK_EQ(0, strcmp( 14950 utf_buffer, 14951 "Now is the time for all good men to come to the aid of the party" 14952 "Now is the time for all good men to come to the aid of the party")); 14953 14954 // Now do some stuff to make sure the strings are flattened, etc. 14955 CompileRun( 14956 "/[^a-z]/.test(cons);" 14957 "/[^a-z]/.test(slice);" 14958 "/[^a-z]/.test(slice_on_cons);"); 14959 const char* expected_cons = 14960 "Now is the time for all good men to come to the aid of the party" 14961 "Now is the time for all good men to come to the aid of the party"; 14962 const char* expected_slice = 14963 "ow is the time for all good men to come to the aid of the part"; 14964 const char* expected_slice_on_cons = 14965 "ow is the time for all good men to come to the aid of the party" 14966 "Now is the time for all good men to come to the aid of the part"; 14967 CHECK(v8_str(expected_cons) 14968 ->Equals(env.local(), env->Global() 14969 ->Get(env.local(), v8_str("cons")) 14970 .ToLocalChecked()) 14971 .FromJust()); 14972 CHECK(v8_str(expected_slice) 14973 ->Equals(env.local(), env->Global() 14974 ->Get(env.local(), v8_str("slice")) 14975 .ToLocalChecked()) 14976 .FromJust()); 14977 CHECK(v8_str(expected_slice_on_cons) 14978 ->Equals(env.local(), 14979 env->Global() 14980 ->Get(env.local(), v8_str("slice_on_cons")) 14981 .ToLocalChecked()) 14982 .FromJust()); 14983 } 14984 i::DeleteArray(two_byte_string); 14985 } 14986 14987 14988 TEST(CompileExternalTwoByteSource) { 14989 LocalContext context; 14990 v8::HandleScope scope(context->GetIsolate()); 14991 14992 // This is a very short list of sources, which currently is to check for a 14993 // regression caused by r2703. 14994 const char* one_byte_sources[] = { 14995 "0.5", 14996 "-0.5", // This mainly testes PushBack in the Scanner. 14997 "--0.5", // This mainly testes PushBack in the Scanner. 14998 NULL}; 14999 15000 // Compile the sources as external two byte strings. 15001 for (int i = 0; one_byte_sources[i] != NULL; i++) { 15002 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]); 15003 TestResource* uc16_resource = new TestResource(two_byte_string); 15004 v8::Local<v8::String> source = 15005 v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource) 15006 .ToLocalChecked(); 15007 v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>()); 15008 } 15009 } 15010 15011 15012 #ifndef V8_INTERPRETED_REGEXP 15013 15014 struct RegExpInterruptionData { 15015 v8::base::Atomic32 loop_count; 15016 UC16VectorResource* string_resource; 15017 v8::Persistent<v8::String> string; 15018 } regexp_interruption_data; 15019 15020 15021 class RegExpInterruptionThread : public v8::base::Thread { 15022 public: 15023 explicit RegExpInterruptionThread(v8::Isolate* isolate) 15024 : Thread(Options("TimeoutThread")), isolate_(isolate) {} 15025 15026 virtual void Run() { 15027 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0); 15028 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7; 15029 v8::base::NoBarrier_AtomicIncrement( 15030 ®exp_interruption_data.loop_count, 1)) { 15031 // Wait a bit before requesting GC. 15032 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50)); 15033 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); 15034 } 15035 // Wait a bit before terminating. 15036 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50)); 15037 isolate_->TerminateExecution(); 15038 } 15039 15040 private: 15041 v8::Isolate* isolate_; 15042 }; 15043 15044 15045 void RunBeforeGC(v8::Isolate* isolate, v8::GCType type, 15046 v8::GCCallbackFlags flags) { 15047 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) { 15048 return; 15049 } 15050 v8::HandleScope scope(isolate); 15051 v8::Local<v8::String> string = v8::Local<v8::String>::New( 15052 CcTest::isolate(), regexp_interruption_data.string); 15053 string->MakeExternal(regexp_interruption_data.string_resource); 15054 } 15055 15056 15057 // Test that RegExp execution can be interrupted. Specifically, we test 15058 // * interrupting with GC 15059 // * turn the subject string from one-byte internal to two-byte external string 15060 // * force termination 15061 TEST(RegExpInterruption) { 15062 LocalContext env; 15063 v8::HandleScope scope(env->GetIsolate()); 15064 15065 RegExpInterruptionThread timeout_thread(env->GetIsolate()); 15066 15067 env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC); 15068 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 15069 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content); 15070 v8::Local<v8::String> string = v8_str(one_byte_content); 15071 15072 env->Global()->Set(env.local(), v8_str("a"), string).FromJust(); 15073 regexp_interruption_data.string.Reset(env->GetIsolate(), string); 15074 regexp_interruption_data.string_resource = new UC16VectorResource( 15075 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content))); 15076 15077 v8::TryCatch try_catch(env->GetIsolate()); 15078 timeout_thread.Start(); 15079 15080 CompileRun("/((a*)*)*b/.exec(a)"); 15081 CHECK(try_catch.HasTerminated()); 15082 15083 timeout_thread.Join(); 15084 15085 regexp_interruption_data.string.Reset(); 15086 i::DeleteArray(uc16_content); 15087 } 15088 15089 #endif // V8_INTERPRETED_REGEXP 15090 15091 15092 // Test that we cannot set a property on the global object if there 15093 // is a read-only property in the prototype chain. 15094 TEST(ReadOnlyPropertyInGlobalProto) { 15095 v8::Isolate* isolate = CcTest::isolate(); 15096 v8::HandleScope scope(isolate); 15097 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15098 LocalContext context(0, templ); 15099 v8::Local<v8::Object> global = context->Global(); 15100 v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast( 15101 global->Get(context.local(), v8_str("__proto__")).ToLocalChecked()); 15102 global_proto->DefineOwnProperty(context.local(), v8_str("x"), 15103 v8::Integer::New(isolate, 0), v8::ReadOnly) 15104 .FromJust(); 15105 global_proto->DefineOwnProperty(context.local(), v8_str("y"), 15106 v8::Integer::New(isolate, 0), v8::ReadOnly) 15107 .FromJust(); 15108 // Check without 'eval' or 'with'. 15109 v8::Local<v8::Value> res = 15110 CompileRun("function f() { x = 42; return x; }; f()"); 15111 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15112 // Check with 'eval'. 15113 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 15114 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15115 // Check with 'with'. 15116 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 15117 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15118 } 15119 15120 15121 TEST(CreateDataProperty) { 15122 LocalContext env; 15123 v8::Isolate* isolate = env->GetIsolate(); 15124 v8::HandleScope handle_scope(isolate); 15125 15126 CompileRun( 15127 "var a = {};" 15128 "var b = [];" 15129 "Object.defineProperty(a, 'foo', {value: 23});" 15130 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); 15131 15132 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast( 15133 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 15134 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast( 15135 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 15136 { 15137 // Can't change a non-configurable properties. 15138 v8::TryCatch try_catch(isolate); 15139 CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"), 15140 v8::Integer::New(isolate, 42)).FromJust()); 15141 CHECK(!try_catch.HasCaught()); 15142 CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"), 15143 v8::Integer::New(isolate, 42)).FromJust()); 15144 CHECK(!try_catch.HasCaught()); 15145 v8::Local<v8::Value> val = 15146 obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); 15147 CHECK(val->IsNumber()); 15148 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15149 } 15150 15151 { 15152 // Set a regular property. 15153 v8::TryCatch try_catch(isolate); 15154 CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"), 15155 v8::Integer::New(isolate, 42)).FromJust()); 15156 CHECK(!try_catch.HasCaught()); 15157 v8::Local<v8::Value> val = 15158 obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); 15159 CHECK(val->IsNumber()); 15160 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15161 } 15162 15163 { 15164 // Set an indexed property. 15165 v8::TryCatch try_catch(isolate); 15166 CHECK(obj->CreateDataProperty(env.local(), v8_str("1"), 15167 v8::Integer::New(isolate, 42)).FromJust()); 15168 CHECK(!try_catch.HasCaught()); 15169 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); 15170 CHECK(val->IsNumber()); 15171 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15172 } 15173 15174 { 15175 // Special cases for arrays. 15176 v8::TryCatch try_catch(isolate); 15177 CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"), 15178 v8::Integer::New(isolate, 1)).FromJust()); 15179 CHECK(!try_catch.HasCaught()); 15180 } 15181 { 15182 // Special cases for arrays: index exceeds the array's length 15183 v8::TryCatch try_catch(isolate); 15184 CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23)) 15185 .FromJust()); 15186 CHECK(!try_catch.HasCaught()); 15187 CHECK_EQ(2U, arr->Length()); 15188 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); 15189 CHECK(val->IsNumber()); 15190 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); 15191 15192 // Set an existing entry. 15193 CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42)) 15194 .FromJust()); 15195 CHECK(!try_catch.HasCaught()); 15196 val = arr->Get(env.local(), 0).ToLocalChecked(); 15197 CHECK(val->IsNumber()); 15198 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15199 } 15200 15201 CompileRun("Object.freeze(a);"); 15202 { 15203 // Can't change non-extensible objects. 15204 v8::TryCatch try_catch(isolate); 15205 CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"), 15206 v8::Integer::New(isolate, 42)).FromJust()); 15207 CHECK(!try_catch.HasCaught()); 15208 } 15209 15210 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15211 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 15212 v8::Local<v8::Object> access_checked = 15213 templ->NewInstance(env.local()).ToLocalChecked(); 15214 { 15215 v8::TryCatch try_catch(isolate); 15216 CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"), 15217 v8::Integer::New(isolate, 42)) 15218 .IsNothing()); 15219 CHECK(try_catch.HasCaught()); 15220 } 15221 } 15222 15223 15224 TEST(DefineOwnProperty) { 15225 LocalContext env; 15226 v8::Isolate* isolate = env->GetIsolate(); 15227 v8::HandleScope handle_scope(isolate); 15228 15229 CompileRun( 15230 "var a = {};" 15231 "var b = [];" 15232 "Object.defineProperty(a, 'foo', {value: 23});" 15233 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); 15234 15235 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast( 15236 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 15237 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast( 15238 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 15239 { 15240 // Can't change a non-configurable properties. 15241 v8::TryCatch try_catch(isolate); 15242 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"), 15243 v8::Integer::New(isolate, 42)).FromJust()); 15244 CHECK(!try_catch.HasCaught()); 15245 CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"), 15246 v8::Integer::New(isolate, 42)).FromJust()); 15247 CHECK(!try_catch.HasCaught()); 15248 v8::Local<v8::Value> val = 15249 obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); 15250 CHECK(val->IsNumber()); 15251 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15252 } 15253 15254 { 15255 // Set a regular property. 15256 v8::TryCatch try_catch(isolate); 15257 CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"), 15258 v8::Integer::New(isolate, 42)).FromJust()); 15259 CHECK(!try_catch.HasCaught()); 15260 v8::Local<v8::Value> val = 15261 obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); 15262 CHECK(val->IsNumber()); 15263 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15264 } 15265 15266 { 15267 // Set an indexed property. 15268 v8::TryCatch try_catch(isolate); 15269 CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"), 15270 v8::Integer::New(isolate, 42)).FromJust()); 15271 CHECK(!try_catch.HasCaught()); 15272 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); 15273 CHECK(val->IsNumber()); 15274 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15275 } 15276 15277 { 15278 // Special cases for arrays. 15279 v8::TryCatch try_catch(isolate); 15280 CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"), 15281 v8::Integer::New(isolate, 1)).FromJust()); 15282 CHECK(!try_catch.HasCaught()); 15283 } 15284 { 15285 // Special cases for arrays: index exceeds the array's length 15286 v8::TryCatch try_catch(isolate); 15287 CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"), 15288 v8::Integer::New(isolate, 23)).FromJust()); 15289 CHECK(!try_catch.HasCaught()); 15290 CHECK_EQ(2U, arr->Length()); 15291 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); 15292 CHECK(val->IsNumber()); 15293 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); 15294 15295 // Set an existing entry. 15296 CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"), 15297 v8::Integer::New(isolate, 42)).FromJust()); 15298 CHECK(!try_catch.HasCaught()); 15299 val = arr->Get(env.local(), 0).ToLocalChecked(); 15300 CHECK(val->IsNumber()); 15301 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15302 } 15303 15304 { 15305 // Set a non-writable property. 15306 v8::TryCatch try_catch(isolate); 15307 CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"), 15308 v8::Integer::New(isolate, 42), 15309 v8::ReadOnly).FromJust()); 15310 CHECK(!try_catch.HasCaught()); 15311 v8::Local<v8::Value> val = 15312 obj->Get(env.local(), v8_str("lala")).ToLocalChecked(); 15313 CHECK(val->IsNumber()); 15314 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15315 CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes( 15316 env.local(), v8_str("lala")).FromJust()); 15317 CHECK(!try_catch.HasCaught()); 15318 } 15319 15320 CompileRun("Object.freeze(a);"); 15321 { 15322 // Can't change non-extensible objects. 15323 v8::TryCatch try_catch(isolate); 15324 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"), 15325 v8::Integer::New(isolate, 42)).FromJust()); 15326 CHECK(!try_catch.HasCaught()); 15327 } 15328 15329 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15330 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 15331 v8::Local<v8::Object> access_checked = 15332 templ->NewInstance(env.local()).ToLocalChecked(); 15333 { 15334 v8::TryCatch try_catch(isolate); 15335 CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"), 15336 v8::Integer::New(isolate, 42)) 15337 .IsNothing()); 15338 CHECK(try_catch.HasCaught()); 15339 } 15340 } 15341 15342 15343 THREADED_TEST(GetCurrentContextWhenNotInContext) { 15344 i::Isolate* isolate = CcTest::i_isolate(); 15345 CHECK(isolate != NULL); 15346 CHECK(isolate->context() == NULL); 15347 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 15348 v8::HandleScope scope(v8_isolate); 15349 // The following should not crash, but return an empty handle. 15350 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 15351 CHECK(current.IsEmpty()); 15352 } 15353 15354 15355 // Check that a variable declaration with no explicit initialization 15356 // value does shadow an existing property in the prototype chain. 15357 THREADED_TEST(InitGlobalVarInProtoChain) { 15358 LocalContext context; 15359 v8::HandleScope scope(context->GetIsolate()); 15360 // Introduce a variable in the prototype chain. 15361 CompileRun("__proto__.x = 42"); 15362 v8::Local<v8::Value> result = CompileRun("var x = 43; x"); 15363 CHECK(!result->IsUndefined()); 15364 CHECK_EQ(43, result->Int32Value(context.local()).FromJust()); 15365 } 15366 15367 15368 // Regression test for issue 398. 15369 // If a function is added to an object, creating a constant function 15370 // field, and the result is cloned, replacing the constant function on the 15371 // original should not affect the clone. 15372 // See http://code.google.com/p/v8/issues/detail?id=398 15373 THREADED_TEST(ReplaceConstantFunction) { 15374 LocalContext context; 15375 v8::Isolate* isolate = context->GetIsolate(); 15376 v8::HandleScope scope(isolate); 15377 v8::Local<v8::Object> obj = v8::Object::New(isolate); 15378 v8::Local<v8::FunctionTemplate> func_templ = 15379 v8::FunctionTemplate::New(isolate); 15380 v8::Local<v8::String> foo_string = v8_str("foo"); 15381 obj->Set(context.local(), foo_string, 15382 func_templ->GetFunction(context.local()).ToLocalChecked()) 15383 .FromJust(); 15384 v8::Local<v8::Object> obj_clone = obj->Clone(); 15385 obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust(); 15386 CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined()); 15387 } 15388 15389 15390 static void CheckElementValue(i::Isolate* isolate, 15391 int expected, 15392 i::Handle<i::Object> obj, 15393 int offset) { 15394 i::Object* element = 15395 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked(); 15396 CHECK_EQ(expected, i::Smi::cast(element)->value()); 15397 } 15398 15399 15400 template <class ExternalArrayClass, class ElementType> 15401 static void ObjectWithExternalArrayTestHelper(Local<Context> context, 15402 v8::Local<Object> obj, 15403 int element_count, 15404 i::ExternalArrayType array_type, 15405 int64_t low, int64_t high) { 15406 i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj); 15407 i::Isolate* isolate = jsobj->GetIsolate(); 15408 obj->Set(context, v8_str("field"), 15409 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503)) 15410 .FromJust(); 15411 CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust()); 15412 v8::Local<v8::Value> result = CompileRun("ext_array.field"); 15413 CHECK_EQ(1503, result->Int32Value(context).FromJust()); 15414 result = CompileRun("ext_array[1]"); 15415 CHECK_EQ(1, result->Int32Value(context).FromJust()); 15416 15417 // Check assigned smis 15418 result = CompileRun("for (var i = 0; i < 8; i++) {" 15419 " ext_array[i] = i;" 15420 "}" 15421 "var sum = 0;" 15422 "for (var i = 0; i < 8; i++) {" 15423 " sum += ext_array[i];" 15424 "}" 15425 "sum;"); 15426 15427 CHECK_EQ(28, result->Int32Value(context).FromJust()); 15428 // Check pass through of assigned smis 15429 result = CompileRun("var sum = 0;" 15430 "for (var i = 0; i < 8; i++) {" 15431 " sum += ext_array[i] = ext_array[i] = -i;" 15432 "}" 15433 "sum;"); 15434 CHECK_EQ(-28, result->Int32Value(context).FromJust()); 15435 15436 15437 // Check assigned smis in reverse order 15438 result = CompileRun("for (var i = 8; --i >= 0; ) {" 15439 " ext_array[i] = i;" 15440 "}" 15441 "var sum = 0;" 15442 "for (var i = 0; i < 8; i++) {" 15443 " sum += ext_array[i];" 15444 "}" 15445 "sum;"); 15446 CHECK_EQ(28, result->Int32Value(context).FromJust()); 15447 15448 // Check pass through of assigned HeapNumbers 15449 result = CompileRun("var sum = 0;" 15450 "for (var i = 0; i < 16; i+=2) {" 15451 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 15452 "}" 15453 "sum;"); 15454 CHECK_EQ(-28, result->Int32Value(context).FromJust()); 15455 15456 // Check assigned HeapNumbers 15457 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 15458 " ext_array[i] = (i * 0.5);" 15459 "}" 15460 "var sum = 0;" 15461 "for (var i = 0; i < 16; i+=2) {" 15462 " sum += ext_array[i];" 15463 "}" 15464 "sum;"); 15465 CHECK_EQ(28, result->Int32Value(context).FromJust()); 15466 15467 // Check assigned HeapNumbers in reverse order 15468 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 15469 " ext_array[i] = (i * 0.5);" 15470 "}" 15471 "var sum = 0;" 15472 "for (var i = 0; i < 16; i+=2) {" 15473 " sum += ext_array[i];" 15474 "}" 15475 "sum;"); 15476 CHECK_EQ(28, result->Int32Value(context).FromJust()); 15477 15478 i::ScopedVector<char> test_buf(1024); 15479 15480 // Check legal boundary conditions. 15481 // The repeated loads and stores ensure the ICs are exercised. 15482 const char* boundary_program = 15483 "var res = 0;" 15484 "for (var i = 0; i < 16; i++) {" 15485 " ext_array[i] = %lld;" 15486 " if (i > 8) {" 15487 " res = ext_array[i];" 15488 " }" 15489 "}" 15490 "res;"; 15491 i::SNPrintF(test_buf, 15492 boundary_program, 15493 low); 15494 result = CompileRun(test_buf.start()); 15495 CHECK_EQ(low, result->IntegerValue(context).FromJust()); 15496 15497 i::SNPrintF(test_buf, 15498 boundary_program, 15499 high); 15500 result = CompileRun(test_buf.start()); 15501 CHECK_EQ(high, result->IntegerValue(context).FromJust()); 15502 15503 // Check misprediction of type in IC. 15504 result = CompileRun("var tmp_array = ext_array;" 15505 "var sum = 0;" 15506 "for (var i = 0; i < 8; i++) {" 15507 " tmp_array[i] = i;" 15508 " sum += tmp_array[i];" 15509 " if (i == 4) {" 15510 " tmp_array = {};" 15511 " }" 15512 "}" 15513 "sum;"); 15514 // Force GC to trigger verification. 15515 CcTest::heap()->CollectAllGarbage(); 15516 CHECK_EQ(28, result->Int32Value(context).FromJust()); 15517 15518 // Make sure out-of-range loads do not throw. 15519 i::SNPrintF(test_buf, 15520 "var caught_exception = false;" 15521 "try {" 15522 " ext_array[%d];" 15523 "} catch (e) {" 15524 " caught_exception = true;" 15525 "}" 15526 "caught_exception;", 15527 element_count); 15528 result = CompileRun(test_buf.start()); 15529 CHECK_EQ(false, result->BooleanValue(context).FromJust()); 15530 15531 // Make sure out-of-range stores do not throw. 15532 i::SNPrintF(test_buf, 15533 "var caught_exception = false;" 15534 "try {" 15535 " ext_array[%d] = 1;" 15536 "} catch (e) {" 15537 " caught_exception = true;" 15538 "}" 15539 "caught_exception;", 15540 element_count); 15541 result = CompileRun(test_buf.start()); 15542 CHECK_EQ(false, result->BooleanValue(context).FromJust()); 15543 15544 // Check other boundary conditions, values and operations. 15545 result = CompileRun("for (var i = 0; i < 8; i++) {" 15546 " ext_array[7] = undefined;" 15547 "}" 15548 "ext_array[7];"); 15549 CHECK_EQ(0, result->Int32Value(context).FromJust()); 15550 if (array_type == i::kExternalFloat64Array || 15551 array_type == i::kExternalFloat32Array) { 15552 CHECK(std::isnan( 15553 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number())); 15554 } else { 15555 CheckElementValue(isolate, 0, jsobj, 7); 15556 } 15557 15558 result = CompileRun("for (var i = 0; i < 8; i++) {" 15559 " ext_array[6] = '2.3';" 15560 "}" 15561 "ext_array[6];"); 15562 CHECK_EQ(2, result->Int32Value(context).FromJust()); 15563 CHECK_EQ(2, 15564 static_cast<int>( 15565 i::Object::GetElement( 15566 isolate, jsobj, 6).ToHandleChecked()->Number())); 15567 15568 if (array_type != i::kExternalFloat32Array && 15569 array_type != i::kExternalFloat64Array) { 15570 // Though the specification doesn't state it, be explicit about 15571 // converting NaNs and +/-Infinity to zero. 15572 result = CompileRun("for (var i = 0; i < 8; i++) {" 15573 " ext_array[i] = 5;" 15574 "}" 15575 "for (var i = 0; i < 8; i++) {" 15576 " ext_array[i] = NaN;" 15577 "}" 15578 "ext_array[5];"); 15579 CHECK_EQ(0, result->Int32Value(context).FromJust()); 15580 CheckElementValue(isolate, 0, jsobj, 5); 15581 15582 result = CompileRun("for (var i = 0; i < 8; i++) {" 15583 " ext_array[i] = 5;" 15584 "}" 15585 "for (var i = 0; i < 8; i++) {" 15586 " ext_array[i] = Infinity;" 15587 "}" 15588 "ext_array[5];"); 15589 int expected_value = 15590 (array_type == i::kExternalUint8ClampedArray) ? 255 : 0; 15591 CHECK_EQ(expected_value, result->Int32Value(context).FromJust()); 15592 CheckElementValue(isolate, expected_value, jsobj, 5); 15593 15594 result = CompileRun("for (var i = 0; i < 8; i++) {" 15595 " ext_array[i] = 5;" 15596 "}" 15597 "for (var i = 0; i < 8; i++) {" 15598 " ext_array[i] = -Infinity;" 15599 "}" 15600 "ext_array[5];"); 15601 CHECK_EQ(0, result->Int32Value(context).FromJust()); 15602 CheckElementValue(isolate, 0, jsobj, 5); 15603 15604 // Check truncation behavior of integral arrays. 15605 const char* unsigned_data = 15606 "var source_data = [0.6, 10.6];" 15607 "var expected_results = [0, 10];"; 15608 const char* signed_data = 15609 "var source_data = [0.6, 10.6, -0.6, -10.6];" 15610 "var expected_results = [0, 10, 0, -10];"; 15611 const char* pixel_data = 15612 "var source_data = [0.6, 10.6];" 15613 "var expected_results = [1, 11];"; 15614 bool is_unsigned = (array_type == i::kExternalUint8Array || 15615 array_type == i::kExternalUint16Array || 15616 array_type == i::kExternalUint32Array); 15617 bool is_pixel_data = array_type == i::kExternalUint8ClampedArray; 15618 15619 i::SNPrintF(test_buf, 15620 "%s" 15621 "var all_passed = true;" 15622 "for (var i = 0; i < source_data.length; i++) {" 15623 " for (var j = 0; j < 8; j++) {" 15624 " ext_array[j] = source_data[i];" 15625 " }" 15626 " all_passed = all_passed &&" 15627 " (ext_array[5] == expected_results[i]);" 15628 "}" 15629 "all_passed;", 15630 (is_unsigned ? 15631 unsigned_data : 15632 (is_pixel_data ? pixel_data : signed_data))); 15633 result = CompileRun(test_buf.start()); 15634 CHECK_EQ(true, result->BooleanValue(context).FromJust()); 15635 } 15636 15637 i::Handle<ExternalArrayClass> array(ExternalArrayClass::cast( 15638 i::Handle<i::JSObject>::cast(jsobj)->elements())); 15639 for (int i = 0; i < element_count; i++) { 15640 array->set(i, static_cast<ElementType>(i)); 15641 } 15642 15643 // Test complex assignments 15644 result = CompileRun("function ee_op_test_complex_func(sum) {" 15645 " for (var i = 0; i < 40; ++i) {" 15646 " sum += (ext_array[i] += 1);" 15647 " sum += (ext_array[i] -= 1);" 15648 " } " 15649 " return sum;" 15650 "}" 15651 "sum=0;" 15652 "for (var i=0;i<10000;++i) {" 15653 " sum=ee_op_test_complex_func(sum);" 15654 "}" 15655 "sum;"); 15656 CHECK_EQ(16000000, result->Int32Value(context).FromJust()); 15657 15658 // Test count operations 15659 result = CompileRun("function ee_op_test_count_func(sum) {" 15660 " for (var i = 0; i < 40; ++i) {" 15661 " sum += (++ext_array[i]);" 15662 " sum += (--ext_array[i]);" 15663 " } " 15664 " return sum;" 15665 "}" 15666 "sum=0;" 15667 "for (var i=0;i<10000;++i) {" 15668 " sum=ee_op_test_count_func(sum);" 15669 "}" 15670 "sum;"); 15671 CHECK_EQ(16000000, result->Int32Value(context).FromJust()); 15672 15673 result = CompileRun("ext_array[3] = 33;" 15674 "delete ext_array[3];" 15675 "ext_array[3];"); 15676 CHECK_EQ(33, result->Int32Value(context).FromJust()); 15677 15678 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 15679 "ext_array[2] = 12; ext_array[3] = 13;" 15680 "ext_array.__defineGetter__('2'," 15681 "function() { return 120; });" 15682 "ext_array[2];"); 15683 CHECK_EQ(12, result->Int32Value(context).FromJust()); 15684 15685 result = CompileRun("var js_array = new Array(40);" 15686 "js_array[0] = 77;" 15687 "js_array;"); 15688 CHECK_EQ(77, v8::Object::Cast(*result) 15689 ->Get(context, v8_str("0")) 15690 .ToLocalChecked() 15691 ->Int32Value(context) 15692 .FromJust()); 15693 15694 result = CompileRun("ext_array[1] = 23;" 15695 "ext_array.__proto__ = [];" 15696 "js_array.__proto__ = ext_array;" 15697 "js_array.concat(ext_array);"); 15698 CHECK_EQ(77, v8::Object::Cast(*result) 15699 ->Get(context, v8_str("0")) 15700 .ToLocalChecked() 15701 ->Int32Value(context) 15702 .FromJust()); 15703 CHECK_EQ(23, v8::Object::Cast(*result) 15704 ->Get(context, v8_str("1")) 15705 .ToLocalChecked() 15706 ->Int32Value(context) 15707 .FromJust()); 15708 15709 result = CompileRun("ext_array[1] = 23;"); 15710 CHECK_EQ(23, result->Int32Value(context).FromJust()); 15711 } 15712 15713 15714 template <class FixedTypedArrayClass, i::ElementsKind elements_kind, 15715 class ElementType> 15716 static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type, 15717 ElementType low, ElementType high) { 15718 i::FLAG_allow_natives_syntax = true; 15719 LocalContext context; 15720 i::Isolate* isolate = CcTest::i_isolate(); 15721 i::Factory* factory = isolate->factory(); 15722 v8::HandleScope scope(context->GetIsolate()); 15723 const int kElementCount = 260; 15724 i::Handle<i::JSTypedArray> jsobj = 15725 factory->NewJSTypedArray(elements_kind, kElementCount); 15726 i::Handle<FixedTypedArrayClass> fixed_array( 15727 FixedTypedArrayClass::cast(jsobj->elements())); 15728 CHECK_EQ(FixedTypedArrayClass::kInstanceType, 15729 fixed_array->map()->instance_type()); 15730 CHECK_EQ(kElementCount, fixed_array->length()); 15731 CcTest::heap()->CollectAllGarbage(); 15732 for (int i = 0; i < kElementCount; i++) { 15733 fixed_array->set(i, static_cast<ElementType>(i)); 15734 } 15735 // Force GC to trigger verification. 15736 CcTest::heap()->CollectAllGarbage(); 15737 for (int i = 0; i < kElementCount; i++) { 15738 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)), 15739 static_cast<int64_t>(fixed_array->get_scalar(i))); 15740 } 15741 v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj); 15742 15743 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>( 15744 context.local(), obj, kElementCount, array_type, 15745 static_cast<int64_t>(low), 15746 static_cast<int64_t>(high)); 15747 } 15748 15749 15750 THREADED_TEST(FixedUint8Array) { 15751 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>( 15752 i::kExternalUint8Array, 0x0, 0xFF); 15753 } 15754 15755 15756 THREADED_TEST(FixedUint8ClampedArray) { 15757 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray, 15758 i::UINT8_CLAMPED_ELEMENTS, uint8_t>( 15759 i::kExternalUint8ClampedArray, 0x0, 0xFF); 15760 } 15761 15762 15763 THREADED_TEST(FixedInt8Array) { 15764 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>( 15765 i::kExternalInt8Array, -0x80, 0x7F); 15766 } 15767 15768 15769 THREADED_TEST(FixedUint16Array) { 15770 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>( 15771 i::kExternalUint16Array, 0x0, 0xFFFF); 15772 } 15773 15774 15775 THREADED_TEST(FixedInt16Array) { 15776 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>( 15777 i::kExternalInt16Array, -0x8000, 0x7FFF); 15778 } 15779 15780 15781 THREADED_TEST(FixedUint32Array) { 15782 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>( 15783 i::kExternalUint32Array, 0x0, UINT_MAX); 15784 } 15785 15786 15787 THREADED_TEST(FixedInt32Array) { 15788 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>( 15789 i::kExternalInt32Array, INT_MIN, INT_MAX); 15790 } 15791 15792 15793 THREADED_TEST(FixedFloat32Array) { 15794 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>( 15795 i::kExternalFloat32Array, -500, 500); 15796 } 15797 15798 15799 THREADED_TEST(FixedFloat64Array) { 15800 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>( 15801 i::kExternalFloat64Array, -500, 500); 15802 } 15803 15804 15805 template <typename ElementType, typename TypedArray, class ExternalArrayClass, 15806 class ArrayBufferType> 15807 void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, 15808 int64_t high) { 15809 const int kElementCount = 50; 15810 15811 i::ScopedVector<ElementType> backing_store(kElementCount+2); 15812 15813 LocalContext env; 15814 v8::Isolate* isolate = env->GetIsolate(); 15815 v8::HandleScope handle_scope(isolate); 15816 15817 Local<ArrayBufferType> ab = 15818 ArrayBufferType::New(isolate, backing_store.start(), 15819 (kElementCount + 2) * sizeof(ElementType)); 15820 Local<TypedArray> ta = 15821 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 15822 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 15823 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 15824 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset()); 15825 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength()); 15826 CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust()); 15827 15828 ElementType* data = backing_store.start() + 2; 15829 for (int i = 0; i < kElementCount; i++) { 15830 data[i] = static_cast<ElementType>(i); 15831 } 15832 15833 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 15834 env.local(), ta, kElementCount, array_type, low, high); 15835 } 15836 15837 15838 THREADED_TEST(Uint8Array) { 15839 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array, 15840 v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); 15841 } 15842 15843 15844 THREADED_TEST(Int8Array) { 15845 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array, 15846 v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F); 15847 } 15848 15849 15850 THREADED_TEST(Uint16Array) { 15851 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array, 15852 v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF); 15853 } 15854 15855 15856 THREADED_TEST(Int16Array) { 15857 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array, 15858 v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000, 15859 0x7FFF); 15860 } 15861 15862 15863 THREADED_TEST(Uint32Array) { 15864 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array, 15865 v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX); 15866 } 15867 15868 15869 THREADED_TEST(Int32Array) { 15870 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array, 15871 v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN, 15872 INT_MAX); 15873 } 15874 15875 15876 THREADED_TEST(Float32Array) { 15877 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array, 15878 v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500); 15879 } 15880 15881 15882 THREADED_TEST(Float64Array) { 15883 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array, 15884 v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500); 15885 } 15886 15887 15888 THREADED_TEST(Uint8ClampedArray) { 15889 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, 15890 i::FixedUint8ClampedArray, v8::ArrayBuffer>( 15891 i::kExternalUint8ClampedArray, 0, 0xFF); 15892 } 15893 15894 15895 THREADED_TEST(DataView) { 15896 const int kSize = 50; 15897 15898 i::ScopedVector<uint8_t> backing_store(kSize+2); 15899 15900 LocalContext env; 15901 v8::Isolate* isolate = env->GetIsolate(); 15902 v8::HandleScope handle_scope(isolate); 15903 15904 Local<v8::ArrayBuffer> ab = 15905 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 15906 Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize); 15907 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 15908 CHECK_EQ(2u, dv->ByteOffset()); 15909 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 15910 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); 15911 } 15912 15913 15914 THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) { 15915 LocalContext env; 15916 v8::Isolate* isolate = env->GetIsolate(); 15917 v8::HandleScope handle_scope(isolate); 15918 15919 // Make sure the pointer looks like a heap object 15920 uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag); 15921 15922 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store 15923 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8); 15924 15925 // Should not crash 15926 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 15927 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 15928 CcTest::heap()->CollectAllGarbage(); 15929 CcTest::heap()->CollectAllGarbage(); 15930 15931 // Should not move the pointer 15932 CHECK_EQ(ab->GetContents().Data(), store_ptr); 15933 } 15934 15935 15936 THREADED_TEST(SkipArrayBufferDuringScavenge) { 15937 LocalContext env; 15938 v8::Isolate* isolate = env->GetIsolate(); 15939 v8::HandleScope handle_scope(isolate); 15940 15941 // Make sure the pointer looks like a heap object 15942 Local<v8::Object> tmp = v8::Object::New(isolate); 15943 uint8_t* store_ptr = 15944 reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp)); 15945 15946 // Make `store_ptr` point to from space 15947 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 15948 15949 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store 15950 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8); 15951 15952 // Should not crash, 15953 // i.e. backing store pointer should not be treated as a heap object pointer 15954 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 15955 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 15956 15957 // Use `ab` to silence compiler warning 15958 CHECK_EQ(ab->GetContents().Data(), store_ptr); 15959 } 15960 15961 15962 THREADED_TEST(SharedUint8Array) { 15963 i::FLAG_harmony_sharedarraybuffer = true; 15964 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array, 15965 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); 15966 } 15967 15968 15969 THREADED_TEST(SharedInt8Array) { 15970 i::FLAG_harmony_sharedarraybuffer = true; 15971 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array, 15972 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80, 15973 0x7F); 15974 } 15975 15976 15977 THREADED_TEST(SharedUint16Array) { 15978 i::FLAG_harmony_sharedarraybuffer = true; 15979 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array, 15980 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0, 15981 0xFFFF); 15982 } 15983 15984 15985 THREADED_TEST(SharedInt16Array) { 15986 i::FLAG_harmony_sharedarraybuffer = true; 15987 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array, 15988 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000, 15989 0x7FFF); 15990 } 15991 15992 15993 THREADED_TEST(SharedUint32Array) { 15994 i::FLAG_harmony_sharedarraybuffer = true; 15995 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array, 15996 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0, 15997 UINT_MAX); 15998 } 15999 16000 16001 THREADED_TEST(SharedInt32Array) { 16002 i::FLAG_harmony_sharedarraybuffer = true; 16003 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array, 16004 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN, 16005 INT_MAX); 16006 } 16007 16008 16009 THREADED_TEST(SharedFloat32Array) { 16010 i::FLAG_harmony_sharedarraybuffer = true; 16011 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array, 16012 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500, 16013 500); 16014 } 16015 16016 16017 THREADED_TEST(SharedFloat64Array) { 16018 i::FLAG_harmony_sharedarraybuffer = true; 16019 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array, 16020 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500, 16021 500); 16022 } 16023 16024 16025 THREADED_TEST(SharedUint8ClampedArray) { 16026 i::FLAG_harmony_sharedarraybuffer = true; 16027 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, 16028 i::FixedUint8ClampedArray, v8::SharedArrayBuffer>( 16029 i::kExternalUint8ClampedArray, 0, 0xFF); 16030 } 16031 16032 16033 THREADED_TEST(SharedDataView) { 16034 i::FLAG_harmony_sharedarraybuffer = true; 16035 const int kSize = 50; 16036 16037 i::ScopedVector<uint8_t> backing_store(kSize + 2); 16038 16039 LocalContext env; 16040 v8::Isolate* isolate = env->GetIsolate(); 16041 v8::HandleScope handle_scope(isolate); 16042 16043 Local<v8::SharedArrayBuffer> ab = 16044 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 16045 Local<v8::DataView> dv = 16046 v8::DataView::New(ab, 2, kSize); 16047 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 16048 CHECK_EQ(2u, dv->ByteOffset()); 16049 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 16050 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); 16051 } 16052 16053 16054 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 16055 THREADED_TEST(Is##View) { \ 16056 LocalContext env; \ 16057 v8::Isolate* isolate = env->GetIsolate(); \ 16058 v8::HandleScope handle_scope(isolate); \ 16059 \ 16060 Local<Value> result = CompileRun( \ 16061 "var ab = new ArrayBuffer(128);" \ 16062 "new " #View "(ab)"); \ 16063 CHECK(result->IsArrayBufferView()); \ 16064 CHECK(result->Is##View()); \ 16065 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 16066 } 16067 16068 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 16069 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 16070 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 16071 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 16072 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 16073 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 16074 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 16075 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 16076 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 16077 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 16078 16079 #undef IS_ARRAY_BUFFER_VIEW_TEST 16080 16081 16082 16083 THREADED_TEST(ScriptContextDependence) { 16084 LocalContext c1; 16085 v8::HandleScope scope(c1->GetIsolate()); 16086 const char *source = "foo"; 16087 v8::Local<v8::Script> dep = v8_compile(source); 16088 v8::ScriptCompiler::Source script_source( 16089 v8::String::NewFromUtf8(c1->GetIsolate(), source, 16090 v8::NewStringType::kNormal) 16091 .ToLocalChecked()); 16092 v8::Local<v8::UnboundScript> indep = 16093 v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source) 16094 .ToLocalChecked(); 16095 c1->Global() 16096 ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo", 16097 v8::NewStringType::kNormal) 16098 .ToLocalChecked(), 16099 v8::Integer::New(c1->GetIsolate(), 100)) 16100 .FromJust(); 16101 CHECK_EQ( 16102 dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(), 16103 100); 16104 CHECK_EQ(indep->BindToCurrentContext() 16105 ->Run(c1.local()) 16106 .ToLocalChecked() 16107 ->Int32Value(c1.local()) 16108 .FromJust(), 16109 100); 16110 LocalContext c2; 16111 c2->Global() 16112 ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo", 16113 v8::NewStringType::kNormal) 16114 .ToLocalChecked(), 16115 v8::Integer::New(c2->GetIsolate(), 101)) 16116 .FromJust(); 16117 CHECK_EQ( 16118 dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(), 16119 100); 16120 CHECK_EQ(indep->BindToCurrentContext() 16121 ->Run(c2.local()) 16122 .ToLocalChecked() 16123 ->Int32Value(c2.local()) 16124 .FromJust(), 16125 101); 16126 } 16127 16128 16129 THREADED_TEST(StackTrace) { 16130 LocalContext context; 16131 v8::HandleScope scope(context->GetIsolate()); 16132 v8::TryCatch try_catch(context->GetIsolate()); 16133 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 16134 v8::Local<v8::String> src = v8_str(source); 16135 v8::Local<v8::String> origin = v8_str("stack-trace-test"); 16136 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin)); 16137 CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(), 16138 &script_source) 16139 .ToLocalChecked() 16140 ->BindToCurrentContext() 16141 ->Run(context.local()) 16142 .IsEmpty()); 16143 CHECK(try_catch.HasCaught()); 16144 v8::String::Utf8Value stack( 16145 try_catch.StackTrace(context.local()).ToLocalChecked()); 16146 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 16147 } 16148 16149 16150 // Checks that a StackFrame has certain expected values. 16151 void checkStackFrame(const char* expected_script_name, 16152 const char* expected_func_name, int expected_line_number, 16153 int expected_column, bool is_eval, bool is_constructor, 16154 v8::Local<v8::StackFrame> frame) { 16155 v8::HandleScope scope(CcTest::isolate()); 16156 v8::String::Utf8Value func_name(frame->GetFunctionName()); 16157 v8::String::Utf8Value script_name(frame->GetScriptName()); 16158 if (*script_name == NULL) { 16159 // The situation where there is no associated script, like for evals. 16160 CHECK(expected_script_name == NULL); 16161 } else { 16162 CHECK(strstr(*script_name, expected_script_name) != NULL); 16163 } 16164 CHECK(strstr(*func_name, expected_func_name) != NULL); 16165 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 16166 CHECK_EQ(expected_column, frame->GetColumn()); 16167 CHECK_EQ(is_eval, frame->IsEval()); 16168 CHECK_EQ(is_constructor, frame->IsConstructor()); 16169 } 16170 16171 16172 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 16173 v8::HandleScope scope(args.GetIsolate()); 16174 const char* origin = "capture-stack-trace-test"; 16175 const int kOverviewTest = 1; 16176 const int kDetailedTest = 2; 16177 const int kFunctionName = 3; 16178 const int kDisplayName = 4; 16179 const int kFunctionNameAndDisplayName = 5; 16180 const int kDisplayNameIsNotString = 6; 16181 const int kFunctionNameIsNotString = 7; 16182 16183 CHECK(args.Length() == 1); 16184 16185 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 16186 int testGroup = args[0]->Int32Value(context).FromJust(); 16187 if (testGroup == kOverviewTest) { 16188 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16189 args.GetIsolate(), 10, v8::StackTrace::kOverview); 16190 CHECK_EQ(4, stackTrace->GetFrameCount()); 16191 checkStackFrame(origin, "bar", 2, 10, false, false, 16192 stackTrace->GetFrame(0)); 16193 checkStackFrame(origin, "foo", 6, 3, false, false, 16194 stackTrace->GetFrame(1)); 16195 // This is the source string inside the eval which has the call to foo. 16196 checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2)); 16197 // The last frame is an anonymous function which has the initial eval call. 16198 checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3)); 16199 16200 CHECK(stackTrace->AsArray()->IsArray()); 16201 } else if (testGroup == kDetailedTest) { 16202 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16203 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 16204 CHECK_EQ(4, stackTrace->GetFrameCount()); 16205 checkStackFrame(origin, "bat", 4, 22, false, false, 16206 stackTrace->GetFrame(0)); 16207 checkStackFrame(origin, "baz", 8, 3, false, true, 16208 stackTrace->GetFrame(1)); 16209 bool is_eval = true; 16210 // This is the source string inside the eval which has the call to baz. 16211 checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2)); 16212 // The last frame is an anonymous function which has the initial eval call. 16213 checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3)); 16214 16215 CHECK(stackTrace->AsArray()->IsArray()); 16216 } else if (testGroup == kFunctionName) { 16217 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16218 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16219 CHECK_EQ(3, stackTrace->GetFrameCount()); 16220 checkStackFrame(origin, "function.name", 2, 24, false, false, 16221 stackTrace->GetFrame(0)); 16222 } else if (testGroup == kDisplayName) { 16223 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16224 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16225 CHECK_EQ(3, stackTrace->GetFrameCount()); 16226 checkStackFrame(origin, "function.displayName", 2, 24, false, false, 16227 stackTrace->GetFrame(0)); 16228 } else if (testGroup == kFunctionNameAndDisplayName) { 16229 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16230 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16231 CHECK_EQ(3, stackTrace->GetFrameCount()); 16232 checkStackFrame(origin, "function.displayName", 2, 24, false, false, 16233 stackTrace->GetFrame(0)); 16234 } else if (testGroup == kDisplayNameIsNotString) { 16235 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16236 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16237 CHECK_EQ(3, stackTrace->GetFrameCount()); 16238 checkStackFrame(origin, "function.name", 2, 24, false, false, 16239 stackTrace->GetFrame(0)); 16240 } else if (testGroup == kFunctionNameIsNotString) { 16241 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16242 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16243 CHECK_EQ(3, stackTrace->GetFrameCount()); 16244 checkStackFrame(origin, "f", 2, 24, false, false, stackTrace->GetFrame(0)); 16245 } 16246 } 16247 16248 16249 // Tests the C++ StackTrace API. 16250 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 16251 // THREADED_TEST(CaptureStackTrace) { 16252 TEST(CaptureStackTrace) { 16253 v8::Isolate* isolate = CcTest::isolate(); 16254 v8::HandleScope scope(isolate); 16255 v8::Local<v8::String> origin = v8_str("capture-stack-trace-test"); 16256 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 16257 templ->Set(v8_str("AnalyzeStackInNativeCode"), 16258 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode)); 16259 LocalContext context(0, templ); 16260 16261 // Test getting OVERVIEW information. Should ignore information that is not 16262 // script name, function name, line number, and column offset. 16263 const char *overview_source = 16264 "function bar() {\n" 16265 " var y; AnalyzeStackInNativeCode(1);\n" 16266 "}\n" 16267 "function foo() {\n" 16268 "\n" 16269 " bar();\n" 16270 "}\n" 16271 "var x;eval('new foo();');"; 16272 v8::Local<v8::String> overview_src = v8_str(overview_source); 16273 v8::ScriptCompiler::Source script_source(overview_src, 16274 v8::ScriptOrigin(origin)); 16275 v8::Local<Value> overview_result( 16276 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source) 16277 .ToLocalChecked() 16278 ->BindToCurrentContext() 16279 ->Run(context.local()) 16280 .ToLocalChecked()); 16281 CHECK(!overview_result.IsEmpty()); 16282 CHECK(overview_result->IsObject()); 16283 16284 // Test getting DETAILED information. 16285 const char *detailed_source = 16286 "function bat() {AnalyzeStackInNativeCode(2);\n" 16287 "}\n" 16288 "\n" 16289 "function baz() {\n" 16290 " bat();\n" 16291 "}\n" 16292 "eval('new baz();');"; 16293 v8::Local<v8::String> detailed_src = v8_str(detailed_source); 16294 // Make the script using a non-zero line and column offset. 16295 v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3); 16296 v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5); 16297 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 16298 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin); 16299 v8::Local<v8::UnboundScript> detailed_script( 16300 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2) 16301 .ToLocalChecked()); 16302 v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext() 16303 ->Run(context.local()) 16304 .ToLocalChecked()); 16305 CHECK(!detailed_result.IsEmpty()); 16306 CHECK(detailed_result->IsObject()); 16307 16308 // Test using function.name and function.displayName in stack trace 16309 const char* function_name_source = 16310 "function bar(function_name, display_name, testGroup) {\n" 16311 " var f = function() { AnalyzeStackInNativeCode(testGroup); };\n" 16312 " if (function_name) {\n" 16313 " Object.defineProperty(f, 'name', { value: function_name });\n" 16314 " }\n" 16315 " if (display_name) {\n" 16316 " f.displayName = display_name;" 16317 " }\n" 16318 " f()\n" 16319 "}\n" 16320 "bar('function.name', undefined, 3);\n" 16321 "bar(undefined, 'function.displayName', 4);\n" 16322 "bar('function.name', 'function.displayName', 5);\n" 16323 "bar('function.name', 239, 6);\n" 16324 "bar(239, undefined, 7);\n"; 16325 v8::Local<v8::String> function_name_src = 16326 v8::String::NewFromUtf8(isolate, function_name_source, 16327 v8::NewStringType::kNormal) 16328 .ToLocalChecked(); 16329 v8::ScriptCompiler::Source script_source3(function_name_src, 16330 v8::ScriptOrigin(origin)); 16331 v8::Local<Value> function_name_result( 16332 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3) 16333 .ToLocalChecked() 16334 ->BindToCurrentContext() 16335 ->Run(context.local()) 16336 .ToLocalChecked()); 16337 CHECK(!function_name_result.IsEmpty()); 16338 } 16339 16340 16341 static void StackTraceForUncaughtExceptionListener( 16342 v8::Local<v8::Message> message, v8::Local<Value>) { 16343 report_count++; 16344 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16345 CHECK_EQ(2, stack_trace->GetFrameCount()); 16346 checkStackFrame("origin", "foo", 2, 3, false, false, 16347 stack_trace->GetFrame(0)); 16348 checkStackFrame("origin", "bar", 5, 3, false, false, 16349 stack_trace->GetFrame(1)); 16350 } 16351 16352 16353 TEST(CaptureStackTraceForUncaughtException) { 16354 report_count = 0; 16355 LocalContext env; 16356 v8::Isolate* isolate = env->GetIsolate(); 16357 v8::HandleScope scope(isolate); 16358 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener); 16359 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16360 16361 CompileRunWithOrigin( 16362 "function foo() {\n" 16363 " throw 1;\n" 16364 "};\n" 16365 "function bar() {\n" 16366 " foo();\n" 16367 "};", 16368 "origin"); 16369 v8::Local<v8::Object> global = env->Global(); 16370 Local<Value> trouble = 16371 global->Get(env.local(), v8_str("bar")).ToLocalChecked(); 16372 CHECK(trouble->IsFunction()); 16373 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty()); 16374 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16375 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 16376 CHECK_EQ(1, report_count); 16377 } 16378 16379 16380 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) { 16381 report_count = 0; 16382 LocalContext env; 16383 v8::Isolate* isolate = env->GetIsolate(); 16384 v8::HandleScope scope(isolate); 16385 16386 // Create an Error object first. 16387 CompileRunWithOrigin( 16388 "function foo() {\n" 16389 "e=new Error('err');\n" 16390 "};\n" 16391 "function bar() {\n" 16392 " foo();\n" 16393 "};\n" 16394 "var e;", 16395 "origin"); 16396 v8::Local<v8::Object> global = env->Global(); 16397 Local<Value> trouble = 16398 global->Get(env.local(), v8_str("bar")).ToLocalChecked(); 16399 CHECK(trouble->IsFunction()); 16400 Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).ToLocalChecked(); 16401 16402 // Enable capturing detailed stack trace late, and throw the exception. 16403 // The detailed stack trace should be extracted from the simple stack. 16404 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener); 16405 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16406 CompileRunWithOrigin("throw e", "origin"); 16407 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16408 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 16409 CHECK_EQ(1, report_count); 16410 } 16411 16412 16413 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 16414 LocalContext env; 16415 v8::Isolate* isolate = env->GetIsolate(); 16416 v8::HandleScope scope(isolate); 16417 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024, 16418 v8::StackTrace::kDetailed); 16419 16420 CompileRun( 16421 "var setters = ['column', 'lineNumber', 'scriptName',\n" 16422 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 16423 " 'isConstructor'];\n" 16424 "for (var i = 0; i < setters.length; i++) {\n" 16425 " var prop = setters[i];\n" 16426 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 16427 "}\n"); 16428 CompileRun("throw 'exception';"); 16429 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16430 } 16431 16432 16433 static void StackTraceFunctionNameListener(v8::Local<v8::Message> message, 16434 v8::Local<Value>) { 16435 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16436 CHECK_EQ(5, stack_trace->GetFrameCount()); 16437 checkStackFrame("origin", "foo:0", 4, 7, false, false, 16438 stack_trace->GetFrame(0)); 16439 checkStackFrame("origin", "foo:1", 5, 27, false, false, 16440 stack_trace->GetFrame(1)); 16441 checkStackFrame("origin", "foo", 5, 27, false, false, 16442 stack_trace->GetFrame(2)); 16443 checkStackFrame("origin", "foo", 5, 27, false, false, 16444 stack_trace->GetFrame(3)); 16445 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4)); 16446 } 16447 16448 16449 TEST(GetStackTraceContainsFunctionsWithFunctionName) { 16450 LocalContext env; 16451 v8::Isolate* isolate = env->GetIsolate(); 16452 v8::HandleScope scope(isolate); 16453 16454 CompileRunWithOrigin( 16455 "function gen(name, counter) {\n" 16456 " var f = function foo() {\n" 16457 " if (counter === 0)\n" 16458 " throw 1;\n" 16459 " gen(name, counter - 1)();\n" 16460 " };\n" 16461 " if (counter == 3) {\n" 16462 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n" 16463 " } else {\n" 16464 " Object.defineProperty(f, 'name', {writable:true});\n" 16465 " if (counter == 2)\n" 16466 " f.name = 42;\n" 16467 " else\n" 16468 " f.name = name + ':' + counter;\n" 16469 " }\n" 16470 " return f;\n" 16471 "};", 16472 "origin"); 16473 16474 isolate->AddMessageListener(StackTraceFunctionNameListener); 16475 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16476 CompileRunWithOrigin("gen('foo', 3)();", "origin"); 16477 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16478 isolate->RemoveMessageListeners(StackTraceFunctionNameListener); 16479 } 16480 16481 16482 static void RethrowStackTraceHandler(v8::Local<v8::Message> message, 16483 v8::Local<v8::Value> data) { 16484 // Use the frame where JavaScript is called from. 16485 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16486 CHECK(!stack_trace.IsEmpty()); 16487 int frame_count = stack_trace->GetFrameCount(); 16488 CHECK_EQ(3, frame_count); 16489 int line_number[] = {1, 2, 5}; 16490 for (int i = 0; i < frame_count; i++) { 16491 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16492 } 16493 } 16494 16495 16496 // Test that we only return the stack trace at the site where the exception 16497 // is first thrown (not where it is rethrown). 16498 TEST(RethrowStackTrace) { 16499 LocalContext env; 16500 v8::Isolate* isolate = env->GetIsolate(); 16501 v8::HandleScope scope(isolate); 16502 // We make sure that 16503 // - the stack trace of the ReferenceError in g() is reported. 16504 // - the stack trace is not overwritten when e1 is rethrown by t(). 16505 // - the stack trace of e2 does not overwrite that of e1. 16506 const char* source = 16507 "function g() { error; } \n" 16508 "function f() { g(); } \n" 16509 "function t(e) { throw e; } \n" 16510 "try { \n" 16511 " f(); \n" 16512 "} catch (e1) { \n" 16513 " try { \n" 16514 " error; \n" 16515 " } catch (e2) { \n" 16516 " t(e1); \n" 16517 " } \n" 16518 "} \n"; 16519 isolate->AddMessageListener(RethrowStackTraceHandler); 16520 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16521 CompileRun(source); 16522 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16523 isolate->RemoveMessageListeners(RethrowStackTraceHandler); 16524 } 16525 16526 16527 static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message, 16528 v8::Local<v8::Value> data) { 16529 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16530 CHECK(!stack_trace.IsEmpty()); 16531 int frame_count = stack_trace->GetFrameCount(); 16532 CHECK_EQ(2, frame_count); 16533 int line_number[] = {3, 7}; 16534 for (int i = 0; i < frame_count; i++) { 16535 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16536 } 16537 } 16538 16539 16540 // Test that we do not recognize identity for primitive exceptions. 16541 TEST(RethrowPrimitiveStackTrace) { 16542 LocalContext env; 16543 v8::Isolate* isolate = env->GetIsolate(); 16544 v8::HandleScope scope(isolate); 16545 // We do not capture stack trace for non Error objects on creation time. 16546 // Instead, we capture the stack trace on last throw. 16547 const char* source = 16548 "function g() { throw 404; } \n" 16549 "function f() { g(); } \n" 16550 "function t(e) { throw e; } \n" 16551 "try { \n" 16552 " f(); \n" 16553 "} catch (e1) { \n" 16554 " t(e1) \n" 16555 "} \n"; 16556 isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler); 16557 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16558 CompileRun(source); 16559 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16560 isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 16561 } 16562 16563 16564 static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message, 16565 v8::Local<v8::Value> data) { 16566 // Use the frame where JavaScript is called from. 16567 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16568 CHECK(!stack_trace.IsEmpty()); 16569 CHECK_EQ(1, stack_trace->GetFrameCount()); 16570 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 16571 } 16572 16573 16574 // Test that the stack trace is captured when the error object is created and 16575 // not where it is thrown. 16576 TEST(RethrowExistingStackTrace) { 16577 LocalContext env; 16578 v8::Isolate* isolate = env->GetIsolate(); 16579 v8::HandleScope scope(isolate); 16580 const char* source = 16581 "var e = new Error(); \n" 16582 "throw e; \n"; 16583 isolate->AddMessageListener(RethrowExistingStackTraceHandler); 16584 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16585 CompileRun(source); 16586 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16587 isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler); 16588 } 16589 16590 16591 static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message, 16592 v8::Local<v8::Value> data) { 16593 // Use the frame where JavaScript is called from. 16594 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16595 CHECK(!stack_trace.IsEmpty()); 16596 CHECK_EQ(1, stack_trace->GetFrameCount()); 16597 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 16598 } 16599 16600 16601 // Test that the stack trace is captured where the bogus Error object is thrown. 16602 TEST(RethrowBogusErrorStackTrace) { 16603 LocalContext env; 16604 v8::Isolate* isolate = env->GetIsolate(); 16605 v8::HandleScope scope(isolate); 16606 const char* source = 16607 "var e = {__proto__: new Error()} \n" 16608 "throw e; \n"; 16609 isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler); 16610 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16611 CompileRun(source); 16612 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16613 isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 16614 } 16615 16616 16617 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler; 16618 int promise_reject_counter = 0; 16619 int promise_revoke_counter = 0; 16620 int promise_reject_msg_line_number = -1; 16621 int promise_reject_msg_column_number = -1; 16622 int promise_reject_line_number = -1; 16623 int promise_reject_column_number = -1; 16624 int promise_reject_frame_count = -1; 16625 16626 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) { 16627 v8::Local<v8::Object> global = CcTest::global(); 16628 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 16629 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) { 16630 promise_reject_counter++; 16631 global->Set(context, v8_str("rejected"), reject_message.GetPromise()) 16632 .FromJust(); 16633 global->Set(context, v8_str("value"), reject_message.GetValue()).FromJust(); 16634 v8::Local<v8::Message> message = v8::Exception::CreateMessage( 16635 CcTest::isolate(), reject_message.GetValue()); 16636 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16637 16638 promise_reject_msg_line_number = message->GetLineNumber(context).FromJust(); 16639 promise_reject_msg_column_number = 16640 message->GetStartColumn(context).FromJust() + 1; 16641 16642 if (!stack_trace.IsEmpty()) { 16643 promise_reject_frame_count = stack_trace->GetFrameCount(); 16644 if (promise_reject_frame_count > 0) { 16645 CHECK(stack_trace->GetFrame(0) 16646 ->GetScriptName() 16647 ->Equals(context, v8_str("pro")) 16648 .FromJust()); 16649 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber(); 16650 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn(); 16651 } else { 16652 promise_reject_line_number = -1; 16653 promise_reject_column_number = -1; 16654 } 16655 } 16656 } else { 16657 promise_revoke_counter++; 16658 global->Set(context, v8_str("revoked"), reject_message.GetPromise()) 16659 .FromJust(); 16660 CHECK(reject_message.GetValue().IsEmpty()); 16661 } 16662 } 16663 16664 16665 v8::Local<v8::Promise> GetPromise(const char* name) { 16666 return v8::Local<v8::Promise>::Cast( 16667 CcTest::global() 16668 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name)) 16669 .ToLocalChecked()); 16670 } 16671 16672 16673 v8::Local<v8::Value> RejectValue() { 16674 return CcTest::global() 16675 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value")) 16676 .ToLocalChecked(); 16677 } 16678 16679 16680 void ResetPromiseStates() { 16681 promise_reject_counter = 0; 16682 promise_revoke_counter = 0; 16683 promise_reject_msg_line_number = -1; 16684 promise_reject_msg_column_number = -1; 16685 promise_reject_line_number = -1; 16686 promise_reject_column_number = -1; 16687 promise_reject_frame_count = -1; 16688 16689 v8::Local<v8::Object> global = CcTest::global(); 16690 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 16691 global->Set(context, v8_str("rejected"), v8_str("")).FromJust(); 16692 global->Set(context, v8_str("value"), v8_str("")).FromJust(); 16693 global->Set(context, v8_str("revoked"), v8_str("")).FromJust(); 16694 } 16695 16696 16697 TEST(PromiseRejectCallback) { 16698 LocalContext env; 16699 v8::Isolate* isolate = env->GetIsolate(); 16700 v8::HandleScope scope(isolate); 16701 16702 isolate->SetPromiseRejectCallback(PromiseRejectCallback); 16703 16704 ResetPromiseStates(); 16705 16706 // Create promise p0. 16707 CompileRun( 16708 "var reject; \n" 16709 "var p0 = new Promise( \n" 16710 " function(res, rej) { \n" 16711 " reject = rej; \n" 16712 " } \n" 16713 "); \n"); 16714 CHECK(!GetPromise("p0")->HasHandler()); 16715 CHECK_EQ(0, promise_reject_counter); 16716 CHECK_EQ(0, promise_revoke_counter); 16717 16718 // Add resolve handler (and default reject handler) to p0. 16719 CompileRun("var p1 = p0.then(function(){});"); 16720 CHECK(GetPromise("p0")->HasHandler()); 16721 CHECK(!GetPromise("p1")->HasHandler()); 16722 CHECK_EQ(0, promise_reject_counter); 16723 CHECK_EQ(0, promise_revoke_counter); 16724 16725 // Reject p0. 16726 CompileRun("reject('ppp');"); 16727 CHECK(GetPromise("p0")->HasHandler()); 16728 CHECK(!GetPromise("p1")->HasHandler()); 16729 CHECK_EQ(1, promise_reject_counter); 16730 CHECK_EQ(0, promise_revoke_counter); 16731 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event); 16732 CHECK( 16733 GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust()); 16734 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust()); 16735 16736 // Reject p0 again. Callback is not triggered again. 16737 CompileRun("reject();"); 16738 CHECK(GetPromise("p0")->HasHandler()); 16739 CHECK(!GetPromise("p1")->HasHandler()); 16740 CHECK_EQ(1, promise_reject_counter); 16741 CHECK_EQ(0, promise_revoke_counter); 16742 16743 // Add resolve handler to p1. 16744 CompileRun("var p2 = p1.then(function(){});"); 16745 CHECK(GetPromise("p0")->HasHandler()); 16746 CHECK(GetPromise("p1")->HasHandler()); 16747 CHECK(!GetPromise("p2")->HasHandler()); 16748 CHECK_EQ(2, promise_reject_counter); 16749 CHECK_EQ(1, promise_revoke_counter); 16750 CHECK( 16751 GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust()); 16752 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust()); 16753 CHECK( 16754 GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust()); 16755 16756 ResetPromiseStates(); 16757 16758 // Create promise q0. 16759 CompileRun( 16760 "var q0 = new Promise( \n" 16761 " function(res, rej) { \n" 16762 " reject = rej; \n" 16763 " } \n" 16764 "); \n"); 16765 CHECK(!GetPromise("q0")->HasHandler()); 16766 CHECK_EQ(0, promise_reject_counter); 16767 CHECK_EQ(0, promise_revoke_counter); 16768 16769 // Add reject handler to q0. 16770 CompileRun("var q1 = q0.catch(function() {});"); 16771 CHECK(GetPromise("q0")->HasHandler()); 16772 CHECK(!GetPromise("q1")->HasHandler()); 16773 CHECK_EQ(0, promise_reject_counter); 16774 CHECK_EQ(0, promise_revoke_counter); 16775 16776 // Reject q0. 16777 CompileRun("reject('qq')"); 16778 CHECK(GetPromise("q0")->HasHandler()); 16779 CHECK(!GetPromise("q1")->HasHandler()); 16780 CHECK_EQ(0, promise_reject_counter); 16781 CHECK_EQ(0, promise_revoke_counter); 16782 16783 // Add a new reject handler, which rejects by returning Promise.reject(). 16784 // The returned promise q_ triggers a reject callback at first, only to 16785 // revoke it when returning it causes q2 to be rejected. 16786 CompileRun( 16787 "var q_;" 16788 "var q2 = q0.catch( \n" 16789 " function() { \n" 16790 " q_ = Promise.reject('qqq'); \n" 16791 " return q_; \n" 16792 " } \n" 16793 "); \n"); 16794 CHECK(GetPromise("q0")->HasHandler()); 16795 CHECK(!GetPromise("q1")->HasHandler()); 16796 CHECK(!GetPromise("q2")->HasHandler()); 16797 CHECK(GetPromise("q_")->HasHandler()); 16798 CHECK_EQ(2, promise_reject_counter); 16799 CHECK_EQ(1, promise_revoke_counter); 16800 CHECK( 16801 GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust()); 16802 CHECK( 16803 GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust()); 16804 CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust()); 16805 16806 // Add a reject handler to the resolved q1, which rejects by throwing. 16807 CompileRun( 16808 "var q3 = q1.then( \n" 16809 " function() { \n" 16810 " throw 'qqqq'; \n" 16811 " } \n" 16812 "); \n"); 16813 CHECK(GetPromise("q0")->HasHandler()); 16814 CHECK(GetPromise("q1")->HasHandler()); 16815 CHECK(!GetPromise("q2")->HasHandler()); 16816 CHECK(!GetPromise("q3")->HasHandler()); 16817 CHECK_EQ(3, promise_reject_counter); 16818 CHECK_EQ(1, promise_revoke_counter); 16819 CHECK( 16820 GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust()); 16821 CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust()); 16822 16823 ResetPromiseStates(); 16824 16825 // Create promise r0, which has three handlers, two of which handle rejects. 16826 CompileRun( 16827 "var r0 = new Promise( \n" 16828 " function(res, rej) { \n" 16829 " reject = rej; \n" 16830 " } \n" 16831 "); \n" 16832 "var r1 = r0.catch(function() {}); \n" 16833 "var r2 = r0.then(function() {}); \n" 16834 "var r3 = r0.then(function() {}, \n" 16835 " function() {}); \n"); 16836 CHECK(GetPromise("r0")->HasHandler()); 16837 CHECK(!GetPromise("r1")->HasHandler()); 16838 CHECK(!GetPromise("r2")->HasHandler()); 16839 CHECK(!GetPromise("r3")->HasHandler()); 16840 CHECK_EQ(0, promise_reject_counter); 16841 CHECK_EQ(0, promise_revoke_counter); 16842 16843 // Reject r0. 16844 CompileRun("reject('rrr')"); 16845 CHECK(GetPromise("r0")->HasHandler()); 16846 CHECK(!GetPromise("r1")->HasHandler()); 16847 CHECK(!GetPromise("r2")->HasHandler()); 16848 CHECK(!GetPromise("r3")->HasHandler()); 16849 CHECK_EQ(1, promise_reject_counter); 16850 CHECK_EQ(0, promise_revoke_counter); 16851 CHECK( 16852 GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust()); 16853 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust()); 16854 16855 // Add reject handler to r2. 16856 CompileRun("var r4 = r2.catch(function() {});"); 16857 CHECK(GetPromise("r0")->HasHandler()); 16858 CHECK(!GetPromise("r1")->HasHandler()); 16859 CHECK(GetPromise("r2")->HasHandler()); 16860 CHECK(!GetPromise("r3")->HasHandler()); 16861 CHECK(!GetPromise("r4")->HasHandler()); 16862 CHECK_EQ(1, promise_reject_counter); 16863 CHECK_EQ(1, promise_revoke_counter); 16864 CHECK( 16865 GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust()); 16866 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust()); 16867 16868 // Add reject handlers to r4. 16869 CompileRun("var r5 = r4.then(function() {}, function() {});"); 16870 CHECK(GetPromise("r0")->HasHandler()); 16871 CHECK(!GetPromise("r1")->HasHandler()); 16872 CHECK(GetPromise("r2")->HasHandler()); 16873 CHECK(!GetPromise("r3")->HasHandler()); 16874 CHECK(GetPromise("r4")->HasHandler()); 16875 CHECK(!GetPromise("r5")->HasHandler()); 16876 CHECK_EQ(1, promise_reject_counter); 16877 CHECK_EQ(1, promise_revoke_counter); 16878 16879 ResetPromiseStates(); 16880 16881 // Create promise s0, which has three handlers, none of which handle rejects. 16882 CompileRun( 16883 "var s0 = new Promise( \n" 16884 " function(res, rej) { \n" 16885 " reject = rej; \n" 16886 " } \n" 16887 "); \n" 16888 "var s1 = s0.then(function() {}); \n" 16889 "var s2 = s0.then(function() {}); \n" 16890 "var s3 = s0.then(function() {}); \n"); 16891 CHECK(GetPromise("s0")->HasHandler()); 16892 CHECK(!GetPromise("s1")->HasHandler()); 16893 CHECK(!GetPromise("s2")->HasHandler()); 16894 CHECK(!GetPromise("s3")->HasHandler()); 16895 CHECK_EQ(0, promise_reject_counter); 16896 CHECK_EQ(0, promise_revoke_counter); 16897 16898 // Reject s0. 16899 CompileRun("reject('sss')"); 16900 CHECK(GetPromise("s0")->HasHandler()); 16901 CHECK(!GetPromise("s1")->HasHandler()); 16902 CHECK(!GetPromise("s2")->HasHandler()); 16903 CHECK(!GetPromise("s3")->HasHandler()); 16904 CHECK_EQ(3, promise_reject_counter); 16905 CHECK_EQ(0, promise_revoke_counter); 16906 CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust()); 16907 16908 // Test stack frames. 16909 env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true); 16910 16911 ResetPromiseStates(); 16912 16913 // Create promise t0, which is rejected in the constructor with an error. 16914 CompileRunWithOrigin( 16915 "var t0 = new Promise( \n" 16916 " function(res, rej) { \n" 16917 " reference_error; \n" 16918 " } \n" 16919 "); \n", 16920 "pro", 0, 0); 16921 CHECK(!GetPromise("t0")->HasHandler()); 16922 CHECK_EQ(1, promise_reject_counter); 16923 CHECK_EQ(0, promise_revoke_counter); 16924 CHECK_EQ(2, promise_reject_frame_count); 16925 CHECK_EQ(3, promise_reject_line_number); 16926 CHECK_EQ(5, promise_reject_column_number); 16927 CHECK_EQ(3, promise_reject_msg_line_number); 16928 CHECK_EQ(5, promise_reject_msg_column_number); 16929 16930 ResetPromiseStates(); 16931 16932 // Create promise u0 and chain u1 to it, which is rejected via throw. 16933 CompileRunWithOrigin( 16934 "var u0 = Promise.resolve(); \n" 16935 "var u1 = u0.then( \n" 16936 " function() { \n" 16937 " (function() { \n" 16938 " throw new Error(); \n" 16939 " })(); \n" 16940 " } \n" 16941 " ); \n", 16942 "pro", 0, 0); 16943 CHECK(GetPromise("u0")->HasHandler()); 16944 CHECK(!GetPromise("u1")->HasHandler()); 16945 CHECK_EQ(1, promise_reject_counter); 16946 CHECK_EQ(0, promise_revoke_counter); 16947 CHECK_EQ(2, promise_reject_frame_count); 16948 CHECK_EQ(5, promise_reject_line_number); 16949 CHECK_EQ(23, promise_reject_column_number); 16950 CHECK_EQ(5, promise_reject_msg_line_number); 16951 CHECK_EQ(23, promise_reject_msg_column_number); 16952 16953 // Throw in u3, which handles u1's rejection. 16954 CompileRunWithOrigin( 16955 "function f() { \n" 16956 " return (function() { \n" 16957 " return new Error(); \n" 16958 " })(); \n" 16959 "} \n" 16960 "var u2 = Promise.reject(f()); \n" 16961 "var u3 = u1.catch( \n" 16962 " function() { \n" 16963 " return u2; \n" 16964 " } \n" 16965 " ); \n", 16966 "pro", 0, 0); 16967 CHECK(GetPromise("u0")->HasHandler()); 16968 CHECK(GetPromise("u1")->HasHandler()); 16969 CHECK(GetPromise("u2")->HasHandler()); 16970 CHECK(!GetPromise("u3")->HasHandler()); 16971 CHECK_EQ(3, promise_reject_counter); 16972 CHECK_EQ(2, promise_revoke_counter); 16973 CHECK_EQ(3, promise_reject_frame_count); 16974 CHECK_EQ(3, promise_reject_line_number); 16975 CHECK_EQ(12, promise_reject_column_number); 16976 CHECK_EQ(3, promise_reject_msg_line_number); 16977 CHECK_EQ(12, promise_reject_msg_column_number); 16978 16979 ResetPromiseStates(); 16980 16981 // Create promise rejected promise v0, which is incorrectly handled by v1 16982 // via chaining cycle. 16983 CompileRunWithOrigin( 16984 "var v0 = Promise.reject(); \n" 16985 "var v1 = v0.catch( \n" 16986 " function() { \n" 16987 " return v1; \n" 16988 " } \n" 16989 " ); \n", 16990 "pro", 0, 0); 16991 CHECK(GetPromise("v0")->HasHandler()); 16992 CHECK(!GetPromise("v1")->HasHandler()); 16993 CHECK_EQ(2, promise_reject_counter); 16994 CHECK_EQ(1, promise_revoke_counter); 16995 CHECK_EQ(0, promise_reject_frame_count); 16996 CHECK_EQ(-1, promise_reject_line_number); 16997 CHECK_EQ(-1, promise_reject_column_number); 16998 16999 ResetPromiseStates(); 17000 17001 // Create promise t1, which rejects by throwing syntax error from eval. 17002 CompileRunWithOrigin( 17003 "var t1 = new Promise( \n" 17004 " function(res, rej) { \n" 17005 " var content = '\\n\\\n" 17006 " }'; \n" 17007 " eval(content); \n" 17008 " } \n" 17009 "); \n", 17010 "pro", 0, 0); 17011 CHECK(!GetPromise("t1")->HasHandler()); 17012 CHECK_EQ(1, promise_reject_counter); 17013 CHECK_EQ(0, promise_revoke_counter); 17014 CHECK_EQ(2, promise_reject_frame_count); 17015 CHECK_EQ(5, promise_reject_line_number); 17016 CHECK_EQ(10, promise_reject_column_number); 17017 CHECK_EQ(2, promise_reject_msg_line_number); 17018 CHECK_EQ(7, promise_reject_msg_column_number); 17019 } 17020 17021 17022 void AnalyzeStackOfEvalWithSourceURL( 17023 const v8::FunctionCallbackInfo<v8::Value>& args) { 17024 v8::HandleScope scope(args.GetIsolate()); 17025 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17026 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17027 CHECK_EQ(5, stackTrace->GetFrameCount()); 17028 v8::Local<v8::String> url = v8_str("eval_url"); 17029 for (int i = 0; i < 3; i++) { 17030 v8::Local<v8::String> name = 17031 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17032 CHECK(!name.IsEmpty()); 17033 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17034 } 17035 } 17036 17037 17038 TEST(SourceURLInStackTrace) { 17039 v8::Isolate* isolate = CcTest::isolate(); 17040 v8::HandleScope scope(isolate); 17041 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17042 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 17043 v8::FunctionTemplate::New(isolate, 17044 AnalyzeStackOfEvalWithSourceURL)); 17045 LocalContext context(0, templ); 17046 17047 const char *source = 17048 "function outer() {\n" 17049 "function bar() {\n" 17050 " AnalyzeStackOfEvalWithSourceURL();\n" 17051 "}\n" 17052 "function foo() {\n" 17053 "\n" 17054 " bar();\n" 17055 "}\n" 17056 "foo();\n" 17057 "}\n" 17058 "eval('(' + outer +')()%s');"; 17059 17060 i::ScopedVector<char> code(1024); 17061 i::SNPrintF(code, source, "//# sourceURL=eval_url"); 17062 CHECK(CompileRun(code.start())->IsUndefined()); 17063 i::SNPrintF(code, source, "//@ sourceURL=eval_url"); 17064 CHECK(CompileRun(code.start())->IsUndefined()); 17065 } 17066 17067 17068 static int scriptIdInStack[2]; 17069 17070 void AnalyzeScriptIdInStack( 17071 const v8::FunctionCallbackInfo<v8::Value>& args) { 17072 v8::HandleScope scope(args.GetIsolate()); 17073 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17074 args.GetIsolate(), 10, v8::StackTrace::kScriptId); 17075 CHECK_EQ(2, stackTrace->GetFrameCount()); 17076 for (int i = 0; i < 2; i++) { 17077 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId(); 17078 } 17079 } 17080 17081 17082 TEST(ScriptIdInStackTrace) { 17083 v8::Isolate* isolate = CcTest::isolate(); 17084 v8::HandleScope scope(isolate); 17085 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17086 templ->Set(v8_str("AnalyzeScriptIdInStack"), 17087 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack)); 17088 LocalContext context(0, templ); 17089 17090 v8::Local<v8::String> scriptSource = v8_str( 17091 "function foo() {\n" 17092 " AnalyzeScriptIdInStack();" 17093 "}\n" 17094 "foo();\n"); 17095 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test"); 17096 script->Run(context.local()).ToLocalChecked(); 17097 for (int i = 0; i < 2; i++) { 17098 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); 17099 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId()); 17100 } 17101 } 17102 17103 17104 void AnalyzeStackOfInlineScriptWithSourceURL( 17105 const v8::FunctionCallbackInfo<v8::Value>& args) { 17106 v8::HandleScope scope(args.GetIsolate()); 17107 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17108 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17109 CHECK_EQ(4, stackTrace->GetFrameCount()); 17110 v8::Local<v8::String> url = v8_str("source_url"); 17111 for (int i = 0; i < 3; i++) { 17112 v8::Local<v8::String> name = 17113 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17114 CHECK(!name.IsEmpty()); 17115 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17116 } 17117 } 17118 17119 17120 TEST(InlineScriptWithSourceURLInStackTrace) { 17121 v8::Isolate* isolate = CcTest::isolate(); 17122 v8::HandleScope scope(isolate); 17123 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17124 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 17125 v8::FunctionTemplate::New( 17126 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL)); 17127 LocalContext context(0, templ); 17128 17129 const char *source = 17130 "function outer() {\n" 17131 "function bar() {\n" 17132 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 17133 "}\n" 17134 "function foo() {\n" 17135 "\n" 17136 " bar();\n" 17137 "}\n" 17138 "foo();\n" 17139 "}\n" 17140 "outer()\n%s"; 17141 17142 i::ScopedVector<char> code(1024); 17143 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17144 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17145 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17146 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17147 } 17148 17149 17150 void AnalyzeStackOfDynamicScriptWithSourceURL( 17151 const v8::FunctionCallbackInfo<v8::Value>& args) { 17152 v8::HandleScope scope(args.GetIsolate()); 17153 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17154 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17155 CHECK_EQ(4, stackTrace->GetFrameCount()); 17156 v8::Local<v8::String> url = v8_str("source_url"); 17157 for (int i = 0; i < 3; i++) { 17158 v8::Local<v8::String> name = 17159 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17160 CHECK(!name.IsEmpty()); 17161 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17162 } 17163 } 17164 17165 17166 TEST(DynamicWithSourceURLInStackTrace) { 17167 v8::Isolate* isolate = CcTest::isolate(); 17168 v8::HandleScope scope(isolate); 17169 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17170 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 17171 v8::FunctionTemplate::New( 17172 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL)); 17173 LocalContext context(0, templ); 17174 17175 const char *source = 17176 "function outer() {\n" 17177 "function bar() {\n" 17178 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 17179 "}\n" 17180 "function foo() {\n" 17181 "\n" 17182 " bar();\n" 17183 "}\n" 17184 "foo();\n" 17185 "}\n" 17186 "outer()\n%s"; 17187 17188 i::ScopedVector<char> code(1024); 17189 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17190 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17191 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17192 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17193 } 17194 17195 17196 TEST(DynamicWithSourceURLInStackTraceString) { 17197 LocalContext context; 17198 v8::HandleScope scope(context->GetIsolate()); 17199 17200 const char *source = 17201 "function outer() {\n" 17202 " function foo() {\n" 17203 " FAIL.FAIL;\n" 17204 " }\n" 17205 " foo();\n" 17206 "}\n" 17207 "outer()\n%s"; 17208 17209 i::ScopedVector<char> code(1024); 17210 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17211 v8::TryCatch try_catch(context->GetIsolate()); 17212 CompileRunWithOrigin(code.start(), "", 0, 0); 17213 CHECK(try_catch.HasCaught()); 17214 v8::String::Utf8Value stack( 17215 try_catch.StackTrace(context.local()).ToLocalChecked()); 17216 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL); 17217 } 17218 17219 17220 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17221 LocalContext context; 17222 v8::HandleScope scope(context->GetIsolate()); 17223 17224 const char *source = 17225 "function outer() {\n" 17226 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n" 17227 " //# sourceURL=source_url\";\n" 17228 " eval(scriptContents);\n" 17229 " foo(); }\n" 17230 "outer();\n" 17231 "//# sourceURL=outer_url"; 17232 17233 v8::TryCatch try_catch(context->GetIsolate()); 17234 CompileRun(source); 17235 CHECK(try_catch.HasCaught()); 17236 17237 Local<v8::Message> message = try_catch.Message(); 17238 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName(); 17239 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url")); 17240 } 17241 17242 17243 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17244 LocalContext context; 17245 v8::HandleScope scope(context->GetIsolate()); 17246 17247 const char *source = 17248 "function outer() {\n" 17249 " var scriptContents = \"function boo(){ boo(); }\\\n" 17250 " //# sourceURL=source_url\";\n" 17251 " eval(scriptContents);\n" 17252 " boo(); }\n" 17253 "outer();\n" 17254 "//# sourceURL=outer_url"; 17255 17256 v8::TryCatch try_catch(context->GetIsolate()); 17257 CompileRun(source); 17258 CHECK(try_catch.HasCaught()); 17259 17260 Local<v8::Message> message = try_catch.Message(); 17261 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName(); 17262 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url")); 17263 } 17264 17265 17266 static void CreateGarbageInOldSpace() { 17267 i::Factory* factory = CcTest::i_isolate()->factory(); 17268 v8::HandleScope scope(CcTest::isolate()); 17269 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate()); 17270 for (int i = 0; i < 1000; i++) { 17271 factory->NewFixedArray(1000, i::TENURED); 17272 } 17273 } 17274 17275 17276 // Test that idle notification can be handled and eventually collects garbage. 17277 TEST(TestIdleNotification) { 17278 if (!i::FLAG_incremental_marking) return; 17279 const intptr_t MB = 1024 * 1024; 17280 const double IdlePauseInSeconds = 1.0; 17281 LocalContext env; 17282 v8::HandleScope scope(env->GetIsolate()); 17283 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17284 CreateGarbageInOldSpace(); 17285 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17286 CHECK_GT(size_with_garbage, initial_size + MB); 17287 bool finished = false; 17288 for (int i = 0; i < 200 && !finished; i++) { 17289 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) { 17290 CcTest::heap()->StartIdleIncrementalMarking(); 17291 } 17292 finished = env->GetIsolate()->IdleNotificationDeadline( 17293 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / 17294 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + 17295 IdlePauseInSeconds); 17296 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) { 17297 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted(); 17298 } 17299 } 17300 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17301 CHECK(finished); 17302 CHECK_LT(final_size, initial_size + 1); 17303 } 17304 17305 17306 TEST(Regress2333) { 17307 LocalContext env; 17308 for (int i = 0; i < 3; i++) { 17309 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 17310 } 17311 } 17312 17313 static uint32_t* stack_limit; 17314 17315 static void GetStackLimitCallback( 17316 const v8::FunctionCallbackInfo<v8::Value>& args) { 17317 stack_limit = reinterpret_cast<uint32_t*>( 17318 CcTest::i_isolate()->stack_guard()->real_climit()); 17319 } 17320 17321 17322 // Uses the address of a local variable to determine the stack top now. 17323 // Given a size, returns an address that is that far from the current 17324 // top of stack. 17325 static uint32_t* ComputeStackLimit(uint32_t size) { 17326 uint32_t* answer = &size - (size / sizeof(size)); 17327 // If the size is very large and the stack is very near the bottom of 17328 // memory then the calculation above may wrap around and give an address 17329 // that is above the (downwards-growing) stack. In that case we return 17330 // a very low address. 17331 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 17332 return answer; 17333 } 17334 17335 17336 // We need at least 165kB for an x64 debug build with clang and ASAN. 17337 static const int stack_breathing_room = 256 * i::KB; 17338 17339 17340 TEST(SetStackLimit) { 17341 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 17342 17343 // Set stack limit. 17344 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17345 17346 // Execute a script. 17347 LocalContext env; 17348 v8::HandleScope scope(env->GetIsolate()); 17349 Local<v8::FunctionTemplate> fun_templ = 17350 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback); 17351 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 17352 CHECK(env->Global() 17353 ->Set(env.local(), v8_str("get_stack_limit"), fun) 17354 .FromJust()); 17355 CompileRun("get_stack_limit();"); 17356 17357 CHECK(stack_limit == set_limit); 17358 } 17359 17360 17361 TEST(SetStackLimitInThread) { 17362 uint32_t* set_limit; 17363 { 17364 v8::Locker locker(CcTest::isolate()); 17365 set_limit = ComputeStackLimit(stack_breathing_room); 17366 17367 // Set stack limit. 17368 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17369 17370 // Execute a script. 17371 v8::HandleScope scope(CcTest::isolate()); 17372 LocalContext env; 17373 Local<v8::FunctionTemplate> fun_templ = 17374 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback); 17375 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 17376 CHECK(env->Global() 17377 ->Set(env.local(), v8_str("get_stack_limit"), fun) 17378 .FromJust()); 17379 CompileRun("get_stack_limit();"); 17380 17381 CHECK(stack_limit == set_limit); 17382 } 17383 { 17384 v8::Locker locker(CcTest::isolate()); 17385 CHECK(stack_limit == set_limit); 17386 } 17387 } 17388 17389 17390 THREADED_TEST(GetHeapStatistics) { 17391 LocalContext c1; 17392 v8::HandleScope scope(c1->GetIsolate()); 17393 v8::HeapStatistics heap_statistics; 17394 CHECK_EQ(0u, heap_statistics.total_heap_size()); 17395 CHECK_EQ(0u, heap_statistics.used_heap_size()); 17396 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 17397 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 17398 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 17399 } 17400 17401 17402 class VisitorImpl : public v8::ExternalResourceVisitor { 17403 public: 17404 explicit VisitorImpl(TestResource** resource) { 17405 for (int i = 0; i < 4; i++) { 17406 resource_[i] = resource[i]; 17407 found_resource_[i] = false; 17408 } 17409 } 17410 virtual ~VisitorImpl() {} 17411 virtual void VisitExternalString(v8::Local<v8::String> string) { 17412 if (!string->IsExternal()) { 17413 CHECK(string->IsExternalOneByte()); 17414 return; 17415 } 17416 v8::String::ExternalStringResource* resource = 17417 string->GetExternalStringResource(); 17418 CHECK(resource); 17419 for (int i = 0; i < 4; i++) { 17420 if (resource_[i] == resource) { 17421 CHECK(!found_resource_[i]); 17422 found_resource_[i] = true; 17423 } 17424 } 17425 } 17426 void CheckVisitedResources() { 17427 for (int i = 0; i < 4; i++) { 17428 CHECK(found_resource_[i]); 17429 } 17430 } 17431 17432 private: 17433 v8::String::ExternalStringResource* resource_[4]; 17434 bool found_resource_[4]; 17435 }; 17436 17437 17438 TEST(ExternalizeOldSpaceTwoByteCons) { 17439 v8::Isolate* isolate = CcTest::isolate(); 17440 LocalContext env; 17441 v8::HandleScope scope(isolate); 17442 v8::Local<v8::String> cons = 17443 CompileRun("'Romeo Montague ' + 'Juliet Capulet'") 17444 ->ToString(env.local()) 17445 .ToLocalChecked(); 17446 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 17447 CcTest::heap()->CollectAllAvailableGarbage(); 17448 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); 17449 17450 TestResource* resource = new TestResource( 17451 AsciiToTwoByteString("Romeo Montague Juliet Capulet")); 17452 cons->MakeExternal(resource); 17453 17454 CHECK(cons->IsExternal()); 17455 CHECK_EQ(resource, cons->GetExternalStringResource()); 17456 String::Encoding encoding; 17457 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 17458 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 17459 } 17460 17461 17462 TEST(ExternalizeOldSpaceOneByteCons) { 17463 v8::Isolate* isolate = CcTest::isolate(); 17464 LocalContext env; 17465 v8::HandleScope scope(isolate); 17466 v8::Local<v8::String> cons = 17467 CompileRun("'Romeo Montague ' + 'Juliet Capulet'") 17468 ->ToString(env.local()) 17469 .ToLocalChecked(); 17470 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 17471 CcTest::heap()->CollectAllAvailableGarbage(); 17472 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); 17473 17474 TestOneByteResource* resource = 17475 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet")); 17476 cons->MakeExternal(resource); 17477 17478 CHECK(cons->IsExternalOneByte()); 17479 CHECK_EQ(resource, cons->GetExternalOneByteStringResource()); 17480 String::Encoding encoding; 17481 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 17482 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 17483 } 17484 17485 17486 TEST(VisitExternalStrings) { 17487 v8::Isolate* isolate = CcTest::isolate(); 17488 LocalContext env; 17489 v8::HandleScope scope(isolate); 17490 const char* string = "Some string"; 17491 uint16_t* two_byte_string = AsciiToTwoByteString(string); 17492 TestResource* resource[4]; 17493 resource[0] = new TestResource(two_byte_string); 17494 v8::Local<v8::String> string0 = 17495 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0]) 17496 .ToLocalChecked(); 17497 resource[1] = new TestResource(two_byte_string, NULL, false); 17498 v8::Local<v8::String> string1 = 17499 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1]) 17500 .ToLocalChecked(); 17501 17502 // Externalized symbol. 17503 resource[2] = new TestResource(two_byte_string, NULL, false); 17504 v8::Local<v8::String> string2 = 17505 v8::String::NewFromUtf8(env->GetIsolate(), string, 17506 v8::NewStringType::kInternalized) 17507 .ToLocalChecked(); 17508 CHECK(string2->MakeExternal(resource[2])); 17509 17510 // Symbolized External. 17511 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 17512 v8::Local<v8::String> string3 = 17513 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3]) 17514 .ToLocalChecked(); 17515 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. 17516 // Turn into a symbol. 17517 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 17518 CHECK(!CcTest::i_isolate()->factory()->InternalizeString( 17519 string3_i).is_null()); 17520 CHECK(string3_i->IsInternalizedString()); 17521 17522 // We need to add usages for string* to avoid warnings in GCC 4.7 17523 CHECK(string0->IsExternal()); 17524 CHECK(string1->IsExternal()); 17525 CHECK(string2->IsExternal()); 17526 CHECK(string3->IsExternal()); 17527 17528 VisitorImpl visitor(resource); 17529 isolate->VisitExternalResources(&visitor); 17530 visitor.CheckVisitedResources(); 17531 } 17532 17533 17534 TEST(ExternalStringCollectedAtTearDown) { 17535 int destroyed = 0; 17536 v8::Isolate::CreateParams create_params; 17537 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 17538 v8::Isolate* isolate = v8::Isolate::New(create_params); 17539 { v8::Isolate::Scope isolate_scope(isolate); 17540 v8::HandleScope handle_scope(isolate); 17541 const char* s = "One string to test them all, one string to find them."; 17542 TestOneByteResource* inscription = 17543 new TestOneByteResource(i::StrDup(s), &destroyed); 17544 v8::Local<v8::String> ring = 17545 v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked(); 17546 // Ring is still alive. Orcs are roaming freely across our lands. 17547 CHECK_EQ(0, destroyed); 17548 USE(ring); 17549 } 17550 17551 isolate->Dispose(); 17552 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 17553 CHECK_EQ(1, destroyed); 17554 } 17555 17556 17557 TEST(ExternalInternalizedStringCollectedAtTearDown) { 17558 int destroyed = 0; 17559 v8::Isolate::CreateParams create_params; 17560 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 17561 v8::Isolate* isolate = v8::Isolate::New(create_params); 17562 { v8::Isolate::Scope isolate_scope(isolate); 17563 LocalContext env(isolate); 17564 v8::HandleScope handle_scope(isolate); 17565 CompileRun("var ring = 'One string to test them all';"); 17566 const char* s = "One string to test them all"; 17567 TestOneByteResource* inscription = 17568 new TestOneByteResource(i::StrDup(s), &destroyed); 17569 v8::Local<v8::String> ring = 17570 CompileRun("ring")->ToString(env.local()).ToLocalChecked(); 17571 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 17572 ring->MakeExternal(inscription); 17573 // Ring is still alive. Orcs are roaming freely across our lands. 17574 CHECK_EQ(0, destroyed); 17575 USE(ring); 17576 } 17577 17578 isolate->Dispose(); 17579 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 17580 CHECK_EQ(1, destroyed); 17581 } 17582 17583 17584 TEST(ExternalInternalizedStringCollectedAtGC) { 17585 int destroyed = 0; 17586 { LocalContext env; 17587 v8::HandleScope handle_scope(env->GetIsolate()); 17588 CompileRun("var ring = 'One string to test them all';"); 17589 const char* s = "One string to test them all"; 17590 TestOneByteResource* inscription = 17591 new TestOneByteResource(i::StrDup(s), &destroyed); 17592 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>(); 17593 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 17594 ring->MakeExternal(inscription); 17595 // Ring is still alive. Orcs are roaming freely across our lands. 17596 CHECK_EQ(0, destroyed); 17597 USE(ring); 17598 } 17599 17600 // Garbage collector deals swift blows to evil. 17601 CcTest::i_isolate()->compilation_cache()->Clear(); 17602 CcTest::heap()->CollectAllAvailableGarbage(); 17603 17604 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 17605 CHECK_EQ(1, destroyed); 17606 } 17607 17608 17609 static double DoubleFromBits(uint64_t value) { 17610 double target; 17611 i::MemCopy(&target, &value, sizeof(target)); 17612 return target; 17613 } 17614 17615 17616 static uint64_t DoubleToBits(double value) { 17617 uint64_t target; 17618 i::MemCopy(&target, &value, sizeof(target)); 17619 return target; 17620 } 17621 17622 17623 static double DoubleToDateTime(double input) { 17624 double date_limit = 864e13; 17625 if (std::isnan(input) || input < -date_limit || input > date_limit) { 17626 return std::numeric_limits<double>::quiet_NaN(); 17627 } 17628 return (input < 0) ? -(std::floor(-input)) : std::floor(input); 17629 } 17630 17631 17632 // We don't have a consistent way to write 64-bit constants syntactically, so we 17633 // split them into two 32-bit constants and combine them programmatically. 17634 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 17635 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 17636 } 17637 17638 17639 THREADED_TEST(QuietSignalingNaNs) { 17640 LocalContext context; 17641 v8::Isolate* isolate = context->GetIsolate(); 17642 v8::HandleScope scope(isolate); 17643 v8::TryCatch try_catch(isolate); 17644 17645 // Special double values. 17646 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 17647 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 17648 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 17649 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 17650 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 17651 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 17652 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 17653 17654 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 17655 // on either side of the epoch. 17656 double date_limit = 864e13; 17657 17658 double test_values[] = { 17659 snan, 17660 qnan, 17661 infinity, 17662 max_normal, 17663 date_limit + 1, 17664 date_limit, 17665 min_normal, 17666 max_denormal, 17667 min_denormal, 17668 0, 17669 -0, 17670 -min_denormal, 17671 -max_denormal, 17672 -min_normal, 17673 -date_limit, 17674 -date_limit - 1, 17675 -max_normal, 17676 -infinity, 17677 -qnan, 17678 -snan 17679 }; 17680 int num_test_values = 20; 17681 17682 for (int i = 0; i < num_test_values; i++) { 17683 double test_value = test_values[i]; 17684 17685 // Check that Number::New preserves non-NaNs and quiets SNaNs. 17686 v8::Local<v8::Value> number = v8::Number::New(isolate, test_value); 17687 double stored_number = number->NumberValue(context.local()).FromJust(); 17688 if (!std::isnan(test_value)) { 17689 CHECK_EQ(test_value, stored_number); 17690 } else { 17691 uint64_t stored_bits = DoubleToBits(stored_number); 17692 // Check if quiet nan (bits 51..62 all set). 17693 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 17694 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \ 17695 !defined(USE_SIMULATOR) 17696 // Most significant fraction bit for quiet nan is set to 0 17697 // on MIPS architecture. Allowed by IEEE-754. 17698 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17699 #else 17700 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17701 #endif 17702 } 17703 17704 // Check that Date::New preserves non-NaNs in the date range and 17705 // quiets SNaNs. 17706 v8::Local<v8::Value> date = 17707 v8::Date::New(context.local(), test_value).ToLocalChecked(); 17708 double expected_stored_date = DoubleToDateTime(test_value); 17709 double stored_date = date->NumberValue(context.local()).FromJust(); 17710 if (!std::isnan(expected_stored_date)) { 17711 CHECK_EQ(expected_stored_date, stored_date); 17712 } else { 17713 uint64_t stored_bits = DoubleToBits(stored_date); 17714 // Check if quiet nan (bits 51..62 all set). 17715 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 17716 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \ 17717 !defined(USE_SIMULATOR) 17718 // Most significant fraction bit for quiet nan is set to 0 17719 // on MIPS architecture. Allowed by IEEE-754. 17720 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17721 #else 17722 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17723 #endif 17724 } 17725 } 17726 } 17727 17728 17729 static void SpaghettiIncident( 17730 const v8::FunctionCallbackInfo<v8::Value>& args) { 17731 v8::HandleScope scope(args.GetIsolate()); 17732 v8::TryCatch tc(args.GetIsolate()); 17733 v8::MaybeLocal<v8::String> str( 17734 args[0]->ToString(args.GetIsolate()->GetCurrentContext())); 17735 USE(str); 17736 if (tc.HasCaught()) 17737 tc.ReThrow(); 17738 } 17739 17740 17741 // Test that an exception can be propagated down through a spaghetti 17742 // stack using ReThrow. 17743 THREADED_TEST(SpaghettiStackReThrow) { 17744 v8::Isolate* isolate = CcTest::isolate(); 17745 v8::HandleScope scope(isolate); 17746 LocalContext context; 17747 context->Global() 17748 ->Set(context.local(), v8_str("s"), 17749 v8::FunctionTemplate::New(isolate, SpaghettiIncident) 17750 ->GetFunction(context.local()) 17751 .ToLocalChecked()) 17752 .FromJust(); 17753 v8::TryCatch try_catch(isolate); 17754 CompileRun( 17755 "var i = 0;" 17756 "var o = {" 17757 " toString: function () {" 17758 " if (i == 10) {" 17759 " throw 'Hey!';" 17760 " } else {" 17761 " i++;" 17762 " return s(o);" 17763 " }" 17764 " }" 17765 "};" 17766 "s(o);"); 17767 CHECK(try_catch.HasCaught()); 17768 v8::String::Utf8Value value(try_catch.Exception()); 17769 CHECK_EQ(0, strcmp(*value, "Hey!")); 17770 } 17771 17772 17773 TEST(Regress528) { 17774 v8::V8::Initialize(); 17775 v8::Isolate* isolate = CcTest::isolate(); 17776 i::FLAG_retain_maps_for_n_gc = 0; 17777 v8::HandleScope scope(isolate); 17778 v8::Local<Context> other_context; 17779 int gc_count; 17780 17781 // Create a context used to keep the code from aging in the compilation 17782 // cache. 17783 other_context = Context::New(isolate); 17784 17785 // Context-dependent context data creates reference from the compilation 17786 // cache to the global object. 17787 const char* source_simple = "1"; 17788 { 17789 v8::HandleScope scope(isolate); 17790 v8::Local<Context> context = Context::New(isolate); 17791 17792 context->Enter(); 17793 Local<v8::String> obj = v8_str(""); 17794 context->SetEmbedderData(0, obj); 17795 CompileRun(source_simple); 17796 context->Exit(); 17797 } 17798 isolate->ContextDisposedNotification(); 17799 for (gc_count = 1; gc_count < 10; gc_count++) { 17800 other_context->Enter(); 17801 CompileRun(source_simple); 17802 other_context->Exit(); 17803 CcTest::heap()->CollectAllGarbage(); 17804 if (GetGlobalObjectsCount() == 1) break; 17805 } 17806 CHECK_GE(2, gc_count); 17807 CHECK_EQ(1, GetGlobalObjectsCount()); 17808 17809 // Eval in a function creates reference from the compilation cache to the 17810 // global object. 17811 const char* source_eval = "function f(){eval('1')}; f()"; 17812 { 17813 v8::HandleScope scope(isolate); 17814 v8::Local<Context> context = Context::New(isolate); 17815 17816 context->Enter(); 17817 CompileRun(source_eval); 17818 context->Exit(); 17819 } 17820 isolate->ContextDisposedNotification(); 17821 for (gc_count = 1; gc_count < 10; gc_count++) { 17822 other_context->Enter(); 17823 CompileRun(source_eval); 17824 other_context->Exit(); 17825 CcTest::heap()->CollectAllGarbage(); 17826 if (GetGlobalObjectsCount() == 1) break; 17827 } 17828 CHECK_GE(2, gc_count); 17829 CHECK_EQ(1, GetGlobalObjectsCount()); 17830 17831 // Looking up the line number for an exception creates reference from the 17832 // compilation cache to the global object. 17833 const char* source_exception = "function f(){throw 1;} f()"; 17834 { 17835 v8::HandleScope scope(isolate); 17836 v8::Local<Context> context = Context::New(isolate); 17837 17838 context->Enter(); 17839 v8::TryCatch try_catch(isolate); 17840 CompileRun(source_exception); 17841 CHECK(try_catch.HasCaught()); 17842 v8::Local<v8::Message> message = try_catch.Message(); 17843 CHECK(!message.IsEmpty()); 17844 CHECK_EQ(1, message->GetLineNumber(context).FromJust()); 17845 context->Exit(); 17846 } 17847 isolate->ContextDisposedNotification(); 17848 for (gc_count = 1; gc_count < 10; gc_count++) { 17849 other_context->Enter(); 17850 CompileRun(source_exception); 17851 other_context->Exit(); 17852 CcTest::heap()->CollectAllGarbage(); 17853 if (GetGlobalObjectsCount() == 1) break; 17854 } 17855 CHECK_GE(2, gc_count); 17856 CHECK_EQ(1, GetGlobalObjectsCount()); 17857 17858 isolate->ContextDisposedNotification(); 17859 } 17860 17861 17862 THREADED_TEST(ScriptOrigin) { 17863 LocalContext env; 17864 v8::HandleScope scope(env->GetIsolate()); 17865 v8::ScriptOrigin origin = v8::ScriptOrigin( 17866 v8_str("test"), v8::Integer::New(env->GetIsolate(), 1), 17867 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()), 17868 v8::Local<v8::Integer>(), v8::True(env->GetIsolate()), 17869 v8_str("http://sourceMapUrl"), v8::True(env->GetIsolate())); 17870 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}"); 17871 v8::Script::Compile(env.local(), script, &origin) 17872 .ToLocalChecked() 17873 ->Run(env.local()) 17874 .ToLocalChecked(); 17875 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17876 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 17877 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17878 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 17879 17880 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 17881 CHECK_EQ(0, strcmp("test", 17882 *v8::String::Utf8Value(script_origin_f.ResourceName()))); 17883 CHECK_EQ( 17884 1, 17885 script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust()); 17886 CHECK(script_origin_f.Options().IsSharedCrossOrigin()); 17887 CHECK(script_origin_f.Options().IsEmbedderDebugScript()); 17888 CHECK(script_origin_f.Options().IsOpaque()); 17889 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined()); 17890 17891 CHECK_EQ(0, strcmp("http://sourceMapUrl", 17892 *v8::String::Utf8Value(script_origin_f.SourceMapUrl()))); 17893 17894 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 17895 CHECK_EQ(0, strcmp("test", 17896 *v8::String::Utf8Value(script_origin_g.ResourceName()))); 17897 CHECK_EQ( 17898 1, 17899 script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust()); 17900 CHECK(script_origin_g.Options().IsSharedCrossOrigin()); 17901 CHECK(script_origin_g.Options().IsEmbedderDebugScript()); 17902 CHECK(script_origin_g.Options().IsOpaque()); 17903 CHECK_EQ(0, strcmp("http://sourceMapUrl", 17904 *v8::String::Utf8Value(script_origin_g.SourceMapUrl()))); 17905 } 17906 17907 17908 THREADED_TEST(FunctionGetInferredName) { 17909 LocalContext env; 17910 v8::HandleScope scope(env->GetIsolate()); 17911 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 17912 v8::Local<v8::String> script = 17913 v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 17914 v8::Script::Compile(env.local(), script, &origin) 17915 .ToLocalChecked() 17916 ->Run(env.local()) 17917 .ToLocalChecked(); 17918 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17919 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 17920 CHECK_EQ(0, 17921 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()))); 17922 } 17923 17924 17925 THREADED_TEST(FunctionGetDebugName) { 17926 LocalContext env; 17927 v8::HandleScope scope(env->GetIsolate()); 17928 const char* code = 17929 "var error = false;" 17930 "function a() { this.x = 1; };" 17931 "a.displayName = 'display_a';" 17932 "var b = (function() {" 17933 " var f = function() { this.x = 2; };" 17934 " f.displayName = 'display_b';" 17935 " return f;" 17936 "})();" 17937 "var c = function() {};" 17938 "c.__defineGetter__('displayName', function() {" 17939 " error = true;" 17940 " throw new Error();" 17941 "});" 17942 "function d() {};" 17943 "d.__defineGetter__('displayName', function() {" 17944 " error = true;" 17945 " return 'wrong_display_name';" 17946 "});" 17947 "function e() {};" 17948 "e.displayName = 'wrong_display_name';" 17949 "e.__defineSetter__('displayName', function() {" 17950 " error = true;" 17951 " throw new Error();" 17952 "});" 17953 "function f() {};" 17954 "f.displayName = { 'foo': 6, toString: function() {" 17955 " error = true;" 17956 " return 'wrong_display_name';" 17957 "}};" 17958 "var g = function() {" 17959 " arguments.callee.displayName = 'set_in_runtime';" 17960 "}; g();" 17961 "var h = function() {};" 17962 "h.displayName = 'displayName';" 17963 "Object.defineProperty(h, 'name', { value: 'function.name' });" 17964 "var i = function() {};" 17965 "i.displayName = 239;" 17966 "Object.defineProperty(i, 'name', { value: 'function.name' });" 17967 "var j = function() {};" 17968 "Object.defineProperty(j, 'name', { value: 'function.name' });" 17969 "var foo = { bar : { baz : function() {}}}; var k = foo.bar.baz;"; 17970 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 17971 v8::Script::Compile(env.local(), v8_str(code), &origin) 17972 .ToLocalChecked() 17973 ->Run(env.local()) 17974 .ToLocalChecked(); 17975 v8::Local<v8::Value> error = 17976 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked(); 17977 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust()); 17978 const char* functions[] = {"a", "display_a", 17979 "b", "display_b", 17980 "c", "c", 17981 "d", "d", 17982 "e", "e", 17983 "f", "f", 17984 "g", "set_in_runtime", 17985 "h", "displayName", 17986 "i", "function.name", 17987 "j", "function.name", 17988 "k", "foo.bar.baz"}; 17989 for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) { 17990 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17991 env->Global() 17992 ->Get(env.local(), 17993 v8::String::NewFromUtf8(env->GetIsolate(), functions[i * 2], 17994 v8::NewStringType::kNormal) 17995 .ToLocalChecked()) 17996 .ToLocalChecked()); 17997 CHECK_EQ(0, strcmp(functions[i * 2 + 1], 17998 *v8::String::Utf8Value(f->GetDebugName()))); 17999 } 18000 } 18001 18002 18003 THREADED_TEST(FunctionGetDisplayName) { 18004 LocalContext env; 18005 v8::HandleScope scope(env->GetIsolate()); 18006 const char* code = "var error = false;" 18007 "function a() { this.x = 1; };" 18008 "a.displayName = 'display_a';" 18009 "var b = (function() {" 18010 " var f = function() { this.x = 2; };" 18011 " f.displayName = 'display_b';" 18012 " return f;" 18013 "})();" 18014 "var c = function() {};" 18015 "c.__defineGetter__('displayName', function() {" 18016 " error = true;" 18017 " throw new Error();" 18018 "});" 18019 "function d() {};" 18020 "d.__defineGetter__('displayName', function() {" 18021 " error = true;" 18022 " return 'wrong_display_name';" 18023 "});" 18024 "function e() {};" 18025 "e.displayName = 'wrong_display_name';" 18026 "e.__defineSetter__('displayName', function() {" 18027 " error = true;" 18028 " throw new Error();" 18029 "});" 18030 "function f() {};" 18031 "f.displayName = { 'foo': 6, toString: function() {" 18032 " error = true;" 18033 " return 'wrong_display_name';" 18034 "}};" 18035 "var g = function() {" 18036 " arguments.callee.displayName = 'set_in_runtime';" 18037 "}; g();"; 18038 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18039 v8::Script::Compile(env.local(), v8_str(code), &origin) 18040 .ToLocalChecked() 18041 ->Run(env.local()) 18042 .ToLocalChecked(); 18043 v8::Local<v8::Value> error = 18044 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked(); 18045 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( 18046 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 18047 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( 18048 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 18049 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( 18050 env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked()); 18051 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( 18052 env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked()); 18053 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( 18054 env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked()); 18055 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18056 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18057 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18058 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18059 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust()); 18060 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName()))); 18061 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName()))); 18062 CHECK(c->GetDisplayName()->IsUndefined()); 18063 CHECK(d->GetDisplayName()->IsUndefined()); 18064 CHECK(e->GetDisplayName()->IsUndefined()); 18065 CHECK(f->GetDisplayName()->IsUndefined()); 18066 CHECK_EQ( 18067 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()))); 18068 } 18069 18070 18071 THREADED_TEST(ScriptLineNumber) { 18072 LocalContext env; 18073 v8::HandleScope scope(env->GetIsolate()); 18074 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18075 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}"); 18076 v8::Script::Compile(env.local(), script, &origin) 18077 .ToLocalChecked() 18078 ->Run(env.local()) 18079 .ToLocalChecked(); 18080 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18081 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18082 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18083 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18084 CHECK_EQ(0, f->GetScriptLineNumber()); 18085 CHECK_EQ(2, g->GetScriptLineNumber()); 18086 } 18087 18088 18089 THREADED_TEST(ScriptColumnNumber) { 18090 LocalContext env; 18091 v8::Isolate* isolate = env->GetIsolate(); 18092 v8::HandleScope scope(isolate); 18093 v8::ScriptOrigin origin = 18094 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3), 18095 v8::Integer::New(isolate, 2)); 18096 v8::Local<v8::String> script = 18097 v8_str("function foo() {}\n\n function bar() {}"); 18098 v8::Script::Compile(env.local(), script, &origin) 18099 .ToLocalChecked() 18100 ->Run(env.local()) 18101 .ToLocalChecked(); 18102 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18103 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked()); 18104 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18105 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked()); 18106 CHECK_EQ(14, foo->GetScriptColumnNumber()); 18107 CHECK_EQ(17, bar->GetScriptColumnNumber()); 18108 } 18109 18110 18111 THREADED_TEST(FunctionIsBuiltin) { 18112 LocalContext env; 18113 v8::Isolate* isolate = env->GetIsolate(); 18114 v8::HandleScope scope(isolate); 18115 v8::Local<v8::Function> f; 18116 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); 18117 CHECK(f->IsBuiltin()); 18118 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); 18119 CHECK(f->IsBuiltin()); 18120 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); 18121 CHECK(f->IsBuiltin()); 18122 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); 18123 CHECK(f->IsBuiltin()); 18124 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); 18125 CHECK(!f->IsBuiltin()); 18126 } 18127 18128 18129 THREADED_TEST(FunctionGetScriptId) { 18130 LocalContext env; 18131 v8::Isolate* isolate = env->GetIsolate(); 18132 v8::HandleScope scope(isolate); 18133 v8::ScriptOrigin origin = 18134 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3), 18135 v8::Integer::New(isolate, 2)); 18136 v8::Local<v8::String> scriptSource = 18137 v8_str("function foo() {}\n\n function bar() {}"); 18138 v8::Local<v8::Script> script( 18139 v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked()); 18140 script->Run(env.local()).ToLocalChecked(); 18141 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18142 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked()); 18143 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18144 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked()); 18145 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId()); 18146 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId()); 18147 } 18148 18149 18150 THREADED_TEST(FunctionGetBoundFunction) { 18151 LocalContext env; 18152 v8::HandleScope scope(env->GetIsolate()); 18153 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18154 v8::Local<v8::String> script = v8_str( 18155 "var a = new Object();\n" 18156 "a.x = 1;\n" 18157 "function f () { return this.x };\n" 18158 "var g = f.bind(a);\n" 18159 "var b = g();"); 18160 v8::Script::Compile(env.local(), script, &origin) 18161 .ToLocalChecked() 18162 ->Run(env.local()) 18163 .ToLocalChecked(); 18164 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18165 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18166 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18167 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18168 CHECK(g->GetBoundFunction()->IsFunction()); 18169 Local<v8::Function> original_function = Local<v8::Function>::Cast( 18170 g->GetBoundFunction()); 18171 CHECK(f->GetName() 18172 ->Equals(env.local(), original_function->GetName()) 18173 .FromJust()); 18174 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber()); 18175 CHECK_EQ(f->GetScriptColumnNumber(), 18176 original_function->GetScriptColumnNumber()); 18177 } 18178 18179 18180 static void GetterWhichReturns42( 18181 Local<String> name, 18182 const v8::PropertyCallbackInfo<v8::Value>& info) { 18183 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18184 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18185 info.GetReturnValue().Set(v8_num(42)); 18186 } 18187 18188 18189 static void SetterWhichSetsYOnThisTo23( 18190 Local<String> name, 18191 Local<Value> value, 18192 const v8::PropertyCallbackInfo<void>& info) { 18193 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18194 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18195 Local<Object>::Cast(info.This()) 18196 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18197 .FromJust(); 18198 } 18199 18200 18201 void FooGetInterceptor(Local<Name> name, 18202 const v8::PropertyCallbackInfo<v8::Value>& info) { 18203 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18204 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18205 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 18206 .FromJust()) { 18207 return; 18208 } 18209 info.GetReturnValue().Set(v8_num(42)); 18210 } 18211 18212 18213 void FooSetInterceptor(Local<Name> name, Local<Value> value, 18214 const v8::PropertyCallbackInfo<v8::Value>& info) { 18215 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18216 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18217 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 18218 .FromJust()) { 18219 return; 18220 } 18221 Local<Object>::Cast(info.This()) 18222 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18223 .FromJust(); 18224 info.GetReturnValue().Set(v8_num(23)); 18225 } 18226 18227 18228 TEST(SetterOnConstructorPrototype) { 18229 v8::Isolate* isolate = CcTest::isolate(); 18230 v8::HandleScope scope(isolate); 18231 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18232 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 18233 SetterWhichSetsYOnThisTo23); 18234 LocalContext context; 18235 CHECK(context->Global() 18236 ->Set(context.local(), v8_str("P"), 18237 templ->NewInstance(context.local()).ToLocalChecked()) 18238 .FromJust()); 18239 CompileRun("function C1() {" 18240 " this.x = 23;" 18241 "};" 18242 "C1.prototype = P;" 18243 "function C2() {" 18244 " this.x = 23" 18245 "};" 18246 "C2.prototype = { };" 18247 "C2.prototype.__proto__ = P;"); 18248 18249 v8::Local<v8::Script> script; 18250 script = v8_compile("new C1();"); 18251 for (int i = 0; i < 10; i++) { 18252 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18253 script->Run(context.local()).ToLocalChecked()); 18254 CHECK_EQ(42, c1->Get(context.local(), v8_str("x")) 18255 .ToLocalChecked() 18256 ->Int32Value(context.local()) 18257 .FromJust()); 18258 CHECK_EQ(23, c1->Get(context.local(), v8_str("y")) 18259 .ToLocalChecked() 18260 ->Int32Value(context.local()) 18261 .FromJust()); 18262 } 18263 18264 script = v8_compile("new C2();"); 18265 for (int i = 0; i < 10; i++) { 18266 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast( 18267 script->Run(context.local()).ToLocalChecked()); 18268 CHECK_EQ(42, c2->Get(context.local(), v8_str("x")) 18269 .ToLocalChecked() 18270 ->Int32Value(context.local()) 18271 .FromJust()); 18272 CHECK_EQ(23, c2->Get(context.local(), v8_str("y")) 18273 .ToLocalChecked() 18274 ->Int32Value(context.local()) 18275 .FromJust()); 18276 } 18277 } 18278 18279 18280 static void NamedPropertyGetterWhichReturns42( 18281 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 18282 info.GetReturnValue().Set(v8_num(42)); 18283 } 18284 18285 18286 static void NamedPropertySetterWhichSetsYOnThisTo23( 18287 Local<Name> name, Local<Value> value, 18288 const v8::PropertyCallbackInfo<v8::Value>& info) { 18289 if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x")) 18290 .FromJust()) { 18291 Local<Object>::Cast(info.This()) 18292 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18293 .FromJust(); 18294 } 18295 } 18296 18297 18298 THREADED_TEST(InterceptorOnConstructorPrototype) { 18299 v8::Isolate* isolate = CcTest::isolate(); 18300 v8::HandleScope scope(isolate); 18301 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18302 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 18303 NamedPropertyGetterWhichReturns42, 18304 NamedPropertySetterWhichSetsYOnThisTo23)); 18305 LocalContext context; 18306 CHECK(context->Global() 18307 ->Set(context.local(), v8_str("P"), 18308 templ->NewInstance(context.local()).ToLocalChecked()) 18309 .FromJust()); 18310 CompileRun("function C1() {" 18311 " this.x = 23;" 18312 "};" 18313 "C1.prototype = P;" 18314 "function C2() {" 18315 " this.x = 23" 18316 "};" 18317 "C2.prototype = { };" 18318 "C2.prototype.__proto__ = P;"); 18319 18320 v8::Local<v8::Script> script; 18321 script = v8_compile("new C1();"); 18322 for (int i = 0; i < 10; i++) { 18323 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18324 script->Run(context.local()).ToLocalChecked()); 18325 CHECK_EQ(23, c1->Get(context.local(), v8_str("x")) 18326 .ToLocalChecked() 18327 ->Int32Value(context.local()) 18328 .FromJust()); 18329 CHECK_EQ(42, c1->Get(context.local(), v8_str("y")) 18330 .ToLocalChecked() 18331 ->Int32Value(context.local()) 18332 .FromJust()); 18333 } 18334 18335 script = v8_compile("new C2();"); 18336 for (int i = 0; i < 10; i++) { 18337 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast( 18338 script->Run(context.local()).ToLocalChecked()); 18339 CHECK_EQ(23, c2->Get(context.local(), v8_str("x")) 18340 .ToLocalChecked() 18341 ->Int32Value(context.local()) 18342 .FromJust()); 18343 CHECK_EQ(42, c2->Get(context.local(), v8_str("y")) 18344 .ToLocalChecked() 18345 ->Int32Value(context.local()) 18346 .FromJust()); 18347 } 18348 } 18349 18350 18351 TEST(Regress618) { 18352 const char* source = "function C1() {" 18353 " this.x = 23;" 18354 "};" 18355 "C1.prototype = P;"; 18356 18357 LocalContext context; 18358 v8::Isolate* isolate = context->GetIsolate(); 18359 v8::HandleScope scope(isolate); 18360 v8::Local<v8::Script> script; 18361 18362 // Use a simple object as prototype. 18363 v8::Local<v8::Object> prototype = v8::Object::New(isolate); 18364 prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust(); 18365 CHECK(context->Global() 18366 ->Set(context.local(), v8_str("P"), prototype) 18367 .FromJust()); 18368 18369 // This compile will add the code to the compilation cache. 18370 CompileRun(source); 18371 18372 script = v8_compile("new C1();"); 18373 // Allow enough iterations for the inobject slack tracking logic 18374 // to finalize instance size and install the fast construct stub. 18375 for (int i = 0; i < 256; i++) { 18376 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18377 script->Run(context.local()).ToLocalChecked()); 18378 CHECK_EQ(23, c1->Get(context.local(), v8_str("x")) 18379 .ToLocalChecked() 18380 ->Int32Value(context.local()) 18381 .FromJust()); 18382 CHECK_EQ(42, c1->Get(context.local(), v8_str("y")) 18383 .ToLocalChecked() 18384 ->Int32Value(context.local()) 18385 .FromJust()); 18386 } 18387 18388 // Use an API object with accessors as prototype. 18389 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18390 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 18391 SetterWhichSetsYOnThisTo23); 18392 CHECK(context->Global() 18393 ->Set(context.local(), v8_str("P"), 18394 templ->NewInstance(context.local()).ToLocalChecked()) 18395 .FromJust()); 18396 18397 // This compile will get the code from the compilation cache. 18398 CompileRun(source); 18399 18400 script = v8_compile("new C1();"); 18401 for (int i = 0; i < 10; i++) { 18402 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18403 script->Run(context.local()).ToLocalChecked()); 18404 CHECK_EQ(42, c1->Get(context.local(), v8_str("x")) 18405 .ToLocalChecked() 18406 ->Int32Value(context.local()) 18407 .FromJust()); 18408 CHECK_EQ(23, c1->Get(context.local(), v8_str("y")) 18409 .ToLocalChecked() 18410 ->Int32Value(context.local()) 18411 .FromJust()); 18412 } 18413 } 18414 18415 v8::Isolate* gc_callbacks_isolate = NULL; 18416 int prologue_call_count = 0; 18417 int epilogue_call_count = 0; 18418 int prologue_call_count_second = 0; 18419 int epilogue_call_count_second = 0; 18420 int prologue_call_count_alloc = 0; 18421 int epilogue_call_count_alloc = 0; 18422 18423 void PrologueCallback(v8::Isolate* isolate, 18424 v8::GCType, 18425 v8::GCCallbackFlags flags) { 18426 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18427 CHECK_EQ(gc_callbacks_isolate, isolate); 18428 ++prologue_call_count; 18429 } 18430 18431 void EpilogueCallback(v8::Isolate* isolate, 18432 v8::GCType, 18433 v8::GCCallbackFlags flags) { 18434 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18435 CHECK_EQ(gc_callbacks_isolate, isolate); 18436 ++epilogue_call_count; 18437 } 18438 18439 18440 void PrologueCallbackSecond(v8::Isolate* isolate, 18441 v8::GCType, 18442 v8::GCCallbackFlags flags) { 18443 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18444 CHECK_EQ(gc_callbacks_isolate, isolate); 18445 ++prologue_call_count_second; 18446 } 18447 18448 18449 void EpilogueCallbackSecond(v8::Isolate* isolate, 18450 v8::GCType, 18451 v8::GCCallbackFlags flags) { 18452 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18453 CHECK_EQ(gc_callbacks_isolate, isolate); 18454 ++epilogue_call_count_second; 18455 } 18456 18457 18458 void PrologueCallbackAlloc(v8::Isolate* isolate, 18459 v8::GCType, 18460 v8::GCCallbackFlags flags) { 18461 v8::HandleScope scope(isolate); 18462 18463 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18464 CHECK_EQ(gc_callbacks_isolate, isolate); 18465 ++prologue_call_count_alloc; 18466 18467 // Simulate full heap to see if we will reenter this callback 18468 SimulateFullSpace(CcTest::heap()->new_space()); 18469 18470 Local<Object> obj = Object::New(isolate); 18471 CHECK(!obj.IsEmpty()); 18472 18473 CcTest::heap()->CollectAllGarbage( 18474 i::Heap::kAbortIncrementalMarkingMask); 18475 } 18476 18477 18478 void EpilogueCallbackAlloc(v8::Isolate* isolate, 18479 v8::GCType, 18480 v8::GCCallbackFlags flags) { 18481 v8::HandleScope scope(isolate); 18482 18483 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18484 CHECK_EQ(gc_callbacks_isolate, isolate); 18485 ++epilogue_call_count_alloc; 18486 18487 // Simulate full heap to see if we will reenter this callback 18488 SimulateFullSpace(CcTest::heap()->new_space()); 18489 18490 Local<Object> obj = Object::New(isolate); 18491 CHECK(!obj.IsEmpty()); 18492 18493 CcTest::heap()->CollectAllGarbage( 18494 i::Heap::kAbortIncrementalMarkingMask); 18495 } 18496 18497 18498 TEST(GCCallbacksOld) { 18499 LocalContext context; 18500 18501 gc_callbacks_isolate = context->GetIsolate(); 18502 18503 context->GetIsolate()->AddGCPrologueCallback(PrologueCallback); 18504 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback); 18505 CHECK_EQ(0, prologue_call_count); 18506 CHECK_EQ(0, epilogue_call_count); 18507 CcTest::heap()->CollectAllGarbage(); 18508 CHECK_EQ(1, prologue_call_count); 18509 CHECK_EQ(1, epilogue_call_count); 18510 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond); 18511 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond); 18512 CcTest::heap()->CollectAllGarbage(); 18513 CHECK_EQ(2, prologue_call_count); 18514 CHECK_EQ(2, epilogue_call_count); 18515 CHECK_EQ(1, prologue_call_count_second); 18516 CHECK_EQ(1, epilogue_call_count_second); 18517 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback); 18518 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback); 18519 CcTest::heap()->CollectAllGarbage(); 18520 CHECK_EQ(2, prologue_call_count); 18521 CHECK_EQ(2, epilogue_call_count); 18522 CHECK_EQ(2, prologue_call_count_second); 18523 CHECK_EQ(2, epilogue_call_count_second); 18524 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond); 18525 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18526 CcTest::heap()->CollectAllGarbage(); 18527 CHECK_EQ(2, prologue_call_count); 18528 CHECK_EQ(2, epilogue_call_count); 18529 CHECK_EQ(2, prologue_call_count_second); 18530 CHECK_EQ(2, epilogue_call_count_second); 18531 } 18532 18533 18534 TEST(GCCallbacks) { 18535 LocalContext context; 18536 v8::Isolate* isolate = context->GetIsolate(); 18537 gc_callbacks_isolate = isolate; 18538 isolate->AddGCPrologueCallback(PrologueCallback); 18539 isolate->AddGCEpilogueCallback(EpilogueCallback); 18540 CHECK_EQ(0, prologue_call_count); 18541 CHECK_EQ(0, epilogue_call_count); 18542 CcTest::heap()->CollectAllGarbage(); 18543 CHECK_EQ(1, prologue_call_count); 18544 CHECK_EQ(1, epilogue_call_count); 18545 isolate->AddGCPrologueCallback(PrologueCallbackSecond); 18546 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); 18547 CcTest::heap()->CollectAllGarbage(); 18548 CHECK_EQ(2, prologue_call_count); 18549 CHECK_EQ(2, epilogue_call_count); 18550 CHECK_EQ(1, prologue_call_count_second); 18551 CHECK_EQ(1, epilogue_call_count_second); 18552 isolate->RemoveGCPrologueCallback(PrologueCallback); 18553 isolate->RemoveGCEpilogueCallback(EpilogueCallback); 18554 CcTest::heap()->CollectAllGarbage(); 18555 CHECK_EQ(2, prologue_call_count); 18556 CHECK_EQ(2, epilogue_call_count); 18557 CHECK_EQ(2, prologue_call_count_second); 18558 CHECK_EQ(2, epilogue_call_count_second); 18559 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); 18560 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18561 CcTest::heap()->CollectAllGarbage(); 18562 CHECK_EQ(2, prologue_call_count); 18563 CHECK_EQ(2, epilogue_call_count); 18564 CHECK_EQ(2, prologue_call_count_second); 18565 CHECK_EQ(2, epilogue_call_count_second); 18566 18567 CHECK_EQ(0, prologue_call_count_alloc); 18568 CHECK_EQ(0, epilogue_call_count_alloc); 18569 isolate->AddGCPrologueCallback(PrologueCallbackAlloc); 18570 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc); 18571 CcTest::heap()->CollectAllGarbage( 18572 i::Heap::kAbortIncrementalMarkingMask); 18573 CHECK_EQ(1, prologue_call_count_alloc); 18574 CHECK_EQ(1, epilogue_call_count_alloc); 18575 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc); 18576 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc); 18577 } 18578 18579 18580 THREADED_TEST(TwoByteStringInOneByteCons) { 18581 // See Chromium issue 47824. 18582 LocalContext context; 18583 v8::HandleScope scope(context->GetIsolate()); 18584 18585 const char* init_code = 18586 "var str1 = 'abelspendabel';" 18587 "var str2 = str1 + str1 + str1;" 18588 "str2;"; 18589 Local<Value> result = CompileRun(init_code); 18590 18591 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 18592 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 18593 18594 CHECK(result->IsString()); 18595 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 18596 int length = string->length(); 18597 CHECK(string->IsOneByteRepresentation()); 18598 18599 i::Handle<i::String> flat_string = i::String::Flatten(string); 18600 18601 CHECK(string->IsOneByteRepresentation()); 18602 CHECK(flat_string->IsOneByteRepresentation()); 18603 18604 // Create external resource. 18605 uint16_t* uc16_buffer = new uint16_t[length + 1]; 18606 18607 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 18608 uc16_buffer[length] = 0; 18609 18610 TestResource resource(uc16_buffer); 18611 18612 flat_string->MakeExternal(&resource); 18613 18614 CHECK(flat_string->IsTwoByteRepresentation()); 18615 18616 // If the cons string has been short-circuited, skip the following checks. 18617 if (!string.is_identical_to(flat_string)) { 18618 // At this point, we should have a Cons string which is flat and one-byte, 18619 // with a first half that is a two-byte string (although it only contains 18620 // one-byte characters). This is a valid sequence of steps, and it can 18621 // happen in real pages. 18622 CHECK(string->IsOneByteRepresentation()); 18623 i::ConsString* cons = i::ConsString::cast(*string); 18624 CHECK_EQ(0, cons->second()->length()); 18625 CHECK(cons->first()->IsTwoByteRepresentation()); 18626 } 18627 18628 // Check that some string operations work. 18629 18630 // Atom RegExp. 18631 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 18632 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); 18633 18634 // Nonatom RegExp. 18635 reresult = CompileRun("str2.match(/abe./g).length;"); 18636 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); 18637 18638 reresult = CompileRun("str2.search(/bel/g);"); 18639 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); 18640 18641 reresult = CompileRun("str2.search(/be./g);"); 18642 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); 18643 18644 ExpectTrue("/bel/g.test(str2);"); 18645 18646 ExpectTrue("/be./g.test(str2);"); 18647 18648 reresult = CompileRun("/bel/g.exec(str2);"); 18649 CHECK(!reresult->IsNull()); 18650 18651 reresult = CompileRun("/be./g.exec(str2);"); 18652 CHECK(!reresult->IsNull()); 18653 18654 ExpectString("str2.substring(2, 10);", "elspenda"); 18655 18656 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 18657 18658 ExpectString("str2.charAt(2);", "e"); 18659 18660 ExpectObject("str2.indexOf('els');", indexof); 18661 18662 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 18663 18664 reresult = CompileRun("str2.charCodeAt(2);"); 18665 CHECK_EQ(static_cast<int32_t>('e'), 18666 reresult->Int32Value(context.local()).FromJust()); 18667 } 18668 18669 18670 TEST(ContainsOnlyOneByte) { 18671 v8::V8::Initialize(); 18672 v8::Isolate* isolate = CcTest::isolate(); 18673 v8::HandleScope scope(isolate); 18674 // Make a buffer long enough that it won't automatically be converted. 18675 const int length = 512; 18676 // Ensure word aligned assignment. 18677 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 18678 v8::base::SmartArrayPointer<uintptr_t> aligned_contents( 18679 new uintptr_t[aligned_length]); 18680 uint16_t* string_contents = 18681 reinterpret_cast<uint16_t*>(aligned_contents.get()); 18682 // Set to contain only one byte. 18683 for (int i = 0; i < length-1; i++) { 18684 string_contents[i] = 0x41; 18685 } 18686 string_contents[length-1] = 0; 18687 // Simple case. 18688 Local<String> string = 18689 String::NewExternalTwoByte(isolate, 18690 new TestResource(string_contents, NULL, false)) 18691 .ToLocalChecked(); 18692 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18693 // Counter example. 18694 string = String::NewFromTwoByte(isolate, string_contents, 18695 v8::NewStringType::kNormal) 18696 .ToLocalChecked(); 18697 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 18698 // Test left right and balanced cons strings. 18699 Local<String> base = v8_str("a"); 18700 Local<String> left = base; 18701 Local<String> right = base; 18702 for (int i = 0; i < 1000; i++) { 18703 left = String::Concat(base, left); 18704 right = String::Concat(right, base); 18705 } 18706 Local<String> balanced = String::Concat(left, base); 18707 balanced = String::Concat(balanced, right); 18708 Local<String> cons_strings[] = {left, balanced, right}; 18709 Local<String> two_byte = 18710 String::NewExternalTwoByte(isolate, 18711 new TestResource(string_contents, NULL, false)) 18712 .ToLocalChecked(); 18713 USE(two_byte); USE(cons_strings); 18714 for (size_t i = 0; i < arraysize(cons_strings); i++) { 18715 // Base assumptions. 18716 string = cons_strings[i]; 18717 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 18718 // Test left and right concatentation. 18719 string = String::Concat(two_byte, cons_strings[i]); 18720 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18721 string = String::Concat(cons_strings[i], two_byte); 18722 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18723 } 18724 // Set bits in different positions 18725 // for strings of different lengths and alignments. 18726 for (int alignment = 0; alignment < 7; alignment++) { 18727 for (int size = 2; alignment + size < length; size *= 2) { 18728 int zero_offset = size + alignment; 18729 string_contents[zero_offset] = 0; 18730 for (int i = 0; i < size; i++) { 18731 int shift = 8 + (i % 7); 18732 string_contents[alignment + i] = 1 << shift; 18733 string = String::NewExternalTwoByte( 18734 isolate, 18735 new TestResource(string_contents + alignment, NULL, false)) 18736 .ToLocalChecked(); 18737 CHECK_EQ(size, string->Length()); 18738 CHECK(!string->ContainsOnlyOneByte()); 18739 string_contents[alignment + i] = 0x41; 18740 } 18741 string_contents[zero_offset] = 0x41; 18742 } 18743 } 18744 } 18745 18746 18747 // Failed access check callback that performs a GC on each invocation. 18748 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 18749 v8::AccessType type, 18750 Local<v8::Value> data) { 18751 CcTest::heap()->CollectAllGarbage(); 18752 CcTest::isolate()->ThrowException( 18753 v8::Exception::Error(v8_str("cross context"))); 18754 } 18755 18756 18757 TEST(GCInFailedAccessCheckCallback) { 18758 // Install a failed access check callback that performs a GC on each 18759 // invocation. Then force the callback to be called from va 18760 18761 v8::V8::Initialize(); 18762 v8::Isolate* isolate = CcTest::isolate(); 18763 18764 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 18765 18766 v8::HandleScope scope(isolate); 18767 18768 // Create an ObjectTemplate for global objects and install access 18769 // check callbacks that will block access. 18770 v8::Local<v8::ObjectTemplate> global_template = 18771 v8::ObjectTemplate::New(isolate); 18772 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 18773 18774 // Create a context and set an x property on it's global object. 18775 LocalContext context0(NULL, global_template); 18776 CHECK(context0->Global() 18777 ->Set(context0.local(), v8_str("x"), v8_num(42)) 18778 .FromJust()); 18779 v8::Local<v8::Object> global0 = context0->Global(); 18780 18781 // Create a context with a different security token so that the 18782 // failed access check callback will be called on each access. 18783 LocalContext context1(NULL, global_template); 18784 CHECK(context1->Global() 18785 ->Set(context1.local(), v8_str("other"), global0) 18786 .FromJust()); 18787 18788 v8::TryCatch try_catch(isolate); 18789 18790 // Get property with failed access check. 18791 CHECK(CompileRun("other.x").IsEmpty()); 18792 CHECK(try_catch.HasCaught()); 18793 try_catch.Reset(); 18794 18795 // Get element with failed access check. 18796 CHECK(CompileRun("other[0]").IsEmpty()); 18797 CHECK(try_catch.HasCaught()); 18798 try_catch.Reset(); 18799 18800 // Set property with failed access check. 18801 CHECK(CompileRun("other.x = new Object()").IsEmpty()); 18802 CHECK(try_catch.HasCaught()); 18803 try_catch.Reset(); 18804 18805 // Set element with failed access check. 18806 CHECK(CompileRun("other[0] = new Object()").IsEmpty()); 18807 CHECK(try_catch.HasCaught()); 18808 try_catch.Reset(); 18809 18810 // Get property attribute with failed access check. 18811 CHECK(CompileRun("\'x\' in other").IsEmpty()); 18812 CHECK(try_catch.HasCaught()); 18813 try_catch.Reset(); 18814 18815 // Get property attribute for element with failed access check. 18816 CHECK(CompileRun("0 in other").IsEmpty()); 18817 CHECK(try_catch.HasCaught()); 18818 try_catch.Reset(); 18819 18820 // Delete property. 18821 CHECK(CompileRun("delete other.x").IsEmpty()); 18822 CHECK(try_catch.HasCaught()); 18823 try_catch.Reset(); 18824 18825 // Delete element. 18826 CHECK(global0->Delete(context1.local(), 0).IsNothing()); 18827 CHECK(try_catch.HasCaught()); 18828 try_catch.Reset(); 18829 18830 // DefineAccessor. 18831 CHECK(global0->SetAccessor(context1.local(), v8_str("x"), GetXValue, NULL, 18832 v8_str("x")) 18833 .IsNothing()); 18834 CHECK(try_catch.HasCaught()); 18835 try_catch.Reset(); 18836 18837 // Define JavaScript accessor. 18838 CHECK(CompileRun( 18839 "Object.prototype.__defineGetter__.call(" 18840 " other, \'x\', function() { return 42; })").IsEmpty()); 18841 CHECK(try_catch.HasCaught()); 18842 try_catch.Reset(); 18843 18844 // LookupAccessor. 18845 CHECK(CompileRun( 18846 "Object.prototype.__lookupGetter__.call(" 18847 " other, \'x\')").IsEmpty()); 18848 CHECK(try_catch.HasCaught()); 18849 try_catch.Reset(); 18850 18851 // HasOwnElement. 18852 CHECK(CompileRun( 18853 "Object.prototype.hasOwnProperty.call(" 18854 "other, \'0\')").IsEmpty()); 18855 CHECK(try_catch.HasCaught()); 18856 try_catch.Reset(); 18857 18858 CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing()); 18859 CHECK(try_catch.HasCaught()); 18860 try_catch.Reset(); 18861 18862 CHECK( 18863 global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing()); 18864 CHECK(try_catch.HasCaught()); 18865 try_catch.Reset(); 18866 18867 CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x")) 18868 .IsNothing()); 18869 CHECK(try_catch.HasCaught()); 18870 try_catch.Reset(); 18871 18872 // Reset the failed access check callback so it does not influence 18873 // the other tests. 18874 isolate->SetFailedAccessCheckCallbackFunction(NULL); 18875 } 18876 18877 18878 TEST(IsolateNewDispose) { 18879 v8::Isolate* current_isolate = CcTest::isolate(); 18880 v8::Isolate::CreateParams create_params; 18881 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18882 v8::Isolate* isolate = v8::Isolate::New(create_params); 18883 CHECK(isolate != NULL); 18884 CHECK(current_isolate != isolate); 18885 CHECK(current_isolate == CcTest::isolate()); 18886 18887 isolate->SetFatalErrorHandler(StoringErrorCallback); 18888 last_location = last_message = NULL; 18889 isolate->Dispose(); 18890 CHECK(!last_location); 18891 CHECK(!last_message); 18892 } 18893 18894 18895 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) { 18896 v8::Isolate::CreateParams create_params; 18897 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18898 v8::Isolate* isolate = v8::Isolate::New(create_params); 18899 { 18900 v8::Isolate::Scope i_scope(isolate); 18901 v8::HandleScope scope(isolate); 18902 LocalContext context(isolate); 18903 // Run something in this isolate. 18904 ExpectTrue("true"); 18905 isolate->SetFatalErrorHandler(StoringErrorCallback); 18906 last_location = last_message = NULL; 18907 // Still entered, should fail. 18908 isolate->Dispose(); 18909 CHECK(last_location); 18910 CHECK(last_message); 18911 } 18912 isolate->Dispose(); 18913 } 18914 18915 18916 static void BreakArrayGuarantees(const char* script) { 18917 v8::Isolate::CreateParams create_params; 18918 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18919 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 18920 isolate1->Enter(); 18921 v8::Persistent<v8::Context> context1; 18922 { 18923 v8::HandleScope scope(isolate1); 18924 context1.Reset(isolate1, Context::New(isolate1)); 18925 } 18926 18927 { 18928 v8::HandleScope scope(isolate1); 18929 v8::Local<v8::Context> context = 18930 v8::Local<v8::Context>::New(isolate1, context1); 18931 v8::Context::Scope context_scope(context); 18932 v8::internal::Isolate* i_isolate = 18933 reinterpret_cast<v8::internal::Isolate*>(isolate1); 18934 CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact()); 18935 // Run something in new isolate. 18936 CompileRun(script); 18937 CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact()); 18938 } 18939 isolate1->Exit(); 18940 isolate1->Dispose(); 18941 } 18942 18943 18944 TEST(VerifyArrayPrototypeGuarantees) { 18945 // Break fast array hole handling by element changes. 18946 BreakArrayGuarantees("[].__proto__[1] = 3;"); 18947 BreakArrayGuarantees("Object.prototype[3] = 'three';"); 18948 BreakArrayGuarantees("Array.prototype.push(1);"); 18949 BreakArrayGuarantees("Array.prototype.unshift(1);"); 18950 // Break fast array hole handling by changing length. 18951 BreakArrayGuarantees("Array.prototype.length = 30;"); 18952 // Break fast array hole handling by prototype structure changes. 18953 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };"); 18954 // By sending elements to dictionary mode. 18955 BreakArrayGuarantees( 18956 "Object.defineProperty(Array.prototype, 0, {" 18957 " get: function() { return 3; }});"); 18958 BreakArrayGuarantees( 18959 "Object.defineProperty(Object.prototype, 0, {" 18960 " get: function() { return 3; }});"); 18961 } 18962 18963 18964 TEST(RunTwoIsolatesOnSingleThread) { 18965 // Run isolate 1. 18966 v8::Isolate::CreateParams create_params; 18967 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18968 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 18969 isolate1->Enter(); 18970 v8::Persistent<v8::Context> context1; 18971 { 18972 v8::HandleScope scope(isolate1); 18973 context1.Reset(isolate1, Context::New(isolate1)); 18974 } 18975 18976 { 18977 v8::HandleScope scope(isolate1); 18978 v8::Local<v8::Context> context = 18979 v8::Local<v8::Context>::New(isolate1, context1); 18980 v8::Context::Scope context_scope(context); 18981 // Run something in new isolate. 18982 CompileRun("var foo = 'isolate 1';"); 18983 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18984 } 18985 18986 // Run isolate 2. 18987 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 18988 v8::Persistent<v8::Context> context2; 18989 18990 { 18991 v8::Isolate::Scope iscope(isolate2); 18992 v8::HandleScope scope(isolate2); 18993 context2.Reset(isolate2, Context::New(isolate2)); 18994 v8::Local<v8::Context> context = 18995 v8::Local<v8::Context>::New(isolate2, context2); 18996 v8::Context::Scope context_scope(context); 18997 18998 // Run something in new isolate. 18999 CompileRun("var foo = 'isolate 2';"); 19000 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19001 } 19002 19003 { 19004 v8::HandleScope scope(isolate1); 19005 v8::Local<v8::Context> context = 19006 v8::Local<v8::Context>::New(isolate1, context1); 19007 v8::Context::Scope context_scope(context); 19008 // Now again in isolate 1 19009 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19010 } 19011 19012 isolate1->Exit(); 19013 19014 // Run some stuff in default isolate. 19015 v8::Persistent<v8::Context> context_default; 19016 { 19017 v8::Isolate* isolate = CcTest::isolate(); 19018 v8::Isolate::Scope iscope(isolate); 19019 v8::HandleScope scope(isolate); 19020 context_default.Reset(isolate, Context::New(isolate)); 19021 } 19022 19023 { 19024 v8::HandleScope scope(CcTest::isolate()); 19025 v8::Local<v8::Context> context = 19026 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19027 v8::Context::Scope context_scope(context); 19028 // Variables in other isolates should be not available, verify there 19029 // is an exception. 19030 ExpectTrue("function f() {" 19031 " try {" 19032 " foo;" 19033 " return false;" 19034 " } catch(e) {" 19035 " return true;" 19036 " }" 19037 "};" 19038 "var isDefaultIsolate = true;" 19039 "f()"); 19040 } 19041 19042 isolate1->Enter(); 19043 19044 { 19045 v8::Isolate::Scope iscope(isolate2); 19046 v8::HandleScope scope(isolate2); 19047 v8::Local<v8::Context> context = 19048 v8::Local<v8::Context>::New(isolate2, context2); 19049 v8::Context::Scope context_scope(context); 19050 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19051 } 19052 19053 { 19054 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19055 v8::Local<v8::Context> context = 19056 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 19057 v8::Context::Scope context_scope(context); 19058 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19059 } 19060 19061 { 19062 v8::Isolate::Scope iscope(isolate2); 19063 context2.Reset(); 19064 } 19065 19066 context1.Reset(); 19067 isolate1->Exit(); 19068 19069 isolate2->SetFatalErrorHandler(StoringErrorCallback); 19070 last_location = last_message = NULL; 19071 19072 isolate1->Dispose(); 19073 CHECK(!last_location); 19074 CHECK(!last_message); 19075 19076 isolate2->Dispose(); 19077 CHECK(!last_location); 19078 CHECK(!last_message); 19079 19080 // Check that default isolate still runs. 19081 { 19082 v8::HandleScope scope(CcTest::isolate()); 19083 v8::Local<v8::Context> context = 19084 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19085 v8::Context::Scope context_scope(context); 19086 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 19087 } 19088 } 19089 19090 19091 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 19092 v8::Isolate::Scope isolate_scope(isolate); 19093 v8::HandleScope scope(isolate); 19094 LocalContext context(isolate); 19095 i::ScopedVector<char> code(1024); 19096 i::SNPrintF(code, "function fib(n) {" 19097 " if (n <= 2) return 1;" 19098 " return fib(n-1) + fib(n-2);" 19099 "}" 19100 "fib(%d)", limit); 19101 Local<Value> value = CompileRun(code.start()); 19102 CHECK(value->IsNumber()); 19103 return static_cast<int>(value->NumberValue(context.local()).FromJust()); 19104 } 19105 19106 class IsolateThread : public v8::base::Thread { 19107 public: 19108 explicit IsolateThread(int fib_limit) 19109 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {} 19110 19111 void Run() { 19112 v8::Isolate::CreateParams create_params; 19113 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19114 v8::Isolate* isolate = v8::Isolate::New(create_params); 19115 result_ = CalcFibonacci(isolate, fib_limit_); 19116 isolate->Dispose(); 19117 } 19118 19119 int result() { return result_; } 19120 19121 private: 19122 int fib_limit_; 19123 int result_; 19124 }; 19125 19126 19127 TEST(MultipleIsolatesOnIndividualThreads) { 19128 IsolateThread thread1(21); 19129 IsolateThread thread2(12); 19130 19131 // Compute some fibonacci numbers on 3 threads in 3 isolates. 19132 thread1.Start(); 19133 thread2.Start(); 19134 19135 int result1 = CalcFibonacci(CcTest::isolate(), 21); 19136 int result2 = CalcFibonacci(CcTest::isolate(), 12); 19137 19138 thread1.Join(); 19139 thread2.Join(); 19140 19141 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 19142 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 19143 CHECK_EQ(result1, 10946); 19144 CHECK_EQ(result2, 144); 19145 CHECK_EQ(result1, thread1.result()); 19146 CHECK_EQ(result2, thread2.result()); 19147 } 19148 19149 19150 TEST(IsolateDifferentContexts) { 19151 v8::Isolate::CreateParams create_params; 19152 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19153 v8::Isolate* isolate = v8::Isolate::New(create_params); 19154 Local<v8::Context> context; 19155 { 19156 v8::Isolate::Scope isolate_scope(isolate); 19157 v8::HandleScope handle_scope(isolate); 19158 context = v8::Context::New(isolate); 19159 v8::Context::Scope context_scope(context); 19160 Local<Value> v = CompileRun("2"); 19161 CHECK(v->IsNumber()); 19162 CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust())); 19163 } 19164 { 19165 v8::Isolate::Scope isolate_scope(isolate); 19166 v8::HandleScope handle_scope(isolate); 19167 context = v8::Context::New(isolate); 19168 v8::Context::Scope context_scope(context); 19169 Local<Value> v = CompileRun("22"); 19170 CHECK(v->IsNumber()); 19171 CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust())); 19172 } 19173 isolate->Dispose(); 19174 } 19175 19176 class InitDefaultIsolateThread : public v8::base::Thread { 19177 public: 19178 enum TestCase { 19179 SetResourceConstraints, 19180 SetFatalHandler, 19181 SetCounterFunction, 19182 SetCreateHistogramFunction, 19183 SetAddHistogramSampleFunction 19184 }; 19185 19186 explicit InitDefaultIsolateThread(TestCase testCase) 19187 : Thread(Options("InitDefaultIsolateThread")), 19188 testCase_(testCase), 19189 result_(false) {} 19190 19191 void Run() { 19192 v8::Isolate::CreateParams create_params; 19193 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19194 const intptr_t pageSizeMult = 19195 v8::internal::Page::kPageSize / v8::internal::MB; 19196 switch (testCase_) { 19197 case SetResourceConstraints: { 19198 create_params.constraints.set_max_semi_space_size(1 * pageSizeMult); 19199 create_params.constraints.set_max_old_space_size(4 * pageSizeMult); 19200 break; 19201 } 19202 default: 19203 break; 19204 } 19205 v8::Isolate* isolate = v8::Isolate::New(create_params); 19206 isolate->Enter(); 19207 switch (testCase_) { 19208 case SetResourceConstraints: 19209 // Already handled in pre-Isolate-creation block. 19210 break; 19211 19212 case SetFatalHandler: 19213 isolate->SetFatalErrorHandler(NULL); 19214 break; 19215 19216 case SetCounterFunction: 19217 CcTest::isolate()->SetCounterFunction(NULL); 19218 break; 19219 19220 case SetCreateHistogramFunction: 19221 CcTest::isolate()->SetCreateHistogramFunction(NULL); 19222 break; 19223 19224 case SetAddHistogramSampleFunction: 19225 CcTest::isolate()->SetAddHistogramSampleFunction(NULL); 19226 break; 19227 } 19228 isolate->Exit(); 19229 isolate->Dispose(); 19230 result_ = true; 19231 } 19232 19233 bool result() { return result_; } 19234 19235 private: 19236 TestCase testCase_; 19237 bool result_; 19238 }; 19239 19240 19241 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 19242 InitDefaultIsolateThread thread(testCase); 19243 thread.Start(); 19244 thread.Join(); 19245 CHECK_EQ(thread.result(), true); 19246 } 19247 19248 19249 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 19250 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 19251 } 19252 19253 19254 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 19255 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 19256 } 19257 19258 19259 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 19260 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 19261 } 19262 19263 19264 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 19265 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 19266 } 19267 19268 19269 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 19270 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 19271 } 19272 19273 19274 TEST(StringCheckMultipleContexts) { 19275 const char* code = 19276 "(function() { return \"a\".charAt(0); })()"; 19277 19278 { 19279 // Run the code twice in the first context to initialize the call IC. 19280 LocalContext context1; 19281 v8::HandleScope scope(context1->GetIsolate()); 19282 ExpectString(code, "a"); 19283 ExpectString(code, "a"); 19284 } 19285 19286 { 19287 // Change the String.prototype in the second context and check 19288 // that the right function gets called. 19289 LocalContext context2; 19290 v8::HandleScope scope(context2->GetIsolate()); 19291 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 19292 ExpectString(code, "not a"); 19293 } 19294 } 19295 19296 19297 TEST(NumberCheckMultipleContexts) { 19298 const char* code = 19299 "(function() { return (42).toString(); })()"; 19300 19301 { 19302 // Run the code twice in the first context to initialize the call IC. 19303 LocalContext context1; 19304 v8::HandleScope scope(context1->GetIsolate()); 19305 ExpectString(code, "42"); 19306 ExpectString(code, "42"); 19307 } 19308 19309 { 19310 // Change the Number.prototype in the second context and check 19311 // that the right function gets called. 19312 LocalContext context2; 19313 v8::HandleScope scope(context2->GetIsolate()); 19314 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 19315 ExpectString(code, "not 42"); 19316 } 19317 } 19318 19319 19320 TEST(BooleanCheckMultipleContexts) { 19321 const char* code = 19322 "(function() { return true.toString(); })()"; 19323 19324 { 19325 // Run the code twice in the first context to initialize the call IC. 19326 LocalContext context1; 19327 v8::HandleScope scope(context1->GetIsolate()); 19328 ExpectString(code, "true"); 19329 ExpectString(code, "true"); 19330 } 19331 19332 { 19333 // Change the Boolean.prototype in the second context and check 19334 // that the right function gets called. 19335 LocalContext context2; 19336 v8::HandleScope scope(context2->GetIsolate()); 19337 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 19338 ExpectString(code, ""); 19339 } 19340 } 19341 19342 19343 TEST(DontDeleteCellLoadIC) { 19344 const char* function_code = 19345 "function readCell() { while (true) { return cell; } }"; 19346 19347 { 19348 // Run the code twice in the first context to initialize the load 19349 // IC for a don't delete cell. 19350 LocalContext context1; 19351 v8::HandleScope scope(context1->GetIsolate()); 19352 CompileRun("var cell = \"first\";"); 19353 ExpectBoolean("delete cell", false); 19354 CompileRun(function_code); 19355 ExpectString("readCell()", "first"); 19356 ExpectString("readCell()", "first"); 19357 } 19358 19359 { 19360 // Use a deletable cell in the second context. 19361 LocalContext context2; 19362 v8::HandleScope scope(context2->GetIsolate()); 19363 CompileRun("cell = \"second\";"); 19364 CompileRun(function_code); 19365 ExpectString("readCell()", "second"); 19366 ExpectBoolean("delete cell", true); 19367 ExpectString("(function() {" 19368 " try {" 19369 " return readCell();" 19370 " } catch(e) {" 19371 " return e.toString();" 19372 " }" 19373 "})()", 19374 "ReferenceError: cell is not defined"); 19375 CompileRun("cell = \"new_second\";"); 19376 CcTest::heap()->CollectAllGarbage(); 19377 ExpectString("readCell()", "new_second"); 19378 ExpectString("readCell()", "new_second"); 19379 } 19380 } 19381 19382 19383 class Visitor42 : public v8::PersistentHandleVisitor { 19384 public: 19385 explicit Visitor42(v8::Persistent<v8::Object>* object) 19386 : counter_(0), object_(object) { } 19387 19388 virtual void VisitPersistentHandle(Persistent<Value>* value, 19389 uint16_t class_id) { 19390 if (class_id != 42) return; 19391 CHECK_EQ(42, value->WrapperClassId()); 19392 v8::Isolate* isolate = CcTest::isolate(); 19393 v8::HandleScope handle_scope(isolate); 19394 v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 19395 v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_); 19396 CHECK(handle->IsObject()); 19397 CHECK(Local<Object>::Cast(handle) 19398 ->Equals(isolate->GetCurrentContext(), object) 19399 .FromJust()); 19400 ++counter_; 19401 } 19402 19403 int counter_; 19404 v8::Persistent<v8::Object>* object_; 19405 }; 19406 19407 19408 TEST(PersistentHandleVisitor) { 19409 LocalContext context; 19410 v8::Isolate* isolate = context->GetIsolate(); 19411 v8::HandleScope scope(isolate); 19412 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19413 CHECK_EQ(0, object.WrapperClassId()); 19414 object.SetWrapperClassId(42); 19415 CHECK_EQ(42, object.WrapperClassId()); 19416 19417 Visitor42 visitor(&object); 19418 isolate->VisitHandlesWithClassIds(&visitor); 19419 CHECK_EQ(1, visitor.counter_); 19420 19421 object.Reset(); 19422 } 19423 19424 19425 TEST(WrapperClassId) { 19426 LocalContext context; 19427 v8::Isolate* isolate = context->GetIsolate(); 19428 v8::HandleScope scope(isolate); 19429 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19430 CHECK_EQ(0, object.WrapperClassId()); 19431 object.SetWrapperClassId(65535); 19432 CHECK_EQ(65535, object.WrapperClassId()); 19433 object.Reset(); 19434 } 19435 19436 19437 TEST(PersistentHandleInNewSpaceVisitor) { 19438 LocalContext context; 19439 v8::Isolate* isolate = context->GetIsolate(); 19440 v8::HandleScope scope(isolate); 19441 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate)); 19442 CHECK_EQ(0, object1.WrapperClassId()); 19443 object1.SetWrapperClassId(42); 19444 CHECK_EQ(42, object1.WrapperClassId()); 19445 19446 CcTest::heap()->CollectAllGarbage(); 19447 CcTest::heap()->CollectAllGarbage(); 19448 19449 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); 19450 CHECK_EQ(0, object2.WrapperClassId()); 19451 object2.SetWrapperClassId(42); 19452 CHECK_EQ(42, object2.WrapperClassId()); 19453 19454 Visitor42 visitor(&object2); 19455 isolate->VisitHandlesForPartialDependence(&visitor); 19456 CHECK_EQ(1, visitor.counter_); 19457 19458 object1.Reset(); 19459 object2.Reset(); 19460 } 19461 19462 19463 TEST(RegExp) { 19464 i::FLAG_harmony_regexps = true; 19465 i::FLAG_harmony_unicode_regexps = true; 19466 LocalContext context; 19467 v8::HandleScope scope(context->GetIsolate()); 19468 19469 v8::Local<v8::RegExp> re = 19470 v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone) 19471 .ToLocalChecked(); 19472 CHECK(re->IsRegExp()); 19473 CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust()); 19474 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19475 19476 re = v8::RegExp::New(context.local(), v8_str("bar"), 19477 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19478 v8::RegExp::kGlobal)) 19479 .ToLocalChecked(); 19480 CHECK(re->IsRegExp()); 19481 CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust()); 19482 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 19483 static_cast<int>(re->GetFlags())); 19484 19485 re = v8::RegExp::New(context.local(), v8_str("baz"), 19486 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19487 v8::RegExp::kMultiline)) 19488 .ToLocalChecked(); 19489 CHECK(re->IsRegExp()); 19490 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust()); 19491 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19492 static_cast<int>(re->GetFlags())); 19493 19494 re = v8::RegExp::New(context.local(), v8_str("baz"), 19495 static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode | 19496 v8::RegExp::kSticky)) 19497 .ToLocalChecked(); 19498 CHECK(re->IsRegExp()); 19499 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust()); 19500 CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky, 19501 static_cast<int>(re->GetFlags())); 19502 19503 re = CompileRun("/quux/").As<v8::RegExp>(); 19504 CHECK(re->IsRegExp()); 19505 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust()); 19506 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19507 19508 re = CompileRun("/quux/gm").As<v8::RegExp>(); 19509 CHECK(re->IsRegExp()); 19510 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust()); 19511 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 19512 static_cast<int>(re->GetFlags())); 19513 19514 // Override the RegExp constructor and check the API constructor 19515 // still works. 19516 CompileRun("RegExp = function() {}"); 19517 19518 re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone) 19519 .ToLocalChecked(); 19520 CHECK(re->IsRegExp()); 19521 CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust()); 19522 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19523 19524 re = v8::RegExp::New(context.local(), v8_str("foobarbaz"), 19525 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19526 v8::RegExp::kMultiline)) 19527 .ToLocalChecked(); 19528 CHECK(re->IsRegExp()); 19529 CHECK( 19530 re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust()); 19531 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19532 static_cast<int>(re->GetFlags())); 19533 19534 CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust()); 19535 ExpectTrue("re.test('FoobarbaZ')"); 19536 19537 // RegExps are objects on which you can set properties. 19538 re->Set(context.local(), v8_str("property"), 19539 v8::Integer::New(context->GetIsolate(), 32)) 19540 .FromJust(); 19541 v8::Local<v8::Value> value(CompileRun("re.property")); 19542 CHECK_EQ(32, value->Int32Value(context.local()).FromJust()); 19543 19544 v8::TryCatch try_catch(context->GetIsolate()); 19545 CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone) 19546 .IsEmpty()); 19547 CHECK(try_catch.HasCaught()); 19548 CHECK(context->Global() 19549 ->Set(context.local(), v8_str("ex"), try_catch.Exception()) 19550 .FromJust()); 19551 ExpectTrue("ex instanceof SyntaxError"); 19552 } 19553 19554 19555 THREADED_TEST(Equals) { 19556 LocalContext localContext; 19557 v8::HandleScope handleScope(localContext->GetIsolate()); 19558 19559 v8::Local<v8::Object> globalProxy = localContext->Global(); 19560 v8::Local<Value> global = globalProxy->GetPrototype(); 19561 19562 CHECK(global->StrictEquals(global)); 19563 CHECK(!global->StrictEquals(globalProxy)); 19564 CHECK(!globalProxy->StrictEquals(global)); 19565 CHECK(globalProxy->StrictEquals(globalProxy)); 19566 19567 CHECK(global->Equals(localContext.local(), global).FromJust()); 19568 CHECK(!global->Equals(localContext.local(), globalProxy).FromJust()); 19569 CHECK(!globalProxy->Equals(localContext.local(), global).FromJust()); 19570 CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust()); 19571 } 19572 19573 19574 static void Getter(v8::Local<v8::Name> property, 19575 const v8::PropertyCallbackInfo<v8::Value>& info) { 19576 info.GetReturnValue().Set(v8_str("42!")); 19577 } 19578 19579 19580 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 19581 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate()); 19582 result->Set(info.GetIsolate()->GetCurrentContext(), 0, 19583 v8_str("universalAnswer")) 19584 .FromJust(); 19585 info.GetReturnValue().Set(result); 19586 } 19587 19588 19589 TEST(NamedEnumeratorAndForIn) { 19590 LocalContext context; 19591 v8::Isolate* isolate = context->GetIsolate(); 19592 v8::HandleScope handle_scope(isolate); 19593 v8::Context::Scope context_scope(context.local()); 19594 19595 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate); 19596 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL, 19597 NULL, Enumerator)); 19598 CHECK(context->Global() 19599 ->Set(context.local(), v8_str("o"), 19600 tmpl->NewInstance(context.local()).ToLocalChecked()) 19601 .FromJust()); 19602 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast( 19603 CompileRun("var result = []; for (var k in o) result.push(k); result")); 19604 CHECK_EQ(1u, result->Length()); 19605 CHECK(v8_str("universalAnswer") 19606 ->Equals(context.local(), 19607 result->Get(context.local(), 0).ToLocalChecked()) 19608 .FromJust()); 19609 } 19610 19611 19612 TEST(DefinePropertyPostDetach) { 19613 LocalContext context; 19614 v8::HandleScope scope(context->GetIsolate()); 19615 v8::Local<v8::Object> proxy = context->Global(); 19616 v8::Local<v8::Function> define_property = 19617 CompileRun( 19618 "(function() {" 19619 " Object.defineProperty(" 19620 " this," 19621 " 1," 19622 " { configurable: true, enumerable: true, value: 3 });" 19623 "})") 19624 .As<Function>(); 19625 context->DetachGlobal(); 19626 CHECK(define_property->Call(context.local(), proxy, 0, NULL).IsEmpty()); 19627 } 19628 19629 19630 static void InstallContextId(v8::Local<Context> context, int id) { 19631 Context::Scope scope(context); 19632 CHECK(CompileRun("Object.prototype") 19633 .As<Object>() 19634 ->Set(context, v8_str("context_id"), 19635 v8::Integer::New(context->GetIsolate(), id)) 19636 .FromJust()); 19637 } 19638 19639 19640 static void CheckContextId(v8::Local<Object> object, int expected) { 19641 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 19642 CHECK_EQ(expected, object->Get(context, v8_str("context_id")) 19643 .ToLocalChecked() 19644 ->Int32Value(context) 19645 .FromJust()); 19646 } 19647 19648 19649 THREADED_TEST(CreationContext) { 19650 v8::Isolate* isolate = CcTest::isolate(); 19651 HandleScope handle_scope(isolate); 19652 Local<Context> context1 = Context::New(isolate); 19653 InstallContextId(context1, 1); 19654 Local<Context> context2 = Context::New(isolate); 19655 InstallContextId(context2, 2); 19656 Local<Context> context3 = Context::New(isolate); 19657 InstallContextId(context3, 3); 19658 19659 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate); 19660 19661 Local<Object> object1; 19662 Local<Function> func1; 19663 { 19664 Context::Scope scope(context1); 19665 object1 = Object::New(isolate); 19666 func1 = tmpl->GetFunction(context1).ToLocalChecked(); 19667 } 19668 19669 Local<Object> object2; 19670 Local<Function> func2; 19671 { 19672 Context::Scope scope(context2); 19673 object2 = Object::New(isolate); 19674 func2 = tmpl->GetFunction(context2).ToLocalChecked(); 19675 } 19676 19677 Local<Object> instance1; 19678 Local<Object> instance2; 19679 19680 { 19681 Context::Scope scope(context3); 19682 instance1 = func1->NewInstance(context3).ToLocalChecked(); 19683 instance2 = func2->NewInstance(context3).ToLocalChecked(); 19684 } 19685 19686 { 19687 Local<Context> other_context = Context::New(isolate); 19688 Context::Scope scope(other_context); 19689 CHECK(object1->CreationContext() == context1); 19690 CheckContextId(object1, 1); 19691 CHECK(func1->CreationContext() == context1); 19692 CheckContextId(func1, 1); 19693 CHECK(instance1->CreationContext() == context1); 19694 CheckContextId(instance1, 1); 19695 CHECK(object2->CreationContext() == context2); 19696 CheckContextId(object2, 2); 19697 CHECK(func2->CreationContext() == context2); 19698 CheckContextId(func2, 2); 19699 CHECK(instance2->CreationContext() == context2); 19700 CheckContextId(instance2, 2); 19701 } 19702 19703 { 19704 Context::Scope scope(context1); 19705 CHECK(object1->CreationContext() == context1); 19706 CheckContextId(object1, 1); 19707 CHECK(func1->CreationContext() == context1); 19708 CheckContextId(func1, 1); 19709 CHECK(instance1->CreationContext() == context1); 19710 CheckContextId(instance1, 1); 19711 CHECK(object2->CreationContext() == context2); 19712 CheckContextId(object2, 2); 19713 CHECK(func2->CreationContext() == context2); 19714 CheckContextId(func2, 2); 19715 CHECK(instance2->CreationContext() == context2); 19716 CheckContextId(instance2, 2); 19717 } 19718 19719 { 19720 Context::Scope scope(context2); 19721 CHECK(object1->CreationContext() == context1); 19722 CheckContextId(object1, 1); 19723 CHECK(func1->CreationContext() == context1); 19724 CheckContextId(func1, 1); 19725 CHECK(instance1->CreationContext() == context1); 19726 CheckContextId(instance1, 1); 19727 CHECK(object2->CreationContext() == context2); 19728 CheckContextId(object2, 2); 19729 CHECK(func2->CreationContext() == context2); 19730 CheckContextId(func2, 2); 19731 CHECK(instance2->CreationContext() == context2); 19732 CheckContextId(instance2, 2); 19733 } 19734 } 19735 19736 19737 THREADED_TEST(CreationContextOfJsFunction) { 19738 HandleScope handle_scope(CcTest::isolate()); 19739 Local<Context> context = Context::New(CcTest::isolate()); 19740 InstallContextId(context, 1); 19741 19742 Local<Object> function; 19743 { 19744 Context::Scope scope(context); 19745 function = CompileRun("function foo() {}; foo").As<Object>(); 19746 } 19747 19748 Local<Context> other_context = Context::New(CcTest::isolate()); 19749 Context::Scope scope(other_context); 19750 CHECK(function->CreationContext() == context); 19751 CheckContextId(function, 1); 19752 } 19753 19754 19755 THREADED_TEST(CreationContextOfJsBoundFunction) { 19756 HandleScope handle_scope(CcTest::isolate()); 19757 Local<Context> context1 = Context::New(CcTest::isolate()); 19758 InstallContextId(context1, 1); 19759 Local<Context> context2 = Context::New(CcTest::isolate()); 19760 InstallContextId(context2, 2); 19761 19762 Local<Function> target_function; 19763 { 19764 Context::Scope scope(context1); 19765 target_function = CompileRun("function foo() {}; foo").As<Function>(); 19766 } 19767 19768 Local<Function> bound_function1, bound_function2; 19769 { 19770 Context::Scope scope(context2); 19771 CHECK(context2->Global() 19772 ->Set(context2, v8_str("foo"), target_function) 19773 .FromJust()); 19774 bound_function1 = CompileRun("foo.bind(1)").As<Function>(); 19775 bound_function2 = 19776 CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>(); 19777 } 19778 19779 Local<Context> other_context = Context::New(CcTest::isolate()); 19780 Context::Scope scope(other_context); 19781 CHECK(bound_function1->CreationContext() == context1); 19782 CheckContextId(bound_function1, 1); 19783 CHECK(bound_function2->CreationContext() == context2); 19784 CheckContextId(bound_function2, 1); 19785 } 19786 19787 19788 void HasOwnPropertyIndexedPropertyGetter( 19789 uint32_t index, 19790 const v8::PropertyCallbackInfo<v8::Value>& info) { 19791 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 19792 } 19793 19794 19795 void HasOwnPropertyNamedPropertyGetter( 19796 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) { 19797 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 19798 .FromJust()) { 19799 info.GetReturnValue().Set(v8_str("yes")); 19800 } 19801 } 19802 19803 19804 void HasOwnPropertyIndexedPropertyQuery( 19805 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 19806 if (index == 42) info.GetReturnValue().Set(1); 19807 } 19808 19809 19810 void HasOwnPropertyNamedPropertyQuery( 19811 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) { 19812 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 19813 .FromJust()) { 19814 info.GetReturnValue().Set(1); 19815 } 19816 } 19817 19818 19819 void HasOwnPropertyNamedPropertyQuery2( 19820 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) { 19821 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar")) 19822 .FromJust()) { 19823 info.GetReturnValue().Set(1); 19824 } 19825 } 19826 19827 19828 void HasOwnPropertyAccessorGetter( 19829 Local<String> property, 19830 const v8::PropertyCallbackInfo<v8::Value>& info) { 19831 info.GetReturnValue().Set(v8_str("yes")); 19832 } 19833 19834 19835 TEST(HasOwnProperty) { 19836 LocalContext env; 19837 v8::Isolate* isolate = env->GetIsolate(); 19838 v8::HandleScope scope(isolate); 19839 { // Check normal properties and defined getters. 19840 Local<Value> value = CompileRun( 19841 "function Foo() {" 19842 " this.foo = 11;" 19843 " this.__defineGetter__('baz', function() { return 1; });" 19844 "};" 19845 "function Bar() { " 19846 " this.bar = 13;" 19847 " this.__defineGetter__('bla', function() { return 2; });" 19848 "};" 19849 "Bar.prototype = new Foo();" 19850 "new Bar();"); 19851 CHECK(value->IsObject()); 19852 Local<Object> object = value->ToObject(env.local()).ToLocalChecked(); 19853 CHECK(object->Has(env.local(), v8_str("foo")).FromJust()); 19854 CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19855 CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 19856 CHECK(object->Has(env.local(), v8_str("baz")).FromJust()); 19857 CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust()); 19858 CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust()); 19859 } 19860 { // Check named getter interceptors. 19861 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19862 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 19863 HasOwnPropertyNamedPropertyGetter)); 19864 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19865 CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 19866 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19867 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 19868 } 19869 { // Check indexed getter interceptors. 19870 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19871 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 19872 HasOwnPropertyIndexedPropertyGetter)); 19873 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19874 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 19875 CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust()); 19876 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19877 } 19878 { // Check named query interceptors. 19879 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19880 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 19881 0, 0, HasOwnPropertyNamedPropertyQuery)); 19882 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19883 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19884 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 19885 } 19886 { // Check indexed query interceptors. 19887 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19888 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 19889 0, 0, HasOwnPropertyIndexedPropertyQuery)); 19890 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19891 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 19892 CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust()); 19893 } 19894 { // Check callbacks. 19895 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19896 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 19897 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19898 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19899 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 19900 } 19901 { // Check that query wins on disagreement. 19902 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19903 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 19904 HasOwnPropertyNamedPropertyGetter, 0, 19905 HasOwnPropertyNamedPropertyQuery2)); 19906 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 19907 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 19908 CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 19909 } 19910 } 19911 19912 19913 TEST(IndexedInterceptorWithStringProto) { 19914 v8::Isolate* isolate = CcTest::isolate(); 19915 v8::HandleScope scope(isolate); 19916 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19917 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 19918 NULL, NULL, HasOwnPropertyIndexedPropertyQuery)); 19919 LocalContext context; 19920 CHECK(context->Global() 19921 ->Set(context.local(), v8_str("obj"), 19922 templ->NewInstance(context.local()).ToLocalChecked()) 19923 .FromJust()); 19924 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 19925 // These should be intercepted. 19926 CHECK(CompileRun("42 in obj")->BooleanValue(context.local()).FromJust()); 19927 CHECK(CompileRun("'42' in obj")->BooleanValue(context.local()).FromJust()); 19928 // These should fall through to the String prototype. 19929 CHECK(CompileRun("0 in obj")->BooleanValue(context.local()).FromJust()); 19930 CHECK(CompileRun("'0' in obj")->BooleanValue(context.local()).FromJust()); 19931 // And these should both fail. 19932 CHECK(!CompileRun("32 in obj")->BooleanValue(context.local()).FromJust()); 19933 CHECK(!CompileRun("'32' in obj")->BooleanValue(context.local()).FromJust()); 19934 } 19935 19936 19937 void CheckCodeGenerationAllowed() { 19938 Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 19939 Local<Value> result = CompileRun("eval('42')"); 19940 CHECK_EQ(42, result->Int32Value(context).FromJust()); 19941 result = CompileRun("(function(e) { return e('42'); })(eval)"); 19942 CHECK_EQ(42, result->Int32Value(context).FromJust()); 19943 result = CompileRun("var f = new Function('return 42'); f()"); 19944 CHECK_EQ(42, result->Int32Value(context).FromJust()); 19945 } 19946 19947 19948 void CheckCodeGenerationDisallowed() { 19949 TryCatch try_catch(CcTest::isolate()); 19950 19951 Local<Value> result = CompileRun("eval('42')"); 19952 CHECK(result.IsEmpty()); 19953 CHECK(try_catch.HasCaught()); 19954 try_catch.Reset(); 19955 19956 result = CompileRun("(function(e) { return e('42'); })(eval)"); 19957 CHECK(result.IsEmpty()); 19958 CHECK(try_catch.HasCaught()); 19959 try_catch.Reset(); 19960 19961 result = CompileRun("var f = new Function('return 42'); f()"); 19962 CHECK(result.IsEmpty()); 19963 CHECK(try_catch.HasCaught()); 19964 } 19965 19966 19967 bool CodeGenerationAllowed(Local<Context> context) { 19968 ApiTestFuzzer::Fuzz(); 19969 return true; 19970 } 19971 19972 19973 bool CodeGenerationDisallowed(Local<Context> context) { 19974 ApiTestFuzzer::Fuzz(); 19975 return false; 19976 } 19977 19978 19979 THREADED_TEST(AllowCodeGenFromStrings) { 19980 LocalContext context; 19981 v8::HandleScope scope(context->GetIsolate()); 19982 19983 // eval and the Function constructor allowed by default. 19984 CHECK(context->IsCodeGenerationFromStringsAllowed()); 19985 CheckCodeGenerationAllowed(); 19986 19987 // Disallow eval and the Function constructor. 19988 context->AllowCodeGenerationFromStrings(false); 19989 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 19990 CheckCodeGenerationDisallowed(); 19991 19992 // Allow again. 19993 context->AllowCodeGenerationFromStrings(true); 19994 CheckCodeGenerationAllowed(); 19995 19996 // Disallow but setting a global callback that will allow the calls. 19997 context->AllowCodeGenerationFromStrings(false); 19998 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 19999 &CodeGenerationAllowed); 20000 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20001 CheckCodeGenerationAllowed(); 20002 20003 // Set a callback that disallows the code generation. 20004 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 20005 &CodeGenerationDisallowed); 20006 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20007 CheckCodeGenerationDisallowed(); 20008 } 20009 20010 20011 TEST(SetErrorMessageForCodeGenFromStrings) { 20012 LocalContext context; 20013 v8::HandleScope scope(context->GetIsolate()); 20014 TryCatch try_catch(context->GetIsolate()); 20015 20016 Local<String> message = v8_str("Message"); 20017 Local<String> expected_message = v8_str("Uncaught EvalError: Message"); 20018 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 20019 &CodeGenerationDisallowed); 20020 context->AllowCodeGenerationFromStrings(false); 20021 context->SetErrorMessageForCodeGenerationFromStrings(message); 20022 Local<Value> result = CompileRun("eval('42')"); 20023 CHECK(result.IsEmpty()); 20024 CHECK(try_catch.HasCaught()); 20025 Local<String> actual_message = try_catch.Message()->Get(); 20026 CHECK(expected_message->Equals(context.local(), actual_message).FromJust()); 20027 } 20028 20029 20030 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 20031 } 20032 20033 20034 THREADED_TEST(CallAPIFunctionOnNonObject) { 20035 LocalContext context; 20036 v8::Isolate* isolate = context->GetIsolate(); 20037 v8::HandleScope scope(isolate); 20038 Local<FunctionTemplate> templ = 20039 v8::FunctionTemplate::New(isolate, NonObjectThis); 20040 Local<Function> function = 20041 templ->GetFunction(context.local()).ToLocalChecked(); 20042 CHECK(context->Global() 20043 ->Set(context.local(), v8_str("f"), function) 20044 .FromJust()); 20045 TryCatch try_catch(isolate); 20046 CompileRun("f.call(2)"); 20047 } 20048 20049 20050 // Regression test for issue 1470. 20051 THREADED_TEST(ReadOnlyIndexedProperties) { 20052 v8::Isolate* isolate = CcTest::isolate(); 20053 v8::HandleScope scope(isolate); 20054 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20055 20056 LocalContext context; 20057 Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked(); 20058 CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust()); 20059 obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"), 20060 v8::ReadOnly) 20061 .FromJust(); 20062 obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust(); 20063 CHECK(v8_str("DONT_CHANGE") 20064 ->Equals(context.local(), 20065 obj->Get(context.local(), v8_str("1")).ToLocalChecked()) 20066 .FromJust()); 20067 obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"), 20068 v8::ReadOnly) 20069 .FromJust(); 20070 obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust(); 20071 CHECK(v8_str("DONT_CHANGE") 20072 ->Equals(context.local(), 20073 obj->Get(context.local(), v8_num(2)).ToLocalChecked()) 20074 .FromJust()); 20075 20076 // Test non-smi case. 20077 obj->DefineOwnProperty(context.local(), v8_str("2000000000"), 20078 v8_str("DONT_CHANGE"), v8::ReadOnly) 20079 .FromJust(); 20080 obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust(); 20081 CHECK(v8_str("DONT_CHANGE") 20082 ->Equals(context.local(), 20083 obj->Get(context.local(), v8_str("2000000000")) 20084 .ToLocalChecked()) 20085 .FromJust()); 20086 } 20087 20088 20089 static int CountLiveMapsInMapCache(i::Context* context) { 20090 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache()); 20091 int length = map_cache->length(); 20092 int count = 0; 20093 for (int i = 0; i < length; i++) { 20094 i::Object* value = map_cache->get(i); 20095 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++; 20096 } 20097 return count; 20098 } 20099 20100 20101 THREADED_TEST(Regress1516) { 20102 LocalContext context; 20103 v8::HandleScope scope(context->GetIsolate()); 20104 20105 // Object with 20 properties is not a common case, so it should be removed 20106 // from the cache after GC. 20107 { v8::HandleScope temp_scope(context->GetIsolate()); 20108 CompileRun( 20109 "({" 20110 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, " 20111 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, " 20112 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, " 20113 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, " 20114 "})"); 20115 } 20116 20117 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context()); 20118 CHECK_LE(1, elements); 20119 20120 CcTest::heap()->CollectAllGarbage(); 20121 20122 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context())); 20123 } 20124 20125 20126 THREADED_TEST(Regress93759) { 20127 v8::Isolate* isolate = CcTest::isolate(); 20128 HandleScope scope(isolate); 20129 20130 // Template for object with security check. 20131 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate); 20132 no_proto_template->SetAccessCheckCallback(AccessAlwaysBlocked); 20133 20134 // Templates for objects with hidden prototypes and possibly security check. 20135 Local<FunctionTemplate> hidden_proto_template = 20136 v8::FunctionTemplate::New(isolate); 20137 hidden_proto_template->SetHiddenPrototype(true); 20138 20139 Local<FunctionTemplate> protected_hidden_proto_template = 20140 v8::FunctionTemplate::New(isolate); 20141 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallback( 20142 AccessAlwaysBlocked); 20143 protected_hidden_proto_template->SetHiddenPrototype(true); 20144 20145 // Context for "foreign" objects used in test. 20146 Local<Context> context = v8::Context::New(isolate); 20147 context->Enter(); 20148 20149 // Plain object, no security check. 20150 Local<Object> simple_object = Object::New(isolate); 20151 20152 // Object with explicit security check. 20153 Local<Object> protected_object = 20154 no_proto_template->NewInstance(context).ToLocalChecked(); 20155 20156 // JSGlobalProxy object, always have security check. 20157 Local<Object> proxy_object = context->Global(); 20158 20159 // Global object, the prototype of proxy_object. No security checks. 20160 Local<Object> global_object = 20161 proxy_object->GetPrototype()->ToObject(context).ToLocalChecked(); 20162 20163 // Hidden prototype without security check. 20164 Local<Object> hidden_prototype = hidden_proto_template->GetFunction(context) 20165 .ToLocalChecked() 20166 ->NewInstance(context) 20167 .ToLocalChecked(); 20168 Local<Object> object_with_hidden = 20169 Object::New(isolate); 20170 object_with_hidden->SetPrototype(context, hidden_prototype).FromJust(); 20171 20172 context->Exit(); 20173 20174 // Template for object for second context. Values to test are put on it as 20175 // properties. 20176 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 20177 global_template->Set(v8_str("simple"), simple_object); 20178 global_template->Set(v8_str("protected"), protected_object); 20179 global_template->Set(v8_str("global"), global_object); 20180 global_template->Set(v8_str("proxy"), proxy_object); 20181 global_template->Set(v8_str("hidden"), object_with_hidden); 20182 20183 LocalContext context2(NULL, global_template); 20184 20185 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 20186 CHECK(result1->Equals(context2.local(), simple_object->GetPrototype()) 20187 .FromJust()); 20188 20189 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 20190 CHECK(result2->IsNull()); 20191 20192 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 20193 CHECK(result3->Equals(context2.local(), global_object->GetPrototype()) 20194 .FromJust()); 20195 20196 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 20197 CHECK(result4->IsNull()); 20198 20199 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 20200 CHECK(result5->Equals(context2.local(), object_with_hidden->GetPrototype() 20201 ->ToObject(context2.local()) 20202 .ToLocalChecked() 20203 ->GetPrototype()) 20204 .FromJust()); 20205 } 20206 20207 20208 static void TestReceiver(Local<Value> expected_result, 20209 Local<Value> expected_receiver, 20210 const char* code) { 20211 Local<Value> result = CompileRun(code); 20212 Local<Context> context = CcTest::isolate()->GetCurrentContext(); 20213 CHECK(result->IsObject()); 20214 CHECK(expected_receiver 20215 ->Equals(context, 20216 result.As<v8::Object>()->Get(context, 1).ToLocalChecked()) 20217 .FromJust()); 20218 CHECK(expected_result 20219 ->Equals(context, 20220 result.As<v8::Object>()->Get(context, 0).ToLocalChecked()) 20221 .FromJust()); 20222 } 20223 20224 20225 THREADED_TEST(ForeignFunctionReceiver) { 20226 v8::Isolate* isolate = CcTest::isolate(); 20227 HandleScope scope(isolate); 20228 20229 // Create two contexts with different "id" properties ('i' and 'o'). 20230 // Call a function both from its own context and from a the foreign 20231 // context, and see what "this" is bound to (returning both "this" 20232 // and "this.id" for comparison). 20233 20234 Local<Context> foreign_context = v8::Context::New(isolate); 20235 foreign_context->Enter(); 20236 Local<Value> foreign_function = 20237 CompileRun("function func() { return { 0: this.id, " 20238 " 1: this, " 20239 " toString: function() { " 20240 " return this[0];" 20241 " }" 20242 " };" 20243 "}" 20244 "var id = 'i';" 20245 "func;"); 20246 CHECK(foreign_function->IsFunction()); 20247 foreign_context->Exit(); 20248 20249 LocalContext context; 20250 20251 Local<String> password = v8_str("Password"); 20252 // Don't get hit by security checks when accessing foreign_context's 20253 // global receiver (aka. global proxy). 20254 context->SetSecurityToken(password); 20255 foreign_context->SetSecurityToken(password); 20256 20257 Local<String> i = v8_str("i"); 20258 Local<String> o = v8_str("o"); 20259 Local<String> id = v8_str("id"); 20260 20261 CompileRun("function ownfunc() { return { 0: this.id, " 20262 " 1: this, " 20263 " toString: function() { " 20264 " return this[0];" 20265 " }" 20266 " };" 20267 "}" 20268 "var id = 'o';" 20269 "ownfunc"); 20270 CHECK(context->Global() 20271 ->Set(context.local(), v8_str("func"), foreign_function) 20272 .FromJust()); 20273 20274 // Sanity check the contexts. 20275 CHECK( 20276 i->Equals( 20277 context.local(), 20278 foreign_context->Global()->Get(context.local(), id).ToLocalChecked()) 20279 .FromJust()); 20280 CHECK(o->Equals(context.local(), 20281 context->Global()->Get(context.local(), id).ToLocalChecked()) 20282 .FromJust()); 20283 20284 // Checking local function's receiver. 20285 // Calling function using its call/apply methods. 20286 TestReceiver(o, context->Global(), "ownfunc.call()"); 20287 TestReceiver(o, context->Global(), "ownfunc.apply()"); 20288 // Making calls through built-in functions. 20289 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 20290 CHECK( 20291 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")) 20292 .FromJust()); 20293 CHECK( 20294 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")) 20295 .FromJust()); 20296 CHECK( 20297 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")) 20298 .FromJust()); 20299 // Calling with environment record as base. 20300 TestReceiver(o, context->Global(), "ownfunc()"); 20301 // Calling with no base. 20302 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 20303 20304 // Checking foreign function return value. 20305 // Calling function using its call/apply methods. 20306 TestReceiver(i, foreign_context->Global(), "func.call()"); 20307 TestReceiver(i, foreign_context->Global(), "func.apply()"); 20308 // Calling function using another context's call/apply methods. 20309 TestReceiver(i, foreign_context->Global(), 20310 "Function.prototype.call.call(func)"); 20311 TestReceiver(i, foreign_context->Global(), 20312 "Function.prototype.call.apply(func)"); 20313 TestReceiver(i, foreign_context->Global(), 20314 "Function.prototype.apply.call(func)"); 20315 TestReceiver(i, foreign_context->Global(), 20316 "Function.prototype.apply.apply(func)"); 20317 // Making calls through built-in functions. 20318 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 20319 // ToString(func()) is func()[0], i.e., the returned this.id. 20320 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]")) 20321 .FromJust()); 20322 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]")) 20323 .FromJust()); 20324 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]")) 20325 .FromJust()); 20326 20327 // Calling with environment record as base. 20328 TestReceiver(i, foreign_context->Global(), "func()"); 20329 // Calling with no base. 20330 TestReceiver(i, foreign_context->Global(), "(1,func)()"); 20331 } 20332 20333 20334 uint8_t callback_fired = 0; 20335 20336 20337 void CallCompletedCallback1() { 20338 v8::base::OS::Print("Firing callback 1.\n"); 20339 callback_fired ^= 1; // Toggle first bit. 20340 } 20341 20342 20343 void CallCompletedCallback2() { 20344 v8::base::OS::Print("Firing callback 2.\n"); 20345 callback_fired ^= 2; // Toggle second bit. 20346 } 20347 20348 20349 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 20350 int32_t level = 20351 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust(); 20352 if (level < 3) { 20353 level++; 20354 v8::base::OS::Print("Entering recursion level %d.\n", level); 20355 char script[64]; 20356 i::Vector<char> script_vector(script, sizeof(script)); 20357 i::SNPrintF(script_vector, "recursion(%d)", level); 20358 CompileRun(script_vector.start()); 20359 v8::base::OS::Print("Leaving recursion level %d.\n", level); 20360 CHECK_EQ(0, callback_fired); 20361 } else { 20362 v8::base::OS::Print("Recursion ends.\n"); 20363 CHECK_EQ(0, callback_fired); 20364 } 20365 } 20366 20367 20368 TEST(CallCompletedCallback) { 20369 LocalContext env; 20370 v8::HandleScope scope(env->GetIsolate()); 20371 v8::Local<v8::FunctionTemplate> recursive_runtime = 20372 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall); 20373 env->Global() 20374 ->Set(env.local(), v8_str("recursion"), 20375 recursive_runtime->GetFunction(env.local()).ToLocalChecked()) 20376 .FromJust(); 20377 // Adding the same callback a second time has no effect. 20378 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20379 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20380 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); 20381 v8::base::OS::Print("--- Script (1) ---\n"); 20382 Local<Script> script = 20383 v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked(); 20384 script->Run(env.local()).ToLocalChecked(); 20385 CHECK_EQ(3, callback_fired); 20386 20387 v8::base::OS::Print("\n--- Script (2) ---\n"); 20388 callback_fired = 0; 20389 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); 20390 script->Run(env.local()).ToLocalChecked(); 20391 CHECK_EQ(2, callback_fired); 20392 20393 v8::base::OS::Print("\n--- Function ---\n"); 20394 callback_fired = 0; 20395 Local<Function> recursive_function = Local<Function>::Cast( 20396 env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked()); 20397 v8::Local<Value> args[] = {v8_num(0)}; 20398 recursive_function->Call(env.local(), env->Global(), 1, args) 20399 .ToLocalChecked(); 20400 CHECK_EQ(2, callback_fired); 20401 } 20402 20403 20404 void CallCompletedCallbackNoException() { 20405 v8::HandleScope scope(CcTest::isolate()); 20406 CompileRun("1+1;"); 20407 } 20408 20409 20410 void CallCompletedCallbackException() { 20411 v8::HandleScope scope(CcTest::isolate()); 20412 CompileRun("throw 'second exception';"); 20413 } 20414 20415 20416 TEST(CallCompletedCallbackOneException) { 20417 LocalContext env; 20418 v8::HandleScope scope(env->GetIsolate()); 20419 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException); 20420 CompileRun("throw 'exception';"); 20421 } 20422 20423 20424 TEST(CallCompletedCallbackTwoExceptions) { 20425 LocalContext env; 20426 v8::HandleScope scope(env->GetIsolate()); 20427 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException); 20428 CompileRun("throw 'first exception';"); 20429 } 20430 20431 20432 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) { 20433 v8::HandleScope scope(info.GetIsolate()); 20434 CompileRun("ext1Calls++;"); 20435 } 20436 20437 20438 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) { 20439 v8::HandleScope scope(info.GetIsolate()); 20440 CompileRun("ext2Calls++;"); 20441 } 20442 20443 20444 void* g_passed_to_three = NULL; 20445 20446 20447 static void MicrotaskThree(void* data) { 20448 g_passed_to_three = data; 20449 } 20450 20451 20452 TEST(EnqueueMicrotask) { 20453 LocalContext env; 20454 v8::HandleScope scope(env->GetIsolate()); 20455 CompileRun( 20456 "var ext1Calls = 0;" 20457 "var ext2Calls = 0;"); 20458 CompileRun("1+1;"); 20459 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20460 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20461 20462 env->GetIsolate()->EnqueueMicrotask( 20463 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 20464 CompileRun("1+1;"); 20465 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20466 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20467 20468 env->GetIsolate()->EnqueueMicrotask( 20469 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 20470 env->GetIsolate()->EnqueueMicrotask( 20471 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20472 CompileRun("1+1;"); 20473 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20474 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20475 20476 env->GetIsolate()->EnqueueMicrotask( 20477 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20478 CompileRun("1+1;"); 20479 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20480 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20481 20482 CompileRun("1+1;"); 20483 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20484 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20485 20486 g_passed_to_three = NULL; 20487 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree); 20488 CompileRun("1+1;"); 20489 CHECK(!g_passed_to_three); 20490 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20491 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20492 20493 int dummy; 20494 env->GetIsolate()->EnqueueMicrotask( 20495 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 20496 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy); 20497 env->GetIsolate()->EnqueueMicrotask( 20498 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20499 CompileRun("1+1;"); 20500 CHECK_EQ(&dummy, g_passed_to_three); 20501 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20502 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20503 g_passed_to_three = NULL; 20504 } 20505 20506 20507 static void MicrotaskExceptionOne( 20508 const v8::FunctionCallbackInfo<Value>& info) { 20509 v8::HandleScope scope(info.GetIsolate()); 20510 CompileRun("exception1Calls++;"); 20511 info.GetIsolate()->ThrowException( 20512 v8::Exception::Error(v8_str("first"))); 20513 } 20514 20515 20516 static void MicrotaskExceptionTwo( 20517 const v8::FunctionCallbackInfo<Value>& info) { 20518 v8::HandleScope scope(info.GetIsolate()); 20519 CompileRun("exception2Calls++;"); 20520 info.GetIsolate()->ThrowException( 20521 v8::Exception::Error(v8_str("second"))); 20522 } 20523 20524 20525 TEST(RunMicrotasksIgnoresThrownExceptions) { 20526 LocalContext env; 20527 v8::Isolate* isolate = env->GetIsolate(); 20528 v8::HandleScope scope(isolate); 20529 CompileRun( 20530 "var exception1Calls = 0;" 20531 "var exception2Calls = 0;"); 20532 isolate->EnqueueMicrotask( 20533 Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked()); 20534 isolate->EnqueueMicrotask( 20535 Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked()); 20536 TryCatch try_catch(isolate); 20537 CompileRun("1+1;"); 20538 CHECK(!try_catch.HasCaught()); 20539 CHECK_EQ(1, 20540 CompileRun("exception1Calls")->Int32Value(env.local()).FromJust()); 20541 CHECK_EQ(1, 20542 CompileRun("exception2Calls")->Int32Value(env.local()).FromJust()); 20543 } 20544 20545 20546 TEST(SetAutorunMicrotasks) { 20547 LocalContext env; 20548 v8::HandleScope scope(env->GetIsolate()); 20549 CompileRun( 20550 "var ext1Calls = 0;" 20551 "var ext2Calls = 0;"); 20552 CompileRun("1+1;"); 20553 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20554 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20555 20556 env->GetIsolate()->EnqueueMicrotask( 20557 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 20558 CompileRun("1+1;"); 20559 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20560 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20561 20562 env->GetIsolate()->SetAutorunMicrotasks(false); 20563 env->GetIsolate()->EnqueueMicrotask( 20564 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 20565 env->GetIsolate()->EnqueueMicrotask( 20566 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20567 CompileRun("1+1;"); 20568 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20569 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20570 20571 env->GetIsolate()->RunMicrotasks(); 20572 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20573 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20574 20575 env->GetIsolate()->EnqueueMicrotask( 20576 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20577 CompileRun("1+1;"); 20578 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20579 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20580 20581 env->GetIsolate()->RunMicrotasks(); 20582 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20583 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20584 20585 env->GetIsolate()->SetAutorunMicrotasks(true); 20586 env->GetIsolate()->EnqueueMicrotask( 20587 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20588 CompileRun("1+1;"); 20589 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20590 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20591 20592 env->GetIsolate()->EnqueueMicrotask( 20593 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 20594 { 20595 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate()); 20596 CompileRun("1+1;"); 20597 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20598 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20599 } 20600 20601 CompileRun("1+1;"); 20602 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 20603 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 20604 } 20605 20606 20607 TEST(RunMicrotasksWithoutEnteringContext) { 20608 v8::Isolate* isolate = CcTest::isolate(); 20609 HandleScope handle_scope(isolate); 20610 isolate->SetAutorunMicrotasks(false); 20611 Local<Context> context = Context::New(isolate); 20612 { 20613 Context::Scope context_scope(context); 20614 CompileRun("var ext1Calls = 0;"); 20615 isolate->EnqueueMicrotask( 20616 Function::New(context, MicrotaskOne).ToLocalChecked()); 20617 } 20618 isolate->RunMicrotasks(); 20619 { 20620 Context::Scope context_scope(context); 20621 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust()); 20622 } 20623 isolate->SetAutorunMicrotasks(true); 20624 } 20625 20626 20627 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) { 20628 v8::DebugEvent event = event_details.GetEvent(); 20629 if (event != v8::Break) return; 20630 Local<Object> exec_state = event_details.GetExecutionState(); 20631 Local<Context> context = CcTest::isolate()->GetCurrentContext(); 20632 Local<Value> break_id = 20633 exec_state->Get(context, v8_str("break_id")).ToLocalChecked(); 20634 CompileRun("function f(id) { new FrameDetails(id, 0); }"); 20635 Local<Function> fun = Local<Function>::Cast( 20636 CcTest::global()->Get(context, v8_str("f")).ToLocalChecked()); 20637 fun->Call(context, CcTest::global(), 1, &break_id).ToLocalChecked(); 20638 } 20639 20640 20641 TEST(Regress385349) { 20642 i::FLAG_harmony_object_observe = true; 20643 i::FLAG_allow_natives_syntax = true; 20644 v8::Isolate* isolate = CcTest::isolate(); 20645 HandleScope handle_scope(isolate); 20646 isolate->SetAutorunMicrotasks(false); 20647 Local<Context> context = Context::New(isolate); 20648 v8::Debug::SetDebugEventListener(isolate, DebugEventInObserver); 20649 { 20650 Context::Scope context_scope(context); 20651 CompileRun("var obj = {};" 20652 "Object.observe(obj, function(changes) { debugger; });" 20653 "obj.a = 0;"); 20654 } 20655 isolate->RunMicrotasks(); 20656 isolate->SetAutorunMicrotasks(true); 20657 v8::Debug::SetDebugEventListener(isolate, nullptr); 20658 } 20659 20660 20661 #ifdef ENABLE_DISASSEMBLER 20662 static int probes_counter = 0; 20663 static int misses_counter = 0; 20664 static int updates_counter = 0; 20665 20666 20667 static int* LookupCounter(const char* name) { 20668 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 20669 return &probes_counter; 20670 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 20671 return &misses_counter; 20672 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 20673 return &updates_counter; 20674 } 20675 return NULL; 20676 } 20677 20678 20679 static const char* kMegamorphicTestProgram = 20680 "function ClassA() { };" 20681 "function ClassB() { };" 20682 "ClassA.prototype.foo = function() { };" 20683 "ClassB.prototype.foo = function() { };" 20684 "function fooify(obj) { obj.foo(); };" 20685 "var a = new ClassA();" 20686 "var b = new ClassB();" 20687 "for (var i = 0; i < 10000; i++) {" 20688 " fooify(a);" 20689 " fooify(b);" 20690 "}"; 20691 #endif 20692 20693 20694 static void StubCacheHelper(bool primary) { 20695 #ifdef ENABLE_DISASSEMBLER 20696 i::FLAG_native_code_counters = true; 20697 if (primary) { 20698 i::FLAG_test_primary_stub_cache = true; 20699 } else { 20700 i::FLAG_test_secondary_stub_cache = true; 20701 } 20702 i::FLAG_crankshaft = false; 20703 LocalContext env; 20704 env->GetIsolate()->SetCounterFunction(LookupCounter); 20705 v8::HandleScope scope(env->GetIsolate()); 20706 int initial_probes = probes_counter; 20707 int initial_misses = misses_counter; 20708 int initial_updates = updates_counter; 20709 CompileRun(kMegamorphicTestProgram); 20710 int probes = probes_counter - initial_probes; 20711 int misses = misses_counter - initial_misses; 20712 int updates = updates_counter - initial_updates; 20713 CHECK_LT(updates, 10); 20714 CHECK_LT(misses, 10); 20715 // TODO(verwaest): Update this test to overflow the degree of polymorphism 20716 // before megamorphism. The number of probes will only work once we teach the 20717 // serializer to embed references to counters in the stubs, given that the 20718 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub. 20719 CHECK_GE(probes, 0); 20720 #endif 20721 } 20722 20723 20724 TEST(SecondaryStubCache) { 20725 StubCacheHelper(true); 20726 } 20727 20728 20729 TEST(PrimaryStubCache) { 20730 StubCacheHelper(false); 20731 } 20732 20733 20734 #ifdef DEBUG 20735 static int cow_arrays_created_runtime = 0; 20736 20737 20738 static int* LookupCounterCOWArrays(const char* name) { 20739 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) { 20740 return &cow_arrays_created_runtime; 20741 } 20742 return NULL; 20743 } 20744 #endif 20745 20746 20747 TEST(CheckCOWArraysCreatedRuntimeCounter) { 20748 #ifdef DEBUG 20749 i::FLAG_native_code_counters = true; 20750 LocalContext env; 20751 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays); 20752 v8::HandleScope scope(env->GetIsolate()); 20753 int initial_cow_arrays = cow_arrays_created_runtime; 20754 CompileRun("var o = [1, 2, 3];"); 20755 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays); 20756 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};"); 20757 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays); 20758 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};"); 20759 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays); 20760 #endif 20761 } 20762 20763 20764 TEST(StaticGetters) { 20765 LocalContext context; 20766 i::Factory* factory = CcTest::i_isolate()->factory(); 20767 v8::Isolate* isolate = CcTest::isolate(); 20768 v8::HandleScope scope(isolate); 20769 i::Handle<i::Object> undefined_value = factory->undefined_value(); 20770 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 20771 i::Handle<i::Object> null_value = factory->null_value(); 20772 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 20773 i::Handle<i::Object> true_value = factory->true_value(); 20774 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 20775 i::Handle<i::Object> false_value = factory->false_value(); 20776 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 20777 } 20778 20779 20780 UNINITIALIZED_TEST(IsolateEmbedderData) { 20781 CcTest::DisableAutomaticDispose(); 20782 v8::Isolate::CreateParams create_params; 20783 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 20784 v8::Isolate* isolate = v8::Isolate::New(create_params); 20785 isolate->Enter(); 20786 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 20787 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20788 CHECK(!isolate->GetData(slot)); 20789 CHECK(!i_isolate->GetData(slot)); 20790 } 20791 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20792 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 20793 isolate->SetData(slot, data); 20794 } 20795 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20796 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 20797 CHECK_EQ(data, isolate->GetData(slot)); 20798 CHECK_EQ(data, i_isolate->GetData(slot)); 20799 } 20800 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20801 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 20802 isolate->SetData(slot, data); 20803 } 20804 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20805 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 20806 CHECK_EQ(data, isolate->GetData(slot)); 20807 CHECK_EQ(data, i_isolate->GetData(slot)); 20808 } 20809 isolate->Exit(); 20810 isolate->Dispose(); 20811 } 20812 20813 20814 TEST(StringEmpty) { 20815 LocalContext context; 20816 i::Factory* factory = CcTest::i_isolate()->factory(); 20817 v8::Isolate* isolate = CcTest::isolate(); 20818 v8::HandleScope scope(isolate); 20819 i::Handle<i::Object> empty_string = factory->empty_string(); 20820 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 20821 } 20822 20823 20824 static int instance_checked_getter_count = 0; 20825 static void InstanceCheckedGetter( 20826 Local<String> name, 20827 const v8::PropertyCallbackInfo<v8::Value>& info) { 20828 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 20829 .FromJust()); 20830 instance_checked_getter_count++; 20831 info.GetReturnValue().Set(v8_num(11)); 20832 } 20833 20834 20835 static int instance_checked_setter_count = 0; 20836 static void InstanceCheckedSetter(Local<String> name, 20837 Local<Value> value, 20838 const v8::PropertyCallbackInfo<void>& info) { 20839 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 20840 .FromJust()); 20841 CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23)) 20842 .FromJust()); 20843 instance_checked_setter_count++; 20844 } 20845 20846 20847 static void CheckInstanceCheckedResult(int getters, int setters, 20848 bool expects_callbacks, 20849 TryCatch* try_catch) { 20850 if (expects_callbacks) { 20851 CHECK(!try_catch->HasCaught()); 20852 CHECK_EQ(getters, instance_checked_getter_count); 20853 CHECK_EQ(setters, instance_checked_setter_count); 20854 } else { 20855 CHECK(try_catch->HasCaught()); 20856 CHECK_EQ(0, instance_checked_getter_count); 20857 CHECK_EQ(0, instance_checked_setter_count); 20858 } 20859 try_catch->Reset(); 20860 } 20861 20862 20863 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 20864 instance_checked_getter_count = 0; 20865 instance_checked_setter_count = 0; 20866 TryCatch try_catch(CcTest::isolate()); 20867 20868 // Test path through generic runtime code. 20869 CompileRun("obj.foo"); 20870 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 20871 CompileRun("obj.foo = 23"); 20872 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 20873 20874 // Test path through generated LoadIC and StoredIC. 20875 CompileRun("function test_get(o) { o.foo; }" 20876 "test_get(obj);"); 20877 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 20878 CompileRun("test_get(obj);"); 20879 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 20880 CompileRun("test_get(obj);"); 20881 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 20882 CompileRun("function test_set(o) { o.foo = 23; }" 20883 "test_set(obj);"); 20884 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 20885 CompileRun("test_set(obj);"); 20886 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 20887 CompileRun("test_set(obj);"); 20888 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 20889 20890 // Test path through optimized code. 20891 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 20892 "test_get(obj);"); 20893 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 20894 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 20895 "test_set(obj);"); 20896 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 20897 20898 // Cleanup so that closures start out fresh in next check. 20899 CompileRun("%DeoptimizeFunction(test_get);" 20900 "%ClearFunctionTypeFeedback(test_get);" 20901 "%DeoptimizeFunction(test_set);" 20902 "%ClearFunctionTypeFeedback(test_set);"); 20903 } 20904 20905 20906 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 20907 v8::internal::FLAG_allow_natives_syntax = true; 20908 LocalContext context; 20909 v8::HandleScope scope(context->GetIsolate()); 20910 20911 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 20912 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 20913 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter, 20914 Local<Value>(), v8::DEFAULT, v8::None, 20915 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20916 CHECK(context->Global() 20917 ->Set(context.local(), v8_str("f"), 20918 templ->GetFunction(context.local()).ToLocalChecked()) 20919 .FromJust()); 20920 20921 printf("Testing positive ...\n"); 20922 CompileRun("var obj = new f();"); 20923 CHECK(templ->HasInstance( 20924 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 20925 CheckInstanceCheckedAccessors(true); 20926 20927 printf("Testing negative ...\n"); 20928 CompileRun("var obj = {};" 20929 "obj.__proto__ = new f();"); 20930 CHECK(!templ->HasInstance( 20931 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 20932 CheckInstanceCheckedAccessors(false); 20933 } 20934 20935 20936 static void EmptyInterceptorGetter( 20937 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {} 20938 20939 20940 static void EmptyInterceptorSetter( 20941 Local<String> name, Local<Value> value, 20942 const v8::PropertyCallbackInfo<v8::Value>& info) {} 20943 20944 20945 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 20946 v8::internal::FLAG_allow_natives_syntax = true; 20947 LocalContext context; 20948 v8::HandleScope scope(context->GetIsolate()); 20949 20950 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 20951 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 20952 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter, 20953 EmptyInterceptorSetter); 20954 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter, 20955 Local<Value>(), v8::DEFAULT, v8::None, 20956 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20957 CHECK(context->Global() 20958 ->Set(context.local(), v8_str("f"), 20959 templ->GetFunction(context.local()).ToLocalChecked()) 20960 .FromJust()); 20961 20962 printf("Testing positive ...\n"); 20963 CompileRun("var obj = new f();"); 20964 CHECK(templ->HasInstance( 20965 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 20966 CheckInstanceCheckedAccessors(true); 20967 20968 printf("Testing negative ...\n"); 20969 CompileRun("var obj = {};" 20970 "obj.__proto__ = new f();"); 20971 CHECK(!templ->HasInstance( 20972 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 20973 CheckInstanceCheckedAccessors(false); 20974 } 20975 20976 20977 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 20978 v8::internal::FLAG_allow_natives_syntax = true; 20979 LocalContext context; 20980 v8::HandleScope scope(context->GetIsolate()); 20981 20982 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 20983 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 20984 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter, 20985 InstanceCheckedSetter, Local<Value>(), v8::DEFAULT, 20986 v8::None, 20987 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20988 CHECK(context->Global() 20989 ->Set(context.local(), v8_str("f"), 20990 templ->GetFunction(context.local()).ToLocalChecked()) 20991 .FromJust()); 20992 20993 printf("Testing positive ...\n"); 20994 CompileRun("var obj = new f();"); 20995 CHECK(templ->HasInstance( 20996 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 20997 CheckInstanceCheckedAccessors(true); 20998 20999 printf("Testing negative ...\n"); 21000 CompileRun("var obj = {};" 21001 "obj.__proto__ = new f();"); 21002 CHECK(!templ->HasInstance( 21003 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21004 CheckInstanceCheckedAccessors(false); 21005 21006 printf("Testing positive with modified prototype chain ...\n"); 21007 CompileRun("var obj = new f();" 21008 "var pro = {};" 21009 "pro.__proto__ = obj.__proto__;" 21010 "obj.__proto__ = pro;"); 21011 CHECK(templ->HasInstance( 21012 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21013 CheckInstanceCheckedAccessors(true); 21014 } 21015 21016 21017 TEST(TryFinallyMessage) { 21018 LocalContext context; 21019 v8::HandleScope scope(context->GetIsolate()); 21020 { 21021 // Test that the original error message is not lost if there is a 21022 // recursive call into Javascript is done in the finally block, e.g. to 21023 // initialize an IC. (crbug.com/129171) 21024 TryCatch try_catch(context->GetIsolate()); 21025 const char* trigger_ic = 21026 "try { \n" 21027 " throw new Error('test'); \n" 21028 "} finally { \n" 21029 " var x = 0; \n" 21030 " x++; \n" // Trigger an IC initialization here. 21031 "} \n"; 21032 CompileRun(trigger_ic); 21033 CHECK(try_catch.HasCaught()); 21034 Local<Message> message = try_catch.Message(); 21035 CHECK(!message.IsEmpty()); 21036 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 21037 } 21038 21039 { 21040 // Test that the original exception message is indeed overwritten if 21041 // a new error is thrown in the finally block. 21042 TryCatch try_catch(context->GetIsolate()); 21043 const char* throw_again = 21044 "try { \n" 21045 " throw new Error('test'); \n" 21046 "} finally { \n" 21047 " var x = 0; \n" 21048 " x++; \n" 21049 " throw new Error('again'); \n" // This is the new uncaught error. 21050 "} \n"; 21051 CompileRun(throw_again); 21052 CHECK(try_catch.HasCaught()); 21053 Local<Message> message = try_catch.Message(); 21054 CHECK(!message.IsEmpty()); 21055 CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust()); 21056 } 21057 } 21058 21059 21060 static void Helper137002(bool do_store, 21061 bool polymorphic, 21062 bool remove_accessor, 21063 bool interceptor) { 21064 LocalContext context; 21065 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate()); 21066 if (interceptor) { 21067 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor, 21068 FooSetInterceptor)); 21069 } else { 21070 templ->SetAccessor(v8_str("foo"), 21071 GetterWhichReturns42, 21072 SetterWhichSetsYOnThisTo23); 21073 } 21074 CHECK(context->Global() 21075 ->Set(context.local(), v8_str("obj"), 21076 templ->NewInstance(context.local()).ToLocalChecked()) 21077 .FromJust()); 21078 21079 // Turn monomorphic on slow object with native accessor, then turn 21080 // polymorphic, finally optimize to create negative lookup and fail. 21081 CompileRun(do_store ? 21082 "function f(x) { x.foo = void 0; }" : 21083 "function f(x) { return x.foo; }"); 21084 CompileRun("obj.y = void 0;"); 21085 if (!interceptor) { 21086 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 21087 } 21088 CompileRun("obj.__proto__ = null;" 21089 "f(obj); f(obj); f(obj);"); 21090 if (polymorphic) { 21091 CompileRun("f({});"); 21092 } 21093 CompileRun("obj.y = void 0;" 21094 "%OptimizeFunctionOnNextCall(f);"); 21095 if (remove_accessor) { 21096 CompileRun("delete obj.foo;"); 21097 } 21098 CompileRun("var result = f(obj);"); 21099 if (do_store) { 21100 CompileRun("result = obj.y;"); 21101 } 21102 if (remove_accessor && !interceptor) { 21103 CHECK(context->Global() 21104 ->Get(context.local(), v8_str("result")) 21105 .ToLocalChecked() 21106 ->IsUndefined()); 21107 } else { 21108 CHECK_EQ(do_store ? 23 : 42, context->Global() 21109 ->Get(context.local(), v8_str("result")) 21110 .ToLocalChecked() 21111 ->Int32Value(context.local()) 21112 .FromJust()); 21113 } 21114 } 21115 21116 21117 THREADED_TEST(Regress137002a) { 21118 i::FLAG_allow_natives_syntax = true; 21119 i::FLAG_compilation_cache = false; 21120 v8::HandleScope scope(CcTest::isolate()); 21121 for (int i = 0; i < 16; i++) { 21122 Helper137002(i & 8, i & 4, i & 2, i & 1); 21123 } 21124 } 21125 21126 21127 THREADED_TEST(Regress137002b) { 21128 i::FLAG_allow_natives_syntax = true; 21129 LocalContext context; 21130 v8::Isolate* isolate = context->GetIsolate(); 21131 v8::HandleScope scope(isolate); 21132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21133 templ->SetAccessor(v8_str("foo"), 21134 GetterWhichReturns42, 21135 SetterWhichSetsYOnThisTo23); 21136 CHECK(context->Global() 21137 ->Set(context.local(), v8_str("obj"), 21138 templ->NewInstance(context.local()).ToLocalChecked()) 21139 .FromJust()); 21140 21141 // Turn monomorphic on slow object with native accessor, then just 21142 // delete the property and fail. 21143 CompileRun("function load(x) { return x.foo; }" 21144 "function store(x) { x.foo = void 0; }" 21145 "function keyed_load(x, key) { return x[key]; }" 21146 // Second version of function has a different source (add void 0) 21147 // so that it does not share code with the first version. This 21148 // ensures that the ICs are monomorphic. 21149 "function load2(x) { void 0; return x.foo; }" 21150 "function store2(x) { void 0; x.foo = void 0; }" 21151 "function keyed_load2(x, key) { void 0; return x[key]; }" 21152 21153 "obj.y = void 0;" 21154 "obj.__proto__ = null;" 21155 "var subobj = {};" 21156 "subobj.y = void 0;" 21157 "subobj.__proto__ = obj;" 21158 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21159 21160 // Make the ICs monomorphic. 21161 "load(obj); load(obj);" 21162 "load2(subobj); load2(subobj);" 21163 "store(obj); store(obj);" 21164 "store2(subobj); store2(subobj);" 21165 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 21166 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 21167 21168 // Actually test the shiny new ICs and better not crash. This 21169 // serves as a regression test for issue 142088 as well. 21170 "load(obj);" 21171 "load2(subobj);" 21172 "store(obj);" 21173 "store2(subobj);" 21174 "keyed_load(obj, 'foo');" 21175 "keyed_load2(subobj, 'foo');" 21176 21177 // Delete the accessor. It better not be called any more now. 21178 "delete obj.foo;" 21179 "obj.y = void 0;" 21180 "subobj.y = void 0;" 21181 21182 "var load_result = load(obj);" 21183 "var load_result2 = load2(subobj);" 21184 "var keyed_load_result = keyed_load(obj, 'foo');" 21185 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 21186 "store(obj);" 21187 "store2(subobj);" 21188 "var y_from_obj = obj.y;" 21189 "var y_from_subobj = subobj.y;"); 21190 CHECK(context->Global() 21191 ->Get(context.local(), v8_str("load_result")) 21192 .ToLocalChecked() 21193 ->IsUndefined()); 21194 CHECK(context->Global() 21195 ->Get(context.local(), v8_str("load_result2")) 21196 .ToLocalChecked() 21197 ->IsUndefined()); 21198 CHECK(context->Global() 21199 ->Get(context.local(), v8_str("keyed_load_result")) 21200 .ToLocalChecked() 21201 ->IsUndefined()); 21202 CHECK(context->Global() 21203 ->Get(context.local(), v8_str("keyed_load_result2")) 21204 .ToLocalChecked() 21205 ->IsUndefined()); 21206 CHECK(context->Global() 21207 ->Get(context.local(), v8_str("y_from_obj")) 21208 .ToLocalChecked() 21209 ->IsUndefined()); 21210 CHECK(context->Global() 21211 ->Get(context.local(), v8_str("y_from_subobj")) 21212 .ToLocalChecked() 21213 ->IsUndefined()); 21214 } 21215 21216 21217 THREADED_TEST(Regress142088) { 21218 i::FLAG_allow_natives_syntax = true; 21219 LocalContext context; 21220 v8::Isolate* isolate = context->GetIsolate(); 21221 v8::HandleScope scope(isolate); 21222 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21223 templ->SetAccessor(v8_str("foo"), 21224 GetterWhichReturns42, 21225 SetterWhichSetsYOnThisTo23); 21226 CHECK(context->Global() 21227 ->Set(context.local(), v8_str("obj"), 21228 templ->NewInstance(context.local()).ToLocalChecked()) 21229 .FromJust()); 21230 21231 CompileRun("function load(x) { return x.foo; }" 21232 "var o = Object.create(obj);" 21233 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21234 "load(o); load(o); load(o); load(o);"); 21235 } 21236 21237 21238 THREADED_TEST(Regress137496) { 21239 i::FLAG_expose_gc = true; 21240 LocalContext context; 21241 v8::HandleScope scope(context->GetIsolate()); 21242 21243 // Compile a try-finally clause where the finally block causes a GC 21244 // while there still is a message pending for external reporting. 21245 TryCatch try_catch(context->GetIsolate()); 21246 try_catch.SetVerbose(true); 21247 CompileRun("try { throw new Error(); } finally { gc(); }"); 21248 CHECK(try_catch.HasCaught()); 21249 } 21250 21251 21252 THREADED_TEST(Regress157124) { 21253 LocalContext context; 21254 v8::Isolate* isolate = context->GetIsolate(); 21255 v8::HandleScope scope(isolate); 21256 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21257 Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked(); 21258 obj->GetIdentityHash(); 21259 obj->DeletePrivate(context.local(), 21260 v8::Private::ForApi(isolate, v8_str("Bug"))) 21261 .FromJust(); 21262 } 21263 21264 21265 THREADED_TEST(Regress2535) { 21266 LocalContext context; 21267 v8::HandleScope scope(context->GetIsolate()); 21268 Local<Value> set_value = CompileRun("new Set();"); 21269 Local<Object> set_object(Local<Object>::Cast(set_value)); 21270 CHECK_EQ(0, set_object->InternalFieldCount()); 21271 Local<Value> map_value = CompileRun("new Map();"); 21272 Local<Object> map_object(Local<Object>::Cast(map_value)); 21273 CHECK_EQ(0, map_object->InternalFieldCount()); 21274 } 21275 21276 21277 THREADED_TEST(Regress2746) { 21278 LocalContext context; 21279 v8::Isolate* isolate = context->GetIsolate(); 21280 v8::HandleScope scope(isolate); 21281 Local<Object> obj = Object::New(isolate); 21282 Local<v8::Private> key = v8::Private::New(isolate, v8_str("key")); 21283 CHECK( 21284 obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust()); 21285 Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked(); 21286 CHECK(!value.IsEmpty()); 21287 CHECK(value->IsUndefined()); 21288 } 21289 21290 21291 THREADED_TEST(Regress260106) { 21292 LocalContext context; 21293 v8::Isolate* isolate = context->GetIsolate(); 21294 v8::HandleScope scope(isolate); 21295 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, 21296 DummyCallHandler); 21297 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 21298 Local<Function> function = 21299 templ->GetFunction(context.local()).ToLocalChecked(); 21300 CHECK(!function.IsEmpty()); 21301 CHECK(function->IsFunction()); 21302 } 21303 21304 21305 THREADED_TEST(JSONParseObject) { 21306 LocalContext context; 21307 HandleScope scope(context->GetIsolate()); 21308 Local<Value> obj = 21309 v8::JSON::Parse(context->GetIsolate(), v8_str("{\"x\":42}")) 21310 .ToLocalChecked(); 21311 Local<Object> global = context->Global(); 21312 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 21313 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 21314 } 21315 21316 21317 THREADED_TEST(JSONParseNumber) { 21318 LocalContext context; 21319 HandleScope scope(context->GetIsolate()); 21320 Local<Value> obj = 21321 v8::JSON::Parse(context->GetIsolate(), v8_str("42")).ToLocalChecked(); 21322 Local<Object> global = context->Global(); 21323 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 21324 ExpectString("JSON.stringify(obj)", "42"); 21325 } 21326 21327 21328 #if V8_OS_POSIX && !V8_OS_NACL 21329 class ThreadInterruptTest { 21330 public: 21331 ThreadInterruptTest() : sem_(0), sem_value_(0) { } 21332 ~ThreadInterruptTest() {} 21333 21334 void RunTest() { 21335 InterruptThread i_thread(this); 21336 i_thread.Start(); 21337 21338 sem_.Wait(); 21339 CHECK_EQ(kExpectedValue, sem_value_); 21340 } 21341 21342 private: 21343 static const int kExpectedValue = 1; 21344 21345 class InterruptThread : public v8::base::Thread { 21346 public: 21347 explicit InterruptThread(ThreadInterruptTest* test) 21348 : Thread(Options("InterruptThread")), test_(test) {} 21349 21350 virtual void Run() { 21351 struct sigaction action; 21352 21353 // Ensure that we'll enter waiting condition 21354 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 21355 21356 // Setup signal handler 21357 memset(&action, 0, sizeof(action)); 21358 action.sa_handler = SignalHandler; 21359 sigaction(SIGCHLD, &action, NULL); 21360 21361 // Send signal 21362 kill(getpid(), SIGCHLD); 21363 21364 // Ensure that if wait has returned because of error 21365 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 21366 21367 // Set value and signal semaphore 21368 test_->sem_value_ = 1; 21369 test_->sem_.Signal(); 21370 } 21371 21372 static void SignalHandler(int signal) { 21373 } 21374 21375 private: 21376 ThreadInterruptTest* test_; 21377 }; 21378 21379 v8::base::Semaphore sem_; 21380 volatile int sem_value_; 21381 }; 21382 21383 21384 THREADED_TEST(SemaphoreInterruption) { 21385 ThreadInterruptTest().RunTest(); 21386 } 21387 21388 21389 #endif // V8_OS_POSIX 21390 21391 21392 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21393 CHECK(false); 21394 } 21395 21396 21397 TEST(JSONStringifyAccessCheck) { 21398 v8::V8::Initialize(); 21399 v8::Isolate* isolate = CcTest::isolate(); 21400 v8::HandleScope scope(isolate); 21401 21402 // Create an ObjectTemplate for global objects and install access 21403 // check callbacks that will block access. 21404 v8::Local<v8::ObjectTemplate> global_template = 21405 v8::ObjectTemplate::New(isolate); 21406 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 21407 21408 // Create a context and set an x property on it's global object. 21409 LocalContext context0(NULL, global_template); 21410 v8::Local<v8::Object> global0 = context0->Global(); 21411 global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust(); 21412 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 21413 21414 for (int i = 0; i < 2; i++) { 21415 if (i == 1) { 21416 // Install a toJSON function on the second run. 21417 v8::Local<v8::FunctionTemplate> toJSON = 21418 v8::FunctionTemplate::New(isolate, UnreachableCallback); 21419 21420 global0->Set(context0.local(), v8_str("toJSON"), 21421 toJSON->GetFunction(context0.local()).ToLocalChecked()) 21422 .FromJust(); 21423 } 21424 // Create a context with a different security token so that the 21425 // failed access check callback will be called on each access. 21426 LocalContext context1(NULL, global_template); 21427 CHECK(context1->Global() 21428 ->Set(context1.local(), v8_str("other"), global0) 21429 .FromJust()); 21430 21431 CHECK(CompileRun("JSON.stringify(other)").IsEmpty()); 21432 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty()); 21433 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty()); 21434 } 21435 } 21436 21437 21438 bool access_check_fail_thrown = false; 21439 bool catch_callback_called = false; 21440 21441 21442 // Failed access check callback that performs a GC on each invocation. 21443 void FailedAccessCheckThrows(Local<v8::Object> target, 21444 v8::AccessType type, 21445 Local<v8::Value> data) { 21446 access_check_fail_thrown = true; 21447 i::PrintF("Access check failed. Error thrown.\n"); 21448 CcTest::isolate()->ThrowException( 21449 v8::Exception::Error(v8_str("cross context"))); 21450 } 21451 21452 21453 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21454 for (int i = 0; i < args.Length(); i++) { 21455 i::PrintF("%s\n", *String::Utf8Value(args[i])); 21456 } 21457 catch_callback_called = true; 21458 } 21459 21460 21461 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21462 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 21463 CHECK( 21464 args[0] 21465 ->ToObject(context) 21466 .ToLocalChecked() 21467 ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked()) 21468 .IsNothing()); 21469 } 21470 21471 21472 void CheckCorrectThrow(const char* script) { 21473 // Test that the script, when wrapped into a try-catch, triggers the catch 21474 // clause due to failed access check throwing an exception. 21475 // The subsequent try-catch should run without any exception. 21476 access_check_fail_thrown = false; 21477 catch_callback_called = false; 21478 i::ScopedVector<char> source(1024); 21479 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 21480 CompileRun(source.start()); 21481 CHECK(access_check_fail_thrown); 21482 CHECK(catch_callback_called); 21483 21484 access_check_fail_thrown = false; 21485 catch_callback_called = false; 21486 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 21487 CHECK(!access_check_fail_thrown); 21488 CHECK(!catch_callback_called); 21489 } 21490 21491 21492 TEST(AccessCheckThrows) { 21493 i::FLAG_allow_natives_syntax = true; 21494 v8::V8::Initialize(); 21495 v8::Isolate* isolate = CcTest::isolate(); 21496 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 21497 v8::HandleScope scope(isolate); 21498 21499 // Create an ObjectTemplate for global objects and install access 21500 // check callbacks that will block access. 21501 v8::Local<v8::ObjectTemplate> global_template = 21502 v8::ObjectTemplate::New(isolate); 21503 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 21504 21505 // Create a context and set an x property on it's global object. 21506 LocalContext context0(NULL, global_template); 21507 v8::Local<v8::Object> global0 = context0->Global(); 21508 21509 // Create a context with a different security token so that the 21510 // failed access check callback will be called on each access. 21511 LocalContext context1(NULL, global_template); 21512 CHECK(context1->Global() 21513 ->Set(context1.local(), v8_str("other"), global0) 21514 .FromJust()); 21515 21516 v8::Local<v8::FunctionTemplate> catcher_fun = 21517 v8::FunctionTemplate::New(isolate, CatcherCallback); 21518 CHECK(context1->Global() 21519 ->Set(context1.local(), v8_str("catcher"), 21520 catcher_fun->GetFunction(context1.local()).ToLocalChecked()) 21521 .FromJust()); 21522 21523 v8::Local<v8::FunctionTemplate> has_own_property_fun = 21524 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback); 21525 CHECK(context1->Global() 21526 ->Set(context1.local(), v8_str("has_own_property"), 21527 has_own_property_fun->GetFunction(context1.local()) 21528 .ToLocalChecked()) 21529 .FromJust()); 21530 21531 { 21532 v8::TryCatch try_catch(isolate); 21533 access_check_fail_thrown = false; 21534 CompileRun("other.x;"); 21535 CHECK(access_check_fail_thrown); 21536 CHECK(try_catch.HasCaught()); 21537 } 21538 21539 CheckCorrectThrow("other.x"); 21540 CheckCorrectThrow("other[1]"); 21541 CheckCorrectThrow("JSON.stringify(other)"); 21542 CheckCorrectThrow("has_own_property(other, 'x')"); 21543 CheckCorrectThrow("%GetProperty(other, 'x')"); 21544 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)"); 21545 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)"); 21546 CheckCorrectThrow("%DeleteProperty_Sloppy(other, 'x')"); 21547 CheckCorrectThrow("%DeleteProperty_Strict(other, 'x')"); 21548 CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')"); 21549 CheckCorrectThrow("%DeleteProperty_Strict(other, '1')"); 21550 CheckCorrectThrow("%HasOwnProperty(other, 'x')"); 21551 CheckCorrectThrow("%HasProperty('x', other)"); 21552 CheckCorrectThrow("%PropertyIsEnumerable(other, 'x')"); 21553 // PROPERTY_ATTRIBUTES_NONE = 0 21554 CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" 21555 "other, 'x', null, null, 1)"); 21556 21557 // Reset the failed access check callback so it does not influence 21558 // the other tests. 21559 isolate->SetFailedAccessCheckCallbackFunction(NULL); 21560 } 21561 21562 21563 class RequestInterruptTestBase { 21564 public: 21565 RequestInterruptTestBase() 21566 : env_(), 21567 isolate_(env_->GetIsolate()), 21568 sem_(0), 21569 warmup_(20000), 21570 should_continue_(true) { 21571 } 21572 21573 virtual ~RequestInterruptTestBase() { } 21574 21575 virtual void StartInterruptThread() = 0; 21576 21577 virtual void TestBody() = 0; 21578 21579 void RunTest() { 21580 StartInterruptThread(); 21581 21582 v8::HandleScope handle_scope(isolate_); 21583 21584 TestBody(); 21585 21586 // Verify we arrived here because interruptor was called 21587 // not due to a bug causing us to exit the loop too early. 21588 CHECK(!should_continue()); 21589 } 21590 21591 void WakeUpInterruptor() { 21592 sem_.Signal(); 21593 } 21594 21595 bool should_continue() const { return should_continue_; } 21596 21597 bool ShouldContinue() { 21598 if (warmup_ > 0) { 21599 if (--warmup_ == 0) { 21600 WakeUpInterruptor(); 21601 } 21602 } 21603 21604 return should_continue_; 21605 } 21606 21607 static void ShouldContinueCallback( 21608 const v8::FunctionCallbackInfo<Value>& info) { 21609 RequestInterruptTestBase* test = 21610 reinterpret_cast<RequestInterruptTestBase*>( 21611 info.Data().As<v8::External>()->Value()); 21612 info.GetReturnValue().Set(test->ShouldContinue()); 21613 } 21614 21615 LocalContext env_; 21616 v8::Isolate* isolate_; 21617 v8::base::Semaphore sem_; 21618 int warmup_; 21619 bool should_continue_; 21620 }; 21621 21622 21623 class RequestInterruptTestBaseWithSimpleInterrupt 21624 : public RequestInterruptTestBase { 21625 public: 21626 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { } 21627 21628 virtual void StartInterruptThread() { 21629 i_thread.Start(); 21630 } 21631 21632 private: 21633 class InterruptThread : public v8::base::Thread { 21634 public: 21635 explicit InterruptThread(RequestInterruptTestBase* test) 21636 : Thread(Options("RequestInterruptTest")), test_(test) {} 21637 21638 virtual void Run() { 21639 test_->sem_.Wait(); 21640 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 21641 } 21642 21643 static void OnInterrupt(v8::Isolate* isolate, void* data) { 21644 reinterpret_cast<RequestInterruptTestBase*>(data)-> 21645 should_continue_ = false; 21646 } 21647 21648 private: 21649 RequestInterruptTestBase* test_; 21650 }; 21651 21652 InterruptThread i_thread; 21653 }; 21654 21655 21656 class RequestInterruptTestWithFunctionCall 21657 : public RequestInterruptTestBaseWithSimpleInterrupt { 21658 public: 21659 virtual void TestBody() { 21660 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback, 21661 v8::External::New(isolate_, this)) 21662 .ToLocalChecked(); 21663 CHECK(env_->Global() 21664 ->Set(env_.local(), v8_str("ShouldContinue"), func) 21665 .FromJust()); 21666 21667 CompileRun("while (ShouldContinue()) { }"); 21668 } 21669 }; 21670 21671 21672 class RequestInterruptTestWithMethodCall 21673 : public RequestInterruptTestBaseWithSimpleInterrupt { 21674 public: 21675 virtual void TestBody() { 21676 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 21677 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 21678 proto->Set(v8_str("shouldContinue"), 21679 Function::New(env_.local(), ShouldContinueCallback, 21680 v8::External::New(isolate_, this)) 21681 .ToLocalChecked()); 21682 CHECK(env_->Global() 21683 ->Set(env_.local(), v8_str("Klass"), 21684 t->GetFunction(env_.local()).ToLocalChecked()) 21685 .FromJust()); 21686 21687 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 21688 } 21689 }; 21690 21691 21692 class RequestInterruptTestWithAccessor 21693 : public RequestInterruptTestBaseWithSimpleInterrupt { 21694 public: 21695 virtual void TestBody() { 21696 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 21697 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 21698 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New( 21699 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 21700 CHECK(env_->Global() 21701 ->Set(env_.local(), v8_str("Klass"), 21702 t->GetFunction(env_.local()).ToLocalChecked()) 21703 .FromJust()); 21704 21705 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 21706 } 21707 }; 21708 21709 21710 class RequestInterruptTestWithNativeAccessor 21711 : public RequestInterruptTestBaseWithSimpleInterrupt { 21712 public: 21713 virtual void TestBody() { 21714 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 21715 t->InstanceTemplate()->SetNativeDataProperty( 21716 v8_str("shouldContinue"), 21717 &ShouldContinueNativeGetter, 21718 NULL, 21719 v8::External::New(isolate_, this)); 21720 CHECK(env_->Global() 21721 ->Set(env_.local(), v8_str("Klass"), 21722 t->GetFunction(env_.local()).ToLocalChecked()) 21723 .FromJust()); 21724 21725 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 21726 } 21727 21728 private: 21729 static void ShouldContinueNativeGetter( 21730 Local<String> property, 21731 const v8::PropertyCallbackInfo<v8::Value>& info) { 21732 RequestInterruptTestBase* test = 21733 reinterpret_cast<RequestInterruptTestBase*>( 21734 info.Data().As<v8::External>()->Value()); 21735 info.GetReturnValue().Set(test->ShouldContinue()); 21736 } 21737 }; 21738 21739 21740 class RequestInterruptTestWithMethodCallAndInterceptor 21741 : public RequestInterruptTestBaseWithSimpleInterrupt { 21742 public: 21743 virtual void TestBody() { 21744 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 21745 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 21746 proto->Set(v8_str("shouldContinue"), 21747 Function::New(env_.local(), ShouldContinueCallback, 21748 v8::External::New(isolate_, this)) 21749 .ToLocalChecked()); 21750 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate(); 21751 instance_template->SetHandler( 21752 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor)); 21753 21754 CHECK(env_->Global() 21755 ->Set(env_.local(), v8_str("Klass"), 21756 t->GetFunction(env_.local()).ToLocalChecked()) 21757 .FromJust()); 21758 21759 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 21760 } 21761 21762 private: 21763 static void EmptyInterceptor( 21764 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {} 21765 }; 21766 21767 21768 class RequestInterruptTestWithMathAbs 21769 : public RequestInterruptTestBaseWithSimpleInterrupt { 21770 public: 21771 virtual void TestBody() { 21772 env_->Global() 21773 ->Set(env_.local(), v8_str("WakeUpInterruptor"), 21774 Function::New(env_.local(), WakeUpInterruptorCallback, 21775 v8::External::New(isolate_, this)) 21776 .ToLocalChecked()) 21777 .FromJust(); 21778 21779 env_->Global() 21780 ->Set(env_.local(), v8_str("ShouldContinue"), 21781 Function::New(env_.local(), ShouldContinueCallback, 21782 v8::External::New(isolate_, this)) 21783 .ToLocalChecked()) 21784 .FromJust(); 21785 21786 i::FLAG_allow_natives_syntax = true; 21787 CompileRun("function loopish(o) {" 21788 " var pre = 10;" 21789 " while (o.abs(1) > 0) {" 21790 " if (o.abs(1) >= 0 && !ShouldContinue()) break;" 21791 " if (pre > 0) {" 21792 " if (--pre === 0) WakeUpInterruptor(o === Math);" 21793 " }" 21794 " }" 21795 "}" 21796 "var i = 50;" 21797 "var obj = {abs: function () { return i-- }, x: null};" 21798 "delete obj.x;" 21799 "loopish(obj);" 21800 "%OptimizeFunctionOnNextCall(loopish);" 21801 "loopish(Math);"); 21802 21803 i::FLAG_allow_natives_syntax = false; 21804 } 21805 21806 private: 21807 static void WakeUpInterruptorCallback( 21808 const v8::FunctionCallbackInfo<Value>& info) { 21809 if (!info[0] 21810 ->BooleanValue(info.GetIsolate()->GetCurrentContext()) 21811 .FromJust()) { 21812 return; 21813 } 21814 21815 RequestInterruptTestBase* test = 21816 reinterpret_cast<RequestInterruptTestBase*>( 21817 info.Data().As<v8::External>()->Value()); 21818 test->WakeUpInterruptor(); 21819 } 21820 21821 static void ShouldContinueCallback( 21822 const v8::FunctionCallbackInfo<Value>& info) { 21823 RequestInterruptTestBase* test = 21824 reinterpret_cast<RequestInterruptTestBase*>( 21825 info.Data().As<v8::External>()->Value()); 21826 info.GetReturnValue().Set(test->should_continue()); 21827 } 21828 }; 21829 21830 21831 TEST(RequestInterruptTestWithFunctionCall) { 21832 RequestInterruptTestWithFunctionCall().RunTest(); 21833 } 21834 21835 21836 TEST(RequestInterruptTestWithMethodCall) { 21837 RequestInterruptTestWithMethodCall().RunTest(); 21838 } 21839 21840 21841 TEST(RequestInterruptTestWithAccessor) { 21842 RequestInterruptTestWithAccessor().RunTest(); 21843 } 21844 21845 21846 TEST(RequestInterruptTestWithNativeAccessor) { 21847 RequestInterruptTestWithNativeAccessor().RunTest(); 21848 } 21849 21850 21851 TEST(RequestInterruptTestWithMethodCallAndInterceptor) { 21852 RequestInterruptTestWithMethodCallAndInterceptor().RunTest(); 21853 } 21854 21855 21856 TEST(RequestInterruptTestWithMathAbs) { 21857 RequestInterruptTestWithMathAbs().RunTest(); 21858 } 21859 21860 21861 class RequestMultipleInterrupts : public RequestInterruptTestBase { 21862 public: 21863 RequestMultipleInterrupts() : i_thread(this), counter_(0) {} 21864 21865 virtual void StartInterruptThread() { 21866 i_thread.Start(); 21867 } 21868 21869 virtual void TestBody() { 21870 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback, 21871 v8::External::New(isolate_, this)) 21872 .ToLocalChecked(); 21873 CHECK(env_->Global() 21874 ->Set(env_.local(), v8_str("ShouldContinue"), func) 21875 .FromJust()); 21876 21877 CompileRun("while (ShouldContinue()) { }"); 21878 } 21879 21880 private: 21881 class InterruptThread : public v8::base::Thread { 21882 public: 21883 enum { NUM_INTERRUPTS = 10 }; 21884 explicit InterruptThread(RequestMultipleInterrupts* test) 21885 : Thread(Options("RequestInterruptTest")), test_(test) {} 21886 21887 virtual void Run() { 21888 test_->sem_.Wait(); 21889 for (int i = 0; i < NUM_INTERRUPTS; i++) { 21890 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 21891 } 21892 } 21893 21894 static void OnInterrupt(v8::Isolate* isolate, void* data) { 21895 RequestMultipleInterrupts* test = 21896 reinterpret_cast<RequestMultipleInterrupts*>(data); 21897 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS; 21898 } 21899 21900 private: 21901 RequestMultipleInterrupts* test_; 21902 }; 21903 21904 InterruptThread i_thread; 21905 int counter_; 21906 }; 21907 21908 21909 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); } 21910 21911 21912 static bool interrupt_was_called = false; 21913 21914 21915 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) { 21916 interrupt_was_called = true; 21917 } 21918 21919 21920 TEST(RequestInterruptSmallScripts) { 21921 LocalContext env; 21922 v8::Isolate* isolate = CcTest::isolate(); 21923 v8::HandleScope scope(isolate); 21924 21925 interrupt_was_called = false; 21926 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL); 21927 CompileRun("(function(x){return x;})(1);"); 21928 CHECK(interrupt_was_called); 21929 } 21930 21931 21932 static Local<Value> function_new_expected_env; 21933 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { 21934 CHECK( 21935 function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(), 21936 info.Data()) 21937 .FromJust()); 21938 info.GetReturnValue().Set(17); 21939 } 21940 21941 21942 THREADED_TEST(FunctionNew) { 21943 LocalContext env; 21944 v8::Isolate* isolate = env->GetIsolate(); 21945 v8::HandleScope scope(isolate); 21946 Local<Object> data = v8::Object::New(isolate); 21947 function_new_expected_env = data; 21948 Local<Function> func = 21949 Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked(); 21950 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust()); 21951 Local<Value> result = CompileRun("func();"); 21952 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust()); 21953 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 21954 // Verify function not cached 21955 auto serial_number = handle( 21956 i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func)) 21957 ->shared() 21958 ->get_api_func_data() 21959 ->serial_number()), 21960 i_isolate); 21961 auto cache = i_isolate->function_cache(); 21962 CHECK(cache->Lookup(serial_number)->IsTheHole()); 21963 // Verify that each Function::New creates a new function instance 21964 Local<Object> data2 = v8::Object::New(isolate); 21965 function_new_expected_env = data2; 21966 Local<Function> func2 = 21967 Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked(); 21968 CHECK(!func2->IsNull()); 21969 CHECK(!func->Equals(env.local(), func2).FromJust()); 21970 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust()); 21971 Local<Value> result2 = CompileRun("func2();"); 21972 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust()); 21973 } 21974 21975 21976 TEST(EscapeableHandleScope) { 21977 HandleScope outer_scope(CcTest::isolate()); 21978 LocalContext context; 21979 const int runs = 10; 21980 Local<String> values[runs]; 21981 for (int i = 0; i < runs; i++) { 21982 v8::EscapableHandleScope inner_scope(CcTest::isolate()); 21983 Local<String> value; 21984 if (i != 0) value = v8_str("escape value"); 21985 values[i] = inner_scope.Escape(value); 21986 } 21987 for (int i = 0; i < runs; i++) { 21988 Local<String> expected; 21989 if (i != 0) { 21990 CHECK(v8_str("escape value") 21991 ->Equals(context.local(), values[i]) 21992 .FromJust()); 21993 } else { 21994 CHECK(values[i].IsEmpty()); 21995 } 21996 } 21997 } 21998 21999 22000 static void SetterWhichExpectsThisAndHolderToDiffer( 22001 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) { 22002 CHECK(info.Holder() != info.This()); 22003 } 22004 22005 22006 TEST(Regress239669) { 22007 LocalContext context; 22008 v8::Isolate* isolate = context->GetIsolate(); 22009 v8::HandleScope scope(isolate); 22010 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22011 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer); 22012 CHECK(context->Global() 22013 ->Set(context.local(), v8_str("P"), 22014 templ->NewInstance(context.local()).ToLocalChecked()) 22015 .FromJust()); 22016 CompileRun( 22017 "function C1() {" 22018 " this.x = 23;" 22019 "};" 22020 "C1.prototype = P;" 22021 "for (var i = 0; i < 4; i++ ) {" 22022 " new C1();" 22023 "}"); 22024 } 22025 22026 22027 class ApiCallOptimizationChecker { 22028 private: 22029 static Local<Object> data; 22030 static Local<Object> receiver; 22031 static Local<Object> holder; 22032 static Local<Object> callee; 22033 static int count; 22034 22035 static void OptimizationCallback( 22036 const v8::FunctionCallbackInfo<v8::Value>& info) { 22037 CHECK(callee == info.Callee()); 22038 CHECK(data == info.Data()); 22039 CHECK(receiver == info.This()); 22040 if (info.Length() == 1) { 22041 CHECK(v8_num(1) 22042 ->Equals(info.GetIsolate()->GetCurrentContext(), info[0]) 22043 .FromJust()); 22044 } 22045 CHECK(holder == info.Holder()); 22046 count++; 22047 info.GetReturnValue().Set(v8_str("returned")); 22048 } 22049 22050 public: 22051 enum SignatureType { 22052 kNoSignature, 22053 kSignatureOnReceiver, 22054 kSignatureOnPrototype 22055 }; 22056 22057 void RunAll() { 22058 SignatureType signature_types[] = 22059 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; 22060 for (unsigned i = 0; i < arraysize(signature_types); i++) { 22061 SignatureType signature_type = signature_types[i]; 22062 for (int j = 0; j < 2; j++) { 22063 bool global = j == 0; 22064 int key = signature_type + 22065 arraysize(signature_types) * (global ? 1 : 0); 22066 Run(signature_type, global, key); 22067 } 22068 } 22069 } 22070 22071 void Run(SignatureType signature_type, bool global, int key) { 22072 v8::Isolate* isolate = CcTest::isolate(); 22073 v8::HandleScope scope(isolate); 22074 // Build a template for signature checks. 22075 Local<v8::ObjectTemplate> signature_template; 22076 Local<v8::Signature> signature; 22077 { 22078 Local<v8::FunctionTemplate> parent_template = 22079 FunctionTemplate::New(isolate); 22080 parent_template->SetHiddenPrototype(true); 22081 Local<v8::FunctionTemplate> function_template 22082 = FunctionTemplate::New(isolate); 22083 function_template->Inherit(parent_template); 22084 switch (signature_type) { 22085 case kNoSignature: 22086 break; 22087 case kSignatureOnReceiver: 22088 signature = v8::Signature::New(isolate, function_template); 22089 break; 22090 case kSignatureOnPrototype: 22091 signature = v8::Signature::New(isolate, parent_template); 22092 break; 22093 } 22094 signature_template = function_template->InstanceTemplate(); 22095 } 22096 // Global object must pass checks. 22097 Local<v8::Context> context = 22098 v8::Context::New(isolate, NULL, signature_template); 22099 v8::Context::Scope context_scope(context); 22100 // Install regular object that can pass signature checks. 22101 Local<Object> function_receiver = 22102 signature_template->NewInstance(context).ToLocalChecked(); 22103 CHECK(context->Global() 22104 ->Set(context, v8_str("function_receiver"), function_receiver) 22105 .FromJust()); 22106 // Get the holder objects. 22107 Local<Object> inner_global = 22108 Local<Object>::Cast(context->Global()->GetPrototype()); 22109 // Install functions on hidden prototype object if there is one. 22110 data = Object::New(isolate); 22111 Local<FunctionTemplate> function_template = FunctionTemplate::New( 22112 isolate, OptimizationCallback, data, signature); 22113 Local<Function> function = 22114 function_template->GetFunction(context).ToLocalChecked(); 22115 Local<Object> global_holder = inner_global; 22116 Local<Object> function_holder = function_receiver; 22117 if (signature_type == kSignatureOnPrototype) { 22118 function_holder = Local<Object>::Cast(function_holder->GetPrototype()); 22119 global_holder = Local<Object>::Cast(global_holder->GetPrototype()); 22120 } 22121 global_holder->Set(context, v8_str("g_f"), function).FromJust(); 22122 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); 22123 function_holder->Set(context, v8_str("f"), function).FromJust(); 22124 function_holder->SetAccessorProperty(v8_str("acc"), function, function); 22125 // Initialize expected values. 22126 callee = function; 22127 count = 0; 22128 if (global) { 22129 receiver = context->Global(); 22130 holder = inner_global; 22131 } else { 22132 holder = function_receiver; 22133 // If not using a signature, add something else to the prototype chain 22134 // to test the case that holder != receiver 22135 if (signature_type == kNoSignature) { 22136 receiver = Local<Object>::Cast(CompileRun( 22137 "var receiver_subclass = {};\n" 22138 "receiver_subclass.__proto__ = function_receiver;\n" 22139 "receiver_subclass")); 22140 } else { 22141 receiver = Local<Object>::Cast(CompileRun( 22142 "var receiver_subclass = function_receiver;\n" 22143 "receiver_subclass")); 22144 } 22145 } 22146 // With no signature, the holder is not set. 22147 if (signature_type == kNoSignature) holder = receiver; 22148 // build wrap_function 22149 i::ScopedVector<char> wrap_function(200); 22150 if (global) { 22151 i::SNPrintF( 22152 wrap_function, 22153 "function wrap_f_%d() { var f = g_f; return f(); }\n" 22154 "function wrap_get_%d() { return this.g_acc; }\n" 22155 "function wrap_set_%d() { return this.g_acc = 1; }\n", 22156 key, key, key); 22157 } else { 22158 i::SNPrintF( 22159 wrap_function, 22160 "function wrap_f_%d() { return receiver_subclass.f(); }\n" 22161 "function wrap_get_%d() { return receiver_subclass.acc; }\n" 22162 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", 22163 key, key, key); 22164 } 22165 // build source string 22166 i::ScopedVector<char> source(1000); 22167 i::SNPrintF( 22168 source, 22169 "%s\n" // wrap functions 22170 "function wrap_f() { return wrap_f_%d(); }\n" 22171 "function wrap_get() { return wrap_get_%d(); }\n" 22172 "function wrap_set() { return wrap_set_%d(); }\n" 22173 "check = function(returned) {\n" 22174 " if (returned !== 'returned') { throw returned; }\n" 22175 "}\n" 22176 "\n" 22177 "check(wrap_f());\n" 22178 "check(wrap_f());\n" 22179 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" 22180 "check(wrap_f());\n" 22181 "\n" 22182 "check(wrap_get());\n" 22183 "check(wrap_get());\n" 22184 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" 22185 "check(wrap_get());\n" 22186 "\n" 22187 "check = function(returned) {\n" 22188 " if (returned !== 1) { throw returned; }\n" 22189 "}\n" 22190 "check(wrap_set());\n" 22191 "check(wrap_set());\n" 22192 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" 22193 "check(wrap_set());\n", 22194 wrap_function.start(), key, key, key, key, key, key); 22195 v8::TryCatch try_catch(isolate); 22196 CompileRun(source.start()); 22197 CHECK(!try_catch.HasCaught()); 22198 CHECK_EQ(9, count); 22199 } 22200 }; 22201 22202 22203 Local<Object> ApiCallOptimizationChecker::data; 22204 Local<Object> ApiCallOptimizationChecker::receiver; 22205 Local<Object> ApiCallOptimizationChecker::holder; 22206 Local<Object> ApiCallOptimizationChecker::callee; 22207 int ApiCallOptimizationChecker::count = 0; 22208 22209 22210 TEST(FunctionCallOptimization) { 22211 i::FLAG_allow_natives_syntax = true; 22212 ApiCallOptimizationChecker checker; 22213 checker.RunAll(); 22214 } 22215 22216 22217 TEST(FunctionCallOptimizationMultipleArgs) { 22218 i::FLAG_allow_natives_syntax = true; 22219 LocalContext context; 22220 v8::Isolate* isolate = context->GetIsolate(); 22221 v8::HandleScope scope(isolate); 22222 Local<Object> global = context->Global(); 22223 Local<v8::Function> function = 22224 Function::New(context.local(), Returns42).ToLocalChecked(); 22225 global->Set(context.local(), v8_str("x"), function).FromJust(); 22226 CompileRun( 22227 "function x_wrap() {\n" 22228 " for (var i = 0; i < 5; i++) {\n" 22229 " x(1,2,3);\n" 22230 " }\n" 22231 "}\n" 22232 "x_wrap();\n" 22233 "%OptimizeFunctionOnNextCall(x_wrap);" 22234 "x_wrap();\n"); 22235 } 22236 22237 22238 static void ReturnsSymbolCallback( 22239 const v8::FunctionCallbackInfo<v8::Value>& info) { 22240 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate())); 22241 } 22242 22243 22244 TEST(ApiCallbackCanReturnSymbols) { 22245 i::FLAG_allow_natives_syntax = true; 22246 LocalContext context; 22247 v8::Isolate* isolate = context->GetIsolate(); 22248 v8::HandleScope scope(isolate); 22249 Local<Object> global = context->Global(); 22250 Local<v8::Function> function = 22251 Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked(); 22252 global->Set(context.local(), v8_str("x"), function).FromJust(); 22253 CompileRun( 22254 "function x_wrap() {\n" 22255 " for (var i = 0; i < 5; i++) {\n" 22256 " x();\n" 22257 " }\n" 22258 "}\n" 22259 "x_wrap();\n" 22260 "%OptimizeFunctionOnNextCall(x_wrap);" 22261 "x_wrap();\n"); 22262 } 22263 22264 22265 TEST(EmptyApiCallback) { 22266 LocalContext context; 22267 auto isolate = context->GetIsolate(); 22268 v8::HandleScope scope(isolate); 22269 auto global = context->Global(); 22270 auto function = FunctionTemplate::New(isolate) 22271 ->GetFunction(context.local()) 22272 .ToLocalChecked(); 22273 global->Set(context.local(), v8_str("x"), function).FromJust(); 22274 22275 auto result = CompileRun("x()"); 22276 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 22277 22278 result = CompileRun("x(1,2,3)"); 22279 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 22280 22281 result = CompileRun("x.call(undefined)"); 22282 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 22283 22284 result = CompileRun("x.call(null)"); 22285 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 22286 22287 result = CompileRun("7 + x.call(3) + 11"); 22288 CHECK(result->IsInt32()); 22289 CHECK_EQ(21, result->Int32Value(context.local()).FromJust()); 22290 22291 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11"); 22292 CHECK(result->IsInt32()); 22293 CHECK_EQ(21, result->Int32Value(context.local()).FromJust()); 22294 22295 result = CompileRun("var y = []; x.call(y)"); 22296 CHECK(result->IsArray()); 22297 22298 result = CompileRun("x.call(y, 1, 2, 3, 4)"); 22299 CHECK(result->IsArray()); 22300 } 22301 22302 22303 TEST(SimpleSignatureCheck) { 22304 LocalContext context; 22305 auto isolate = context->GetIsolate(); 22306 v8::HandleScope scope(isolate); 22307 auto global = context->Global(); 22308 auto sig_obj = FunctionTemplate::New(isolate); 22309 auto sig = v8::Signature::New(isolate, sig_obj); 22310 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 22311 global->Set(context.local(), v8_str("sig_obj"), 22312 sig_obj->GetFunction(context.local()).ToLocalChecked()) 22313 .FromJust(); 22314 global->Set(context.local(), v8_str("x"), 22315 x->GetFunction(context.local()).ToLocalChecked()) 22316 .FromJust(); 22317 CompileRun("var s = new sig_obj();"); 22318 { 22319 TryCatch try_catch(isolate); 22320 CompileRun("x()"); 22321 CHECK(try_catch.HasCaught()); 22322 } 22323 { 22324 TryCatch try_catch(isolate); 22325 CompileRun("x.call(1)"); 22326 CHECK(try_catch.HasCaught()); 22327 } 22328 { 22329 TryCatch try_catch(isolate); 22330 auto result = CompileRun("s.x = x; s.x()"); 22331 CHECK(!try_catch.HasCaught()); 22332 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22333 } 22334 { 22335 TryCatch try_catch(isolate); 22336 auto result = CompileRun("x.call(s)"); 22337 CHECK(!try_catch.HasCaught()); 22338 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22339 } 22340 } 22341 22342 22343 TEST(ChainSignatureCheck) { 22344 LocalContext context; 22345 auto isolate = context->GetIsolate(); 22346 v8::HandleScope scope(isolate); 22347 auto global = context->Global(); 22348 auto sig_obj = FunctionTemplate::New(isolate); 22349 auto sig = v8::Signature::New(isolate, sig_obj); 22350 for (int i = 0; i < 4; ++i) { 22351 auto temp = FunctionTemplate::New(isolate); 22352 temp->Inherit(sig_obj); 22353 sig_obj = temp; 22354 } 22355 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 22356 global->Set(context.local(), v8_str("sig_obj"), 22357 sig_obj->GetFunction(context.local()).ToLocalChecked()) 22358 .FromJust(); 22359 global->Set(context.local(), v8_str("x"), 22360 x->GetFunction(context.local()).ToLocalChecked()) 22361 .FromJust(); 22362 CompileRun("var s = new sig_obj();"); 22363 { 22364 TryCatch try_catch(isolate); 22365 CompileRun("x()"); 22366 CHECK(try_catch.HasCaught()); 22367 } 22368 { 22369 TryCatch try_catch(isolate); 22370 CompileRun("x.call(1)"); 22371 CHECK(try_catch.HasCaught()); 22372 } 22373 { 22374 TryCatch try_catch(isolate); 22375 auto result = CompileRun("s.x = x; s.x()"); 22376 CHECK(!try_catch.HasCaught()); 22377 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22378 } 22379 { 22380 TryCatch try_catch(isolate); 22381 auto result = CompileRun("x.call(s)"); 22382 CHECK(!try_catch.HasCaught()); 22383 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22384 } 22385 } 22386 22387 22388 TEST(PrototypeSignatureCheck) { 22389 LocalContext context; 22390 auto isolate = context->GetIsolate(); 22391 v8::HandleScope scope(isolate); 22392 auto global = context->Global(); 22393 auto sig_obj = FunctionTemplate::New(isolate); 22394 sig_obj->SetHiddenPrototype(true); 22395 auto sig = v8::Signature::New(isolate, sig_obj); 22396 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 22397 global->Set(context.local(), v8_str("sig_obj"), 22398 sig_obj->GetFunction(context.local()).ToLocalChecked()) 22399 .FromJust(); 22400 global->Set(context.local(), v8_str("x"), 22401 x->GetFunction(context.local()).ToLocalChecked()) 22402 .FromJust(); 22403 CompileRun("s = {}; s.__proto__ = new sig_obj();"); 22404 { 22405 TryCatch try_catch(isolate); 22406 CompileRun("x()"); 22407 CHECK(try_catch.HasCaught()); 22408 } 22409 { 22410 TryCatch try_catch(isolate); 22411 CompileRun("x.call(1)"); 22412 CHECK(try_catch.HasCaught()); 22413 } 22414 { 22415 TryCatch try_catch(isolate); 22416 auto result = CompileRun("s.x = x; s.x()"); 22417 CHECK(!try_catch.HasCaught()); 22418 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22419 } 22420 { 22421 TryCatch try_catch(isolate); 22422 auto result = CompileRun("x.call(s)"); 22423 CHECK(!try_catch.HasCaught()); 22424 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 22425 } 22426 } 22427 22428 22429 static const char* last_event_message; 22430 static int last_event_status; 22431 void StoringEventLoggerCallback(const char* message, int status) { 22432 last_event_message = message; 22433 last_event_status = status; 22434 } 22435 22436 22437 TEST(EventLogging) { 22438 v8::Isolate* isolate = CcTest::isolate(); 22439 isolate->SetEventLogger(StoringEventLoggerCallback); 22440 v8::internal::HistogramTimer histogramTimer( 22441 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50, 22442 reinterpret_cast<v8::internal::Isolate*>(isolate)); 22443 histogramTimer.Start(); 22444 CHECK_EQ(0, strcmp("V8.Test", last_event_message)); 22445 CHECK_EQ(0, last_event_status); 22446 histogramTimer.Stop(); 22447 CHECK_EQ(0, strcmp("V8.Test", last_event_message)); 22448 CHECK_EQ(1, last_event_status); 22449 } 22450 22451 22452 TEST(Promises) { 22453 LocalContext context; 22454 v8::Isolate* isolate = context->GetIsolate(); 22455 v8::HandleScope scope(isolate); 22456 22457 // Creation. 22458 Local<v8::Promise::Resolver> pr = 22459 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22460 Local<v8::Promise::Resolver> rr = 22461 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22462 Local<v8::Promise> p = pr->GetPromise(); 22463 Local<v8::Promise> r = rr->GetPromise(); 22464 22465 // IsPromise predicate. 22466 CHECK(p->IsPromise()); 22467 CHECK(r->IsPromise()); 22468 Local<Value> o = v8::Object::New(isolate); 22469 CHECK(!o->IsPromise()); 22470 22471 // Resolution and rejection. 22472 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust(); 22473 CHECK(p->IsPromise()); 22474 rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust(); 22475 CHECK(r->IsPromise()); 22476 } 22477 22478 22479 TEST(PromiseThen) { 22480 LocalContext context; 22481 v8::Isolate* isolate = context->GetIsolate(); 22482 v8::HandleScope scope(isolate); 22483 Local<Object> global = context->Global(); 22484 22485 // Creation. 22486 Local<v8::Promise::Resolver> pr = 22487 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22488 Local<v8::Promise::Resolver> qr = 22489 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22490 Local<v8::Promise> p = pr->GetPromise(); 22491 Local<v8::Promise> q = qr->GetPromise(); 22492 22493 CHECK(p->IsPromise()); 22494 CHECK(q->IsPromise()); 22495 22496 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust(); 22497 qr->Resolve(context.local(), p).FromJust(); 22498 22499 // Chaining non-pending promises. 22500 CompileRun( 22501 "var x1 = 0;\n" 22502 "var x2 = 0;\n" 22503 "function f1(x) { x1 = x; return x+1 };\n" 22504 "function f2(x) { x2 = x; return x+1 };\n"); 22505 Local<Function> f1 = Local<Function>::Cast( 22506 global->Get(context.local(), v8_str("f1")).ToLocalChecked()); 22507 Local<Function> f2 = Local<Function>::Cast( 22508 global->Get(context.local(), v8_str("f2")).ToLocalChecked()); 22509 22510 // Then 22511 CompileRun("x1 = x2 = 0;"); 22512 q->Then(context.local(), f1).ToLocalChecked(); 22513 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 22514 .ToLocalChecked() 22515 ->Int32Value(context.local()) 22516 .FromJust()); 22517 isolate->RunMicrotasks(); 22518 CHECK_EQ(1, global->Get(context.local(), v8_str("x1")) 22519 .ToLocalChecked() 22520 ->Int32Value(context.local()) 22521 .FromJust()); 22522 22523 // Then 22524 CompileRun("x1 = x2 = 0;"); 22525 pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22526 qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 22527 22528 qr->Resolve(context.local(), pr).FromJust(); 22529 qr->GetPromise() 22530 ->Then(context.local(), f1) 22531 .ToLocalChecked() 22532 ->Then(context.local(), f2) 22533 .ToLocalChecked(); 22534 22535 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 22536 .ToLocalChecked() 22537 ->Int32Value(context.local()) 22538 .FromJust()); 22539 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 22540 .ToLocalChecked() 22541 ->Int32Value(context.local()) 22542 .FromJust()); 22543 isolate->RunMicrotasks(); 22544 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 22545 .ToLocalChecked() 22546 ->Int32Value(context.local()) 22547 .FromJust()); 22548 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 22549 .ToLocalChecked() 22550 ->Int32Value(context.local()) 22551 .FromJust()); 22552 22553 pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust(); 22554 22555 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 22556 .ToLocalChecked() 22557 ->Int32Value(context.local()) 22558 .FromJust()); 22559 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 22560 .ToLocalChecked() 22561 ->Int32Value(context.local()) 22562 .FromJust()); 22563 isolate->RunMicrotasks(); 22564 CHECK_EQ(3, global->Get(context.local(), v8_str("x1")) 22565 .ToLocalChecked() 22566 ->Int32Value(context.local()) 22567 .FromJust()); 22568 CHECK_EQ(4, global->Get(context.local(), v8_str("x2")) 22569 .ToLocalChecked() 22570 ->Int32Value(context.local()) 22571 .FromJust()); 22572 } 22573 22574 22575 TEST(DisallowJavascriptExecutionScope) { 22576 LocalContext context; 22577 v8::Isolate* isolate = context->GetIsolate(); 22578 v8::HandleScope scope(isolate); 22579 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22580 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22581 CompileRun("2+2"); 22582 } 22583 22584 22585 TEST(AllowJavascriptExecutionScope) { 22586 LocalContext context; 22587 v8::Isolate* isolate = context->GetIsolate(); 22588 v8::HandleScope scope(isolate); 22589 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22590 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22591 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22592 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22593 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate); 22594 CompileRun("1+1"); 22595 } 22596 } 22597 22598 22599 TEST(ThrowOnJavascriptExecution) { 22600 LocalContext context; 22601 v8::Isolate* isolate = context->GetIsolate(); 22602 v8::HandleScope scope(isolate); 22603 v8::TryCatch try_catch(isolate); 22604 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22605 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22606 CompileRun("1+1"); 22607 CHECK(try_catch.HasCaught()); 22608 } 22609 22610 22611 TEST(Regress354123) { 22612 LocalContext current; 22613 v8::Isolate* isolate = current->GetIsolate(); 22614 v8::HandleScope scope(isolate); 22615 22616 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 22617 templ->SetAccessCheckCallback(AccessCounter); 22618 CHECK(current->Global() 22619 ->Set(current.local(), v8_str("friend"), 22620 templ->NewInstance(current.local()).ToLocalChecked()) 22621 .FromJust()); 22622 22623 // Test access using __proto__ from the prototype chain. 22624 access_count = 0; 22625 CompileRun("friend.__proto__ = {};"); 22626 CHECK_EQ(2, access_count); 22627 CompileRun("friend.__proto__;"); 22628 CHECK_EQ(4, access_count); 22629 22630 // Test access using __proto__ as a hijacked function (A). 22631 access_count = 0; 22632 CompileRun("var p = Object.prototype;" 22633 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;" 22634 "f.call(friend, {});"); 22635 CHECK_EQ(1, access_count); 22636 CompileRun("var p = Object.prototype;" 22637 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;" 22638 "f.call(friend);"); 22639 CHECK_EQ(2, access_count); 22640 22641 // Test access using __proto__ as a hijacked function (B). 22642 access_count = 0; 22643 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');" 22644 "f.call(friend, {});"); 22645 CHECK_EQ(1, access_count); 22646 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');" 22647 "f.call(friend);"); 22648 CHECK_EQ(2, access_count); 22649 22650 // Test access using Object.setPrototypeOf reflective method. 22651 access_count = 0; 22652 CompileRun("Object.setPrototypeOf(friend, {});"); 22653 CHECK_EQ(1, access_count); 22654 CompileRun("Object.getPrototypeOf(friend);"); 22655 CHECK_EQ(2, access_count); 22656 } 22657 22658 22659 TEST(CaptureStackTraceForStackOverflow) { 22660 v8::internal::FLAG_stack_size = 150; 22661 LocalContext current; 22662 v8::Isolate* isolate = current->GetIsolate(); 22663 v8::HandleScope scope(isolate); 22664 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, 22665 v8::StackTrace::kDetailed); 22666 v8::TryCatch try_catch(isolate); 22667 CompileRun("(function f(x) { f(x+1); })(0)"); 22668 CHECK(try_catch.HasCaught()); 22669 } 22670 22671 22672 TEST(ScriptNameAndLineNumber) { 22673 LocalContext env; 22674 v8::Isolate* isolate = env->GetIsolate(); 22675 v8::HandleScope scope(isolate); 22676 const char* url = "http://www.foo.com/foo.js"; 22677 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); 22678 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin); 22679 Local<Script> script = 22680 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked(); 22681 Local<Value> script_name = script->GetUnboundScript()->GetScriptName(); 22682 CHECK(!script_name.IsEmpty()); 22683 CHECK(script_name->IsString()); 22684 String::Utf8Value utf8_name(script_name); 22685 CHECK_EQ(0, strcmp(url, *utf8_name)); 22686 int line_number = script->GetUnboundScript()->GetLineNumber(0); 22687 CHECK_EQ(13, line_number); 22688 } 22689 22690 void CheckMagicComments(Local<Script> script, const char* expected_source_url, 22691 const char* expected_source_mapping_url) { 22692 if (expected_source_url != NULL) { 22693 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL()); 22694 CHECK_EQ(0, strcmp(expected_source_url, *url)); 22695 } else { 22696 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined()); 22697 } 22698 if (expected_source_mapping_url != NULL) { 22699 v8::String::Utf8Value url( 22700 script->GetUnboundScript()->GetSourceMappingURL()); 22701 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url)); 22702 } else { 22703 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined()); 22704 } 22705 } 22706 22707 void SourceURLHelper(const char* source, const char* expected_source_url, 22708 const char* expected_source_mapping_url) { 22709 Local<Script> script = v8_compile(source); 22710 CheckMagicComments(script, expected_source_url, expected_source_mapping_url); 22711 } 22712 22713 22714 TEST(ScriptSourceURLAndSourceMappingURL) { 22715 LocalContext env; 22716 v8::Isolate* isolate = env->GetIsolate(); 22717 v8::HandleScope scope(isolate); 22718 SourceURLHelper("function foo() {}\n" 22719 "//# sourceURL=bar1.js\n", "bar1.js", NULL); 22720 SourceURLHelper("function foo() {}\n" 22721 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js"); 22722 22723 // Both sourceURL and sourceMappingURL. 22724 SourceURLHelper("function foo() {}\n" 22725 "//# sourceURL=bar3.js\n" 22726 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js"); 22727 22728 // Two source URLs; the first one is ignored. 22729 SourceURLHelper("function foo() {}\n" 22730 "//# sourceURL=ignoreme.js\n" 22731 "//# sourceURL=bar5.js\n", "bar5.js", NULL); 22732 SourceURLHelper("function foo() {}\n" 22733 "//# sourceMappingURL=ignoreme.js\n" 22734 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js"); 22735 22736 // SourceURL or sourceMappingURL in the middle of the script. 22737 SourceURLHelper("function foo() {}\n" 22738 "//# sourceURL=bar7.js\n" 22739 "function baz() {}\n", "bar7.js", NULL); 22740 SourceURLHelper("function foo() {}\n" 22741 "//# sourceMappingURL=bar8.js\n" 22742 "function baz() {}\n", NULL, "bar8.js"); 22743 22744 // Too much whitespace. 22745 SourceURLHelper("function foo() {}\n" 22746 "//# sourceURL=bar9.js\n" 22747 "//# sourceMappingURL=bar10.js\n", NULL, NULL); 22748 SourceURLHelper("function foo() {}\n" 22749 "//# sourceURL =bar11.js\n" 22750 "//# sourceMappingURL =bar12.js\n", NULL, NULL); 22751 22752 // Disallowed characters in value. 22753 SourceURLHelper("function foo() {}\n" 22754 "//# sourceURL=bar13 .js \n" 22755 "//# sourceMappingURL=bar14 .js \n", 22756 NULL, NULL); 22757 SourceURLHelper("function foo() {}\n" 22758 "//# sourceURL=bar15\t.js \n" 22759 "//# sourceMappingURL=bar16\t.js \n", 22760 NULL, NULL); 22761 SourceURLHelper("function foo() {}\n" 22762 "//# sourceURL=bar17'.js \n" 22763 "//# sourceMappingURL=bar18'.js \n", 22764 NULL, NULL); 22765 SourceURLHelper("function foo() {}\n" 22766 "//# sourceURL=bar19\".js \n" 22767 "//# sourceMappingURL=bar20\".js \n", 22768 NULL, NULL); 22769 22770 // Not too much whitespace. 22771 SourceURLHelper("function foo() {}\n" 22772 "//# sourceURL= bar21.js \n" 22773 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js"); 22774 } 22775 22776 22777 TEST(GetOwnPropertyDescriptor) { 22778 LocalContext env; 22779 v8::Isolate* isolate = env->GetIsolate(); 22780 v8::HandleScope scope(isolate); 22781 CompileRun( 22782 "var x = { value : 13};" 22783 "Object.defineProperty(x, 'p0', {value : 12});" 22784 "Object.defineProperty(x, 'p1', {" 22785 " set : function(value) { this.value = value; }," 22786 " get : function() { return this.value; }," 22787 "});"); 22788 Local<Object> x = Local<Object>::Cast( 22789 env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked()); 22790 Local<Value> desc = 22791 x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop")) 22792 .ToLocalChecked(); 22793 CHECK(desc->IsUndefined()); 22794 desc = 22795 x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked(); 22796 CHECK(v8_num(12) 22797 ->Equals(env.local(), Local<Object>::Cast(desc) 22798 ->Get(env.local(), v8_str("value")) 22799 .ToLocalChecked()) 22800 .FromJust()); 22801 desc = 22802 x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked(); 22803 Local<Function> set = 22804 Local<Function>::Cast(Local<Object>::Cast(desc) 22805 ->Get(env.local(), v8_str("set")) 22806 .ToLocalChecked()); 22807 Local<Function> get = 22808 Local<Function>::Cast(Local<Object>::Cast(desc) 22809 ->Get(env.local(), v8_str("get")) 22810 .ToLocalChecked()); 22811 CHECK(v8_num(13) 22812 ->Equals(env.local(), 22813 get->Call(env.local(), x, 0, NULL).ToLocalChecked()) 22814 .FromJust()); 22815 Local<Value> args[] = {v8_num(14)}; 22816 set->Call(env.local(), x, 1, args).ToLocalChecked(); 22817 CHECK(v8_num(14) 22818 ->Equals(env.local(), 22819 get->Call(env.local(), x, 0, NULL).ToLocalChecked()) 22820 .FromJust()); 22821 } 22822 22823 22824 TEST(Regress411877) { 22825 v8::Isolate* isolate = CcTest::isolate(); 22826 v8::HandleScope handle_scope(isolate); 22827 v8::Local<v8::ObjectTemplate> object_template = 22828 v8::ObjectTemplate::New(isolate); 22829 object_template->SetAccessCheckCallback(AccessCounter); 22830 22831 v8::Local<Context> context = Context::New(isolate); 22832 v8::Context::Scope context_scope(context); 22833 22834 CHECK(context->Global() 22835 ->Set(context, v8_str("o"), 22836 object_template->NewInstance(context).ToLocalChecked()) 22837 .FromJust()); 22838 CompileRun("Object.getOwnPropertyNames(o)"); 22839 } 22840 22841 22842 TEST(GetHiddenPropertyTableAfterAccessCheck) { 22843 v8::Isolate* isolate = CcTest::isolate(); 22844 v8::HandleScope handle_scope(isolate); 22845 v8::Local<v8::ObjectTemplate> object_template = 22846 v8::ObjectTemplate::New(isolate); 22847 object_template->SetAccessCheckCallback(AccessCounter); 22848 22849 v8::Local<Context> context = Context::New(isolate); 22850 v8::Context::Scope context_scope(context); 22851 22852 v8::Local<v8::Object> obj = 22853 object_template->NewInstance(context).ToLocalChecked(); 22854 obj->Set(context, v8_str("key"), v8_str("value")).FromJust(); 22855 obj->Delete(context, v8_str("key")).FromJust(); 22856 22857 obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")), 22858 v8_str("hidden value 2")) 22859 .FromJust(); 22860 } 22861 22862 22863 TEST(Regress411793) { 22864 v8::Isolate* isolate = CcTest::isolate(); 22865 v8::HandleScope handle_scope(isolate); 22866 v8::Local<v8::ObjectTemplate> object_template = 22867 v8::ObjectTemplate::New(isolate); 22868 object_template->SetAccessCheckCallback(AccessCounter); 22869 22870 v8::Local<Context> context = Context::New(isolate); 22871 v8::Context::Scope context_scope(context); 22872 22873 CHECK(context->Global() 22874 ->Set(context, v8_str("o"), 22875 object_template->NewInstance(context).ToLocalChecked()) 22876 .FromJust()); 22877 CompileRun( 22878 "Object.defineProperty(o, 'key', " 22879 " { get: function() {}, set: function() {} });"); 22880 } 22881 22882 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream { 22883 public: 22884 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {} 22885 22886 virtual size_t GetMoreData(const uint8_t** src) { 22887 // Unlike in real use cases, this function will never block. 22888 if (chunks_[index_] == NULL) { 22889 return 0; 22890 } 22891 // Copy the data, since the caller takes ownership of it. 22892 size_t len = strlen(chunks_[index_]); 22893 // We don't need to zero-terminate since we return the length. 22894 uint8_t* copy = new uint8_t[len]; 22895 memcpy(copy, chunks_[index_], len); 22896 *src = copy; 22897 ++index_; 22898 return len; 22899 } 22900 22901 // Helper for constructing a string from chunks (the compilation needs it 22902 // too). 22903 static char* FullSourceString(const char** chunks) { 22904 size_t total_len = 0; 22905 for (size_t i = 0; chunks[i] != NULL; ++i) { 22906 total_len += strlen(chunks[i]); 22907 } 22908 char* full_string = new char[total_len + 1]; 22909 size_t offset = 0; 22910 for (size_t i = 0; chunks[i] != NULL; ++i) { 22911 size_t len = strlen(chunks[i]); 22912 memcpy(full_string + offset, chunks[i], len); 22913 offset += len; 22914 } 22915 full_string[total_len] = 0; 22916 return full_string; 22917 } 22918 22919 private: 22920 const char** chunks_; 22921 unsigned index_; 22922 }; 22923 22924 22925 // Helper function for running streaming tests. 22926 void RunStreamingTest(const char** chunks, 22927 v8::ScriptCompiler::StreamedSource::Encoding encoding = 22928 v8::ScriptCompiler::StreamedSource::ONE_BYTE, 22929 bool expected_success = true, 22930 const char* expected_source_url = NULL, 22931 const char* expected_source_mapping_url = NULL) { 22932 LocalContext env; 22933 v8::Isolate* isolate = env->GetIsolate(); 22934 v8::HandleScope scope(isolate); 22935 v8::TryCatch try_catch(isolate); 22936 22937 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks), 22938 encoding); 22939 v8::ScriptCompiler::ScriptStreamingTask* task = 22940 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 22941 22942 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 22943 // task here in the main thread. 22944 task->Run(); 22945 delete task; 22946 22947 // Possible errors are only produced while compiling. 22948 CHECK_EQ(false, try_catch.HasCaught()); 22949 22950 v8::ScriptOrigin origin(v8_str("http://foo.com")); 22951 char* full_source = TestSourceStream::FullSourceString(chunks); 22952 v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile( 22953 env.local(), &source, v8_str(full_source), origin); 22954 if (expected_success) { 22955 CHECK(!script.IsEmpty()); 22956 v8::Local<Value> result( 22957 script.ToLocalChecked()->Run(env.local()).ToLocalChecked()); 22958 // All scripts are supposed to return the fixed value 13 when ran. 22959 CHECK_EQ(13, result->Int32Value(env.local()).FromJust()); 22960 CheckMagicComments(script.ToLocalChecked(), expected_source_url, 22961 expected_source_mapping_url); 22962 } else { 22963 CHECK(script.IsEmpty()); 22964 CHECK(try_catch.HasCaught()); 22965 } 22966 delete[] full_source; 22967 } 22968 22969 22970 TEST(StreamingSimpleScript) { 22971 // This script is unrealistically small, since no one chunk is enough to fill 22972 // the backing buffer of Scanner, let alone overflow it. 22973 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 22974 NULL}; 22975 RunStreamingTest(chunks); 22976 } 22977 22978 22979 TEST(StreamingBiggerScript) { 22980 const char* chunk1 = 22981 "function foo() {\n" 22982 " // Make this chunk sufficiently long so that it will overflow the\n" 22983 " // backing buffer of the Scanner.\n" 22984 " var i = 0;\n" 22985 " var result = 0;\n" 22986 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 22987 " result = 0;\n" 22988 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 22989 " result = 0;\n" 22990 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 22991 " result = 0;\n" 22992 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 22993 " return result;\n" 22994 "}\n"; 22995 const char* chunks[] = {chunk1, "foo(); ", NULL}; 22996 RunStreamingTest(chunks); 22997 } 22998 22999 23000 TEST(StreamingScriptWithParseError) { 23001 // Test that parse errors from streamed scripts are propagated correctly. 23002 { 23003 char chunk1[] = 23004 " // This will result in a parse error.\n" 23005 " var if else then foo"; 23006 char chunk2[] = " 13\n"; 23007 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23008 23009 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE, 23010 false); 23011 } 23012 // Test that the next script succeeds normally. 23013 { 23014 char chunk1[] = 23015 " // This will be parsed successfully.\n" 23016 " function foo() { return "; 23017 char chunk2[] = " 13; }\n"; 23018 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23019 23020 RunStreamingTest(chunks); 23021 } 23022 } 23023 23024 23025 TEST(StreamingUtf8Script) { 23026 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers 23027 // don't like it. 23028 const char* chunk1 = 23029 "function foo() {\n" 23030 " // This function will contain an UTF-8 character which is not in\n" 23031 " // ASCII.\n" 23032 " var foob\xec\x92\x81r = 13;\n" 23033 " return foob\xec\x92\x81r;\n" 23034 "}\n"; 23035 const char* chunks[] = {chunk1, "foo(); ", NULL}; 23036 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23037 } 23038 23039 23040 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) { 23041 // A sanity check to prove that the approach of splitting UTF-8 23042 // characters is correct. Here is an UTF-8 character which will take three 23043 // bytes. 23044 const char* reference = "\xec\x92\x81"; 23045 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned. 23046 23047 char chunk1[] = 23048 "function foo() {\n" 23049 " // This function will contain an UTF-8 character which is not in\n" 23050 " // ASCII.\n" 23051 " var foob"; 23052 char chunk2[] = 23053 "XXXr = 13;\n" 23054 " return foob\xec\x92\x81r;\n" 23055 "}\n"; 23056 for (int i = 0; i < 3; ++i) { 23057 chunk2[i] = reference[i]; 23058 } 23059 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23060 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23061 } 23062 23063 23064 TEST(StreamingUtf8ScriptWithSplitCharacters) { 23065 // Stream data where a multi-byte UTF-8 character is split between two data 23066 // chunks. 23067 const char* reference = "\xec\x92\x81"; 23068 char chunk1[] = 23069 "function foo() {\n" 23070 " // This function will contain an UTF-8 character which is not in\n" 23071 " // ASCII.\n" 23072 " var foobX"; 23073 char chunk2[] = 23074 "XXr = 13;\n" 23075 " return foob\xec\x92\x81r;\n" 23076 "}\n"; 23077 chunk1[strlen(chunk1) - 1] = reference[0]; 23078 chunk2[0] = reference[1]; 23079 chunk2[1] = reference[2]; 23080 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23081 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23082 } 23083 23084 23085 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) { 23086 // Tests edge cases which should still be decoded correctly. 23087 23088 // Case 1: a chunk contains only bytes for a split character (and no other 23089 // data). This kind of a chunk would be exceptionally small, but we should 23090 // still decode it correctly. 23091 const char* reference = "\xec\x92\x81"; 23092 // The small chunk is at the beginning of the split character 23093 { 23094 char chunk1[] = 23095 "function foo() {\n" 23096 " // This function will contain an UTF-8 character which is not in\n" 23097 " // ASCII.\n" 23098 " var foob"; 23099 char chunk2[] = "XX"; 23100 char chunk3[] = 23101 "Xr = 13;\n" 23102 " return foob\xec\x92\x81r;\n" 23103 "}\n"; 23104 chunk2[0] = reference[0]; 23105 chunk2[1] = reference[1]; 23106 chunk3[0] = reference[2]; 23107 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23108 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23109 } 23110 // The small chunk is at the end of a character 23111 { 23112 char chunk1[] = 23113 "function foo() {\n" 23114 " // This function will contain an UTF-8 character which is not in\n" 23115 " // ASCII.\n" 23116 " var foobX"; 23117 char chunk2[] = "XX"; 23118 char chunk3[] = 23119 "r = 13;\n" 23120 " return foob\xec\x92\x81r;\n" 23121 "}\n"; 23122 chunk1[strlen(chunk1) - 1] = reference[0]; 23123 chunk2[0] = reference[1]; 23124 chunk2[1] = reference[2]; 23125 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23126 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23127 } 23128 // Case 2: the script ends with a multi-byte character. Make sure that it's 23129 // decoded correctly and not just ignored. 23130 { 23131 char chunk1[] = 23132 "var foob\xec\x92\x81 = 13;\n" 23133 "foob\xec\x92\x81"; 23134 const char* chunks[] = {chunk1, NULL}; 23135 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23136 } 23137 } 23138 23139 23140 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { 23141 // Test cases where a UTF-8 character is split over several chunks. Those 23142 // cases are not supported (the embedder should give the data in big enough 23143 // chunks), but we shouldn't crash, just produce a parse error. 23144 const char* reference = "\xec\x92\x81"; 23145 char chunk1[] = 23146 "function foo() {\n" 23147 " // This function will contain an UTF-8 character which is not in\n" 23148 " // ASCII.\n" 23149 " var foobX"; 23150 char chunk2[] = "X"; 23151 char chunk3[] = 23152 "Xr = 13;\n" 23153 " return foob\xec\x92\x81r;\n" 23154 "}\n"; 23155 chunk1[strlen(chunk1) - 1] = reference[0]; 23156 chunk2[0] = reference[1]; 23157 chunk3[0] = reference[2]; 23158 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23159 23160 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 23161 } 23162 23163 23164 TEST(StreamingProducesParserCache) { 23165 i::FLAG_min_preparse_length = 0; 23166 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 23167 NULL}; 23168 23169 LocalContext env; 23170 v8::Isolate* isolate = env->GetIsolate(); 23171 v8::HandleScope scope(isolate); 23172 23173 v8::ScriptCompiler::StreamedSource source( 23174 new TestSourceStream(chunks), 23175 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 23176 v8::ScriptCompiler::ScriptStreamingTask* task = 23177 v8::ScriptCompiler::StartStreamingScript( 23178 isolate, &source, v8::ScriptCompiler::kProduceParserCache); 23179 23180 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 23181 // task here in the main thread. 23182 task->Run(); 23183 delete task; 23184 23185 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData(); 23186 CHECK(cached_data != NULL); 23187 CHECK(cached_data->data != NULL); 23188 CHECK(!cached_data->rejected); 23189 CHECK_GT(cached_data->length, 0); 23190 } 23191 23192 23193 TEST(StreamingWithDebuggingEnabledLate) { 23194 // The streaming parser can only parse lazily, i.e. inner functions are not 23195 // fully parsed. However, we may compile inner functions eagerly when 23196 // debugging. Make sure that we can deal with this when turning on debugging 23197 // after streaming parser has already finished parsing. 23198 i::FLAG_min_preparse_length = 0; 23199 const char* chunks[] = {"with({x:1}) {", 23200 " var foo = function foo(y) {", 23201 " return x + y;", 23202 " };", 23203 " foo(2);", 23204 "}", 23205 NULL}; 23206 23207 LocalContext env; 23208 v8::Isolate* isolate = env->GetIsolate(); 23209 v8::HandleScope scope(isolate); 23210 v8::TryCatch try_catch(isolate); 23211 23212 v8::ScriptCompiler::StreamedSource source( 23213 new TestSourceStream(chunks), 23214 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 23215 v8::ScriptCompiler::ScriptStreamingTask* task = 23216 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 23217 23218 task->Run(); 23219 delete task; 23220 23221 CHECK(!try_catch.HasCaught()); 23222 23223 v8::ScriptOrigin origin(v8_str("http://foo.com")); 23224 char* full_source = TestSourceStream::FullSourceString(chunks); 23225 23226 EnableDebugger(isolate); 23227 23228 v8::Local<Script> script = 23229 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source), 23230 origin) 23231 .ToLocalChecked(); 23232 23233 Maybe<uint32_t> result = 23234 script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local()); 23235 CHECK_EQ(3U, result.FromMaybe(0)); 23236 23237 delete[] full_source; 23238 23239 DisableDebugger(isolate); 23240 } 23241 23242 23243 TEST(StreamingScriptWithInvalidUtf8) { 23244 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a 23245 // chunk don't produce a crash. 23246 const char* reference = "\xec\x92\x81\x80\x80"; 23247 char chunk1[] = 23248 "function foo() {\n" 23249 " // This function will contain an UTF-8 character which is not in\n" 23250 " // ASCII.\n" 23251 " var foobXXXXX"; // Too many bytes which look like incomplete chars! 23252 char chunk2[] = 23253 "r = 13;\n" 23254 " return foob\xec\x92\x81\x80\x80r;\n" 23255 "}\n"; 23256 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i]; 23257 23258 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23259 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 23260 } 23261 23262 23263 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) { 23264 // Regression test: Stream data where there are several multi-byte UTF-8 23265 // characters in a sequence and one of them is split between two data chunks. 23266 const char* reference = "\xec\x92\x81"; 23267 char chunk1[] = 23268 "function foo() {\n" 23269 " // This function will contain an UTF-8 character which is not in\n" 23270 " // ASCII.\n" 23271 " var foob\xec\x92\x81X"; 23272 char chunk2[] = 23273 "XXr = 13;\n" 23274 " return foob\xec\x92\x81\xec\x92\x81r;\n" 23275 "}\n"; 23276 chunk1[strlen(chunk1) - 1] = reference[0]; 23277 chunk2[0] = reference[1]; 23278 chunk2[1] = reference[2]; 23279 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23280 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23281 } 23282 23283 23284 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) { 23285 // Another regression test, similar to the previous one. The difference is 23286 // that the split character is not the last one in the sequence. 23287 const char* reference = "\xec\x92\x81"; 23288 char chunk1[] = 23289 "function foo() {\n" 23290 " // This function will contain an UTF-8 character which is not in\n" 23291 " // ASCII.\n" 23292 " var foobX"; 23293 char chunk2[] = 23294 "XX\xec\x92\x81r = 13;\n" 23295 " return foob\xec\x92\x81\xec\x92\x81r;\n" 23296 "}\n"; 23297 chunk1[strlen(chunk1) - 1] = reference[0]; 23298 chunk2[0] = reference[1]; 23299 chunk2[1] = reference[2]; 23300 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23301 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23302 } 23303 23304 23305 TEST(StreamingWithHarmonyScopes) { 23306 // Don't use RunStreamingTest here so that both scripts get to use the same 23307 // LocalContext and HandleScope. 23308 LocalContext env; 23309 v8::Isolate* isolate = env->GetIsolate(); 23310 v8::HandleScope scope(isolate); 23311 23312 // First, run a script with a let variable. 23313 CompileRun("\"use strict\"; let x = 1;"); 23314 23315 // Then stream a script which (erroneously) tries to introduce the same 23316 // variable again. 23317 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL}; 23318 23319 v8::TryCatch try_catch(isolate); 23320 v8::ScriptCompiler::StreamedSource source( 23321 new TestSourceStream(chunks), 23322 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 23323 v8::ScriptCompiler::ScriptStreamingTask* task = 23324 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 23325 task->Run(); 23326 delete task; 23327 23328 // Parsing should succeed (the script will be parsed and compiled in a context 23329 // independent way, so the error is not detected). 23330 CHECK_EQ(false, try_catch.HasCaught()); 23331 23332 v8::ScriptOrigin origin(v8_str("http://foo.com")); 23333 char* full_source = TestSourceStream::FullSourceString(chunks); 23334 v8::Local<Script> script = 23335 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source), 23336 origin) 23337 .ToLocalChecked(); 23338 CHECK(!script.IsEmpty()); 23339 CHECK_EQ(false, try_catch.HasCaught()); 23340 23341 // Running the script exposes the error. 23342 CHECK(script->Run(env.local()).IsEmpty()); 23343 CHECK(try_catch.HasCaught()); 23344 delete[] full_source; 23345 } 23346 23347 23348 TEST(CodeCache) { 23349 v8::Isolate::CreateParams create_params; 23350 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 23351 23352 const char* source = "Math.sqrt(4)"; 23353 const char* origin = "code cache test"; 23354 v8::ScriptCompiler::CachedData* cache; 23355 23356 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 23357 { 23358 v8::Isolate::Scope iscope(isolate1); 23359 v8::HandleScope scope(isolate1); 23360 v8::Local<v8::Context> context = v8::Context::New(isolate1); 23361 v8::Context::Scope cscope(context); 23362 v8::Local<v8::String> source_string = v8_str(source); 23363 v8::ScriptOrigin script_origin(v8_str(origin)); 23364 v8::ScriptCompiler::Source source(source_string, script_origin); 23365 v8::ScriptCompiler::CompileOptions option = 23366 v8::ScriptCompiler::kProduceCodeCache; 23367 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked(); 23368 int length = source.GetCachedData()->length; 23369 uint8_t* cache_data = new uint8_t[length]; 23370 memcpy(cache_data, source.GetCachedData()->data, length); 23371 cache = new v8::ScriptCompiler::CachedData( 23372 cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned); 23373 } 23374 isolate1->Dispose(); 23375 23376 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 23377 { 23378 v8::Isolate::Scope iscope(isolate2); 23379 v8::HandleScope scope(isolate2); 23380 v8::Local<v8::Context> context = v8::Context::New(isolate2); 23381 v8::Context::Scope cscope(context); 23382 v8::Local<v8::String> source_string = v8_str(source); 23383 v8::ScriptOrigin script_origin(v8_str(origin)); 23384 v8::ScriptCompiler::Source source(source_string, script_origin, cache); 23385 v8::ScriptCompiler::CompileOptions option = 23386 v8::ScriptCompiler::kConsumeCodeCache; 23387 v8::Local<v8::Script> script; 23388 { 23389 i::DisallowCompilation no_compile( 23390 reinterpret_cast<i::Isolate*>(isolate2)); 23391 script = v8::ScriptCompiler::Compile(context, &source, option) 23392 .ToLocalChecked(); 23393 } 23394 CHECK_EQ(2, script->Run(context) 23395 .ToLocalChecked() 23396 ->ToInt32(context) 23397 .ToLocalChecked() 23398 ->Int32Value(context) 23399 .FromJust()); 23400 } 23401 isolate2->Dispose(); 23402 } 23403 23404 23405 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) { 23406 const char* garbage = "garbage garbage garbage garbage garbage garbage"; 23407 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage); 23408 int length = 16; 23409 v8::ScriptCompiler::CachedData* cached_data = 23410 new v8::ScriptCompiler::CachedData(data, length); 23411 CHECK(!cached_data->rejected); 23412 v8::ScriptOrigin origin(v8_str("origin")); 23413 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data); 23414 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 23415 v8::Local<v8::Script> script = 23416 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked(); 23417 CHECK(cached_data->rejected); 23418 CHECK_EQ( 23419 42, 23420 script->Run(context).ToLocalChecked()->Int32Value(context).FromJust()); 23421 } 23422 23423 23424 TEST(InvalidCacheData) { 23425 v8::V8::Initialize(); 23426 v8::HandleScope scope(CcTest::isolate()); 23427 LocalContext context; 23428 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache); 23429 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache); 23430 } 23431 23432 23433 TEST(ParserCacheRejectedGracefully) { 23434 i::FLAG_min_preparse_length = 0; 23435 v8::V8::Initialize(); 23436 v8::HandleScope scope(CcTest::isolate()); 23437 LocalContext context; 23438 // Produce valid cached data. 23439 v8::ScriptOrigin origin(v8_str("origin")); 23440 v8::Local<v8::String> source_str = v8_str("function foo() {}"); 23441 v8::ScriptCompiler::Source source(source_str, origin); 23442 v8::Local<v8::Script> script = 23443 v8::ScriptCompiler::Compile(context.local(), &source, 23444 v8::ScriptCompiler::kProduceParserCache) 23445 .ToLocalChecked(); 23446 USE(script); 23447 const v8::ScriptCompiler::CachedData* original_cached_data = 23448 source.GetCachedData(); 23449 CHECK(original_cached_data != NULL); 23450 CHECK(original_cached_data->data != NULL); 23451 CHECK(!original_cached_data->rejected); 23452 CHECK_GT(original_cached_data->length, 0); 23453 // Recompiling the same script with it won't reject the data. 23454 { 23455 v8::ScriptCompiler::Source source_with_cached_data( 23456 source_str, origin, 23457 new v8::ScriptCompiler::CachedData(original_cached_data->data, 23458 original_cached_data->length)); 23459 v8::Local<v8::Script> script = 23460 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data, 23461 v8::ScriptCompiler::kConsumeParserCache) 23462 .ToLocalChecked(); 23463 USE(script); 23464 const v8::ScriptCompiler::CachedData* new_cached_data = 23465 source_with_cached_data.GetCachedData(); 23466 CHECK(new_cached_data != NULL); 23467 CHECK(!new_cached_data->rejected); 23468 } 23469 // Compile an incompatible script with the cached data. The new script doesn't 23470 // have the same starting position for the function as the old one, so the old 23471 // cached data will be incompatible with it and will be rejected. 23472 { 23473 v8::Local<v8::String> incompatible_source_str = 23474 v8_str(" function foo() {}"); 23475 v8::ScriptCompiler::Source source_with_cached_data( 23476 incompatible_source_str, origin, 23477 new v8::ScriptCompiler::CachedData(original_cached_data->data, 23478 original_cached_data->length)); 23479 v8::Local<v8::Script> script = 23480 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data, 23481 v8::ScriptCompiler::kConsumeParserCache) 23482 .ToLocalChecked(); 23483 USE(script); 23484 const v8::ScriptCompiler::CachedData* new_cached_data = 23485 source_with_cached_data.GetCachedData(); 23486 CHECK(new_cached_data != NULL); 23487 CHECK(new_cached_data->rejected); 23488 } 23489 } 23490 23491 23492 TEST(StringConcatOverflow) { 23493 v8::V8::Initialize(); 23494 v8::HandleScope scope(CcTest::isolate()); 23495 RandomLengthOneByteResource* r = 23496 new RandomLengthOneByteResource(i::String::kMaxLength); 23497 v8::Local<v8::String> str = 23498 v8::String::NewExternalOneByte(CcTest::isolate(), r).ToLocalChecked(); 23499 CHECK(!str.IsEmpty()); 23500 v8::TryCatch try_catch(CcTest::isolate()); 23501 v8::Local<v8::String> result = v8::String::Concat(str, str); 23502 CHECK(result.IsEmpty()); 23503 CHECK(!try_catch.HasCaught()); 23504 } 23505 23506 23507 TEST(TurboAsmDisablesNeuter) { 23508 v8::V8::Initialize(); 23509 v8::HandleScope scope(CcTest::isolate()); 23510 LocalContext context; 23511 bool should_be_neuterable = !i::FLAG_turbo_asm; 23512 const char* load = 23513 "function Module(stdlib, foreign, heap) {" 23514 " 'use asm';" 23515 " var MEM32 = new stdlib.Int32Array(heap);" 23516 " function load() { return MEM32[0]; }" 23517 " return { load: load };" 23518 "}" 23519 "var buffer = new ArrayBuffer(4);" 23520 "Module(this, {}, buffer).load();" 23521 "buffer"; 23522 23523 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF. 23524 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>(); 23525 CHECK_EQ(should_be_neuterable, result->IsNeuterable()); 23526 23527 const char* store = 23528 "function Module(stdlib, foreign, heap) {" 23529 " 'use asm';" 23530 " var MEM32 = new stdlib.Int32Array(heap);" 23531 " function store() { MEM32[0] = 0; }" 23532 " return { store: store };" 23533 "}" 23534 "var buffer = new ArrayBuffer(4);" 23535 "Module(this, {}, buffer).store();" 23536 "buffer"; 23537 23538 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF. 23539 result = CompileRun(store).As<v8::ArrayBuffer>(); 23540 CHECK_EQ(should_be_neuterable, result->IsNeuterable()); 23541 } 23542 23543 23544 TEST(GetPrototypeAccessControl) { 23545 i::FLAG_allow_natives_syntax = true; 23546 v8::Isolate* isolate = CcTest::isolate(); 23547 v8::HandleScope handle_scope(isolate); 23548 LocalContext env; 23549 23550 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 23551 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 23552 23553 CHECK(env->Global() 23554 ->Set(env.local(), v8_str("prohibited"), 23555 obj_template->NewInstance(env.local()).ToLocalChecked()) 23556 .FromJust()); 23557 23558 CHECK(CompileRun( 23559 "function f() { return %_GetPrototype(prohibited); }" 23560 "%OptimizeFunctionOnNextCall(f);" 23561 "f();")->IsNull()); 23562 } 23563 23564 23565 TEST(GetPrototypeHidden) { 23566 i::FLAG_allow_natives_syntax = true; 23567 v8::Isolate* isolate = CcTest::isolate(); 23568 v8::HandleScope handle_scope(isolate); 23569 LocalContext env; 23570 23571 Local<FunctionTemplate> t = FunctionTemplate::New(isolate); 23572 t->SetHiddenPrototype(true); 23573 Local<Object> proto = t->GetFunction(env.local()) 23574 .ToLocalChecked() 23575 ->NewInstance(env.local()) 23576 .ToLocalChecked(); 23577 Local<Object> object = Object::New(isolate); 23578 Local<Object> proto2 = Object::New(isolate); 23579 object->SetPrototype(env.local(), proto).FromJust(); 23580 proto->SetPrototype(env.local(), proto2).FromJust(); 23581 23582 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust()); 23583 CHECK(env->Global()->Set(env.local(), v8_str("proto"), proto).FromJust()); 23584 CHECK(env->Global()->Set(env.local(), v8_str("proto2"), proto2).FromJust()); 23585 23586 v8::Local<v8::Value> result = CompileRun("%_GetPrototype(object)"); 23587 CHECK(result->Equals(env.local(), proto2).FromJust()); 23588 23589 result = CompileRun( 23590 "function f() { return %_GetPrototype(object); }" 23591 "%OptimizeFunctionOnNextCall(f);" 23592 "f()"); 23593 CHECK(result->Equals(env.local(), proto2).FromJust()); 23594 } 23595 23596 23597 TEST(ClassPrototypeCreationContext) { 23598 v8::Isolate* isolate = CcTest::isolate(); 23599 v8::HandleScope handle_scope(isolate); 23600 LocalContext env; 23601 23602 Local<Object> result = Local<Object>::Cast( 23603 CompileRun("'use strict'; class Example { }; Example.prototype")); 23604 CHECK(env.local() == result->CreationContext()); 23605 } 23606 23607 23608 TEST(SimpleStreamingScriptWithSourceURL) { 23609 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n", 23610 "//# sourceURL=bar2.js\n", NULL}; 23611 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, 23612 "bar2.js"); 23613 } 23614 23615 23616 TEST(StreamingScriptWithSplitSourceURL) { 23617 const char* chunks[] = {"function foo() { ret", "urn 13; } f", 23618 "oo();\n//# sourceURL=b", "ar2.js\n", NULL}; 23619 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, 23620 "bar2.js"); 23621 } 23622 23623 23624 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { 23625 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#", 23626 " sourceMappingURL=bar2.js\n", "foo();", NULL}; 23627 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL, 23628 "bar2.js"); 23629 } 23630 23631 23632 TEST(NewStringRangeError) { 23633 v8::Isolate* isolate = CcTest::isolate(); 23634 v8::HandleScope handle_scope(isolate); 23635 const int length = i::String::kMaxLength + 1; 23636 const int buffer_size = length * sizeof(uint16_t); 23637 void* buffer = malloc(buffer_size); 23638 if (buffer == NULL) return; 23639 memset(buffer, 'A', buffer_size); 23640 { 23641 v8::TryCatch try_catch(isolate); 23642 char* data = reinterpret_cast<char*>(buffer); 23643 CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, 23644 length) 23645 .IsEmpty()); 23646 CHECK(!try_catch.HasCaught()); 23647 } 23648 { 23649 v8::TryCatch try_catch(isolate); 23650 uint8_t* data = reinterpret_cast<uint8_t*>(buffer); 23651 CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal, 23652 length) 23653 .IsEmpty()); 23654 CHECK(!try_catch.HasCaught()); 23655 } 23656 { 23657 v8::TryCatch try_catch(isolate); 23658 uint16_t* data = reinterpret_cast<uint16_t*>(buffer); 23659 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal, 23660 length) 23661 .IsEmpty()); 23662 CHECK(!try_catch.HasCaught()); 23663 } 23664 free(buffer); 23665 } 23666 23667 23668 TEST(SealHandleScope) { 23669 v8::Isolate* isolate = CcTest::isolate(); 23670 v8::HandleScope handle_scope(isolate); 23671 LocalContext env; 23672 23673 v8::SealHandleScope seal(isolate); 23674 23675 // Should fail 23676 v8::Local<v8::Object> obj = v8::Object::New(isolate); 23677 23678 USE(obj); 23679 } 23680 23681 23682 TEST(SealHandleScopeNested) { 23683 v8::Isolate* isolate = CcTest::isolate(); 23684 v8::HandleScope handle_scope(isolate); 23685 LocalContext env; 23686 23687 v8::SealHandleScope seal(isolate); 23688 23689 { 23690 v8::HandleScope handle_scope(isolate); 23691 23692 // Should work 23693 v8::Local<v8::Object> obj = v8::Object::New(isolate); 23694 23695 USE(obj); 23696 } 23697 } 23698 23699 23700 static bool access_was_called = false; 23701 23702 23703 static bool AccessAlwaysAllowedWithFlag(Local<v8::Context> accessing_context, 23704 Local<v8::Object> accessed_object) { 23705 access_was_called = true; 23706 return true; 23707 } 23708 23709 23710 static bool AccessAlwaysBlockedWithFlag(Local<v8::Context> accessing_context, 23711 Local<v8::Object> accessed_object) { 23712 access_was_called = true; 23713 return false; 23714 } 23715 23716 23717 TEST(StrongModeAccessCheckAllowed) { 23718 i::FLAG_strong_mode = true; 23719 v8::Isolate* isolate = CcTest::isolate(); 23720 v8::HandleScope handle_scope(isolate); 23721 v8::Local<Value> value; 23722 access_was_called = false; 23723 23724 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 23725 23726 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 23727 obj_template->SetAccessCheckCallback(AccessAlwaysAllowedWithFlag); 23728 23729 // Create an environment 23730 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 23731 context0->Enter(); 23732 v8::Local<v8::Object> global0 = context0->Global(); 23733 global0->Set(context0, v8_str("object"), 23734 obj_template->NewInstance(context0).ToLocalChecked()) 23735 .FromJust(); 23736 { 23737 v8::TryCatch try_catch(isolate); 23738 value = CompileRun("'use strong'; object.x"); 23739 CHECK(!try_catch.HasCaught()); 23740 CHECK(!access_was_called); 23741 CHECK_EQ(42, value->Int32Value(context0).FromJust()); 23742 } 23743 { 23744 v8::TryCatch try_catch(isolate); 23745 value = CompileRun("'use strong'; object.foo"); 23746 CHECK(try_catch.HasCaught()); 23747 CHECK(!access_was_called); 23748 } 23749 { 23750 v8::TryCatch try_catch(isolate); 23751 value = CompileRun("'use strong'; object[10]"); 23752 CHECK(try_catch.HasCaught()); 23753 CHECK(!access_was_called); 23754 } 23755 23756 // Create an environment 23757 v8::Local<Context> context1 = Context::New(isolate); 23758 context1->Enter(); 23759 v8::Local<v8::Object> global1 = context1->Global(); 23760 global1->Set(context1, v8_str("object"), 23761 obj_template->NewInstance(context1).ToLocalChecked()) 23762 .FromJust(); 23763 { 23764 v8::TryCatch try_catch(isolate); 23765 value = CompileRun("'use strong'; object.x"); 23766 CHECK(!try_catch.HasCaught()); 23767 CHECK(access_was_called); 23768 CHECK_EQ(42, value->Int32Value(context1).FromJust()); 23769 } 23770 access_was_called = false; 23771 { 23772 v8::TryCatch try_catch(isolate); 23773 value = CompileRun("'use strong'; object.foo"); 23774 CHECK(try_catch.HasCaught()); 23775 CHECK(access_was_called); 23776 } 23777 access_was_called = false; 23778 { 23779 v8::TryCatch try_catch(isolate); 23780 value = CompileRun("'use strong'; object[10]"); 23781 CHECK(try_catch.HasCaught()); 23782 CHECK(access_was_called); 23783 } 23784 23785 context1->Exit(); 23786 context0->Exit(); 23787 } 23788 23789 23790 TEST(StrongModeAccessCheckBlocked) { 23791 i::FLAG_strong_mode = true; 23792 v8::Isolate* isolate = CcTest::isolate(); 23793 v8::HandleScope handle_scope(isolate); 23794 v8::Local<Value> value; 23795 access_was_called = false; 23796 23797 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 23798 23799 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 23800 obj_template->SetAccessCheckCallback(AccessAlwaysBlockedWithFlag); 23801 23802 // Create an environment 23803 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 23804 context0->Enter(); 23805 v8::Local<v8::Object> global0 = context0->Global(); 23806 global0->Set(context0, v8_str("object"), 23807 obj_template->NewInstance(context0).ToLocalChecked()) 23808 .FromJust(); 23809 { 23810 v8::TryCatch try_catch(isolate); 23811 value = CompileRun("'use strong'; object.x"); 23812 CHECK(!try_catch.HasCaught()); 23813 CHECK(!access_was_called); 23814 CHECK_EQ(42, value->Int32Value(context0).FromJust()); 23815 } 23816 { 23817 v8::TryCatch try_catch(isolate); 23818 value = CompileRun("'use strong'; object.foo"); 23819 CHECK(try_catch.HasCaught()); 23820 CHECK(!access_was_called); 23821 } 23822 { 23823 v8::TryCatch try_catch(isolate); 23824 value = CompileRun("'use strong'; object[10]"); 23825 CHECK(try_catch.HasCaught()); 23826 CHECK(!access_was_called); 23827 } 23828 23829 // Create an environment 23830 v8::Local<Context> context1 = Context::New(isolate); 23831 context1->Enter(); 23832 v8::Local<v8::Object> global1 = context1->Global(); 23833 global1->Set(context1, v8_str("object"), 23834 obj_template->NewInstance(context1).ToLocalChecked()) 23835 .FromJust(); 23836 { 23837 v8::TryCatch try_catch(isolate); 23838 value = CompileRun("'use strong'; object.x"); 23839 CHECK(try_catch.HasCaught()); 23840 CHECK(access_was_called); 23841 } 23842 access_was_called = false; 23843 { 23844 v8::TryCatch try_catch(isolate); 23845 value = CompileRun("'use strong'; object.foo"); 23846 CHECK(try_catch.HasCaught()); 23847 CHECK(access_was_called); 23848 } 23849 access_was_called = false; 23850 { 23851 v8::TryCatch try_catch(isolate); 23852 value = CompileRun("'use strong'; object[10]"); 23853 CHECK(try_catch.HasCaught()); 23854 CHECK(access_was_called); 23855 } 23856 23857 context1->Exit(); 23858 context0->Exit(); 23859 } 23860 23861 23862 TEST(StrongModeArityCallFromApi) { 23863 i::FLAG_strong_mode = true; 23864 LocalContext env; 23865 v8::Isolate* isolate = env->GetIsolate(); 23866 v8::HandleScope scope(isolate); 23867 Local<Function> fun; 23868 { 23869 v8::TryCatch try_catch(isolate); 23870 fun = Local<Function>::Cast(CompileRun( 23871 "function f(x) { 'use strong'; }" 23872 "f")); 23873 23874 CHECK(!try_catch.HasCaught()); 23875 } 23876 23877 { 23878 v8::TryCatch try_catch(isolate); 23879 CHECK(fun->Call(env.local(), v8::Undefined(isolate), 0, nullptr).IsEmpty()); 23880 CHECK(try_catch.HasCaught()); 23881 } 23882 23883 { 23884 v8::TryCatch try_catch(isolate); 23885 v8::Local<Value> args[] = {v8_num(42)}; 23886 fun->Call(env.local(), v8::Undefined(isolate), arraysize(args), args) 23887 .ToLocalChecked(); 23888 CHECK(!try_catch.HasCaught()); 23889 } 23890 23891 { 23892 v8::TryCatch try_catch(isolate); 23893 v8::Local<Value> args[] = {v8_num(42), v8_num(555)}; 23894 fun->Call(env.local(), v8::Undefined(isolate), arraysize(args), args) 23895 .ToLocalChecked(); 23896 CHECK(!try_catch.HasCaught()); 23897 } 23898 } 23899 23900 23901 TEST(StrongModeArityCallFromApi2) { 23902 i::FLAG_strong_mode = true; 23903 LocalContext env; 23904 v8::Isolate* isolate = env->GetIsolate(); 23905 v8::HandleScope scope(isolate); 23906 Local<Function> fun; 23907 { 23908 v8::TryCatch try_catch(isolate); 23909 fun = Local<Function>::Cast(CompileRun( 23910 "'use strong';" 23911 "function f(x) {}" 23912 "f")); 23913 23914 CHECK(!try_catch.HasCaught()); 23915 } 23916 23917 { 23918 v8::TryCatch try_catch(isolate); 23919 CHECK(fun->Call(env.local(), v8::Undefined(isolate), 0, nullptr).IsEmpty()); 23920 CHECK(try_catch.HasCaught()); 23921 } 23922 23923 { 23924 v8::TryCatch try_catch(isolate); 23925 v8::Local<Value> args[] = {v8_num(42)}; 23926 fun->Call(env.local(), v8::Undefined(isolate), arraysize(args), args) 23927 .ToLocalChecked(); 23928 CHECK(!try_catch.HasCaught()); 23929 } 23930 23931 { 23932 v8::TryCatch try_catch(isolate); 23933 v8::Local<Value> args[] = {v8_num(42), v8_num(555)}; 23934 fun->Call(env.local(), v8::Undefined(isolate), arraysize(args), args) 23935 .ToLocalChecked(); 23936 CHECK(!try_catch.HasCaught()); 23937 } 23938 } 23939 23940 23941 TEST(StrongObjectDelete) { 23942 i::FLAG_strong_mode = true; 23943 LocalContext env; 23944 v8::Isolate* isolate = env->GetIsolate(); 23945 v8::HandleScope scope(isolate); 23946 Local<Object> obj; 23947 { 23948 v8::TryCatch try_catch(isolate); 23949 obj = Local<Object>::Cast(CompileRun( 23950 "'use strong';" 23951 "({});")); 23952 CHECK(!try_catch.HasCaught()); 23953 } 23954 obj->DefineOwnProperty(env.local(), v8_str("foo"), v8_num(1), v8::None) 23955 .FromJust(); 23956 obj->DefineOwnProperty(env.local(), v8_str("2"), v8_num(1), v8::None) 23957 .FromJust(); 23958 CHECK(obj->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 23959 CHECK(obj->HasOwnProperty(env.local(), v8_str("2")).FromJust()); 23960 CHECK(!obj->Delete(env.local(), v8_str("foo")).FromJust()); 23961 CHECK(!obj->Delete(env.local(), 2).FromJust()); 23962 } 23963 23964 23965 static void ExtrasBindingTestRuntimeFunction( 23966 const v8::FunctionCallbackInfo<v8::Value>& args) { 23967 CHECK_EQ( 23968 3, 23969 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust()); 23970 args.GetReturnValue().Set(v8_num(7)); 23971 } 23972 23973 23974 TEST(ExtrasBindingObject) { 23975 v8::Isolate* isolate = CcTest::isolate(); 23976 v8::HandleScope handle_scope(isolate); 23977 LocalContext env; 23978 23979 // standalone.gypi ensures we include the test-extra.js file, which should 23980 // export the tested functions. 23981 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 23982 23983 auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive")) 23984 .ToLocalChecked() 23985 .As<v8::Function>(); 23986 auto undefined = v8::Undefined(isolate); 23987 auto result = func->Call(env.local(), undefined, 0, {}) 23988 .ToLocalChecked() 23989 .As<v8::Number>(); 23990 CHECK_EQ(5, result->Int32Value(env.local()).FromJust()); 23991 23992 v8::Local<v8::FunctionTemplate> runtimeFunction = 23993 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction); 23994 binding->Set(env.local(), v8_str("runtime"), 23995 runtimeFunction->GetFunction(env.local()).ToLocalChecked()) 23996 .FromJust(); 23997 func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime")) 23998 .ToLocalChecked() 23999 .As<v8::Function>(); 24000 result = func->Call(env.local(), undefined, 0, {}) 24001 .ToLocalChecked() 24002 .As<v8::Number>(); 24003 CHECK_EQ(7, result->Int32Value(env.local()).FromJust()); 24004 } 24005 24006 24007 TEST(ExperimentalExtras) { 24008 i::FLAG_experimental_extras = true; 24009 24010 v8::Isolate* isolate = CcTest::isolate(); 24011 v8::HandleScope handle_scope(isolate); 24012 LocalContext env; 24013 24014 // standalone.gypi ensures we include the test-experimental-extra.js file, 24015 // which should export the tested functions. 24016 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24017 24018 auto func = 24019 binding->Get(env.local(), v8_str("testExperimentalExtraShouldReturnTen")) 24020 .ToLocalChecked() 24021 .As<v8::Function>(); 24022 auto undefined = v8::Undefined(isolate); 24023 auto result = func->Call(env.local(), undefined, 0, {}) 24024 .ToLocalChecked() 24025 .As<v8::Number>(); 24026 CHECK_EQ(10, result->Int32Value(env.local()).FromJust()); 24027 24028 v8::Local<v8::FunctionTemplate> runtimeFunction = 24029 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction); 24030 binding->Set(env.local(), v8_str("runtime"), 24031 runtimeFunction->GetFunction(env.local()).ToLocalChecked()) 24032 .FromJust(); 24033 func = binding->Get(env.local(), 24034 v8_str("testExperimentalExtraShouldCallToRuntime")) 24035 .ToLocalChecked() 24036 .As<v8::Function>(); 24037 result = func->Call(env.local(), undefined, 0, {}) 24038 .ToLocalChecked() 24039 .As<v8::Number>(); 24040 CHECK_EQ(7, result->Int32Value(env.local()).FromJust()); 24041 } 24042 24043 24044 TEST(ExtrasUtilsObject) { 24045 LocalContext context; 24046 v8::Isolate* isolate = context->GetIsolate(); 24047 v8::HandleScope handle_scope(isolate); 24048 24049 LocalContext env; 24050 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24051 24052 auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils")) 24053 .ToLocalChecked() 24054 .As<v8::Function>(); 24055 auto undefined = v8::Undefined(isolate); 24056 auto result = func->Call(env.local(), undefined, 0, {}) 24057 .ToLocalChecked() 24058 .As<v8::Object>(); 24059 24060 auto private_symbol = result->Get(env.local(), v8_str("privateSymbol")) 24061 .ToLocalChecked() 24062 .As<v8::Symbol>(); 24063 i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol); 24064 CHECK_EQ(true, ips->IsPrivate()); 24065 24066 CompileRun("var result = 0; function store(x) { result = x; }"); 24067 auto store = CompileRun("store").As<v8::Function>(); 24068 24069 auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise")) 24070 .ToLocalChecked() 24071 .As<v8::Promise>(); 24072 fulfilled_promise->Then(env.local(), store).ToLocalChecked(); 24073 isolate->RunMicrotasks(); 24074 CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust()); 24075 24076 auto fulfilled_promise_2 = 24077 result->Get(env.local(), v8_str("fulfilledPromise2")) 24078 .ToLocalChecked() 24079 .As<v8::Promise>(); 24080 fulfilled_promise_2->Then(env.local(), store).ToLocalChecked(); 24081 isolate->RunMicrotasks(); 24082 CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust()); 24083 24084 auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise")) 24085 .ToLocalChecked() 24086 .As<v8::Promise>(); 24087 rejected_promise->Catch(env.local(), store).ToLocalChecked(); 24088 isolate->RunMicrotasks(); 24089 CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust()); 24090 } 24091 24092 24093 TEST(Map) { 24094 v8::Isolate* isolate = CcTest::isolate(); 24095 v8::HandleScope handle_scope(isolate); 24096 LocalContext env; 24097 24098 v8::Local<v8::Map> map = v8::Map::New(isolate); 24099 CHECK(map->IsObject()); 24100 CHECK(map->IsMap()); 24101 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype"))); 24102 CHECK_EQ(0U, map->Size()); 24103 24104 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])"); 24105 CHECK(val->IsMap()); 24106 map = v8::Local<v8::Map>::Cast(val); 24107 CHECK_EQ(2U, map->Size()); 24108 24109 v8::Local<v8::Array> contents = map->AsArray(); 24110 CHECK_EQ(4U, contents->Length()); 24111 CHECK_EQ( 24112 1, 24113 contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value()); 24114 CHECK_EQ( 24115 2, 24116 contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value()); 24117 CHECK_EQ( 24118 3, 24119 contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value()); 24120 CHECK_EQ( 24121 4, 24122 contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value()); 24123 24124 CHECK_EQ(2U, map->Size()); 24125 24126 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); 24127 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); 24128 24129 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); 24130 CHECK(!map->Has(env.local(), map).FromJust()); 24131 24132 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1)) 24133 .ToLocalChecked() 24134 ->Int32Value(env.local()) 24135 .FromJust()); 24136 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3)) 24137 .ToLocalChecked() 24138 ->Int32Value(env.local()) 24139 .FromJust()); 24140 24141 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42)) 24142 .ToLocalChecked() 24143 ->IsUndefined()); 24144 24145 CHECK(!map->Set(env.local(), map, map).IsEmpty()); 24146 CHECK_EQ(3U, map->Size()); 24147 CHECK(map->Has(env.local(), map).FromJust()); 24148 24149 CHECK(map->Delete(env.local(), map).FromJust()); 24150 CHECK_EQ(2U, map->Size()); 24151 CHECK(!map->Has(env.local(), map).FromJust()); 24152 CHECK(!map->Delete(env.local(), map).FromJust()); 24153 24154 map->Clear(); 24155 CHECK_EQ(0U, map->Size()); 24156 } 24157 24158 24159 TEST(Set) { 24160 v8::Isolate* isolate = CcTest::isolate(); 24161 v8::HandleScope handle_scope(isolate); 24162 LocalContext env; 24163 24164 v8::Local<v8::Set> set = v8::Set::New(isolate); 24165 CHECK(set->IsObject()); 24166 CHECK(set->IsSet()); 24167 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype"))); 24168 CHECK_EQ(0U, set->Size()); 24169 24170 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])"); 24171 CHECK(val->IsSet()); 24172 set = v8::Local<v8::Set>::Cast(val); 24173 CHECK_EQ(2U, set->Size()); 24174 24175 v8::Local<v8::Array> keys = set->AsArray(); 24176 CHECK_EQ(2U, keys->Length()); 24177 CHECK_EQ(1, 24178 keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value()); 24179 CHECK_EQ(2, 24180 keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value()); 24181 24182 CHECK_EQ(2U, set->Size()); 24183 24184 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); 24185 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); 24186 24187 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); 24188 CHECK(!set->Has(env.local(), set).FromJust()); 24189 24190 CHECK(!set->Add(env.local(), set).IsEmpty()); 24191 CHECK_EQ(3U, set->Size()); 24192 CHECK(set->Has(env.local(), set).FromJust()); 24193 24194 CHECK(set->Delete(env.local(), set).FromJust()); 24195 CHECK_EQ(2U, set->Size()); 24196 CHECK(!set->Has(env.local(), set).FromJust()); 24197 CHECK(!set->Delete(env.local(), set).FromJust()); 24198 24199 set->Clear(); 24200 CHECK_EQ(0U, set->Size()); 24201 } 24202 24203 24204 TEST(CompatibleReceiverCheckOnCachedICHandler) { 24205 v8::Isolate* isolate = CcTest::isolate(); 24206 v8::HandleScope scope(isolate); 24207 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate); 24208 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent); 24209 auto returns_42 = 24210 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature); 24211 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42); 24212 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate); 24213 child->Inherit(parent); 24214 LocalContext env; 24215 CHECK(env->Global() 24216 ->Set(env.local(), v8_str("Child"), 24217 child->GetFunction(env.local()).ToLocalChecked()) 24218 .FromJust()); 24219 24220 // Make sure there's a compiled stub for "Child.prototype.age" in the cache. 24221 CompileRun( 24222 "var real = new Child();\n" 24223 "for (var i = 0; i < 3; ++i) {\n" 24224 " real.age;\n" 24225 "}\n"); 24226 24227 // Check that the cached stub is never used. 24228 ExpectInt32( 24229 "var fake = Object.create(Child.prototype);\n" 24230 "var result = 0;\n" 24231 "function test(d) {\n" 24232 " if (d == 3) return;\n" 24233 " try {\n" 24234 " fake.age;\n" 24235 " result = 1;\n" 24236 " } catch (e) {\n" 24237 " }\n" 24238 " test(d+1);\n" 24239 "}\n" 24240 "test(0);\n" 24241 "result;\n", 24242 0); 24243 } 24244 24245 class FutexInterruptionThread : public v8::base::Thread { 24246 public: 24247 explicit FutexInterruptionThread(v8::Isolate* isolate) 24248 : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {} 24249 24250 virtual void Run() { 24251 // Wait a bit before terminating. 24252 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 24253 isolate_->TerminateExecution(); 24254 } 24255 24256 private: 24257 v8::Isolate* isolate_; 24258 }; 24259 24260 24261 TEST(FutexInterruption) { 24262 i::FLAG_harmony_sharedarraybuffer = true; 24263 v8::Isolate* isolate = CcTest::isolate(); 24264 v8::HandleScope scope(isolate); 24265 LocalContext env; 24266 24267 FutexInterruptionThread timeout_thread(isolate); 24268 24269 v8::TryCatch try_catch(CcTest::isolate()); 24270 timeout_thread.Start(); 24271 24272 CompileRun( 24273 "var ab = new SharedArrayBuffer(4);" 24274 "var i32a = new Int32Array(ab);" 24275 "Atomics.futexWait(i32a, 0, 0);"); 24276 CHECK(try_catch.HasTerminated()); 24277 timeout_thread.Join(); 24278 } 24279 24280 24281 TEST(EstimatedContextSize) { 24282 v8::Isolate* isolate = CcTest::isolate(); 24283 v8::HandleScope scope(isolate); 24284 LocalContext env; 24285 CHECK(50000 < env->EstimatedSize()); 24286 } 24287 24288 24289 static int nb_uncaught_exception_callback_calls = 0; 24290 24291 24292 bool NoAbortOnUncaughtException(v8::Isolate* isolate) { 24293 ++nb_uncaught_exception_callback_calls; 24294 return false; 24295 } 24296 24297 24298 TEST(AbortOnUncaughtExceptionNoAbort) { 24299 v8::Isolate* isolate = CcTest::isolate(); 24300 v8::HandleScope handle_scope(isolate); 24301 v8::Local<v8::ObjectTemplate> global_template = 24302 v8::ObjectTemplate::New(isolate); 24303 LocalContext env(NULL, global_template); 24304 24305 i::FLAG_abort_on_uncaught_exception = true; 24306 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException); 24307 24308 CompileRun("function boom() { throw new Error(\"boom\") }"); 24309 24310 v8::Local<v8::Object> global_object = env->Global(); 24311 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 24312 global_object->Get(env.local(), v8_str("boom")).ToLocalChecked()); 24313 24314 CHECK(foo->Call(env.local(), global_object, 0, NULL).IsEmpty()); 24315 24316 CHECK_EQ(1, nb_uncaught_exception_callback_calls); 24317 } 24318 24319 24320 TEST(AccessCheckedIsConcatSpreadable) { 24321 i::FLAG_harmony_concat_spreadable = true; 24322 v8::Isolate* isolate = CcTest::isolate(); 24323 HandleScope scope(isolate); 24324 LocalContext env; 24325 24326 // Object with access check 24327 Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate); 24328 spreadable_template->SetAccessCheckCallback(AccessBlocker); 24329 spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate), 24330 v8::Boolean::New(isolate, true)); 24331 Local<Object> object = 24332 spreadable_template->NewInstance(env.local()).ToLocalChecked(); 24333 24334 allowed_access = true; 24335 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust()); 24336 object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust(); 24337 object->Set(env.local(), 0U, v8_str("a")).FromJust(); 24338 object->Set(env.local(), 1U, v8_str("b")).FromJust(); 24339 24340 // Access check is allowed, and the object is spread 24341 CompileRun("var result = [].concat(object)"); 24342 ExpectTrue("Array.isArray(result)"); 24343 ExpectString("result[0]", "a"); 24344 ExpectString("result[1]", "b"); 24345 ExpectTrue("result.length === 2"); 24346 ExpectTrue("object[Symbol.isConcatSpreadable]"); 24347 24348 // If access check fails, the value of @@isConcatSpreadable is ignored 24349 allowed_access = false; 24350 CompileRun("var result = [].concat(object)"); 24351 ExpectTrue("Array.isArray(result)"); 24352 ExpectTrue("result[0] === object"); 24353 ExpectTrue("result.length === 1"); 24354 ExpectTrue("object[Symbol.isConcatSpreadable] === undefined"); 24355 } 24356 24357 24358 TEST(AccessCheckedToStringTag) { 24359 i::FLAG_harmony_tostring = true; 24360 v8::Isolate* isolate = CcTest::isolate(); 24361 HandleScope scope(isolate); 24362 LocalContext env; 24363 24364 // Object with access check 24365 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); 24366 object_template->SetAccessCheckCallback(AccessBlocker); 24367 Local<Object> object = 24368 object_template->NewInstance(env.local()).ToLocalChecked(); 24369 24370 allowed_access = true; 24371 env->Global()->Set(env.local(), v8_str("object"), object).FromJust(); 24372 object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello")) 24373 .FromJust(); 24374 24375 // Access check is allowed, and the toStringTag is read 24376 CompileRun("var result = Object.prototype.toString.call(object)"); 24377 ExpectString("result", "[object hello]"); 24378 ExpectString("object[Symbol.toStringTag]", "hello"); 24379 24380 // ToString through the API should succeed too. 24381 String::Utf8Value result_allowed( 24382 object->ObjectProtoToString(env.local()).ToLocalChecked()); 24383 CHECK_EQ(0, strcmp(*result_allowed, "[object hello]")); 24384 24385 // If access check fails, the value of @@toStringTag is ignored 24386 allowed_access = false; 24387 CompileRun("var result = Object.prototype.toString.call(object)"); 24388 ExpectString("result", "[object Object]"); 24389 ExpectTrue("object[Symbol.toStringTag] === undefined"); 24390 24391 // ToString through the API should also fail. 24392 String::Utf8Value result_denied( 24393 object->ObjectProtoToString(env.local()).ToLocalChecked()); 24394 CHECK_EQ(0, strcmp(*result_denied, "[object Object]")); 24395 } 24396 24397 24398 TEST(ObjectTemplateIntrinsics) { 24399 v8::Isolate* isolate = CcTest::isolate(); 24400 v8::HandleScope scope(isolate); 24401 LocalContext env; 24402 24403 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); 24404 object_template->SetIntrinsicDataProperty(v8_str("values"), 24405 v8::kArrayProto_values); 24406 Local<Object> object = 24407 object_template->NewInstance(env.local()).ToLocalChecked(); 24408 24409 CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust()); 24410 ExpectString("typeof obj1.values", "function"); 24411 24412 auto values = Local<Function>::Cast( 24413 object->Get(env.local(), v8_str("values")).ToLocalChecked()); 24414 auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values)); 24415 auto ctx = v8::Utils::OpenHandle(*env.local()); 24416 CHECK_EQ(fn->GetCreationContext(), *ctx); 24417 24418 { 24419 LocalContext env2; 24420 Local<Object> object2 = 24421 object_template->NewInstance(env2.local()).ToLocalChecked(); 24422 CHECK( 24423 env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust()); 24424 ExpectString("typeof obj2.values", "function"); 24425 CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(), 24426 *object2->Get(env2.local(), v8_str("values")).ToLocalChecked()); 24427 24428 auto values2 = Local<Function>::Cast( 24429 object2->Get(env2.local(), v8_str("values")).ToLocalChecked()); 24430 auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2)); 24431 auto ctx2 = v8::Utils::OpenHandle(*env2.local()); 24432 CHECK_EQ(fn2->GetCreationContext(), *ctx2); 24433 } 24434 } 24435 24436 24437 TEST(Proxy) { 24438 i::FLAG_harmony_proxies = true; 24439 LocalContext context; 24440 v8::Isolate* isolate = CcTest::isolate(); 24441 v8::HandleScope scope(isolate); 24442 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>(); 24443 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>(); 24444 24445 v8::Local<v8::Proxy> proxy = 24446 v8::Proxy::New(context.local(), target, handler).ToLocalChecked(); 24447 CHECK(proxy->IsProxy()); 24448 CHECK(!target->IsProxy()); 24449 CHECK(!proxy->IsRevoked()); 24450 CHECK(proxy->GetTarget()->SameValue(target)); 24451 CHECK(proxy->GetHandler()->SameValue(handler)); 24452 24453 proxy->Revoke(); 24454 CHECK(proxy->IsProxy()); 24455 CHECK(!target->IsProxy()); 24456 CHECK(proxy->IsRevoked()); 24457 CHECK(proxy->GetTarget()->SameValue(target)); 24458 CHECK(proxy->GetHandler()->IsNull()); 24459 } 24460