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/profiler/cpu-profiler.h" 51 #include "src/unicode-inl.h" 52 #include "src/utils.h" 53 #include "src/vm-state.h" 54 #include "test/cctest/heap/heap-tester.h" 55 #include "test/cctest/heap/heap-utils.h" 56 57 static const bool kLogThreading = false; 58 59 using ::v8::Boolean; 60 using ::v8::BooleanObject; 61 using ::v8::Context; 62 using ::v8::Extension; 63 using ::v8::Function; 64 using ::v8::FunctionTemplate; 65 using ::v8::HandleScope; 66 using ::v8::Local; 67 using ::v8::Maybe; 68 using ::v8::Message; 69 using ::v8::MessageCallback; 70 using ::v8::Name; 71 using ::v8::None; 72 using ::v8::Object; 73 using ::v8::ObjectTemplate; 74 using ::v8::Persistent; 75 using ::v8::PropertyAttribute; 76 using ::v8::Script; 77 using ::v8::StackTrace; 78 using ::v8::String; 79 using ::v8::Symbol; 80 using ::v8::TryCatch; 81 using ::v8::Undefined; 82 using ::v8::UniqueId; 83 using ::v8::V8; 84 using ::v8::Value; 85 86 87 #define THREADED_PROFILED_TEST(Name) \ 88 static void Test##Name(); \ 89 TEST(Name##WithProfiler) { \ 90 RunWithProfiler(&Test##Name); \ 91 } \ 92 THREADED_TEST(Name) 93 94 95 void RunWithProfiler(void (*test)()) { 96 LocalContext env; 97 v8::HandleScope scope(env->GetIsolate()); 98 v8::Local<v8::String> profile_name = v8_str("my_profile1"); 99 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 100 101 cpu_profiler->StartProfiling(profile_name); 102 (*test)(); 103 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles(); 104 } 105 106 107 static int signature_callback_count; 108 static Local<Value> signature_expected_receiver; 109 static void IncrementingSignatureCallback( 110 const v8::FunctionCallbackInfo<v8::Value>& args) { 111 ApiTestFuzzer::Fuzz(); 112 signature_callback_count++; 113 CHECK(signature_expected_receiver->Equals( 114 args.GetIsolate()->GetCurrentContext(), 115 args.Holder()) 116 .FromJust()); 117 CHECK(signature_expected_receiver->Equals( 118 args.GetIsolate()->GetCurrentContext(), 119 args.This()) 120 .FromJust()); 121 v8::Local<v8::Array> result = 122 v8::Array::New(args.GetIsolate(), args.Length()); 123 for (int i = 0; i < args.Length(); i++) { 124 CHECK(result->Set(args.GetIsolate()->GetCurrentContext(), 125 v8::Integer::New(args.GetIsolate(), i), args[i]) 126 .FromJust()); 127 } 128 args.GetReturnValue().Set(result); 129 } 130 131 132 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) { 133 info.GetReturnValue().Set(42); 134 } 135 136 137 // Tests that call v8::V8::Dispose() cannot be threaded. 138 UNINITIALIZED_TEST(InitializeAndDisposeOnce) { 139 CHECK(v8::V8::Initialize()); 140 CHECK(v8::V8::Dispose()); 141 } 142 143 144 // Tests that call v8::V8::Dispose() cannot be threaded. 145 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) { 146 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 147 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 148 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 149 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 150 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 151 } 152 153 154 THREADED_TEST(Handles) { 155 v8::HandleScope scope(CcTest::isolate()); 156 Local<Context> local_env; 157 { 158 LocalContext env; 159 local_env = env.local(); 160 } 161 162 // Local context should still be live. 163 CHECK(!local_env.IsEmpty()); 164 local_env->Enter(); 165 166 v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); 167 CHECK(!undef.IsEmpty()); 168 CHECK(undef->IsUndefined()); 169 170 const char* source = "1 + 2 + 3"; 171 Local<Script> script = v8_compile(source); 172 CHECK_EQ(6, v8_run_int32value(script)); 173 174 local_env->Exit(); 175 } 176 177 178 THREADED_TEST(IsolateOfContext) { 179 v8::HandleScope scope(CcTest::isolate()); 180 v8::Local<Context> env = Context::New(CcTest::isolate()); 181 182 CHECK(!env->GetIsolate()->InContext()); 183 CHECK(env->GetIsolate() == CcTest::isolate()); 184 env->Enter(); 185 CHECK(env->GetIsolate()->InContext()); 186 CHECK(env->GetIsolate() == CcTest::isolate()); 187 env->Exit(); 188 CHECK(!env->GetIsolate()->InContext()); 189 CHECK(env->GetIsolate() == CcTest::isolate()); 190 } 191 192 193 static void TestSignature(const char* loop_js, Local<Value> receiver, 194 v8::Isolate* isolate) { 195 i::ScopedVector<char> source(200); 196 i::SNPrintF(source, 197 "for (var i = 0; i < 10; i++) {" 198 " %s" 199 "}", 200 loop_js); 201 signature_callback_count = 0; 202 signature_expected_receiver = receiver; 203 bool expected_to_throw = receiver.IsEmpty(); 204 v8::TryCatch try_catch(isolate); 205 CompileRun(source.start()); 206 CHECK_EQ(expected_to_throw, try_catch.HasCaught()); 207 if (!expected_to_throw) { 208 CHECK_EQ(10, signature_callback_count); 209 } else { 210 CHECK(v8_str("TypeError: Illegal invocation") 211 ->Equals(isolate->GetCurrentContext(), 212 try_catch.Exception() 213 ->ToString(isolate->GetCurrentContext()) 214 .ToLocalChecked()) 215 .FromJust()); 216 } 217 } 218 219 220 THREADED_TEST(ReceiverSignature) { 221 LocalContext env; 222 v8::Isolate* isolate = env->GetIsolate(); 223 v8::HandleScope scope(isolate); 224 // Setup templates. 225 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 226 v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun); 227 v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New( 228 isolate, IncrementingSignatureCallback, Local<Value>(), sig); 229 v8::Local<v8::FunctionTemplate> callback = 230 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback); 231 v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate); 232 sub_fun->Inherit(fun); 233 v8::Local<v8::FunctionTemplate> unrel_fun = 234 v8::FunctionTemplate::New(isolate); 235 // Install properties. 236 v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); 237 fun_proto->Set(v8_str("prop_sig"), callback_sig); 238 fun_proto->Set(v8_str("prop"), callback); 239 fun_proto->SetAccessorProperty( 240 v8_str("accessor_sig"), callback_sig, callback_sig); 241 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); 242 // Instantiate templates. 243 Local<Value> fun_instance = 244 fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 245 Local<Value> sub_fun_instance = 246 sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 247 // Setup global variables. 248 CHECK(env->Global() 249 ->Set(env.local(), v8_str("Fun"), 250 fun->GetFunction(env.local()).ToLocalChecked()) 251 .FromJust()); 252 CHECK(env->Global() 253 ->Set(env.local(), v8_str("UnrelFun"), 254 unrel_fun->GetFunction(env.local()).ToLocalChecked()) 255 .FromJust()); 256 CHECK(env->Global() 257 ->Set(env.local(), v8_str("fun_instance"), fun_instance) 258 .FromJust()); 259 CHECK(env->Global() 260 ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance) 261 .FromJust()); 262 CompileRun( 263 "var accessor_sig_key = 'accessor_sig';" 264 "var accessor_key = 'accessor';" 265 "var prop_sig_key = 'prop_sig';" 266 "var prop_key = 'prop';" 267 "" 268 "function copy_props(obj) {" 269 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" 270 " var source = Fun.prototype;" 271 " for (var i in keys) {" 272 " var key = keys[i];" 273 " var desc = Object.getOwnPropertyDescriptor(source, key);" 274 " Object.defineProperty(obj, key, desc);" 275 " }" 276 "}" 277 "" 278 "var obj = {};" 279 "copy_props(obj);" 280 "var unrel = new UnrelFun();" 281 "copy_props(unrel);"); 282 // Test with and without ICs 283 const char* test_objects[] = { 284 "fun_instance", "sub_fun_instance", "obj", "unrel" }; 285 unsigned bad_signature_start_offset = 2; 286 for (unsigned i = 0; i < arraysize(test_objects); i++) { 287 i::ScopedVector<char> source(200); 288 i::SNPrintF( 289 source, "var test_object = %s; test_object", test_objects[i]); 290 Local<Value> test_object = CompileRun(source.start()); 291 TestSignature("test_object.prop();", test_object, isolate); 292 TestSignature("test_object.accessor;", test_object, isolate); 293 TestSignature("test_object[accessor_key];", test_object, isolate); 294 TestSignature("test_object.accessor = 1;", test_object, isolate); 295 TestSignature("test_object[accessor_key] = 1;", test_object, isolate); 296 if (i >= bad_signature_start_offset) test_object = Local<Value>(); 297 TestSignature("test_object.prop_sig();", test_object, isolate); 298 TestSignature("test_object.accessor_sig;", test_object, isolate); 299 TestSignature("test_object[accessor_sig_key];", test_object, isolate); 300 TestSignature("test_object.accessor_sig = 1;", test_object, isolate); 301 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate); 302 } 303 } 304 305 306 THREADED_TEST(HulIgennem) { 307 LocalContext env; 308 v8::Isolate* isolate = env->GetIsolate(); 309 v8::HandleScope scope(isolate); 310 v8::Local<v8::Primitive> undef = v8::Undefined(isolate); 311 Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked(); 312 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 313 undef_str->WriteUtf8(value); 314 CHECK_EQ(0, strcmp(value, "undefined")); 315 i::DeleteArray(value); 316 } 317 318 319 THREADED_TEST(Access) { 320 LocalContext env; 321 v8::Isolate* isolate = env->GetIsolate(); 322 v8::HandleScope scope(isolate); 323 Local<v8::Object> obj = v8::Object::New(isolate); 324 Local<Value> foo_before = 325 obj->Get(env.local(), v8_str("foo")).ToLocalChecked(); 326 CHECK(foo_before->IsUndefined()); 327 Local<String> bar_str = v8_str("bar"); 328 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust()); 329 Local<Value> foo_after = 330 obj->Get(env.local(), v8_str("foo")).ToLocalChecked(); 331 CHECK(!foo_after->IsUndefined()); 332 CHECK(foo_after->IsString()); 333 CHECK(bar_str->Equals(env.local(), foo_after).FromJust()); 334 } 335 336 337 THREADED_TEST(AccessElement) { 338 LocalContext env; 339 v8::HandleScope scope(env->GetIsolate()); 340 Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 341 Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked(); 342 CHECK(before->IsUndefined()); 343 Local<String> bar_str = v8_str("bar"); 344 CHECK(obj->Set(env.local(), 1, bar_str).FromJust()); 345 Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked(); 346 CHECK(!after->IsUndefined()); 347 CHECK(after->IsString()); 348 CHECK(bar_str->Equals(env.local(), after).FromJust()); 349 350 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 351 CHECK(v8_str("a") 352 ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked()) 353 .FromJust()); 354 CHECK(v8_str("b") 355 ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked()) 356 .FromJust()); 357 } 358 359 360 THREADED_TEST(Script) { 361 LocalContext env; 362 v8::HandleScope scope(env->GetIsolate()); 363 const char* source = "1 + 2 + 3"; 364 Local<Script> script = v8_compile(source); 365 CHECK_EQ(6, v8_run_int32value(script)); 366 } 367 368 369 class TestResource: public String::ExternalStringResource { 370 public: 371 explicit TestResource(uint16_t* data, int* counter = NULL, 372 bool owning_data = true) 373 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { 374 while (data[length_]) ++length_; 375 } 376 377 ~TestResource() { 378 if (owning_data_) i::DeleteArray(data_); 379 if (counter_ != NULL) ++*counter_; 380 } 381 382 const uint16_t* data() const { 383 return data_; 384 } 385 386 size_t length() const { 387 return length_; 388 } 389 390 private: 391 uint16_t* data_; 392 size_t length_; 393 int* counter_; 394 bool owning_data_; 395 }; 396 397 398 class TestOneByteResource : public String::ExternalOneByteStringResource { 399 public: 400 explicit TestOneByteResource(const char* data, int* counter = NULL, 401 size_t offset = 0) 402 : orig_data_(data), 403 data_(data + offset), 404 length_(strlen(data) - offset), 405 counter_(counter) {} 406 407 ~TestOneByteResource() { 408 i::DeleteArray(orig_data_); 409 if (counter_ != NULL) ++*counter_; 410 } 411 412 const char* data() const { 413 return data_; 414 } 415 416 size_t length() const { 417 return length_; 418 } 419 420 private: 421 const char* orig_data_; 422 const char* data_; 423 size_t length_; 424 int* counter_; 425 }; 426 427 428 THREADED_TEST(ScriptUsingStringResource) { 429 int dispose_count = 0; 430 const char* c_source = "1 + 2 * 3"; 431 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 432 { 433 LocalContext env; 434 v8::HandleScope scope(env->GetIsolate()); 435 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 436 Local<String> source = 437 String::NewExternalTwoByte(env->GetIsolate(), resource) 438 .ToLocalChecked(); 439 Local<Script> script = v8_compile(source); 440 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 441 CHECK(value->IsNumber()); 442 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 443 CHECK(source->IsExternal()); 444 CHECK_EQ(resource, 445 static_cast<TestResource*>(source->GetExternalStringResource())); 446 String::Encoding encoding = String::UNKNOWN_ENCODING; 447 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 448 source->GetExternalStringResourceBase(&encoding)); 449 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 450 CcTest::heap()->CollectAllGarbage(); 451 CHECK_EQ(0, dispose_count); 452 } 453 CcTest::i_isolate()->compilation_cache()->Clear(); 454 CcTest::heap()->CollectAllAvailableGarbage(); 455 CHECK_EQ(1, dispose_count); 456 } 457 458 459 THREADED_TEST(ScriptUsingOneByteStringResource) { 460 int dispose_count = 0; 461 const char* c_source = "1 + 2 * 3"; 462 { 463 LocalContext env; 464 v8::HandleScope scope(env->GetIsolate()); 465 TestOneByteResource* resource = 466 new TestOneByteResource(i::StrDup(c_source), &dispose_count); 467 Local<String> source = 468 String::NewExternalOneByte(env->GetIsolate(), resource) 469 .ToLocalChecked(); 470 CHECK(source->IsExternalOneByte()); 471 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 472 source->GetExternalOneByteStringResource()); 473 String::Encoding encoding = String::UNKNOWN_ENCODING; 474 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 475 source->GetExternalStringResourceBase(&encoding)); 476 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 477 Local<Script> script = v8_compile(source); 478 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 479 CHECK(value->IsNumber()); 480 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 481 CcTest::heap()->CollectAllGarbage(); 482 CHECK_EQ(0, dispose_count); 483 } 484 CcTest::i_isolate()->compilation_cache()->Clear(); 485 CcTest::heap()->CollectAllAvailableGarbage(); 486 CHECK_EQ(1, dispose_count); 487 } 488 489 490 THREADED_TEST(ScriptMakingExternalString) { 491 int dispose_count = 0; 492 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 493 { 494 LocalContext env; 495 v8::HandleScope scope(env->GetIsolate()); 496 Local<String> source = 497 String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 498 v8::NewStringType::kNormal) 499 .ToLocalChecked(); 500 // Trigger GCs so that the newly allocated string moves to old gen. 501 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 502 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 503 CHECK_EQ(source->IsExternal(), false); 504 CHECK_EQ(source->IsExternalOneByte(), false); 505 String::Encoding encoding = String::UNKNOWN_ENCODING; 506 CHECK(!source->GetExternalStringResourceBase(&encoding)); 507 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 508 bool success = source->MakeExternal(new TestResource(two_byte_source, 509 &dispose_count)); 510 CHECK(success); 511 Local<Script> script = v8_compile(source); 512 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 513 CHECK(value->IsNumber()); 514 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 515 CcTest::heap()->CollectAllGarbage(); 516 CHECK_EQ(0, dispose_count); 517 } 518 CcTest::i_isolate()->compilation_cache()->Clear(); 519 CcTest::heap()->CollectAllGarbage(); 520 CHECK_EQ(1, dispose_count); 521 } 522 523 524 THREADED_TEST(ScriptMakingExternalOneByteString) { 525 int dispose_count = 0; 526 const char* c_source = "1 + 2 * 3"; 527 { 528 LocalContext env; 529 v8::HandleScope scope(env->GetIsolate()); 530 Local<String> source = v8_str(c_source); 531 // Trigger GCs so that the newly allocated string moves to old gen. 532 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 533 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 534 bool success = source->MakeExternal( 535 new TestOneByteResource(i::StrDup(c_source), &dispose_count)); 536 CHECK(success); 537 Local<Script> script = v8_compile(source); 538 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 539 CHECK(value->IsNumber()); 540 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 541 CcTest::heap()->CollectAllGarbage(); 542 CHECK_EQ(0, dispose_count); 543 } 544 CcTest::i_isolate()->compilation_cache()->Clear(); 545 CcTest::heap()->CollectAllGarbage(); 546 CHECK_EQ(1, dispose_count); 547 } 548 549 550 TEST(MakingExternalStringConditions) { 551 LocalContext env; 552 v8::HandleScope scope(env->GetIsolate()); 553 554 // Free some space in the new space so that we can check freshness. 555 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 556 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 557 558 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 559 Local<String> local_string = 560 String::NewFromTwoByte(env->GetIsolate(), two_byte_string, 561 v8::NewStringType::kNormal) 562 .ToLocalChecked(); 563 i::DeleteArray(two_byte_string); 564 565 // We should refuse to externalize new space strings. 566 CHECK(!local_string->CanMakeExternal()); 567 // Trigger GCs so that the newly allocated string moves to old gen. 568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 570 // Old space strings should be accepted. 571 CHECK(local_string->CanMakeExternal()); 572 } 573 574 575 TEST(MakingExternalOneByteStringConditions) { 576 LocalContext env; 577 v8::HandleScope scope(env->GetIsolate()); 578 579 // Free some space in the new space so that we can check freshness. 580 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 581 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 582 583 Local<String> local_string = v8_str("s1"); 584 // We should refuse to externalize new space strings. 585 CHECK(!local_string->CanMakeExternal()); 586 // Trigger GCs so that the newly allocated string moves to old gen. 587 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 588 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 589 // Old space strings should be accepted. 590 CHECK(local_string->CanMakeExternal()); 591 } 592 593 594 TEST(MakingExternalUnalignedOneByteString) { 595 LocalContext env; 596 v8::HandleScope scope(env->GetIsolate()); 597 598 CompileRun("function cons(a, b) { return a + b; }" 599 "function slice(a) { return a.substring(1); }"); 600 // Create a cons string that will land in old pointer space. 601 Local<String> cons = Local<String>::Cast(CompileRun( 602 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 603 // Create a sliced string that will land in old pointer space. 604 Local<String> slice = Local<String>::Cast(CompileRun( 605 "slice('abcdefghijklmnopqrstuvwxyz');")); 606 607 // Trigger GCs so that the newly allocated string moves to old gen. 608 i::heap::SimulateFullSpace(CcTest::heap()->old_space()); 609 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 610 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 611 612 // Turn into external string with unaligned resource data. 613 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 614 bool success = 615 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1)); 616 CHECK(success); 617 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 618 success = 619 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1)); 620 CHECK(success); 621 622 // Trigger GCs and force evacuation. 623 CcTest::heap()->CollectAllGarbage(); 624 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 625 } 626 627 628 THREADED_TEST(UsingExternalString) { 629 i::Factory* factory = CcTest::i_isolate()->factory(); 630 { 631 v8::HandleScope scope(CcTest::isolate()); 632 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 633 Local<String> string = 634 String::NewExternalTwoByte(CcTest::isolate(), 635 new TestResource(two_byte_string)) 636 .ToLocalChecked(); 637 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 638 // Trigger GCs so that the newly allocated string moves to old gen. 639 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 640 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 641 i::Handle<i::String> isymbol = 642 factory->InternalizeString(istring); 643 CHECK(isymbol->IsInternalizedString()); 644 } 645 CcTest::heap()->CollectAllGarbage(); 646 CcTest::heap()->CollectAllGarbage(); 647 } 648 649 650 THREADED_TEST(UsingExternalOneByteString) { 651 i::Factory* factory = CcTest::i_isolate()->factory(); 652 { 653 v8::HandleScope scope(CcTest::isolate()); 654 const char* one_byte_string = "test string"; 655 Local<String> string = 656 String::NewExternalOneByte( 657 CcTest::isolate(), 658 new TestOneByteResource(i::StrDup(one_byte_string))) 659 .ToLocalChecked(); 660 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 661 // Trigger GCs so that the newly allocated string moves to old gen. 662 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 663 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 664 i::Handle<i::String> isymbol = 665 factory->InternalizeString(istring); 666 CHECK(isymbol->IsInternalizedString()); 667 } 668 CcTest::heap()->CollectAllGarbage(); 669 CcTest::heap()->CollectAllGarbage(); 670 } 671 672 673 class RandomLengthResource : public v8::String::ExternalStringResource { 674 public: 675 explicit RandomLengthResource(int length) : length_(length) {} 676 virtual const uint16_t* data() const { return string_; } 677 virtual size_t length() const { return length_; } 678 679 private: 680 uint16_t string_[10]; 681 int length_; 682 }; 683 684 685 class RandomLengthOneByteResource 686 : public v8::String::ExternalOneByteStringResource { 687 public: 688 explicit RandomLengthOneByteResource(int length) : length_(length) {} 689 virtual const char* data() const { return string_; } 690 virtual size_t length() const { return length_; } 691 692 private: 693 char string_[10]; 694 int length_; 695 }; 696 697 698 THREADED_TEST(NewExternalForVeryLongString) { 699 auto isolate = CcTest::isolate(); 700 { 701 v8::HandleScope scope(isolate); 702 v8::TryCatch try_catch(isolate); 703 RandomLengthOneByteResource r(1 << 30); 704 v8::MaybeLocal<v8::String> maybe_str = 705 v8::String::NewExternalOneByte(isolate, &r); 706 CHECK(maybe_str.IsEmpty()); 707 CHECK(!try_catch.HasCaught()); 708 } 709 710 { 711 v8::HandleScope scope(isolate); 712 v8::TryCatch try_catch(isolate); 713 RandomLengthResource r(1 << 30); 714 v8::MaybeLocal<v8::String> maybe_str = 715 v8::String::NewExternalTwoByte(isolate, &r); 716 CHECK(maybe_str.IsEmpty()); 717 CHECK(!try_catch.HasCaught()); 718 } 719 } 720 721 722 THREADED_TEST(ScavengeExternalString) { 723 i::FLAG_stress_compaction = false; 724 i::FLAG_gc_global = false; 725 int dispose_count = 0; 726 bool in_new_space = false; 727 { 728 v8::HandleScope scope(CcTest::isolate()); 729 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 730 Local<String> string = 731 String::NewExternalTwoByte( 732 CcTest::isolate(), 733 new TestResource(two_byte_string, &dispose_count)) 734 .ToLocalChecked(); 735 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 736 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 737 in_new_space = CcTest::heap()->InNewSpace(*istring); 738 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); 739 CHECK_EQ(0, dispose_count); 740 } 741 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); 742 CHECK_EQ(1, dispose_count); 743 } 744 745 746 THREADED_TEST(ScavengeExternalOneByteString) { 747 i::FLAG_stress_compaction = false; 748 i::FLAG_gc_global = false; 749 int dispose_count = 0; 750 bool in_new_space = false; 751 { 752 v8::HandleScope scope(CcTest::isolate()); 753 const char* one_byte_string = "test string"; 754 Local<String> string = 755 String::NewExternalOneByte( 756 CcTest::isolate(), 757 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count)) 758 .ToLocalChecked(); 759 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 760 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 761 in_new_space = CcTest::heap()->InNewSpace(*istring); 762 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring)); 763 CHECK_EQ(0, dispose_count); 764 } 765 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE); 766 CHECK_EQ(1, dispose_count); 767 } 768 769 770 class TestOneByteResourceWithDisposeControl : public TestOneByteResource { 771 public: 772 // Only used by non-threaded tests, so it can use static fields. 773 static int dispose_calls; 774 static int dispose_count; 775 776 TestOneByteResourceWithDisposeControl(const char* data, bool dispose) 777 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {} 778 779 void Dispose() { 780 ++dispose_calls; 781 if (dispose_) delete this; 782 } 783 private: 784 bool dispose_; 785 }; 786 787 788 int TestOneByteResourceWithDisposeControl::dispose_count = 0; 789 int TestOneByteResourceWithDisposeControl::dispose_calls = 0; 790 791 792 TEST(ExternalStringWithDisposeHandling) { 793 const char* c_source = "1 + 2 * 3"; 794 795 // Use a stack allocated external string resource allocated object. 796 TestOneByteResourceWithDisposeControl::dispose_count = 0; 797 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 798 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 799 { 800 LocalContext env; 801 v8::HandleScope scope(env->GetIsolate()); 802 Local<String> source = 803 String::NewExternalOneByte(env->GetIsolate(), &res_stack) 804 .ToLocalChecked(); 805 Local<Script> script = v8_compile(source); 806 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 807 CHECK(value->IsNumber()); 808 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 809 CcTest::heap()->CollectAllAvailableGarbage(); 810 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 811 } 812 CcTest::i_isolate()->compilation_cache()->Clear(); 813 CcTest::heap()->CollectAllAvailableGarbage(); 814 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 815 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 816 817 // Use a heap allocated external string resource allocated object. 818 TestOneByteResourceWithDisposeControl::dispose_count = 0; 819 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 820 TestOneByteResource* res_heap = 821 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true); 822 { 823 LocalContext env; 824 v8::HandleScope scope(env->GetIsolate()); 825 Local<String> source = 826 String::NewExternalOneByte(env->GetIsolate(), res_heap) 827 .ToLocalChecked(); 828 Local<Script> script = v8_compile(source); 829 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 830 CHECK(value->IsNumber()); 831 CHECK_EQ(7, value->Int32Value(env.local()).FromJust()); 832 CcTest::heap()->CollectAllAvailableGarbage(); 833 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 834 } 835 CcTest::i_isolate()->compilation_cache()->Clear(); 836 CcTest::heap()->CollectAllAvailableGarbage(); 837 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 838 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count); 839 } 840 841 842 THREADED_TEST(StringConcat) { 843 { 844 LocalContext env; 845 v8::HandleScope scope(env->GetIsolate()); 846 const char* one_byte_string_1 = "function a_times_t"; 847 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 848 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 849 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 850 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 851 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 852 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 853 Local<String> left = v8_str(one_byte_string_1); 854 855 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 856 Local<String> right = 857 String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 858 v8::NewStringType::kNormal) 859 .ToLocalChecked(); 860 i::DeleteArray(two_byte_source); 861 862 Local<String> source = String::Concat(left, right); 863 right = String::NewExternalOneByte( 864 env->GetIsolate(), 865 new TestOneByteResource(i::StrDup(one_byte_extern_1))) 866 .ToLocalChecked(); 867 source = String::Concat(source, right); 868 right = String::NewExternalTwoByte( 869 env->GetIsolate(), 870 new TestResource(AsciiToTwoByteString(two_byte_extern_1))) 871 .ToLocalChecked(); 872 source = String::Concat(source, right); 873 right = v8_str(one_byte_string_2); 874 source = String::Concat(source, right); 875 876 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 877 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source, 878 v8::NewStringType::kNormal) 879 .ToLocalChecked(); 880 i::DeleteArray(two_byte_source); 881 882 source = String::Concat(source, right); 883 right = String::NewExternalTwoByte( 884 env->GetIsolate(), 885 new TestResource(AsciiToTwoByteString(two_byte_extern_2))) 886 .ToLocalChecked(); 887 source = String::Concat(source, right); 888 Local<Script> script = v8_compile(source); 889 Local<Value> value = script->Run(env.local()).ToLocalChecked(); 890 CHECK(value->IsNumber()); 891 CHECK_EQ(68, value->Int32Value(env.local()).FromJust()); 892 } 893 CcTest::i_isolate()->compilation_cache()->Clear(); 894 CcTest::heap()->CollectAllGarbage(); 895 CcTest::heap()->CollectAllGarbage(); 896 } 897 898 899 THREADED_TEST(GlobalProperties) { 900 LocalContext env; 901 v8::HandleScope scope(env->GetIsolate()); 902 v8::Local<v8::Object> global = env->Global(); 903 CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust()); 904 Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked(); 905 CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust()); 906 } 907 908 909 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 910 i::Address callback) { 911 ApiTestFuzzer::Fuzz(); 912 CheckReturnValue(info, callback); 913 info.GetReturnValue().Set(v8_str("bad value")); 914 info.GetReturnValue().Set(v8_num(102)); 915 } 916 917 918 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 919 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 920 } 921 922 923 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 924 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 925 } 926 927 static void construct_callback( 928 const v8::FunctionCallbackInfo<Value>& info) { 929 ApiTestFuzzer::Fuzz(); 930 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 931 CHECK( 932 info.This() 933 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1)) 934 .FromJust()); 935 CHECK( 936 info.This() 937 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2)) 938 .FromJust()); 939 info.GetReturnValue().Set(v8_str("bad value")); 940 info.GetReturnValue().Set(info.This()); 941 } 942 943 944 static void Return239Callback( 945 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 946 ApiTestFuzzer::Fuzz(); 947 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 948 info.GetReturnValue().Set(v8_str("bad value")); 949 info.GetReturnValue().Set(v8_num(239)); 950 } 951 952 953 template<typename Handler> 954 static void TestFunctionTemplateInitializer(Handler handler, 955 Handler handler_2) { 956 // Test constructor calls. 957 { 958 LocalContext env; 959 v8::Isolate* isolate = env->GetIsolate(); 960 v8::HandleScope scope(isolate); 961 962 Local<v8::FunctionTemplate> fun_templ = 963 v8::FunctionTemplate::New(isolate, handler); 964 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 965 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 966 Local<Script> script = v8_compile("obj()"); 967 for (int i = 0; i < 30; i++) { 968 CHECK_EQ(102, v8_run_int32value(script)); 969 } 970 } 971 // Use SetCallHandler to initialize a function template, should work like 972 // the previous one. 973 { 974 LocalContext env; 975 v8::Isolate* isolate = env->GetIsolate(); 976 v8::HandleScope scope(isolate); 977 978 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 979 fun_templ->SetCallHandler(handler_2); 980 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 981 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 982 Local<Script> script = v8_compile("obj()"); 983 for (int i = 0; i < 30; i++) { 984 CHECK_EQ(102, v8_run_int32value(script)); 985 } 986 } 987 } 988 989 990 template<typename Constructor, typename Accessor> 991 static void TestFunctionTemplateAccessor(Constructor constructor, 992 Accessor accessor) { 993 LocalContext env; 994 v8::HandleScope scope(env->GetIsolate()); 995 996 Local<v8::FunctionTemplate> fun_templ = 997 v8::FunctionTemplate::New(env->GetIsolate(), constructor); 998 fun_templ->SetClassName(v8_str("funky")); 999 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 1000 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1001 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1002 Local<Value> result = 1003 v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked(); 1004 CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust()); 1005 CompileRun("var obj_instance = new obj();"); 1006 Local<Script> script; 1007 script = v8_compile("obj_instance.x"); 1008 for (int i = 0; i < 30; i++) { 1009 CHECK_EQ(1, v8_run_int32value(script)); 1010 } 1011 script = v8_compile("obj_instance.m"); 1012 for (int i = 0; i < 30; i++) { 1013 CHECK_EQ(239, v8_run_int32value(script)); 1014 } 1015 } 1016 1017 1018 THREADED_PROFILED_TEST(FunctionTemplate) { 1019 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 1020 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 1021 } 1022 1023 1024 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1025 ApiTestFuzzer::Fuzz(); 1026 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1027 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1028 } 1029 1030 1031 template<typename Callback> 1032 static void TestSimpleCallback(Callback callback) { 1033 LocalContext env; 1034 v8::Isolate* isolate = env->GetIsolate(); 1035 v8::HandleScope scope(isolate); 1036 1037 v8::Local<v8::ObjectTemplate> object_template = 1038 v8::ObjectTemplate::New(isolate); 1039 object_template->Set(isolate, "callback", 1040 v8::FunctionTemplate::New(isolate, callback)); 1041 v8::Local<v8::Object> object = 1042 object_template->NewInstance(env.local()).ToLocalChecked(); 1043 CHECK((*env) 1044 ->Global() 1045 ->Set(env.local(), v8_str("callback_object"), object) 1046 .FromJust()); 1047 v8::Local<v8::Script> script; 1048 script = v8_compile("callback_object.callback(17)"); 1049 for (int i = 0; i < 30; i++) { 1050 CHECK_EQ(51424, v8_run_int32value(script)); 1051 } 1052 script = v8_compile("callback_object.callback(17, 24)"); 1053 for (int i = 0; i < 30; i++) { 1054 CHECK_EQ(51425, v8_run_int32value(script)); 1055 } 1056 } 1057 1058 1059 THREADED_PROFILED_TEST(SimpleCallback) { 1060 TestSimpleCallback(SimpleCallback); 1061 } 1062 1063 1064 template<typename T> 1065 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1066 1067 // constant return values 1068 static int32_t fast_return_value_int32 = 471; 1069 static uint32_t fast_return_value_uint32 = 571; 1070 static const double kFastReturnValueDouble = 2.7; 1071 // variable return values 1072 static bool fast_return_value_bool = false; 1073 enum ReturnValueOddball { 1074 kNullReturnValue, 1075 kUndefinedReturnValue, 1076 kEmptyStringReturnValue 1077 }; 1078 static ReturnValueOddball fast_return_value_void; 1079 static bool fast_return_value_object_is_empty = false; 1080 1081 // Helper function to avoid compiler error: insufficient contextual information 1082 // to determine type when applying FUNCTION_ADDR to a template function. 1083 static i::Address address_of(v8::FunctionCallback callback) { 1084 return FUNCTION_ADDR(callback); 1085 } 1086 1087 template<> 1088 void FastReturnValueCallback<int32_t>( 1089 const v8::FunctionCallbackInfo<v8::Value>& info) { 1090 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1091 info.GetReturnValue().Set(fast_return_value_int32); 1092 } 1093 1094 template<> 1095 void FastReturnValueCallback<uint32_t>( 1096 const v8::FunctionCallbackInfo<v8::Value>& info) { 1097 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1098 info.GetReturnValue().Set(fast_return_value_uint32); 1099 } 1100 1101 template<> 1102 void FastReturnValueCallback<double>( 1103 const v8::FunctionCallbackInfo<v8::Value>& info) { 1104 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1105 info.GetReturnValue().Set(kFastReturnValueDouble); 1106 } 1107 1108 template<> 1109 void FastReturnValueCallback<bool>( 1110 const v8::FunctionCallbackInfo<v8::Value>& info) { 1111 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1112 info.GetReturnValue().Set(fast_return_value_bool); 1113 } 1114 1115 template<> 1116 void FastReturnValueCallback<void>( 1117 const v8::FunctionCallbackInfo<v8::Value>& info) { 1118 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1119 switch (fast_return_value_void) { 1120 case kNullReturnValue: 1121 info.GetReturnValue().SetNull(); 1122 break; 1123 case kUndefinedReturnValue: 1124 info.GetReturnValue().SetUndefined(); 1125 break; 1126 case kEmptyStringReturnValue: 1127 info.GetReturnValue().SetEmptyString(); 1128 break; 1129 } 1130 } 1131 1132 template<> 1133 void FastReturnValueCallback<Object>( 1134 const v8::FunctionCallbackInfo<v8::Value>& info) { 1135 v8::Local<v8::Object> object; 1136 if (!fast_return_value_object_is_empty) { 1137 object = Object::New(info.GetIsolate()); 1138 } 1139 info.GetReturnValue().Set(object); 1140 } 1141 1142 template <typename T> 1143 Local<Value> TestFastReturnValues() { 1144 LocalContext env; 1145 v8::Isolate* isolate = env->GetIsolate(); 1146 v8::EscapableHandleScope scope(isolate); 1147 v8::Local<v8::ObjectTemplate> object_template = 1148 v8::ObjectTemplate::New(isolate); 1149 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1150 object_template->Set(isolate, "callback", 1151 v8::FunctionTemplate::New(isolate, callback)); 1152 v8::Local<v8::Object> object = 1153 object_template->NewInstance(env.local()).ToLocalChecked(); 1154 CHECK((*env) 1155 ->Global() 1156 ->Set(env.local(), v8_str("callback_object"), object) 1157 .FromJust()); 1158 return scope.Escape(CompileRun("callback_object.callback()")); 1159 } 1160 1161 1162 THREADED_PROFILED_TEST(FastReturnValues) { 1163 LocalContext env; 1164 v8::Isolate* isolate = env->GetIsolate(); 1165 v8::HandleScope scope(isolate); 1166 v8::Local<v8::Value> value; 1167 // check int32_t and uint32_t 1168 int32_t int_values[] = { 1169 0, 234, -723, 1170 i::Smi::kMinValue, i::Smi::kMaxValue 1171 }; 1172 for (size_t i = 0; i < arraysize(int_values); i++) { 1173 for (int modifier = -1; modifier <= 1; modifier++) { 1174 int int_value = int_values[i] + modifier; 1175 // check int32_t 1176 fast_return_value_int32 = int_value; 1177 value = TestFastReturnValues<int32_t>(); 1178 CHECK(value->IsInt32()); 1179 CHECK_EQ(fast_return_value_int32, 1180 value->Int32Value(env.local()).FromJust()); 1181 // check uint32_t 1182 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1183 value = TestFastReturnValues<uint32_t>(); 1184 CHECK(value->IsUint32()); 1185 CHECK_EQ(fast_return_value_uint32, 1186 value->Uint32Value(env.local()).FromJust()); 1187 } 1188 } 1189 // check double 1190 value = TestFastReturnValues<double>(); 1191 CHECK(value->IsNumber()); 1192 CHECK_EQ(kFastReturnValueDouble, 1193 value->ToNumber(env.local()).ToLocalChecked()->Value()); 1194 // check bool values 1195 for (int i = 0; i < 2; i++) { 1196 fast_return_value_bool = i == 0; 1197 value = TestFastReturnValues<bool>(); 1198 CHECK(value->IsBoolean()); 1199 CHECK_EQ(fast_return_value_bool, 1200 value->ToBoolean(env.local()).ToLocalChecked()->Value()); 1201 } 1202 // check oddballs 1203 ReturnValueOddball oddballs[] = { 1204 kNullReturnValue, 1205 kUndefinedReturnValue, 1206 kEmptyStringReturnValue 1207 }; 1208 for (size_t i = 0; i < arraysize(oddballs); i++) { 1209 fast_return_value_void = oddballs[i]; 1210 value = TestFastReturnValues<void>(); 1211 switch (fast_return_value_void) { 1212 case kNullReturnValue: 1213 CHECK(value->IsNull()); 1214 break; 1215 case kUndefinedReturnValue: 1216 CHECK(value->IsUndefined()); 1217 break; 1218 case kEmptyStringReturnValue: 1219 CHECK(value->IsString()); 1220 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1221 break; 1222 } 1223 } 1224 // check handles 1225 fast_return_value_object_is_empty = false; 1226 value = TestFastReturnValues<Object>(); 1227 CHECK(value->IsObject()); 1228 fast_return_value_object_is_empty = true; 1229 value = TestFastReturnValues<Object>(); 1230 CHECK(value->IsUndefined()); 1231 } 1232 1233 1234 THREADED_TEST(FunctionTemplateSetLength) { 1235 LocalContext env; 1236 v8::Isolate* isolate = env->GetIsolate(); 1237 v8::HandleScope scope(isolate); 1238 { 1239 Local<v8::FunctionTemplate> fun_templ = 1240 v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(), 1241 Local<v8::Signature>(), 23); 1242 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1243 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1244 Local<Script> script = v8_compile("obj.length"); 1245 CHECK_EQ(23, v8_run_int32value(script)); 1246 } 1247 { 1248 Local<v8::FunctionTemplate> fun_templ = 1249 v8::FunctionTemplate::New(isolate, handle_callback); 1250 fun_templ->SetLength(22); 1251 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1252 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1253 Local<Script> script = v8_compile("obj.length"); 1254 CHECK_EQ(22, v8_run_int32value(script)); 1255 } 1256 { 1257 // Without setting length it defaults to 0. 1258 Local<v8::FunctionTemplate> fun_templ = 1259 v8::FunctionTemplate::New(isolate, handle_callback); 1260 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 1261 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust()); 1262 Local<Script> script = v8_compile("obj.length"); 1263 CHECK_EQ(0, v8_run_int32value(script)); 1264 } 1265 } 1266 1267 1268 static void* expected_ptr; 1269 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1270 void* ptr = v8::External::Cast(*args.Data())->Value(); 1271 CHECK_EQ(expected_ptr, ptr); 1272 args.GetReturnValue().Set(true); 1273 } 1274 1275 1276 static void TestExternalPointerWrapping() { 1277 LocalContext env; 1278 v8::Isolate* isolate = env->GetIsolate(); 1279 v8::HandleScope scope(isolate); 1280 1281 v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr); 1282 1283 v8::Local<v8::Object> obj = v8::Object::New(isolate); 1284 CHECK(obj->Set(env.local(), v8_str("func"), 1285 v8::FunctionTemplate::New(isolate, callback, data) 1286 ->GetFunction(env.local()) 1287 .ToLocalChecked()) 1288 .FromJust()); 1289 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust()); 1290 1291 CHECK(CompileRun("function foo() {\n" 1292 " for (var i = 0; i < 13; i++) obj.func();\n" 1293 "}\n" 1294 "foo(), true") 1295 ->BooleanValue(env.local()) 1296 .FromJust()); 1297 } 1298 1299 1300 THREADED_TEST(ExternalWrap) { 1301 // Check heap allocated object. 1302 int* ptr = new int; 1303 expected_ptr = ptr; 1304 TestExternalPointerWrapping(); 1305 delete ptr; 1306 1307 // Check stack allocated object. 1308 int foo; 1309 expected_ptr = &foo; 1310 TestExternalPointerWrapping(); 1311 1312 // Check not aligned addresses. 1313 const int n = 100; 1314 char* s = new char[n]; 1315 for (int i = 0; i < n; i++) { 1316 expected_ptr = s + i; 1317 TestExternalPointerWrapping(); 1318 } 1319 1320 delete[] s; 1321 1322 // Check several invalid addresses. 1323 expected_ptr = reinterpret_cast<void*>(1); 1324 TestExternalPointerWrapping(); 1325 1326 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1327 TestExternalPointerWrapping(); 1328 1329 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1330 TestExternalPointerWrapping(); 1331 1332 #if defined(V8_HOST_ARCH_X64) 1333 // Check a value with a leading 1 bit in x64 Smi encoding. 1334 expected_ptr = reinterpret_cast<void*>(0x400000000); 1335 TestExternalPointerWrapping(); 1336 1337 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1338 TestExternalPointerWrapping(); 1339 1340 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1341 TestExternalPointerWrapping(); 1342 #endif 1343 } 1344 1345 1346 THREADED_TEST(FindInstanceInPrototypeChain) { 1347 LocalContext env; 1348 v8::Isolate* isolate = env->GetIsolate(); 1349 v8::HandleScope scope(isolate); 1350 1351 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate); 1352 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate); 1353 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate); 1354 derived->Inherit(base); 1355 1356 Local<v8::Function> base_function = 1357 base->GetFunction(env.local()).ToLocalChecked(); 1358 Local<v8::Function> derived_function = 1359 derived->GetFunction(env.local()).ToLocalChecked(); 1360 Local<v8::Function> other_function = 1361 other->GetFunction(env.local()).ToLocalChecked(); 1362 1363 Local<v8::Object> base_instance = 1364 base_function->NewInstance(env.local()).ToLocalChecked(); 1365 Local<v8::Object> derived_instance = 1366 derived_function->NewInstance(env.local()).ToLocalChecked(); 1367 Local<v8::Object> derived_instance2 = 1368 derived_function->NewInstance(env.local()).ToLocalChecked(); 1369 Local<v8::Object> other_instance = 1370 other_function->NewInstance(env.local()).ToLocalChecked(); 1371 CHECK( 1372 derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance) 1373 .FromJust()); 1374 CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2) 1375 .FromJust()); 1376 1377 // base_instance is only an instance of base. 1378 CHECK(base_instance->Equals(env.local(), 1379 base_instance->FindInstanceInPrototypeChain(base)) 1380 .FromJust()); 1381 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1382 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1383 1384 // derived_instance is an instance of base and derived. 1385 CHECK(derived_instance->Equals(env.local(), 1386 derived_instance->FindInstanceInPrototypeChain( 1387 base)) 1388 .FromJust()); 1389 CHECK(derived_instance->Equals(env.local(), 1390 derived_instance->FindInstanceInPrototypeChain( 1391 derived)) 1392 .FromJust()); 1393 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1394 1395 // other_instance is an instance of other and its immediate 1396 // prototype derived_instance2 is an instance of base and derived. 1397 // Note, derived_instance is an instance of base and derived too, 1398 // but it comes after derived_instance2 in the prototype chain of 1399 // other_instance. 1400 CHECK(derived_instance2->Equals( 1401 env.local(), 1402 other_instance->FindInstanceInPrototypeChain(base)) 1403 .FromJust()); 1404 CHECK(derived_instance2->Equals(env.local(), 1405 other_instance->FindInstanceInPrototypeChain( 1406 derived)) 1407 .FromJust()); 1408 CHECK(other_instance->Equals( 1409 env.local(), 1410 other_instance->FindInstanceInPrototypeChain(other)) 1411 .FromJust()); 1412 } 1413 1414 1415 THREADED_TEST(TinyInteger) { 1416 LocalContext env; 1417 v8::Isolate* isolate = env->GetIsolate(); 1418 v8::HandleScope scope(isolate); 1419 1420 int32_t value = 239; 1421 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1422 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1423 1424 value_obj = v8::Integer::New(isolate, value); 1425 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1426 } 1427 1428 1429 THREADED_TEST(BigSmiInteger) { 1430 LocalContext env; 1431 v8::HandleScope scope(env->GetIsolate()); 1432 v8::Isolate* isolate = CcTest::isolate(); 1433 1434 int32_t value = i::Smi::kMaxValue; 1435 // We cannot add one to a Smi::kMaxValue without wrapping. 1436 if (i::SmiValuesAre31Bits()) { 1437 CHECK(i::Smi::IsValid(value)); 1438 CHECK(!i::Smi::IsValid(value + 1)); 1439 1440 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1442 1443 value_obj = v8::Integer::New(isolate, value); 1444 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1445 } 1446 } 1447 1448 1449 THREADED_TEST(BigInteger) { 1450 LocalContext env; 1451 v8::HandleScope scope(env->GetIsolate()); 1452 v8::Isolate* isolate = CcTest::isolate(); 1453 1454 // We cannot add one to a Smi::kMaxValue without wrapping. 1455 if (i::SmiValuesAre31Bits()) { 1456 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1457 // The code will not be run in that case, due to the "if" guard. 1458 int32_t value = 1459 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1460 CHECK(value > i::Smi::kMaxValue); 1461 CHECK(!i::Smi::IsValid(value)); 1462 1463 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1464 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1465 1466 value_obj = v8::Integer::New(isolate, value); 1467 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1468 } 1469 } 1470 1471 1472 THREADED_TEST(TinyUnsignedInteger) { 1473 LocalContext env; 1474 v8::HandleScope scope(env->GetIsolate()); 1475 v8::Isolate* isolate = CcTest::isolate(); 1476 1477 uint32_t value = 239; 1478 1479 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1480 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1481 1482 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1483 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1484 } 1485 1486 1487 THREADED_TEST(BigUnsignedSmiInteger) { 1488 LocalContext env; 1489 v8::HandleScope scope(env->GetIsolate()); 1490 v8::Isolate* isolate = CcTest::isolate(); 1491 1492 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1493 CHECK(i::Smi::IsValid(value)); 1494 CHECK(!i::Smi::IsValid(value + 1)); 1495 1496 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1497 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1498 1499 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1500 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1501 } 1502 1503 1504 THREADED_TEST(BigUnsignedInteger) { 1505 LocalContext env; 1506 v8::HandleScope scope(env->GetIsolate()); 1507 v8::Isolate* isolate = CcTest::isolate(); 1508 1509 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1510 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1511 CHECK(!i::Smi::IsValid(value)); 1512 1513 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1514 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1515 1516 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1517 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1518 } 1519 1520 1521 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1522 LocalContext env; 1523 v8::HandleScope scope(env->GetIsolate()); 1524 v8::Isolate* isolate = CcTest::isolate(); 1525 1526 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1527 uint32_t value = INT32_MAX_AS_UINT + 1; 1528 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1529 1530 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1532 1533 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1534 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1535 } 1536 1537 1538 THREADED_TEST(IsNativeError) { 1539 LocalContext env; 1540 v8::HandleScope scope(env->GetIsolate()); 1541 v8::Local<Value> syntax_error = CompileRun( 1542 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1543 CHECK(syntax_error->IsNativeError()); 1544 v8::Local<Value> not_error = CompileRun("{a:42}"); 1545 CHECK(!not_error->IsNativeError()); 1546 v8::Local<Value> not_object = CompileRun("42"); 1547 CHECK(!not_object->IsNativeError()); 1548 } 1549 1550 1551 THREADED_TEST(IsGeneratorFunctionOrObject) { 1552 LocalContext env; 1553 v8::HandleScope scope(env->GetIsolate()); 1554 1555 CompileRun("function *gen() { yield 1; }\nfunction func() {}"); 1556 v8::Local<Value> gen = CompileRun("gen"); 1557 v8::Local<Value> genObj = CompileRun("gen()"); 1558 v8::Local<Value> object = CompileRun("{a:42}"); 1559 v8::Local<Value> func = CompileRun("func"); 1560 1561 CHECK(gen->IsGeneratorFunction()); 1562 CHECK(gen->IsFunction()); 1563 CHECK(!gen->IsGeneratorObject()); 1564 1565 CHECK(!genObj->IsGeneratorFunction()); 1566 CHECK(!genObj->IsFunction()); 1567 CHECK(genObj->IsGeneratorObject()); 1568 1569 CHECK(!object->IsGeneratorFunction()); 1570 CHECK(!object->IsFunction()); 1571 CHECK(!object->IsGeneratorObject()); 1572 1573 CHECK(!func->IsGeneratorFunction()); 1574 CHECK(func->IsFunction()); 1575 CHECK(!func->IsGeneratorObject()); 1576 } 1577 1578 1579 THREADED_TEST(ArgumentsObject) { 1580 LocalContext env; 1581 v8::HandleScope scope(env->GetIsolate()); 1582 v8::Local<Value> arguments_object = 1583 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;"); 1584 CHECK(arguments_object->IsArgumentsObject()); 1585 v8::Local<Value> array = CompileRun("[1,2,3]"); 1586 CHECK(!array->IsArgumentsObject()); 1587 v8::Local<Value> object = CompileRun("{a:42}"); 1588 CHECK(!object->IsArgumentsObject()); 1589 } 1590 1591 1592 THREADED_TEST(IsMapOrSet) { 1593 LocalContext env; 1594 v8::HandleScope scope(env->GetIsolate()); 1595 v8::Local<Value> map = CompileRun("new Map()"); 1596 v8::Local<Value> set = CompileRun("new Set()"); 1597 v8::Local<Value> weak_map = CompileRun("new WeakMap()"); 1598 v8::Local<Value> weak_set = CompileRun("new WeakSet()"); 1599 CHECK(map->IsMap()); 1600 CHECK(set->IsSet()); 1601 CHECK(weak_map->IsWeakMap()); 1602 CHECK(weak_set->IsWeakSet()); 1603 1604 CHECK(!map->IsSet()); 1605 CHECK(!map->IsWeakMap()); 1606 CHECK(!map->IsWeakSet()); 1607 1608 CHECK(!set->IsMap()); 1609 CHECK(!set->IsWeakMap()); 1610 CHECK(!set->IsWeakSet()); 1611 1612 CHECK(!weak_map->IsMap()); 1613 CHECK(!weak_map->IsSet()); 1614 CHECK(!weak_map->IsWeakSet()); 1615 1616 CHECK(!weak_set->IsMap()); 1617 CHECK(!weak_set->IsSet()); 1618 CHECK(!weak_set->IsWeakMap()); 1619 1620 v8::Local<Value> object = CompileRun("{a:42}"); 1621 CHECK(!object->IsMap()); 1622 CHECK(!object->IsSet()); 1623 CHECK(!object->IsWeakMap()); 1624 CHECK(!object->IsWeakSet()); 1625 } 1626 1627 1628 THREADED_TEST(StringObject) { 1629 LocalContext env; 1630 v8::HandleScope scope(env->GetIsolate()); 1631 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")"); 1632 CHECK(boxed_string->IsStringObject()); 1633 v8::Local<Value> unboxed_string = CompileRun("\"test\""); 1634 CHECK(!unboxed_string->IsStringObject()); 1635 v8::Local<Value> boxed_not_string = CompileRun("new Number(42)"); 1636 CHECK(!boxed_not_string->IsStringObject()); 1637 v8::Local<Value> not_object = CompileRun("0"); 1638 CHECK(!not_object->IsStringObject()); 1639 v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1640 CHECK(!as_boxed.IsEmpty()); 1641 Local<v8::String> the_string = as_boxed->ValueOf(); 1642 CHECK(!the_string.IsEmpty()); 1643 ExpectObject("\"test\"", the_string); 1644 v8::Local<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1645 CHECK(new_boxed_string->IsStringObject()); 1646 as_boxed = new_boxed_string.As<v8::StringObject>(); 1647 the_string = as_boxed->ValueOf(); 1648 CHECK(!the_string.IsEmpty()); 1649 ExpectObject("\"test\"", the_string); 1650 } 1651 1652 1653 TEST(StringObjectDelete) { 1654 LocalContext context; 1655 v8::HandleScope scope(context->GetIsolate()); 1656 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")"); 1657 CHECK(boxed_string->IsStringObject()); 1658 v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>(); 1659 CHECK(!str_obj->Delete(context.local(), 2).FromJust()); 1660 CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust()); 1661 } 1662 1663 1664 THREADED_TEST(NumberObject) { 1665 LocalContext env; 1666 v8::HandleScope scope(env->GetIsolate()); 1667 v8::Local<Value> boxed_number = CompileRun("new Number(42)"); 1668 CHECK(boxed_number->IsNumberObject()); 1669 v8::Local<Value> unboxed_number = CompileRun("42"); 1670 CHECK(!unboxed_number->IsNumberObject()); 1671 v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1672 CHECK(!boxed_not_number->IsNumberObject()); 1673 v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1674 CHECK(!as_boxed.IsEmpty()); 1675 double the_number = as_boxed->ValueOf(); 1676 CHECK_EQ(42.0, the_number); 1677 v8::Local<v8::Value> new_boxed_number = 1678 v8::NumberObject::New(env->GetIsolate(), 43); 1679 CHECK(new_boxed_number->IsNumberObject()); 1680 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1681 the_number = as_boxed->ValueOf(); 1682 CHECK_EQ(43.0, the_number); 1683 } 1684 1685 1686 THREADED_TEST(BooleanObject) { 1687 LocalContext env; 1688 v8::HandleScope scope(env->GetIsolate()); 1689 v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1690 CHECK(boxed_boolean->IsBooleanObject()); 1691 v8::Local<Value> unboxed_boolean = CompileRun("true"); 1692 CHECK(!unboxed_boolean->IsBooleanObject()); 1693 v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1694 CHECK(!boxed_not_boolean->IsBooleanObject()); 1695 v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>(); 1696 CHECK(!as_boxed.IsEmpty()); 1697 bool the_boolean = as_boxed->ValueOf(); 1698 CHECK_EQ(true, the_boolean); 1699 v8::Local<v8::Value> boxed_true = 1700 v8::BooleanObject::New(env->GetIsolate(), true); 1701 v8::Local<v8::Value> boxed_false = 1702 v8::BooleanObject::New(env->GetIsolate(), false); 1703 CHECK(boxed_true->IsBooleanObject()); 1704 CHECK(boxed_false->IsBooleanObject()); 1705 as_boxed = boxed_true.As<v8::BooleanObject>(); 1706 CHECK_EQ(true, as_boxed->ValueOf()); 1707 as_boxed = boxed_false.As<v8::BooleanObject>(); 1708 CHECK_EQ(false, as_boxed->ValueOf()); 1709 } 1710 1711 1712 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1713 LocalContext env; 1714 v8::HandleScope scope(env->GetIsolate()); 1715 1716 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); 1717 CHECK(primitive_false->IsBoolean()); 1718 CHECK(!primitive_false->IsBooleanObject()); 1719 CHECK(!primitive_false->BooleanValue(env.local()).FromJust()); 1720 CHECK(!primitive_false->IsTrue()); 1721 CHECK(primitive_false->IsFalse()); 1722 1723 Local<Value> false_value = BooleanObject::New(env->GetIsolate(), false); 1724 CHECK(!false_value->IsBoolean()); 1725 CHECK(false_value->IsBooleanObject()); 1726 CHECK(false_value->BooleanValue(env.local()).FromJust()); 1727 CHECK(!false_value->IsTrue()); 1728 CHECK(!false_value->IsFalse()); 1729 1730 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1731 CHECK(!false_boolean_object->IsBoolean()); 1732 CHECK(false_boolean_object->IsBooleanObject()); 1733 CHECK(false_boolean_object->BooleanValue(env.local()).FromJust()); 1734 CHECK(!false_boolean_object->ValueOf()); 1735 CHECK(!false_boolean_object->IsTrue()); 1736 CHECK(!false_boolean_object->IsFalse()); 1737 1738 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); 1739 CHECK(primitive_true->IsBoolean()); 1740 CHECK(!primitive_true->IsBooleanObject()); 1741 CHECK(primitive_true->BooleanValue(env.local()).FromJust()); 1742 CHECK(primitive_true->IsTrue()); 1743 CHECK(!primitive_true->IsFalse()); 1744 1745 Local<Value> true_value = BooleanObject::New(env->GetIsolate(), true); 1746 CHECK(!true_value->IsBoolean()); 1747 CHECK(true_value->IsBooleanObject()); 1748 CHECK(true_value->BooleanValue(env.local()).FromJust()); 1749 CHECK(!true_value->IsTrue()); 1750 CHECK(!true_value->IsFalse()); 1751 1752 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1753 CHECK(!true_boolean_object->IsBoolean()); 1754 CHECK(true_boolean_object->IsBooleanObject()); 1755 CHECK(true_boolean_object->BooleanValue(env.local()).FromJust()); 1756 CHECK(true_boolean_object->ValueOf()); 1757 CHECK(!true_boolean_object->IsTrue()); 1758 CHECK(!true_boolean_object->IsFalse()); 1759 } 1760 1761 1762 THREADED_TEST(Number) { 1763 LocalContext env; 1764 v8::HandleScope scope(env->GetIsolate()); 1765 double PI = 3.1415926; 1766 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI); 1767 CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust()); 1768 } 1769 1770 1771 THREADED_TEST(ToNumber) { 1772 LocalContext env; 1773 v8::Isolate* isolate = CcTest::isolate(); 1774 v8::HandleScope scope(isolate); 1775 Local<String> str = v8_str("3.1415926"); 1776 CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust()); 1777 v8::Local<v8::Boolean> t = v8::True(isolate); 1778 CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust()); 1779 v8::Local<v8::Boolean> f = v8::False(isolate); 1780 CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust()); 1781 } 1782 1783 1784 THREADED_TEST(Date) { 1785 LocalContext env; 1786 v8::HandleScope scope(env->GetIsolate()); 1787 double PI = 3.1415926; 1788 Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked(); 1789 CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust()); 1790 CHECK(date.As<v8::Date>() 1791 ->Set(env.local(), v8_str("property"), 1792 v8::Integer::New(env->GetIsolate(), 42)) 1793 .FromJust()); 1794 CHECK_EQ(42, date.As<v8::Date>() 1795 ->Get(env.local(), v8_str("property")) 1796 .ToLocalChecked() 1797 ->Int32Value(env.local()) 1798 .FromJust()); 1799 } 1800 1801 1802 THREADED_TEST(Boolean) { 1803 LocalContext env; 1804 v8::Isolate* isolate = env->GetIsolate(); 1805 v8::HandleScope scope(isolate); 1806 v8::Local<v8::Boolean> t = v8::True(isolate); 1807 CHECK(t->Value()); 1808 v8::Local<v8::Boolean> f = v8::False(isolate); 1809 CHECK(!f->Value()); 1810 v8::Local<v8::Primitive> u = v8::Undefined(isolate); 1811 CHECK(!u->BooleanValue(env.local()).FromJust()); 1812 v8::Local<v8::Primitive> n = v8::Null(isolate); 1813 CHECK(!n->BooleanValue(env.local()).FromJust()); 1814 v8::Local<String> str1 = v8_str(""); 1815 CHECK(!str1->BooleanValue(env.local()).FromJust()); 1816 v8::Local<String> str2 = v8_str("x"); 1817 CHECK(str2->BooleanValue(env.local()).FromJust()); 1818 CHECK(!v8::Number::New(isolate, 0)->BooleanValue(env.local()).FromJust()); 1819 CHECK(v8::Number::New(isolate, -1)->BooleanValue(env.local()).FromJust()); 1820 CHECK(v8::Number::New(isolate, 1)->BooleanValue(env.local()).FromJust()); 1821 CHECK(v8::Number::New(isolate, 42)->BooleanValue(env.local()).FromJust()); 1822 CHECK(!v8_compile("NaN") 1823 ->Run(env.local()) 1824 .ToLocalChecked() 1825 ->BooleanValue(env.local()) 1826 .FromJust()); 1827 } 1828 1829 1830 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1831 ApiTestFuzzer::Fuzz(); 1832 args.GetReturnValue().Set(v8_num(13.4)); 1833 } 1834 1835 1836 static void GetM(Local<String> name, 1837 const v8::PropertyCallbackInfo<v8::Value>& info) { 1838 ApiTestFuzzer::Fuzz(); 1839 info.GetReturnValue().Set(v8_num(876)); 1840 } 1841 1842 1843 THREADED_TEST(GlobalPrototype) { 1844 v8::Isolate* isolate = CcTest::isolate(); 1845 v8::HandleScope scope(isolate); 1846 v8::Local<v8::FunctionTemplate> func_templ = 1847 v8::FunctionTemplate::New(isolate); 1848 func_templ->PrototypeTemplate()->Set( 1849 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler)); 1850 v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1851 templ->Set(isolate, "x", v8_num(200)); 1852 templ->SetAccessor(v8_str("m"), GetM); 1853 LocalContext env(0, templ); 1854 v8::Local<Script> script(v8_compile("dummy()")); 1855 v8::Local<Value> result(script->Run(env.local()).ToLocalChecked()); 1856 CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust()); 1857 CHECK_EQ(200, v8_run_int32value(v8_compile("x"))); 1858 CHECK_EQ(876, v8_run_int32value(v8_compile("m"))); 1859 } 1860 1861 1862 THREADED_TEST(ObjectTemplate) { 1863 LocalContext env; 1864 v8::Isolate* isolate = CcTest::isolate(); 1865 v8::HandleScope scope(isolate); 1866 Local<v8::FunctionTemplate> acc = 1867 v8::FunctionTemplate::New(isolate, Returns42); 1868 CHECK(env->Global() 1869 ->Set(env.local(), v8_str("acc"), 1870 acc->GetFunction(env.local()).ToLocalChecked()) 1871 .FromJust()); 1872 1873 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 1874 v8::Local<v8::String> class_name = v8_str("the_class_name"); 1875 fun->SetClassName(class_name); 1876 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun); 1877 templ1->Set(isolate, "x", v8_num(10)); 1878 templ1->Set(isolate, "y", v8_num(13)); 1879 templ1->Set(v8_str("foo"), acc); 1880 Local<v8::Object> instance1 = 1881 templ1->NewInstance(env.local()).ToLocalChecked(); 1882 CHECK(class_name->StrictEquals(instance1->GetConstructorName())); 1883 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust()); 1884 CHECK(CompileRun("(p.x == 10)")->BooleanValue(env.local()).FromJust()); 1885 CHECK(CompileRun("(p.y == 13)")->BooleanValue(env.local()).FromJust()); 1886 CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(env.local()).FromJust()); 1887 CHECK(CompileRun("(p.foo == acc)")->BooleanValue(env.local()).FromJust()); 1888 // Ensure that foo become a data field. 1889 CompileRun("p.foo = function() {}"); 1890 Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate); 1891 fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); 1892 Local<ObjectTemplate> templ2 = fun2->InstanceTemplate(); 1893 templ2->Set(isolate, "a", v8_num(12)); 1894 templ2->Set(isolate, "b", templ1); 1895 templ2->Set(v8_str("bar"), acc); 1896 templ2->SetAccessorProperty(v8_str("acc"), acc); 1897 Local<v8::Object> instance2 = 1898 templ2->NewInstance(env.local()).ToLocalChecked(); 1899 CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust()); 1900 CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(env.local()).FromJust()); 1901 CHECK(CompileRun("(q.a == 12)")->BooleanValue(env.local()).FromJust()); 1902 CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(env.local()).FromJust()); 1903 CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(env.local()).FromJust()); 1904 CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(env.local()).FromJust()); 1905 CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(env.local()).FromJust()); 1906 CHECK(CompileRun("(q.b !== p)")->BooleanValue(env.local()).FromJust()); 1907 CHECK(CompileRun("(q.acc == 42)")->BooleanValue(env.local()).FromJust()); 1908 CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(env.local()).FromJust()); 1909 CHECK(CompileRun("(q.bar == acc)")->BooleanValue(env.local()).FromJust()); 1910 1911 instance2 = templ2->NewInstance(env.local()).ToLocalChecked(); 1912 CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust()); 1913 CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(env.local()).FromJust()); 1914 CHECK(CompileRun("(q2.a == 12)")->BooleanValue(env.local()).FromJust()); 1915 CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(env.local()).FromJust()); 1916 CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(env.local()).FromJust()); 1917 CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(env.local()).FromJust()); 1918 CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(env.local()).FromJust()); 1919 CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(env.local()).FromJust()); 1920 CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(env.local()).FromJust()); 1921 CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(env.local()).FromJust()); 1922 1923 CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(env.local()).FromJust()); 1924 CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)") 1925 ->BooleanValue(env.local()) 1926 .FromJust()); 1927 CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');" 1928 "(desc1.get === acc)") 1929 ->BooleanValue(env.local()) 1930 .FromJust()); 1931 CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');" 1932 "(desc2.get === acc)") 1933 ->BooleanValue(env.local()) 1934 .FromJust()); 1935 } 1936 1937 THREADED_TEST(IntegerValue) { 1938 LocalContext env; 1939 v8::Isolate* isolate = CcTest::isolate(); 1940 v8::HandleScope scope(isolate); 1941 1942 CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust()); 1943 } 1944 1945 static void GetNirk(Local<String> name, 1946 const v8::PropertyCallbackInfo<v8::Value>& info) { 1947 ApiTestFuzzer::Fuzz(); 1948 info.GetReturnValue().Set(v8_num(900)); 1949 } 1950 1951 static void GetRino(Local<String> name, 1952 const v8::PropertyCallbackInfo<v8::Value>& info) { 1953 ApiTestFuzzer::Fuzz(); 1954 info.GetReturnValue().Set(v8_num(560)); 1955 } 1956 1957 enum ObjectInstantiationMode { 1958 // Create object using ObjectTemplate::NewInstance. 1959 ObjectTemplate_NewInstance, 1960 // Create object using FunctionTemplate::NewInstance on constructor. 1961 Constructor_GetFunction_NewInstance, 1962 // Create object using new operator on constructor. 1963 Constructor_GetFunction_New 1964 }; 1965 1966 // Test object instance creation using a function template with an instance 1967 // template inherited from another function template with accessors and data 1968 // properties in prototype template. 1969 static void TestObjectTemplateInheritedWithPrototype( 1970 ObjectInstantiationMode mode) { 1971 LocalContext env; 1972 v8::Isolate* isolate = CcTest::isolate(); 1973 v8::HandleScope scope(isolate); 1974 1975 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); 1976 fun_A->SetClassName(v8_str("A")); 1977 v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate(); 1978 prototype_templ->Set(isolate, "a", v8_num(113)); 1979 prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk); 1980 prototype_templ->Set(isolate, "b", v8_num(153)); 1981 1982 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); 1983 v8::Local<v8::String> class_name = v8_str("B"); 1984 fun_B->SetClassName(class_name); 1985 fun_B->Inherit(fun_A); 1986 prototype_templ = fun_B->PrototypeTemplate(); 1987 prototype_templ->Set(isolate, "c", v8_num(713)); 1988 prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino); 1989 prototype_templ->Set(isolate, "d", v8_num(753)); 1990 1991 Local<ObjectTemplate> templ = fun_B->InstanceTemplate(); 1992 templ->Set(isolate, "x", v8_num(10)); 1993 templ->Set(isolate, "y", v8_num(13)); 1994 1995 // Perform several iterations to trigger creation from cached boilerplate. 1996 for (int i = 0; i < 3; i++) { 1997 Local<v8::Object> instance; 1998 switch (mode) { 1999 case ObjectTemplate_NewInstance: 2000 instance = templ->NewInstance(env.local()).ToLocalChecked(); 2001 break; 2002 2003 case Constructor_GetFunction_NewInstance: { 2004 Local<v8::Function> function_B = 2005 fun_B->GetFunction(env.local()).ToLocalChecked(); 2006 instance = function_B->NewInstance(env.local()).ToLocalChecked(); 2007 break; 2008 } 2009 case Constructor_GetFunction_New: { 2010 Local<v8::Function> function_B = 2011 fun_B->GetFunction(env.local()).ToLocalChecked(); 2012 if (i == 0) { 2013 CHECK(env->Global() 2014 ->Set(env.local(), class_name, function_B) 2015 .FromJust()); 2016 } 2017 instance = 2018 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked(); 2019 break; 2020 } 2021 default: 2022 UNREACHABLE(); 2023 } 2024 2025 CHECK(class_name->StrictEquals(instance->GetConstructorName())); 2026 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); 2027 2028 CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust()); 2029 CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust()); 2030 2031 CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust()); 2032 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); 2033 CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust()); 2034 CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust()); 2035 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); 2036 CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust()); 2037 } 2038 } 2039 2040 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) { 2041 TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance); 2042 } 2043 2044 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) { 2045 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance); 2046 } 2047 2048 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) { 2049 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New); 2050 } 2051 2052 // Test object instance creation using a function template without an instance 2053 // template inherited from another function template. 2054 static void TestObjectTemplateInheritedWithoutInstanceTemplate( 2055 ObjectInstantiationMode mode) { 2056 LocalContext env; 2057 v8::Isolate* isolate = CcTest::isolate(); 2058 v8::HandleScope scope(isolate); 2059 2060 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); 2061 fun_A->SetClassName(v8_str("A")); 2062 2063 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate(); 2064 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk); 2065 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino); 2066 2067 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); 2068 v8::Local<v8::String> class_name = v8_str("B"); 2069 fun_B->SetClassName(class_name); 2070 fun_B->Inherit(fun_A); 2071 2072 // Perform several iterations to trigger creation from cached boilerplate. 2073 for (int i = 0; i < 3; i++) { 2074 Local<v8::Object> instance; 2075 switch (mode) { 2076 case Constructor_GetFunction_NewInstance: { 2077 Local<v8::Function> function_B = 2078 fun_B->GetFunction(env.local()).ToLocalChecked(); 2079 instance = function_B->NewInstance(env.local()).ToLocalChecked(); 2080 break; 2081 } 2082 case Constructor_GetFunction_New: { 2083 Local<v8::Function> function_B = 2084 fun_B->GetFunction(env.local()).ToLocalChecked(); 2085 if (i == 0) { 2086 CHECK(env->Global() 2087 ->Set(env.local(), class_name, function_B) 2088 .FromJust()); 2089 } 2090 instance = 2091 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked(); 2092 break; 2093 } 2094 default: 2095 UNREACHABLE(); 2096 } 2097 2098 CHECK(class_name->StrictEquals(instance->GetConstructorName())); 2099 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); 2100 2101 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); 2102 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); 2103 } 2104 } 2105 2106 THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) { 2107 TestObjectTemplateInheritedWithoutInstanceTemplate( 2108 Constructor_GetFunction_NewInstance); 2109 } 2110 2111 THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) { 2112 TestObjectTemplateInheritedWithoutInstanceTemplate( 2113 Constructor_GetFunction_New); 2114 } 2115 2116 THREADED_TEST(TestObjectTemplateClassInheritance) { 2117 LocalContext env; 2118 v8::Isolate* isolate = CcTest::isolate(); 2119 v8::HandleScope scope(isolate); 2120 2121 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); 2122 fun_A->SetClassName(v8_str("A")); 2123 2124 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate(); 2125 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk); 2126 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino); 2127 2128 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); 2129 v8::Local<v8::String> class_name = v8_str("B"); 2130 fun_B->SetClassName(class_name); 2131 fun_B->Inherit(fun_A); 2132 2133 v8::Local<v8::String> subclass_name = v8_str("C"); 2134 v8::Local<v8::Object> b_proto; 2135 v8::Local<v8::Object> c_proto; 2136 // Perform several iterations to make sure the cache doesn't break 2137 // subclassing. 2138 for (int i = 0; i < 3; i++) { 2139 Local<v8::Function> function_B = 2140 fun_B->GetFunction(env.local()).ToLocalChecked(); 2141 if (i == 0) { 2142 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust()); 2143 CompileRun("class C extends B {}"); 2144 b_proto = 2145 CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked(); 2146 c_proto = 2147 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked(); 2148 CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust()); 2149 } 2150 Local<v8::Object> instance = 2151 CompileRun("new C()")->ToObject(env.local()).ToLocalChecked(); 2152 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust()); 2153 2154 CHECK(subclass_name->StrictEquals(instance->GetConstructorName())); 2155 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); 2156 2157 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); 2158 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); 2159 } 2160 } 2161 2162 static void NamedPropertyGetterWhichReturns42( 2163 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 2164 info.GetReturnValue().Set(v8_num(42)); 2165 } 2166 2167 THREADED_TEST(TestObjectTemplateReflectConstruct) { 2168 LocalContext env; 2169 v8::Isolate* isolate = CcTest::isolate(); 2170 v8::HandleScope scope(isolate); 2171 2172 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); 2173 fun_B->InstanceTemplate()->SetHandler( 2174 v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42)); 2175 v8::Local<v8::String> class_name = v8_str("B"); 2176 fun_B->SetClassName(class_name); 2177 2178 v8::Local<v8::String> subclass_name = v8_str("C"); 2179 v8::Local<v8::Object> b_proto; 2180 v8::Local<v8::Object> c_proto; 2181 // Perform several iterations to make sure the cache doesn't break 2182 // subclassing. 2183 for (int i = 0; i < 3; i++) { 2184 Local<v8::Function> function_B = 2185 fun_B->GetFunction(env.local()).ToLocalChecked(); 2186 if (i == 0) { 2187 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust()); 2188 CompileRun("function C() {}"); 2189 c_proto = 2190 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked(); 2191 } 2192 Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)") 2193 ->ToObject(env.local()) 2194 .ToLocalChecked(); 2195 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust()); 2196 2197 CHECK(subclass_name->StrictEquals(instance->GetConstructorName())); 2198 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); 2199 2200 CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); 2201 CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); 2202 } 2203 } 2204 2205 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 2206 ApiTestFuzzer::Fuzz(); 2207 args.GetReturnValue().Set(v8_num(17.2)); 2208 } 2209 2210 2211 static void GetKnurd(Local<String> property, 2212 const v8::PropertyCallbackInfo<v8::Value>& info) { 2213 ApiTestFuzzer::Fuzz(); 2214 info.GetReturnValue().Set(v8_num(15.2)); 2215 } 2216 2217 2218 THREADED_TEST(DescriptorInheritance) { 2219 v8::Isolate* isolate = CcTest::isolate(); 2220 v8::HandleScope scope(isolate); 2221 v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate); 2222 super->PrototypeTemplate()->Set(isolate, "flabby", 2223 v8::FunctionTemplate::New(isolate, 2224 GetFlabby)); 2225 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14)); 2226 2227 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 2228 2229 v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate); 2230 base1->Inherit(super); 2231 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1)); 2232 2233 v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate); 2234 base2->Inherit(super); 2235 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1)); 2236 2237 LocalContext env; 2238 2239 CHECK(env->Global() 2240 ->Set(env.local(), v8_str("s"), 2241 super->GetFunction(env.local()).ToLocalChecked()) 2242 .FromJust()); 2243 CHECK(env->Global() 2244 ->Set(env.local(), v8_str("base1"), 2245 base1->GetFunction(env.local()).ToLocalChecked()) 2246 .FromJust()); 2247 CHECK(env->Global() 2248 ->Set(env.local(), v8_str("base2"), 2249 base2->GetFunction(env.local()).ToLocalChecked()) 2250 .FromJust()); 2251 2252 // Checks right __proto__ chain. 2253 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype") 2254 ->BooleanValue(env.local()) 2255 .FromJust()); 2256 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype") 2257 ->BooleanValue(env.local()) 2258 .FromJust()); 2259 2260 CHECK(v8_compile("s.prototype.PI == 3.14") 2261 ->Run(env.local()) 2262 .ToLocalChecked() 2263 ->BooleanValue(env.local()) 2264 .FromJust()); 2265 2266 // Instance accessor should not be visible on function object or its prototype 2267 CHECK( 2268 CompileRun("s.knurd == undefined")->BooleanValue(env.local()).FromJust()); 2269 CHECK(CompileRun("s.prototype.knurd == undefined") 2270 ->BooleanValue(env.local()) 2271 .FromJust()); 2272 CHECK(CompileRun("base1.prototype.knurd == undefined") 2273 ->BooleanValue(env.local()) 2274 .FromJust()); 2275 2276 CHECK(env->Global() 2277 ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local()) 2278 .ToLocalChecked() 2279 ->NewInstance(env.local()) 2280 .ToLocalChecked()) 2281 .FromJust()); 2282 CHECK_EQ(17.2, 2283 CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust()); 2284 CHECK(CompileRun("'flabby' in obj")->BooleanValue(env.local()).FromJust()); 2285 CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust()); 2286 CHECK(CompileRun("'knurd' in obj")->BooleanValue(env.local()).FromJust()); 2287 CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust()); 2288 2289 CHECK(env->Global() 2290 ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local()) 2291 .ToLocalChecked() 2292 ->NewInstance(env.local()) 2293 .ToLocalChecked()) 2294 .FromJust()); 2295 CHECK_EQ(17.2, 2296 CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust()); 2297 CHECK(CompileRun("'flabby' in obj2")->BooleanValue(env.local()).FromJust()); 2298 CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust()); 2299 CHECK(CompileRun("'knurd' in obj2")->BooleanValue(env.local()).FromJust()); 2300 CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust()); 2301 2302 // base1 and base2 cannot cross reference to each's prototype 2303 CHECK(CompileRun("obj.v2")->IsUndefined()); 2304 CHECK(CompileRun("obj2.v1")->IsUndefined()); 2305 } 2306 2307 THREADED_TEST(DescriptorInheritance2) { 2308 LocalContext env; 2309 v8::Isolate* isolate = CcTest::isolate(); 2310 v8::HandleScope scope(isolate); 2311 v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); 2312 fun_A->SetClassName(v8_str("A")); 2313 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd); 2314 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk); 2315 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino); 2316 2317 v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); 2318 fun_B->SetClassName(v8_str("B")); 2319 fun_B->Inherit(fun_A); 2320 2321 v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate); 2322 fun_C->SetClassName(v8_str("C")); 2323 fun_C->Inherit(fun_B); 2324 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd); 2325 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk); 2326 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino); 2327 2328 v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate); 2329 fun_D->SetClassName(v8_str("D")); 2330 fun_D->Inherit(fun_C); 2331 2332 v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate); 2333 fun_E->SetClassName(v8_str("E")); 2334 fun_E->Inherit(fun_D); 2335 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd); 2336 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk); 2337 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino); 2338 2339 v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate); 2340 fun_F->SetClassName(v8_str("F")); 2341 fun_F->Inherit(fun_E); 2342 v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate(); 2343 const int kDataPropertiesNumber = 100; 2344 for (int i = 0; i < kDataPropertiesNumber; i++) { 2345 v8::Local<v8::Value> val = v8_num(i); 2346 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked(); 2347 v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str); 2348 2349 templ->Set(name, val); 2350 templ->Set(val_str, val); 2351 } 2352 2353 CHECK(env->Global() 2354 ->Set(env.local(), v8_str("F"), 2355 fun_F->GetFunction(env.local()).ToLocalChecked()) 2356 .FromJust()); 2357 2358 v8::Local<v8::Script> script = v8_compile("o = new F()"); 2359 2360 for (int i = 0; i < 100; i++) { 2361 v8::HandleScope scope(isolate); 2362 script->Run(env.local()).ToLocalChecked(); 2363 } 2364 v8::Local<v8::Object> object = script->Run(env.local()) 2365 .ToLocalChecked() 2366 ->ToObject(env.local()) 2367 .ToLocalChecked(); 2368 2369 CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust()); 2370 CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust()); 2371 CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust()); 2372 2373 CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust()); 2374 CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust()); 2375 CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust()); 2376 2377 CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust()); 2378 CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust()); 2379 CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust()); 2380 2381 for (int i = 0; i < kDataPropertiesNumber; i++) { 2382 v8::Local<v8::Value> val = v8_num(i); 2383 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked(); 2384 v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str); 2385 2386 CHECK_EQ(i, object->Get(env.local(), name) 2387 .ToLocalChecked() 2388 ->IntegerValue(env.local()) 2389 .FromJust()); 2390 CHECK_EQ(i, object->Get(env.local(), val) 2391 .ToLocalChecked() 2392 ->IntegerValue(env.local()) 2393 .FromJust()); 2394 } 2395 } 2396 2397 2398 // Helper functions for Interceptor/Accessor interaction tests 2399 2400 void SimpleAccessorGetter(Local<String> name, 2401 const v8::PropertyCallbackInfo<v8::Value>& info) { 2402 Local<Object> self = Local<Object>::Cast(info.This()); 2403 info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(), 2404 String::Concat(v8_str("accessor_"), name)) 2405 .ToLocalChecked()); 2406 } 2407 2408 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 2409 const v8::PropertyCallbackInfo<void>& info) { 2410 Local<Object> self = Local<Object>::Cast(info.This()); 2411 CHECK(self->Set(info.GetIsolate()->GetCurrentContext(), 2412 String::Concat(v8_str("accessor_"), name), value) 2413 .FromJust()); 2414 } 2415 2416 void SymbolAccessorGetter(Local<Name> name, 2417 const v8::PropertyCallbackInfo<v8::Value>& info) { 2418 CHECK(name->IsSymbol()); 2419 Local<Symbol> sym = Local<Symbol>::Cast(name); 2420 if (sym->Name()->IsUndefined()) 2421 return; 2422 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info); 2423 } 2424 2425 void SymbolAccessorSetter(Local<Name> name, Local<Value> value, 2426 const v8::PropertyCallbackInfo<void>& info) { 2427 CHECK(name->IsSymbol()); 2428 Local<Symbol> sym = Local<Symbol>::Cast(name); 2429 if (sym->Name()->IsUndefined()) 2430 return; 2431 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info); 2432 } 2433 2434 void SymbolAccessorGetterReturnsDefault( 2435 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 2436 CHECK(name->IsSymbol()); 2437 Local<Symbol> sym = Local<Symbol>::Cast(name); 2438 if (sym->Name()->IsUndefined()) return; 2439 info.GetReturnValue().Set(info.Data()); 2440 } 2441 2442 static void ThrowingSymbolAccessorGetter( 2443 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 2444 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name)); 2445 } 2446 2447 2448 THREADED_TEST(AccessorIsPreservedOnAttributeChange) { 2449 v8::Isolate* isolate = CcTest::isolate(); 2450 v8::HandleScope scope(isolate); 2451 LocalContext env; 2452 v8::Local<v8::Value> res = CompileRun("var a = []; a;"); 2453 i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); 2454 CHECK(a->map()->instance_descriptors()->IsFixedArray()); 2455 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2456 CompileRun("Object.defineProperty(a, 'length', { writable: false });"); 2457 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2458 // But we should still have an AccessorInfo. 2459 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); 2460 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR); 2461 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state()); 2462 CHECK(it.GetAccessors()->IsAccessorInfo()); 2463 } 2464 2465 2466 THREADED_TEST(UndefinedIsNotEnumerable) { 2467 LocalContext env; 2468 v8::HandleScope scope(env->GetIsolate()); 2469 v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)"); 2470 CHECK(result->IsFalse()); 2471 } 2472 2473 2474 v8::Local<Script> call_recursively_script; 2475 static const int kTargetRecursionDepth = 150; // near maximum 2476 2477 2478 static void CallScriptRecursivelyCall( 2479 const v8::FunctionCallbackInfo<v8::Value>& args) { 2480 ApiTestFuzzer::Fuzz(); 2481 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 2482 int depth = args.This() 2483 ->Get(context, v8_str("depth")) 2484 .ToLocalChecked() 2485 ->Int32Value(context) 2486 .FromJust(); 2487 if (depth == kTargetRecursionDepth) return; 2488 CHECK(args.This() 2489 ->Set(context, v8_str("depth"), 2490 v8::Integer::New(args.GetIsolate(), depth + 1)) 2491 .FromJust()); 2492 args.GetReturnValue().Set( 2493 call_recursively_script->Run(context).ToLocalChecked()); 2494 } 2495 2496 2497 static void CallFunctionRecursivelyCall( 2498 const v8::FunctionCallbackInfo<v8::Value>& args) { 2499 ApiTestFuzzer::Fuzz(); 2500 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 2501 int depth = args.This() 2502 ->Get(context, v8_str("depth")) 2503 .ToLocalChecked() 2504 ->Int32Value(context) 2505 .FromJust(); 2506 if (depth == kTargetRecursionDepth) { 2507 printf("[depth = %d]\n", depth); 2508 return; 2509 } 2510 CHECK(args.This() 2511 ->Set(context, v8_str("depth"), 2512 v8::Integer::New(args.GetIsolate(), depth + 1)) 2513 .FromJust()); 2514 v8::Local<Value> function = 2515 args.This() 2516 ->Get(context, v8_str("callFunctionRecursively")) 2517 .ToLocalChecked(); 2518 args.GetReturnValue().Set(function.As<Function>() 2519 ->Call(context, args.This(), 0, NULL) 2520 .ToLocalChecked()); 2521 } 2522 2523 2524 THREADED_TEST(DeepCrossLanguageRecursion) { 2525 v8::Isolate* isolate = CcTest::isolate(); 2526 v8::HandleScope scope(isolate); 2527 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 2528 global->Set(v8_str("callScriptRecursively"), 2529 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall)); 2530 global->Set(v8_str("callFunctionRecursively"), 2531 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall)); 2532 LocalContext env(NULL, global); 2533 2534 CHECK(env->Global() 2535 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0)) 2536 .FromJust()); 2537 call_recursively_script = v8_compile("callScriptRecursively()"); 2538 call_recursively_script->Run(env.local()).ToLocalChecked(); 2539 call_recursively_script = v8::Local<Script>(); 2540 2541 CHECK(env->Global() 2542 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0)) 2543 .FromJust()); 2544 CompileRun("callFunctionRecursively()"); 2545 } 2546 2547 2548 static void ThrowingPropertyHandlerGet( 2549 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) { 2550 // Since this interceptor is used on "with" objects, the runtime will look up 2551 // @@unscopables. Punt. 2552 if (key->IsSymbol()) return; 2553 ApiTestFuzzer::Fuzz(); 2554 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key)); 2555 } 2556 2557 2558 static void ThrowingPropertyHandlerSet( 2559 Local<Name> key, Local<Value>, 2560 const v8::PropertyCallbackInfo<v8::Value>& info) { 2561 info.GetIsolate()->ThrowException(key); 2562 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2563 } 2564 2565 2566 THREADED_TEST(CallbackExceptionRegression) { 2567 v8::Isolate* isolate = CcTest::isolate(); 2568 v8::HandleScope scope(isolate); 2569 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 2570 obj->SetHandler(v8::NamedPropertyHandlerConfiguration( 2571 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet)); 2572 LocalContext env; 2573 CHECK(env->Global() 2574 ->Set(env.local(), v8_str("obj"), 2575 obj->NewInstance(env.local()).ToLocalChecked()) 2576 .FromJust()); 2577 v8::Local<Value> otto = 2578 CompileRun("try { with (obj) { otto; } } catch (e) { e; }"); 2579 CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust()); 2580 v8::Local<Value> netto = 2581 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }"); 2582 CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust()); 2583 } 2584 2585 2586 THREADED_TEST(FunctionPrototype) { 2587 v8::Isolate* isolate = CcTest::isolate(); 2588 v8::HandleScope scope(isolate); 2589 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate); 2590 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2591 LocalContext env; 2592 CHECK(env->Global() 2593 ->Set(env.local(), v8_str("Foo"), 2594 Foo->GetFunction(env.local()).ToLocalChecked()) 2595 .FromJust()); 2596 Local<Script> script = v8_compile("Foo.prototype.plak"); 2597 CHECK_EQ(v8_run_int32value(script), 321); 2598 } 2599 2600 2601 THREADED_TEST(InternalFields) { 2602 LocalContext env; 2603 v8::Isolate* isolate = env->GetIsolate(); 2604 v8::HandleScope scope(isolate); 2605 2606 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2607 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2608 instance_templ->SetInternalFieldCount(1); 2609 Local<v8::Object> obj = templ->GetFunction(env.local()) 2610 .ToLocalChecked() 2611 ->NewInstance(env.local()) 2612 .ToLocalChecked(); 2613 CHECK_EQ(1, obj->InternalFieldCount()); 2614 CHECK(obj->GetInternalField(0)->IsUndefined()); 2615 obj->SetInternalField(0, v8_num(17)); 2616 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust()); 2617 } 2618 2619 2620 THREADED_TEST(GlobalObjectInternalFields) { 2621 v8::Isolate* isolate = CcTest::isolate(); 2622 v8::HandleScope scope(isolate); 2623 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 2624 global_template->SetInternalFieldCount(1); 2625 LocalContext env(NULL, global_template); 2626 v8::Local<v8::Object> global_proxy = env->Global(); 2627 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2628 CHECK_EQ(1, global->InternalFieldCount()); 2629 CHECK(global->GetInternalField(0)->IsUndefined()); 2630 global->SetInternalField(0, v8_num(17)); 2631 CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust()); 2632 } 2633 2634 2635 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2636 LocalContext env; 2637 v8::HandleScope scope(CcTest::isolate()); 2638 2639 v8::Local<v8::Object> global = env->Global(); 2640 CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust()); 2641 CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust()); 2642 } 2643 2644 2645 static void CheckAlignedPointerInInternalField(Local<v8::Object> obj, 2646 void* value) { 2647 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2648 obj->SetAlignedPointerInInternalField(0, value); 2649 CcTest::heap()->CollectAllGarbage(); 2650 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2651 } 2652 2653 2654 THREADED_TEST(InternalFieldsAlignedPointers) { 2655 LocalContext env; 2656 v8::Isolate* isolate = env->GetIsolate(); 2657 v8::HandleScope scope(isolate); 2658 2659 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2660 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2661 instance_templ->SetInternalFieldCount(1); 2662 Local<v8::Object> obj = templ->GetFunction(env.local()) 2663 .ToLocalChecked() 2664 ->NewInstance(env.local()) 2665 .ToLocalChecked(); 2666 CHECK_EQ(1, obj->InternalFieldCount()); 2667 2668 CheckAlignedPointerInInternalField(obj, NULL); 2669 2670 int* heap_allocated = new int[100]; 2671 CheckAlignedPointerInInternalField(obj, heap_allocated); 2672 delete[] heap_allocated; 2673 2674 int stack_allocated[100]; 2675 CheckAlignedPointerInInternalField(obj, stack_allocated); 2676 2677 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2678 CheckAlignedPointerInInternalField(obj, huge); 2679 2680 v8::Global<v8::Object> persistent(isolate, obj); 2681 CHECK_EQ(1, Object::InternalFieldCount(persistent)); 2682 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0)); 2683 } 2684 2685 2686 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index, 2687 void* value) { 2688 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2689 (*env)->SetAlignedPointerInEmbedderData(index, value); 2690 CcTest::heap()->CollectAllGarbage(); 2691 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2692 } 2693 2694 2695 static void* AlignedTestPointer(int i) { 2696 return reinterpret_cast<void*>(i * 1234); 2697 } 2698 2699 2700 THREADED_TEST(EmbedderDataAlignedPointers) { 2701 LocalContext env; 2702 v8::HandleScope scope(env->GetIsolate()); 2703 2704 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2705 2706 int* heap_allocated = new int[100]; 2707 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2708 delete[] heap_allocated; 2709 2710 int stack_allocated[100]; 2711 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2712 2713 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2714 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2715 2716 // Test growing of the embedder data's backing store. 2717 for (int i = 0; i < 100; i++) { 2718 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2719 } 2720 CcTest::heap()->CollectAllGarbage(); 2721 for (int i = 0; i < 100; i++) { 2722 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2723 } 2724 } 2725 2726 2727 static void CheckEmbedderData(LocalContext* env, int index, 2728 v8::Local<Value> data) { 2729 (*env)->SetEmbedderData(index, data); 2730 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2731 } 2732 2733 2734 THREADED_TEST(EmbedderData) { 2735 LocalContext env; 2736 v8::Isolate* isolate = env->GetIsolate(); 2737 v8::HandleScope scope(isolate); 2738 2739 CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps")); 2740 CheckEmbedderData(&env, 2, v8_str("over the lazy dog.")); 2741 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345)); 2742 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true)); 2743 } 2744 2745 2746 THREADED_TEST(IdentityHash) { 2747 LocalContext env; 2748 v8::Isolate* isolate = env->GetIsolate(); 2749 v8::HandleScope scope(isolate); 2750 2751 // Ensure that the test starts with an fresh heap to test whether the hash 2752 // code is based on the address. 2753 CcTest::heap()->CollectAllGarbage(); 2754 Local<v8::Object> obj = v8::Object::New(isolate); 2755 int hash = obj->GetIdentityHash(); 2756 int hash1 = obj->GetIdentityHash(); 2757 CHECK_EQ(hash, hash1); 2758 int hash2 = v8::Object::New(isolate)->GetIdentityHash(); 2759 // Since the identity hash is essentially a random number two consecutive 2760 // objects should not be assigned the same hash code. If the test below fails 2761 // the random number generator should be evaluated. 2762 CHECK_NE(hash, hash2); 2763 CcTest::heap()->CollectAllGarbage(); 2764 int hash3 = v8::Object::New(isolate)->GetIdentityHash(); 2765 // Make sure that the identity hash is not based on the initial address of 2766 // the object alone. If the test below fails the random number generator 2767 // should be evaluated. 2768 CHECK_NE(hash, hash3); 2769 int hash4 = obj->GetIdentityHash(); 2770 CHECK_EQ(hash, hash4); 2771 2772 // Check identity hashes behaviour in the presence of JS accessors. 2773 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2774 { 2775 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2776 Local<v8::Object> o1 = v8::Object::New(isolate); 2777 Local<v8::Object> o2 = v8::Object::New(isolate); 2778 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2779 } 2780 { 2781 CompileRun( 2782 "function cnst() { return 42; };\n" 2783 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2784 Local<v8::Object> o1 = v8::Object::New(isolate); 2785 Local<v8::Object> o2 = v8::Object::New(isolate); 2786 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2787 } 2788 } 2789 2790 2791 void GlobalProxyIdentityHash(bool set_in_js) { 2792 LocalContext env; 2793 v8::Isolate* isolate = env->GetIsolate(); 2794 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 2795 v8::HandleScope scope(isolate); 2796 Local<Object> global_proxy = env->Global(); 2797 i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy); 2798 CHECK(env->Global() 2799 ->Set(env.local(), v8_str("global"), global_proxy) 2800 .FromJust()); 2801 int32_t hash1; 2802 if (set_in_js) { 2803 CompileRun("var m = new Set(); m.add(global);"); 2804 i::Object* original_hash = i_global_proxy->GetHash(); 2805 CHECK(original_hash->IsSmi()); 2806 hash1 = i::Smi::cast(original_hash)->value(); 2807 } else { 2808 hash1 = i::Object::GetOrCreateHash(i_isolate, i_global_proxy)->value(); 2809 } 2810 // Hash should be retained after being detached. 2811 env->DetachGlobal(); 2812 int hash2 = global_proxy->GetIdentityHash(); 2813 CHECK_EQ(hash1, hash2); 2814 { 2815 // Re-attach global proxy to a new context, hash should stay the same. 2816 LocalContext env2(NULL, Local<ObjectTemplate>(), global_proxy); 2817 int hash3 = global_proxy->GetIdentityHash(); 2818 CHECK_EQ(hash1, hash3); 2819 } 2820 } 2821 2822 2823 THREADED_TEST(GlobalProxyIdentityHash) { 2824 GlobalProxyIdentityHash(true); 2825 GlobalProxyIdentityHash(false); 2826 } 2827 2828 2829 TEST(SymbolIdentityHash) { 2830 LocalContext env; 2831 v8::Isolate* isolate = env->GetIsolate(); 2832 v8::HandleScope scope(isolate); 2833 2834 { 2835 Local<v8::Symbol> symbol = v8::Symbol::New(isolate); 2836 int hash = symbol->GetIdentityHash(); 2837 int hash1 = symbol->GetIdentityHash(); 2838 CHECK_EQ(hash, hash1); 2839 CcTest::heap()->CollectAllGarbage(); 2840 int hash3 = symbol->GetIdentityHash(); 2841 CHECK_EQ(hash, hash3); 2842 } 2843 2844 { 2845 v8::Local<v8::Symbol> js_symbol = 2846 CompileRun("Symbol('foo')").As<v8::Symbol>(); 2847 int hash = js_symbol->GetIdentityHash(); 2848 int hash1 = js_symbol->GetIdentityHash(); 2849 CHECK_EQ(hash, hash1); 2850 CcTest::heap()->CollectAllGarbage(); 2851 int hash3 = js_symbol->GetIdentityHash(); 2852 CHECK_EQ(hash, hash3); 2853 } 2854 } 2855 2856 2857 TEST(StringIdentityHash) { 2858 LocalContext env; 2859 v8::Isolate* isolate = env->GetIsolate(); 2860 v8::HandleScope scope(isolate); 2861 2862 Local<v8::String> str = v8_str("str1"); 2863 int hash = str->GetIdentityHash(); 2864 int hash1 = str->GetIdentityHash(); 2865 CHECK_EQ(hash, hash1); 2866 CcTest::heap()->CollectAllGarbage(); 2867 int hash3 = str->GetIdentityHash(); 2868 CHECK_EQ(hash, hash3); 2869 2870 Local<v8::String> str2 = v8_str("str1"); 2871 int hash4 = str2->GetIdentityHash(); 2872 CHECK_EQ(hash, hash4); 2873 } 2874 2875 2876 THREADED_TEST(SymbolProperties) { 2877 LocalContext env; 2878 v8::Isolate* isolate = env->GetIsolate(); 2879 v8::HandleScope scope(isolate); 2880 2881 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2882 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2883 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol")); 2884 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3")); 2885 2886 CcTest::heap()->CollectAllGarbage(); 2887 2888 // Check basic symbol functionality. 2889 CHECK(sym1->IsSymbol()); 2890 CHECK(sym2->IsSymbol()); 2891 CHECK(!obj->IsSymbol()); 2892 2893 CHECK(sym1->Equals(env.local(), sym1).FromJust()); 2894 CHECK(sym2->Equals(env.local(), sym2).FromJust()); 2895 CHECK(!sym1->Equals(env.local(), sym2).FromJust()); 2896 CHECK(!sym2->Equals(env.local(), sym1).FromJust()); 2897 CHECK(sym1->StrictEquals(sym1)); 2898 CHECK(sym2->StrictEquals(sym2)); 2899 CHECK(!sym1->StrictEquals(sym2)); 2900 CHECK(!sym2->StrictEquals(sym1)); 2901 2902 CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust()); 2903 2904 v8::Local<v8::Value> sym_val = sym2; 2905 CHECK(sym_val->IsSymbol()); 2906 CHECK(sym_val->Equals(env.local(), sym2).FromJust()); 2907 CHECK(sym_val->StrictEquals(sym2)); 2908 CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust()); 2909 2910 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2911 CHECK(sym_obj->IsSymbolObject()); 2912 CHECK(!sym2->IsSymbolObject()); 2913 CHECK(!obj->IsSymbolObject()); 2914 CHECK(sym_obj->Equals(env.local(), sym2).FromJust()); 2915 CHECK(!sym_obj->StrictEquals(sym2)); 2916 CHECK(v8::SymbolObject::Cast(*sym_obj) 2917 ->Equals(env.local(), sym_obj) 2918 .FromJust()); 2919 CHECK(v8::SymbolObject::Cast(*sym_obj) 2920 ->ValueOf() 2921 ->Equals(env.local(), sym2) 2922 .FromJust()); 2923 2924 // Make sure delete of a non-existent symbol property works. 2925 CHECK(obj->Delete(env.local(), sym1).FromJust()); 2926 CHECK(!obj->Has(env.local(), sym1).FromJust()); 2927 2928 CHECK( 2929 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust()); 2930 CHECK(obj->Has(env.local(), sym1).FromJust()); 2931 CHECK_EQ(1503, obj->Get(env.local(), sym1) 2932 .ToLocalChecked() 2933 ->Int32Value(env.local()) 2934 .FromJust()); 2935 CHECK( 2936 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust()); 2937 CHECK(obj->Has(env.local(), sym1).FromJust()); 2938 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2939 .ToLocalChecked() 2940 ->Int32Value(env.local()) 2941 .FromJust()); 2942 CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust()); 2943 2944 CHECK_EQ(0u, 2945 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2946 unsigned num_props = 2947 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 2948 CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20)) 2949 .FromJust()); 2950 CHECK_EQ(1u, 2951 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2952 CHECK_EQ(num_props + 1, 2953 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 2954 2955 CcTest::heap()->CollectAllGarbage(); 2956 2957 CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter, 2958 SymbolAccessorSetter) 2959 .FromJust()); 2960 CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined()); 2961 CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust()); 2962 CHECK(obj->Get(env.local(), sym3) 2963 .ToLocalChecked() 2964 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2965 .FromJust()); 2966 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 2967 .ToLocalChecked() 2968 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 2969 .FromJust()); 2970 2971 // Add another property and delete it afterwards to force the object in 2972 // slow case. 2973 CHECK( 2974 obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust()); 2975 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2976 .ToLocalChecked() 2977 ->Int32Value(env.local()) 2978 .FromJust()); 2979 CHECK_EQ(2008, obj->Get(env.local(), sym2) 2980 .ToLocalChecked() 2981 ->Int32Value(env.local()) 2982 .FromJust()); 2983 CHECK_EQ(2002, obj->Get(env.local(), sym1) 2984 .ToLocalChecked() 2985 ->Int32Value(env.local()) 2986 .FromJust()); 2987 CHECK_EQ(2u, 2988 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 2989 2990 CHECK(obj->Has(env.local(), sym1).FromJust()); 2991 CHECK(obj->Has(env.local(), sym2).FromJust()); 2992 CHECK(obj->Has(env.local(), sym3).FromJust()); 2993 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust()); 2994 CHECK(obj->Delete(env.local(), sym2).FromJust()); 2995 CHECK(obj->Has(env.local(), sym1).FromJust()); 2996 CHECK(!obj->Has(env.local(), sym2).FromJust()); 2997 CHECK(obj->Has(env.local(), sym3).FromJust()); 2998 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust()); 2999 CHECK_EQ(2002, obj->Get(env.local(), sym1) 3000 .ToLocalChecked() 3001 ->Int32Value(env.local()) 3002 .FromJust()); 3003 CHECK(obj->Get(env.local(), sym3) 3004 .ToLocalChecked() 3005 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 3006 .FromJust()); 3007 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 3008 .ToLocalChecked() 3009 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 3010 .FromJust()); 3011 CHECK_EQ(2u, 3012 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3013 3014 // Symbol properties are inherited. 3015 v8::Local<v8::Object> child = v8::Object::New(isolate); 3016 CHECK(child->SetPrototype(env.local(), obj).FromJust()); 3017 CHECK(child->Has(env.local(), sym1).FromJust()); 3018 CHECK_EQ(2002, child->Get(env.local(), sym1) 3019 .ToLocalChecked() 3020 ->Int32Value(env.local()) 3021 .FromJust()); 3022 CHECK(obj->Get(env.local(), sym3) 3023 .ToLocalChecked() 3024 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 3025 .FromJust()); 3026 CHECK(obj->Get(env.local(), v8_str("accessor_sym3")) 3027 .ToLocalChecked() 3028 ->Equals(env.local(), v8::Integer::New(isolate, 42)) 3029 .FromJust()); 3030 CHECK_EQ(0u, 3031 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3032 } 3033 3034 3035 THREADED_TEST(SymbolTemplateProperties) { 3036 LocalContext env; 3037 v8::Isolate* isolate = env->GetIsolate(); 3038 v8::HandleScope scope(isolate); 3039 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate); 3040 v8::Local<v8::Name> name = v8::Symbol::New(isolate); 3041 CHECK(!name.IsEmpty()); 3042 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate)); 3043 v8::Local<v8::Object> new_instance = 3044 foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked(); 3045 CHECK(!new_instance.IsEmpty()); 3046 CHECK(new_instance->Has(env.local(), name).FromJust()); 3047 } 3048 3049 3050 THREADED_TEST(PrivatePropertiesOnProxies) { 3051 LocalContext env; 3052 v8::Isolate* isolate = env->GetIsolate(); 3053 v8::HandleScope scope(isolate); 3054 3055 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>(); 3056 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>(); 3057 3058 v8::Local<v8::Proxy> proxy = 3059 v8::Proxy::New(env.local(), target, handler).ToLocalChecked(); 3060 3061 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 3062 v8::Local<v8::Private> priv2 = 3063 v8::Private::New(isolate, v8_str("my-private")); 3064 3065 CcTest::heap()->CollectAllGarbage(); 3066 3067 CHECK(priv2->Name() 3068 ->Equals(env.local(), 3069 v8::String::NewFromUtf8(isolate, "my-private", 3070 v8::NewStringType::kNormal) 3071 .ToLocalChecked()) 3072 .FromJust()); 3073 3074 // Make sure delete of a non-existent private symbol property works. 3075 proxy->DeletePrivate(env.local(), priv1).FromJust(); 3076 CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust()); 3077 3078 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503)) 3079 .FromJust()); 3080 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 3081 CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1) 3082 .ToLocalChecked() 3083 ->Int32Value(env.local()) 3084 .FromJust()); 3085 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002)) 3086 .FromJust()); 3087 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 3088 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 3089 .ToLocalChecked() 3090 ->Int32Value(env.local()) 3091 .FromJust()); 3092 3093 CHECK_EQ(0u, 3094 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3095 unsigned num_props = 3096 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 3097 CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8( 3098 isolate, "bla", v8::NewStringType::kNormal) 3099 .ToLocalChecked(), 3100 v8::Integer::New(isolate, 20)) 3101 .FromJust()); 3102 CHECK_EQ(1u, 3103 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3104 CHECK_EQ(num_props + 1, 3105 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 3106 3107 CcTest::heap()->CollectAllGarbage(); 3108 3109 // Add another property and delete it afterwards to force the object in 3110 // slow case. 3111 CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008)) 3112 .FromJust()); 3113 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 3114 .ToLocalChecked() 3115 ->Int32Value(env.local()) 3116 .FromJust()); 3117 CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2) 3118 .ToLocalChecked() 3119 ->Int32Value(env.local()) 3120 .FromJust()); 3121 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 3122 .ToLocalChecked() 3123 ->Int32Value(env.local()) 3124 .FromJust()); 3125 CHECK_EQ(1u, 3126 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3127 3128 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 3129 CHECK(proxy->HasPrivate(env.local(), priv2).FromJust()); 3130 CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust()); 3131 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust()); 3132 CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust()); 3133 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1) 3134 .ToLocalChecked() 3135 ->Int32Value(env.local()) 3136 .FromJust()); 3137 CHECK_EQ(1u, 3138 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3139 3140 // Private properties are not inherited (for the time being). 3141 v8::Local<v8::Object> child = v8::Object::New(isolate); 3142 CHECK(child->SetPrototype(env.local(), proxy).FromJust()); 3143 CHECK(!child->HasPrivate(env.local(), priv1).FromJust()); 3144 CHECK_EQ(0u, 3145 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3146 } 3147 3148 3149 THREADED_TEST(PrivateProperties) { 3150 LocalContext env; 3151 v8::Isolate* isolate = env->GetIsolate(); 3152 v8::HandleScope scope(isolate); 3153 3154 v8::Local<v8::Object> obj = v8::Object::New(isolate); 3155 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 3156 v8::Local<v8::Private> priv2 = 3157 v8::Private::New(isolate, v8_str("my-private")); 3158 3159 CcTest::heap()->CollectAllGarbage(); 3160 3161 CHECK(priv2->Name() 3162 ->Equals(env.local(), 3163 v8::String::NewFromUtf8(isolate, "my-private", 3164 v8::NewStringType::kNormal) 3165 .ToLocalChecked()) 3166 .FromJust()); 3167 3168 // Make sure delete of a non-existent private symbol property works. 3169 obj->DeletePrivate(env.local(), priv1).FromJust(); 3170 CHECK(!obj->HasPrivate(env.local(), priv1).FromJust()); 3171 3172 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503)) 3173 .FromJust()); 3174 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 3175 CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1) 3176 .ToLocalChecked() 3177 ->Int32Value(env.local()) 3178 .FromJust()); 3179 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002)) 3180 .FromJust()); 3181 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 3182 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 3183 .ToLocalChecked() 3184 ->Int32Value(env.local()) 3185 .FromJust()); 3186 3187 CHECK_EQ(0u, 3188 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3189 unsigned num_props = 3190 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length(); 3191 CHECK(obj->Set(env.local(), v8::String::NewFromUtf8( 3192 isolate, "bla", v8::NewStringType::kNormal) 3193 .ToLocalChecked(), 3194 v8::Integer::New(isolate, 20)) 3195 .FromJust()); 3196 CHECK_EQ(1u, 3197 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3198 CHECK_EQ(num_props + 1, 3199 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length()); 3200 3201 CcTest::heap()->CollectAllGarbage(); 3202 3203 // Add another property and delete it afterwards to force the object in 3204 // slow case. 3205 CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008)) 3206 .FromJust()); 3207 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 3208 .ToLocalChecked() 3209 ->Int32Value(env.local()) 3210 .FromJust()); 3211 CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2) 3212 .ToLocalChecked() 3213 ->Int32Value(env.local()) 3214 .FromJust()); 3215 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 3216 .ToLocalChecked() 3217 ->Int32Value(env.local()) 3218 .FromJust()); 3219 CHECK_EQ(1u, 3220 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3221 3222 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 3223 CHECK(obj->HasPrivate(env.local(), priv2).FromJust()); 3224 CHECK(obj->DeletePrivate(env.local(), priv2).FromJust()); 3225 CHECK(obj->HasPrivate(env.local(), priv1).FromJust()); 3226 CHECK(!obj->HasPrivate(env.local(), priv2).FromJust()); 3227 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1) 3228 .ToLocalChecked() 3229 ->Int32Value(env.local()) 3230 .FromJust()); 3231 CHECK_EQ(1u, 3232 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3233 3234 // Private properties are not inherited (for the time being). 3235 v8::Local<v8::Object> child = v8::Object::New(isolate); 3236 CHECK(child->SetPrototype(env.local(), obj).FromJust()); 3237 CHECK(!child->HasPrivate(env.local(), priv1).FromJust()); 3238 CHECK_EQ(0u, 3239 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length()); 3240 } 3241 3242 3243 THREADED_TEST(GlobalSymbols) { 3244 LocalContext env; 3245 v8::Isolate* isolate = env->GetIsolate(); 3246 v8::HandleScope scope(isolate); 3247 3248 v8::Local<String> name = v8_str("my-symbol"); 3249 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name); 3250 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name); 3251 CHECK(glob2->SameValue(glob)); 3252 3253 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name); 3254 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name); 3255 CHECK(glob_api2->SameValue(glob_api)); 3256 CHECK(!glob_api->SameValue(glob)); 3257 3258 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name); 3259 CHECK(!sym->SameValue(glob)); 3260 3261 CompileRun("var sym2 = Symbol.for('my-symbol')"); 3262 v8::Local<Value> sym2 = 3263 env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked(); 3264 CHECK(sym2->SameValue(glob)); 3265 CHECK(!sym2->SameValue(glob_api)); 3266 } 3267 3268 3269 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*), 3270 const char* name) { 3271 LocalContext env; 3272 v8::Isolate* isolate = env->GetIsolate(); 3273 v8::HandleScope scope(isolate); 3274 3275 v8::Local<v8::Symbol> symbol = getter(isolate); 3276 std::string script = std::string("var sym = ") + name; 3277 CompileRun(script.c_str()); 3278 v8::Local<Value> value = 3279 env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked(); 3280 3281 CHECK(!value.IsEmpty()); 3282 CHECK(!symbol.IsEmpty()); 3283 CHECK(value->SameValue(symbol)); 3284 } 3285 3286 3287 THREADED_TEST(WellKnownSymbols) { 3288 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator"); 3289 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables"); 3290 } 3291 3292 3293 THREADED_TEST(GlobalPrivates) { 3294 i::FLAG_allow_natives_syntax = true; 3295 LocalContext env; 3296 v8::Isolate* isolate = env->GetIsolate(); 3297 v8::HandleScope scope(isolate); 3298 3299 v8::Local<String> name = v8_str("my-private"); 3300 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name); 3301 v8::Local<v8::Object> obj = v8::Object::New(isolate); 3302 CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3)) 3303 .FromJust()); 3304 3305 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name); 3306 CHECK(obj->HasPrivate(env.local(), glob2).FromJust()); 3307 3308 v8::Local<v8::Private> priv = v8::Private::New(isolate, name); 3309 CHECK(!obj->HasPrivate(env.local(), priv).FromJust()); 3310 3311 CompileRun("var intern = %CreatePrivateSymbol('my-private')"); 3312 v8::Local<Value> intern = 3313 env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked(); 3314 CHECK(!obj->Has(env.local(), intern).FromJust()); 3315 } 3316 3317 3318 class ScopedArrayBufferContents { 3319 public: 3320 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents) 3321 : contents_(contents) {} 3322 ~ScopedArrayBufferContents() { free(contents_.Data()); } 3323 void* Data() const { return contents_.Data(); } 3324 size_t ByteLength() const { return contents_.ByteLength(); } 3325 3326 private: 3327 const v8::ArrayBuffer::Contents contents_; 3328 }; 3329 3330 template <typename T> 3331 static void CheckInternalFieldsAreZero(v8::Local<T> value) { 3332 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 3333 for (int i = 0; i < value->InternalFieldCount(); i++) { 3334 CHECK_EQ(0, value->GetInternalField(i) 3335 ->Int32Value(CcTest::isolate()->GetCurrentContext()) 3336 .FromJust()); 3337 } 3338 } 3339 3340 3341 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 3342 LocalContext env; 3343 v8::Isolate* isolate = env->GetIsolate(); 3344 v8::HandleScope handle_scope(isolate); 3345 3346 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024); 3347 CheckInternalFieldsAreZero(ab); 3348 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 3349 CHECK(!ab->IsExternal()); 3350 CcTest::heap()->CollectAllGarbage(); 3351 3352 ScopedArrayBufferContents ab_contents(ab->Externalize()); 3353 CHECK(ab->IsExternal()); 3354 3355 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 3356 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 3357 CHECK(data != NULL); 3358 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust()); 3359 3360 v8::Local<v8::Value> result = CompileRun("ab.byteLength"); 3361 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3362 3363 result = CompileRun( 3364 "var u8 = new Uint8Array(ab);" 3365 "u8[0] = 0xFF;" 3366 "u8[1] = 0xAA;" 3367 "u8.length"); 3368 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3369 CHECK_EQ(0xFF, data[0]); 3370 CHECK_EQ(0xAA, data[1]); 3371 data[0] = 0xCC; 3372 data[1] = 0x11; 3373 result = CompileRun("u8[0] + u8[1]"); 3374 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3375 } 3376 3377 3378 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 3379 LocalContext env; 3380 v8::Isolate* isolate = env->GetIsolate(); 3381 v8::HandleScope handle_scope(isolate); 3382 3383 3384 v8::Local<v8::Value> result = CompileRun( 3385 "var ab1 = new ArrayBuffer(2);" 3386 "var u8_a = new Uint8Array(ab1);" 3387 "u8_a[0] = 0xAA;" 3388 "u8_a[1] = 0xFF; u8_a.buffer"); 3389 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 3390 CheckInternalFieldsAreZero(ab1); 3391 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3392 CHECK(!ab1->IsExternal()); 3393 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 3394 CHECK(ab1->IsExternal()); 3395 3396 result = CompileRun("ab1.byteLength"); 3397 CHECK_EQ(2, result->Int32Value(env.local()).FromJust()); 3398 result = CompileRun("u8_a[0]"); 3399 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust()); 3400 result = CompileRun("u8_a[1]"); 3401 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3402 result = CompileRun( 3403 "var u8_b = new Uint8Array(ab1);" 3404 "u8_b[0] = 0xBB;" 3405 "u8_a[0]"); 3406 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust()); 3407 result = CompileRun("u8_b[1]"); 3408 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3409 3410 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3411 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3412 CHECK_EQ(0xBB, ab1_data[0]); 3413 CHECK_EQ(0xFF, ab1_data[1]); 3414 ab1_data[0] = 0xCC; 3415 ab1_data[1] = 0x11; 3416 result = CompileRun("u8_a[0] + u8_a[1]"); 3417 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3418 } 3419 3420 3421 THREADED_TEST(ArrayBuffer_External) { 3422 LocalContext env; 3423 v8::Isolate* isolate = env->GetIsolate(); 3424 v8::HandleScope handle_scope(isolate); 3425 3426 i::ScopedVector<uint8_t> my_data(100); 3427 memset(my_data.start(), 0, 100); 3428 Local<v8::ArrayBuffer> ab3 = 3429 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3430 CheckInternalFieldsAreZero(ab3); 3431 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3432 CHECK(ab3->IsExternal()); 3433 3434 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust()); 3435 3436 v8::Local<v8::Value> result = CompileRun("ab3.byteLength"); 3437 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3438 3439 result = CompileRun( 3440 "var u8_b = new Uint8Array(ab3);" 3441 "u8_b[0] = 0xBB;" 3442 "u8_b[1] = 0xCC;" 3443 "u8_b.length"); 3444 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3445 CHECK_EQ(0xBB, my_data[0]); 3446 CHECK_EQ(0xCC, my_data[1]); 3447 my_data[0] = 0xCC; 3448 my_data[1] = 0x11; 3449 result = CompileRun("u8_b[0] + u8_b[1]"); 3450 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3451 } 3452 3453 3454 THREADED_TEST(ArrayBuffer_DisableNeuter) { 3455 LocalContext env; 3456 v8::Isolate* isolate = env->GetIsolate(); 3457 v8::HandleScope handle_scope(isolate); 3458 3459 i::ScopedVector<uint8_t> my_data(100); 3460 memset(my_data.start(), 0, 100); 3461 Local<v8::ArrayBuffer> ab = 3462 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3463 CHECK(ab->IsNeuterable()); 3464 3465 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab); 3466 buf->set_is_neuterable(false); 3467 3468 CHECK(!ab->IsNeuterable()); 3469 } 3470 3471 3472 static void CheckDataViewIsNeutered(v8::Local<v8::DataView> dv) { 3473 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 3474 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 3475 } 3476 3477 3478 static void CheckIsNeutered(v8::Local<v8::TypedArray> ta) { 3479 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 3480 CHECK_EQ(0, static_cast<int>(ta->Length())); 3481 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 3482 } 3483 3484 3485 static void CheckIsTypedArrayVarNeutered(const char* name) { 3486 i::ScopedVector<char> source(1024); 3487 i::SNPrintF(source, 3488 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 3489 name, name, name); 3490 CHECK(CompileRun(source.start())->IsTrue()); 3491 v8::Local<v8::TypedArray> ta = 3492 v8::Local<v8::TypedArray>::Cast(CompileRun(name)); 3493 CheckIsNeutered(ta); 3494 } 3495 3496 3497 template <typename TypedArray, int kElementSize> 3498 static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab, 3499 int byteOffset, int length) { 3500 v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 3501 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 3502 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 3503 CHECK_EQ(length, static_cast<int>(ta->Length())); 3504 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 3505 return ta; 3506 } 3507 3508 3509 THREADED_TEST(ArrayBuffer_NeuteringApi) { 3510 LocalContext env; 3511 v8::Isolate* isolate = env->GetIsolate(); 3512 v8::HandleScope handle_scope(isolate); 3513 3514 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024); 3515 3516 v8::Local<v8::Uint8Array> u8a = 3517 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 3518 v8::Local<v8::Uint8ClampedArray> u8c = 3519 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 3520 v8::Local<v8::Int8Array> i8a = 3521 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 3522 3523 v8::Local<v8::Uint16Array> u16a = 3524 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 3525 v8::Local<v8::Int16Array> i16a = 3526 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 3527 3528 v8::Local<v8::Uint32Array> u32a = 3529 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 3530 v8::Local<v8::Int32Array> i32a = 3531 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 3532 3533 v8::Local<v8::Float32Array> f32a = 3534 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 3535 v8::Local<v8::Float64Array> f64a = 3536 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 3537 3538 v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 3539 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 3540 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 3541 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 3542 3543 ScopedArrayBufferContents contents(buffer->Externalize()); 3544 buffer->Neuter(); 3545 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 3546 CheckIsNeutered(u8a); 3547 CheckIsNeutered(u8c); 3548 CheckIsNeutered(i8a); 3549 CheckIsNeutered(u16a); 3550 CheckIsNeutered(i16a); 3551 CheckIsNeutered(u32a); 3552 CheckIsNeutered(i32a); 3553 CheckIsNeutered(f32a); 3554 CheckIsNeutered(f64a); 3555 CheckDataViewIsNeutered(dv); 3556 } 3557 3558 3559 THREADED_TEST(ArrayBuffer_NeuteringScript) { 3560 LocalContext env; 3561 v8::Isolate* isolate = env->GetIsolate(); 3562 v8::HandleScope handle_scope(isolate); 3563 3564 CompileRun( 3565 "var ab = new ArrayBuffer(1024);" 3566 "var u8a = new Uint8Array(ab, 1, 1023);" 3567 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 3568 "var i8a = new Int8Array(ab, 1, 1023);" 3569 "var u16a = new Uint16Array(ab, 2, 511);" 3570 "var i16a = new Int16Array(ab, 2, 511);" 3571 "var u32a = new Uint32Array(ab, 4, 255);" 3572 "var i32a = new Int32Array(ab, 4, 255);" 3573 "var f32a = new Float32Array(ab, 4, 255);" 3574 "var f64a = new Float64Array(ab, 8, 127);" 3575 "var dv = new DataView(ab, 1, 1023);"); 3576 3577 v8::Local<v8::ArrayBuffer> ab = 3578 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 3579 3580 v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv")); 3581 3582 ScopedArrayBufferContents contents(ab->Externalize()); 3583 ab->Neuter(); 3584 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 3585 CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength"))); 3586 3587 CheckIsTypedArrayVarNeutered("u8a"); 3588 CheckIsTypedArrayVarNeutered("u8c"); 3589 CheckIsTypedArrayVarNeutered("i8a"); 3590 CheckIsTypedArrayVarNeutered("u16a"); 3591 CheckIsTypedArrayVarNeutered("i16a"); 3592 CheckIsTypedArrayVarNeutered("u32a"); 3593 CheckIsTypedArrayVarNeutered("i32a"); 3594 CheckIsTypedArrayVarNeutered("f32a"); 3595 CheckIsTypedArrayVarNeutered("f64a"); 3596 3597 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 3598 CheckDataViewIsNeutered(dv); 3599 } 3600 3601 3602 class ScopedSharedArrayBufferContents { 3603 public: 3604 explicit ScopedSharedArrayBufferContents( 3605 const v8::SharedArrayBuffer::Contents& contents) 3606 : contents_(contents) {} 3607 ~ScopedSharedArrayBufferContents() { free(contents_.Data()); } 3608 void* Data() const { return contents_.Data(); } 3609 size_t ByteLength() const { return contents_.ByteLength(); } 3610 3611 private: 3612 const v8::SharedArrayBuffer::Contents contents_; 3613 }; 3614 3615 3616 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) { 3617 i::FLAG_harmony_sharedarraybuffer = true; 3618 LocalContext env; 3619 v8::Isolate* isolate = env->GetIsolate(); 3620 v8::HandleScope handle_scope(isolate); 3621 3622 Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024); 3623 CheckInternalFieldsAreZero(ab); 3624 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 3625 CHECK(!ab->IsExternal()); 3626 CcTest::heap()->CollectAllGarbage(); 3627 3628 ScopedSharedArrayBufferContents ab_contents(ab->Externalize()); 3629 CHECK(ab->IsExternal()); 3630 3631 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 3632 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 3633 CHECK(data != NULL); 3634 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust()); 3635 3636 v8::Local<v8::Value> result = CompileRun("ab.byteLength"); 3637 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3638 3639 result = CompileRun( 3640 "var u8 = new Uint8Array(ab);" 3641 "u8[0] = 0xFF;" 3642 "u8[1] = 0xAA;" 3643 "u8.length"); 3644 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust()); 3645 CHECK_EQ(0xFF, data[0]); 3646 CHECK_EQ(0xAA, data[1]); 3647 data[0] = 0xCC; 3648 data[1] = 0x11; 3649 result = CompileRun("u8[0] + u8[1]"); 3650 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3651 } 3652 3653 3654 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) { 3655 i::FLAG_harmony_sharedarraybuffer = true; 3656 LocalContext env; 3657 v8::Isolate* isolate = env->GetIsolate(); 3658 v8::HandleScope handle_scope(isolate); 3659 3660 3661 v8::Local<v8::Value> result = CompileRun( 3662 "var ab1 = new SharedArrayBuffer(2);" 3663 "var u8_a = new Uint8Array(ab1);" 3664 "u8_a[0] = 0xAA;" 3665 "u8_a[1] = 0xFF; u8_a.buffer"); 3666 Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result); 3667 CheckInternalFieldsAreZero(ab1); 3668 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3669 CHECK(!ab1->IsExternal()); 3670 ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize()); 3671 CHECK(ab1->IsExternal()); 3672 3673 result = CompileRun("ab1.byteLength"); 3674 CHECK_EQ(2, result->Int32Value(env.local()).FromJust()); 3675 result = CompileRun("u8_a[0]"); 3676 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust()); 3677 result = CompileRun("u8_a[1]"); 3678 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3679 result = CompileRun( 3680 "var u8_b = new Uint8Array(ab1);" 3681 "u8_b[0] = 0xBB;" 3682 "u8_a[0]"); 3683 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust()); 3684 result = CompileRun("u8_b[1]"); 3685 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust()); 3686 3687 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3688 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3689 CHECK_EQ(0xBB, ab1_data[0]); 3690 CHECK_EQ(0xFF, ab1_data[1]); 3691 ab1_data[0] = 0xCC; 3692 ab1_data[1] = 0x11; 3693 result = CompileRun("u8_a[0] + u8_a[1]"); 3694 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3695 } 3696 3697 3698 THREADED_TEST(SharedArrayBuffer_External) { 3699 i::FLAG_harmony_sharedarraybuffer = true; 3700 LocalContext env; 3701 v8::Isolate* isolate = env->GetIsolate(); 3702 v8::HandleScope handle_scope(isolate); 3703 3704 i::ScopedVector<uint8_t> my_data(100); 3705 memset(my_data.start(), 0, 100); 3706 Local<v8::SharedArrayBuffer> ab3 = 3707 v8::SharedArrayBuffer::New(isolate, my_data.start(), 100); 3708 CheckInternalFieldsAreZero(ab3); 3709 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3710 CHECK(ab3->IsExternal()); 3711 3712 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust()); 3713 3714 v8::Local<v8::Value> result = CompileRun("ab3.byteLength"); 3715 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3716 3717 result = CompileRun( 3718 "var u8_b = new Uint8Array(ab3);" 3719 "u8_b[0] = 0xBB;" 3720 "u8_b[1] = 0xCC;" 3721 "u8_b.length"); 3722 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 3723 CHECK_EQ(0xBB, my_data[0]); 3724 CHECK_EQ(0xCC, my_data[1]); 3725 my_data[0] = 0xCC; 3726 my_data[1] = 0x11; 3727 result = CompileRun("u8_b[0] + u8_b[1]"); 3728 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust()); 3729 } 3730 3731 3732 THREADED_TEST(HiddenProperties) { 3733 LocalContext env; 3734 v8::Isolate* isolate = env->GetIsolate(); 3735 v8::HandleScope scope(isolate); 3736 3737 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3738 v8::Local<v8::Private> key = 3739 v8::Private::ForApi(isolate, v8_str("api-test::hidden-key")); 3740 v8::Local<v8::String> empty = v8_str(""); 3741 v8::Local<v8::String> prop_name = v8_str("prop_name"); 3742 3743 CcTest::heap()->CollectAllGarbage(); 3744 3745 // Make sure delete of a non-existent hidden value works 3746 obj->DeletePrivate(env.local(), key).FromJust(); 3747 3748 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503)) 3749 .FromJust()); 3750 CHECK_EQ(1503, obj->GetPrivate(env.local(), key) 3751 .ToLocalChecked() 3752 ->Int32Value(env.local()) 3753 .FromJust()); 3754 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002)) 3755 .FromJust()); 3756 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3757 .ToLocalChecked() 3758 ->Int32Value(env.local()) 3759 .FromJust()); 3760 3761 CcTest::heap()->CollectAllGarbage(); 3762 3763 // Make sure we do not find the hidden property. 3764 CHECK(!obj->Has(env.local(), empty).FromJust()); 3765 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3766 .ToLocalChecked() 3767 ->Int32Value(env.local()) 3768 .FromJust()); 3769 CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined()); 3770 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3771 .ToLocalChecked() 3772 ->Int32Value(env.local()) 3773 .FromJust()); 3774 CHECK( 3775 obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust()); 3776 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3777 .ToLocalChecked() 3778 ->Int32Value(env.local()) 3779 .FromJust()); 3780 CHECK_EQ(2003, obj->Get(env.local(), empty) 3781 .ToLocalChecked() 3782 ->Int32Value(env.local()) 3783 .FromJust()); 3784 3785 CcTest::heap()->CollectAllGarbage(); 3786 3787 // Add another property and delete it afterwards to force the object in 3788 // slow case. 3789 CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008)) 3790 .FromJust()); 3791 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3792 .ToLocalChecked() 3793 ->Int32Value(env.local()) 3794 .FromJust()); 3795 CHECK_EQ(2008, obj->Get(env.local(), prop_name) 3796 .ToLocalChecked() 3797 ->Int32Value(env.local()) 3798 .FromJust()); 3799 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3800 .ToLocalChecked() 3801 ->Int32Value(env.local()) 3802 .FromJust()); 3803 CHECK(obj->Delete(env.local(), prop_name).FromJust()); 3804 CHECK_EQ(2002, obj->GetPrivate(env.local(), key) 3805 .ToLocalChecked() 3806 ->Int32Value(env.local()) 3807 .FromJust()); 3808 3809 CcTest::heap()->CollectAllGarbage(); 3810 3811 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002)) 3812 .FromJust()); 3813 CHECK(obj->DeletePrivate(env.local(), key).FromJust()); 3814 CHECK(!obj->HasPrivate(env.local(), key).FromJust()); 3815 } 3816 3817 3818 THREADED_TEST(Regress97784) { 3819 // Regression test for crbug.com/97784 3820 // Messing with the Object.prototype should not have effect on 3821 // hidden properties. 3822 LocalContext env; 3823 v8::HandleScope scope(env->GetIsolate()); 3824 3825 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3826 v8::Local<v8::Private> key = 3827 v8::Private::New(env->GetIsolate(), v8_str("hidden")); 3828 3829 CompileRun( 3830 "set_called = false;" 3831 "Object.defineProperty(" 3832 " Object.prototype," 3833 " 'hidden'," 3834 " {get: function() { return 45; }," 3835 " set: function() { set_called = true; }})"); 3836 3837 CHECK(!obj->HasPrivate(env.local(), key).FromJust()); 3838 // Make sure that the getter and setter from Object.prototype is not invoked. 3839 // If it did we would have full access to the hidden properties in 3840 // the accessor. 3841 CHECK( 3842 obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42)) 3843 .FromJust()); 3844 ExpectFalse("set_called"); 3845 CHECK_EQ(42, obj->GetPrivate(env.local(), key) 3846 .ToLocalChecked() 3847 ->Int32Value(env.local()) 3848 .FromJust()); 3849 } 3850 3851 3852 THREADED_TEST(External) { 3853 v8::HandleScope scope(CcTest::isolate()); 3854 int x = 3; 3855 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x); 3856 LocalContext env; 3857 CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust()); 3858 Local<Value> reext_obj = CompileRun("this.ext"); 3859 v8::Local<v8::External> reext = reext_obj.As<v8::External>(); 3860 int* ptr = static_cast<int*>(reext->Value()); 3861 CHECK_EQ(x, 3); 3862 *ptr = 10; 3863 CHECK_EQ(x, 10); 3864 3865 // Make sure unaligned pointers are wrapped properly. 3866 char* data = i::StrDup("0123456789"); 3867 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]); 3868 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]); 3869 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]); 3870 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]); 3871 3872 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3873 CHECK_EQ('0', *char_ptr); 3874 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3875 CHECK_EQ('1', *char_ptr); 3876 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3877 CHECK_EQ('2', *char_ptr); 3878 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3879 CHECK_EQ('3', *char_ptr); 3880 i::DeleteArray(data); 3881 } 3882 3883 3884 THREADED_TEST(GlobalHandle) { 3885 v8::Isolate* isolate = CcTest::isolate(); 3886 v8::Persistent<String> global; 3887 { 3888 v8::HandleScope scope(isolate); 3889 global.Reset(isolate, v8_str("str")); 3890 } 3891 { 3892 v8::HandleScope scope(isolate); 3893 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3894 } 3895 global.Reset(); 3896 { 3897 v8::HandleScope scope(isolate); 3898 global.Reset(isolate, v8_str("str")); 3899 } 3900 { 3901 v8::HandleScope scope(isolate); 3902 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3903 } 3904 global.Reset(); 3905 } 3906 3907 3908 THREADED_TEST(ResettingGlobalHandle) { 3909 v8::Isolate* isolate = CcTest::isolate(); 3910 v8::Persistent<String> global; 3911 { 3912 v8::HandleScope scope(isolate); 3913 global.Reset(isolate, v8_str("str")); 3914 } 3915 v8::internal::GlobalHandles* global_handles = 3916 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3917 int initial_handle_count = global_handles->global_handles_count(); 3918 { 3919 v8::HandleScope scope(isolate); 3920 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3921 } 3922 { 3923 v8::HandleScope scope(isolate); 3924 global.Reset(isolate, v8_str("longer")); 3925 } 3926 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3927 { 3928 v8::HandleScope scope(isolate); 3929 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3930 } 3931 global.Reset(); 3932 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3933 } 3934 3935 3936 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3937 v8::Isolate* isolate = CcTest::isolate(); 3938 v8::Persistent<String> global; 3939 { 3940 v8::HandleScope scope(isolate); 3941 global.Reset(isolate, v8_str("str")); 3942 } 3943 v8::internal::GlobalHandles* global_handles = 3944 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3945 int initial_handle_count = global_handles->global_handles_count(); 3946 { 3947 v8::HandleScope scope(isolate); 3948 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3949 } 3950 { 3951 v8::HandleScope scope(isolate); 3952 Local<String> empty; 3953 global.Reset(isolate, empty); 3954 } 3955 CHECK(global.IsEmpty()); 3956 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3957 } 3958 3959 3960 template <class T> 3961 static v8::Global<T> PassUnique(v8::Global<T> unique) { 3962 return unique.Pass(); 3963 } 3964 3965 3966 template <class T> 3967 static v8::Global<T> ReturnUnique(v8::Isolate* isolate, 3968 const v8::Persistent<T>& global) { 3969 v8::Global<String> unique(isolate, global); 3970 return unique.Pass(); 3971 } 3972 3973 3974 THREADED_TEST(Global) { 3975 v8::Isolate* isolate = CcTest::isolate(); 3976 v8::Persistent<String> global; 3977 { 3978 v8::HandleScope scope(isolate); 3979 global.Reset(isolate, v8_str("str")); 3980 } 3981 v8::internal::GlobalHandles* global_handles = 3982 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3983 int initial_handle_count = global_handles->global_handles_count(); 3984 { 3985 v8::Global<String> unique(isolate, global); 3986 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3987 // Test assignment via Pass 3988 { 3989 v8::Global<String> copy = unique.Pass(); 3990 CHECK(unique.IsEmpty()); 3991 CHECK(copy == global); 3992 CHECK_EQ(initial_handle_count + 1, 3993 global_handles->global_handles_count()); 3994 unique = copy.Pass(); 3995 } 3996 // Test ctor via Pass 3997 { 3998 v8::Global<String> copy(unique.Pass()); 3999 CHECK(unique.IsEmpty()); 4000 CHECK(copy == global); 4001 CHECK_EQ(initial_handle_count + 1, 4002 global_handles->global_handles_count()); 4003 unique = copy.Pass(); 4004 } 4005 // Test pass through function call 4006 { 4007 v8::Global<String> copy = PassUnique(unique.Pass()); 4008 CHECK(unique.IsEmpty()); 4009 CHECK(copy == global); 4010 CHECK_EQ(initial_handle_count + 1, 4011 global_handles->global_handles_count()); 4012 unique = copy.Pass(); 4013 } 4014 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 4015 } 4016 // Test pass from function call 4017 { 4018 v8::Global<String> unique = ReturnUnique(isolate, global); 4019 CHECK(unique == global); 4020 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 4021 } 4022 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 4023 global.Reset(); 4024 } 4025 4026 4027 namespace { 4028 4029 class TwoPassCallbackData; 4030 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); 4031 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); 4032 4033 4034 class TwoPassCallbackData { 4035 public: 4036 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter) 4037 : first_pass_called_(false), 4038 second_pass_called_(false), 4039 trigger_gc_(false), 4040 instance_counter_(instance_counter) { 4041 HandleScope scope(isolate); 4042 i::ScopedVector<char> buffer(40); 4043 i::SNPrintF(buffer, "%p", static_cast<void*>(this)); 4044 auto string = 4045 v8::String::NewFromUtf8(isolate, buffer.start(), 4046 v8::NewStringType::kNormal).ToLocalChecked(); 4047 cell_.Reset(isolate, string); 4048 (*instance_counter_)++; 4049 } 4050 4051 ~TwoPassCallbackData() { 4052 CHECK(first_pass_called_); 4053 CHECK(second_pass_called_); 4054 CHECK(cell_.IsEmpty()); 4055 (*instance_counter_)--; 4056 } 4057 4058 void FirstPass() { 4059 CHECK(!first_pass_called_); 4060 CHECK(!second_pass_called_); 4061 CHECK(!cell_.IsEmpty()); 4062 cell_.Reset(); 4063 first_pass_called_ = true; 4064 } 4065 4066 void SecondPass() { 4067 CHECK(first_pass_called_); 4068 CHECK(!second_pass_called_); 4069 CHECK(cell_.IsEmpty()); 4070 second_pass_called_ = true; 4071 delete this; 4072 } 4073 4074 void SetWeak() { 4075 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter); 4076 } 4077 4078 void MarkTriggerGc() { trigger_gc_ = true; } 4079 bool trigger_gc() { return trigger_gc_; } 4080 4081 int* instance_counter() { return instance_counter_; } 4082 4083 private: 4084 bool first_pass_called_; 4085 bool second_pass_called_; 4086 bool trigger_gc_; 4087 v8::Global<v8::String> cell_; 4088 int* instance_counter_; 4089 }; 4090 4091 4092 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { 4093 ApiTestFuzzer::Fuzz(); 4094 bool trigger_gc = data.GetParameter()->trigger_gc(); 4095 int* instance_counter = data.GetParameter()->instance_counter(); 4096 data.GetParameter()->SecondPass(); 4097 if (!trigger_gc) return; 4098 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter); 4099 data_2->SetWeak(); 4100 CcTest::heap()->CollectAllGarbage(); 4101 } 4102 4103 4104 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { 4105 data.GetParameter()->FirstPass(); 4106 data.SetSecondPassCallback(SecondPassCallback); 4107 } 4108 4109 } // namespace 4110 4111 4112 TEST(TwoPassPhantomCallbacks) { 4113 auto isolate = CcTest::isolate(); 4114 const size_t kLength = 20; 4115 int instance_counter = 0; 4116 for (size_t i = 0; i < kLength; ++i) { 4117 auto data = new TwoPassCallbackData(isolate, &instance_counter); 4118 data->SetWeak(); 4119 } 4120 CHECK_EQ(static_cast<int>(kLength), instance_counter); 4121 CcTest::heap()->CollectAllGarbage(); 4122 EmptyMessageQueues(isolate); 4123 CHECK_EQ(0, instance_counter); 4124 } 4125 4126 4127 TEST(TwoPassPhantomCallbacksNestedGc) { 4128 auto isolate = CcTest::isolate(); 4129 const size_t kLength = 20; 4130 TwoPassCallbackData* array[kLength]; 4131 int instance_counter = 0; 4132 for (size_t i = 0; i < kLength; ++i) { 4133 array[i] = new TwoPassCallbackData(isolate, &instance_counter); 4134 array[i]->SetWeak(); 4135 } 4136 array[5]->MarkTriggerGc(); 4137 array[10]->MarkTriggerGc(); 4138 array[15]->MarkTriggerGc(); 4139 CHECK_EQ(static_cast<int>(kLength), instance_counter); 4140 CcTest::heap()->CollectAllGarbage(); 4141 EmptyMessageQueues(isolate); 4142 CHECK_EQ(0, instance_counter); 4143 } 4144 4145 4146 namespace { 4147 4148 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); } 4149 4150 4151 Local<v8::Object> NewObjectForIntKey( 4152 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ, 4153 int key) { 4154 auto local = Local<v8::ObjectTemplate>::New(isolate, templ); 4155 auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); 4156 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key)); 4157 return obj; 4158 } 4159 4160 4161 template <typename K, typename V> 4162 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> { 4163 public: 4164 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType; 4165 static const v8::PersistentContainerCallbackType kCallbackType = 4166 v8::kWeakWithInternalFields; 4167 struct WeakCallbackDataType { 4168 MapType* map; 4169 K key; 4170 }; 4171 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, 4172 Local<V> value) { 4173 WeakCallbackDataType* data = new WeakCallbackDataType; 4174 data->map = map; 4175 data->key = key; 4176 return data; 4177 } 4178 static MapType* MapFromWeakCallbackInfo( 4179 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { 4180 return data.GetParameter()->map; 4181 } 4182 static K KeyFromWeakCallbackInfo( 4183 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { 4184 return data.GetParameter()->key; 4185 } 4186 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; } 4187 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) { 4188 CHECK_EQ(IntKeyToVoidPointer(key), 4189 v8::Object::GetAlignedPointerFromInternalField(value, 0)); 4190 } 4191 static void OnWeakCallback( 4192 const v8::WeakCallbackInfo<WeakCallbackDataType>&) {} 4193 static void DisposeWeak( 4194 const v8::WeakCallbackInfo<WeakCallbackDataType>& info) { 4195 K key = KeyFromWeakCallbackInfo(info); 4196 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0)); 4197 DisposeCallbackData(info.GetParameter()); 4198 } 4199 }; 4200 4201 4202 template <typename Map> 4203 void TestGlobalValueMap() { 4204 LocalContext env; 4205 v8::Isolate* isolate = env->GetIsolate(); 4206 v8::Global<ObjectTemplate> templ; 4207 { 4208 HandleScope scope(isolate); 4209 auto t = ObjectTemplate::New(isolate); 4210 t->SetInternalFieldCount(1); 4211 templ.Reset(isolate, t); 4212 } 4213 Map map(isolate); 4214 v8::internal::GlobalHandles* global_handles = 4215 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 4216 int initial_handle_count = global_handles->global_handles_count(); 4217 CHECK_EQ(0, static_cast<int>(map.Size())); 4218 { 4219 HandleScope scope(isolate); 4220 Local<v8::Object> obj = map.Get(7); 4221 CHECK(obj.IsEmpty()); 4222 Local<v8::Object> expected = v8::Object::New(isolate); 4223 map.Set(7, expected); 4224 CHECK_EQ(1, static_cast<int>(map.Size())); 4225 obj = map.Get(7); 4226 CHECK(expected->Equals(env.local(), obj).FromJust()); 4227 { 4228 typename Map::PersistentValueReference ref = map.GetReference(7); 4229 CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust()); 4230 } 4231 v8::Global<v8::Object> removed = map.Remove(7); 4232 CHECK_EQ(0, static_cast<int>(map.Size())); 4233 CHECK(expected == removed); 4234 removed = map.Remove(7); 4235 CHECK(removed.IsEmpty()); 4236 map.Set(8, expected); 4237 CHECK_EQ(1, static_cast<int>(map.Size())); 4238 map.Set(8, expected); 4239 CHECK_EQ(1, static_cast<int>(map.Size())); 4240 { 4241 typename Map::PersistentValueReference ref; 4242 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8); 4243 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref); 4244 CHECK_EQ(1, static_cast<int>(map.Size())); 4245 CHECK(expected == removed); 4246 CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust()); 4247 } 4248 } 4249 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 4250 if (map.IsWeak()) { 4251 CcTest::i_isolate()->heap()->CollectAllGarbage( 4252 i::Heap::kAbortIncrementalMarkingMask); 4253 } else { 4254 map.Clear(); 4255 } 4256 CHECK_EQ(0, static_cast<int>(map.Size())); 4257 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 4258 { 4259 HandleScope scope(isolate); 4260 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9); 4261 map.Set(9, value); 4262 map.Clear(); 4263 } 4264 CHECK_EQ(0, static_cast<int>(map.Size())); 4265 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 4266 } 4267 4268 } // namespace 4269 4270 4271 TEST(GlobalValueMap) { 4272 // Default case, w/o weak callbacks: 4273 TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>(); 4274 4275 // Custom traits with weak callbacks: 4276 typedef v8::GlobalValueMap<int, v8::Object, 4277 PhantomStdMapTraits<int, v8::Object>> WeakMap; 4278 TestGlobalValueMap<WeakMap>(); 4279 } 4280 4281 4282 TEST(PersistentValueVector) { 4283 LocalContext env; 4284 v8::Isolate* isolate = env->GetIsolate(); 4285 v8::internal::GlobalHandles* global_handles = 4286 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 4287 int handle_count = global_handles->global_handles_count(); 4288 HandleScope scope(isolate); 4289 4290 v8::PersistentValueVector<v8::Object> vector(isolate); 4291 4292 Local<v8::Object> obj1 = v8::Object::New(isolate); 4293 Local<v8::Object> obj2 = v8::Object::New(isolate); 4294 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate)); 4295 4296 CHECK(vector.IsEmpty()); 4297 CHECK_EQ(0, static_cast<int>(vector.Size())); 4298 4299 vector.ReserveCapacity(3); 4300 CHECK(vector.IsEmpty()); 4301 4302 vector.Append(obj1); 4303 vector.Append(obj2); 4304 vector.Append(obj1); 4305 vector.Append(obj3.Pass()); 4306 vector.Append(obj1); 4307 4308 CHECK(!vector.IsEmpty()); 4309 CHECK_EQ(5, static_cast<int>(vector.Size())); 4310 CHECK(obj3.IsEmpty()); 4311 CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust()); 4312 CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust()); 4313 CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust()); 4314 CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust()); 4315 4316 CHECK_EQ(5 + handle_count, global_handles->global_handles_count()); 4317 4318 vector.Clear(); 4319 CHECK(vector.IsEmpty()); 4320 CHECK_EQ(0, static_cast<int>(vector.Size())); 4321 CHECK_EQ(handle_count, global_handles->global_handles_count()); 4322 } 4323 4324 4325 THREADED_TEST(GlobalHandleUpcast) { 4326 v8::Isolate* isolate = CcTest::isolate(); 4327 v8::HandleScope scope(isolate); 4328 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str")); 4329 v8::Persistent<String> global_string(isolate, local); 4330 v8::Persistent<Value>& global_value = 4331 v8::Persistent<Value>::Cast(global_string); 4332 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 4333 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 4334 global_string.Reset(); 4335 } 4336 4337 4338 THREADED_TEST(HandleEquality) { 4339 v8::Isolate* isolate = CcTest::isolate(); 4340 v8::Persistent<String> global1; 4341 v8::Persistent<String> global2; 4342 { 4343 v8::HandleScope scope(isolate); 4344 global1.Reset(isolate, v8_str("str")); 4345 global2.Reset(isolate, v8_str("str2")); 4346 } 4347 CHECK_EQ(global1 == global1, true); 4348 CHECK_EQ(global1 != global1, false); 4349 { 4350 v8::HandleScope scope(isolate); 4351 Local<String> local1 = Local<String>::New(isolate, global1); 4352 Local<String> local2 = Local<String>::New(isolate, global2); 4353 4354 CHECK_EQ(global1 == local1, true); 4355 CHECK_EQ(global1 != local1, false); 4356 CHECK_EQ(local1 == global1, true); 4357 CHECK_EQ(local1 != global1, false); 4358 4359 CHECK_EQ(global1 == local2, false); 4360 CHECK_EQ(global1 != local2, true); 4361 CHECK_EQ(local2 == global1, false); 4362 CHECK_EQ(local2 != global1, true); 4363 4364 CHECK_EQ(local1 == local2, false); 4365 CHECK_EQ(local1 != local2, true); 4366 4367 Local<String> anotherLocal1 = Local<String>::New(isolate, global1); 4368 CHECK_EQ(local1 == anotherLocal1, true); 4369 CHECK_EQ(local1 != anotherLocal1, false); 4370 } 4371 global1.Reset(); 4372 global2.Reset(); 4373 } 4374 4375 4376 THREADED_TEST(LocalHandle) { 4377 v8::HandleScope scope(CcTest::isolate()); 4378 v8::Local<String> local = 4379 v8::Local<String>::New(CcTest::isolate(), v8_str("str")); 4380 CHECK_EQ(local->Length(), 3); 4381 } 4382 4383 4384 class WeakCallCounter { 4385 public: 4386 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {} 4387 int id() { return id_; } 4388 void increment() { number_of_weak_calls_++; } 4389 int NumberOfWeakCalls() { return number_of_weak_calls_; } 4390 4391 private: 4392 int id_; 4393 int number_of_weak_calls_; 4394 }; 4395 4396 4397 template <typename T> 4398 struct WeakCallCounterAndPersistent { 4399 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) 4400 : counter(counter) {} 4401 WeakCallCounter* counter; 4402 v8::Persistent<T> handle; 4403 }; 4404 4405 4406 template <typename T> 4407 static void WeakPointerCallback( 4408 const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) { 4409 CHECK_EQ(1234, data.GetParameter()->counter->id()); 4410 data.GetParameter()->counter->increment(); 4411 data.GetParameter()->handle.Reset(); 4412 } 4413 4414 4415 template <typename T> 4416 static UniqueId MakeUniqueId(const Persistent<T>& p) { 4417 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 4418 } 4419 4420 4421 THREADED_TEST(ApiObjectGroups) { 4422 LocalContext env; 4423 v8::Isolate* iso = env->GetIsolate(); 4424 HandleScope scope(iso); 4425 4426 WeakCallCounter counter(1234); 4427 4428 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4429 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4430 WeakCallCounterAndPersistent<Value> g1c1(&counter); 4431 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4432 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4433 WeakCallCounterAndPersistent<Value> g2c1(&counter); 4434 4435 { 4436 HandleScope scope(iso); 4437 g1s1.handle.Reset(iso, Object::New(iso)); 4438 g1s2.handle.Reset(iso, Object::New(iso)); 4439 g1c1.handle.Reset(iso, Object::New(iso)); 4440 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4441 v8::WeakCallbackType::kParameter); 4442 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4443 v8::WeakCallbackType::kParameter); 4444 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4445 v8::WeakCallbackType::kParameter); 4446 4447 g2s1.handle.Reset(iso, Object::New(iso)); 4448 g2s2.handle.Reset(iso, Object::New(iso)); 4449 g2c1.handle.Reset(iso, Object::New(iso)); 4450 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4451 v8::WeakCallbackType::kParameter); 4452 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4453 v8::WeakCallbackType::kParameter); 4454 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4455 v8::WeakCallbackType::kParameter); 4456 } 4457 4458 WeakCallCounterAndPersistent<Value> root(&counter); 4459 root.handle.Reset(iso, g1s1.handle); // make a root. 4460 4461 // Connect group 1 and 2, make a cycle. 4462 { 4463 HandleScope scope(iso); 4464 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>()) 4465 ->Set(env.local(), 0, Local<Value>::New(iso, g2s2.handle)) 4466 .FromJust()); 4467 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>()) 4468 ->Set(env.local(), 0, Local<Value>::New(iso, g1s1.handle)) 4469 .FromJust()); 4470 } 4471 4472 { 4473 UniqueId id1 = MakeUniqueId(g1s1.handle); 4474 UniqueId id2 = MakeUniqueId(g2s2.handle); 4475 iso->SetObjectGroupId(g1s1.handle, id1); 4476 iso->SetObjectGroupId(g1s2.handle, id1); 4477 iso->SetReferenceFromGroup(id1, g1c1.handle); 4478 iso->SetObjectGroupId(g2s1.handle, id2); 4479 iso->SetObjectGroupId(g2s2.handle, id2); 4480 iso->SetReferenceFromGroup(id2, g2c1.handle); 4481 } 4482 // Do a single full GC, ensure incremental marking is stopped. 4483 v8::internal::Heap* heap = 4484 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4485 heap->CollectAllGarbage(); 4486 4487 // All object should be alive. 4488 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4489 4490 // Weaken the root. 4491 root.handle.SetWeak(&root, &WeakPointerCallback, 4492 v8::WeakCallbackType::kParameter); 4493 // But make children strong roots---all the objects (except for children) 4494 // should be collectable now. 4495 g1c1.handle.ClearWeak(); 4496 g2c1.handle.ClearWeak(); 4497 4498 // Groups are deleted, rebuild groups. 4499 { 4500 UniqueId id1 = MakeUniqueId(g1s1.handle); 4501 UniqueId id2 = MakeUniqueId(g2s2.handle); 4502 iso->SetObjectGroupId(g1s1.handle, id1); 4503 iso->SetObjectGroupId(g1s2.handle, id1); 4504 iso->SetReferenceFromGroup(id1, g1c1.handle); 4505 iso->SetObjectGroupId(g2s1.handle, id2); 4506 iso->SetObjectGroupId(g2s2.handle, id2); 4507 iso->SetReferenceFromGroup(id2, g2c1.handle); 4508 } 4509 4510 heap->CollectAllGarbage(); 4511 4512 // All objects should be gone. 5 global handles in total. 4513 CHECK_EQ(5, counter.NumberOfWeakCalls()); 4514 4515 // And now make children weak again and collect them. 4516 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4517 v8::WeakCallbackType::kParameter); 4518 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4519 v8::WeakCallbackType::kParameter); 4520 4521 heap->CollectAllGarbage(); 4522 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4523 } 4524 4525 4526 THREADED_TEST(ApiObjectGroupsForSubtypes) { 4527 LocalContext env; 4528 v8::Isolate* iso = env->GetIsolate(); 4529 HandleScope scope(iso); 4530 4531 WeakCallCounter counter(1234); 4532 4533 WeakCallCounterAndPersistent<Object> g1s1(&counter); 4534 WeakCallCounterAndPersistent<String> g1s2(&counter); 4535 WeakCallCounterAndPersistent<String> g1c1(&counter); 4536 WeakCallCounterAndPersistent<Object> g2s1(&counter); 4537 WeakCallCounterAndPersistent<String> g2s2(&counter); 4538 WeakCallCounterAndPersistent<String> g2c1(&counter); 4539 4540 { 4541 HandleScope scope(iso); 4542 g1s1.handle.Reset(iso, Object::New(iso)); 4543 g1s2.handle.Reset(iso, v8_str("foo1")); 4544 g1c1.handle.Reset(iso, v8_str("foo2")); 4545 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4546 v8::WeakCallbackType::kParameter); 4547 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4548 v8::WeakCallbackType::kParameter); 4549 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4550 v8::WeakCallbackType::kParameter); 4551 4552 g2s1.handle.Reset(iso, Object::New(iso)); 4553 g2s2.handle.Reset(iso, v8_str("foo3")); 4554 g2c1.handle.Reset(iso, v8_str("foo4")); 4555 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4556 v8::WeakCallbackType::kParameter); 4557 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4558 v8::WeakCallbackType::kParameter); 4559 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4560 v8::WeakCallbackType::kParameter); 4561 } 4562 4563 WeakCallCounterAndPersistent<Value> root(&counter); 4564 root.handle.Reset(iso, g1s1.handle); // make a root. 4565 4566 // Connect group 1 and 2, make a cycle. 4567 { 4568 HandleScope scope(iso); 4569 CHECK(Local<Object>::New(iso, g1s1.handle) 4570 ->Set(env.local(), 0, Local<Object>::New(iso, g2s1.handle)) 4571 .FromJust()); 4572 CHECK(Local<Object>::New(iso, g2s1.handle) 4573 ->Set(env.local(), 0, Local<Object>::New(iso, g1s1.handle)) 4574 .FromJust()); 4575 } 4576 4577 { 4578 UniqueId id1 = MakeUniqueId(g1s1.handle); 4579 UniqueId id2 = MakeUniqueId(g2s2.handle); 4580 iso->SetObjectGroupId(g1s1.handle, id1); 4581 iso->SetObjectGroupId(g1s2.handle, id1); 4582 iso->SetReference(g1s1.handle, g1c1.handle); 4583 iso->SetObjectGroupId(g2s1.handle, id2); 4584 iso->SetObjectGroupId(g2s2.handle, id2); 4585 iso->SetReferenceFromGroup(id2, g2c1.handle); 4586 } 4587 // Do a single full GC, ensure incremental marking is stopped. 4588 v8::internal::Heap* heap = 4589 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4590 heap->CollectAllGarbage(); 4591 4592 // All object should be alive. 4593 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4594 4595 // Weaken the root. 4596 root.handle.SetWeak(&root, &WeakPointerCallback, 4597 v8::WeakCallbackType::kParameter); 4598 // But make children strong roots---all the objects (except for children) 4599 // should be collectable now. 4600 g1c1.handle.ClearWeak(); 4601 g2c1.handle.ClearWeak(); 4602 4603 // Groups are deleted, rebuild groups. 4604 { 4605 UniqueId id1 = MakeUniqueId(g1s1.handle); 4606 UniqueId id2 = MakeUniqueId(g2s2.handle); 4607 iso->SetObjectGroupId(g1s1.handle, id1); 4608 iso->SetObjectGroupId(g1s2.handle, id1); 4609 iso->SetReference(g1s1.handle, g1c1.handle); 4610 iso->SetObjectGroupId(g2s1.handle, id2); 4611 iso->SetObjectGroupId(g2s2.handle, id2); 4612 iso->SetReferenceFromGroup(id2, g2c1.handle); 4613 } 4614 4615 heap->CollectAllGarbage(); 4616 4617 // All objects should be gone. 5 global handles in total. 4618 CHECK_EQ(5, counter.NumberOfWeakCalls()); 4619 4620 // And now make children weak again and collect them. 4621 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback, 4622 v8::WeakCallbackType::kParameter); 4623 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback, 4624 v8::WeakCallbackType::kParameter); 4625 4626 heap->CollectAllGarbage(); 4627 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4628 } 4629 4630 4631 THREADED_TEST(ApiObjectGroupsCycle) { 4632 LocalContext env; 4633 v8::Isolate* iso = env->GetIsolate(); 4634 HandleScope scope(iso); 4635 4636 WeakCallCounter counter(1234); 4637 4638 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4639 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4640 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4641 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4642 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4643 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4644 WeakCallCounterAndPersistent<Value> g4s1(&counter); 4645 WeakCallCounterAndPersistent<Value> g4s2(&counter); 4646 4647 { 4648 HandleScope scope(iso); 4649 g1s1.handle.Reset(iso, Object::New(iso)); 4650 g1s2.handle.Reset(iso, Object::New(iso)); 4651 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback, 4652 v8::WeakCallbackType::kParameter); 4653 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback, 4654 v8::WeakCallbackType::kParameter); 4655 CHECK(g1s1.handle.IsWeak()); 4656 CHECK(g1s2.handle.IsWeak()); 4657 4658 g2s1.handle.Reset(iso, Object::New(iso)); 4659 g2s2.handle.Reset(iso, Object::New(iso)); 4660 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback, 4661 v8::WeakCallbackType::kParameter); 4662 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback, 4663 v8::WeakCallbackType::kParameter); 4664 CHECK(g2s1.handle.IsWeak()); 4665 CHECK(g2s2.handle.IsWeak()); 4666 4667 g3s1.handle.Reset(iso, Object::New(iso)); 4668 g3s2.handle.Reset(iso, Object::New(iso)); 4669 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback, 4670 v8::WeakCallbackType::kParameter); 4671 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback, 4672 v8::WeakCallbackType::kParameter); 4673 CHECK(g3s1.handle.IsWeak()); 4674 CHECK(g3s2.handle.IsWeak()); 4675 4676 g4s1.handle.Reset(iso, Object::New(iso)); 4677 g4s2.handle.Reset(iso, Object::New(iso)); 4678 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback, 4679 v8::WeakCallbackType::kParameter); 4680 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback, 4681 v8::WeakCallbackType::kParameter); 4682 CHECK(g4s1.handle.IsWeak()); 4683 CHECK(g4s2.handle.IsWeak()); 4684 } 4685 4686 WeakCallCounterAndPersistent<Value> root(&counter); 4687 root.handle.Reset(iso, g1s1.handle); // make a root. 4688 4689 // Connect groups. We're building the following cycle: 4690 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4691 // groups. 4692 { 4693 UniqueId id1 = MakeUniqueId(g1s1.handle); 4694 UniqueId id2 = MakeUniqueId(g2s1.handle); 4695 UniqueId id3 = MakeUniqueId(g3s1.handle); 4696 UniqueId id4 = MakeUniqueId(g4s1.handle); 4697 iso->SetObjectGroupId(g1s1.handle, id1); 4698 iso->SetObjectGroupId(g1s2.handle, id1); 4699 iso->SetReferenceFromGroup(id1, g2s1.handle); 4700 iso->SetObjectGroupId(g2s1.handle, id2); 4701 iso->SetObjectGroupId(g2s2.handle, id2); 4702 iso->SetReferenceFromGroup(id2, g3s1.handle); 4703 iso->SetObjectGroupId(g3s1.handle, id3); 4704 iso->SetObjectGroupId(g3s2.handle, id3); 4705 iso->SetReferenceFromGroup(id3, g4s1.handle); 4706 iso->SetObjectGroupId(g4s1.handle, id4); 4707 iso->SetObjectGroupId(g4s2.handle, id4); 4708 iso->SetReferenceFromGroup(id4, g1s1.handle); 4709 } 4710 // Do a single full GC 4711 v8::internal::Heap* heap = 4712 reinterpret_cast<v8::internal::Isolate*>(iso)->heap(); 4713 heap->CollectAllGarbage(); 4714 4715 // All object should be alive. 4716 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4717 4718 // Weaken the root. 4719 root.handle.SetWeak(&root, &WeakPointerCallback, 4720 v8::WeakCallbackType::kParameter); 4721 4722 // Groups are deleted, rebuild groups. 4723 { 4724 UniqueId id1 = MakeUniqueId(g1s1.handle); 4725 UniqueId id2 = MakeUniqueId(g2s1.handle); 4726 UniqueId id3 = MakeUniqueId(g3s1.handle); 4727 UniqueId id4 = MakeUniqueId(g4s1.handle); 4728 iso->SetObjectGroupId(g1s1.handle, id1); 4729 iso->SetObjectGroupId(g1s2.handle, id1); 4730 iso->SetReferenceFromGroup(id1, g2s1.handle); 4731 iso->SetObjectGroupId(g2s1.handle, id2); 4732 iso->SetObjectGroupId(g2s2.handle, id2); 4733 iso->SetReferenceFromGroup(id2, g3s1.handle); 4734 iso->SetObjectGroupId(g3s1.handle, id3); 4735 iso->SetObjectGroupId(g3s2.handle, id3); 4736 iso->SetReferenceFromGroup(id3, g4s1.handle); 4737 iso->SetObjectGroupId(g4s1.handle, id4); 4738 iso->SetObjectGroupId(g4s2.handle, id4); 4739 iso->SetReferenceFromGroup(id4, g1s1.handle); 4740 } 4741 4742 heap->CollectAllGarbage(); 4743 4744 // All objects should be gone. 9 global handles in total. 4745 CHECK_EQ(9, counter.NumberOfWeakCalls()); 4746 } 4747 4748 4749 THREADED_TEST(ScriptException) { 4750 LocalContext env; 4751 v8::HandleScope scope(env->GetIsolate()); 4752 Local<Script> script = v8_compile("throw 'panama!';"); 4753 v8::TryCatch try_catch(env->GetIsolate()); 4754 v8::MaybeLocal<Value> result = script->Run(env.local()); 4755 CHECK(result.IsEmpty()); 4756 CHECK(try_catch.HasCaught()); 4757 String::Utf8Value exception_value(try_catch.Exception()); 4758 CHECK_EQ(0, strcmp(*exception_value, "panama!")); 4759 } 4760 4761 4762 TEST(TryCatchCustomException) { 4763 LocalContext env; 4764 v8::Isolate* isolate = env->GetIsolate(); 4765 v8::HandleScope scope(isolate); 4766 v8::TryCatch try_catch(isolate); 4767 CompileRun( 4768 "function CustomError() { this.a = 'b'; }" 4769 "(function f() { throw new CustomError(); })();"); 4770 CHECK(try_catch.HasCaught()); 4771 CHECK(try_catch.Exception() 4772 ->ToObject(env.local()) 4773 .ToLocalChecked() 4774 ->Get(env.local(), v8_str("a")) 4775 .ToLocalChecked() 4776 ->Equals(env.local(), v8_str("b")) 4777 .FromJust()); 4778 } 4779 4780 4781 bool message_received; 4782 4783 4784 static void check_message_0(v8::Local<v8::Message> message, 4785 v8::Local<Value> data) { 4786 CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext()) 4787 .FromJust()); 4788 CHECK_EQ(6.75, message->GetScriptOrigin() 4789 .ResourceName() 4790 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4791 .FromJust()); 4792 CHECK(!message->IsSharedCrossOrigin()); 4793 message_received = true; 4794 } 4795 4796 4797 THREADED_TEST(MessageHandler0) { 4798 message_received = false; 4799 v8::HandleScope scope(CcTest::isolate()); 4800 CHECK(!message_received); 4801 LocalContext context; 4802 CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76)); 4803 v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75"); 4804 CHECK(script->Run(context.local()).IsEmpty()); 4805 CHECK(message_received); 4806 // clear out the message listener 4807 CcTest::isolate()->RemoveMessageListeners(check_message_0); 4808 } 4809 4810 4811 static void check_message_1(v8::Local<v8::Message> message, 4812 v8::Local<Value> data) { 4813 CHECK(data->IsNumber()); 4814 CHECK_EQ(1337, 4815 data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust()); 4816 CHECK(!message->IsSharedCrossOrigin()); 4817 message_received = true; 4818 } 4819 4820 4821 TEST(MessageHandler1) { 4822 message_received = false; 4823 v8::HandleScope scope(CcTest::isolate()); 4824 CHECK(!message_received); 4825 CcTest::isolate()->AddMessageListener(check_message_1); 4826 LocalContext context; 4827 CompileRun("throw 1337;"); 4828 CHECK(message_received); 4829 // clear out the message listener 4830 CcTest::isolate()->RemoveMessageListeners(check_message_1); 4831 } 4832 4833 4834 static void check_message_2(v8::Local<v8::Message> message, 4835 v8::Local<Value> data) { 4836 LocalContext context; 4837 CHECK(data->IsObject()); 4838 v8::Local<v8::Value> hidden_property = 4839 v8::Object::Cast(*data) 4840 ->GetPrivate( 4841 context.local(), 4842 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key"))) 4843 .ToLocalChecked(); 4844 CHECK(v8_str("hidden value") 4845 ->Equals(context.local(), hidden_property) 4846 .FromJust()); 4847 CHECK(!message->IsSharedCrossOrigin()); 4848 message_received = true; 4849 } 4850 4851 4852 TEST(MessageHandler2) { 4853 message_received = false; 4854 v8::HandleScope scope(CcTest::isolate()); 4855 CHECK(!message_received); 4856 CcTest::isolate()->AddMessageListener(check_message_2); 4857 LocalContext context; 4858 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 4859 v8::Object::Cast(*error) 4860 ->SetPrivate(context.local(), 4861 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")), 4862 v8_str("hidden value")) 4863 .FromJust(); 4864 CHECK(context->Global() 4865 ->Set(context.local(), v8_str("error"), error) 4866 .FromJust()); 4867 CompileRun("throw error;"); 4868 CHECK(message_received); 4869 // clear out the message listener 4870 CcTest::isolate()->RemoveMessageListeners(check_message_2); 4871 } 4872 4873 4874 static void check_message_3(v8::Local<v8::Message> message, 4875 v8::Local<Value> data) { 4876 CHECK(message->IsSharedCrossOrigin()); 4877 CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin()); 4878 CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript()); 4879 CHECK(message->GetScriptOrigin().Options().IsOpaque()); 4880 CHECK_EQ(6.75, message->GetScriptOrigin() 4881 .ResourceName() 4882 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4883 .FromJust()); 4884 CHECK_EQ(7.40, message->GetScriptOrigin() 4885 .SourceMapUrl() 4886 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4887 .FromJust()); 4888 message_received = true; 4889 } 4890 4891 4892 TEST(MessageHandler3) { 4893 message_received = false; 4894 v8::Isolate* isolate = CcTest::isolate(); 4895 v8::HandleScope scope(isolate); 4896 CHECK(!message_received); 4897 isolate->AddMessageListener(check_message_3); 4898 LocalContext context; 4899 v8::ScriptOrigin origin = v8::ScriptOrigin( 4900 v8_str("6.75"), v8::Integer::New(isolate, 1), 4901 v8::Integer::New(isolate, 2), v8::True(isolate), Local<v8::Integer>(), 4902 v8::True(isolate), v8_str("7.40"), v8::True(isolate)); 4903 v8::Local<v8::Script> script = 4904 Script::Compile(context.local(), v8_str("throw 'error'"), &origin) 4905 .ToLocalChecked(); 4906 CHECK(script->Run(context.local()).IsEmpty()); 4907 CHECK(message_received); 4908 // clear out the message listener 4909 isolate->RemoveMessageListeners(check_message_3); 4910 } 4911 4912 4913 static void check_message_4(v8::Local<v8::Message> message, 4914 v8::Local<Value> data) { 4915 CHECK(!message->IsSharedCrossOrigin()); 4916 CHECK_EQ(6.75, message->GetScriptOrigin() 4917 .ResourceName() 4918 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4919 .FromJust()); 4920 message_received = true; 4921 } 4922 4923 4924 TEST(MessageHandler4) { 4925 message_received = false; 4926 v8::Isolate* isolate = CcTest::isolate(); 4927 v8::HandleScope scope(isolate); 4928 CHECK(!message_received); 4929 isolate->AddMessageListener(check_message_4); 4930 LocalContext context; 4931 v8::ScriptOrigin origin = 4932 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4933 v8::Integer::New(isolate, 2), v8::False(isolate)); 4934 v8::Local<v8::Script> script = 4935 Script::Compile(context.local(), v8_str("throw 'error'"), &origin) 4936 .ToLocalChecked(); 4937 CHECK(script->Run(context.local()).IsEmpty()); 4938 CHECK(message_received); 4939 // clear out the message listener 4940 isolate->RemoveMessageListeners(check_message_4); 4941 } 4942 4943 4944 static void check_message_5a(v8::Local<v8::Message> message, 4945 v8::Local<Value> data) { 4946 CHECK(message->IsSharedCrossOrigin()); 4947 CHECK_EQ(6.75, message->GetScriptOrigin() 4948 .ResourceName() 4949 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4950 .FromJust()); 4951 message_received = true; 4952 } 4953 4954 4955 static void check_message_5b(v8::Local<v8::Message> message, 4956 v8::Local<Value> data) { 4957 CHECK(!message->IsSharedCrossOrigin()); 4958 CHECK_EQ(6.75, message->GetScriptOrigin() 4959 .ResourceName() 4960 ->NumberValue(CcTest::isolate()->GetCurrentContext()) 4961 .FromJust()); 4962 message_received = true; 4963 } 4964 4965 4966 TEST(MessageHandler5) { 4967 message_received = false; 4968 v8::Isolate* isolate = CcTest::isolate(); 4969 v8::HandleScope scope(isolate); 4970 CHECK(!message_received); 4971 isolate->AddMessageListener(check_message_5a); 4972 LocalContext context; 4973 v8::ScriptOrigin origin1 = 4974 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4975 v8::Integer::New(isolate, 2), v8::True(isolate)); 4976 v8::Local<v8::Script> script = 4977 Script::Compile(context.local(), v8_str("throw 'error'"), &origin1) 4978 .ToLocalChecked(); 4979 CHECK(script->Run(context.local()).IsEmpty()); 4980 CHECK(message_received); 4981 // clear out the message listener 4982 isolate->RemoveMessageListeners(check_message_5a); 4983 4984 message_received = false; 4985 isolate->AddMessageListener(check_message_5b); 4986 v8::ScriptOrigin origin2 = 4987 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), 4988 v8::Integer::New(isolate, 2), v8::False(isolate)); 4989 script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2) 4990 .ToLocalChecked(); 4991 CHECK(script->Run(context.local()).IsEmpty()); 4992 CHECK(message_received); 4993 // clear out the message listener 4994 isolate->RemoveMessageListeners(check_message_5b); 4995 } 4996 4997 4998 TEST(NativeWeakMap) { 4999 v8::Isolate* isolate = CcTest::isolate(); 5000 HandleScope scope(isolate); 5001 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate)); 5002 CHECK(!weak_map.IsEmpty()); 5003 5004 LocalContext env; 5005 Local<Object> value = v8::Object::New(isolate); 5006 5007 Local<Object> local1 = v8::Object::New(isolate); 5008 CHECK(!weak_map->Has(local1)); 5009 CHECK(weak_map->Get(local1)->IsUndefined()); 5010 weak_map->Set(local1, value); 5011 CHECK(weak_map->Has(local1)); 5012 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 5013 5014 WeakCallCounter counter(1234); 5015 WeakCallCounterAndPersistent<Value> o1(&counter); 5016 WeakCallCounterAndPersistent<Value> o2(&counter); 5017 WeakCallCounterAndPersistent<Value> s1(&counter); 5018 { 5019 HandleScope scope(isolate); 5020 Local<v8::Object> obj1 = v8::Object::New(isolate); 5021 Local<v8::Object> obj2 = v8::Object::New(isolate); 5022 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 5023 5024 weak_map->Set(obj1, value); 5025 weak_map->Set(obj2, value); 5026 weak_map->Set(sym1, value); 5027 5028 o1.handle.Reset(isolate, obj1); 5029 o2.handle.Reset(isolate, obj2); 5030 s1.handle.Reset(isolate, sym1); 5031 5032 CHECK(weak_map->Has(local1)); 5033 CHECK(weak_map->Has(obj1)); 5034 CHECK(weak_map->Has(obj2)); 5035 CHECK(weak_map->Has(sym1)); 5036 5037 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 5038 CHECK(value->Equals(env.local(), weak_map->Get(obj1)).FromJust()); 5039 CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust()); 5040 CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust()); 5041 } 5042 CcTest::heap()->CollectAllGarbage(); 5043 { 5044 HandleScope scope(isolate); 5045 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 5046 CHECK(value->Equals(env.local(), 5047 weak_map->Get(Local<Value>::New(isolate, o1.handle))) 5048 .FromJust()); 5049 CHECK(value->Equals(env.local(), 5050 weak_map->Get(Local<Value>::New(isolate, o2.handle))) 5051 .FromJust()); 5052 CHECK(value->Equals(env.local(), 5053 weak_map->Get(Local<Value>::New(isolate, s1.handle))) 5054 .FromJust()); 5055 } 5056 5057 o1.handle.SetWeak(&o1, &WeakPointerCallback, 5058 v8::WeakCallbackType::kParameter); 5059 o2.handle.SetWeak(&o2, &WeakPointerCallback, 5060 v8::WeakCallbackType::kParameter); 5061 s1.handle.SetWeak(&s1, &WeakPointerCallback, 5062 v8::WeakCallbackType::kParameter); 5063 5064 CcTest::heap()->CollectAllGarbage(); 5065 CHECK_EQ(3, counter.NumberOfWeakCalls()); 5066 5067 CHECK(o1.handle.IsEmpty()); 5068 CHECK(o2.handle.IsEmpty()); 5069 CHECK(s1.handle.IsEmpty()); 5070 5071 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust()); 5072 CHECK(weak_map->Delete(local1)); 5073 CHECK(!weak_map->Has(local1)); 5074 CHECK(weak_map->Get(local1)->IsUndefined()); 5075 } 5076 5077 5078 THREADED_TEST(GetSetProperty) { 5079 LocalContext context; 5080 v8::Isolate* isolate = context->GetIsolate(); 5081 v8::HandleScope scope(isolate); 5082 CHECK(context->Global() 5083 ->Set(context.local(), v8_str("foo"), v8_num(14)) 5084 .FromJust()); 5085 CHECK(context->Global() 5086 ->Set(context.local(), v8_str("12"), v8_num(92)) 5087 .FromJust()); 5088 CHECK(context->Global() 5089 ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32)) 5090 .FromJust()); 5091 CHECK(context->Global() 5092 ->Set(context.local(), v8_num(13), v8_num(56)) 5093 .FromJust()); 5094 Local<Value> foo = CompileRun("this.foo"); 5095 CHECK_EQ(14, foo->Int32Value(context.local()).FromJust()); 5096 Local<Value> twelve = CompileRun("this[12]"); 5097 CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust()); 5098 Local<Value> sixteen = CompileRun("this[16]"); 5099 CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust()); 5100 Local<Value> thirteen = CompileRun("this[13]"); 5101 CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust()); 5102 CHECK_EQ(92, context->Global() 5103 ->Get(context.local(), v8::Integer::New(isolate, 12)) 5104 .ToLocalChecked() 5105 ->Int32Value(context.local()) 5106 .FromJust()); 5107 CHECK_EQ(92, context->Global() 5108 ->Get(context.local(), v8_str("12")) 5109 .ToLocalChecked() 5110 ->Int32Value(context.local()) 5111 .FromJust()); 5112 CHECK_EQ(92, context->Global() 5113 ->Get(context.local(), v8_num(12)) 5114 .ToLocalChecked() 5115 ->Int32Value(context.local()) 5116 .FromJust()); 5117 CHECK_EQ(32, context->Global() 5118 ->Get(context.local(), v8::Integer::New(isolate, 16)) 5119 .ToLocalChecked() 5120 ->Int32Value(context.local()) 5121 .FromJust()); 5122 CHECK_EQ(32, context->Global() 5123 ->Get(context.local(), v8_str("16")) 5124 .ToLocalChecked() 5125 ->Int32Value(context.local()) 5126 .FromJust()); 5127 CHECK_EQ(32, context->Global() 5128 ->Get(context.local(), v8_num(16)) 5129 .ToLocalChecked() 5130 ->Int32Value(context.local()) 5131 .FromJust()); 5132 CHECK_EQ(56, context->Global() 5133 ->Get(context.local(), v8::Integer::New(isolate, 13)) 5134 .ToLocalChecked() 5135 ->Int32Value(context.local()) 5136 .FromJust()); 5137 CHECK_EQ(56, context->Global() 5138 ->Get(context.local(), v8_str("13")) 5139 .ToLocalChecked() 5140 ->Int32Value(context.local()) 5141 .FromJust()); 5142 CHECK_EQ(56, context->Global() 5143 ->Get(context.local(), v8_num(13)) 5144 .ToLocalChecked() 5145 ->Int32Value(context.local()) 5146 .FromJust()); 5147 } 5148 5149 5150 THREADED_TEST(PropertyAttributes) { 5151 LocalContext context; 5152 v8::HandleScope scope(context->GetIsolate()); 5153 // none 5154 Local<String> prop = v8_str("none"); 5155 CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust()); 5156 CHECK_EQ(v8::None, context->Global() 5157 ->GetPropertyAttributes(context.local(), prop) 5158 .FromJust()); 5159 // read-only 5160 prop = v8_str("read_only"); 5161 context->Global() 5162 ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly) 5163 .FromJust(); 5164 CHECK_EQ(7, context->Global() 5165 ->Get(context.local(), prop) 5166 .ToLocalChecked() 5167 ->Int32Value(context.local()) 5168 .FromJust()); 5169 CHECK_EQ(v8::ReadOnly, context->Global() 5170 ->GetPropertyAttributes(context.local(), prop) 5171 .FromJust()); 5172 CompileRun("read_only = 9"); 5173 CHECK_EQ(7, context->Global() 5174 ->Get(context.local(), prop) 5175 .ToLocalChecked() 5176 ->Int32Value(context.local()) 5177 .FromJust()); 5178 CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust()); 5179 CHECK_EQ(7, context->Global() 5180 ->Get(context.local(), prop) 5181 .ToLocalChecked() 5182 ->Int32Value(context.local()) 5183 .FromJust()); 5184 // dont-delete 5185 prop = v8_str("dont_delete"); 5186 context->Global() 5187 ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete) 5188 .FromJust(); 5189 CHECK_EQ(13, context->Global() 5190 ->Get(context.local(), prop) 5191 .ToLocalChecked() 5192 ->Int32Value(context.local()) 5193 .FromJust()); 5194 CompileRun("delete dont_delete"); 5195 CHECK_EQ(13, context->Global() 5196 ->Get(context.local(), prop) 5197 .ToLocalChecked() 5198 ->Int32Value(context.local()) 5199 .FromJust()); 5200 CHECK_EQ(v8::DontDelete, context->Global() 5201 ->GetPropertyAttributes(context.local(), prop) 5202 .FromJust()); 5203 // dont-enum 5204 prop = v8_str("dont_enum"); 5205 context->Global() 5206 ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum) 5207 .FromJust(); 5208 CHECK_EQ(v8::DontEnum, context->Global() 5209 ->GetPropertyAttributes(context.local(), prop) 5210 .FromJust()); 5211 // absent 5212 prop = v8_str("absent"); 5213 CHECK_EQ(v8::None, context->Global() 5214 ->GetPropertyAttributes(context.local(), prop) 5215 .FromJust()); 5216 Local<Value> fake_prop = v8_num(1); 5217 CHECK_EQ(v8::None, context->Global() 5218 ->GetPropertyAttributes(context.local(), fake_prop) 5219 .FromJust()); 5220 // exception 5221 TryCatch try_catch(context->GetIsolate()); 5222 Local<Value> exception = 5223 CompileRun("({ toString: function() { throw 'exception';} })"); 5224 CHECK(context->Global() 5225 ->GetPropertyAttributes(context.local(), exception) 5226 .IsNothing()); 5227 CHECK(try_catch.HasCaught()); 5228 String::Utf8Value exception_value(try_catch.Exception()); 5229 CHECK_EQ(0, strcmp("exception", *exception_value)); 5230 try_catch.Reset(); 5231 } 5232 5233 5234 THREADED_TEST(Array) { 5235 LocalContext context; 5236 v8::HandleScope scope(context->GetIsolate()); 5237 Local<v8::Array> array = v8::Array::New(context->GetIsolate()); 5238 CHECK_EQ(0u, array->Length()); 5239 CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined()); 5240 CHECK(!array->Has(context.local(), 0).FromJust()); 5241 CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined()); 5242 CHECK(!array->Has(context.local(), 100).FromJust()); 5243 CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust()); 5244 CHECK_EQ(3u, array->Length()); 5245 CHECK(!array->Has(context.local(), 0).FromJust()); 5246 CHECK(!array->Has(context.local(), 1).FromJust()); 5247 CHECK(array->Has(context.local(), 2).FromJust()); 5248 CHECK_EQ(7, array->Get(context.local(), 2) 5249 .ToLocalChecked() 5250 ->Int32Value(context.local()) 5251 .FromJust()); 5252 Local<Value> obj = CompileRun("[1, 2, 3]"); 5253 Local<v8::Array> arr = obj.As<v8::Array>(); 5254 CHECK_EQ(3u, arr->Length()); 5255 CHECK_EQ(1, arr->Get(context.local(), 0) 5256 .ToLocalChecked() 5257 ->Int32Value(context.local()) 5258 .FromJust()); 5259 CHECK_EQ(2, arr->Get(context.local(), 1) 5260 .ToLocalChecked() 5261 ->Int32Value(context.local()) 5262 .FromJust()); 5263 CHECK_EQ(3, arr->Get(context.local(), 2) 5264 .ToLocalChecked() 5265 ->Int32Value(context.local()) 5266 .FromJust()); 5267 array = v8::Array::New(context->GetIsolate(), 27); 5268 CHECK_EQ(27u, array->Length()); 5269 array = v8::Array::New(context->GetIsolate(), -27); 5270 CHECK_EQ(0u, array->Length()); 5271 } 5272 5273 5274 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 5275 v8::EscapableHandleScope scope(args.GetIsolate()); 5276 ApiTestFuzzer::Fuzz(); 5277 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); 5278 for (int i = 0; i < args.Length(); i++) { 5279 CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i]) 5280 .FromJust()); 5281 } 5282 args.GetReturnValue().Set(scope.Escape(result)); 5283 } 5284 5285 5286 THREADED_TEST(Vector) { 5287 v8::Isolate* isolate = CcTest::isolate(); 5288 v8::HandleScope scope(isolate); 5289 Local<ObjectTemplate> global = ObjectTemplate::New(isolate); 5290 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF)); 5291 LocalContext context(0, global); 5292 5293 const char* fun = "f()"; 5294 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 5295 CHECK_EQ(0u, a0->Length()); 5296 5297 const char* fun2 = "f(11)"; 5298 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 5299 CHECK_EQ(1u, a1->Length()); 5300 CHECK_EQ(11, a1->Get(context.local(), 0) 5301 .ToLocalChecked() 5302 ->Int32Value(context.local()) 5303 .FromJust()); 5304 5305 const char* fun3 = "f(12, 13)"; 5306 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 5307 CHECK_EQ(2u, a2->Length()); 5308 CHECK_EQ(12, a2->Get(context.local(), 0) 5309 .ToLocalChecked() 5310 ->Int32Value(context.local()) 5311 .FromJust()); 5312 CHECK_EQ(13, a2->Get(context.local(), 1) 5313 .ToLocalChecked() 5314 ->Int32Value(context.local()) 5315 .FromJust()); 5316 5317 const char* fun4 = "f(14, 15, 16)"; 5318 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 5319 CHECK_EQ(3u, a3->Length()); 5320 CHECK_EQ(14, a3->Get(context.local(), 0) 5321 .ToLocalChecked() 5322 ->Int32Value(context.local()) 5323 .FromJust()); 5324 CHECK_EQ(15, a3->Get(context.local(), 1) 5325 .ToLocalChecked() 5326 ->Int32Value(context.local()) 5327 .FromJust()); 5328 CHECK_EQ(16, a3->Get(context.local(), 2) 5329 .ToLocalChecked() 5330 ->Int32Value(context.local()) 5331 .FromJust()); 5332 5333 const char* fun5 = "f(17, 18, 19, 20)"; 5334 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 5335 CHECK_EQ(4u, a4->Length()); 5336 CHECK_EQ(17, a4->Get(context.local(), 0) 5337 .ToLocalChecked() 5338 ->Int32Value(context.local()) 5339 .FromJust()); 5340 CHECK_EQ(18, a4->Get(context.local(), 1) 5341 .ToLocalChecked() 5342 ->Int32Value(context.local()) 5343 .FromJust()); 5344 CHECK_EQ(19, a4->Get(context.local(), 2) 5345 .ToLocalChecked() 5346 ->Int32Value(context.local()) 5347 .FromJust()); 5348 CHECK_EQ(20, a4->Get(context.local(), 3) 5349 .ToLocalChecked() 5350 ->Int32Value(context.local()) 5351 .FromJust()); 5352 } 5353 5354 5355 THREADED_TEST(FunctionCall) { 5356 LocalContext context; 5357 v8::Isolate* isolate = context->GetIsolate(); 5358 v8::HandleScope scope(isolate); 5359 CompileRun( 5360 "function Foo() {" 5361 " var result = [];" 5362 " for (var i = 0; i < arguments.length; i++) {" 5363 " result.push(arguments[i]);" 5364 " }" 5365 " return result;" 5366 "}" 5367 "function ReturnThisSloppy() {" 5368 " return this;" 5369 "}" 5370 "function ReturnThisStrict() {" 5371 " 'use strict';" 5372 " return this;" 5373 "}"); 5374 Local<Function> Foo = Local<Function>::Cast( 5375 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked()); 5376 Local<Function> ReturnThisSloppy = Local<Function>::Cast( 5377 context->Global() 5378 ->Get(context.local(), v8_str("ReturnThisSloppy")) 5379 .ToLocalChecked()); 5380 Local<Function> ReturnThisStrict = Local<Function>::Cast( 5381 context->Global() 5382 ->Get(context.local(), v8_str("ReturnThisStrict")) 5383 .ToLocalChecked()); 5384 5385 v8::Local<Value>* args0 = NULL; 5386 Local<v8::Array> a0 = Local<v8::Array>::Cast( 5387 Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked()); 5388 CHECK_EQ(0u, a0->Length()); 5389 5390 v8::Local<Value> args1[] = {v8_num(1.1)}; 5391 Local<v8::Array> a1 = Local<v8::Array>::Cast( 5392 Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked()); 5393 CHECK_EQ(1u, a1->Length()); 5394 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0)) 5395 .ToLocalChecked() 5396 ->NumberValue(context.local()) 5397 .FromJust()); 5398 5399 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)}; 5400 Local<v8::Array> a2 = Local<v8::Array>::Cast( 5401 Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked()); 5402 CHECK_EQ(2u, a2->Length()); 5403 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0)) 5404 .ToLocalChecked() 5405 ->NumberValue(context.local()) 5406 .FromJust()); 5407 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1)) 5408 .ToLocalChecked() 5409 ->NumberValue(context.local()) 5410 .FromJust()); 5411 5412 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)}; 5413 Local<v8::Array> a3 = Local<v8::Array>::Cast( 5414 Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked()); 5415 CHECK_EQ(3u, a3->Length()); 5416 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0)) 5417 .ToLocalChecked() 5418 ->NumberValue(context.local()) 5419 .FromJust()); 5420 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1)) 5421 .ToLocalChecked() 5422 ->NumberValue(context.local()) 5423 .FromJust()); 5424 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2)) 5425 .ToLocalChecked() 5426 ->NumberValue(context.local()) 5427 .FromJust()); 5428 5429 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9), 5430 v8_num(10.11)}; 5431 Local<v8::Array> a4 = Local<v8::Array>::Cast( 5432 Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked()); 5433 CHECK_EQ(4u, a4->Length()); 5434 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0)) 5435 .ToLocalChecked() 5436 ->NumberValue(context.local()) 5437 .FromJust()); 5438 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1)) 5439 .ToLocalChecked() 5440 ->NumberValue(context.local()) 5441 .FromJust()); 5442 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2)) 5443 .ToLocalChecked() 5444 ->NumberValue(context.local()) 5445 .FromJust()); 5446 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3)) 5447 .ToLocalChecked() 5448 ->NumberValue(context.local()) 5449 .FromJust()); 5450 5451 Local<v8::Value> r1 = 5452 ReturnThisSloppy->Call(context.local(), v8::Undefined(isolate), 0, NULL) 5453 .ToLocalChecked(); 5454 CHECK(r1->StrictEquals(context->Global())); 5455 Local<v8::Value> r2 = 5456 ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, NULL) 5457 .ToLocalChecked(); 5458 CHECK(r2->StrictEquals(context->Global())); 5459 Local<v8::Value> r3 = 5460 ReturnThisSloppy->Call(context.local(), v8_num(42), 0, NULL) 5461 .ToLocalChecked(); 5462 CHECK(r3->IsNumberObject()); 5463 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf()); 5464 Local<v8::Value> r4 = 5465 ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, NULL) 5466 .ToLocalChecked(); 5467 CHECK(r4->IsStringObject()); 5468 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 5469 Local<v8::Value> r5 = 5470 ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, NULL) 5471 .ToLocalChecked(); 5472 CHECK(r5->IsBooleanObject()); 5473 CHECK(r5.As<v8::BooleanObject>()->ValueOf()); 5474 5475 Local<v8::Value> r6 = 5476 ReturnThisStrict->Call(context.local(), v8::Undefined(isolate), 0, NULL) 5477 .ToLocalChecked(); 5478 CHECK(r6->IsUndefined()); 5479 Local<v8::Value> r7 = 5480 ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, NULL) 5481 .ToLocalChecked(); 5482 CHECK(r7->IsNull()); 5483 Local<v8::Value> r8 = 5484 ReturnThisStrict->Call(context.local(), v8_num(42), 0, NULL) 5485 .ToLocalChecked(); 5486 CHECK(r8->StrictEquals(v8_num(42))); 5487 Local<v8::Value> r9 = 5488 ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, NULL) 5489 .ToLocalChecked(); 5490 CHECK(r9->StrictEquals(v8_str("hello"))); 5491 Local<v8::Value> r10 = 5492 ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, NULL) 5493 .ToLocalChecked(); 5494 CHECK(r10->StrictEquals(v8::True(isolate))); 5495 } 5496 5497 5498 THREADED_TEST(ConstructCall) { 5499 LocalContext context; 5500 v8::Isolate* isolate = context->GetIsolate(); 5501 v8::HandleScope scope(isolate); 5502 CompileRun( 5503 "function Foo() {" 5504 " var result = [];" 5505 " for (var i = 0; i < arguments.length; i++) {" 5506 " result.push(arguments[i]);" 5507 " }" 5508 " return result;" 5509 "}"); 5510 Local<Function> Foo = Local<Function>::Cast( 5511 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked()); 5512 5513 v8::Local<Value>* args0 = NULL; 5514 Local<v8::Array> a0 = Local<v8::Array>::Cast( 5515 Foo->NewInstance(context.local(), 0, args0).ToLocalChecked()); 5516 CHECK_EQ(0u, a0->Length()); 5517 5518 v8::Local<Value> args1[] = {v8_num(1.1)}; 5519 Local<v8::Array> a1 = Local<v8::Array>::Cast( 5520 Foo->NewInstance(context.local(), 1, args1).ToLocalChecked()); 5521 CHECK_EQ(1u, a1->Length()); 5522 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0)) 5523 .ToLocalChecked() 5524 ->NumberValue(context.local()) 5525 .FromJust()); 5526 5527 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)}; 5528 Local<v8::Array> a2 = Local<v8::Array>::Cast( 5529 Foo->NewInstance(context.local(), 2, args2).ToLocalChecked()); 5530 CHECK_EQ(2u, a2->Length()); 5531 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0)) 5532 .ToLocalChecked() 5533 ->NumberValue(context.local()) 5534 .FromJust()); 5535 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1)) 5536 .ToLocalChecked() 5537 ->NumberValue(context.local()) 5538 .FromJust()); 5539 5540 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)}; 5541 Local<v8::Array> a3 = Local<v8::Array>::Cast( 5542 Foo->NewInstance(context.local(), 3, args3).ToLocalChecked()); 5543 CHECK_EQ(3u, a3->Length()); 5544 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0)) 5545 .ToLocalChecked() 5546 ->NumberValue(context.local()) 5547 .FromJust()); 5548 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1)) 5549 .ToLocalChecked() 5550 ->NumberValue(context.local()) 5551 .FromJust()); 5552 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2)) 5553 .ToLocalChecked() 5554 ->NumberValue(context.local()) 5555 .FromJust()); 5556 5557 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9), 5558 v8_num(10.11)}; 5559 Local<v8::Array> a4 = Local<v8::Array>::Cast( 5560 Foo->NewInstance(context.local(), 4, args4).ToLocalChecked()); 5561 CHECK_EQ(4u, a4->Length()); 5562 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0)) 5563 .ToLocalChecked() 5564 ->NumberValue(context.local()) 5565 .FromJust()); 5566 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1)) 5567 .ToLocalChecked() 5568 ->NumberValue(context.local()) 5569 .FromJust()); 5570 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2)) 5571 .ToLocalChecked() 5572 ->NumberValue(context.local()) 5573 .FromJust()); 5574 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3)) 5575 .ToLocalChecked() 5576 ->NumberValue(context.local()) 5577 .FromJust()); 5578 } 5579 5580 5581 THREADED_TEST(ConversionNumber) { 5582 LocalContext env; 5583 v8::Isolate* isolate = env->GetIsolate(); 5584 v8::HandleScope scope(isolate); 5585 // Very large number. 5586 CompileRun("var obj = Math.pow(2,32) * 1237;"); 5587 Local<Value> obj = 5588 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5589 CHECK_EQ(5312874545152.0, 5590 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5591 CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5592 CHECK(0u == 5593 obj->ToUint32(env.local()) 5594 .ToLocalChecked() 5595 ->Value()); // NOLINT - no CHECK_EQ for unsigned. 5596 // Large number. 5597 CompileRun("var obj = -1234567890123;"); 5598 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5599 CHECK_EQ(-1234567890123.0, 5600 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5601 CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5602 CHECK(2382691125u == 5603 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5604 // Small positive integer. 5605 CompileRun("var obj = 42;"); 5606 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5607 CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5608 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5609 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5610 // Negative integer. 5611 CompileRun("var obj = -37;"); 5612 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5613 CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5614 CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5615 CHECK(4294967259u == 5616 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5617 // Positive non-int32 integer. 5618 CompileRun("var obj = 0x81234567;"); 5619 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5620 CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5621 CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5622 CHECK(2166572391u == 5623 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5624 // Fraction. 5625 CompileRun("var obj = 42.3;"); 5626 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5627 CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5628 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5629 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5630 // Large negative fraction. 5631 CompileRun("var obj = -5726623061.75;"); 5632 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5633 CHECK_EQ(-5726623061.75, 5634 obj->ToNumber(env.local()).ToLocalChecked()->Value()); 5635 CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value()); 5636 CHECK(2863311531u == 5637 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT 5638 } 5639 5640 5641 THREADED_TEST(isNumberType) { 5642 LocalContext env; 5643 v8::HandleScope scope(env->GetIsolate()); 5644 // Very large number. 5645 CompileRun("var obj = Math.pow(2,32) * 1237;"); 5646 Local<Value> obj = 5647 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5648 CHECK(!obj->IsInt32()); 5649 CHECK(!obj->IsUint32()); 5650 // Large negative number. 5651 CompileRun("var obj = -1234567890123;"); 5652 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5653 CHECK(!obj->IsInt32()); 5654 CHECK(!obj->IsUint32()); 5655 // Small positive integer. 5656 CompileRun("var obj = 42;"); 5657 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5658 CHECK(obj->IsInt32()); 5659 CHECK(obj->IsUint32()); 5660 // Negative integer. 5661 CompileRun("var obj = -37;"); 5662 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5663 CHECK(obj->IsInt32()); 5664 CHECK(!obj->IsUint32()); 5665 // Positive non-int32 integer. 5666 CompileRun("var obj = 0x81234567;"); 5667 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5668 CHECK(!obj->IsInt32()); 5669 CHECK(obj->IsUint32()); 5670 // Fraction. 5671 CompileRun("var obj = 42.3;"); 5672 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5673 CHECK(!obj->IsInt32()); 5674 CHECK(!obj->IsUint32()); 5675 // Large negative fraction. 5676 CompileRun("var obj = -5726623061.75;"); 5677 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5678 CHECK(!obj->IsInt32()); 5679 CHECK(!obj->IsUint32()); 5680 // Positive zero 5681 CompileRun("var obj = 0.0;"); 5682 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5683 CHECK(obj->IsInt32()); 5684 CHECK(obj->IsUint32()); 5685 // Positive zero 5686 CompileRun("var obj = -0.0;"); 5687 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5688 CHECK(!obj->IsInt32()); 5689 CHECK(!obj->IsUint32()); 5690 } 5691 5692 5693 static void CheckUncle(v8::TryCatch* try_catch) { 5694 CHECK(try_catch->HasCaught()); 5695 String::Utf8Value str_value(try_catch->Exception()); 5696 CHECK_EQ(0, strcmp(*str_value, "uncle?")); 5697 try_catch->Reset(); 5698 } 5699 5700 5701 THREADED_TEST(ConversionException) { 5702 LocalContext env; 5703 v8::Isolate* isolate = env->GetIsolate(); 5704 v8::HandleScope scope(isolate); 5705 CompileRun( 5706 "function TestClass() { };" 5707 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 5708 "var obj = new TestClass();"); 5709 Local<Value> obj = 5710 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); 5711 5712 v8::TryCatch try_catch(isolate); 5713 5714 CHECK(obj->ToString(env.local()).IsEmpty()); 5715 CheckUncle(&try_catch); 5716 5717 CHECK(obj->ToNumber(env.local()).IsEmpty()); 5718 CheckUncle(&try_catch); 5719 5720 CHECK(obj->ToInteger(env.local()).IsEmpty()); 5721 CheckUncle(&try_catch); 5722 5723 CHECK(obj->ToUint32(env.local()).IsEmpty()); 5724 CheckUncle(&try_catch); 5725 5726 CHECK(obj->ToInt32(env.local()).IsEmpty()); 5727 CheckUncle(&try_catch); 5728 5729 CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty()); 5730 CHECK(try_catch.HasCaught()); 5731 try_catch.Reset(); 5732 5733 CHECK(obj->Int32Value(env.local()).IsNothing()); 5734 CheckUncle(&try_catch); 5735 5736 CHECK(obj->Uint32Value(env.local()).IsNothing()); 5737 CheckUncle(&try_catch); 5738 5739 CHECK(obj->NumberValue(env.local()).IsNothing()); 5740 CheckUncle(&try_catch); 5741 5742 CHECK(obj->IntegerValue(env.local()).IsNothing()); 5743 CheckUncle(&try_catch); 5744 } 5745 5746 5747 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 5748 ApiTestFuzzer::Fuzz(); 5749 args.GetIsolate()->ThrowException(v8_str("konto")); 5750 } 5751 5752 5753 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 5754 if (args.Length() < 1) { 5755 args.GetReturnValue().Set(false); 5756 return; 5757 } 5758 v8::HandleScope scope(args.GetIsolate()); 5759 v8::TryCatch try_catch(args.GetIsolate()); 5760 Local<Value> result = 5761 CompileRun(args[0] 5762 ->ToString(args.GetIsolate()->GetCurrentContext()) 5763 .ToLocalChecked()); 5764 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 5765 args.GetReturnValue().Set(try_catch.HasCaught()); 5766 } 5767 5768 5769 THREADED_TEST(APICatch) { 5770 v8::Isolate* isolate = CcTest::isolate(); 5771 v8::HandleScope scope(isolate); 5772 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5773 templ->Set(v8_str("ThrowFromC"), 5774 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5775 LocalContext context(0, templ); 5776 CompileRun( 5777 "var thrown = false;" 5778 "try {" 5779 " ThrowFromC();" 5780 "} catch (e) {" 5781 " thrown = true;" 5782 "}"); 5783 Local<Value> thrown = context->Global() 5784 ->Get(context.local(), v8_str("thrown")) 5785 .ToLocalChecked(); 5786 CHECK(thrown->BooleanValue(context.local()).FromJust()); 5787 } 5788 5789 5790 THREADED_TEST(APIThrowTryCatch) { 5791 v8::Isolate* isolate = CcTest::isolate(); 5792 v8::HandleScope scope(isolate); 5793 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5794 templ->Set(v8_str("ThrowFromC"), 5795 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5796 LocalContext context(0, templ); 5797 v8::TryCatch try_catch(isolate); 5798 CompileRun("ThrowFromC();"); 5799 CHECK(try_catch.HasCaught()); 5800 } 5801 5802 5803 // Test that a try-finally block doesn't shadow a try-catch block 5804 // when setting up an external handler. 5805 // 5806 // BUG(271): Some of the exception propagation does not work on the 5807 // ARM simulator because the simulator separates the C++ stack and the 5808 // JS stack. This test therefore fails on the simulator. The test is 5809 // not threaded to allow the threading tests to run on the simulator. 5810 TEST(TryCatchInTryFinally) { 5811 v8::Isolate* isolate = CcTest::isolate(); 5812 v8::HandleScope scope(isolate); 5813 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5814 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher)); 5815 LocalContext context(0, templ); 5816 Local<Value> result = CompileRun( 5817 "try {" 5818 " try {" 5819 " CCatcher('throw 7;');" 5820 " } finally {" 5821 " }" 5822 "} catch (e) {" 5823 "}"); 5824 CHECK(result->IsTrue()); 5825 } 5826 5827 5828 static void check_custom_error_tostring(v8::Local<v8::Message> message, 5829 v8::Local<v8::Value> data) { 5830 const char* uncaught_error = "Uncaught MyError toString"; 5831 CHECK(message->Get() 5832 ->Equals(CcTest::isolate()->GetCurrentContext(), 5833 v8_str(uncaught_error)) 5834 .FromJust()); 5835 } 5836 5837 5838 TEST(CustomErrorToString) { 5839 LocalContext context; 5840 v8::HandleScope scope(context->GetIsolate()); 5841 context->GetIsolate()->AddMessageListener(check_custom_error_tostring); 5842 CompileRun( 5843 "function MyError(name, message) { " 5844 " this.name = name; " 5845 " this.message = message; " 5846 "} " 5847 "MyError.prototype = Object.create(Error.prototype); " 5848 "MyError.prototype.toString = function() { " 5849 " return 'MyError toString'; " 5850 "}; " 5851 "throw new MyError('my name', 'my message'); "); 5852 context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring); 5853 } 5854 5855 5856 static void check_custom_error_message(v8::Local<v8::Message> message, 5857 v8::Local<v8::Value> data) { 5858 const char* uncaught_error = "Uncaught MyError: my message"; 5859 printf("%s\n", *v8::String::Utf8Value(message->Get())); 5860 CHECK(message->Get() 5861 ->Equals(CcTest::isolate()->GetCurrentContext(), 5862 v8_str(uncaught_error)) 5863 .FromJust()); 5864 } 5865 5866 5867 TEST(CustomErrorMessage) { 5868 LocalContext context; 5869 v8::HandleScope scope(context->GetIsolate()); 5870 context->GetIsolate()->AddMessageListener(check_custom_error_message); 5871 5872 // Handlebars. 5873 CompileRun( 5874 "function MyError(msg) { " 5875 " this.name = 'MyError'; " 5876 " this.message = msg; " 5877 "} " 5878 "MyError.prototype = new Error(); " 5879 "throw new MyError('my message'); "); 5880 5881 // Closure. 5882 CompileRun( 5883 "function MyError(msg) { " 5884 " this.name = 'MyError'; " 5885 " this.message = msg; " 5886 "} " 5887 "inherits = function(childCtor, parentCtor) { " 5888 " function tempCtor() {}; " 5889 " tempCtor.prototype = parentCtor.prototype; " 5890 " childCtor.superClass_ = parentCtor.prototype; " 5891 " childCtor.prototype = new tempCtor(); " 5892 " childCtor.prototype.constructor = childCtor; " 5893 "}; " 5894 "inherits(MyError, Error); " 5895 "throw new MyError('my message'); "); 5896 5897 // Object.create. 5898 CompileRun( 5899 "function MyError(msg) { " 5900 " this.name = 'MyError'; " 5901 " this.message = msg; " 5902 "} " 5903 "MyError.prototype = Object.create(Error.prototype); " 5904 "throw new MyError('my message'); "); 5905 5906 context->GetIsolate()->RemoveMessageListeners(check_custom_error_message); 5907 } 5908 5909 5910 static void check_custom_rethrowing_message(v8::Local<v8::Message> message, 5911 v8::Local<v8::Value> data) { 5912 const char* uncaught_error = "Uncaught exception"; 5913 CHECK(message->Get() 5914 ->Equals(CcTest::isolate()->GetCurrentContext(), 5915 v8_str(uncaught_error)) 5916 .FromJust()); 5917 } 5918 5919 5920 TEST(CustomErrorRethrowsOnToString) { 5921 LocalContext context; 5922 v8::HandleScope scope(context->GetIsolate()); 5923 context->GetIsolate()->AddMessageListener(check_custom_rethrowing_message); 5924 5925 CompileRun( 5926 "var e = { toString: function() { throw e; } };" 5927 "try { throw e; } finally {}"); 5928 5929 context->GetIsolate()->RemoveMessageListeners( 5930 check_custom_rethrowing_message); 5931 } 5932 5933 5934 static void receive_message(v8::Local<v8::Message> message, 5935 v8::Local<v8::Value> data) { 5936 message->Get(); 5937 message_received = true; 5938 } 5939 5940 5941 TEST(APIThrowMessage) { 5942 message_received = false; 5943 v8::Isolate* isolate = CcTest::isolate(); 5944 v8::HandleScope scope(isolate); 5945 isolate->AddMessageListener(receive_message); 5946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5947 templ->Set(v8_str("ThrowFromC"), 5948 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5949 LocalContext context(0, templ); 5950 CompileRun("ThrowFromC();"); 5951 CHECK(message_received); 5952 isolate->RemoveMessageListeners(receive_message); 5953 } 5954 5955 5956 TEST(APIThrowMessageAndVerboseTryCatch) { 5957 message_received = false; 5958 v8::Isolate* isolate = CcTest::isolate(); 5959 v8::HandleScope scope(isolate); 5960 isolate->AddMessageListener(receive_message); 5961 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5962 templ->Set(v8_str("ThrowFromC"), 5963 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5964 LocalContext context(0, templ); 5965 v8::TryCatch try_catch(isolate); 5966 try_catch.SetVerbose(true); 5967 Local<Value> result = CompileRun("ThrowFromC();"); 5968 CHECK(try_catch.HasCaught()); 5969 CHECK(result.IsEmpty()); 5970 CHECK(message_received); 5971 isolate->RemoveMessageListeners(receive_message); 5972 } 5973 5974 5975 TEST(APIStackOverflowAndVerboseTryCatch) { 5976 message_received = false; 5977 LocalContext context; 5978 v8::HandleScope scope(context->GetIsolate()); 5979 context->GetIsolate()->AddMessageListener(receive_message); 5980 v8::TryCatch try_catch(context->GetIsolate()); 5981 try_catch.SetVerbose(true); 5982 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 5983 CHECK(try_catch.HasCaught()); 5984 CHECK(result.IsEmpty()); 5985 CHECK(message_received); 5986 context->GetIsolate()->RemoveMessageListeners(receive_message); 5987 } 5988 5989 5990 THREADED_TEST(ExternalScriptException) { 5991 v8::Isolate* isolate = CcTest::isolate(); 5992 v8::HandleScope scope(isolate); 5993 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5994 templ->Set(v8_str("ThrowFromC"), 5995 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5996 LocalContext context(0, templ); 5997 5998 v8::TryCatch try_catch(isolate); 5999 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';"); 6000 CHECK(result.IsEmpty()); 6001 CHECK(try_catch.HasCaught()); 6002 String::Utf8Value exception_value(try_catch.Exception()); 6003 CHECK_EQ(0, strcmp("konto", *exception_value)); 6004 } 6005 6006 6007 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 6008 ApiTestFuzzer::Fuzz(); 6009 CHECK_EQ(4, args.Length()); 6010 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 6011 int count = args[0]->Int32Value(context).FromJust(); 6012 int cInterval = args[2]->Int32Value(context).FromJust(); 6013 if (count == 0) { 6014 args.GetIsolate()->ThrowException(v8_str("FromC")); 6015 return; 6016 } else { 6017 Local<v8::Object> global = context->Global(); 6018 Local<Value> fun = 6019 global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked(); 6020 v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]}; 6021 if (count % cInterval == 0) { 6022 v8::TryCatch try_catch(args.GetIsolate()); 6023 Local<Value> result = fun.As<Function>() 6024 ->Call(context, global, 4, argv) 6025 .FromMaybe(Local<Value>()); 6026 int expected = args[3]->Int32Value(context).FromJust(); 6027 if (try_catch.HasCaught()) { 6028 CHECK_EQ(expected, count); 6029 CHECK(result.IsEmpty()); 6030 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 6031 } else { 6032 CHECK_NE(expected, count); 6033 } 6034 args.GetReturnValue().Set(result); 6035 return; 6036 } else { 6037 args.GetReturnValue().Set(fun.As<Function>() 6038 ->Call(context, global, 4, argv) 6039 .FromMaybe(v8::Local<v8::Value>())); 6040 return; 6041 } 6042 } 6043 } 6044 6045 6046 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 6047 ApiTestFuzzer::Fuzz(); 6048 CHECK_EQ(3, args.Length()); 6049 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 6050 bool equality = args[0]->BooleanValue(context).FromJust(); 6051 int count = args[1]->Int32Value(context).FromJust(); 6052 int expected = args[2]->Int32Value(context).FromJust(); 6053 if (equality) { 6054 CHECK_EQ(count, expected); 6055 } else { 6056 CHECK_NE(count, expected); 6057 } 6058 } 6059 6060 6061 THREADED_TEST(EvalInTryFinally) { 6062 LocalContext context; 6063 v8::HandleScope scope(context->GetIsolate()); 6064 v8::TryCatch try_catch(context->GetIsolate()); 6065 CompileRun( 6066 "(function() {" 6067 " try {" 6068 " eval('asldkf (*&^&*^');" 6069 " } finally {" 6070 " return;" 6071 " }" 6072 "})()"); 6073 CHECK(!try_catch.HasCaught()); 6074 } 6075 6076 6077 // This test works by making a stack of alternating JavaScript and C 6078 // activations. These activations set up exception handlers with regular 6079 // intervals, one interval for C activations and another for JavaScript 6080 // activations. When enough activations have been created an exception is 6081 // thrown and we check that the right activation catches the exception and that 6082 // no other activations do. The right activation is always the topmost one with 6083 // a handler, regardless of whether it is in JavaScript or C. 6084 // 6085 // The notation used to describe a test case looks like this: 6086 // 6087 // *JS[4] *C[3] @JS[2] C[1] JS[0] 6088 // 6089 // Each entry is an activation, either JS or C. The index is the count at that 6090 // level. Stars identify activations with exception handlers, the @ identifies 6091 // the exception handler that should catch the exception. 6092 // 6093 // BUG(271): Some of the exception propagation does not work on the 6094 // ARM simulator because the simulator separates the C++ stack and the 6095 // JS stack. This test therefore fails on the simulator. The test is 6096 // not threaded to allow the threading tests to run on the simulator. 6097 TEST(ExceptionOrder) { 6098 v8::Isolate* isolate = CcTest::isolate(); 6099 v8::HandleScope scope(isolate); 6100 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6101 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck)); 6102 templ->Set(v8_str("CThrowCountDown"), 6103 v8::FunctionTemplate::New(isolate, CThrowCountDown)); 6104 LocalContext context(0, templ); 6105 CompileRun( 6106 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 6107 " if (count == 0) throw 'FromJS';" 6108 " if (count % jsInterval == 0) {" 6109 " try {" 6110 " var value = CThrowCountDown(count - 1," 6111 " jsInterval," 6112 " cInterval," 6113 " expected);" 6114 " check(false, count, expected);" 6115 " return value;" 6116 " } catch (e) {" 6117 " check(true, count, expected);" 6118 " }" 6119 " } else {" 6120 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 6121 " }" 6122 "}"); 6123 Local<Function> fun = Local<Function>::Cast( 6124 context->Global() 6125 ->Get(context.local(), v8_str("JSThrowCountDown")) 6126 .ToLocalChecked()); 6127 6128 const int argc = 4; 6129 // count jsInterval cInterval expected 6130 6131 // *JS[4] *C[3] @JS[2] C[1] JS[0] 6132 v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)}; 6133 fun->Call(context.local(), fun, argc, a0).ToLocalChecked(); 6134 6135 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 6136 v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)}; 6137 fun->Call(context.local(), fun, argc, a1).ToLocalChecked(); 6138 6139 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 6140 v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)}; 6141 fun->Call(context.local(), fun, argc, a2).ToLocalChecked(); 6142 6143 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 6144 v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)}; 6145 fun->Call(context.local(), fun, argc, a3).ToLocalChecked(); 6146 6147 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 6148 v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)}; 6149 fun->Call(context.local(), fun, argc, a4).ToLocalChecked(); 6150 6151 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 6152 v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)}; 6153 fun->Call(context.local(), fun, argc, a5).ToLocalChecked(); 6154 } 6155 6156 6157 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 6158 ApiTestFuzzer::Fuzz(); 6159 CHECK_EQ(1, args.Length()); 6160 args.GetIsolate()->ThrowException(args[0]); 6161 } 6162 6163 6164 THREADED_TEST(ThrowValues) { 6165 v8::Isolate* isolate = CcTest::isolate(); 6166 v8::HandleScope scope(isolate); 6167 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6168 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue)); 6169 LocalContext context(0, templ); 6170 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast( 6171 CompileRun("function Run(obj) {" 6172 " try {" 6173 " Throw(obj);" 6174 " } catch (e) {" 6175 " return e;" 6176 " }" 6177 " return 'no exception';" 6178 "}" 6179 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 6180 CHECK_EQ(5u, result->Length()); 6181 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0)) 6182 .ToLocalChecked() 6183 ->IsString()); 6184 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1)) 6185 .ToLocalChecked() 6186 ->IsNumber()); 6187 CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1)) 6188 .ToLocalChecked() 6189 ->Int32Value(context.local()) 6190 .FromJust()); 6191 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2)) 6192 .ToLocalChecked() 6193 ->IsNumber()); 6194 CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2)) 6195 .ToLocalChecked() 6196 ->Int32Value(context.local()) 6197 .FromJust()); 6198 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3)) 6199 .ToLocalChecked() 6200 ->IsNull()); 6201 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4)) 6202 .ToLocalChecked() 6203 ->IsUndefined()); 6204 } 6205 6206 6207 THREADED_TEST(CatchZero) { 6208 LocalContext context; 6209 v8::HandleScope scope(context->GetIsolate()); 6210 v8::TryCatch try_catch(context->GetIsolate()); 6211 CHECK(!try_catch.HasCaught()); 6212 CompileRun("throw 10"); 6213 CHECK(try_catch.HasCaught()); 6214 CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust()); 6215 try_catch.Reset(); 6216 CHECK(!try_catch.HasCaught()); 6217 CompileRun("throw 0"); 6218 CHECK(try_catch.HasCaught()); 6219 CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust()); 6220 } 6221 6222 6223 THREADED_TEST(CatchExceptionFromWith) { 6224 LocalContext context; 6225 v8::HandleScope scope(context->GetIsolate()); 6226 v8::TryCatch try_catch(context->GetIsolate()); 6227 CHECK(!try_catch.HasCaught()); 6228 CompileRun("var o = {}; with (o) { throw 42; }"); 6229 CHECK(try_catch.HasCaught()); 6230 } 6231 6232 6233 THREADED_TEST(TryCatchAndFinallyHidingException) { 6234 LocalContext context; 6235 v8::HandleScope scope(context->GetIsolate()); 6236 v8::TryCatch try_catch(context->GetIsolate()); 6237 CHECK(!try_catch.HasCaught()); 6238 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 6239 CompileRun("f({toString: function() { throw 42; }});"); 6240 CHECK(!try_catch.HasCaught()); 6241 } 6242 6243 6244 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 6245 v8::TryCatch try_catch(args.GetIsolate()); 6246 } 6247 6248 6249 THREADED_TEST(TryCatchAndFinally) { 6250 LocalContext context; 6251 v8::Isolate* isolate = context->GetIsolate(); 6252 v8::HandleScope scope(isolate); 6253 CHECK(context->Global() 6254 ->Set(context.local(), v8_str("native_with_try_catch"), 6255 v8::FunctionTemplate::New(isolate, WithTryCatch) 6256 ->GetFunction(context.local()) 6257 .ToLocalChecked()) 6258 .FromJust()); 6259 v8::TryCatch try_catch(isolate); 6260 CHECK(!try_catch.HasCaught()); 6261 CompileRun( 6262 "try {\n" 6263 " throw new Error('a');\n" 6264 "} finally {\n" 6265 " native_with_try_catch();\n" 6266 "}\n"); 6267 CHECK(try_catch.HasCaught()); 6268 } 6269 6270 6271 static void TryCatchNested1Helper(int depth) { 6272 if (depth > 0) { 6273 v8::TryCatch try_catch(CcTest::isolate()); 6274 try_catch.SetVerbose(true); 6275 TryCatchNested1Helper(depth - 1); 6276 CHECK(try_catch.HasCaught()); 6277 try_catch.ReThrow(); 6278 } else { 6279 CcTest::isolate()->ThrowException(v8_str("E1")); 6280 } 6281 } 6282 6283 6284 static void TryCatchNested2Helper(int depth) { 6285 if (depth > 0) { 6286 v8::TryCatch try_catch(CcTest::isolate()); 6287 try_catch.SetVerbose(true); 6288 TryCatchNested2Helper(depth - 1); 6289 CHECK(try_catch.HasCaught()); 6290 try_catch.ReThrow(); 6291 } else { 6292 CompileRun("throw 'E2';"); 6293 } 6294 } 6295 6296 6297 TEST(TryCatchNested) { 6298 v8::V8::Initialize(); 6299 LocalContext context; 6300 v8::HandleScope scope(context->GetIsolate()); 6301 6302 { 6303 // Test nested try-catch with a native throw in the end. 6304 v8::TryCatch try_catch(context->GetIsolate()); 6305 TryCatchNested1Helper(5); 6306 CHECK(try_catch.HasCaught()); 6307 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1")); 6308 } 6309 6310 { 6311 // Test nested try-catch with a JavaScript throw in the end. 6312 v8::TryCatch try_catch(context->GetIsolate()); 6313 TryCatchNested2Helper(5); 6314 CHECK(try_catch.HasCaught()); 6315 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2")); 6316 } 6317 } 6318 6319 6320 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 6321 CHECK(try_catch->HasCaught()); 6322 Local<Message> message = try_catch->Message(); 6323 Local<Value> resource = message->GetScriptOrigin().ResourceName(); 6324 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 6325 CHECK_EQ(0, 6326 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a")); 6327 CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext()) 6328 .FromJust()); 6329 CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext()) 6330 .FromJust()); 6331 } 6332 6333 6334 void TryCatchMixedNestingHelper( 6335 const v8::FunctionCallbackInfo<v8::Value>& args) { 6336 ApiTestFuzzer::Fuzz(); 6337 v8::TryCatch try_catch(args.GetIsolate()); 6338 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 6339 CHECK(try_catch.HasCaught()); 6340 TryCatchMixedNestingCheck(&try_catch); 6341 try_catch.ReThrow(); 6342 } 6343 6344 6345 // This test ensures that an outer TryCatch in the following situation: 6346 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 6347 // does not clobber the Message object generated for the inner TryCatch. 6348 // This exercises the ability of TryCatch.ReThrow() to restore the 6349 // inner pending Message before throwing the exception again. 6350 TEST(TryCatchMixedNesting) { 6351 v8::Isolate* isolate = CcTest::isolate(); 6352 v8::HandleScope scope(isolate); 6353 v8::V8::Initialize(); 6354 v8::TryCatch try_catch(isolate); 6355 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6356 templ->Set(v8_str("TryCatchMixedNestingHelper"), 6357 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper)); 6358 LocalContext context(0, templ); 6359 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 6360 TryCatchMixedNestingCheck(&try_catch); 6361 } 6362 6363 6364 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) { 6365 ApiTestFuzzer::Fuzz(); 6366 v8::TryCatch try_catch(args.GetIsolate()); 6367 args.GetIsolate()->ThrowException(v8_str("boom")); 6368 CHECK(try_catch.HasCaught()); 6369 } 6370 6371 6372 TEST(TryCatchNative) { 6373 v8::Isolate* isolate = CcTest::isolate(); 6374 v8::HandleScope scope(isolate); 6375 v8::V8::Initialize(); 6376 v8::TryCatch try_catch(isolate); 6377 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6378 templ->Set(v8_str("TryCatchNativeHelper"), 6379 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper)); 6380 LocalContext context(0, templ); 6381 CompileRun("TryCatchNativeHelper();"); 6382 CHECK(!try_catch.HasCaught()); 6383 } 6384 6385 6386 void TryCatchNativeResetHelper( 6387 const v8::FunctionCallbackInfo<v8::Value>& args) { 6388 ApiTestFuzzer::Fuzz(); 6389 v8::TryCatch try_catch(args.GetIsolate()); 6390 args.GetIsolate()->ThrowException(v8_str("boom")); 6391 CHECK(try_catch.HasCaught()); 6392 try_catch.Reset(); 6393 CHECK(!try_catch.HasCaught()); 6394 } 6395 6396 6397 TEST(TryCatchNativeReset) { 6398 v8::Isolate* isolate = CcTest::isolate(); 6399 v8::HandleScope scope(isolate); 6400 v8::V8::Initialize(); 6401 v8::TryCatch try_catch(isolate); 6402 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6403 templ->Set(v8_str("TryCatchNativeResetHelper"), 6404 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper)); 6405 LocalContext context(0, templ); 6406 CompileRun("TryCatchNativeResetHelper();"); 6407 CHECK(!try_catch.HasCaught()); 6408 } 6409 6410 6411 THREADED_TEST(Equality) { 6412 LocalContext context; 6413 v8::Isolate* isolate = context->GetIsolate(); 6414 v8::HandleScope scope(context->GetIsolate()); 6415 // Check that equality works at all before relying on CHECK_EQ 6416 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust()); 6417 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust()); 6418 6419 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust()); 6420 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust()); 6421 CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust()); 6422 CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust()); 6423 CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust()); 6424 6425 // Assume String is not internalized. 6426 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 6427 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 6428 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 6429 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 6430 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 6431 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); 6432 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN()); 6433 CHECK(!not_a_number->StrictEquals(not_a_number)); 6434 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); 6435 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); 6436 6437 v8::Local<v8::Object> obj = v8::Object::New(isolate); 6438 v8::Persistent<v8::Object> alias(isolate, obj); 6439 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 6440 alias.Reset(); 6441 6442 CHECK(v8_str("a")->SameValue(v8_str("a"))); 6443 CHECK(!v8_str("a")->SameValue(v8_str("b"))); 6444 CHECK(!v8_str("5")->SameValue(v8_num(5))); 6445 CHECK(v8_num(1)->SameValue(v8_num(1))); 6446 CHECK(!v8_num(1)->SameValue(v8_num(2))); 6447 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0))); 6448 CHECK(not_a_number->SameValue(not_a_number)); 6449 CHECK(v8::False(isolate)->SameValue(v8::False(isolate))); 6450 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate))); 6451 } 6452 6453 THREADED_TEST(TypeOf) { 6454 LocalContext context; 6455 v8::Isolate* isolate = context->GetIsolate(); 6456 v8::HandleScope scope(context->GetIsolate()); 6457 6458 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 6459 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked(); 6460 6461 CHECK(v8::Undefined(isolate) 6462 ->TypeOf(isolate) 6463 ->Equals(context.local(), v8_str("undefined")) 6464 .FromJust()); 6465 CHECK(v8::Null(isolate) 6466 ->TypeOf(isolate) 6467 ->Equals(context.local(), v8_str("object")) 6468 .FromJust()); 6469 CHECK(v8_str("str") 6470 ->TypeOf(isolate) 6471 ->Equals(context.local(), v8_str("string")) 6472 .FromJust()); 6473 CHECK(v8_num(0.0) 6474 ->TypeOf(isolate) 6475 ->Equals(context.local(), v8_str("number")) 6476 .FromJust()); 6477 CHECK(v8_num(1) 6478 ->TypeOf(isolate) 6479 ->Equals(context.local(), v8_str("number")) 6480 .FromJust()); 6481 CHECK(v8::Object::New(isolate) 6482 ->TypeOf(isolate) 6483 ->Equals(context.local(), v8_str("object")) 6484 .FromJust()); 6485 CHECK(v8::Boolean::New(isolate, true) 6486 ->TypeOf(isolate) 6487 ->Equals(context.local(), v8_str("boolean")) 6488 .FromJust()); 6489 CHECK(fun->TypeOf(isolate) 6490 ->Equals(context.local(), v8_str("function")) 6491 .FromJust()); 6492 } 6493 6494 THREADED_TEST(MultiRun) { 6495 LocalContext context; 6496 v8::HandleScope scope(context->GetIsolate()); 6497 Local<Script> script = v8_compile("x"); 6498 for (int i = 0; i < 10; i++) { 6499 script->Run(context.local()).IsEmpty(); 6500 } 6501 } 6502 6503 6504 static void GetXValue(Local<Name> name, 6505 const v8::PropertyCallbackInfo<v8::Value>& info) { 6506 ApiTestFuzzer::Fuzz(); 6507 CHECK(info.Data() 6508 ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut")) 6509 .FromJust()); 6510 CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x")) 6511 .FromJust()); 6512 info.GetReturnValue().Set(name); 6513 } 6514 6515 6516 THREADED_TEST(SimplePropertyRead) { 6517 LocalContext context; 6518 v8::Isolate* isolate = context->GetIsolate(); 6519 v8::HandleScope scope(isolate); 6520 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6521 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6522 CHECK(context->Global() 6523 ->Set(context.local(), v8_str("obj"), 6524 templ->NewInstance(context.local()).ToLocalChecked()) 6525 .FromJust()); 6526 Local<Script> script = v8_compile("obj.x"); 6527 for (int i = 0; i < 10; i++) { 6528 Local<Value> result = script->Run(context.local()).ToLocalChecked(); 6529 CHECK(result->Equals(context.local(), v8_str("x")).FromJust()); 6530 } 6531 } 6532 6533 6534 THREADED_TEST(DefinePropertyOnAPIAccessor) { 6535 LocalContext context; 6536 v8::Isolate* isolate = context->GetIsolate(); 6537 v8::HandleScope scope(isolate); 6538 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6539 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6540 CHECK(context->Global() 6541 ->Set(context.local(), v8_str("obj"), 6542 templ->NewInstance(context.local()).ToLocalChecked()) 6543 .FromJust()); 6544 6545 // Uses getOwnPropertyDescriptor to check the configurable status 6546 Local<Script> script_desc = v8_compile( 6547 "var prop = Object.getOwnPropertyDescriptor( " 6548 "obj, 'x');" 6549 "prop.configurable;"); 6550 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked(); 6551 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6552 6553 // Redefine get - but still configurable 6554 Local<Script> script_define = v8_compile( 6555 "var desc = { get: function(){return 42; }," 6556 " configurable: true };" 6557 "Object.defineProperty(obj, 'x', desc);" 6558 "obj.x"); 6559 result = script_define->Run(context.local()).ToLocalChecked(); 6560 CHECK(result->Equals(context.local(), v8_num(42)).FromJust()); 6561 6562 // Check that the accessor is still configurable 6563 result = script_desc->Run(context.local()).ToLocalChecked(); 6564 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6565 6566 // Redefine to a non-configurable 6567 script_define = v8_compile( 6568 "var desc = { get: function(){return 43; }," 6569 " configurable: false };" 6570 "Object.defineProperty(obj, 'x', desc);" 6571 "obj.x"); 6572 result = script_define->Run(context.local()).ToLocalChecked(); 6573 CHECK(result->Equals(context.local(), v8_num(43)).FromJust()); 6574 result = script_desc->Run(context.local()).ToLocalChecked(); 6575 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false); 6576 6577 // Make sure that it is not possible to redefine again 6578 v8::TryCatch try_catch(isolate); 6579 CHECK(script_define->Run(context.local()).IsEmpty()); 6580 CHECK(try_catch.HasCaught()); 6581 String::Utf8Value exception_value(try_catch.Exception()); 6582 CHECK_EQ(0, 6583 strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6584 } 6585 6586 6587 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 6588 v8::Isolate* isolate = CcTest::isolate(); 6589 v8::HandleScope scope(isolate); 6590 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6591 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 6592 LocalContext context; 6593 CHECK(context->Global() 6594 ->Set(context.local(), v8_str("obj"), 6595 templ->NewInstance(context.local()).ToLocalChecked()) 6596 .FromJust()); 6597 6598 Local<Script> script_desc = v8_compile( 6599 "var prop =" 6600 "Object.getOwnPropertyDescriptor( " 6601 "obj, 'x');" 6602 "prop.configurable;"); 6603 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked(); 6604 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6605 6606 Local<Script> script_define = v8_compile( 6607 "var desc = {get: function(){return 42; }," 6608 " configurable: true };" 6609 "Object.defineProperty(obj, 'x', desc);" 6610 "obj.x"); 6611 result = script_define->Run(context.local()).ToLocalChecked(); 6612 CHECK(result->Equals(context.local(), v8_num(42)).FromJust()); 6613 6614 result = script_desc->Run(context.local()).ToLocalChecked(); 6615 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true); 6616 6617 script_define = v8_compile( 6618 "var desc = {get: function(){return 43; }," 6619 " configurable: false };" 6620 "Object.defineProperty(obj, 'x', desc);" 6621 "obj.x"); 6622 result = script_define->Run(context.local()).ToLocalChecked(); 6623 CHECK(result->Equals(context.local(), v8_num(43)).FromJust()); 6624 6625 result = script_desc->Run(context.local()).ToLocalChecked(); 6626 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false); 6627 6628 v8::TryCatch try_catch(isolate); 6629 CHECK(script_define->Run(context.local()).IsEmpty()); 6630 CHECK(try_catch.HasCaught()); 6631 String::Utf8Value exception_value(try_catch.Exception()); 6632 CHECK_EQ(0, 6633 strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6634 } 6635 6636 6637 static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context, 6638 char const* name) { 6639 return v8::Local<v8::Object>::Cast( 6640 (*context) 6641 ->Global() 6642 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name)) 6643 .ToLocalChecked()); 6644 } 6645 6646 6647 THREADED_TEST(DefineAPIAccessorOnObject) { 6648 v8::Isolate* isolate = CcTest::isolate(); 6649 v8::HandleScope scope(isolate); 6650 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6651 LocalContext context; 6652 6653 CHECK(context->Global() 6654 ->Set(context.local(), v8_str("obj1"), 6655 templ->NewInstance(context.local()).ToLocalChecked()) 6656 .FromJust()); 6657 CompileRun("var obj2 = {};"); 6658 6659 CHECK(CompileRun("obj1.x")->IsUndefined()); 6660 CHECK(CompileRun("obj2.x")->IsUndefined()); 6661 6662 CHECK(GetGlobalProperty(&context, "obj1") 6663 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6664 v8_str("donut")) 6665 .FromJust()); 6666 6667 ExpectString("obj1.x", "x"); 6668 CHECK(CompileRun("obj2.x")->IsUndefined()); 6669 6670 CHECK(GetGlobalProperty(&context, "obj2") 6671 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6672 v8_str("donut")) 6673 .FromJust()); 6674 6675 ExpectString("obj1.x", "x"); 6676 ExpectString("obj2.x", "x"); 6677 6678 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6679 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6680 6681 CompileRun( 6682 "Object.defineProperty(obj1, 'x'," 6683 "{ get: function() { return 'y'; }, configurable: true })"); 6684 6685 ExpectString("obj1.x", "y"); 6686 ExpectString("obj2.x", "x"); 6687 6688 CompileRun( 6689 "Object.defineProperty(obj2, 'x'," 6690 "{ get: function() { return 'y'; }, configurable: true })"); 6691 6692 ExpectString("obj1.x", "y"); 6693 ExpectString("obj2.x", "y"); 6694 6695 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6696 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6697 6698 CHECK(GetGlobalProperty(&context, "obj1") 6699 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6700 v8_str("donut")) 6701 .FromJust()); 6702 CHECK(GetGlobalProperty(&context, "obj2") 6703 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6704 v8_str("donut")) 6705 .FromJust()); 6706 6707 ExpectString("obj1.x", "x"); 6708 ExpectString("obj2.x", "x"); 6709 6710 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6711 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6712 6713 // Define getters/setters, but now make them not configurable. 6714 CompileRun( 6715 "Object.defineProperty(obj1, 'x'," 6716 "{ get: function() { return 'z'; }, configurable: false })"); 6717 CompileRun( 6718 "Object.defineProperty(obj2, 'x'," 6719 "{ get: function() { return 'z'; }, configurable: false })"); 6720 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6721 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6722 6723 ExpectString("obj1.x", "z"); 6724 ExpectString("obj2.x", "z"); 6725 6726 CHECK(GetGlobalProperty(&context, "obj1") 6727 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6728 v8_str("donut")) 6729 .IsNothing()); 6730 CHECK(GetGlobalProperty(&context, "obj2") 6731 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6732 v8_str("donut")) 6733 .IsNothing()); 6734 6735 ExpectString("obj1.x", "z"); 6736 ExpectString("obj2.x", "z"); 6737 } 6738 6739 6740 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 6741 v8::Isolate* isolate = CcTest::isolate(); 6742 v8::HandleScope scope(isolate); 6743 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6744 LocalContext context; 6745 6746 CHECK(context->Global() 6747 ->Set(context.local(), v8_str("obj1"), 6748 templ->NewInstance(context.local()).ToLocalChecked()) 6749 .FromJust()); 6750 CompileRun("var obj2 = {};"); 6751 6752 CHECK(GetGlobalProperty(&context, "obj1") 6753 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6754 v8_str("donut"), v8::DEFAULT, v8::DontDelete) 6755 .FromJust()); 6756 CHECK(GetGlobalProperty(&context, "obj2") 6757 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6758 v8_str("donut"), v8::DEFAULT, v8::DontDelete) 6759 .FromJust()); 6760 6761 ExpectString("obj1.x", "x"); 6762 ExpectString("obj2.x", "x"); 6763 6764 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 6765 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 6766 6767 CHECK(GetGlobalProperty(&context, "obj1") 6768 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6769 v8_str("donut")) 6770 .IsNothing()); 6771 CHECK(GetGlobalProperty(&context, "obj2") 6772 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL, 6773 v8_str("donut")) 6774 .IsNothing()); 6775 6776 { 6777 v8::TryCatch try_catch(isolate); 6778 CompileRun( 6779 "Object.defineProperty(obj1, 'x'," 6780 "{get: function() { return 'func'; }})"); 6781 CHECK(try_catch.HasCaught()); 6782 String::Utf8Value exception_value(try_catch.Exception()); 6783 CHECK_EQ( 6784 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6785 } 6786 { 6787 v8::TryCatch try_catch(isolate); 6788 CompileRun( 6789 "Object.defineProperty(obj2, 'x'," 6790 "{get: function() { return 'func'; }})"); 6791 CHECK(try_catch.HasCaught()); 6792 String::Utf8Value exception_value(try_catch.Exception()); 6793 CHECK_EQ( 6794 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x")); 6795 } 6796 } 6797 6798 6799 static void Get239Value(Local<Name> name, 6800 const v8::PropertyCallbackInfo<v8::Value>& info) { 6801 ApiTestFuzzer::Fuzz(); 6802 CHECK(info.Data() 6803 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut")) 6804 .FromJust()); 6805 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239")) 6806 .FromJust()); 6807 info.GetReturnValue().Set(name); 6808 } 6809 6810 6811 THREADED_TEST(ElementAPIAccessor) { 6812 v8::Isolate* isolate = CcTest::isolate(); 6813 v8::HandleScope scope(isolate); 6814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6815 LocalContext context; 6816 6817 CHECK(context->Global() 6818 ->Set(context.local(), v8_str("obj1"), 6819 templ->NewInstance(context.local()).ToLocalChecked()) 6820 .FromJust()); 6821 CompileRun("var obj2 = {};"); 6822 6823 CHECK(GetGlobalProperty(&context, "obj1") 6824 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL, 6825 v8_str("donut")) 6826 .FromJust()); 6827 CHECK(GetGlobalProperty(&context, "obj2") 6828 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL, 6829 v8_str("donut")) 6830 .FromJust()); 6831 6832 ExpectString("obj1[239]", "239"); 6833 ExpectString("obj2[239]", "239"); 6834 ExpectString("obj1['239']", "239"); 6835 ExpectString("obj2['239']", "239"); 6836 } 6837 6838 6839 v8::Persistent<Value> xValue; 6840 6841 6842 static void SetXValue(Local<Name> name, Local<Value> value, 6843 const v8::PropertyCallbackInfo<void>& info) { 6844 Local<Context> context = info.GetIsolate()->GetCurrentContext(); 6845 CHECK(value->Equals(context, v8_num(4)).FromJust()); 6846 CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust()); 6847 CHECK(name->Equals(context, v8_str("x")).FromJust()); 6848 CHECK(xValue.IsEmpty()); 6849 xValue.Reset(info.GetIsolate(), value); 6850 } 6851 6852 6853 THREADED_TEST(SimplePropertyWrite) { 6854 v8::Isolate* isolate = CcTest::isolate(); 6855 v8::HandleScope scope(isolate); 6856 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6857 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 6858 LocalContext context; 6859 CHECK(context->Global() 6860 ->Set(context.local(), v8_str("obj"), 6861 templ->NewInstance(context.local()).ToLocalChecked()) 6862 .FromJust()); 6863 Local<Script> script = v8_compile("obj.x = 4"); 6864 for (int i = 0; i < 10; i++) { 6865 CHECK(xValue.IsEmpty()); 6866 script->Run(context.local()).ToLocalChecked(); 6867 CHECK(v8_num(4) 6868 ->Equals(context.local(), 6869 Local<Value>::New(CcTest::isolate(), xValue)) 6870 .FromJust()); 6871 xValue.Reset(); 6872 } 6873 } 6874 6875 6876 THREADED_TEST(SetterOnly) { 6877 v8::Isolate* isolate = CcTest::isolate(); 6878 v8::HandleScope scope(isolate); 6879 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6880 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 6881 LocalContext context; 6882 CHECK(context->Global() 6883 ->Set(context.local(), v8_str("obj"), 6884 templ->NewInstance(context.local()).ToLocalChecked()) 6885 .FromJust()); 6886 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 6887 for (int i = 0; i < 10; i++) { 6888 CHECK(xValue.IsEmpty()); 6889 script->Run(context.local()).ToLocalChecked(); 6890 CHECK(v8_num(4) 6891 ->Equals(context.local(), 6892 Local<Value>::New(CcTest::isolate(), xValue)) 6893 .FromJust()); 6894 xValue.Reset(); 6895 } 6896 } 6897 6898 6899 THREADED_TEST(NoAccessors) { 6900 v8::Isolate* isolate = CcTest::isolate(); 6901 v8::HandleScope scope(isolate); 6902 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6903 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL), 6904 NULL, v8_str("donut")); 6905 LocalContext context; 6906 CHECK(context->Global() 6907 ->Set(context.local(), v8_str("obj"), 6908 templ->NewInstance(context.local()).ToLocalChecked()) 6909 .FromJust()); 6910 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 6911 for (int i = 0; i < 10; i++) { 6912 script->Run(context.local()).ToLocalChecked(); 6913 } 6914 } 6915 6916 6917 THREADED_TEST(MultiContexts) { 6918 v8::Isolate* isolate = CcTest::isolate(); 6919 v8::HandleScope scope(isolate); 6920 v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6921 templ->Set(v8_str("dummy"), 6922 v8::FunctionTemplate::New(isolate, DummyCallHandler)); 6923 6924 Local<String> password = v8_str("Password"); 6925 6926 // Create an environment 6927 LocalContext context0(0, templ); 6928 context0->SetSecurityToken(password); 6929 v8::Local<v8::Object> global0 = context0->Global(); 6930 CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234)) 6931 .FromJust()); 6932 CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom")) 6933 .ToLocalChecked() 6934 ->Int32Value(context0.local()) 6935 .FromJust()); 6936 6937 // Create an independent environment 6938 LocalContext context1(0, templ); 6939 context1->SetSecurityToken(password); 6940 v8::Local<v8::Object> global1 = context1->Global(); 6941 CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234)) 6942 .FromJust()); 6943 CHECK(!global0->Equals(context1.local(), global1).FromJust()); 6944 CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom")) 6945 .ToLocalChecked() 6946 ->Int32Value(context0.local()) 6947 .FromJust()); 6948 CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom")) 6949 .ToLocalChecked() 6950 ->Int32Value(context1.local()) 6951 .FromJust()); 6952 6953 // Now create a new context with the old global 6954 LocalContext context2(0, templ, global1); 6955 context2->SetSecurityToken(password); 6956 v8::Local<v8::Object> global2 = context2->Global(); 6957 CHECK(global1->Equals(context2.local(), global2).FromJust()); 6958 CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom")) 6959 .ToLocalChecked() 6960 ->Int32Value(context1.local()) 6961 .FromJust()); 6962 CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom")) 6963 .ToLocalChecked() 6964 ->Int32Value(context2.local()) 6965 .FromJust()); 6966 } 6967 6968 6969 THREADED_TEST(FunctionPrototypeAcrossContexts) { 6970 // Make sure that functions created by cloning boilerplates cannot 6971 // communicate through their __proto__ field. 6972 6973 v8::HandleScope scope(CcTest::isolate()); 6974 6975 LocalContext env0; 6976 v8::Local<v8::Object> global0 = env0->Global(); 6977 v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object")) 6978 .ToLocalChecked() 6979 .As<v8::Object>(); 6980 v8::Local<v8::Object> tostring0 = 6981 object0->Get(env0.local(), v8_str("toString")) 6982 .ToLocalChecked() 6983 .As<v8::Object>(); 6984 v8::Local<v8::Object> proto0 = 6985 tostring0->Get(env0.local(), v8_str("__proto__")) 6986 .ToLocalChecked() 6987 .As<v8::Object>(); 6988 CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust()); 6989 6990 LocalContext env1; 6991 v8::Local<v8::Object> global1 = env1->Global(); 6992 v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object")) 6993 .ToLocalChecked() 6994 .As<v8::Object>(); 6995 v8::Local<v8::Object> tostring1 = 6996 object1->Get(env1.local(), v8_str("toString")) 6997 .ToLocalChecked() 6998 .As<v8::Object>(); 6999 v8::Local<v8::Object> proto1 = 7000 tostring1->Get(env1.local(), v8_str("__proto__")) 7001 .ToLocalChecked() 7002 .As<v8::Object>(); 7003 CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust()); 7004 } 7005 7006 7007 THREADED_TEST(Regress892105) { 7008 // Make sure that object and array literals created by cloning 7009 // boilerplates cannot communicate through their __proto__ 7010 // field. This is rather difficult to check, but we try to add stuff 7011 // to Object.prototype and Array.prototype and create a new 7012 // environment. This should succeed. 7013 7014 v8::HandleScope scope(CcTest::isolate()); 7015 7016 Local<String> source = v8_str( 7017 "Object.prototype.obj = 1234;" 7018 "Array.prototype.arr = 4567;" 7019 "8901"); 7020 7021 LocalContext env0; 7022 Local<Script> script0 = v8_compile(source); 7023 CHECK_EQ(8901.0, script0->Run(env0.local()) 7024 .ToLocalChecked() 7025 ->NumberValue(env0.local()) 7026 .FromJust()); 7027 7028 LocalContext env1; 7029 Local<Script> script1 = v8_compile(source); 7030 CHECK_EQ(8901.0, script1->Run(env1.local()) 7031 .ToLocalChecked() 7032 ->NumberValue(env1.local()) 7033 .FromJust()); 7034 } 7035 7036 7037 THREADED_TEST(UndetectableObject) { 7038 LocalContext env; 7039 v8::HandleScope scope(env->GetIsolate()); 7040 7041 Local<v8::FunctionTemplate> desc = 7042 v8::FunctionTemplate::New(env->GetIsolate()); 7043 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 7044 7045 Local<v8::Object> obj = desc->GetFunction(env.local()) 7046 .ToLocalChecked() 7047 ->NewInstance(env.local()) 7048 .ToLocalChecked(); 7049 CHECK( 7050 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 7051 7052 ExpectString("undetectable.toString()", "[object Object]"); 7053 ExpectString("typeof undetectable", "undefined"); 7054 ExpectString("typeof(undetectable)", "undefined"); 7055 ExpectBoolean("typeof undetectable == 'undefined'", true); 7056 ExpectBoolean("typeof undetectable == 'object'", false); 7057 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 7058 ExpectBoolean("!undetectable", true); 7059 7060 ExpectObject("true&&undetectable", obj); 7061 ExpectBoolean("false&&undetectable", false); 7062 ExpectBoolean("true||undetectable", true); 7063 ExpectObject("false||undetectable", obj); 7064 7065 ExpectObject("undetectable&&true", obj); 7066 ExpectObject("undetectable&&false", obj); 7067 ExpectBoolean("undetectable||true", true); 7068 ExpectBoolean("undetectable||false", false); 7069 7070 ExpectBoolean("undetectable==null", true); 7071 ExpectBoolean("null==undetectable", true); 7072 ExpectBoolean("undetectable==undefined", true); 7073 ExpectBoolean("undefined==undetectable", true); 7074 ExpectBoolean("undetectable==undetectable", true); 7075 7076 7077 ExpectBoolean("undetectable===null", false); 7078 ExpectBoolean("null===undetectable", false); 7079 ExpectBoolean("undetectable===undefined", false); 7080 ExpectBoolean("undefined===undetectable", false); 7081 ExpectBoolean("undetectable===undetectable", true); 7082 } 7083 7084 7085 THREADED_TEST(VoidLiteral) { 7086 LocalContext env; 7087 v8::Isolate* isolate = env->GetIsolate(); 7088 v8::HandleScope scope(isolate); 7089 7090 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 7091 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 7092 7093 Local<v8::Object> obj = desc->GetFunction(env.local()) 7094 .ToLocalChecked() 7095 ->NewInstance(env.local()) 7096 .ToLocalChecked(); 7097 CHECK( 7098 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 7099 7100 ExpectBoolean("undefined == void 0", true); 7101 ExpectBoolean("undetectable == void 0", true); 7102 ExpectBoolean("null == void 0", true); 7103 ExpectBoolean("undefined === void 0", true); 7104 ExpectBoolean("undetectable === void 0", false); 7105 ExpectBoolean("null === void 0", false); 7106 7107 ExpectBoolean("void 0 == undefined", true); 7108 ExpectBoolean("void 0 == undetectable", true); 7109 ExpectBoolean("void 0 == null", true); 7110 ExpectBoolean("void 0 === undefined", true); 7111 ExpectBoolean("void 0 === undetectable", false); 7112 ExpectBoolean("void 0 === null", false); 7113 7114 ExpectString( 7115 "(function() {" 7116 " try {" 7117 " return x === void 0;" 7118 " } catch(e) {" 7119 " return e.toString();" 7120 " }" 7121 "})()", 7122 "ReferenceError: x is not defined"); 7123 ExpectString( 7124 "(function() {" 7125 " try {" 7126 " return void 0 === x;" 7127 " } catch(e) {" 7128 " return e.toString();" 7129 " }" 7130 "})()", 7131 "ReferenceError: x is not defined"); 7132 } 7133 7134 7135 THREADED_TEST(ExtensibleOnUndetectable) { 7136 LocalContext env; 7137 v8::Isolate* isolate = env->GetIsolate(); 7138 v8::HandleScope scope(isolate); 7139 7140 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 7141 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 7142 7143 Local<v8::Object> obj = desc->GetFunction(env.local()) 7144 .ToLocalChecked() 7145 ->NewInstance(env.local()) 7146 .ToLocalChecked(); 7147 CHECK( 7148 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 7149 7150 Local<String> source = v8_str( 7151 "undetectable.x = 42;" 7152 "undetectable.x"); 7153 7154 Local<Script> script = v8_compile(source); 7155 7156 CHECK(v8::Integer::New(isolate, 42) 7157 ->Equals(env.local(), script->Run(env.local()).ToLocalChecked()) 7158 .FromJust()); 7159 7160 ExpectBoolean("Object.isExtensible(undetectable)", true); 7161 7162 source = v8_str("Object.preventExtensions(undetectable);"); 7163 script = v8_compile(source); 7164 script->Run(env.local()).ToLocalChecked(); 7165 ExpectBoolean("Object.isExtensible(undetectable)", false); 7166 7167 source = v8_str("undetectable.y = 2000;"); 7168 script = v8_compile(source); 7169 script->Run(env.local()).ToLocalChecked(); 7170 ExpectBoolean("undetectable.y == undefined", true); 7171 } 7172 7173 7174 // The point of this test is type checking. We run it only so compilers 7175 // don't complain about an unused function. 7176 TEST(PersistentHandles) { 7177 LocalContext env; 7178 v8::Isolate* isolate = CcTest::isolate(); 7179 v8::HandleScope scope(isolate); 7180 Local<String> str = v8_str("foo"); 7181 v8::Persistent<String> p_str(isolate, str); 7182 p_str.Reset(); 7183 Local<Script> scr = v8_compile(""); 7184 v8::Persistent<Script> p_scr(isolate, scr); 7185 p_scr.Reset(); 7186 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 7187 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 7188 p_templ.Reset(); 7189 } 7190 7191 7192 static void HandleLogDelegator( 7193 const v8::FunctionCallbackInfo<v8::Value>& args) { 7194 ApiTestFuzzer::Fuzz(); 7195 } 7196 7197 7198 THREADED_TEST(GlobalObjectTemplate) { 7199 v8::Isolate* isolate = CcTest::isolate(); 7200 v8::HandleScope handle_scope(isolate); 7201 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 7202 global_template->Set(v8_str("JSNI_Log"), 7203 v8::FunctionTemplate::New(isolate, HandleLogDelegator)); 7204 v8::Local<Context> context = Context::New(isolate, 0, global_template); 7205 Context::Scope context_scope(context); 7206 CompileRun("JSNI_Log('LOG')"); 7207 } 7208 7209 7210 static const char* kSimpleExtensionSource = 7211 "function Foo() {" 7212 " return 4;" 7213 "}"; 7214 7215 7216 TEST(SimpleExtensions) { 7217 v8::HandleScope handle_scope(CcTest::isolate()); 7218 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 7219 const char* extension_names[] = {"simpletest"}; 7220 v8::ExtensionConfiguration extensions(1, extension_names); 7221 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7222 Context::Scope lock(context); 7223 v8::Local<Value> result = CompileRun("Foo()"); 7224 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 7225 .FromJust()); 7226 } 7227 7228 7229 static const char* kStackTraceFromExtensionSource = 7230 "function foo() {" 7231 " throw new Error();" 7232 "}" 7233 "function bar() {" 7234 " foo();" 7235 "}"; 7236 7237 7238 TEST(StackTraceInExtension) { 7239 v8::HandleScope handle_scope(CcTest::isolate()); 7240 v8::RegisterExtension( 7241 new Extension("stacktracetest", kStackTraceFromExtensionSource)); 7242 const char* extension_names[] = {"stacktracetest"}; 7243 v8::ExtensionConfiguration extensions(1, extension_names); 7244 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7245 Context::Scope lock(context); 7246 CompileRun( 7247 "function user() { bar(); }" 7248 "var error;" 7249 "try{ user(); } catch (e) { error = e; }"); 7250 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')"))); 7251 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')"))); 7252 CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')"))); 7253 } 7254 7255 7256 TEST(NullExtensions) { 7257 v8::HandleScope handle_scope(CcTest::isolate()); 7258 v8::RegisterExtension(new Extension("nulltest", NULL)); 7259 const char* extension_names[] = {"nulltest"}; 7260 v8::ExtensionConfiguration extensions(1, extension_names); 7261 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7262 Context::Scope lock(context); 7263 v8::Local<Value> result = CompileRun("1+3"); 7264 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 7265 .FromJust()); 7266 } 7267 7268 7269 static const char* kEmbeddedExtensionSource = 7270 "function Ret54321(){return 54321;}~~@@$" 7271 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 7272 static const int kEmbeddedExtensionSourceValidLen = 34; 7273 7274 7275 TEST(ExtensionMissingSourceLength) { 7276 v8::HandleScope handle_scope(CcTest::isolate()); 7277 v8::RegisterExtension( 7278 new Extension("srclentest_fail", kEmbeddedExtensionSource)); 7279 const char* extension_names[] = {"srclentest_fail"}; 7280 v8::ExtensionConfiguration extensions(1, extension_names); 7281 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7282 CHECK(0 == *context); 7283 } 7284 7285 7286 TEST(ExtensionWithSourceLength) { 7287 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 7288 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 7289 v8::HandleScope handle_scope(CcTest::isolate()); 7290 i::ScopedVector<char> extension_name(32); 7291 i::SNPrintF(extension_name, "ext #%d", source_len); 7292 v8::RegisterExtension(new Extension( 7293 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len)); 7294 const char* extension_names[1] = {extension_name.start()}; 7295 v8::ExtensionConfiguration extensions(1, extension_names); 7296 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7297 if (source_len == kEmbeddedExtensionSourceValidLen) { 7298 Context::Scope lock(context); 7299 v8::Local<Value> result = CompileRun("Ret54321()"); 7300 CHECK(v8::Integer::New(CcTest::isolate(), 54321) 7301 ->Equals(context, result) 7302 .FromJust()); 7303 } else { 7304 // Anything but exactly the right length should fail to compile. 7305 CHECK(0 == *context); 7306 } 7307 } 7308 } 7309 7310 7311 static const char* kEvalExtensionSource1 = 7312 "function UseEval1() {" 7313 " var x = 42;" 7314 " return eval('x');" 7315 "}"; 7316 7317 7318 static const char* kEvalExtensionSource2 = 7319 "(function() {" 7320 " var x = 42;" 7321 " function e() {" 7322 " return eval('x');" 7323 " }" 7324 " this.UseEval2 = e;" 7325 "})()"; 7326 7327 7328 TEST(UseEvalFromExtension) { 7329 v8::HandleScope handle_scope(CcTest::isolate()); 7330 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 7331 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 7332 const char* extension_names[] = {"evaltest1", "evaltest2"}; 7333 v8::ExtensionConfiguration extensions(2, extension_names); 7334 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7335 Context::Scope lock(context); 7336 v8::Local<Value> result = CompileRun("UseEval1()"); 7337 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7338 .FromJust()); 7339 result = CompileRun("UseEval2()"); 7340 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7341 .FromJust()); 7342 } 7343 7344 7345 static const char* kWithExtensionSource1 = 7346 "function UseWith1() {" 7347 " var x = 42;" 7348 " with({x:87}) { return x; }" 7349 "}"; 7350 7351 7352 static const char* kWithExtensionSource2 = 7353 "(function() {" 7354 " var x = 42;" 7355 " function e() {" 7356 " with ({x:87}) { return x; }" 7357 " }" 7358 " this.UseWith2 = e;" 7359 "})()"; 7360 7361 7362 TEST(UseWithFromExtension) { 7363 v8::HandleScope handle_scope(CcTest::isolate()); 7364 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 7365 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 7366 const char* extension_names[] = {"withtest1", "withtest2"}; 7367 v8::ExtensionConfiguration extensions(2, extension_names); 7368 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7369 Context::Scope lock(context); 7370 v8::Local<Value> result = CompileRun("UseWith1()"); 7371 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87)) 7372 .FromJust()); 7373 result = CompileRun("UseWith2()"); 7374 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87)) 7375 .FromJust()); 7376 } 7377 7378 7379 TEST(AutoExtensions) { 7380 v8::HandleScope handle_scope(CcTest::isolate()); 7381 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 7382 extension->set_auto_enable(true); 7383 v8::RegisterExtension(extension); 7384 v8::Local<Context> context = Context::New(CcTest::isolate()); 7385 Context::Scope lock(context); 7386 v8::Local<Value> result = CompileRun("Foo()"); 7387 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4)) 7388 .FromJust()); 7389 } 7390 7391 7392 static const char* kSyntaxErrorInExtensionSource = "["; 7393 7394 7395 // Test that a syntax error in an extension does not cause a fatal 7396 // error but results in an empty context. 7397 TEST(SyntaxErrorExtensions) { 7398 v8::HandleScope handle_scope(CcTest::isolate()); 7399 v8::RegisterExtension( 7400 new Extension("syntaxerror", kSyntaxErrorInExtensionSource)); 7401 const char* extension_names[] = {"syntaxerror"}; 7402 v8::ExtensionConfiguration extensions(1, extension_names); 7403 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7404 CHECK(context.IsEmpty()); 7405 } 7406 7407 7408 static const char* kExceptionInExtensionSource = "throw 42"; 7409 7410 7411 // Test that an exception when installing an extension does not cause 7412 // a fatal error but results in an empty context. 7413 TEST(ExceptionExtensions) { 7414 v8::HandleScope handle_scope(CcTest::isolate()); 7415 v8::RegisterExtension( 7416 new Extension("exception", kExceptionInExtensionSource)); 7417 const char* extension_names[] = {"exception"}; 7418 v8::ExtensionConfiguration extensions(1, extension_names); 7419 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7420 CHECK(context.IsEmpty()); 7421 } 7422 7423 7424 static const char* kNativeCallInExtensionSource = 7425 "function call_runtime_last_index_of(x) {" 7426 " return %StringLastIndexOf(x, 'bob', 10);" 7427 "}"; 7428 7429 7430 static const char* kNativeCallTest = 7431 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 7432 7433 // Test that a native runtime calls are supported in extensions. 7434 TEST(NativeCallInExtensions) { 7435 v8::HandleScope handle_scope(CcTest::isolate()); 7436 v8::RegisterExtension( 7437 new Extension("nativecall", kNativeCallInExtensionSource)); 7438 const char* extension_names[] = {"nativecall"}; 7439 v8::ExtensionConfiguration extensions(1, extension_names); 7440 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7441 Context::Scope lock(context); 7442 v8::Local<Value> result = CompileRun(kNativeCallTest); 7443 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 3)) 7444 .FromJust()); 7445 } 7446 7447 7448 class NativeFunctionExtension : public Extension { 7449 public: 7450 NativeFunctionExtension(const char* name, const char* source, 7451 v8::FunctionCallback fun = &Echo) 7452 : Extension(name, source), function_(fun) {} 7453 7454 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( 7455 v8::Isolate* isolate, v8::Local<v8::String> name) { 7456 return v8::FunctionTemplate::New(isolate, function_); 7457 } 7458 7459 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 7460 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 7461 } 7462 7463 private: 7464 v8::FunctionCallback function_; 7465 }; 7466 7467 7468 TEST(NativeFunctionDeclaration) { 7469 v8::HandleScope handle_scope(CcTest::isolate()); 7470 const char* name = "nativedecl"; 7471 v8::RegisterExtension( 7472 new NativeFunctionExtension(name, "native function foo();")); 7473 const char* extension_names[] = {name}; 7474 v8::ExtensionConfiguration extensions(1, extension_names); 7475 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7476 Context::Scope lock(context); 7477 v8::Local<Value> result = CompileRun("foo(42);"); 7478 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42)) 7479 .FromJust()); 7480 } 7481 7482 7483 TEST(NativeFunctionDeclarationError) { 7484 v8::HandleScope handle_scope(CcTest::isolate()); 7485 const char* name = "nativedeclerr"; 7486 // Syntax error in extension code. 7487 v8::RegisterExtension( 7488 new NativeFunctionExtension(name, "native\nfunction foo();")); 7489 const char* extension_names[] = {name}; 7490 v8::ExtensionConfiguration extensions(1, extension_names); 7491 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7492 CHECK(context.IsEmpty()); 7493 } 7494 7495 7496 TEST(NativeFunctionDeclarationErrorEscape) { 7497 v8::HandleScope handle_scope(CcTest::isolate()); 7498 const char* name = "nativedeclerresc"; 7499 // Syntax error in extension code - escape code in "native" means that 7500 // it's not treated as a keyword. 7501 v8::RegisterExtension( 7502 new NativeFunctionExtension(name, "nativ\\u0065 function foo();")); 7503 const char* extension_names[] = {name}; 7504 v8::ExtensionConfiguration extensions(1, extension_names); 7505 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); 7506 CHECK(context.IsEmpty()); 7507 } 7508 7509 7510 static void CheckDependencies(const char* name, const char* expected) { 7511 v8::HandleScope handle_scope(CcTest::isolate()); 7512 v8::ExtensionConfiguration config(1, &name); 7513 LocalContext context(&config); 7514 CHECK( 7515 v8_str(expected) 7516 ->Equals(context.local(), context->Global() 7517 ->Get(context.local(), v8_str("loaded")) 7518 .ToLocalChecked()) 7519 .FromJust()); 7520 } 7521 7522 7523 /* 7524 * Configuration: 7525 * 7526 * /-- B <--\ 7527 * A <- -- D <-- E 7528 * \-- C <--/ 7529 */ 7530 THREADED_TEST(ExtensionDependency) { 7531 static const char* kEDeps[] = {"D"}; 7532 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 7533 static const char* kDDeps[] = {"B", "C"}; 7534 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 7535 static const char* kBCDeps[] = {"A"}; 7536 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 7537 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 7538 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 7539 CheckDependencies("A", "undefinedA"); 7540 CheckDependencies("B", "undefinedAB"); 7541 CheckDependencies("C", "undefinedAC"); 7542 CheckDependencies("D", "undefinedABCD"); 7543 CheckDependencies("E", "undefinedABCDE"); 7544 v8::HandleScope handle_scope(CcTest::isolate()); 7545 static const char* exts[2] = {"C", "E"}; 7546 v8::ExtensionConfiguration config(2, exts); 7547 LocalContext context(&config); 7548 CHECK( 7549 v8_str("undefinedACBDE") 7550 ->Equals(context.local(), context->Global() 7551 ->Get(context.local(), v8_str("loaded")) 7552 .ToLocalChecked()) 7553 .FromJust()); 7554 } 7555 7556 7557 static const char* kExtensionTestScript = 7558 "native function A();" 7559 "native function B();" 7560 "native function C();" 7561 "function Foo(i) {" 7562 " if (i == 0) return A();" 7563 " if (i == 1) return B();" 7564 " if (i == 2) return C();" 7565 "}"; 7566 7567 7568 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 7569 ApiTestFuzzer::Fuzz(); 7570 if (args.IsConstructCall()) { 7571 CHECK(args.This() 7572 ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"), 7573 args.Data()) 7574 .FromJust()); 7575 args.GetReturnValue().SetNull(); 7576 return; 7577 } 7578 args.GetReturnValue().Set(args.Data()); 7579 } 7580 7581 7582 class FunctionExtension : public Extension { 7583 public: 7584 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {} 7585 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( 7586 v8::Isolate* isolate, v8::Local<String> name); 7587 }; 7588 7589 7590 static int lookup_count = 0; 7591 v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate( 7592 v8::Isolate* isolate, v8::Local<String> name) { 7593 lookup_count++; 7594 if (name->Equals(isolate->GetCurrentContext(), v8_str("A")).FromJust()) { 7595 return v8::FunctionTemplate::New(isolate, CallFun, 7596 v8::Integer::New(isolate, 8)); 7597 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("B")) 7598 .FromJust()) { 7599 return v8::FunctionTemplate::New(isolate, CallFun, 7600 v8::Integer::New(isolate, 7)); 7601 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("C")) 7602 .FromJust()) { 7603 return v8::FunctionTemplate::New(isolate, CallFun, 7604 v8::Integer::New(isolate, 6)); 7605 } else { 7606 return v8::Local<v8::FunctionTemplate>(); 7607 } 7608 } 7609 7610 7611 THREADED_TEST(FunctionLookup) { 7612 v8::RegisterExtension(new FunctionExtension()); 7613 v8::HandleScope handle_scope(CcTest::isolate()); 7614 static const char* exts[1] = {"functiontest"}; 7615 v8::ExtensionConfiguration config(1, exts); 7616 LocalContext context(&config); 7617 CHECK_EQ(3, lookup_count); 7618 CHECK(v8::Integer::New(CcTest::isolate(), 8) 7619 ->Equals(context.local(), CompileRun("Foo(0)")) 7620 .FromJust()); 7621 CHECK(v8::Integer::New(CcTest::isolate(), 7) 7622 ->Equals(context.local(), CompileRun("Foo(1)")) 7623 .FromJust()); 7624 CHECK(v8::Integer::New(CcTest::isolate(), 6) 7625 ->Equals(context.local(), CompileRun("Foo(2)")) 7626 .FromJust()); 7627 } 7628 7629 7630 THREADED_TEST(NativeFunctionConstructCall) { 7631 v8::RegisterExtension(new FunctionExtension()); 7632 v8::HandleScope handle_scope(CcTest::isolate()); 7633 static const char* exts[1] = {"functiontest"}; 7634 v8::ExtensionConfiguration config(1, exts); 7635 LocalContext context(&config); 7636 for (int i = 0; i < 10; i++) { 7637 // Run a few times to ensure that allocation of objects doesn't 7638 // change behavior of a constructor function. 7639 CHECK(v8::Integer::New(CcTest::isolate(), 8) 7640 ->Equals(context.local(), CompileRun("(new A()).data")) 7641 .FromJust()); 7642 CHECK(v8::Integer::New(CcTest::isolate(), 7) 7643 ->Equals(context.local(), CompileRun("(new B()).data")) 7644 .FromJust()); 7645 CHECK(v8::Integer::New(CcTest::isolate(), 6) 7646 ->Equals(context.local(), CompileRun("(new C()).data")) 7647 .FromJust()); 7648 } 7649 } 7650 7651 7652 static const char* last_location; 7653 static const char* last_message; 7654 void StoringErrorCallback(const char* location, const char* message) { 7655 if (last_location == NULL) { 7656 last_location = location; 7657 last_message = message; 7658 } 7659 } 7660 7661 7662 // ErrorReporting creates a circular extensions configuration and 7663 // tests that the fatal error handler gets called. This renders V8 7664 // unusable and therefore this test cannot be run in parallel. 7665 TEST(ErrorReporting) { 7666 CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback); 7667 static const char* aDeps[] = {"B"}; 7668 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 7669 static const char* bDeps[] = {"A"}; 7670 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 7671 last_location = NULL; 7672 v8::ExtensionConfiguration config(1, bDeps); 7673 v8::Local<Context> context = Context::New(CcTest::isolate(), &config); 7674 CHECK(context.IsEmpty()); 7675 CHECK(last_location); 7676 } 7677 7678 7679 static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message, 7680 v8::Local<Value> data) { 7681 v8::Isolate* isolate = CcTest::isolate(); 7682 Local<Context> context = isolate->GetCurrentContext(); 7683 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined()); 7684 CHECK(v8::Undefined(isolate) 7685 ->Equals(context, message->GetScriptOrigin().ResourceName()) 7686 .FromJust()); 7687 message->GetLineNumber(context).FromJust(); 7688 message->GetSourceLine(context).ToLocalChecked(); 7689 } 7690 7691 7692 THREADED_TEST(ErrorWithMissingScriptInfo) { 7693 LocalContext context; 7694 v8::HandleScope scope(context->GetIsolate()); 7695 context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener); 7696 CompileRun("throw Error()"); 7697 context->GetIsolate()->RemoveMessageListeners( 7698 MissingScriptInfoMessageListener); 7699 } 7700 7701 7702 struct FlagAndPersistent { 7703 bool flag; 7704 v8::Global<v8::Object> handle; 7705 }; 7706 7707 7708 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7709 data.GetParameter()->flag = true; 7710 data.GetParameter()->handle.Reset(); 7711 } 7712 7713 7714 static void IndependentWeakHandle(bool global_gc, bool interlinked) { 7715 v8::Isolate* iso = CcTest::isolate(); 7716 v8::HandleScope scope(iso); 7717 v8::Local<Context> context = Context::New(iso); 7718 Context::Scope context_scope(context); 7719 7720 FlagAndPersistent object_a, object_b; 7721 7722 intptr_t big_heap_size; 7723 7724 { 7725 v8::HandleScope handle_scope(iso); 7726 Local<Object> a(v8::Object::New(iso)); 7727 Local<Object> b(v8::Object::New(iso)); 7728 object_a.handle.Reset(iso, a); 7729 object_b.handle.Reset(iso, b); 7730 if (interlinked) { 7731 a->Set(context, v8_str("x"), b).FromJust(); 7732 b->Set(context, v8_str("x"), a).FromJust(); 7733 } 7734 if (global_gc) { 7735 CcTest::heap()->CollectAllGarbage(); 7736 } else { 7737 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7738 } 7739 // We are relying on this creating a big flag array and reserving the space 7740 // up front. 7741 v8::Local<Value> big_array = CompileRun("new Array(5000)"); 7742 a->Set(context, v8_str("y"), big_array).FromJust(); 7743 big_heap_size = CcTest::heap()->SizeOfObjects(); 7744 } 7745 7746 object_a.flag = false; 7747 object_b.flag = false; 7748 object_a.handle.SetWeak(&object_a, &SetFlag, 7749 v8::WeakCallbackType::kParameter); 7750 object_b.handle.SetWeak(&object_b, &SetFlag, 7751 v8::WeakCallbackType::kParameter); 7752 CHECK(!object_b.handle.IsIndependent()); 7753 object_a.handle.MarkIndependent(); 7754 object_b.handle.MarkIndependent(); 7755 CHECK(object_b.handle.IsIndependent()); 7756 if (global_gc) { 7757 CcTest::heap()->CollectAllGarbage(); 7758 } else { 7759 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7760 } 7761 // A single GC should be enough to reclaim the memory, since we are using 7762 // phantom handles. 7763 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 20000); 7764 CHECK(object_a.flag); 7765 CHECK(object_b.flag); 7766 } 7767 7768 7769 TEST(IndependentWeakHandle) { 7770 IndependentWeakHandle(false, false); 7771 IndependentWeakHandle(false, true); 7772 IndependentWeakHandle(true, false); 7773 IndependentWeakHandle(true, true); 7774 } 7775 7776 7777 class Trivial { 7778 public: 7779 explicit Trivial(int x) : x_(x) {} 7780 7781 int x() { return x_; } 7782 void set_x(int x) { x_ = x; } 7783 7784 private: 7785 int x_; 7786 }; 7787 7788 7789 class Trivial2 { 7790 public: 7791 Trivial2(int x, int y) : y_(y), x_(x) {} 7792 7793 int x() { return x_; } 7794 void set_x(int x) { x_ = x; } 7795 7796 int y() { return y_; } 7797 void set_y(int y) { y_ = y; } 7798 7799 private: 7800 int y_; 7801 int x_; 7802 }; 7803 7804 7805 void CheckInternalFields( 7806 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 7807 v8::Persistent<v8::Object>* handle = data.GetParameter(); 7808 handle->Reset(); 7809 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0)); 7810 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1)); 7811 CHECK_EQ(42, t1->x()); 7812 CHECK_EQ(103, t2->x()); 7813 t1->set_x(1729); 7814 t2->set_x(33550336); 7815 } 7816 7817 7818 void InternalFieldCallback(bool global_gc) { 7819 LocalContext env; 7820 v8::Isolate* isolate = env->GetIsolate(); 7821 v8::HandleScope scope(isolate); 7822 7823 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 7824 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 7825 Trivial* t1; 7826 Trivial2* t2; 7827 instance_templ->SetInternalFieldCount(2); 7828 { 7829 v8::HandleScope scope(isolate); 7830 Local<v8::Object> obj = templ->GetFunction(env.local()) 7831 .ToLocalChecked() 7832 ->NewInstance(env.local()) 7833 .ToLocalChecked(); 7834 v8::Persistent<v8::Object> handle(isolate, obj); 7835 CHECK_EQ(2, obj->InternalFieldCount()); 7836 CHECK(obj->GetInternalField(0)->IsUndefined()); 7837 t1 = new Trivial(42); 7838 t2 = new Trivial2(103, 9); 7839 7840 obj->SetAlignedPointerInInternalField(0, t1); 7841 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0)); 7842 CHECK_EQ(42, t1->x()); 7843 7844 obj->SetAlignedPointerInInternalField(1, t2); 7845 t2 = 7846 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1)); 7847 CHECK_EQ(103, t2->x()); 7848 7849 handle.SetWeak<v8::Persistent<v8::Object>>( 7850 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields); 7851 if (!global_gc) { 7852 handle.MarkIndependent(); 7853 } 7854 } 7855 if (global_gc) { 7856 CcTest::heap()->CollectAllGarbage(); 7857 } else { 7858 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7859 } 7860 7861 CHECK_EQ(1729, t1->x()); 7862 CHECK_EQ(33550336, t2->x()); 7863 7864 delete t1; 7865 delete t2; 7866 } 7867 7868 7869 THREADED_TEST(InternalFieldCallback) { 7870 InternalFieldCallback(false); 7871 InternalFieldCallback(true); 7872 } 7873 7874 7875 static void ResetUseValueAndSetFlag( 7876 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7877 // Blink will reset the handle, and then use the other handle, so they 7878 // can't use the same backing slot. 7879 data.GetParameter()->handle.Reset(); 7880 data.GetParameter()->flag = true; 7881 } 7882 7883 7884 void v8::internal::HeapTester::ResetWeakHandle(bool global_gc) { 7885 using v8::Context; 7886 using v8::Local; 7887 using v8::Object; 7888 7889 v8::Isolate* iso = CcTest::isolate(); 7890 v8::HandleScope scope(iso); 7891 v8::Local<Context> context = Context::New(iso); 7892 Context::Scope context_scope(context); 7893 7894 FlagAndPersistent object_a, object_b; 7895 7896 { 7897 v8::HandleScope handle_scope(iso); 7898 Local<Object> a(v8::Object::New(iso)); 7899 Local<Object> b(v8::Object::New(iso)); 7900 object_a.handle.Reset(iso, a); 7901 object_b.handle.Reset(iso, b); 7902 if (global_gc) { 7903 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 7904 } else { 7905 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7906 } 7907 } 7908 7909 object_a.flag = false; 7910 object_b.flag = false; 7911 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag, 7912 v8::WeakCallbackType::kParameter); 7913 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag, 7914 v8::WeakCallbackType::kParameter); 7915 if (!global_gc) { 7916 object_a.handle.MarkIndependent(); 7917 object_b.handle.MarkIndependent(); 7918 CHECK(object_b.handle.IsIndependent()); 7919 } 7920 if (global_gc) { 7921 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); 7922 } else { 7923 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7924 } 7925 CHECK(object_a.flag); 7926 CHECK(object_b.flag); 7927 } 7928 7929 7930 THREADED_HEAP_TEST(ResetWeakHandle) { 7931 v8::internal::HeapTester::ResetWeakHandle(false); 7932 v8::internal::HeapTester::ResetWeakHandle(true); 7933 } 7934 7935 7936 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); } 7937 7938 7939 static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); } 7940 7941 7942 static void ForceScavenge2( 7943 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7944 data.GetParameter()->flag = true; 7945 InvokeScavenge(); 7946 } 7947 7948 static void ForceScavenge1( 7949 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7950 data.GetParameter()->handle.Reset(); 7951 data.SetSecondPassCallback(ForceScavenge2); 7952 } 7953 7954 7955 static void ForceMarkSweep2( 7956 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7957 data.GetParameter()->flag = true; 7958 InvokeMarkSweep(); 7959 } 7960 7961 static void ForceMarkSweep1( 7962 const v8::WeakCallbackInfo<FlagAndPersistent>& data) { 7963 data.GetParameter()->handle.Reset(); 7964 data.SetSecondPassCallback(ForceMarkSweep2); 7965 } 7966 7967 7968 THREADED_TEST(GCFromWeakCallbacks) { 7969 v8::Isolate* isolate = CcTest::isolate(); 7970 v8::Locker locker(CcTest::isolate()); 7971 v8::HandleScope scope(isolate); 7972 v8::Local<Context> context = Context::New(isolate); 7973 Context::Scope context_scope(context); 7974 7975 static const int kNumberOfGCTypes = 2; 7976 typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback; 7977 Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1, 7978 &ForceMarkSweep1}; 7979 7980 typedef void (*GCInvoker)(); 7981 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 7982 7983 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 7984 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 7985 FlagAndPersistent object; 7986 { 7987 v8::HandleScope handle_scope(isolate); 7988 object.handle.Reset(isolate, v8::Object::New(isolate)); 7989 } 7990 object.flag = false; 7991 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc], 7992 v8::WeakCallbackType::kParameter); 7993 object.handle.MarkIndependent(); 7994 invoke_gc[outer_gc](); 7995 EmptyMessageQueues(isolate); 7996 CHECK(object.flag); 7997 } 7998 } 7999 } 8000 8001 8002 v8::Local<Function> args_fun; 8003 8004 8005 static void ArgumentsTestCallback( 8006 const v8::FunctionCallbackInfo<v8::Value>& args) { 8007 ApiTestFuzzer::Fuzz(); 8008 v8::Isolate* isolate = args.GetIsolate(); 8009 Local<Context> context = isolate->GetCurrentContext(); 8010 CHECK_EQ(3, args.Length()); 8011 CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust()); 8012 CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust()); 8013 CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust()); 8014 CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust()); 8015 v8::HandleScope scope(args.GetIsolate()); 8016 CcTest::heap()->CollectAllGarbage(); 8017 } 8018 8019 8020 THREADED_TEST(Arguments) { 8021 v8::Isolate* isolate = CcTest::isolate(); 8022 v8::HandleScope scope(isolate); 8023 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 8024 global->Set(v8_str("f"), 8025 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback)); 8026 LocalContext context(NULL, global); 8027 args_fun = context->Global() 8028 ->Get(context.local(), v8_str("f")) 8029 .ToLocalChecked() 8030 .As<Function>(); 8031 v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked(); 8032 } 8033 8034 8035 static int p_getter_count; 8036 static int p_getter_count2; 8037 8038 8039 static void PGetter(Local<Name> name, 8040 const v8::PropertyCallbackInfo<v8::Value>& info) { 8041 ApiTestFuzzer::Fuzz(); 8042 p_getter_count++; 8043 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8044 v8::Local<v8::Object> global = context->Global(); 8045 CHECK( 8046 info.Holder() 8047 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked()) 8048 .FromJust()); 8049 if (name->Equals(context, v8_str("p1")).FromJust()) { 8050 CHECK(info.This() 8051 ->Equals(context, 8052 global->Get(context, v8_str("o1")).ToLocalChecked()) 8053 .FromJust()); 8054 } else if (name->Equals(context, v8_str("p2")).FromJust()) { 8055 CHECK(info.This() 8056 ->Equals(context, 8057 global->Get(context, v8_str("o2")).ToLocalChecked()) 8058 .FromJust()); 8059 } else if (name->Equals(context, v8_str("p3")).FromJust()) { 8060 CHECK(info.This() 8061 ->Equals(context, 8062 global->Get(context, v8_str("o3")).ToLocalChecked()) 8063 .FromJust()); 8064 } else if (name->Equals(context, v8_str("p4")).FromJust()) { 8065 CHECK(info.This() 8066 ->Equals(context, 8067 global->Get(context, v8_str("o4")).ToLocalChecked()) 8068 .FromJust()); 8069 } 8070 } 8071 8072 8073 static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) { 8074 ApiTestFuzzer::Fuzz(); 8075 LocalContext context; 8076 CHECK(context->Global() 8077 ->Set(context.local(), v8_str("o1"), 8078 obj->NewInstance(context.local()).ToLocalChecked()) 8079 .FromJust()); 8080 CompileRun( 8081 "o1.__proto__ = { };" 8082 "var o2 = { __proto__: o1 };" 8083 "var o3 = { __proto__: o2 };" 8084 "var o4 = { __proto__: o3 };" 8085 "for (var i = 0; i < 10; i++) o4.p4;" 8086 "for (var i = 0; i < 10; i++) o3.p3;" 8087 "for (var i = 0; i < 10; i++) o2.p2;" 8088 "for (var i = 0; i < 10; i++) o1.p1;"); 8089 } 8090 8091 8092 static void PGetter2(Local<Name> name, 8093 const v8::PropertyCallbackInfo<v8::Value>& info) { 8094 ApiTestFuzzer::Fuzz(); 8095 p_getter_count2++; 8096 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8097 v8::Local<v8::Object> global = context->Global(); 8098 CHECK( 8099 info.Holder() 8100 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked()) 8101 .FromJust()); 8102 if (name->Equals(context, v8_str("p1")).FromJust()) { 8103 CHECK(info.This() 8104 ->Equals(context, 8105 global->Get(context, v8_str("o1")).ToLocalChecked()) 8106 .FromJust()); 8107 } else if (name->Equals(context, v8_str("p2")).FromJust()) { 8108 CHECK(info.This() 8109 ->Equals(context, 8110 global->Get(context, v8_str("o2")).ToLocalChecked()) 8111 .FromJust()); 8112 } else if (name->Equals(context, v8_str("p3")).FromJust()) { 8113 CHECK(info.This() 8114 ->Equals(context, 8115 global->Get(context, v8_str("o3")).ToLocalChecked()) 8116 .FromJust()); 8117 } else if (name->Equals(context, v8_str("p4")).FromJust()) { 8118 CHECK(info.This() 8119 ->Equals(context, 8120 global->Get(context, v8_str("o4")).ToLocalChecked()) 8121 .FromJust()); 8122 } 8123 } 8124 8125 8126 THREADED_TEST(GetterHolders) { 8127 v8::Isolate* isolate = CcTest::isolate(); 8128 v8::HandleScope scope(isolate); 8129 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8130 obj->SetAccessor(v8_str("p1"), PGetter); 8131 obj->SetAccessor(v8_str("p2"), PGetter); 8132 obj->SetAccessor(v8_str("p3"), PGetter); 8133 obj->SetAccessor(v8_str("p4"), PGetter); 8134 p_getter_count = 0; 8135 RunHolderTest(obj); 8136 CHECK_EQ(40, p_getter_count); 8137 } 8138 8139 8140 THREADED_TEST(PreInterceptorHolders) { 8141 v8::Isolate* isolate = CcTest::isolate(); 8142 v8::HandleScope scope(isolate); 8143 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8144 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2)); 8145 p_getter_count2 = 0; 8146 RunHolderTest(obj); 8147 CHECK_EQ(40, p_getter_count2); 8148 } 8149 8150 8151 THREADED_TEST(ObjectInstantiation) { 8152 v8::Isolate* isolate = CcTest::isolate(); 8153 v8::HandleScope scope(isolate); 8154 v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 8155 templ->SetAccessor(v8_str("t"), PGetter2); 8156 LocalContext context; 8157 CHECK(context->Global() 8158 ->Set(context.local(), v8_str("o"), 8159 templ->NewInstance(context.local()).ToLocalChecked()) 8160 .FromJust()); 8161 for (int i = 0; i < 100; i++) { 8162 v8::HandleScope inner_scope(CcTest::isolate()); 8163 v8::Local<v8::Object> obj = 8164 templ->NewInstance(context.local()).ToLocalChecked(); 8165 CHECK(!obj->Equals(context.local(), context->Global() 8166 ->Get(context.local(), v8_str("o")) 8167 .ToLocalChecked()) 8168 .FromJust()); 8169 CHECK( 8170 context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust()); 8171 v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__"); 8172 CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust()); 8173 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust()); 8174 } 8175 } 8176 8177 8178 static int StrCmp16(uint16_t* a, uint16_t* b) { 8179 while (true) { 8180 if (*a == 0 && *b == 0) return 0; 8181 if (*a != *b) return 0 + *a - *b; 8182 a++; 8183 b++; 8184 } 8185 } 8186 8187 8188 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 8189 while (true) { 8190 if (n-- == 0) return 0; 8191 if (*a == 0 && *b == 0) return 0; 8192 if (*a != *b) return 0 + *a - *b; 8193 a++; 8194 b++; 8195 } 8196 } 8197 8198 8199 int GetUtf8Length(Local<String> str) { 8200 int len = str->Utf8Length(); 8201 if (len < 0) { 8202 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 8203 i::String::Flatten(istr); 8204 len = str->Utf8Length(); 8205 } 8206 return len; 8207 } 8208 8209 8210 THREADED_TEST(StringWrite) { 8211 LocalContext context; 8212 v8::HandleScope scope(context->GetIsolate()); 8213 v8::Local<String> str = v8_str("abcde"); 8214 // abc<Icelandic eth><Unicode snowman>. 8215 v8::Local<String> str2 = v8_str("abc\303\260\342\230\203"); 8216 v8::Local<String> str3 = 8217 v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def", 8218 v8::NewStringType::kNormal, 7) 8219 .ToLocalChecked(); 8220 // "ab" + lead surrogate + "cd" + trail surrogate + "ef" 8221 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 }; 8222 v8::Local<String> orphans_str = 8223 v8::String::NewFromTwoByte(context->GetIsolate(), orphans, 8224 v8::NewStringType::kNormal, 8) 8225 .ToLocalChecked(); 8226 // single lead surrogate 8227 uint16_t lead[1] = { 0xd800 }; 8228 v8::Local<String> lead_str = 8229 v8::String::NewFromTwoByte(context->GetIsolate(), lead, 8230 v8::NewStringType::kNormal, 1) 8231 .ToLocalChecked(); 8232 // single trail surrogate 8233 uint16_t trail[1] = { 0xdc00 }; 8234 v8::Local<String> trail_str = 8235 v8::String::NewFromTwoByte(context->GetIsolate(), trail, 8236 v8::NewStringType::kNormal, 1) 8237 .ToLocalChecked(); 8238 // surrogate pair 8239 uint16_t pair[2] = { 0xd800, 0xdc00 }; 8240 v8::Local<String> pair_str = 8241 v8::String::NewFromTwoByte(context->GetIsolate(), pair, 8242 v8::NewStringType::kNormal, 2) 8243 .ToLocalChecked(); 8244 const int kStride = 4; // Must match stride in for loops in JS below. 8245 CompileRun( 8246 "var left = '';" 8247 "for (var i = 0; i < 0xd800; i += 4) {" 8248 " left = left + String.fromCharCode(i);" 8249 "}"); 8250 CompileRun( 8251 "var right = '';" 8252 "for (var i = 0; i < 0xd800; i += 4) {" 8253 " right = String.fromCharCode(i) + right;" 8254 "}"); 8255 v8::Local<v8::Object> global = context->Global(); 8256 Local<String> left_tree = global->Get(context.local(), v8_str("left")) 8257 .ToLocalChecked() 8258 .As<String>(); 8259 Local<String> right_tree = global->Get(context.local(), v8_str("right")) 8260 .ToLocalChecked() 8261 .As<String>(); 8262 8263 CHECK_EQ(5, str2->Length()); 8264 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 8265 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 8266 8267 char buf[100]; 8268 char utf8buf[0xd800 * 3]; 8269 uint16_t wbuf[100]; 8270 int len; 8271 int charlen; 8272 8273 memset(utf8buf, 0x1, 1000); 8274 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 8275 CHECK_EQ(9, len); 8276 CHECK_EQ(5, charlen); 8277 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8278 8279 memset(utf8buf, 0x1, 1000); 8280 len = str2->WriteUtf8(utf8buf, 8, &charlen); 8281 CHECK_EQ(8, len); 8282 CHECK_EQ(5, charlen); 8283 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 8284 8285 memset(utf8buf, 0x1, 1000); 8286 len = str2->WriteUtf8(utf8buf, 7, &charlen); 8287 CHECK_EQ(5, len); 8288 CHECK_EQ(4, charlen); 8289 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8290 8291 memset(utf8buf, 0x1, 1000); 8292 len = str2->WriteUtf8(utf8buf, 6, &charlen); 8293 CHECK_EQ(5, len); 8294 CHECK_EQ(4, charlen); 8295 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8296 8297 memset(utf8buf, 0x1, 1000); 8298 len = str2->WriteUtf8(utf8buf, 5, &charlen); 8299 CHECK_EQ(5, len); 8300 CHECK_EQ(4, charlen); 8301 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 8302 8303 memset(utf8buf, 0x1, 1000); 8304 len = str2->WriteUtf8(utf8buf, 4, &charlen); 8305 CHECK_EQ(3, len); 8306 CHECK_EQ(3, charlen); 8307 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 8308 8309 memset(utf8buf, 0x1, 1000); 8310 len = str2->WriteUtf8(utf8buf, 3, &charlen); 8311 CHECK_EQ(3, len); 8312 CHECK_EQ(3, charlen); 8313 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 8314 8315 memset(utf8buf, 0x1, 1000); 8316 len = str2->WriteUtf8(utf8buf, 2, &charlen); 8317 CHECK_EQ(2, len); 8318 CHECK_EQ(2, charlen); 8319 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 8320 8321 // allow orphan surrogates by default 8322 memset(utf8buf, 0x1, 1000); 8323 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 8324 CHECK_EQ(13, len); 8325 CHECK_EQ(8, charlen); 8326 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef")); 8327 8328 // replace orphan surrogates with unicode replacement character 8329 memset(utf8buf, 0x1, 1000); 8330 len = orphans_str->WriteUtf8(utf8buf, 8331 sizeof(utf8buf), 8332 &charlen, 8333 String::REPLACE_INVALID_UTF8); 8334 CHECK_EQ(13, len); 8335 CHECK_EQ(8, charlen); 8336 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef")); 8337 8338 // replace single lead surrogate with unicode replacement character 8339 memset(utf8buf, 0x1, 1000); 8340 len = lead_str->WriteUtf8(utf8buf, 8341 sizeof(utf8buf), 8342 &charlen, 8343 String::REPLACE_INVALID_UTF8); 8344 CHECK_EQ(4, len); 8345 CHECK_EQ(1, charlen); 8346 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 8347 8348 // replace single trail surrogate with unicode replacement character 8349 memset(utf8buf, 0x1, 1000); 8350 len = trail_str->WriteUtf8(utf8buf, 8351 sizeof(utf8buf), 8352 &charlen, 8353 String::REPLACE_INVALID_UTF8); 8354 CHECK_EQ(4, len); 8355 CHECK_EQ(1, charlen); 8356 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 8357 8358 // do not replace / write anything if surrogate pair does not fit the buffer 8359 // space 8360 memset(utf8buf, 0x1, 1000); 8361 len = pair_str->WriteUtf8(utf8buf, 8362 3, 8363 &charlen, 8364 String::REPLACE_INVALID_UTF8); 8365 CHECK_EQ(0, len); 8366 CHECK_EQ(0, charlen); 8367 8368 memset(utf8buf, 0x1, sizeof(utf8buf)); 8369 len = GetUtf8Length(left_tree); 8370 int utf8_expected = 8371 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 8372 CHECK_EQ(utf8_expected, len); 8373 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 8374 CHECK_EQ(utf8_expected, len); 8375 CHECK_EQ(0xd800 / kStride, charlen); 8376 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 8377 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 8378 CHECK_EQ(0xc0 - kStride, 8379 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 8380 CHECK_EQ(1, utf8buf[utf8_expected]); 8381 8382 memset(utf8buf, 0x1, sizeof(utf8buf)); 8383 len = GetUtf8Length(right_tree); 8384 CHECK_EQ(utf8_expected, len); 8385 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 8386 CHECK_EQ(utf8_expected, len); 8387 CHECK_EQ(0xd800 / kStride, charlen); 8388 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 8389 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 8390 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 8391 CHECK_EQ(1, utf8buf[utf8_expected]); 8392 8393 memset(buf, 0x1, sizeof(buf)); 8394 memset(wbuf, 0x1, sizeof(wbuf)); 8395 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8396 CHECK_EQ(5, len); 8397 len = str->Write(wbuf); 8398 CHECK_EQ(5, len); 8399 CHECK_EQ(0, strcmp("abcde", buf)); 8400 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8401 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 8402 8403 memset(buf, 0x1, sizeof(buf)); 8404 memset(wbuf, 0x1, sizeof(wbuf)); 8405 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 8406 CHECK_EQ(4, len); 8407 len = str->Write(wbuf, 0, 4); 8408 CHECK_EQ(4, len); 8409 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 8410 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 8411 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 8412 8413 memset(buf, 0x1, sizeof(buf)); 8414 memset(wbuf, 0x1, sizeof(wbuf)); 8415 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 8416 CHECK_EQ(5, len); 8417 len = str->Write(wbuf, 0, 5); 8418 CHECK_EQ(5, len); 8419 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 8420 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 8421 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 8422 8423 memset(buf, 0x1, sizeof(buf)); 8424 memset(wbuf, 0x1, sizeof(wbuf)); 8425 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 8426 CHECK_EQ(5, len); 8427 len = str->Write(wbuf, 0, 6); 8428 CHECK_EQ(5, len); 8429 CHECK_EQ(0, strcmp("abcde", buf)); 8430 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8431 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 8432 8433 memset(buf, 0x1, sizeof(buf)); 8434 memset(wbuf, 0x1, sizeof(wbuf)); 8435 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 8436 CHECK_EQ(1, len); 8437 len = str->Write(wbuf, 4, -1); 8438 CHECK_EQ(1, len); 8439 CHECK_EQ(0, strcmp("e", buf)); 8440 uint16_t answer5[] = {'e', '\0'}; 8441 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8442 8443 memset(buf, 0x1, sizeof(buf)); 8444 memset(wbuf, 0x1, sizeof(wbuf)); 8445 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 8446 CHECK_EQ(1, len); 8447 len = str->Write(wbuf, 4, 6); 8448 CHECK_EQ(1, len); 8449 CHECK_EQ(0, strcmp("e", buf)); 8450 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8451 8452 memset(buf, 0x1, sizeof(buf)); 8453 memset(wbuf, 0x1, sizeof(wbuf)); 8454 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 8455 CHECK_EQ(1, len); 8456 len = str->Write(wbuf, 4, 1); 8457 CHECK_EQ(1, len); 8458 CHECK_EQ(0, strncmp("e\1", buf, 2)); 8459 uint16_t answer6[] = {'e', 0x101}; 8460 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 8461 8462 memset(buf, 0x1, sizeof(buf)); 8463 memset(wbuf, 0x1, sizeof(wbuf)); 8464 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 8465 CHECK_EQ(1, len); 8466 len = str->Write(wbuf, 3, 1); 8467 CHECK_EQ(1, len); 8468 CHECK_EQ(0, strncmp("d\1", buf, 2)); 8469 uint16_t answer7[] = {'d', 0x101}; 8470 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 8471 8472 memset(wbuf, 0x1, sizeof(wbuf)); 8473 wbuf[5] = 'X'; 8474 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 8475 CHECK_EQ(5, len); 8476 CHECK_EQ('X', wbuf[5]); 8477 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 8478 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8479 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 8480 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 8481 wbuf[5] = '\0'; 8482 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 8483 8484 memset(buf, 0x1, sizeof(buf)); 8485 buf[5] = 'X'; 8486 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 8487 0, 8488 6, 8489 String::NO_NULL_TERMINATION); 8490 CHECK_EQ(5, len); 8491 CHECK_EQ('X', buf[5]); 8492 CHECK_EQ(0, strncmp("abcde", buf, 5)); 8493 CHECK_NE(0, strcmp("abcde", buf)); 8494 buf[5] = '\0'; 8495 CHECK_EQ(0, strcmp("abcde", buf)); 8496 8497 memset(utf8buf, 0x1, sizeof(utf8buf)); 8498 utf8buf[8] = 'X'; 8499 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8500 String::NO_NULL_TERMINATION); 8501 CHECK_EQ(8, len); 8502 CHECK_EQ('X', utf8buf[8]); 8503 CHECK_EQ(5, charlen); 8504 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 8505 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8506 utf8buf[8] = '\0'; 8507 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8508 8509 memset(utf8buf, 0x1, sizeof(utf8buf)); 8510 utf8buf[5] = 'X'; 8511 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8512 String::NO_NULL_TERMINATION); 8513 CHECK_EQ(5, len); 8514 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 8515 CHECK_EQ(5, charlen); 8516 utf8buf[5] = '\0'; 8517 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 8518 8519 memset(buf, 0x1, sizeof(buf)); 8520 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8521 CHECK_EQ(7, len); 8522 CHECK_EQ(0, strcmp("abc", buf)); 8523 CHECK_EQ(0, buf[3]); 8524 CHECK_EQ(0, strcmp("def", buf + 4)); 8525 8526 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8527 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8528 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8529 } 8530 8531 8532 static void Utf16Helper( 8533 LocalContext& context, // NOLINT 8534 const char* name, 8535 const char* lengths_name, 8536 int len) { 8537 Local<v8::Array> a = Local<v8::Array>::Cast( 8538 context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked()); 8539 Local<v8::Array> alens = 8540 Local<v8::Array>::Cast(context->Global() 8541 ->Get(context.local(), v8_str(lengths_name)) 8542 .ToLocalChecked()); 8543 for (int i = 0; i < len; i++) { 8544 Local<v8::String> string = 8545 Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked()); 8546 Local<v8::Number> expected_len = Local<v8::Number>::Cast( 8547 alens->Get(context.local(), i).ToLocalChecked()); 8548 int length = GetUtf8Length(string); 8549 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 8550 } 8551 } 8552 8553 8554 THREADED_TEST(Utf16) { 8555 LocalContext context; 8556 v8::HandleScope scope(context->GetIsolate()); 8557 CompileRun( 8558 "var pad = '01234567890123456789';" 8559 "var p = [];" 8560 "var plens = [20, 3, 3];" 8561 "p.push('01234567890123456789');" 8562 "var lead = 0xd800;" 8563 "var trail = 0xdc00;" 8564 "p.push(String.fromCharCode(0xd800));" 8565 "p.push(String.fromCharCode(0xdc00));" 8566 "var a = [];" 8567 "var b = [];" 8568 "var c = [];" 8569 "var alens = [];" 8570 "for (var i = 0; i < 3; i++) {" 8571 " p[1] = String.fromCharCode(lead++);" 8572 " for (var j = 0; j < 3; j++) {" 8573 " p[2] = String.fromCharCode(trail++);" 8574 " a.push(p[i] + p[j]);" 8575 " b.push(p[i] + p[j]);" 8576 " c.push(p[i] + p[j]);" 8577 " alens.push(plens[i] + plens[j]);" 8578 " }" 8579 "}" 8580 "alens[5] -= 2;" // Here the surrogate pairs match up. 8581 "var a2 = [];" 8582 "var b2 = [];" 8583 "var c2 = [];" 8584 "var a2lens = [];" 8585 "for (var m = 0; m < 9; m++) {" 8586 " for (var n = 0; n < 9; n++) {" 8587 " a2.push(a[m] + a[n]);" 8588 " b2.push(b[m] + b[n]);" 8589 " var newc = 'x' + c[m] + c[n] + 'y';" 8590 " c2.push(newc.substring(1, newc.length - 1));" 8591 " var utf = alens[m] + alens[n];" // And here. 8592 // The 'n's that start with 0xdc.. are 6-8 8593 // The 'm's that end with 0xd8.. are 1, 4 and 7 8594 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 8595 " a2lens.push(utf);" 8596 " }" 8597 "}"); 8598 Utf16Helper(context, "a", "alens", 9); 8599 Utf16Helper(context, "a2", "a2lens", 81); 8600 } 8601 8602 8603 static bool SameSymbol(Local<String> s1, Local<String> s2) { 8604 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 8605 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 8606 return *is1 == *is2; 8607 } 8608 8609 8610 THREADED_TEST(Utf16Symbol) { 8611 LocalContext context; 8612 v8::HandleScope scope(context->GetIsolate()); 8613 8614 Local<String> symbol1 = 8615 v8::String::NewFromUtf8(context->GetIsolate(), "abc", 8616 v8::NewStringType::kInternalized) 8617 .ToLocalChecked(); 8618 Local<String> symbol2 = 8619 v8::String::NewFromUtf8(context->GetIsolate(), "abc", 8620 v8::NewStringType::kInternalized) 8621 .ToLocalChecked(); 8622 CHECK(SameSymbol(symbol1, symbol2)); 8623 8624 CompileRun( 8625 "var sym0 = 'benedictus';" 8626 "var sym0b = 'S\303\270ren';" 8627 "var sym1 = '\355\240\201\355\260\207';" 8628 "var sym2 = '\360\220\220\210';" 8629 "var sym3 = 'x\355\240\201\355\260\207';" 8630 "var sym4 = 'x\360\220\220\210';" 8631 "if (sym1.length != 2) throw sym1;" 8632 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 8633 "if (sym2.length != 2) throw sym2;" 8634 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 8635 "if (sym3.length != 3) throw sym3;" 8636 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 8637 "if (sym4.length != 3) throw sym4;" 8638 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 8639 Local<String> sym0 = 8640 v8::String::NewFromUtf8(context->GetIsolate(), "benedictus", 8641 v8::NewStringType::kInternalized) 8642 .ToLocalChecked(); 8643 Local<String> sym0b = 8644 v8::String::NewFromUtf8(context->GetIsolate(), "S\303\270ren", 8645 v8::NewStringType::kInternalized) 8646 .ToLocalChecked(); 8647 Local<String> sym1 = 8648 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207", 8649 v8::NewStringType::kInternalized) 8650 .ToLocalChecked(); 8651 Local<String> sym2 = 8652 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210", 8653 v8::NewStringType::kInternalized) 8654 .ToLocalChecked(); 8655 Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(), 8656 "x\355\240\201\355\260\207", 8657 v8::NewStringType::kInternalized) 8658 .ToLocalChecked(); 8659 Local<String> sym4 = 8660 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210", 8661 v8::NewStringType::kInternalized) 8662 .ToLocalChecked(); 8663 v8::Local<v8::Object> global = context->Global(); 8664 Local<Value> s0 = 8665 global->Get(context.local(), v8_str("sym0")).ToLocalChecked(); 8666 Local<Value> s0b = 8667 global->Get(context.local(), v8_str("sym0b")).ToLocalChecked(); 8668 Local<Value> s1 = 8669 global->Get(context.local(), v8_str("sym1")).ToLocalChecked(); 8670 Local<Value> s2 = 8671 global->Get(context.local(), v8_str("sym2")).ToLocalChecked(); 8672 Local<Value> s3 = 8673 global->Get(context.local(), v8_str("sym3")).ToLocalChecked(); 8674 Local<Value> s4 = 8675 global->Get(context.local(), v8_str("sym4")).ToLocalChecked(); 8676 CHECK(SameSymbol(sym0, Local<String>::Cast(s0))); 8677 CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b))); 8678 CHECK(SameSymbol(sym1, Local<String>::Cast(s1))); 8679 CHECK(SameSymbol(sym2, Local<String>::Cast(s2))); 8680 CHECK(SameSymbol(sym3, Local<String>::Cast(s3))); 8681 CHECK(SameSymbol(sym4, Local<String>::Cast(s4))); 8682 } 8683 8684 8685 THREADED_TEST(Utf16MissingTrailing) { 8686 LocalContext context; 8687 v8::HandleScope scope(context->GetIsolate()); 8688 8689 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow` 8690 int size = 1024 * 64; 8691 uint8_t* buffer = new uint8_t[size]; 8692 for (int i = 0; i < size; i += 4) { 8693 buffer[i] = 0xf0; 8694 buffer[i + 1] = 0x9d; 8695 buffer[i + 2] = 0x80; 8696 buffer[i + 3] = 0x9e; 8697 } 8698 8699 // Now invoke the decoder without last 3 bytes 8700 v8::Local<v8::String> str = 8701 v8::String::NewFromUtf8( 8702 context->GetIsolate(), reinterpret_cast<char*>(buffer), 8703 v8::NewStringType::kNormal, size - 3).ToLocalChecked(); 8704 USE(str); 8705 delete[] buffer; 8706 } 8707 8708 8709 THREADED_TEST(Utf16Trailing3Byte) { 8710 LocalContext context; 8711 v8::HandleScope scope(context->GetIsolate()); 8712 8713 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow` 8714 int size = 1024 * 63; 8715 uint8_t* buffer = new uint8_t[size]; 8716 for (int i = 0; i < size; i += 3) { 8717 buffer[i] = 0xe2; 8718 buffer[i + 1] = 0x80; 8719 buffer[i + 2] = 0xa6; 8720 } 8721 8722 // Now invoke the decoder without last 3 bytes 8723 v8::Local<v8::String> str = 8724 v8::String::NewFromUtf8( 8725 context->GetIsolate(), reinterpret_cast<char*>(buffer), 8726 v8::NewStringType::kNormal, size).ToLocalChecked(); 8727 8728 v8::String::Value value(str); 8729 CHECK_EQ(value.length(), size / 3); 8730 CHECK_EQ((*value)[value.length() - 1], 0x2026); 8731 8732 delete[] buffer; 8733 } 8734 8735 8736 THREADED_TEST(ToArrayIndex) { 8737 LocalContext context; 8738 v8::Isolate* isolate = context->GetIsolate(); 8739 v8::HandleScope scope(isolate); 8740 8741 v8::Local<String> str = v8_str("42"); 8742 v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local()); 8743 CHECK(!index.IsEmpty()); 8744 CHECK_EQ(42.0, 8745 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8746 str = v8_str("42asdf"); 8747 index = str->ToArrayIndex(context.local()); 8748 CHECK(index.IsEmpty()); 8749 str = v8_str("-42"); 8750 index = str->ToArrayIndex(context.local()); 8751 CHECK(index.IsEmpty()); 8752 str = v8_str("4294967294"); 8753 index = str->ToArrayIndex(context.local()); 8754 CHECK(!index.IsEmpty()); 8755 CHECK_EQ(4294967294.0, 8756 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8757 v8::Local<v8::Number> num = v8::Number::New(isolate, 1); 8758 index = num->ToArrayIndex(context.local()); 8759 CHECK(!index.IsEmpty()); 8760 CHECK_EQ(1.0, 8761 index.ToLocalChecked()->Uint32Value(context.local()).FromJust()); 8762 num = v8::Number::New(isolate, -1); 8763 index = num->ToArrayIndex(context.local()); 8764 CHECK(index.IsEmpty()); 8765 v8::Local<v8::Object> obj = v8::Object::New(isolate); 8766 index = obj->ToArrayIndex(context.local()); 8767 CHECK(index.IsEmpty()); 8768 } 8769 8770 8771 THREADED_TEST(ErrorConstruction) { 8772 LocalContext context; 8773 v8::HandleScope scope(context->GetIsolate()); 8774 8775 v8::Local<String> foo = v8_str("foo"); 8776 v8::Local<String> message = v8_str("message"); 8777 v8::Local<Value> range_error = v8::Exception::RangeError(foo); 8778 CHECK(range_error->IsObject()); 8779 CHECK(range_error.As<v8::Object>() 8780 ->Get(context.local(), message) 8781 .ToLocalChecked() 8782 ->Equals(context.local(), foo) 8783 .FromJust()); 8784 v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo); 8785 CHECK(reference_error->IsObject()); 8786 CHECK(reference_error.As<v8::Object>() 8787 ->Get(context.local(), message) 8788 .ToLocalChecked() 8789 ->Equals(context.local(), foo) 8790 .FromJust()); 8791 v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo); 8792 CHECK(syntax_error->IsObject()); 8793 CHECK(syntax_error.As<v8::Object>() 8794 ->Get(context.local(), message) 8795 .ToLocalChecked() 8796 ->Equals(context.local(), foo) 8797 .FromJust()); 8798 v8::Local<Value> type_error = v8::Exception::TypeError(foo); 8799 CHECK(type_error->IsObject()); 8800 CHECK(type_error.As<v8::Object>() 8801 ->Get(context.local(), message) 8802 .ToLocalChecked() 8803 ->Equals(context.local(), foo) 8804 .FromJust()); 8805 v8::Local<Value> error = v8::Exception::Error(foo); 8806 CHECK(error->IsObject()); 8807 CHECK(error.As<v8::Object>() 8808 ->Get(context.local(), message) 8809 .ToLocalChecked() 8810 ->Equals(context.local(), foo) 8811 .FromJust()); 8812 } 8813 8814 8815 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) { 8816 ApiTestFuzzer::Fuzz(); 8817 v8::Local<String> foo = v8_str("foo"); 8818 v8::Local<String> message = v8_str("message"); 8819 v8::Local<Value> error = v8::Exception::Error(foo); 8820 CHECK(error->IsObject()); 8821 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8822 CHECK(error.As<v8::Object>() 8823 ->Get(context, message) 8824 .ToLocalChecked() 8825 ->Equals(context, foo) 8826 .FromJust()); 8827 info.GetIsolate()->ThrowException(error); 8828 info.GetReturnValue().SetUndefined(); 8829 } 8830 8831 8832 THREADED_TEST(ExceptionCreateMessage) { 8833 LocalContext context; 8834 v8::HandleScope scope(context->GetIsolate()); 8835 v8::Local<String> foo_str = v8_str("foo"); 8836 v8::Local<String> message_str = v8_str("message"); 8837 8838 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true); 8839 8840 Local<v8::FunctionTemplate> fun = 8841 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception); 8842 v8::Local<v8::Object> global = context->Global(); 8843 CHECK(global->Set(context.local(), v8_str("throwV8Exception"), 8844 fun->GetFunction(context.local()).ToLocalChecked()) 8845 .FromJust()); 8846 8847 TryCatch try_catch(context->GetIsolate()); 8848 CompileRun( 8849 "function f1() {\n" 8850 " throwV8Exception();\n" 8851 "};\n" 8852 "f1();"); 8853 CHECK(try_catch.HasCaught()); 8854 8855 v8::Local<v8::Value> error = try_catch.Exception(); 8856 CHECK(error->IsObject()); 8857 CHECK(error.As<v8::Object>() 8858 ->Get(context.local(), message_str) 8859 .ToLocalChecked() 8860 ->Equals(context.local(), foo_str) 8861 .FromJust()); 8862 8863 v8::Local<v8::Message> message = 8864 v8::Exception::CreateMessage(context->GetIsolate(), error); 8865 CHECK(!message.IsEmpty()); 8866 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 8867 CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust()); 8868 8869 v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace(); 8870 CHECK(!stackTrace.IsEmpty()); 8871 CHECK_EQ(2, stackTrace->GetFrameCount()); 8872 8873 stackTrace = v8::Exception::GetStackTrace(error); 8874 CHECK(!stackTrace.IsEmpty()); 8875 CHECK_EQ(2, stackTrace->GetFrameCount()); 8876 8877 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false); 8878 8879 // Now check message location when SetCaptureStackTraceForUncaughtExceptions 8880 // is false. 8881 try_catch.Reset(); 8882 8883 CompileRun( 8884 "function f2() {\n" 8885 " return throwV8Exception();\n" 8886 "};\n" 8887 "f2();"); 8888 CHECK(try_catch.HasCaught()); 8889 8890 error = try_catch.Exception(); 8891 CHECK(error->IsObject()); 8892 CHECK(error.As<v8::Object>() 8893 ->Get(context.local(), message_str) 8894 .ToLocalChecked() 8895 ->Equals(context.local(), foo_str) 8896 .FromJust()); 8897 8898 message = v8::Exception::CreateMessage(context->GetIsolate(), error); 8899 CHECK(!message.IsEmpty()); 8900 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 8901 CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust()); 8902 8903 // Should be empty stack trace. 8904 stackTrace = message->GetStackTrace(); 8905 CHECK(stackTrace.IsEmpty()); 8906 CHECK(v8::Exception::GetStackTrace(error).IsEmpty()); 8907 } 8908 8909 8910 THREADED_TEST(ExceptionCreateMessageLength) { 8911 LocalContext context; 8912 v8::HandleScope scope(context->GetIsolate()); 8913 8914 // Test that the message is not truncated. 8915 TryCatch try_catch(context->GetIsolate()); 8916 CompileRun( 8917 "var message = 'm';" 8918 "while (message.length < 1000) message += message;" 8919 "throw message;"); 8920 CHECK(try_catch.HasCaught()); 8921 8922 CHECK_LT(1000, try_catch.Message()->Get()->Length()); 8923 } 8924 8925 8926 static void YGetter(Local<String> name, 8927 const v8::PropertyCallbackInfo<v8::Value>& info) { 8928 ApiTestFuzzer::Fuzz(); 8929 info.GetReturnValue().Set(v8_num(10)); 8930 } 8931 8932 8933 static void YSetter(Local<String> name, 8934 Local<Value> value, 8935 const v8::PropertyCallbackInfo<void>& info) { 8936 Local<Object> this_obj = Local<Object>::Cast(info.This()); 8937 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 8938 if (this_obj->Has(context, name).FromJust()) 8939 this_obj->Delete(context, name).FromJust(); 8940 CHECK(this_obj->Set(context, name, value).FromJust()); 8941 } 8942 8943 8944 THREADED_TEST(DeleteAccessor) { 8945 v8::Isolate* isolate = CcTest::isolate(); 8946 v8::HandleScope scope(isolate); 8947 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8948 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 8949 LocalContext context; 8950 v8::Local<v8::Object> holder = 8951 obj->NewInstance(context.local()).ToLocalChecked(); 8952 CHECK(context->Global() 8953 ->Set(context.local(), v8_str("holder"), holder) 8954 .FromJust()); 8955 v8::Local<Value> result = 8956 CompileRun("holder.y = 11; holder.y = 12; holder.y"); 8957 CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust()); 8958 } 8959 8960 8961 static int trouble_nesting = 0; 8962 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 8963 ApiTestFuzzer::Fuzz(); 8964 trouble_nesting++; 8965 8966 // Call a JS function that throws an uncaught exception. 8967 Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 8968 Local<v8::Object> arg_this = context->Global(); 8969 Local<Value> trouble_callee = 8970 (trouble_nesting == 3) 8971 ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked() 8972 : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked(); 8973 CHECK(trouble_callee->IsFunction()); 8974 args.GetReturnValue().Set(Function::Cast(*trouble_callee) 8975 ->Call(context, arg_this, 0, NULL) 8976 .FromMaybe(v8::Local<v8::Value>())); 8977 } 8978 8979 8980 static int report_count = 0; 8981 static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>, 8982 v8::Local<Value>) { 8983 report_count++; 8984 } 8985 8986 8987 // Counts uncaught exceptions, but other tests running in parallel 8988 // also have uncaught exceptions. 8989 TEST(ApiUncaughtException) { 8990 report_count = 0; 8991 LocalContext env; 8992 v8::Isolate* isolate = env->GetIsolate(); 8993 v8::HandleScope scope(isolate); 8994 isolate->AddMessageListener(ApiUncaughtExceptionTestListener); 8995 8996 Local<v8::FunctionTemplate> fun = 8997 v8::FunctionTemplate::New(isolate, TroubleCallback); 8998 v8::Local<v8::Object> global = env->Global(); 8999 CHECK(global->Set(env.local(), v8_str("trouble"), 9000 fun->GetFunction(env.local()).ToLocalChecked()) 9001 .FromJust()); 9002 9003 CompileRun( 9004 "function trouble_callee() {" 9005 " var x = null;" 9006 " return x.foo;" 9007 "};" 9008 "function trouble_caller() {" 9009 " trouble();" 9010 "};"); 9011 Local<Value> trouble = 9012 global->Get(env.local(), v8_str("trouble")).ToLocalChecked(); 9013 CHECK(trouble->IsFunction()); 9014 Local<Value> trouble_callee = 9015 global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked(); 9016 CHECK(trouble_callee->IsFunction()); 9017 Local<Value> trouble_caller = 9018 global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked(); 9019 CHECK(trouble_caller->IsFunction()); 9020 Function::Cast(*trouble_caller) 9021 ->Call(env.local(), global, 0, NULL) 9022 .FromMaybe(v8::Local<v8::Value>()); 9023 CHECK_EQ(1, report_count); 9024 isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener); 9025 } 9026 9027 9028 static const char* script_resource_name = "ExceptionInNativeScript.js"; 9029 static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message, 9030 v8::Local<Value>) { 9031 v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName(); 9032 CHECK(!name_val.IsEmpty() && name_val->IsString()); 9033 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 9034 CHECK_EQ(0, strcmp(script_resource_name, *name)); 9035 v8::Local<v8::Context> context = 9036 v8::Isolate::GetCurrent()->GetCurrentContext(); 9037 CHECK_EQ(3, message->GetLineNumber(context).FromJust()); 9038 v8::String::Utf8Value source_line( 9039 message->GetSourceLine(context).ToLocalChecked()); 9040 CHECK_EQ(0, strcmp(" new o.foo();", *source_line)); 9041 } 9042 9043 9044 TEST(ExceptionInNativeScript) { 9045 LocalContext env; 9046 v8::Isolate* isolate = env->GetIsolate(); 9047 v8::HandleScope scope(isolate); 9048 isolate->AddMessageListener(ExceptionInNativeScriptTestListener); 9049 9050 Local<v8::FunctionTemplate> fun = 9051 v8::FunctionTemplate::New(isolate, TroubleCallback); 9052 v8::Local<v8::Object> global = env->Global(); 9053 CHECK(global->Set(env.local(), v8_str("trouble"), 9054 fun->GetFunction(env.local()).ToLocalChecked()) 9055 .FromJust()); 9056 9057 CompileRunWithOrigin( 9058 "function trouble() {\n" 9059 " var o = {};\n" 9060 " new o.foo();\n" 9061 "};", 9062 script_resource_name); 9063 Local<Value> trouble = 9064 global->Get(env.local(), v8_str("trouble")).ToLocalChecked(); 9065 CHECK(trouble->IsFunction()); 9066 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty()); 9067 isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener); 9068 } 9069 9070 9071 TEST(CompilationErrorUsingTryCatchHandler) { 9072 LocalContext env; 9073 v8::HandleScope scope(env->GetIsolate()); 9074 v8::TryCatch try_catch(env->GetIsolate()); 9075 v8_compile("This doesn't &*&@#$&*^ compile."); 9076 CHECK(*try_catch.Exception()); 9077 CHECK(try_catch.HasCaught()); 9078 } 9079 9080 9081 TEST(TryCatchFinallyUsingTryCatchHandler) { 9082 LocalContext env; 9083 v8::HandleScope scope(env->GetIsolate()); 9084 v8::TryCatch try_catch(env->GetIsolate()); 9085 CompileRun("try { throw ''; } catch (e) {}"); 9086 CHECK(!try_catch.HasCaught()); 9087 CompileRun("try { throw ''; } finally {}"); 9088 CHECK(try_catch.HasCaught()); 9089 try_catch.Reset(); 9090 CompileRun( 9091 "(function() {" 9092 "try { throw ''; } finally { return; }" 9093 "})()"); 9094 CHECK(!try_catch.HasCaught()); 9095 CompileRun( 9096 "(function()" 9097 " { try { throw ''; } finally { throw 0; }" 9098 "})()"); 9099 CHECK(try_catch.HasCaught()); 9100 } 9101 9102 9103 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) { 9104 v8::HandleScope scope(args.GetIsolate()); 9105 CompileRun(args[0] 9106 ->ToString(args.GetIsolate()->GetCurrentContext()) 9107 .ToLocalChecked()); 9108 } 9109 9110 9111 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { 9112 v8::Isolate* isolate = CcTest::isolate(); 9113 v8::HandleScope scope(isolate); 9114 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 9115 templ->Set(v8_str("CEvaluate"), 9116 v8::FunctionTemplate::New(isolate, CEvaluate)); 9117 LocalContext context(0, templ); 9118 v8::TryCatch try_catch(isolate); 9119 CompileRun("try {" 9120 " CEvaluate('throw 1;');" 9121 "} finally {" 9122 "}"); 9123 CHECK(try_catch.HasCaught()); 9124 CHECK(!try_catch.Message().IsEmpty()); 9125 String::Utf8Value exception_value(try_catch.Exception()); 9126 CHECK_EQ(0, strcmp(*exception_value, "1")); 9127 try_catch.Reset(); 9128 CompileRun("try {" 9129 " CEvaluate('throw 1;');" 9130 "} finally {" 9131 " throw 2;" 9132 "}"); 9133 CHECK(try_catch.HasCaught()); 9134 CHECK(!try_catch.Message().IsEmpty()); 9135 String::Utf8Value finally_exception_value(try_catch.Exception()); 9136 CHECK_EQ(0, strcmp(*finally_exception_value, "2")); 9137 } 9138 9139 9140 // For use within the TestSecurityHandler() test. 9141 static bool g_security_callback_result = false; 9142 static bool SecurityTestCallback(Local<v8::Context> accessing_context, 9143 Local<v8::Object> accessed_object, 9144 Local<v8::Value> data) { 9145 printf("a\n"); 9146 CHECK(!data.IsEmpty() && data->IsInt32()); 9147 CHECK_EQ(42, data->Int32Value(accessing_context).FromJust()); 9148 return g_security_callback_result; 9149 } 9150 9151 9152 // SecurityHandler can't be run twice 9153 TEST(SecurityHandler) { 9154 v8::Isolate* isolate = CcTest::isolate(); 9155 v8::HandleScope scope0(isolate); 9156 v8::Local<v8::ObjectTemplate> global_template = 9157 v8::ObjectTemplate::New(isolate); 9158 global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42)); 9159 // Create an environment 9160 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9161 context0->Enter(); 9162 9163 v8::Local<v8::Object> global0 = context0->Global(); 9164 v8::Local<Script> script0 = v8_compile("foo = 111"); 9165 script0->Run(context0).ToLocalChecked(); 9166 CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust()); 9167 v8::Local<Value> foo0 = 9168 global0->Get(context0, v8_str("foo")).ToLocalChecked(); 9169 CHECK_EQ(111, foo0->Int32Value(context0).FromJust()); 9170 v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked(); 9171 CHECK_EQ(999, z0->Int32Value(context0).FromJust()); 9172 9173 // Create another environment, should fail security checks. 9174 v8::HandleScope scope1(isolate); 9175 9176 v8::Local<Context> context1 = Context::New(isolate, NULL, global_template); 9177 context1->Enter(); 9178 9179 v8::Local<v8::Object> global1 = context1->Global(); 9180 global1->Set(context1, v8_str("othercontext"), global0).FromJust(); 9181 // This set will fail the security check. 9182 v8::Local<Script> script1 = 9183 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 9184 CHECK(script1->Run(context1).IsEmpty()); 9185 g_security_callback_result = true; 9186 // This read will pass the security check. 9187 v8::Local<Value> foo1 = 9188 global0->Get(context1, v8_str("foo")).ToLocalChecked(); 9189 CHECK_EQ(111, foo1->Int32Value(context0).FromJust()); 9190 // This read will pass the security check. 9191 v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked(); 9192 CHECK_EQ(999, z1->Int32Value(context1).FromJust()); 9193 9194 // Create another environment, should pass security checks. 9195 { 9196 v8::HandleScope scope2(isolate); 9197 LocalContext context2; 9198 v8::Local<v8::Object> global2 = context2->Global(); 9199 CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0) 9200 .FromJust()); 9201 v8::Local<Script> script2 = 9202 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 9203 script2->Run(context2.local()).ToLocalChecked(); 9204 v8::Local<Value> foo2 = 9205 global0->Get(context2.local(), v8_str("foo")).ToLocalChecked(); 9206 CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust()); 9207 v8::Local<Value> z2 = 9208 global0->Get(context2.local(), v8_str("0")).ToLocalChecked(); 9209 CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust()); 9210 } 9211 9212 context1->Exit(); 9213 context0->Exit(); 9214 } 9215 9216 9217 THREADED_TEST(SecurityChecks) { 9218 LocalContext env1; 9219 v8::HandleScope handle_scope(env1->GetIsolate()); 9220 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9221 9222 Local<Value> foo = v8_str("foo"); 9223 Local<Value> bar = v8_str("bar"); 9224 9225 // Set to the same domain. 9226 env1->SetSecurityToken(foo); 9227 9228 // Create a function in env1. 9229 CompileRun("spy=function(){return spy;}"); 9230 Local<Value> spy = 9231 env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked(); 9232 CHECK(spy->IsFunction()); 9233 9234 // Create another function accessing global objects. 9235 CompileRun("spy2=function(){return new this.Array();}"); 9236 Local<Value> spy2 = 9237 env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked(); 9238 CHECK(spy2->IsFunction()); 9239 9240 // Switch to env2 in the same domain and invoke spy on env2. 9241 { 9242 env2->SetSecurityToken(foo); 9243 // Enter env2 9244 Context::Scope scope_env2(env2); 9245 Local<Value> result = Function::Cast(*spy) 9246 ->Call(env2, env2->Global(), 0, NULL) 9247 .ToLocalChecked(); 9248 CHECK(result->IsFunction()); 9249 } 9250 9251 { 9252 env2->SetSecurityToken(bar); 9253 Context::Scope scope_env2(env2); 9254 9255 // Call cross_domain_call, it should throw an exception 9256 v8::TryCatch try_catch(env1->GetIsolate()); 9257 CHECK(Function::Cast(*spy2)->Call(env2, env2->Global(), 0, NULL).IsEmpty()); 9258 CHECK(try_catch.HasCaught()); 9259 } 9260 } 9261 9262 9263 // Regression test case for issue 1183439. 9264 THREADED_TEST(SecurityChecksForPrototypeChain) { 9265 LocalContext current; 9266 v8::HandleScope scope(current->GetIsolate()); 9267 v8::Local<Context> other = Context::New(current->GetIsolate()); 9268 9269 // Change context to be able to get to the Object function in the 9270 // other context without hitting the security checks. 9271 v8::Local<Value> other_object; 9272 { Context::Scope scope(other); 9273 other_object = 9274 other->Global()->Get(other, v8_str("Object")).ToLocalChecked(); 9275 CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust()); 9276 } 9277 9278 CHECK(current->Global() 9279 ->Set(current.local(), v8_str("other"), other->Global()) 9280 .FromJust()); 9281 CHECK(v8_compile("other") 9282 ->Run(current.local()) 9283 .ToLocalChecked() 9284 ->Equals(current.local(), other->Global()) 9285 .FromJust()); 9286 9287 // Make sure the security check fails here and we get an undefined 9288 // result instead of getting the Object function. Repeat in a loop 9289 // to make sure to exercise the IC code. 9290 v8::Local<Script> access_other0 = v8_compile("other.Object"); 9291 v8::Local<Script> access_other1 = v8_compile("other[42]"); 9292 for (int i = 0; i < 5; i++) { 9293 CHECK(access_other0->Run(current.local()).IsEmpty()); 9294 CHECK(access_other1->Run(current.local()).IsEmpty()); 9295 } 9296 9297 // Create an object that has 'other' in its prototype chain and make 9298 // sure we cannot access the Object function indirectly through 9299 // that. Repeat in a loop to make sure to exercise the IC code. 9300 v8_compile( 9301 "function F() { };" 9302 "F.prototype = other;" 9303 "var f = new F();") 9304 ->Run(current.local()) 9305 .ToLocalChecked(); 9306 v8::Local<Script> access_f0 = v8_compile("f.Object"); 9307 v8::Local<Script> access_f1 = v8_compile("f[42]"); 9308 for (int j = 0; j < 5; j++) { 9309 CHECK(access_f0->Run(current.local()).IsEmpty()); 9310 CHECK(access_f1->Run(current.local()).IsEmpty()); 9311 } 9312 9313 // Now it gets hairy: Set the prototype for the other global object 9314 // to be the current global object. The prototype chain for 'f' now 9315 // goes through 'other' but ends up in the current global object. 9316 { Context::Scope scope(other); 9317 CHECK(other->Global() 9318 ->Set(other, v8_str("__proto__"), current->Global()) 9319 .FromJust()); 9320 } 9321 // Set a named and an index property on the current global 9322 // object. To force the lookup to go through the other global object, 9323 // the properties must not exist in the other global object. 9324 CHECK(current->Global() 9325 ->Set(current.local(), v8_str("foo"), v8_num(100)) 9326 .FromJust()); 9327 CHECK(current->Global() 9328 ->Set(current.local(), v8_num(99), v8_num(101)) 9329 .FromJust()); 9330 // Try to read the properties from f and make sure that the access 9331 // gets stopped by the security checks on the other global object. 9332 Local<Script> access_f2 = v8_compile("f.foo"); 9333 Local<Script> access_f3 = v8_compile("f[99]"); 9334 for (int k = 0; k < 5; k++) { 9335 CHECK(access_f2->Run(current.local()).IsEmpty()); 9336 CHECK(access_f3->Run(current.local()).IsEmpty()); 9337 } 9338 } 9339 9340 9341 static bool security_check_with_gc_called; 9342 9343 static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context, 9344 Local<v8::Object> accessed_object, 9345 Local<v8::Value> data) { 9346 CcTest::heap()->CollectAllGarbage(); 9347 security_check_with_gc_called = true; 9348 return true; 9349 } 9350 9351 9352 TEST(SecurityTestGCAllowed) { 9353 v8::Isolate* isolate = CcTest::isolate(); 9354 v8::HandleScope handle_scope(isolate); 9355 v8::Local<v8::ObjectTemplate> object_template = 9356 v8::ObjectTemplate::New(isolate); 9357 object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC); 9358 9359 v8::Local<Context> context = Context::New(isolate); 9360 v8::Context::Scope context_scope(context); 9361 9362 CHECK(context->Global() 9363 ->Set(context, v8_str("obj"), 9364 object_template->NewInstance(context).ToLocalChecked()) 9365 .FromJust()); 9366 9367 security_check_with_gc_called = false; 9368 CompileRun("obj[0] = new String(1002);"); 9369 CHECK(security_check_with_gc_called); 9370 9371 security_check_with_gc_called = false; 9372 CHECK(CompileRun("obj[0]") 9373 ->ToString(context) 9374 .ToLocalChecked() 9375 ->Equals(context, v8_str("1002")) 9376 .FromJust()); 9377 CHECK(security_check_with_gc_called); 9378 } 9379 9380 9381 THREADED_TEST(CrossDomainDelete) { 9382 LocalContext env1; 9383 v8::HandleScope handle_scope(env1->GetIsolate()); 9384 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9385 9386 Local<Value> foo = v8_str("foo"); 9387 Local<Value> bar = v8_str("bar"); 9388 9389 // Set to the same domain. 9390 env1->SetSecurityToken(foo); 9391 env2->SetSecurityToken(foo); 9392 9393 CHECK( 9394 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9395 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9396 9397 // Change env2 to a different domain and delete env1.prop. 9398 env2->SetSecurityToken(bar); 9399 { 9400 Context::Scope scope_env2(env2); 9401 Local<Value> result = 9402 CompileRun("delete env1.prop"); 9403 CHECK(result.IsEmpty()); 9404 } 9405 9406 // Check that env1.prop still exists. 9407 Local<Value> v = 9408 env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked(); 9409 CHECK(v->IsNumber()); 9410 CHECK_EQ(3, v->Int32Value(env1.local()).FromJust()); 9411 } 9412 9413 9414 THREADED_TEST(CrossDomainPropertyIsEnumerable) { 9415 LocalContext env1; 9416 v8::HandleScope handle_scope(env1->GetIsolate()); 9417 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9418 9419 Local<Value> foo = v8_str("foo"); 9420 Local<Value> bar = v8_str("bar"); 9421 9422 // Set to the same domain. 9423 env1->SetSecurityToken(foo); 9424 env2->SetSecurityToken(foo); 9425 9426 CHECK( 9427 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9428 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9429 9430 // env1.prop is enumerable in env2. 9431 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 9432 { 9433 Context::Scope scope_env2(env2); 9434 Local<Value> result = CompileRun(test); 9435 CHECK(result->IsTrue()); 9436 } 9437 9438 // Change env2 to a different domain and test again. 9439 env2->SetSecurityToken(bar); 9440 { 9441 Context::Scope scope_env2(env2); 9442 Local<Value> result = CompileRun(test); 9443 CHECK(result.IsEmpty()); 9444 } 9445 } 9446 9447 9448 THREADED_TEST(CrossDomainFor) { 9449 LocalContext env1; 9450 v8::HandleScope handle_scope(env1->GetIsolate()); 9451 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9452 9453 Local<Value> foo = v8_str("foo"); 9454 Local<Value> bar = v8_str("bar"); 9455 9456 // Set to the same domain. 9457 env1->SetSecurityToken(foo); 9458 env2->SetSecurityToken(foo); 9459 9460 CHECK( 9461 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9462 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9463 9464 // Change env2 to a different domain and set env1's global object 9465 // as the __proto__ of an object in env2 and enumerate properties 9466 // in for-in. It shouldn't enumerate properties on env1's global 9467 // object. It shouldn't throw either, just silently ignore them. 9468 env2->SetSecurityToken(bar); 9469 { 9470 Context::Scope scope_env2(env2); 9471 Local<Value> result = CompileRun( 9472 "(function() {" 9473 " try {" 9474 " for (var p in env1) {" 9475 " if (p == 'prop') return false;" 9476 " }" 9477 " return true;" 9478 " } catch (e) {" 9479 " return false;" 9480 " }" 9481 "})()"); 9482 CHECK(result->IsTrue()); 9483 } 9484 } 9485 9486 9487 THREADED_TEST(CrossDomainForInOnPrototype) { 9488 LocalContext env1; 9489 v8::HandleScope handle_scope(env1->GetIsolate()); 9490 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9491 9492 Local<Value> foo = v8_str("foo"); 9493 Local<Value> bar = v8_str("bar"); 9494 9495 // Set to the same domain. 9496 env1->SetSecurityToken(foo); 9497 env2->SetSecurityToken(foo); 9498 9499 CHECK( 9500 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust()); 9501 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9502 9503 // Change env2 to a different domain and set env1's global object 9504 // as the __proto__ of an object in env2 and enumerate properties 9505 // in for-in. It shouldn't enumerate properties on env1's global 9506 // object. 9507 env2->SetSecurityToken(bar); 9508 { 9509 Context::Scope scope_env2(env2); 9510 Local<Value> result = CompileRun( 9511 "(function() {" 9512 " var obj = { '__proto__': env1 };" 9513 " try {" 9514 " for (var p in obj) {" 9515 " if (p == 'prop') return false;" 9516 " }" 9517 " return true;" 9518 " } catch (e) {" 9519 " return false;" 9520 " }" 9521 "})()"); 9522 CHECK(result->IsTrue()); 9523 } 9524 } 9525 9526 9527 TEST(ContextDetachGlobal) { 9528 LocalContext env1; 9529 v8::HandleScope handle_scope(env1->GetIsolate()); 9530 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9531 9532 9533 Local<Value> foo = v8_str("foo"); 9534 9535 // Set to the same domain. 9536 env1->SetSecurityToken(foo); 9537 env2->SetSecurityToken(foo); 9538 9539 // Enter env2 9540 env2->Enter(); 9541 9542 // Create a function in env2 and add a reference to it in env1. 9543 Local<v8::Object> global2 = env2->Global(); 9544 CHECK(global2->Set(env2, v8_str("prop"), 9545 v8::Integer::New(env2->GetIsolate(), 1)) 9546 .FromJust()); 9547 CompileRun("function getProp() {return prop;}"); 9548 9549 CHECK(env1->Global() 9550 ->Set(env1.local(), v8_str("getProp"), 9551 global2->Get(env2, v8_str("getProp")).ToLocalChecked()) 9552 .FromJust()); 9553 9554 // Detach env2's global, and reuse the global object of env2 9555 env2->Exit(); 9556 env2->DetachGlobal(); 9557 9558 v8::Local<Context> env3 = Context::New( 9559 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2); 9560 env3->SetSecurityToken(v8_str("bar")); 9561 9562 env3->Enter(); 9563 Local<v8::Object> global3 = env3->Global(); 9564 CHECK(global2->Equals(env3, global3).FromJust()); 9565 CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined()); 9566 CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined()); 9567 CHECK(global3->Set(env3, v8_str("prop"), 9568 v8::Integer::New(env3->GetIsolate(), -1)) 9569 .FromJust()); 9570 CHECK(global3->Set(env3, v8_str("prop2"), 9571 v8::Integer::New(env3->GetIsolate(), 2)) 9572 .FromJust()); 9573 env3->Exit(); 9574 9575 // Call getProp in env1, and it should return the value 1 9576 { 9577 Local<v8::Object> global1 = env1->Global(); 9578 Local<Value> get_prop = 9579 global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked(); 9580 CHECK(get_prop->IsFunction()); 9581 v8::TryCatch try_catch(env1->GetIsolate()); 9582 Local<Value> r = Function::Cast(*get_prop) 9583 ->Call(env1.local(), global1, 0, NULL) 9584 .ToLocalChecked(); 9585 CHECK(!try_catch.HasCaught()); 9586 CHECK_EQ(1, r->Int32Value(env1.local()).FromJust()); 9587 } 9588 9589 // Check that env3 is not accessible from env1 9590 { 9591 v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2")); 9592 CHECK(r.IsEmpty()); 9593 } 9594 } 9595 9596 9597 TEST(DetachGlobal) { 9598 LocalContext env1; 9599 v8::HandleScope scope(env1->GetIsolate()); 9600 9601 // Create second environment. 9602 v8::Local<Context> env2 = Context::New(env1->GetIsolate()); 9603 9604 Local<Value> foo = v8_str("foo"); 9605 9606 // Set same security token for env1 and env2. 9607 env1->SetSecurityToken(foo); 9608 env2->SetSecurityToken(foo); 9609 9610 // Create a property on the global object in env2. 9611 { 9612 v8::Context::Scope scope(env2); 9613 CHECK(env2->Global() 9614 ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42)) 9615 .FromJust()); 9616 } 9617 9618 // Create a reference to env2 global from env1 global. 9619 CHECK(env1->Global() 9620 ->Set(env1.local(), v8_str("other"), env2->Global()) 9621 .FromJust()); 9622 9623 // Check that we have access to other.p in env2 from env1. 9624 Local<Value> result = CompileRun("other.p"); 9625 CHECK(result->IsInt32()); 9626 CHECK_EQ(42, result->Int32Value(env1.local()).FromJust()); 9627 9628 // Hold on to global from env2 and detach global from env2. 9629 Local<v8::Object> global2 = env2->Global(); 9630 env2->DetachGlobal(); 9631 9632 // Check that the global has been detached. No other.p property can 9633 // be found. 9634 result = CompileRun("other.p"); 9635 CHECK(result.IsEmpty()); 9636 9637 // Reuse global2 for env3. 9638 v8::Local<Context> env3 = Context::New( 9639 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2); 9640 CHECK(global2->Equals(env1.local(), env3->Global()).FromJust()); 9641 9642 // Start by using the same security token for env3 as for env1 and env2. 9643 env3->SetSecurityToken(foo); 9644 9645 // Create a property on the global object in env3. 9646 { 9647 v8::Context::Scope scope(env3); 9648 CHECK(env3->Global() 9649 ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24)) 9650 .FromJust()); 9651 } 9652 9653 // Check that other.p is now the property in env3 and that we have access. 9654 result = CompileRun("other.p"); 9655 CHECK(result->IsInt32()); 9656 CHECK_EQ(24, result->Int32Value(env3).FromJust()); 9657 9658 // Change security token for env3 to something different from env1 and env2. 9659 env3->SetSecurityToken(v8_str("bar")); 9660 9661 // Check that we do not have access to other.p in env1. |other| is now 9662 // the global object for env3 which has a different security token, 9663 // so access should be blocked. 9664 result = CompileRun("other.p"); 9665 CHECK(result.IsEmpty()); 9666 } 9667 9668 9669 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) { 9670 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); 9671 info.GetReturnValue().Set( 9672 context->Global()->Get(context, v8_str("x")).ToLocalChecked()); 9673 } 9674 9675 9676 TEST(DetachedAccesses) { 9677 LocalContext env1; 9678 v8::HandleScope scope(env1->GetIsolate()); 9679 9680 // Create second environment. 9681 Local<ObjectTemplate> inner_global_template = 9682 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate(); 9683 inner_global_template ->SetAccessorProperty( 9684 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX)); 9685 v8::Local<Context> env2 = 9686 Context::New(env1->GetIsolate(), NULL, inner_global_template); 9687 9688 Local<Value> foo = v8_str("foo"); 9689 9690 // Set same security token for env1 and env2. 9691 env1->SetSecurityToken(foo); 9692 env2->SetSecurityToken(foo); 9693 9694 CHECK(env1->Global() 9695 ->Set(env1.local(), v8_str("x"), v8_str("env1_x")) 9696 .FromJust()); 9697 9698 { 9699 v8::Context::Scope scope(env2); 9700 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust()); 9701 CompileRun( 9702 "function bound_x() { return x; }" 9703 "function get_x() { return this.x; }" 9704 "function get_x_w() { return (function() {return this.x;})(); }"); 9705 CHECK(env1->Global() 9706 ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x")) 9707 .FromJust()); 9708 CHECK(env1->Global() 9709 ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x")) 9710 .FromJust()); 9711 CHECK(env1->Global() 9712 ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w")) 9713 .FromJust()); 9714 env1->Global() 9715 ->Set(env1.local(), v8_str("this_x"), 9716 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get")) 9717 .FromJust(); 9718 } 9719 9720 Local<Object> env2_global = env2->Global(); 9721 env2->DetachGlobal(); 9722 9723 Local<Value> result; 9724 result = CompileRun("bound_x()"); 9725 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust()); 9726 result = CompileRun("get_x()"); 9727 CHECK(result.IsEmpty()); 9728 result = CompileRun("get_x_w()"); 9729 CHECK(result.IsEmpty()); 9730 result = CompileRun("this_x()"); 9731 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust()); 9732 9733 // Reattach env2's proxy 9734 env2 = Context::New(env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), 9735 env2_global); 9736 env2->SetSecurityToken(foo); 9737 { 9738 v8::Context::Scope scope(env2); 9739 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust()); 9740 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust()); 9741 result = CompileRun( 9742 "results = [];" 9743 "for (var i = 0; i < 4; i++ ) {" 9744 " results.push(env1.bound_x());" 9745 " results.push(env1.get_x());" 9746 " results.push(env1.get_x_w());" 9747 " results.push(env1.this_x());" 9748 "}" 9749 "results"); 9750 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9751 CHECK_EQ(16u, results->Length()); 9752 for (int i = 0; i < 16; i += 4) { 9753 CHECK(v8_str("env2_x") 9754 ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked()) 9755 .FromJust()); 9756 CHECK(v8_str("env1_x") 9757 ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked()) 9758 .FromJust()); 9759 CHECK(v8_str("env3_x") 9760 ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked()) 9761 .FromJust()); 9762 CHECK(v8_str("env2_x") 9763 ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked()) 9764 .FromJust()); 9765 } 9766 } 9767 9768 result = CompileRun( 9769 "results = [];" 9770 "for (var i = 0; i < 4; i++ ) {" 9771 " results.push(bound_x());" 9772 " results.push(get_x());" 9773 " results.push(get_x_w());" 9774 " results.push(this_x());" 9775 "}" 9776 "results"); 9777 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9778 CHECK_EQ(16u, results->Length()); 9779 for (int i = 0; i < 16; i += 4) { 9780 CHECK(v8_str("env2_x") 9781 ->Equals(env1.local(), 9782 results->Get(env1.local(), i + 0).ToLocalChecked()) 9783 .FromJust()); 9784 CHECK(v8_str("env3_x") 9785 ->Equals(env1.local(), 9786 results->Get(env1.local(), i + 1).ToLocalChecked()) 9787 .FromJust()); 9788 CHECK(v8_str("env3_x") 9789 ->Equals(env1.local(), 9790 results->Get(env1.local(), i + 2).ToLocalChecked()) 9791 .FromJust()); 9792 CHECK(v8_str("env2_x") 9793 ->Equals(env1.local(), 9794 results->Get(env1.local(), i + 3).ToLocalChecked()) 9795 .FromJust()); 9796 } 9797 9798 result = CompileRun( 9799 "results = [];" 9800 "for (var i = 0; i < 4; i++ ) {" 9801 " results.push(this.bound_x());" 9802 " results.push(this.get_x());" 9803 " results.push(this.get_x_w());" 9804 " results.push(this.this_x());" 9805 "}" 9806 "results"); 9807 results = Local<v8::Array>::Cast(result); 9808 CHECK_EQ(16u, results->Length()); 9809 for (int i = 0; i < 16; i += 4) { 9810 CHECK(v8_str("env2_x") 9811 ->Equals(env1.local(), 9812 results->Get(env1.local(), i + 0).ToLocalChecked()) 9813 .FromJust()); 9814 CHECK(v8_str("env1_x") 9815 ->Equals(env1.local(), 9816 results->Get(env1.local(), i + 1).ToLocalChecked()) 9817 .FromJust()); 9818 CHECK(v8_str("env3_x") 9819 ->Equals(env1.local(), 9820 results->Get(env1.local(), i + 2).ToLocalChecked()) 9821 .FromJust()); 9822 CHECK(v8_str("env2_x") 9823 ->Equals(env1.local(), 9824 results->Get(env1.local(), i + 3).ToLocalChecked()) 9825 .FromJust()); 9826 } 9827 } 9828 9829 9830 static bool allowed_access = false; 9831 static bool AccessBlocker(Local<v8::Context> accessing_context, 9832 Local<v8::Object> accessed_object, 9833 Local<v8::Value> data) { 9834 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 9835 return context->Global()->Equals(context, accessed_object).FromJust() || 9836 allowed_access; 9837 } 9838 9839 9840 static int g_echo_value = -1; 9841 9842 9843 static void EchoGetter( 9844 Local<String> name, 9845 const v8::PropertyCallbackInfo<v8::Value>& info) { 9846 info.GetReturnValue().Set(v8_num(g_echo_value)); 9847 } 9848 9849 9850 static void EchoSetter(Local<String> name, Local<Value> value, 9851 const v8::PropertyCallbackInfo<void>& args) { 9852 if (value->IsNumber()) 9853 g_echo_value = 9854 value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust(); 9855 } 9856 9857 9858 static void UnreachableGetter( 9859 Local<String> name, 9860 const v8::PropertyCallbackInfo<v8::Value>& info) { 9861 CHECK(false); // This function should not be called.. 9862 } 9863 9864 9865 static void UnreachableSetter(Local<String>, 9866 Local<Value>, 9867 const v8::PropertyCallbackInfo<void>&) { 9868 CHECK(false); // This function should nto be called. 9869 } 9870 9871 9872 static void UnreachableFunction( 9873 const v8::FunctionCallbackInfo<v8::Value>& info) { 9874 CHECK(false); // This function should not be called.. 9875 } 9876 9877 9878 TEST(AccessControl) { 9879 v8::Isolate* isolate = CcTest::isolate(); 9880 v8::HandleScope handle_scope(isolate); 9881 v8::Local<v8::ObjectTemplate> global_template = 9882 v8::ObjectTemplate::New(isolate); 9883 9884 global_template->SetAccessCheckCallback(AccessBlocker); 9885 9886 // Add an accessor accessible by cross-domain JS code. 9887 global_template->SetAccessor( 9888 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 9889 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9890 9891 9892 // Add an accessor that is not accessible by cross-domain JS code. 9893 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter, 9894 UnreachableSetter, v8::Local<Value>(), 9895 v8::DEFAULT); 9896 9897 global_template->SetAccessorProperty( 9898 v8_str("blocked_js_prop"), 9899 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9900 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9901 v8::None, 9902 v8::DEFAULT); 9903 9904 // Create an environment 9905 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9906 context0->Enter(); 9907 9908 v8::Local<v8::Object> global0 = context0->Global(); 9909 9910 // Define a property with JS getter and setter. 9911 CompileRun( 9912 "function getter() { return 'getter'; };\n" 9913 "function setter() { return 'setter'; }\n" 9914 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 9915 9916 Local<Value> getter = 9917 global0->Get(context0, v8_str("getter")).ToLocalChecked(); 9918 Local<Value> setter = 9919 global0->Get(context0, v8_str("setter")).ToLocalChecked(); 9920 9921 // And define normal element. 9922 CHECK(global0->Set(context0, 239, v8_str("239")).FromJust()); 9923 9924 // Define an element with JS getter and setter. 9925 CompileRun( 9926 "function el_getter() { return 'el_getter'; };\n" 9927 "function el_setter() { return 'el_setter'; };\n" 9928 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 9929 9930 Local<Value> el_getter = 9931 global0->Get(context0, v8_str("el_getter")).ToLocalChecked(); 9932 Local<Value> el_setter = 9933 global0->Get(context0, v8_str("el_setter")).ToLocalChecked(); 9934 9935 v8::HandleScope scope1(isolate); 9936 9937 v8::Local<Context> context1 = Context::New(isolate); 9938 context1->Enter(); 9939 9940 v8::Local<v8::Object> global1 = context1->Global(); 9941 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 9942 9943 // Access blocked property. 9944 CompileRun("other.blocked_prop = 1"); 9945 9946 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9947 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 9948 .IsEmpty()); 9949 CHECK( 9950 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty()); 9951 9952 // Access blocked element. 9953 CHECK(CompileRun("other[239] = 1").IsEmpty()); 9954 9955 CHECK(CompileRun("other[239]").IsEmpty()); 9956 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty()); 9957 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty()); 9958 9959 allowed_access = true; 9960 // Now we can enumerate the property. 9961 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 9962 allowed_access = false; 9963 9964 // Access a property with JS accessor. 9965 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty()); 9966 9967 CHECK(CompileRun("other.js_accessor_p").IsEmpty()); 9968 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')") 9969 .IsEmpty()); 9970 9971 allowed_access = true; 9972 9973 ExpectString("other.js_accessor_p", "getter"); 9974 ExpectObject( 9975 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 9976 ExpectObject( 9977 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 9978 ExpectUndefined( 9979 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9980 9981 allowed_access = false; 9982 9983 // Access an element with JS accessor. 9984 CHECK(CompileRun("other[42] = 2").IsEmpty()); 9985 9986 CHECK(CompileRun("other[42]").IsEmpty()); 9987 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty()); 9988 9989 allowed_access = true; 9990 9991 ExpectString("other[42]", "el_getter"); 9992 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 9993 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 9994 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9995 9996 allowed_access = false; 9997 9998 v8::Local<Value> value; 9999 10000 // Access accessible property 10001 value = CompileRun("other.accessible_prop = 3"); 10002 CHECK(value->IsNumber()); 10003 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 10004 CHECK_EQ(3, g_echo_value); 10005 10006 value = CompileRun("other.accessible_prop"); 10007 CHECK(value->IsNumber()); 10008 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 10009 10010 value = CompileRun( 10011 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 10012 CHECK(value->IsNumber()); 10013 CHECK_EQ(3, value->Int32Value(context1).FromJust()); 10014 10015 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 10016 CHECK(value->IsTrue()); 10017 10018 // Enumeration doesn't enumerate accessors from inaccessible objects in 10019 // the prototype chain even if the accessors are in themselves accessible. 10020 // Enumeration doesn't throw, it silently ignores what it can't access. 10021 value = CompileRun( 10022 "(function() {" 10023 " var obj = { '__proto__': other };" 10024 " try {" 10025 " for (var p in obj) {" 10026 " if (p == 'accessible_prop' ||" 10027 " p == 'blocked_js_prop' ||" 10028 " p == 'blocked_js_prop') {" 10029 " return false;" 10030 " }" 10031 " }" 10032 " return true;" 10033 " } catch (e) {" 10034 " return false;" 10035 " }" 10036 "})()"); 10037 CHECK(value->IsTrue()); 10038 10039 // Test that preventExtensions fails on a non-accessible object even if that 10040 // object is already non-extensible. 10041 CHECK(global1->Set(context1, v8_str("checked_object"), 10042 global_template->NewInstance(context1).ToLocalChecked()) 10043 .FromJust()); 10044 allowed_access = true; 10045 CompileRun("Object.preventExtensions(checked_object)"); 10046 ExpectFalse("Object.isExtensible(checked_object)"); 10047 allowed_access = false; 10048 CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty()); 10049 10050 context1->Exit(); 10051 context0->Exit(); 10052 } 10053 10054 10055 TEST(AccessControlES5) { 10056 v8::Isolate* isolate = CcTest::isolate(); 10057 v8::HandleScope handle_scope(isolate); 10058 v8::Local<v8::ObjectTemplate> global_template = 10059 v8::ObjectTemplate::New(isolate); 10060 10061 global_template->SetAccessCheckCallback(AccessBlocker); 10062 10063 // Add accessible accessor. 10064 global_template->SetAccessor( 10065 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 10066 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 10067 10068 10069 // Add an accessor that is not accessible by cross-domain JS code. 10070 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter, 10071 UnreachableSetter, v8::Local<Value>(), 10072 v8::DEFAULT); 10073 10074 // Create an environment 10075 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 10076 context0->Enter(); 10077 10078 v8::Local<v8::Object> global0 = context0->Global(); 10079 10080 v8::Local<Context> context1 = Context::New(isolate); 10081 context1->Enter(); 10082 v8::Local<v8::Object> global1 = context1->Global(); 10083 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 10084 10085 // Regression test for issue 1154. 10086 CHECK(CompileRun("Object.keys(other).length == 1") 10087 ->BooleanValue(context1) 10088 .FromJust()); 10089 CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'") 10090 ->BooleanValue(context1) 10091 .FromJust()); 10092 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 10093 10094 // Regression test for issue 1027. 10095 CompileRun("Object.defineProperty(\n" 10096 " other, 'blocked_prop', {configurable: false})"); 10097 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 10098 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 10099 .IsEmpty()); 10100 10101 // Regression test for issue 1171. 10102 ExpectTrue("Object.isExtensible(other)"); 10103 CompileRun("Object.preventExtensions(other)"); 10104 ExpectTrue("Object.isExtensible(other)"); 10105 10106 // Object.seal and Object.freeze. 10107 CompileRun("Object.freeze(other)"); 10108 ExpectTrue("Object.isExtensible(other)"); 10109 10110 CompileRun("Object.seal(other)"); 10111 ExpectTrue("Object.isExtensible(other)"); 10112 10113 // Regression test for issue 1250. 10114 // Make sure that we can set the accessible accessors value using normal 10115 // assignment. 10116 CompileRun("other.accessible_prop = 42"); 10117 CHECK_EQ(42, g_echo_value); 10118 10119 // [[DefineOwnProperty]] always throws for access-checked objects. 10120 CHECK( 10121 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})") 10122 .IsEmpty()); 10123 CHECK(CompileRun("other.accessible_prop == 42")->IsTrue()); 10124 CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter. 10125 } 10126 10127 static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context, 10128 Local<v8::Object> global, 10129 Local<v8::Value> data) { 10130 i::PrintF("Access blocked.\n"); 10131 return false; 10132 } 10133 10134 10135 THREADED_TEST(AccessControlGetOwnPropertyNames) { 10136 v8::Isolate* isolate = CcTest::isolate(); 10137 v8::HandleScope handle_scope(isolate); 10138 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 10139 10140 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10141 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 10142 10143 // Add an accessor accessible by cross-domain JS code. 10144 obj_template->SetAccessor( 10145 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(), 10146 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 10147 10148 // Create an environment 10149 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 10150 context0->Enter(); 10151 10152 v8::Local<v8::Object> global0 = context0->Global(); 10153 10154 v8::HandleScope scope1(CcTest::isolate()); 10155 10156 v8::Local<Context> context1 = Context::New(isolate); 10157 context1->Enter(); 10158 10159 v8::Local<v8::Object> global1 = context1->Global(); 10160 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust()); 10161 CHECK(global1->Set(context1, v8_str("object"), 10162 obj_template->NewInstance(context1).ToLocalChecked()) 10163 .FromJust()); 10164 10165 v8::Local<Value> value; 10166 10167 // Attempt to get the property names of the other global object and 10168 // of an object that requires access checks. Accessing the other 10169 // global object should be blocked by access checks on the global 10170 // proxy object. Accessing the object that requires access checks 10171 // is blocked by the access checks on the object itself. 10172 value = CompileRun( 10173 "var names = Object.getOwnPropertyNames(other);" 10174 "names.length == 1 && names[0] == 'accessible_prop';"); 10175 CHECK(value->BooleanValue(context1).FromJust()); 10176 10177 value = CompileRun( 10178 "var names = Object.getOwnPropertyNames(object);" 10179 "names.length == 1 && names[0] == 'accessible_prop';"); 10180 CHECK(value->BooleanValue(context1).FromJust()); 10181 10182 context1->Exit(); 10183 context0->Exit(); 10184 } 10185 10186 10187 TEST(Regress470113) { 10188 v8::Isolate* isolate = CcTest::isolate(); 10189 v8::HandleScope handle_scope(isolate); 10190 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 10191 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 10192 LocalContext env; 10193 CHECK(env->Global() 10194 ->Set(env.local(), v8_str("prohibited"), 10195 obj_template->NewInstance(env.local()).ToLocalChecked()) 10196 .FromJust()); 10197 10198 { 10199 v8::TryCatch try_catch(isolate); 10200 CompileRun( 10201 "'use strict';\n" 10202 "class C extends Object {\n" 10203 " m() { super.powned = 'Powned!'; }\n" 10204 "}\n" 10205 "let c = new C();\n" 10206 "c.m.call(prohibited)"); 10207 10208 CHECK(try_catch.HasCaught()); 10209 } 10210 } 10211 10212 10213 static void ConstTenGetter(Local<String> name, 10214 const v8::PropertyCallbackInfo<v8::Value>& info) { 10215 info.GetReturnValue().Set(v8_num(10)); 10216 } 10217 10218 10219 THREADED_TEST(CrossDomainAccessors) { 10220 v8::Isolate* isolate = CcTest::isolate(); 10221 v8::HandleScope handle_scope(isolate); 10222 10223 v8::Local<v8::FunctionTemplate> func_template = 10224 v8::FunctionTemplate::New(isolate); 10225 10226 v8::Local<v8::ObjectTemplate> global_template = 10227 func_template->InstanceTemplate(); 10228 10229 v8::Local<v8::ObjectTemplate> proto_template = 10230 func_template->PrototypeTemplate(); 10231 10232 // Add an accessor to proto that's accessible by cross-domain JS code. 10233 proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, 0, 10234 v8::Local<Value>(), v8::ALL_CAN_READ); 10235 10236 // Add an accessor that is not accessible by cross-domain JS code. 10237 global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter, 0, 10238 v8::Local<Value>(), v8::DEFAULT); 10239 10240 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 10241 context0->Enter(); 10242 10243 Local<v8::Object> global = context0->Global(); 10244 // Add a normal property that shadows 'accessible' 10245 CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust()); 10246 10247 // Enter a new context. 10248 v8::HandleScope scope1(CcTest::isolate()); 10249 v8::Local<Context> context1 = Context::New(isolate); 10250 context1->Enter(); 10251 10252 v8::Local<v8::Object> global1 = context1->Global(); 10253 CHECK(global1->Set(context1, v8_str("other"), global).FromJust()); 10254 10255 // Should return 10, instead of 11 10256 v8::Local<Value> value = 10257 v8_compile("other.accessible")->Run(context1).ToLocalChecked(); 10258 CHECK(value->IsNumber()); 10259 CHECK_EQ(10, value->Int32Value(context1).FromJust()); 10260 10261 v8::MaybeLocal<v8::Value> maybe_value = 10262 v8_compile("other.unreachable")->Run(context1); 10263 CHECK(maybe_value.IsEmpty()); 10264 10265 context1->Exit(); 10266 context0->Exit(); 10267 } 10268 10269 10270 static int access_count = 0; 10271 10272 static bool AccessCounter(Local<v8::Context> accessing_context, 10273 Local<v8::Object> accessed_object, 10274 Local<v8::Value> data) { 10275 access_count++; 10276 return true; 10277 } 10278 10279 10280 // This one is too easily disturbed by other tests. 10281 TEST(AccessControlIC) { 10282 access_count = 0; 10283 10284 v8::Isolate* isolate = CcTest::isolate(); 10285 v8::HandleScope handle_scope(isolate); 10286 10287 // Create an environment. 10288 v8::Local<Context> context0 = Context::New(isolate); 10289 context0->Enter(); 10290 10291 // Create an object that requires access-check functions to be 10292 // called for cross-domain access. 10293 v8::Local<v8::ObjectTemplate> object_template = 10294 v8::ObjectTemplate::New(isolate); 10295 object_template->SetAccessCheckCallback(AccessCounter); 10296 Local<v8::Object> object = 10297 object_template->NewInstance(context0).ToLocalChecked(); 10298 10299 v8::HandleScope scope1(isolate); 10300 10301 // Create another environment. 10302 v8::Local<Context> context1 = Context::New(isolate); 10303 context1->Enter(); 10304 10305 // Make easy access to the object from the other environment. 10306 v8::Local<v8::Object> global1 = context1->Global(); 10307 CHECK(global1->Set(context1, v8_str("obj"), object).FromJust()); 10308 10309 v8::Local<Value> value; 10310 10311 // Check that the named access-control function is called every time. 10312 CompileRun("function testProp(obj) {" 10313 " for (var i = 0; i < 10; i++) obj.prop = 1;" 10314 " for (var j = 0; j < 10; j++) obj.prop;" 10315 " return obj.prop" 10316 "}"); 10317 value = CompileRun("testProp(obj)"); 10318 CHECK(value->IsNumber()); 10319 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10320 CHECK_EQ(21, access_count); 10321 10322 // Check that the named access-control function is called every time. 10323 CompileRun("var p = 'prop';" 10324 "function testKeyed(obj) {" 10325 " for (var i = 0; i < 10; i++) obj[p] = 1;" 10326 " for (var j = 0; j < 10; j++) obj[p];" 10327 " return obj[p];" 10328 "}"); 10329 // Use obj which requires access checks. No inline caching is used 10330 // in that case. 10331 value = CompileRun("testKeyed(obj)"); 10332 CHECK(value->IsNumber()); 10333 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10334 CHECK_EQ(42, access_count); 10335 // Force the inline caches into generic state and try again. 10336 CompileRun("testKeyed({ a: 0 })"); 10337 CompileRun("testKeyed({ b: 0 })"); 10338 value = CompileRun("testKeyed(obj)"); 10339 CHECK(value->IsNumber()); 10340 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10341 CHECK_EQ(63, access_count); 10342 10343 // Check that the indexed access-control function is called every time. 10344 access_count = 0; 10345 10346 CompileRun("function testIndexed(obj) {" 10347 " for (var i = 0; i < 10; i++) obj[0] = 1;" 10348 " for (var j = 0; j < 10; j++) obj[0];" 10349 " return obj[0]" 10350 "}"); 10351 value = CompileRun("testIndexed(obj)"); 10352 CHECK(value->IsNumber()); 10353 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10354 CHECK_EQ(21, access_count); 10355 // Force the inline caches into generic state. 10356 CompileRun("testIndexed(new Array(1))"); 10357 // Test that the indexed access check is called. 10358 value = CompileRun("testIndexed(obj)"); 10359 CHECK(value->IsNumber()); 10360 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10361 CHECK_EQ(42, access_count); 10362 10363 access_count = 0; 10364 // Check that the named access check is called when invoking 10365 // functions on an object that requires access checks. 10366 CompileRun("obj.f = function() {}"); 10367 CompileRun("function testCallNormal(obj) {" 10368 " for (var i = 0; i < 10; i++) obj.f();" 10369 "}"); 10370 CompileRun("testCallNormal(obj)"); 10371 printf("%i\n", access_count); 10372 CHECK_EQ(11, access_count); 10373 10374 // Force obj into slow case. 10375 value = CompileRun("delete obj.prop"); 10376 CHECK(value->BooleanValue(context1).FromJust()); 10377 // Force inline caches into dictionary probing mode. 10378 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 10379 // Test that the named access check is called. 10380 value = CompileRun("testProp(obj);"); 10381 CHECK(value->IsNumber()); 10382 CHECK_EQ(1, value->Int32Value(context1).FromJust()); 10383 CHECK_EQ(33, access_count); 10384 10385 // Force the call inline cache into dictionary probing mode. 10386 CompileRun("o.f = function() {}; testCallNormal(o)"); 10387 // Test that the named access check is still called for each 10388 // invocation of the function. 10389 value = CompileRun("testCallNormal(obj)"); 10390 CHECK_EQ(43, access_count); 10391 10392 context1->Exit(); 10393 context0->Exit(); 10394 } 10395 10396 10397 THREADED_TEST(Version) { v8::V8::GetVersion(); } 10398 10399 10400 static void InstanceFunctionCallback( 10401 const v8::FunctionCallbackInfo<v8::Value>& args) { 10402 ApiTestFuzzer::Fuzz(); 10403 args.GetReturnValue().Set(v8_num(12)); 10404 } 10405 10406 10407 THREADED_TEST(InstanceProperties) { 10408 LocalContext context; 10409 v8::Isolate* isolate = context->GetIsolate(); 10410 v8::HandleScope handle_scope(isolate); 10411 10412 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10413 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10414 10415 instance->Set(v8_str("x"), v8_num(42)); 10416 instance->Set(v8_str("f"), 10417 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback)); 10418 10419 Local<Value> o = t->GetFunction(context.local()) 10420 .ToLocalChecked() 10421 ->NewInstance(context.local()) 10422 .ToLocalChecked(); 10423 10424 CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust()); 10425 Local<Value> value = CompileRun("i.x"); 10426 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10427 10428 value = CompileRun("i.f()"); 10429 CHECK_EQ(12, value->Int32Value(context.local()).FromJust()); 10430 } 10431 10432 10433 static void GlobalObjectInstancePropertiesGet( 10434 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) { 10435 ApiTestFuzzer::Fuzz(); 10436 } 10437 10438 10439 THREADED_TEST(GlobalObjectInstanceProperties) { 10440 v8::Isolate* isolate = CcTest::isolate(); 10441 v8::HandleScope handle_scope(isolate); 10442 10443 Local<Value> global_object; 10444 10445 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10446 t->InstanceTemplate()->SetHandler( 10447 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet)); 10448 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10449 instance_template->Set(v8_str("x"), v8_num(42)); 10450 instance_template->Set(v8_str("f"), 10451 v8::FunctionTemplate::New(isolate, 10452 InstanceFunctionCallback)); 10453 10454 // The script to check how Crankshaft compiles missing global function 10455 // invocations. function g is not defined and should throw on call. 10456 const char* script = 10457 "function wrapper(call) {" 10458 " var x = 0, y = 1;" 10459 " for (var i = 0; i < 1000; i++) {" 10460 " x += i * 100;" 10461 " y += i * 100;" 10462 " }" 10463 " if (call) g();" 10464 "}" 10465 "for (var i = 0; i < 17; i++) wrapper(false);" 10466 "var thrown = 0;" 10467 "try { wrapper(true); } catch (e) { thrown = 1; };" 10468 "thrown"; 10469 10470 { 10471 LocalContext env(NULL, instance_template); 10472 // Hold on to the global object so it can be used again in another 10473 // environment initialization. 10474 global_object = env->Global(); 10475 10476 Local<Value> value = CompileRun("x"); 10477 CHECK_EQ(42, value->Int32Value(env.local()).FromJust()); 10478 value = CompileRun("f()"); 10479 CHECK_EQ(12, value->Int32Value(env.local()).FromJust()); 10480 value = CompileRun(script); 10481 CHECK_EQ(1, value->Int32Value(env.local()).FromJust()); 10482 } 10483 10484 { 10485 // Create new environment reusing the global object. 10486 LocalContext env(NULL, instance_template, global_object); 10487 Local<Value> value = CompileRun("x"); 10488 CHECK_EQ(42, value->Int32Value(env.local()).FromJust()); 10489 value = CompileRun("f()"); 10490 CHECK_EQ(12, value->Int32Value(env.local()).FromJust()); 10491 value = CompileRun(script); 10492 CHECK_EQ(1, value->Int32Value(env.local()).FromJust()); 10493 } 10494 } 10495 10496 THREADED_TEST(ObjectGetOwnPropertyNames) { 10497 LocalContext context; 10498 v8::Isolate* isolate = context->GetIsolate(); 10499 v8::HandleScope handle_scope(isolate); 10500 10501 v8::Local<v8::Object> value = 10502 v8::Local<v8::Object>::Cast(v8::StringObject::New(v8_str("test"))); 10503 v8::Local<v8::Array> properties; 10504 10505 CHECK(value 10506 ->GetOwnPropertyNames(context.local(), 10507 static_cast<v8::PropertyFilter>( 10508 v8::PropertyFilter::ALL_PROPERTIES | 10509 v8::PropertyFilter::SKIP_SYMBOLS)) 10510 .ToLocal(&properties)); 10511 CHECK_EQ(5, properties->Length()); 10512 v8::Local<v8::Value> property; 10513 CHECK(properties->Get(context.local(), 4).ToLocal(&property) && 10514 property->IsString()); 10515 CHECK(property.As<v8::String>() 10516 ->Equals(context.local(), v8_str("length")) 10517 .FromMaybe(false)); 10518 for (int i = 0; i < 4; ++i) { 10519 v8::Local<v8::Value> property; 10520 CHECK(properties->Get(context.local(), i).ToLocal(&property) && 10521 property->IsInt32()); 10522 CHECK_EQ(property.As<v8::Int32>()->Value(), i); 10523 } 10524 10525 CHECK(value->GetOwnPropertyNames(context.local(), v8::ONLY_ENUMERABLE) 10526 .ToLocal(&properties)); 10527 CHECK_EQ(4, properties->Length()); 10528 for (int i = 0; i < 4; ++i) { 10529 v8::Local<v8::Value> property; 10530 CHECK(properties->Get(context.local(), i).ToLocal(&property) && 10531 property->IsInt32()); 10532 CHECK_EQ(property.As<v8::Int32>()->Value(), i); 10533 } 10534 10535 value = value->GetPrototype().As<v8::Object>(); 10536 CHECK(value 10537 ->GetOwnPropertyNames(context.local(), 10538 static_cast<v8::PropertyFilter>( 10539 v8::PropertyFilter::ALL_PROPERTIES | 10540 v8::PropertyFilter::SKIP_SYMBOLS)) 10541 .ToLocal(&properties)); 10542 bool concat_found = false; 10543 bool starts_with_found = false; 10544 for (uint32_t i = 0; i < properties->Length(); ++i) { 10545 v8::Local<v8::Value> property; 10546 CHECK(properties->Get(context.local(), i).ToLocal(&property)); 10547 if (!property->IsString()) continue; 10548 if (!concat_found) 10549 concat_found = property.As<v8::String>() 10550 ->Equals(context.local(), v8_str("concat")) 10551 .FromMaybe(false); 10552 if (!starts_with_found) 10553 starts_with_found = property.As<v8::String>() 10554 ->Equals(context.local(), v8_str("startsWith")) 10555 .FromMaybe(false); 10556 } 10557 CHECK(concat_found && starts_with_found); 10558 } 10559 10560 THREADED_TEST(CallKnownGlobalReceiver) { 10561 v8::Isolate* isolate = CcTest::isolate(); 10562 v8::HandleScope handle_scope(isolate); 10563 10564 Local<Value> global_object; 10565 10566 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10567 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10568 10569 // The script to check that we leave global object not 10570 // global object proxy on stack when we deoptimize from inside 10571 // arguments evaluation. 10572 // To provoke error we need to both force deoptimization 10573 // from arguments evaluation and to force CallIC to take 10574 // CallIC_Miss code path that can't cope with global proxy. 10575 const char* script = 10576 "function bar(x, y) { try { } finally { } }" 10577 "function baz(x) { try { } finally { } }" 10578 "function bom(x) { try { } finally { } }" 10579 "function foo(x) { bar([x], bom(2)); }" 10580 "for (var i = 0; i < 10000; i++) foo(1);" 10581 "foo"; 10582 10583 Local<Value> foo; 10584 { 10585 LocalContext env(NULL, instance_template); 10586 // Hold on to the global object so it can be used again in another 10587 // environment initialization. 10588 global_object = env->Global(); 10589 foo = CompileRun(script); 10590 } 10591 10592 { 10593 // Create new environment reusing the global object. 10594 LocalContext env(NULL, instance_template, global_object); 10595 CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust()); 10596 CompileRun("foo()"); 10597 } 10598 } 10599 10600 10601 static void ShadowFunctionCallback( 10602 const v8::FunctionCallbackInfo<v8::Value>& args) { 10603 ApiTestFuzzer::Fuzz(); 10604 args.GetReturnValue().Set(v8_num(42)); 10605 } 10606 10607 10608 static int shadow_y; 10609 static int shadow_y_setter_call_count; 10610 static int shadow_y_getter_call_count; 10611 10612 10613 static void ShadowYSetter(Local<String>, 10614 Local<Value>, 10615 const v8::PropertyCallbackInfo<void>&) { 10616 shadow_y_setter_call_count++; 10617 shadow_y = 42; 10618 } 10619 10620 10621 static void ShadowYGetter(Local<String> name, 10622 const v8::PropertyCallbackInfo<v8::Value>& info) { 10623 ApiTestFuzzer::Fuzz(); 10624 shadow_y_getter_call_count++; 10625 info.GetReturnValue().Set(v8_num(shadow_y)); 10626 } 10627 10628 10629 static void ShadowIndexedGet(uint32_t index, 10630 const v8::PropertyCallbackInfo<v8::Value>&) { 10631 } 10632 10633 10634 static void ShadowNamedGet(Local<Name> key, 10635 const v8::PropertyCallbackInfo<v8::Value>&) {} 10636 10637 10638 THREADED_TEST(ShadowObject) { 10639 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 10640 v8::Isolate* isolate = CcTest::isolate(); 10641 v8::HandleScope handle_scope(isolate); 10642 10643 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 10644 LocalContext context(NULL, global_template); 10645 10646 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10647 t->InstanceTemplate()->SetHandler( 10648 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet)); 10649 t->InstanceTemplate()->SetHandler( 10650 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet)); 10651 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 10652 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10653 10654 proto->Set(v8_str("f"), 10655 v8::FunctionTemplate::New(isolate, 10656 ShadowFunctionCallback, 10657 Local<Value>())); 10658 proto->Set(v8_str("x"), v8_num(12)); 10659 10660 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 10661 10662 Local<Value> o = t->GetFunction(context.local()) 10663 .ToLocalChecked() 10664 ->NewInstance(context.local()) 10665 .ToLocalChecked(); 10666 CHECK(context->Global() 10667 ->Set(context.local(), v8_str("__proto__"), o) 10668 .FromJust()); 10669 10670 Local<Value> value = 10671 CompileRun("this.propertyIsEnumerable(0)"); 10672 CHECK(value->IsBoolean()); 10673 CHECK(!value->BooleanValue(context.local()).FromJust()); 10674 10675 value = CompileRun("x"); 10676 CHECK_EQ(12, value->Int32Value(context.local()).FromJust()); 10677 10678 value = CompileRun("f()"); 10679 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10680 10681 CompileRun("y = 43"); 10682 CHECK_EQ(1, shadow_y_setter_call_count); 10683 value = CompileRun("y"); 10684 CHECK_EQ(1, shadow_y_getter_call_count); 10685 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 10686 } 10687 10688 10689 THREADED_TEST(HiddenPrototype) { 10690 LocalContext context; 10691 v8::Isolate* isolate = context->GetIsolate(); 10692 v8::HandleScope handle_scope(isolate); 10693 10694 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10695 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10696 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10697 t1->SetHiddenPrototype(true); 10698 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10699 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10700 t2->SetHiddenPrototype(true); 10701 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10702 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10703 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10704 10705 Local<v8::Object> o0 = t0->GetFunction(context.local()) 10706 .ToLocalChecked() 10707 ->NewInstance(context.local()) 10708 .ToLocalChecked(); 10709 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10710 .ToLocalChecked() 10711 ->NewInstance(context.local()) 10712 .ToLocalChecked(); 10713 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10714 .ToLocalChecked() 10715 ->NewInstance(context.local()) 10716 .ToLocalChecked(); 10717 Local<v8::Object> o3 = t3->GetFunction(context.local()) 10718 .ToLocalChecked() 10719 ->NewInstance(context.local()) 10720 .ToLocalChecked(); 10721 10722 // Setting the prototype on an object skips hidden prototypes. 10723 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10724 .ToLocalChecked() 10725 ->Int32Value(context.local()) 10726 .FromJust()); 10727 CHECK(o0->Set(context.local(), v8_str("__proto__"), o1).FromJust()); 10728 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10729 .ToLocalChecked() 10730 ->Int32Value(context.local()) 10731 .FromJust()); 10732 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10733 .ToLocalChecked() 10734 ->Int32Value(context.local()) 10735 .FromJust()); 10736 CHECK(o0->Set(context.local(), v8_str("__proto__"), o2).FromJust()); 10737 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10738 .ToLocalChecked() 10739 ->Int32Value(context.local()) 10740 .FromJust()); 10741 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10742 .ToLocalChecked() 10743 ->Int32Value(context.local()) 10744 .FromJust()); 10745 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10746 .ToLocalChecked() 10747 ->Int32Value(context.local()) 10748 .FromJust()); 10749 CHECK(o0->Set(context.local(), v8_str("__proto__"), o3).FromJust()); 10750 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10751 .ToLocalChecked() 10752 ->Int32Value(context.local()) 10753 .FromJust()); 10754 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10755 .ToLocalChecked() 10756 ->Int32Value(context.local()) 10757 .FromJust()); 10758 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10759 .ToLocalChecked() 10760 ->Int32Value(context.local()) 10761 .FromJust()); 10762 CHECK_EQ(3, o0->Get(context.local(), v8_str("u")) 10763 .ToLocalChecked() 10764 ->Int32Value(context.local()) 10765 .FromJust()); 10766 10767 // Getting the prototype of o0 should get the first visible one 10768 // which is o3. Therefore, z should not be defined on the prototype 10769 // object. 10770 Local<Value> proto = 10771 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked(); 10772 CHECK(proto->IsObject()); 10773 CHECK(proto.As<v8::Object>() 10774 ->Get(context.local(), v8_str("z")) 10775 .ToLocalChecked() 10776 ->IsUndefined()); 10777 } 10778 10779 10780 THREADED_TEST(HiddenPrototypeSet) { 10781 LocalContext context; 10782 v8::Isolate* isolate = context->GetIsolate(); 10783 v8::HandleScope handle_scope(isolate); 10784 10785 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate); 10786 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate); 10787 ht->SetHiddenPrototype(true); 10788 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate); 10789 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10790 10791 Local<v8::Object> o = ot->GetFunction(context.local()) 10792 .ToLocalChecked() 10793 ->NewInstance(context.local()) 10794 .ToLocalChecked(); 10795 Local<v8::Object> h = ht->GetFunction(context.local()) 10796 .ToLocalChecked() 10797 ->NewInstance(context.local()) 10798 .ToLocalChecked(); 10799 Local<v8::Object> p = pt->GetFunction(context.local()) 10800 .ToLocalChecked() 10801 ->NewInstance(context.local()) 10802 .ToLocalChecked(); 10803 CHECK(o->Set(context.local(), v8_str("__proto__"), h).FromJust()); 10804 CHECK(h->Set(context.local(), v8_str("__proto__"), p).FromJust()); 10805 10806 // Setting a property that exists on the hidden prototype goes there. 10807 CHECK(o->Set(context.local(), v8_str("x"), v8_num(7)).FromJust()); 10808 CHECK_EQ(7, o->Get(context.local(), v8_str("x")) 10809 .ToLocalChecked() 10810 ->Int32Value(context.local()) 10811 .FromJust()); 10812 CHECK_EQ(7, h->Get(context.local(), v8_str("x")) 10813 .ToLocalChecked() 10814 ->Int32Value(context.local()) 10815 .FromJust()); 10816 CHECK(p->Get(context.local(), v8_str("x")).ToLocalChecked()->IsUndefined()); 10817 10818 // Setting a new property should not be forwarded to the hidden prototype. 10819 CHECK(o->Set(context.local(), v8_str("y"), v8_num(6)).FromJust()); 10820 CHECK_EQ(6, o->Get(context.local(), v8_str("y")) 10821 .ToLocalChecked() 10822 ->Int32Value(context.local()) 10823 .FromJust()); 10824 CHECK(h->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined()); 10825 CHECK(p->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined()); 10826 10827 // Setting a property that only exists on a prototype of the hidden prototype 10828 // is treated normally again. 10829 CHECK(p->Set(context.local(), v8_str("z"), v8_num(8)).FromJust()); 10830 CHECK_EQ(8, o->Get(context.local(), v8_str("z")) 10831 .ToLocalChecked() 10832 ->Int32Value(context.local()) 10833 .FromJust()); 10834 CHECK_EQ(8, h->Get(context.local(), v8_str("z")) 10835 .ToLocalChecked() 10836 ->Int32Value(context.local()) 10837 .FromJust()); 10838 CHECK_EQ(8, p->Get(context.local(), v8_str("z")) 10839 .ToLocalChecked() 10840 ->Int32Value(context.local()) 10841 .FromJust()); 10842 CHECK(o->Set(context.local(), v8_str("z"), v8_num(9)).FromJust()); 10843 CHECK_EQ(9, o->Get(context.local(), v8_str("z")) 10844 .ToLocalChecked() 10845 ->Int32Value(context.local()) 10846 .FromJust()); 10847 CHECK_EQ(8, h->Get(context.local(), v8_str("z")) 10848 .ToLocalChecked() 10849 ->Int32Value(context.local()) 10850 .FromJust()); 10851 CHECK_EQ(8, p->Get(context.local(), v8_str("z")) 10852 .ToLocalChecked() 10853 ->Int32Value(context.local()) 10854 .FromJust()); 10855 } 10856 10857 10858 // Regression test for issue 2457. 10859 THREADED_TEST(HiddenPrototypeIdentityHash) { 10860 LocalContext context; 10861 v8::HandleScope handle_scope(context->GetIsolate()); 10862 10863 Local<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate()); 10864 t->SetHiddenPrototype(true); 10865 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 10866 Local<Object> p = t->GetFunction(context.local()) 10867 .ToLocalChecked() 10868 ->NewInstance(context.local()) 10869 .ToLocalChecked(); 10870 Local<Object> o = Object::New(context->GetIsolate()); 10871 CHECK(o->SetPrototype(context.local(), p).FromJust()); 10872 10873 int hash = o->GetIdentityHash(); 10874 USE(hash); 10875 CHECK(o->Set(context.local(), v8_str("foo"), v8_num(42)).FromJust()); 10876 CHECK_EQ(hash, o->GetIdentityHash()); 10877 } 10878 10879 10880 THREADED_TEST(SetPrototype) { 10881 LocalContext context; 10882 v8::Isolate* isolate = context->GetIsolate(); 10883 v8::HandleScope handle_scope(isolate); 10884 10885 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10886 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10887 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10888 t1->SetHiddenPrototype(true); 10889 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10890 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10891 t2->SetHiddenPrototype(true); 10892 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10893 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10894 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10895 10896 Local<v8::Object> o0 = t0->GetFunction(context.local()) 10897 .ToLocalChecked() 10898 ->NewInstance(context.local()) 10899 .ToLocalChecked(); 10900 Local<v8::Object> o1 = t1->GetFunction(context.local()) 10901 .ToLocalChecked() 10902 ->NewInstance(context.local()) 10903 .ToLocalChecked(); 10904 Local<v8::Object> o2 = t2->GetFunction(context.local()) 10905 .ToLocalChecked() 10906 ->NewInstance(context.local()) 10907 .ToLocalChecked(); 10908 Local<v8::Object> o3 = t3->GetFunction(context.local()) 10909 .ToLocalChecked() 10910 ->NewInstance(context.local()) 10911 .ToLocalChecked(); 10912 10913 // Setting the prototype on an object does not skip hidden prototypes. 10914 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10915 .ToLocalChecked() 10916 ->Int32Value(context.local()) 10917 .FromJust()); 10918 CHECK(o0->SetPrototype(context.local(), o1).FromJust()); 10919 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10920 .ToLocalChecked() 10921 ->Int32Value(context.local()) 10922 .FromJust()); 10923 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10924 .ToLocalChecked() 10925 ->Int32Value(context.local()) 10926 .FromJust()); 10927 CHECK(o1->SetPrototype(context.local(), o2).FromJust()); 10928 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10929 .ToLocalChecked() 10930 ->Int32Value(context.local()) 10931 .FromJust()); 10932 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10933 .ToLocalChecked() 10934 ->Int32Value(context.local()) 10935 .FromJust()); 10936 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10937 .ToLocalChecked() 10938 ->Int32Value(context.local()) 10939 .FromJust()); 10940 CHECK(o2->SetPrototype(context.local(), o3).FromJust()); 10941 CHECK_EQ(0, o0->Get(context.local(), v8_str("x")) 10942 .ToLocalChecked() 10943 ->Int32Value(context.local()) 10944 .FromJust()); 10945 CHECK_EQ(1, o0->Get(context.local(), v8_str("y")) 10946 .ToLocalChecked() 10947 ->Int32Value(context.local()) 10948 .FromJust()); 10949 CHECK_EQ(2, o0->Get(context.local(), v8_str("z")) 10950 .ToLocalChecked() 10951 ->Int32Value(context.local()) 10952 .FromJust()); 10953 CHECK_EQ(3, o0->Get(context.local(), v8_str("u")) 10954 .ToLocalChecked() 10955 ->Int32Value(context.local()) 10956 .FromJust()); 10957 10958 // Getting the prototype of o0 should get the first visible one 10959 // which is o3. Therefore, z should not be defined on the prototype 10960 // object. 10961 Local<Value> proto = 10962 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked(); 10963 CHECK(proto->IsObject()); 10964 CHECK(proto.As<v8::Object>()->Equals(context.local(), o3).FromJust()); 10965 10966 // However, Object::GetPrototype ignores hidden prototype. 10967 Local<Value> proto0 = o0->GetPrototype(); 10968 CHECK(proto0->IsObject()); 10969 CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust()); 10970 10971 Local<Value> proto1 = o1->GetPrototype(); 10972 CHECK(proto1->IsObject()); 10973 CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust()); 10974 10975 Local<Value> proto2 = o2->GetPrototype(); 10976 CHECK(proto2->IsObject()); 10977 CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust()); 10978 } 10979 10980 10981 // Getting property names of an object with a prototype chain that 10982 // triggers dictionary elements in GetOwnPropertyNames() shouldn't 10983 // crash the runtime. 10984 THREADED_TEST(Regress91517) { 10985 i::FLAG_allow_natives_syntax = true; 10986 LocalContext context; 10987 v8::Isolate* isolate = context->GetIsolate(); 10988 v8::HandleScope handle_scope(isolate); 10989 10990 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10991 t1->SetHiddenPrototype(true); 10992 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 10993 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10994 t2->SetHiddenPrototype(true); 10995 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 10996 t2->InstanceTemplate()->Set(v8_str("objects"), 10997 v8::ObjectTemplate::New(isolate)); 10998 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 10999 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 11000 t3->SetHiddenPrototype(true); 11001 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 11002 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate); 11003 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 11004 11005 // Force dictionary-based properties. 11006 i::ScopedVector<char> name_buf(1024); 11007 for (int i = 1; i <= 1000; i++) { 11008 i::SNPrintF(name_buf, "sdf%d", i); 11009 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 11010 } 11011 11012 Local<v8::Object> o1 = t1->GetFunction(context.local()) 11013 .ToLocalChecked() 11014 ->NewInstance(context.local()) 11015 .ToLocalChecked(); 11016 Local<v8::Object> o2 = t2->GetFunction(context.local()) 11017 .ToLocalChecked() 11018 ->NewInstance(context.local()) 11019 .ToLocalChecked(); 11020 Local<v8::Object> o3 = t3->GetFunction(context.local()) 11021 .ToLocalChecked() 11022 ->NewInstance(context.local()) 11023 .ToLocalChecked(); 11024 Local<v8::Object> o4 = t4->GetFunction(context.local()) 11025 .ToLocalChecked() 11026 ->NewInstance(context.local()) 11027 .ToLocalChecked(); 11028 11029 // Create prototype chain of hidden prototypes. 11030 CHECK(o4->SetPrototype(context.local(), o3).FromJust()); 11031 CHECK(o3->SetPrototype(context.local(), o2).FromJust()); 11032 CHECK(o2->SetPrototype(context.local(), o1).FromJust()); 11033 11034 // Call the runtime version of GetOwnPropertyNames() on the natively 11035 // created object through JavaScript. 11036 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust()); 11037 // PROPERTY_FILTER_NONE = 0 11038 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);"); 11039 11040 ExpectInt32("names.length", 1006); 11041 ExpectTrue("names.indexOf(\"baz\") >= 0"); 11042 ExpectTrue("names.indexOf(\"boo\") >= 0"); 11043 ExpectTrue("names.indexOf(\"foo\") >= 0"); 11044 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 11045 ExpectTrue("names.indexOf(\"objects\") >= 0"); 11046 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 11047 ExpectFalse("names[1005] == undefined"); 11048 } 11049 11050 11051 // Getting property names of an object with a hidden and inherited 11052 // prototype should not duplicate the accessor properties inherited. 11053 THREADED_TEST(Regress269562) { 11054 i::FLAG_allow_natives_syntax = true; 11055 LocalContext context; 11056 v8::HandleScope handle_scope(context->GetIsolate()); 11057 11058 Local<v8::FunctionTemplate> t1 = 11059 v8::FunctionTemplate::New(context->GetIsolate()); 11060 t1->SetHiddenPrototype(true); 11061 11062 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate(); 11063 i1->SetAccessor(v8_str("foo"), 11064 SimpleAccessorGetter, SimpleAccessorSetter); 11065 i1->SetAccessor(v8_str("bar"), 11066 SimpleAccessorGetter, SimpleAccessorSetter); 11067 i1->SetAccessor(v8_str("baz"), 11068 SimpleAccessorGetter, SimpleAccessorSetter); 11069 i1->Set(v8_str("n1"), v8_num(1)); 11070 i1->Set(v8_str("n2"), v8_num(2)); 11071 11072 Local<v8::Object> o1 = t1->GetFunction(context.local()) 11073 .ToLocalChecked() 11074 ->NewInstance(context.local()) 11075 .ToLocalChecked(); 11076 Local<v8::FunctionTemplate> t2 = 11077 v8::FunctionTemplate::New(context->GetIsolate()); 11078 t2->SetHiddenPrototype(true); 11079 11080 // Inherit from t1 and mark prototype as hidden. 11081 t2->Inherit(t1); 11082 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4)); 11083 11084 Local<v8::Object> o2 = t2->GetFunction(context.local()) 11085 .ToLocalChecked() 11086 ->NewInstance(context.local()) 11087 .ToLocalChecked(); 11088 CHECK(o2->SetPrototype(context.local(), o1).FromJust()); 11089 11090 v8::Local<v8::Symbol> sym = 11091 v8::Symbol::New(context->GetIsolate(), v8_str("s1")); 11092 CHECK(o1->Set(context.local(), sym, v8_num(3)).FromJust()); 11093 o1->SetPrivate(context.local(), 11094 v8::Private::New(context->GetIsolate(), v8_str("h1")), 11095 v8::Integer::New(context->GetIsolate(), 2013)) 11096 .FromJust(); 11097 11098 // Call the runtime version of GetOwnPropertyNames() on 11099 // the natively created object through JavaScript. 11100 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o2).FromJust()); 11101 CHECK(context->Global()->Set(context.local(), v8_str("sym"), sym).FromJust()); 11102 // PROPERTY_FILTER_NONE = 0 11103 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);"); 11104 11105 ExpectInt32("names.length", 7); 11106 ExpectTrue("names.indexOf(\"foo\") >= 0"); 11107 ExpectTrue("names.indexOf(\"bar\") >= 0"); 11108 ExpectTrue("names.indexOf(\"baz\") >= 0"); 11109 ExpectTrue("names.indexOf(\"n1\") >= 0"); 11110 ExpectTrue("names.indexOf(\"n2\") >= 0"); 11111 ExpectTrue("names.indexOf(sym) >= 0"); 11112 ExpectTrue("names.indexOf(\"mine\") >= 0"); 11113 } 11114 11115 11116 THREADED_TEST(FunctionReadOnlyPrototype) { 11117 LocalContext context; 11118 v8::Isolate* isolate = context->GetIsolate(); 11119 v8::HandleScope handle_scope(isolate); 11120 11121 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 11122 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 11123 t1->ReadOnlyPrototype(); 11124 CHECK(context->Global() 11125 ->Set(context.local(), v8_str("func1"), 11126 t1->GetFunction(context.local()).ToLocalChecked()) 11127 .FromJust()); 11128 // Configured value of ReadOnly flag. 11129 CHECK( 11130 CompileRun( 11131 "(function() {" 11132 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 11133 " return (descriptor['writable'] == false);" 11134 "})()") 11135 ->BooleanValue(context.local()) 11136 .FromJust()); 11137 CHECK_EQ( 11138 42, 11139 CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust()); 11140 CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x") 11141 ->Int32Value(context.local()) 11142 .FromJust()); 11143 11144 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 11145 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 11146 CHECK(context->Global() 11147 ->Set(context.local(), v8_str("func2"), 11148 t2->GetFunction(context.local()).ToLocalChecked()) 11149 .FromJust()); 11150 // Default value of ReadOnly flag. 11151 CHECK( 11152 CompileRun( 11153 "(function() {" 11154 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 11155 " return (descriptor['writable'] == true);" 11156 "})()") 11157 ->BooleanValue(context.local()) 11158 .FromJust()); 11159 CHECK_EQ( 11160 42, 11161 CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust()); 11162 } 11163 11164 11165 THREADED_TEST(SetPrototypeThrows) { 11166 LocalContext context; 11167 v8::Isolate* isolate = context->GetIsolate(); 11168 v8::HandleScope handle_scope(isolate); 11169 11170 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11171 11172 Local<v8::Object> o0 = t->GetFunction(context.local()) 11173 .ToLocalChecked() 11174 ->NewInstance(context.local()) 11175 .ToLocalChecked(); 11176 Local<v8::Object> o1 = t->GetFunction(context.local()) 11177 .ToLocalChecked() 11178 ->NewInstance(context.local()) 11179 .ToLocalChecked(); 11180 11181 CHECK(o0->SetPrototype(context.local(), o1).FromJust()); 11182 // If setting the prototype leads to the cycle, SetPrototype should 11183 // return false and keep VM in sane state. 11184 v8::TryCatch try_catch(isolate); 11185 CHECK(o1->SetPrototype(context.local(), o0).IsNothing()); 11186 CHECK(!try_catch.HasCaught()); 11187 CHECK(!CcTest::i_isolate()->has_pending_exception()); 11188 11189 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()") 11190 ->Int32Value(context.local()) 11191 .FromJust()); 11192 } 11193 11194 11195 THREADED_TEST(FunctionRemovePrototype) { 11196 LocalContext context; 11197 v8::Isolate* isolate = context->GetIsolate(); 11198 v8::HandleScope handle_scope(isolate); 11199 11200 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 11201 t1->RemovePrototype(); 11202 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked(); 11203 CHECK(!fun->IsConstructor()); 11204 CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust()); 11205 CHECK(!CompileRun("'prototype' in fun") 11206 ->BooleanValue(context.local()) 11207 .FromJust()); 11208 11209 v8::TryCatch try_catch(isolate); 11210 CompileRun("new fun()"); 11211 CHECK(try_catch.HasCaught()); 11212 11213 try_catch.Reset(); 11214 CHECK(fun->NewInstance(context.local()).IsEmpty()); 11215 CHECK(try_catch.HasCaught()); 11216 } 11217 11218 11219 THREADED_TEST(GetterSetterExceptions) { 11220 LocalContext context; 11221 v8::Isolate* isolate = context->GetIsolate(); 11222 v8::HandleScope handle_scope(isolate); 11223 CompileRun( 11224 "function Foo() { };" 11225 "function Throw() { throw 5; };" 11226 "var x = { };" 11227 "x.__defineSetter__('set', Throw);" 11228 "x.__defineGetter__('get', Throw);"); 11229 Local<v8::Object> x = Local<v8::Object>::Cast( 11230 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked()); 11231 v8::TryCatch try_catch(isolate); 11232 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 11233 .IsNothing()); 11234 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 11235 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 11236 .IsNothing()); 11237 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 11238 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 11239 .IsNothing()); 11240 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 11241 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8)) 11242 .IsNothing()); 11243 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty()); 11244 } 11245 11246 11247 THREADED_TEST(Constructor) { 11248 LocalContext context; 11249 v8::Isolate* isolate = context->GetIsolate(); 11250 v8::HandleScope handle_scope(isolate); 11251 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 11252 templ->SetClassName(v8_str("Fun")); 11253 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked(); 11254 CHECK( 11255 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust()); 11256 Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked(); 11257 i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst)); 11258 CHECK(obj->IsJSObject()); 11259 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 11260 CHECK(value->BooleanValue(context.local()).FromJust()); 11261 } 11262 11263 11264 static void ConstructorCallback( 11265 const v8::FunctionCallbackInfo<v8::Value>& args) { 11266 ApiTestFuzzer::Fuzz(); 11267 Local<Object> This; 11268 11269 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 11270 if (args.IsConstructCall()) { 11271 Local<Object> Holder = args.Holder(); 11272 This = Object::New(args.GetIsolate()); 11273 Local<Value> proto = Holder->GetPrototype(); 11274 if (proto->IsObject()) { 11275 This->SetPrototype(context, proto).FromJust(); 11276 } 11277 } else { 11278 This = args.This(); 11279 } 11280 11281 This->Set(context, v8_str("a"), args[0]).FromJust(); 11282 args.GetReturnValue().Set(This); 11283 } 11284 11285 11286 static void FakeConstructorCallback( 11287 const v8::FunctionCallbackInfo<v8::Value>& args) { 11288 ApiTestFuzzer::Fuzz(); 11289 args.GetReturnValue().Set(args[0]); 11290 } 11291 11292 11293 THREADED_TEST(ConstructorForObject) { 11294 LocalContext context; 11295 v8::Isolate* isolate = context->GetIsolate(); 11296 v8::HandleScope handle_scope(isolate); 11297 11298 { 11299 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11300 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 11301 Local<Object> instance = 11302 instance_template->NewInstance(context.local()).ToLocalChecked(); 11303 CHECK(context->Global() 11304 ->Set(context.local(), v8_str("obj"), instance) 11305 .FromJust()); 11306 v8::TryCatch try_catch(isolate); 11307 Local<Value> value; 11308 CHECK(!try_catch.HasCaught()); 11309 11310 // Call the Object's constructor with a 32-bit signed integer. 11311 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 11312 CHECK(!try_catch.HasCaught()); 11313 CHECK(value->IsInt32()); 11314 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11315 11316 Local<Value> args1[] = {v8_num(28)}; 11317 Local<Value> value_obj1 = 11318 instance->CallAsConstructor(context.local(), 1, args1).ToLocalChecked(); 11319 CHECK(value_obj1->IsObject()); 11320 Local<Object> object1 = Local<Object>::Cast(value_obj1); 11321 value = object1->Get(context.local(), v8_str("a")).ToLocalChecked(); 11322 CHECK(value->IsInt32()); 11323 CHECK(!try_catch.HasCaught()); 11324 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11325 11326 // Call the Object's constructor with a String. 11327 value = 11328 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()"); 11329 CHECK(!try_catch.HasCaught()); 11330 CHECK(value->IsString()); 11331 String::Utf8Value string_value1( 11332 value->ToString(context.local()).ToLocalChecked()); 11333 CHECK_EQ(0, strcmp("tipli", *string_value1)); 11334 11335 Local<Value> args2[] = {v8_str("tipli")}; 11336 Local<Value> value_obj2 = 11337 instance->CallAsConstructor(context.local(), 1, args2).ToLocalChecked(); 11338 CHECK(value_obj2->IsObject()); 11339 Local<Object> object2 = Local<Object>::Cast(value_obj2); 11340 value = object2->Get(context.local(), v8_str("a")).ToLocalChecked(); 11341 CHECK(!try_catch.HasCaught()); 11342 CHECK(value->IsString()); 11343 String::Utf8Value string_value2( 11344 value->ToString(context.local()).ToLocalChecked()); 11345 CHECK_EQ(0, strcmp("tipli", *string_value2)); 11346 11347 // Call the Object's constructor with a Boolean. 11348 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 11349 CHECK(!try_catch.HasCaught()); 11350 CHECK(value->IsBoolean()); 11351 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust()); 11352 11353 Local<Value> args3[] = {v8::True(isolate)}; 11354 Local<Value> value_obj3 = 11355 instance->CallAsConstructor(context.local(), 1, args3).ToLocalChecked(); 11356 CHECK(value_obj3->IsObject()); 11357 Local<Object> object3 = Local<Object>::Cast(value_obj3); 11358 value = object3->Get(context.local(), v8_str("a")).ToLocalChecked(); 11359 CHECK(!try_catch.HasCaught()); 11360 CHECK(value->IsBoolean()); 11361 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust()); 11362 11363 // Call the Object's constructor with undefined. 11364 Local<Value> args4[] = {v8::Undefined(isolate)}; 11365 Local<Value> value_obj4 = 11366 instance->CallAsConstructor(context.local(), 1, args4).ToLocalChecked(); 11367 CHECK(value_obj4->IsObject()); 11368 Local<Object> object4 = Local<Object>::Cast(value_obj4); 11369 value = object4->Get(context.local(), v8_str("a")).ToLocalChecked(); 11370 CHECK(!try_catch.HasCaught()); 11371 CHECK(value->IsUndefined()); 11372 11373 // Call the Object's constructor with null. 11374 Local<Value> args5[] = {v8::Null(isolate)}; 11375 Local<Value> value_obj5 = 11376 instance->CallAsConstructor(context.local(), 1, args5).ToLocalChecked(); 11377 CHECK(value_obj5->IsObject()); 11378 Local<Object> object5 = Local<Object>::Cast(value_obj5); 11379 value = object5->Get(context.local(), v8_str("a")).ToLocalChecked(); 11380 CHECK(!try_catch.HasCaught()); 11381 CHECK(value->IsNull()); 11382 } 11383 11384 // Check exception handling when there is no constructor set for the Object. 11385 { 11386 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11387 Local<Object> instance = 11388 instance_template->NewInstance(context.local()).ToLocalChecked(); 11389 CHECK(context->Global() 11390 ->Set(context.local(), v8_str("obj2"), instance) 11391 .FromJust()); 11392 v8::TryCatch try_catch(isolate); 11393 Local<Value> value; 11394 CHECK(!try_catch.HasCaught()); 11395 11396 value = CompileRun("new obj2(28)"); 11397 CHECK(try_catch.HasCaught()); 11398 String::Utf8Value exception_value1(try_catch.Exception()); 11399 CHECK_EQ(0, 11400 strcmp("TypeError: obj2 is not a constructor", *exception_value1)); 11401 try_catch.Reset(); 11402 11403 Local<Value> args[] = {v8_num(29)}; 11404 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty()); 11405 CHECK(try_catch.HasCaught()); 11406 String::Utf8Value exception_value2(try_catch.Exception()); 11407 CHECK_EQ( 11408 0, strcmp("TypeError: object is not a constructor", *exception_value2)); 11409 try_catch.Reset(); 11410 } 11411 11412 // Check the case when constructor throws exception. 11413 { 11414 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11415 instance_template->SetCallAsFunctionHandler(ThrowValue); 11416 Local<Object> instance = 11417 instance_template->NewInstance(context.local()).ToLocalChecked(); 11418 CHECK(context->Global() 11419 ->Set(context.local(), v8_str("obj3"), instance) 11420 .FromJust()); 11421 v8::TryCatch try_catch(isolate); 11422 Local<Value> value; 11423 CHECK(!try_catch.HasCaught()); 11424 11425 value = CompileRun("new obj3(22)"); 11426 CHECK(try_catch.HasCaught()); 11427 String::Utf8Value exception_value1(try_catch.Exception()); 11428 CHECK_EQ(0, strcmp("22", *exception_value1)); 11429 try_catch.Reset(); 11430 11431 Local<Value> args[] = {v8_num(23)}; 11432 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty()); 11433 CHECK(try_catch.HasCaught()); 11434 String::Utf8Value exception_value2(try_catch.Exception()); 11435 CHECK_EQ(0, strcmp("23", *exception_value2)); 11436 try_catch.Reset(); 11437 } 11438 11439 // Check whether constructor returns with an object or non-object. 11440 { 11441 Local<FunctionTemplate> function_template = 11442 FunctionTemplate::New(isolate, FakeConstructorCallback); 11443 Local<Function> function = 11444 function_template->GetFunction(context.local()).ToLocalChecked(); 11445 Local<Object> instance1 = function; 11446 CHECK(context->Global() 11447 ->Set(context.local(), v8_str("obj4"), instance1) 11448 .FromJust()); 11449 v8::TryCatch try_catch(isolate); 11450 Local<Value> value; 11451 CHECK(!try_catch.HasCaught()); 11452 11453 CHECK(instance1->IsObject()); 11454 CHECK(instance1->IsFunction()); 11455 11456 value = CompileRun("new obj4(28)"); 11457 CHECK(!try_catch.HasCaught()); 11458 CHECK(value->IsObject()); 11459 11460 Local<Value> args1[] = {v8_num(28)}; 11461 value = instance1->CallAsConstructor(context.local(), 1, args1) 11462 .ToLocalChecked(); 11463 CHECK(!try_catch.HasCaught()); 11464 CHECK(value->IsObject()); 11465 11466 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11467 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 11468 Local<Object> instance2 = 11469 instance_template->NewInstance(context.local()).ToLocalChecked(); 11470 CHECK(context->Global() 11471 ->Set(context.local(), v8_str("obj5"), instance2) 11472 .FromJust()); 11473 CHECK(!try_catch.HasCaught()); 11474 11475 CHECK(instance2->IsObject()); 11476 CHECK(instance2->IsFunction()); 11477 11478 value = CompileRun("new obj5(28)"); 11479 CHECK(!try_catch.HasCaught()); 11480 CHECK(!value->IsObject()); 11481 11482 Local<Value> args2[] = {v8_num(28)}; 11483 value = instance2->CallAsConstructor(context.local(), 1, args2) 11484 .ToLocalChecked(); 11485 CHECK(!try_catch.HasCaught()); 11486 CHECK(!value->IsObject()); 11487 } 11488 } 11489 11490 11491 THREADED_TEST(FunctionDescriptorException) { 11492 LocalContext context; 11493 v8::Isolate* isolate = context->GetIsolate(); 11494 v8::HandleScope handle_scope(isolate); 11495 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 11496 templ->SetClassName(v8_str("Fun")); 11497 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked(); 11498 CHECK( 11499 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust()); 11500 Local<Value> value = CompileRun( 11501 "function test() {" 11502 " try {" 11503 " (new Fun()).blah()" 11504 " } catch (e) {" 11505 " var str = String(e);" 11506 // " if (str.indexOf('TypeError') == -1) return 1;" 11507 // " if (str.indexOf('[object Fun]') != -1) return 2;" 11508 // " if (str.indexOf('#<Fun>') == -1) return 3;" 11509 " return 0;" 11510 " }" 11511 " return 4;" 11512 "}" 11513 "test();"); 11514 CHECK_EQ(0, value->Int32Value(context.local()).FromJust()); 11515 } 11516 11517 11518 THREADED_TEST(EvalAliasedDynamic) { 11519 LocalContext current; 11520 v8::HandleScope scope(current->GetIsolate()); 11521 11522 // Tests where aliased eval can only be resolved dynamically. 11523 Local<Script> script = v8_compile( 11524 "function f(x) { " 11525 " var foo = 2;" 11526 " with (x) { return eval('foo'); }" 11527 "}" 11528 "foo = 0;" 11529 "result1 = f(new Object());" 11530 "result2 = f(this);" 11531 "var x = new Object();" 11532 "x.eval = function(x) { return 1; };" 11533 "result3 = f(x);"); 11534 script->Run(current.local()).ToLocalChecked(); 11535 CHECK_EQ(2, current->Global() 11536 ->Get(current.local(), v8_str("result1")) 11537 .ToLocalChecked() 11538 ->Int32Value(current.local()) 11539 .FromJust()); 11540 CHECK_EQ(0, current->Global() 11541 ->Get(current.local(), v8_str("result2")) 11542 .ToLocalChecked() 11543 ->Int32Value(current.local()) 11544 .FromJust()); 11545 CHECK_EQ(1, current->Global() 11546 ->Get(current.local(), v8_str("result3")) 11547 .ToLocalChecked() 11548 ->Int32Value(current.local()) 11549 .FromJust()); 11550 11551 v8::TryCatch try_catch(current->GetIsolate()); 11552 script = v8_compile( 11553 "function f(x) { " 11554 " var bar = 2;" 11555 " with (x) { return eval('bar'); }" 11556 "}" 11557 "result4 = f(this)"); 11558 script->Run(current.local()).ToLocalChecked(); 11559 CHECK(!try_catch.HasCaught()); 11560 CHECK_EQ(2, current->Global() 11561 ->Get(current.local(), v8_str("result4")) 11562 .ToLocalChecked() 11563 ->Int32Value(current.local()) 11564 .FromJust()); 11565 11566 try_catch.Reset(); 11567 } 11568 11569 11570 THREADED_TEST(CrossEval) { 11571 v8::HandleScope scope(CcTest::isolate()); 11572 LocalContext other; 11573 LocalContext current; 11574 11575 Local<String> token = v8_str("<security token>"); 11576 other->SetSecurityToken(token); 11577 current->SetSecurityToken(token); 11578 11579 // Set up reference from current to other. 11580 CHECK(current->Global() 11581 ->Set(current.local(), v8_str("other"), other->Global()) 11582 .FromJust()); 11583 11584 // Check that new variables are introduced in other context. 11585 Local<Script> script = v8_compile("other.eval('var foo = 1234')"); 11586 script->Run(current.local()).ToLocalChecked(); 11587 Local<Value> foo = 11588 other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked(); 11589 CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust()); 11590 CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust()); 11591 11592 // Check that writing to non-existing properties introduces them in 11593 // the other context. 11594 script = v8_compile("other.eval('na = 1234')"); 11595 script->Run(current.local()).ToLocalChecked(); 11596 CHECK_EQ(1234, other->Global() 11597 ->Get(current.local(), v8_str("na")) 11598 .ToLocalChecked() 11599 ->Int32Value(other.local()) 11600 .FromJust()); 11601 CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust()); 11602 11603 // Check that global variables in current context are not visible in other 11604 // context. 11605 v8::TryCatch try_catch(CcTest::isolate()); 11606 script = v8_compile("var bar = 42; other.eval('bar');"); 11607 CHECK(script->Run(current.local()).IsEmpty()); 11608 CHECK(try_catch.HasCaught()); 11609 try_catch.Reset(); 11610 11611 // Check that local variables in current context are not visible in other 11612 // context. 11613 script = v8_compile( 11614 "(function() { " 11615 " var baz = 87;" 11616 " return other.eval('baz');" 11617 "})();"); 11618 CHECK(script->Run(current.local()).IsEmpty()); 11619 CHECK(try_catch.HasCaught()); 11620 try_catch.Reset(); 11621 11622 // Check that global variables in the other environment are visible 11623 // when evaluting code. 11624 CHECK(other->Global() 11625 ->Set(other.local(), v8_str("bis"), v8_num(1234)) 11626 .FromJust()); 11627 script = v8_compile("other.eval('bis')"); 11628 CHECK_EQ(1234, script->Run(current.local()) 11629 .ToLocalChecked() 11630 ->Int32Value(current.local()) 11631 .FromJust()); 11632 CHECK(!try_catch.HasCaught()); 11633 11634 // Check that the 'this' pointer points to the global object evaluating 11635 // code. 11636 CHECK(other->Global() 11637 ->Set(current.local(), v8_str("t"), other->Global()) 11638 .FromJust()); 11639 script = v8_compile("other.eval('this == t')"); 11640 Local<Value> result = script->Run(current.local()).ToLocalChecked(); 11641 CHECK(result->IsTrue()); 11642 CHECK(!try_catch.HasCaught()); 11643 11644 // Check that variables introduced in with-statement are not visible in 11645 // other context. 11646 script = v8_compile("with({x:2}){other.eval('x')}"); 11647 CHECK(script->Run(current.local()).IsEmpty()); 11648 CHECK(try_catch.HasCaught()); 11649 try_catch.Reset(); 11650 11651 // Check that you cannot use 'eval.call' with another object than the 11652 // current global object. 11653 script = v8_compile("other.y = 1; eval.call(other, 'y')"); 11654 CHECK(script->Run(current.local()).IsEmpty()); 11655 CHECK(try_catch.HasCaught()); 11656 } 11657 11658 11659 // Test that calling eval in a context which has been detached from 11660 // its global proxy works. 11661 THREADED_TEST(EvalInDetachedGlobal) { 11662 v8::Isolate* isolate = CcTest::isolate(); 11663 v8::HandleScope scope(isolate); 11664 11665 v8::Local<Context> context0 = Context::New(isolate); 11666 v8::Local<Context> context1 = Context::New(isolate); 11667 11668 // Set up function in context0 that uses eval from context0. 11669 context0->Enter(); 11670 v8::Local<v8::Value> fun = CompileRun( 11671 "var x = 42;" 11672 "(function() {" 11673 " var e = eval;" 11674 " return function(s) { return e(s); }" 11675 "})()"); 11676 context0->Exit(); 11677 11678 // Put the function into context1 and call it before and after 11679 // detaching the global. Before detaching, the call succeeds and 11680 // after detaching and exception is thrown. 11681 context1->Enter(); 11682 CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust()); 11683 v8::Local<v8::Value> x_value = CompileRun("fun('x')"); 11684 CHECK_EQ(42, x_value->Int32Value(context1).FromJust()); 11685 context0->DetachGlobal(); 11686 v8::TryCatch catcher(isolate); 11687 x_value = CompileRun("fun('x')"); 11688 CHECK_EQ(42, x_value->Int32Value(context1).FromJust()); 11689 context1->Exit(); 11690 } 11691 11692 11693 THREADED_TEST(CrossLazyLoad) { 11694 v8::HandleScope scope(CcTest::isolate()); 11695 LocalContext other; 11696 LocalContext current; 11697 11698 Local<String> token = v8_str("<security token>"); 11699 other->SetSecurityToken(token); 11700 current->SetSecurityToken(token); 11701 11702 // Set up reference from current to other. 11703 CHECK(current->Global() 11704 ->Set(current.local(), v8_str("other"), other->Global()) 11705 .FromJust()); 11706 11707 // Trigger lazy loading in other context. 11708 Local<Script> script = v8_compile("other.eval('new Date(42)')"); 11709 Local<Value> value = script->Run(current.local()).ToLocalChecked(); 11710 CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust()); 11711 } 11712 11713 11714 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 11715 ApiTestFuzzer::Fuzz(); 11716 if (args.IsConstructCall()) { 11717 if (args[0]->IsInt32()) { 11718 args.GetReturnValue().Set( 11719 v8_num(-args[0] 11720 ->Int32Value(args.GetIsolate()->GetCurrentContext()) 11721 .FromJust())); 11722 return; 11723 } 11724 } 11725 11726 args.GetReturnValue().Set(args[0]); 11727 } 11728 11729 11730 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 11731 args.GetReturnValue().Set(args.This()); 11732 } 11733 11734 11735 // Test that a call handler can be set for objects which will allow 11736 // non-function objects created through the API to be called as 11737 // functions. 11738 THREADED_TEST(CallAsFunction) { 11739 LocalContext context; 11740 v8::Isolate* isolate = context->GetIsolate(); 11741 v8::HandleScope scope(isolate); 11742 11743 { 11744 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11745 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11746 instance_template->SetCallAsFunctionHandler(call_as_function); 11747 Local<v8::Object> instance = t->GetFunction(context.local()) 11748 .ToLocalChecked() 11749 ->NewInstance(context.local()) 11750 .ToLocalChecked(); 11751 CHECK(context->Global() 11752 ->Set(context.local(), v8_str("obj"), instance) 11753 .FromJust()); 11754 v8::TryCatch try_catch(isolate); 11755 Local<Value> value; 11756 CHECK(!try_catch.HasCaught()); 11757 11758 value = CompileRun("obj(42)"); 11759 CHECK(!try_catch.HasCaught()); 11760 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 11761 11762 value = CompileRun("(function(o){return o(49)})(obj)"); 11763 CHECK(!try_catch.HasCaught()); 11764 CHECK_EQ(49, value->Int32Value(context.local()).FromJust()); 11765 11766 // test special case of call as function 11767 value = CompileRun("[obj]['0'](45)"); 11768 CHECK(!try_catch.HasCaught()); 11769 CHECK_EQ(45, value->Int32Value(context.local()).FromJust()); 11770 11771 value = CompileRun( 11772 "obj.call = Function.prototype.call;" 11773 "obj.call(null, 87)"); 11774 CHECK(!try_catch.HasCaught()); 11775 CHECK_EQ(87, value->Int32Value(context.local()).FromJust()); 11776 11777 // Regression tests for bug #1116356: Calling call through call/apply 11778 // must work for non-function receivers. 11779 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 11780 value = CompileRun(apply_99); 11781 CHECK(!try_catch.HasCaught()); 11782 CHECK_EQ(99, value->Int32Value(context.local()).FromJust()); 11783 11784 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 11785 value = CompileRun(call_17); 11786 CHECK(!try_catch.HasCaught()); 11787 CHECK_EQ(17, value->Int32Value(context.local()).FromJust()); 11788 11789 // Check that the call-as-function handler can be called through 11790 // new. 11791 value = CompileRun("new obj(43)"); 11792 CHECK(!try_catch.HasCaught()); 11793 CHECK_EQ(-43, value->Int32Value(context.local()).FromJust()); 11794 11795 // Check that the call-as-function handler can be called through 11796 // the API. 11797 v8::Local<Value> args[] = {v8_num(28)}; 11798 value = instance->CallAsFunction(context.local(), instance, 1, args) 11799 .ToLocalChecked(); 11800 CHECK(!try_catch.HasCaught()); 11801 CHECK_EQ(28, value->Int32Value(context.local()).FromJust()); 11802 } 11803 11804 { 11805 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11806 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 11807 USE(instance_template); 11808 Local<v8::Object> instance = t->GetFunction(context.local()) 11809 .ToLocalChecked() 11810 ->NewInstance(context.local()) 11811 .ToLocalChecked(); 11812 CHECK(context->Global() 11813 ->Set(context.local(), v8_str("obj2"), instance) 11814 .FromJust()); 11815 v8::TryCatch try_catch(isolate); 11816 Local<Value> value; 11817 CHECK(!try_catch.HasCaught()); 11818 11819 // Call an object without call-as-function handler through the JS 11820 value = CompileRun("obj2(28)"); 11821 CHECK(value.IsEmpty()); 11822 CHECK(try_catch.HasCaught()); 11823 String::Utf8Value exception_value1(try_catch.Exception()); 11824 // TODO(verwaest): Better message 11825 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1)); 11826 try_catch.Reset(); 11827 11828 // Call an object without call-as-function handler through the API 11829 value = CompileRun("obj2(28)"); 11830 v8::Local<Value> args[] = {v8_num(28)}; 11831 CHECK( 11832 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty()); 11833 CHECK(try_catch.HasCaught()); 11834 String::Utf8Value exception_value2(try_catch.Exception()); 11835 CHECK_EQ(0, 11836 strcmp("TypeError: object is not a function", *exception_value2)); 11837 try_catch.Reset(); 11838 } 11839 11840 { 11841 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11842 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11843 instance_template->SetCallAsFunctionHandler(ThrowValue); 11844 Local<v8::Object> instance = t->GetFunction(context.local()) 11845 .ToLocalChecked() 11846 ->NewInstance(context.local()) 11847 .ToLocalChecked(); 11848 CHECK(context->Global() 11849 ->Set(context.local(), v8_str("obj3"), instance) 11850 .FromJust()); 11851 v8::TryCatch try_catch(isolate); 11852 Local<Value> value; 11853 CHECK(!try_catch.HasCaught()); 11854 11855 // Catch the exception which is thrown by call-as-function handler 11856 value = CompileRun("obj3(22)"); 11857 CHECK(try_catch.HasCaught()); 11858 String::Utf8Value exception_value1(try_catch.Exception()); 11859 CHECK_EQ(0, strcmp("22", *exception_value1)); 11860 try_catch.Reset(); 11861 11862 v8::Local<Value> args[] = {v8_num(23)}; 11863 CHECK( 11864 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty()); 11865 CHECK(try_catch.HasCaught()); 11866 String::Utf8Value exception_value2(try_catch.Exception()); 11867 CHECK_EQ(0, strcmp("23", *exception_value2)); 11868 try_catch.Reset(); 11869 } 11870 11871 { 11872 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11873 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11874 instance_template->SetCallAsFunctionHandler(ReturnThis); 11875 Local<v8::Object> instance = t->GetFunction(context.local()) 11876 .ToLocalChecked() 11877 ->NewInstance(context.local()) 11878 .ToLocalChecked(); 11879 11880 Local<v8::Value> a1 = 11881 instance->CallAsFunction(context.local(), v8::Undefined(isolate), 0, 11882 NULL) 11883 .ToLocalChecked(); 11884 CHECK(a1->StrictEquals(instance)); 11885 Local<v8::Value> a2 = 11886 instance->CallAsFunction(context.local(), v8::Null(isolate), 0, NULL) 11887 .ToLocalChecked(); 11888 CHECK(a2->StrictEquals(instance)); 11889 Local<v8::Value> a3 = 11890 instance->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11891 .ToLocalChecked(); 11892 CHECK(a3->StrictEquals(instance)); 11893 Local<v8::Value> a4 = 11894 instance->CallAsFunction(context.local(), v8_str("hello"), 0, NULL) 11895 .ToLocalChecked(); 11896 CHECK(a4->StrictEquals(instance)); 11897 Local<v8::Value> a5 = 11898 instance->CallAsFunction(context.local(), v8::True(isolate), 0, NULL) 11899 .ToLocalChecked(); 11900 CHECK(a5->StrictEquals(instance)); 11901 } 11902 11903 { 11904 CompileRun( 11905 "function ReturnThisSloppy() {" 11906 " return this;" 11907 "}" 11908 "function ReturnThisStrict() {" 11909 " 'use strict';" 11910 " return this;" 11911 "}"); 11912 Local<Function> ReturnThisSloppy = Local<Function>::Cast( 11913 context->Global() 11914 ->Get(context.local(), v8_str("ReturnThisSloppy")) 11915 .ToLocalChecked()); 11916 Local<Function> ReturnThisStrict = Local<Function>::Cast( 11917 context->Global() 11918 ->Get(context.local(), v8_str("ReturnThisStrict")) 11919 .ToLocalChecked()); 11920 11921 Local<v8::Value> a1 = 11922 ReturnThisSloppy->CallAsFunction(context.local(), 11923 v8::Undefined(isolate), 0, NULL) 11924 .ToLocalChecked(); 11925 CHECK(a1->StrictEquals(context->Global())); 11926 Local<v8::Value> a2 = 11927 ReturnThisSloppy->CallAsFunction(context.local(), v8::Null(isolate), 0, 11928 NULL) 11929 .ToLocalChecked(); 11930 CHECK(a2->StrictEquals(context->Global())); 11931 Local<v8::Value> a3 = 11932 ReturnThisSloppy->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11933 .ToLocalChecked(); 11934 CHECK(a3->IsNumberObject()); 11935 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf()); 11936 Local<v8::Value> a4 = 11937 ReturnThisSloppy->CallAsFunction(context.local(), v8_str("hello"), 0, 11938 NULL) 11939 .ToLocalChecked(); 11940 CHECK(a4->IsStringObject()); 11941 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 11942 Local<v8::Value> a5 = 11943 ReturnThisSloppy->CallAsFunction(context.local(), v8::True(isolate), 0, 11944 NULL) 11945 .ToLocalChecked(); 11946 CHECK(a5->IsBooleanObject()); 11947 CHECK(a5.As<v8::BooleanObject>()->ValueOf()); 11948 11949 Local<v8::Value> a6 = 11950 ReturnThisStrict->CallAsFunction(context.local(), 11951 v8::Undefined(isolate), 0, NULL) 11952 .ToLocalChecked(); 11953 CHECK(a6->IsUndefined()); 11954 Local<v8::Value> a7 = 11955 ReturnThisStrict->CallAsFunction(context.local(), v8::Null(isolate), 0, 11956 NULL) 11957 .ToLocalChecked(); 11958 CHECK(a7->IsNull()); 11959 Local<v8::Value> a8 = 11960 ReturnThisStrict->CallAsFunction(context.local(), v8_num(42), 0, NULL) 11961 .ToLocalChecked(); 11962 CHECK(a8->StrictEquals(v8_num(42))); 11963 Local<v8::Value> a9 = 11964 ReturnThisStrict->CallAsFunction(context.local(), v8_str("hello"), 0, 11965 NULL) 11966 .ToLocalChecked(); 11967 CHECK(a9->StrictEquals(v8_str("hello"))); 11968 Local<v8::Value> a10 = 11969 ReturnThisStrict->CallAsFunction(context.local(), v8::True(isolate), 0, 11970 NULL) 11971 .ToLocalChecked(); 11972 CHECK(a10->StrictEquals(v8::True(isolate))); 11973 } 11974 } 11975 11976 11977 // Check whether a non-function object is callable. 11978 THREADED_TEST(CallableObject) { 11979 LocalContext context; 11980 v8::Isolate* isolate = context->GetIsolate(); 11981 v8::HandleScope scope(isolate); 11982 11983 { 11984 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11985 instance_template->SetCallAsFunctionHandler(call_as_function); 11986 Local<Object> instance = 11987 instance_template->NewInstance(context.local()).ToLocalChecked(); 11988 v8::TryCatch try_catch(isolate); 11989 11990 CHECK(instance->IsCallable()); 11991 CHECK(!try_catch.HasCaught()); 11992 } 11993 11994 { 11995 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11996 Local<Object> instance = 11997 instance_template->NewInstance(context.local()).ToLocalChecked(); 11998 v8::TryCatch try_catch(isolate); 11999 12000 CHECK(!instance->IsCallable()); 12001 CHECK(!try_catch.HasCaught()); 12002 } 12003 12004 { 12005 Local<FunctionTemplate> function_template = 12006 FunctionTemplate::New(isolate, call_as_function); 12007 Local<Function> function = 12008 function_template->GetFunction(context.local()).ToLocalChecked(); 12009 Local<Object> instance = function; 12010 v8::TryCatch try_catch(isolate); 12011 12012 CHECK(instance->IsCallable()); 12013 CHECK(!try_catch.HasCaught()); 12014 } 12015 12016 { 12017 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate); 12018 Local<Function> function = 12019 function_template->GetFunction(context.local()).ToLocalChecked(); 12020 Local<Object> instance = function; 12021 v8::TryCatch try_catch(isolate); 12022 12023 CHECK(instance->IsCallable()); 12024 CHECK(!try_catch.HasCaught()); 12025 } 12026 } 12027 12028 12029 THREADED_TEST(Regress567998) { 12030 LocalContext env; 12031 v8::HandleScope scope(env->GetIsolate()); 12032 12033 Local<v8::FunctionTemplate> desc = 12034 v8::FunctionTemplate::New(env->GetIsolate()); 12035 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 12036 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable 12037 12038 Local<v8::Object> obj = desc->GetFunction(env.local()) 12039 .ToLocalChecked() 12040 ->NewInstance(env.local()) 12041 .ToLocalChecked(); 12042 CHECK( 12043 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust()); 12044 12045 ExpectString("undetectable.toString()", "[object Object]"); 12046 ExpectString("typeof undetectable", "undefined"); 12047 ExpectString("typeof(undetectable)", "undefined"); 12048 ExpectBoolean("typeof undetectable == 'undefined'", true); 12049 ExpectBoolean("typeof undetectable == 'object'", false); 12050 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 12051 ExpectBoolean("!undetectable", true); 12052 12053 ExpectObject("true&&undetectable", obj); 12054 ExpectBoolean("false&&undetectable", false); 12055 ExpectBoolean("true||undetectable", true); 12056 ExpectObject("false||undetectable", obj); 12057 12058 ExpectObject("undetectable&&true", obj); 12059 ExpectObject("undetectable&&false", obj); 12060 ExpectBoolean("undetectable||true", true); 12061 ExpectBoolean("undetectable||false", false); 12062 12063 ExpectBoolean("undetectable==null", true); 12064 ExpectBoolean("null==undetectable", true); 12065 ExpectBoolean("undetectable==undefined", true); 12066 ExpectBoolean("undefined==undetectable", true); 12067 ExpectBoolean("undetectable==undetectable", true); 12068 12069 ExpectBoolean("undetectable===null", false); 12070 ExpectBoolean("null===undetectable", false); 12071 ExpectBoolean("undetectable===undefined", false); 12072 ExpectBoolean("undefined===undetectable", false); 12073 ExpectBoolean("undetectable===undetectable", true); 12074 } 12075 12076 12077 static int Recurse(v8::Isolate* isolate, int depth, int iterations) { 12078 v8::HandleScope scope(isolate); 12079 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate); 12080 for (int i = 0; i < iterations; i++) { 12081 Local<v8::Number> n(v8::Integer::New(isolate, 42)); 12082 } 12083 return Recurse(isolate, depth - 1, iterations); 12084 } 12085 12086 12087 THREADED_TEST(HandleIteration) { 12088 static const int kIterations = 500; 12089 static const int kNesting = 200; 12090 LocalContext context; 12091 v8::Isolate* isolate = context->GetIsolate(); 12092 v8::HandleScope scope0(isolate); 12093 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 12094 { 12095 v8::HandleScope scope1(isolate); 12096 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 12097 for (int i = 0; i < kIterations; i++) { 12098 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 12099 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate)); 12100 } 12101 12102 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 12103 { 12104 v8::HandleScope scope2(CcTest::isolate()); 12105 for (int j = 0; j < kIterations; j++) { 12106 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 12107 CHECK_EQ(j + 1 + kIterations, 12108 v8::HandleScope::NumberOfHandles(isolate)); 12109 } 12110 } 12111 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 12112 } 12113 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 12114 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations)); 12115 } 12116 12117 12118 static void InterceptorCallICFastApi( 12119 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 12120 ApiTestFuzzer::Fuzz(); 12121 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 12122 int* call_count = 12123 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 12124 ++(*call_count); 12125 if ((*call_count) % 20 == 0) { 12126 CcTest::heap()->CollectAllGarbage(); 12127 } 12128 } 12129 12130 static void FastApiCallback_TrivialSignature( 12131 const v8::FunctionCallbackInfo<v8::Value>& args) { 12132 ApiTestFuzzer::Fuzz(); 12133 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 12134 v8::Isolate* isolate = CcTest::isolate(); 12135 CHECK_EQ(isolate, args.GetIsolate()); 12136 CHECK(args.This() 12137 ->Equals(isolate->GetCurrentContext(), args.Holder()) 12138 .FromJust()); 12139 CHECK(args.Data() 12140 ->Equals(isolate->GetCurrentContext(), v8_str("method_data")) 12141 .FromJust()); 12142 args.GetReturnValue().Set( 12143 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1); 12144 } 12145 12146 static void FastApiCallback_SimpleSignature( 12147 const v8::FunctionCallbackInfo<v8::Value>& args) { 12148 ApiTestFuzzer::Fuzz(); 12149 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 12150 v8::Isolate* isolate = CcTest::isolate(); 12151 CHECK_EQ(isolate, args.GetIsolate()); 12152 CHECK(args.This() 12153 ->GetPrototype() 12154 ->Equals(isolate->GetCurrentContext(), args.Holder()) 12155 .FromJust()); 12156 CHECK(args.Data() 12157 ->Equals(isolate->GetCurrentContext(), v8_str("method_data")) 12158 .FromJust()); 12159 // Note, we're using HasRealNamedProperty instead of Has to avoid 12160 // invoking the interceptor again. 12161 CHECK(args.Holder() 12162 ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo")) 12163 .FromJust()); 12164 args.GetReturnValue().Set( 12165 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1); 12166 } 12167 12168 12169 // Helper to maximize the odds of object moving. 12170 static void GenerateSomeGarbage() { 12171 CompileRun( 12172 "var garbage;" 12173 "for (var i = 0; i < 1000; i++) {" 12174 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 12175 "}" 12176 "garbage = undefined;"); 12177 } 12178 12179 12180 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 12181 static int count = 0; 12182 if (count++ % 3 == 0) { 12183 CcTest::heap()->CollectAllGarbage(); 12184 // This should move the stub 12185 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 12186 } 12187 } 12188 12189 12190 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 12191 LocalContext context; 12192 v8::Isolate* isolate = context->GetIsolate(); 12193 v8::HandleScope scope(isolate); 12194 v8::Local<v8::ObjectTemplate> nativeobject_templ = 12195 v8::ObjectTemplate::New(isolate); 12196 nativeobject_templ->Set(isolate, "callback", 12197 v8::FunctionTemplate::New(isolate, 12198 DirectApiCallback)); 12199 v8::Local<v8::Object> nativeobject_obj = 12200 nativeobject_templ->NewInstance(context.local()).ToLocalChecked(); 12201 CHECK(context->Global() 12202 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj) 12203 .FromJust()); 12204 // call the api function multiple times to ensure direct call stub creation. 12205 CompileRun( 12206 "function f() {" 12207 " for (var i = 1; i <= 30; i++) {" 12208 " nativeobject.callback();" 12209 " }" 12210 "}" 12211 "f();"); 12212 } 12213 12214 12215 void ThrowingDirectApiCallback( 12216 const v8::FunctionCallbackInfo<v8::Value>& args) { 12217 args.GetIsolate()->ThrowException(v8_str("g")); 12218 } 12219 12220 12221 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 12222 LocalContext context; 12223 v8::Isolate* isolate = context->GetIsolate(); 12224 v8::HandleScope scope(isolate); 12225 v8::Local<v8::ObjectTemplate> nativeobject_templ = 12226 v8::ObjectTemplate::New(isolate); 12227 nativeobject_templ->Set(isolate, "callback", 12228 v8::FunctionTemplate::New(isolate, 12229 ThrowingDirectApiCallback)); 12230 v8::Local<v8::Object> nativeobject_obj = 12231 nativeobject_templ->NewInstance(context.local()).ToLocalChecked(); 12232 CHECK(context->Global() 12233 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj) 12234 .FromJust()); 12235 // call the api function multiple times to ensure direct call stub creation. 12236 v8::Local<Value> result = CompileRun( 12237 "var result = '';" 12238 "function f() {" 12239 " for (var i = 1; i <= 5; i++) {" 12240 " try { nativeobject.callback(); } catch (e) { result += e; }" 12241 " }" 12242 "}" 12243 "f(); result;"); 12244 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust()); 12245 } 12246 12247 12248 static int p_getter_count_3; 12249 12250 12251 static Local<Value> DoDirectGetter() { 12252 if (++p_getter_count_3 % 3 == 0) { 12253 CcTest::heap()->CollectAllGarbage(); 12254 GenerateSomeGarbage(); 12255 } 12256 return v8_str("Direct Getter Result"); 12257 } 12258 12259 12260 static void DirectGetterCallback( 12261 Local<String> name, 12262 const v8::PropertyCallbackInfo<v8::Value>& info) { 12263 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 12264 info.GetReturnValue().Set(DoDirectGetter()); 12265 } 12266 12267 12268 template<typename Accessor> 12269 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 12270 LocalContext context; 12271 v8::Isolate* isolate = context->GetIsolate(); 12272 v8::HandleScope scope(isolate); 12273 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12274 obj->SetAccessor(v8_str("p1"), accessor); 12275 CHECK(context->Global() 12276 ->Set(context.local(), v8_str("o1"), 12277 obj->NewInstance(context.local()).ToLocalChecked()) 12278 .FromJust()); 12279 p_getter_count_3 = 0; 12280 v8::Local<v8::Value> result = CompileRun( 12281 "function f() {" 12282 " for (var i = 0; i < 30; i++) o1.p1;" 12283 " return o1.p1" 12284 "}" 12285 "f();"); 12286 CHECK(v8_str("Direct Getter Result") 12287 ->Equals(context.local(), result) 12288 .FromJust()); 12289 CHECK_EQ(31, p_getter_count_3); 12290 } 12291 12292 12293 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 12294 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 12295 } 12296 12297 12298 void ThrowingDirectGetterCallback( 12299 Local<String> name, 12300 const v8::PropertyCallbackInfo<v8::Value>& info) { 12301 info.GetIsolate()->ThrowException(v8_str("g")); 12302 } 12303 12304 12305 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 12306 LocalContext context; 12307 v8::Isolate* isolate = context->GetIsolate(); 12308 v8::HandleScope scope(isolate); 12309 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12310 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 12311 CHECK(context->Global() 12312 ->Set(context.local(), v8_str("o1"), 12313 obj->NewInstance(context.local()).ToLocalChecked()) 12314 .FromJust()); 12315 v8::Local<Value> result = CompileRun( 12316 "var result = '';" 12317 "for (var i = 0; i < 5; i++) {" 12318 " try { o1.p1; } catch (e) { result += e; }" 12319 "}" 12320 "result;"); 12321 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust()); 12322 } 12323 12324 12325 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 12326 int interceptor_call_count = 0; 12327 v8::Isolate* isolate = CcTest::isolate(); 12328 v8::HandleScope scope(isolate); 12329 v8::Local<v8::FunctionTemplate> fun_templ = 12330 v8::FunctionTemplate::New(isolate); 12331 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12332 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"), 12333 v8::Local<v8::Signature>()); 12334 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12335 proto_templ->Set(v8_str("method"), method_templ); 12336 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12337 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12338 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12339 v8::External::New(isolate, &interceptor_call_count))); 12340 LocalContext context; 12341 v8::Local<v8::Function> fun = 12342 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12343 GenerateSomeGarbage(); 12344 CHECK(context->Global() 12345 ->Set(context.local(), v8_str("o"), 12346 fun->NewInstance(context.local()).ToLocalChecked()) 12347 .FromJust()); 12348 CompileRun( 12349 "var result = 0;" 12350 "for (var i = 0; i < 100; i++) {" 12351 " result = o.method(41);" 12352 "}"); 12353 CHECK_EQ(42, context->Global() 12354 ->Get(context.local(), v8_str("result")) 12355 .ToLocalChecked() 12356 ->Int32Value(context.local()) 12357 .FromJust()); 12358 CHECK_EQ(100, interceptor_call_count); 12359 } 12360 12361 12362 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 12363 int interceptor_call_count = 0; 12364 v8::Isolate* isolate = CcTest::isolate(); 12365 v8::HandleScope scope(isolate); 12366 v8::Local<v8::FunctionTemplate> fun_templ = 12367 v8::FunctionTemplate::New(isolate); 12368 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12369 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12370 v8::Signature::New(isolate, fun_templ)); 12371 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12372 proto_templ->Set(v8_str("method"), method_templ); 12373 fun_templ->SetHiddenPrototype(true); 12374 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12375 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12376 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12377 v8::External::New(isolate, &interceptor_call_count))); 12378 LocalContext context; 12379 v8::Local<v8::Function> fun = 12380 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12381 GenerateSomeGarbage(); 12382 CHECK(context->Global() 12383 ->Set(context.local(), v8_str("o"), 12384 fun->NewInstance(context.local()).ToLocalChecked()) 12385 .FromJust()); 12386 CompileRun( 12387 "o.foo = 17;" 12388 "var receiver = {};" 12389 "receiver.__proto__ = o;" 12390 "var result = 0;" 12391 "for (var i = 0; i < 100; i++) {" 12392 " result = receiver.method(41);" 12393 "}"); 12394 CHECK_EQ(42, context->Global() 12395 ->Get(context.local(), v8_str("result")) 12396 .ToLocalChecked() 12397 ->Int32Value(context.local()) 12398 .FromJust()); 12399 CHECK_EQ(100, interceptor_call_count); 12400 } 12401 12402 12403 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 12404 int interceptor_call_count = 0; 12405 v8::Isolate* isolate = CcTest::isolate(); 12406 v8::HandleScope scope(isolate); 12407 v8::Local<v8::FunctionTemplate> fun_templ = 12408 v8::FunctionTemplate::New(isolate); 12409 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12410 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12411 v8::Signature::New(isolate, fun_templ)); 12412 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12413 proto_templ->Set(v8_str("method"), method_templ); 12414 fun_templ->SetHiddenPrototype(true); 12415 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12416 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12417 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12418 v8::External::New(isolate, &interceptor_call_count))); 12419 LocalContext context; 12420 v8::Local<v8::Function> fun = 12421 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12422 GenerateSomeGarbage(); 12423 CHECK(context->Global() 12424 ->Set(context.local(), v8_str("o"), 12425 fun->NewInstance(context.local()).ToLocalChecked()) 12426 .FromJust()); 12427 CompileRun( 12428 "o.foo = 17;" 12429 "var receiver = {};" 12430 "receiver.__proto__ = o;" 12431 "var result = 0;" 12432 "var saved_result = 0;" 12433 "for (var i = 0; i < 100; i++) {" 12434 " result = receiver.method(41);" 12435 " if (i == 50) {" 12436 " saved_result = result;" 12437 " receiver = {method: function(x) { return x - 1 }};" 12438 " }" 12439 "}"); 12440 CHECK_EQ(40, context->Global() 12441 ->Get(context.local(), v8_str("result")) 12442 .ToLocalChecked() 12443 ->Int32Value(context.local()) 12444 .FromJust()); 12445 CHECK_EQ(42, context->Global() 12446 ->Get(context.local(), v8_str("saved_result")) 12447 .ToLocalChecked() 12448 ->Int32Value(context.local()) 12449 .FromJust()); 12450 CHECK_GE(interceptor_call_count, 50); 12451 } 12452 12453 12454 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 12455 int interceptor_call_count = 0; 12456 v8::Isolate* isolate = CcTest::isolate(); 12457 v8::HandleScope scope(isolate); 12458 v8::Local<v8::FunctionTemplate> fun_templ = 12459 v8::FunctionTemplate::New(isolate); 12460 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12461 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12462 v8::Signature::New(isolate, fun_templ)); 12463 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12464 proto_templ->Set(v8_str("method"), method_templ); 12465 fun_templ->SetHiddenPrototype(true); 12466 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12467 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12468 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12469 v8::External::New(isolate, &interceptor_call_count))); 12470 LocalContext context; 12471 v8::Local<v8::Function> fun = 12472 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12473 GenerateSomeGarbage(); 12474 CHECK(context->Global() 12475 ->Set(context.local(), v8_str("o"), 12476 fun->NewInstance(context.local()).ToLocalChecked()) 12477 .FromJust()); 12478 CompileRun( 12479 "o.foo = 17;" 12480 "var receiver = {};" 12481 "receiver.__proto__ = o;" 12482 "var result = 0;" 12483 "var saved_result = 0;" 12484 "for (var i = 0; i < 100; i++) {" 12485 " result = receiver.method(41);" 12486 " if (i == 50) {" 12487 " saved_result = result;" 12488 " o.method = function(x) { return x - 1 };" 12489 " }" 12490 "}"); 12491 CHECK_EQ(40, context->Global() 12492 ->Get(context.local(), v8_str("result")) 12493 .ToLocalChecked() 12494 ->Int32Value(context.local()) 12495 .FromJust()); 12496 CHECK_EQ(42, context->Global() 12497 ->Get(context.local(), v8_str("saved_result")) 12498 .ToLocalChecked() 12499 ->Int32Value(context.local()) 12500 .FromJust()); 12501 CHECK_GE(interceptor_call_count, 50); 12502 } 12503 12504 12505 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 12506 int interceptor_call_count = 0; 12507 v8::Isolate* isolate = CcTest::isolate(); 12508 v8::HandleScope scope(isolate); 12509 v8::Local<v8::FunctionTemplate> fun_templ = 12510 v8::FunctionTemplate::New(isolate); 12511 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12512 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12513 v8::Signature::New(isolate, fun_templ)); 12514 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12515 proto_templ->Set(v8_str("method"), method_templ); 12516 fun_templ->SetHiddenPrototype(true); 12517 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12518 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12519 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12520 v8::External::New(isolate, &interceptor_call_count))); 12521 LocalContext context; 12522 v8::Local<v8::Function> fun = 12523 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12524 GenerateSomeGarbage(); 12525 CHECK(context->Global() 12526 ->Set(context.local(), v8_str("o"), 12527 fun->NewInstance(context.local()).ToLocalChecked()) 12528 .FromJust()); 12529 v8::TryCatch try_catch(isolate); 12530 CompileRun( 12531 "o.foo = 17;" 12532 "var receiver = {};" 12533 "receiver.__proto__ = o;" 12534 "var result = 0;" 12535 "var saved_result = 0;" 12536 "for (var i = 0; i < 100; i++) {" 12537 " result = receiver.method(41);" 12538 " if (i == 50) {" 12539 " saved_result = result;" 12540 " receiver = 333;" 12541 " }" 12542 "}"); 12543 CHECK(try_catch.HasCaught()); 12544 // TODO(verwaest): Adjust message. 12545 CHECK( 12546 v8_str("TypeError: receiver.method is not a function") 12547 ->Equals( 12548 context.local(), 12549 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12550 .FromJust()); 12551 CHECK_EQ(42, context->Global() 12552 ->Get(context.local(), v8_str("saved_result")) 12553 .ToLocalChecked() 12554 ->Int32Value(context.local()) 12555 .FromJust()); 12556 CHECK_GE(interceptor_call_count, 50); 12557 } 12558 12559 12560 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 12561 int interceptor_call_count = 0; 12562 v8::Isolate* isolate = CcTest::isolate(); 12563 v8::HandleScope scope(isolate); 12564 v8::Local<v8::FunctionTemplate> fun_templ = 12565 v8::FunctionTemplate::New(isolate); 12566 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12567 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12568 v8::Signature::New(isolate, fun_templ)); 12569 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12570 proto_templ->Set(v8_str("method"), method_templ); 12571 fun_templ->SetHiddenPrototype(true); 12572 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12573 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 12574 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12575 v8::External::New(isolate, &interceptor_call_count))); 12576 LocalContext context; 12577 v8::Local<v8::Function> fun = 12578 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12579 GenerateSomeGarbage(); 12580 CHECK(context->Global() 12581 ->Set(context.local(), v8_str("o"), 12582 fun->NewInstance(context.local()).ToLocalChecked()) 12583 .FromJust()); 12584 v8::TryCatch try_catch(isolate); 12585 CompileRun( 12586 "o.foo = 17;" 12587 "var receiver = {};" 12588 "receiver.__proto__ = o;" 12589 "var result = 0;" 12590 "var saved_result = 0;" 12591 "for (var i = 0; i < 100; i++) {" 12592 " result = receiver.method(41);" 12593 " if (i == 50) {" 12594 " saved_result = result;" 12595 " receiver = {method: receiver.method};" 12596 " }" 12597 "}"); 12598 CHECK(try_catch.HasCaught()); 12599 CHECK( 12600 v8_str("TypeError: Illegal invocation") 12601 ->Equals( 12602 context.local(), 12603 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12604 .FromJust()); 12605 CHECK_EQ(42, context->Global() 12606 ->Get(context.local(), v8_str("saved_result")) 12607 .ToLocalChecked() 12608 ->Int32Value(context.local()) 12609 .FromJust()); 12610 CHECK_GE(interceptor_call_count, 50); 12611 } 12612 12613 12614 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 12615 v8::Isolate* isolate = CcTest::isolate(); 12616 v8::HandleScope scope(isolate); 12617 v8::Local<v8::FunctionTemplate> fun_templ = 12618 v8::FunctionTemplate::New(isolate); 12619 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12620 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"), 12621 v8::Local<v8::Signature>()); 12622 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12623 proto_templ->Set(v8_str("method"), method_templ); 12624 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12625 USE(templ); 12626 LocalContext context; 12627 v8::Local<v8::Function> fun = 12628 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12629 GenerateSomeGarbage(); 12630 CHECK(context->Global() 12631 ->Set(context.local(), v8_str("o"), 12632 fun->NewInstance(context.local()).ToLocalChecked()) 12633 .FromJust()); 12634 CompileRun( 12635 "var result = 0;" 12636 "for (var i = 0; i < 100; i++) {" 12637 " result = o.method(41);" 12638 "}"); 12639 12640 CHECK_EQ(42, context->Global() 12641 ->Get(context.local(), v8_str("result")) 12642 .ToLocalChecked() 12643 ->Int32Value(context.local()) 12644 .FromJust()); 12645 } 12646 12647 12648 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 12649 v8::Isolate* isolate = CcTest::isolate(); 12650 v8::HandleScope scope(isolate); 12651 v8::Local<v8::FunctionTemplate> fun_templ = 12652 v8::FunctionTemplate::New(isolate); 12653 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12654 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12655 v8::Signature::New(isolate, fun_templ)); 12656 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12657 proto_templ->Set(v8_str("method"), method_templ); 12658 fun_templ->SetHiddenPrototype(true); 12659 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12660 CHECK(!templ.IsEmpty()); 12661 LocalContext context; 12662 v8::Local<v8::Function> fun = 12663 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12664 GenerateSomeGarbage(); 12665 CHECK(context->Global() 12666 ->Set(context.local(), v8_str("o"), 12667 fun->NewInstance(context.local()).ToLocalChecked()) 12668 .FromJust()); 12669 CompileRun( 12670 "o.foo = 17;" 12671 "var receiver = {};" 12672 "receiver.__proto__ = o;" 12673 "var result = 0;" 12674 "for (var i = 0; i < 100; i++) {" 12675 " result = receiver.method(41);" 12676 "}"); 12677 12678 CHECK_EQ(42, context->Global() 12679 ->Get(context.local(), v8_str("result")) 12680 .ToLocalChecked() 12681 ->Int32Value(context.local()) 12682 .FromJust()); 12683 } 12684 12685 12686 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 12687 v8::Isolate* isolate = CcTest::isolate(); 12688 v8::HandleScope scope(isolate); 12689 v8::Local<v8::FunctionTemplate> fun_templ = 12690 v8::FunctionTemplate::New(isolate); 12691 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12692 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12693 v8::Signature::New(isolate, fun_templ)); 12694 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12695 proto_templ->Set(v8_str("method"), method_templ); 12696 fun_templ->SetHiddenPrototype(true); 12697 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12698 CHECK(!templ.IsEmpty()); 12699 LocalContext context; 12700 v8::Local<v8::Function> fun = 12701 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12702 GenerateSomeGarbage(); 12703 CHECK(context->Global() 12704 ->Set(context.local(), v8_str("o"), 12705 fun->NewInstance(context.local()).ToLocalChecked()) 12706 .FromJust()); 12707 CompileRun( 12708 "o.foo = 17;" 12709 "var receiver = {};" 12710 "receiver.__proto__ = o;" 12711 "var result = 0;" 12712 "var saved_result = 0;" 12713 "for (var i = 0; i < 100; i++) {" 12714 " result = receiver.method(41);" 12715 " if (i == 50) {" 12716 " saved_result = result;" 12717 " receiver = {method: function(x) { return x - 1 }};" 12718 " }" 12719 "}"); 12720 CHECK_EQ(40, context->Global() 12721 ->Get(context.local(), v8_str("result")) 12722 .ToLocalChecked() 12723 ->Int32Value(context.local()) 12724 .FromJust()); 12725 CHECK_EQ(42, context->Global() 12726 ->Get(context.local(), v8_str("saved_result")) 12727 .ToLocalChecked() 12728 ->Int32Value(context.local()) 12729 .FromJust()); 12730 } 12731 12732 12733 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 12734 v8::Isolate* isolate = CcTest::isolate(); 12735 v8::HandleScope scope(isolate); 12736 v8::Local<v8::FunctionTemplate> fun_templ = 12737 v8::FunctionTemplate::New(isolate); 12738 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12739 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12740 v8::Signature::New(isolate, fun_templ)); 12741 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12742 proto_templ->Set(v8_str("method"), method_templ); 12743 fun_templ->SetHiddenPrototype(true); 12744 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12745 CHECK(!templ.IsEmpty()); 12746 LocalContext context; 12747 v8::Local<v8::Function> fun = 12748 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12749 GenerateSomeGarbage(); 12750 CHECK(context->Global() 12751 ->Set(context.local(), v8_str("o"), 12752 fun->NewInstance(context.local()).ToLocalChecked()) 12753 .FromJust()); 12754 v8::TryCatch try_catch(isolate); 12755 CompileRun( 12756 "o.foo = 17;" 12757 "var receiver = {};" 12758 "receiver.__proto__ = o;" 12759 "var result = 0;" 12760 "var saved_result = 0;" 12761 "for (var i = 0; i < 100; i++) {" 12762 " result = receiver.method(41);" 12763 " if (i == 50) {" 12764 " saved_result = result;" 12765 " receiver = 333;" 12766 " }" 12767 "}"); 12768 CHECK(try_catch.HasCaught()); 12769 // TODO(verwaest): Adjust message. 12770 CHECK( 12771 v8_str("TypeError: receiver.method is not a function") 12772 ->Equals( 12773 context.local(), 12774 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12775 .FromJust()); 12776 CHECK_EQ(42, context->Global() 12777 ->Get(context.local(), v8_str("saved_result")) 12778 .ToLocalChecked() 12779 ->Int32Value(context.local()) 12780 .FromJust()); 12781 } 12782 12783 12784 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 12785 v8::Isolate* isolate = CcTest::isolate(); 12786 v8::HandleScope scope(isolate); 12787 v8::Local<v8::FunctionTemplate> fun_templ = 12788 v8::FunctionTemplate::New(isolate); 12789 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12790 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12791 v8::Signature::New(isolate, fun_templ)); 12792 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12793 proto_templ->Set(v8_str("method"), method_templ); 12794 fun_templ->SetHiddenPrototype(true); 12795 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12796 CHECK(!templ.IsEmpty()); 12797 LocalContext context; 12798 v8::Local<v8::Function> fun = 12799 fun_templ->GetFunction(context.local()).ToLocalChecked(); 12800 GenerateSomeGarbage(); 12801 CHECK(context->Global() 12802 ->Set(context.local(), v8_str("o"), 12803 fun->NewInstance(context.local()).ToLocalChecked()) 12804 .FromJust()); 12805 v8::TryCatch try_catch(isolate); 12806 CompileRun( 12807 "o.foo = 17;" 12808 "var receiver = {};" 12809 "receiver.__proto__ = o;" 12810 "var result = 0;" 12811 "var saved_result = 0;" 12812 "for (var i = 0; i < 100; i++) {" 12813 " result = receiver.method(41);" 12814 " if (i == 50) {" 12815 " saved_result = result;" 12816 " receiver = Object.create(receiver);" 12817 " }" 12818 "}"); 12819 CHECK(try_catch.HasCaught()); 12820 CHECK( 12821 v8_str("TypeError: Illegal invocation") 12822 ->Equals( 12823 context.local(), 12824 try_catch.Exception()->ToString(context.local()).ToLocalChecked()) 12825 .FromJust()); 12826 CHECK_EQ(42, context->Global() 12827 ->Get(context.local(), v8_str("saved_result")) 12828 .ToLocalChecked() 12829 ->Int32Value(context.local()) 12830 .FromJust()); 12831 } 12832 12833 12834 static void ThrowingGetter(Local<String> name, 12835 const v8::PropertyCallbackInfo<v8::Value>& info) { 12836 ApiTestFuzzer::Fuzz(); 12837 info.GetIsolate()->ThrowException(Local<Value>()); 12838 info.GetReturnValue().SetUndefined(); 12839 } 12840 12841 12842 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 12843 LocalContext context; 12844 HandleScope scope(context->GetIsolate()); 12845 12846 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 12847 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 12848 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 12849 12850 Local<Object> instance = templ->GetFunction(context.local()) 12851 .ToLocalChecked() 12852 ->NewInstance(context.local()) 12853 .ToLocalChecked(); 12854 12855 Local<Object> another = Object::New(context->GetIsolate()); 12856 CHECK(another->SetPrototype(context.local(), instance).FromJust()); 12857 12858 Local<Object> with_js_getter = CompileRun( 12859 "o = {};\n" 12860 "o.__defineGetter__('f', function() { throw undefined; });\n" 12861 "o\n").As<Object>(); 12862 CHECK(!with_js_getter.IsEmpty()); 12863 12864 TryCatch try_catch(context->GetIsolate()); 12865 12866 v8::MaybeLocal<Value> result = 12867 instance->GetRealNamedProperty(context.local(), v8_str("f")); 12868 CHECK(try_catch.HasCaught()); 12869 try_catch.Reset(); 12870 CHECK(result.IsEmpty()); 12871 12872 Maybe<PropertyAttribute> attr = 12873 instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f")); 12874 CHECK(!try_catch.HasCaught()); 12875 CHECK(Just(None) == attr); 12876 12877 result = another->GetRealNamedProperty(context.local(), v8_str("f")); 12878 CHECK(try_catch.HasCaught()); 12879 try_catch.Reset(); 12880 CHECK(result.IsEmpty()); 12881 12882 attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f")); 12883 CHECK(!try_catch.HasCaught()); 12884 CHECK(Just(None) == attr); 12885 12886 result = another->GetRealNamedPropertyInPrototypeChain(context.local(), 12887 v8_str("f")); 12888 CHECK(try_catch.HasCaught()); 12889 try_catch.Reset(); 12890 CHECK(result.IsEmpty()); 12891 12892 attr = another->GetRealNamedPropertyAttributesInPrototypeChain( 12893 context.local(), v8_str("f")); 12894 CHECK(!try_catch.HasCaught()); 12895 CHECK(Just(None) == attr); 12896 12897 result = another->Get(context.local(), v8_str("f")); 12898 CHECK(try_catch.HasCaught()); 12899 try_catch.Reset(); 12900 CHECK(result.IsEmpty()); 12901 12902 result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f")); 12903 CHECK(try_catch.HasCaught()); 12904 try_catch.Reset(); 12905 CHECK(result.IsEmpty()); 12906 12907 attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(), 12908 v8_str("f")); 12909 CHECK(!try_catch.HasCaught()); 12910 CHECK(Just(None) == attr); 12911 12912 result = with_js_getter->Get(context.local(), v8_str("f")); 12913 CHECK(try_catch.HasCaught()); 12914 try_catch.Reset(); 12915 CHECK(result.IsEmpty()); 12916 12917 Local<Object> target = CompileRun("({})").As<Object>(); 12918 Local<Object> handler = CompileRun("({})").As<Object>(); 12919 Local<v8::Proxy> proxy = 12920 v8::Proxy::New(context.local(), target, handler).ToLocalChecked(); 12921 12922 result = target->GetRealNamedProperty(context.local(), v8_str("f")); 12923 CHECK(!try_catch.HasCaught()); 12924 CHECK(result.IsEmpty()); 12925 12926 result = proxy->GetRealNamedProperty(context.local(), v8_str("f")); 12927 CHECK(!try_catch.HasCaught()); 12928 CHECK(result.IsEmpty()); 12929 } 12930 12931 12932 static void ThrowingCallbackWithTryCatch( 12933 const v8::FunctionCallbackInfo<v8::Value>& args) { 12934 TryCatch try_catch(args.GetIsolate()); 12935 // Verboseness is important: it triggers message delivery which can call into 12936 // external code. 12937 try_catch.SetVerbose(true); 12938 CompileRun("throw 'from JS';"); 12939 CHECK(try_catch.HasCaught()); 12940 CHECK(!CcTest::i_isolate()->has_pending_exception()); 12941 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 12942 } 12943 12944 12945 static int call_depth; 12946 12947 12948 static void WithTryCatch(Local<Message> message, Local<Value> data) { 12949 TryCatch try_catch(CcTest::isolate()); 12950 } 12951 12952 12953 static void ThrowFromJS(Local<Message> message, Local<Value> data) { 12954 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 12955 } 12956 12957 12958 static void ThrowViaApi(Local<Message> message, Local<Value> data) { 12959 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi")); 12960 } 12961 12962 12963 static void WebKitLike(Local<Message> message, Local<Value> data) { 12964 Local<String> errorMessageString = message->Get(); 12965 CHECK(!errorMessageString.IsEmpty()); 12966 message->GetStackTrace(); 12967 message->GetScriptOrigin().ResourceName(); 12968 } 12969 12970 12971 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 12972 LocalContext context; 12973 v8::Isolate* isolate = context->GetIsolate(); 12974 HandleScope scope(isolate); 12975 12976 Local<Function> func = 12977 FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch) 12978 ->GetFunction(context.local()) 12979 .ToLocalChecked(); 12980 CHECK( 12981 context->Global()->Set(context.local(), v8_str("func"), func).FromJust()); 12982 12983 MessageCallback callbacks[] = 12984 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 12985 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 12986 MessageCallback callback = callbacks[i]; 12987 if (callback != NULL) { 12988 isolate->AddMessageListener(callback); 12989 } 12990 // Some small number to control number of times message handler should 12991 // throw an exception. 12992 call_depth = 5; 12993 ExpectFalse( 12994 "var thrown = false;\n" 12995 "try { func(); } catch(e) { thrown = true; }\n" 12996 "thrown\n"); 12997 if (callback != NULL) { 12998 isolate->RemoveMessageListeners(callback); 12999 } 13000 } 13001 } 13002 13003 13004 static void ParentGetter(Local<String> name, 13005 const v8::PropertyCallbackInfo<v8::Value>& info) { 13006 ApiTestFuzzer::Fuzz(); 13007 info.GetReturnValue().Set(v8_num(1)); 13008 } 13009 13010 13011 static void ChildGetter(Local<String> name, 13012 const v8::PropertyCallbackInfo<v8::Value>& info) { 13013 ApiTestFuzzer::Fuzz(); 13014 info.GetReturnValue().Set(v8_num(42)); 13015 } 13016 13017 13018 THREADED_TEST(Overriding) { 13019 LocalContext context; 13020 v8::Isolate* isolate = context->GetIsolate(); 13021 v8::HandleScope scope(isolate); 13022 13023 // Parent template. 13024 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate); 13025 Local<ObjectTemplate> parent_instance_templ = 13026 parent_templ->InstanceTemplate(); 13027 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 13028 13029 // Template that inherits from the parent template. 13030 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate); 13031 Local<ObjectTemplate> child_instance_templ = 13032 child_templ->InstanceTemplate(); 13033 child_templ->Inherit(parent_templ); 13034 // Override 'f'. The child version of 'f' should get called for child 13035 // instances. 13036 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 13037 // Add 'g' twice. The 'g' added last should get called for instances. 13038 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 13039 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 13040 13041 // Add 'h' as an accessor to the proto template with ReadOnly attributes 13042 // so 'h' can be shadowed on the instance object. 13043 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 13044 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 13045 v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly); 13046 13047 // Add 'i' as an accessor to the instance template with ReadOnly attributes 13048 // but the attribute does not have effect because it is duplicated with 13049 // NULL setter. 13050 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 13051 v8::Local<Value>(), v8::DEFAULT, 13052 v8::ReadOnly); 13053 13054 13055 // Instantiate the child template. 13056 Local<v8::Object> instance = child_templ->GetFunction(context.local()) 13057 .ToLocalChecked() 13058 ->NewInstance(context.local()) 13059 .ToLocalChecked(); 13060 13061 // Check that the child function overrides the parent one. 13062 CHECK(context->Global() 13063 ->Set(context.local(), v8_str("o"), instance) 13064 .FromJust()); 13065 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); 13066 // Check that the 'g' that was added last is hit. 13067 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 13068 value = v8_compile("o.g")->Run(context.local()).ToLocalChecked(); 13069 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 13070 13071 // Check that 'h' cannot be shadowed. 13072 value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked(); 13073 CHECK_EQ(1, value->Int32Value(context.local()).FromJust()); 13074 13075 // Check that 'i' cannot be shadowed or changed. 13076 value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked(); 13077 CHECK_EQ(42, value->Int32Value(context.local()).FromJust()); 13078 } 13079 13080 13081 static void ShouldThrowOnErrorGetter( 13082 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 13083 ApiTestFuzzer::Fuzz(); 13084 v8::Isolate* isolate = info.GetIsolate(); 13085 Local<Boolean> should_throw_on_error = 13086 Boolean::New(isolate, info.ShouldThrowOnError()); 13087 info.GetReturnValue().Set(should_throw_on_error); 13088 } 13089 13090 13091 template <typename T> 13092 static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value, 13093 const v8::PropertyCallbackInfo<T>& info) { 13094 ApiTestFuzzer::Fuzz(); 13095 v8::Isolate* isolate = info.GetIsolate(); 13096 auto context = isolate->GetCurrentContext(); 13097 Local<Boolean> should_throw_on_error_value = 13098 Boolean::New(isolate, info.ShouldThrowOnError()); 13099 CHECK(context->Global() 13100 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"), 13101 should_throw_on_error_value) 13102 .FromJust()); 13103 } 13104 13105 13106 THREADED_TEST(AccessorShouldThrowOnError) { 13107 LocalContext context; 13108 v8::Isolate* isolate = context->GetIsolate(); 13109 v8::HandleScope scope(isolate); 13110 Local<Object> global = context->Global(); 13111 13112 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13113 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 13114 instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter, 13115 ShouldThrowOnErrorSetter<void>); 13116 13117 Local<v8::Object> instance = templ->GetFunction(context.local()) 13118 .ToLocalChecked() 13119 ->NewInstance(context.local()) 13120 .ToLocalChecked(); 13121 13122 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust()); 13123 13124 // SLOPPY mode 13125 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); 13126 CHECK(value->IsFalse()); 13127 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked(); 13128 value = global->Get(context.local(), v8_str("should_throw_setter")) 13129 .ToLocalChecked(); 13130 CHECK(value->IsFalse()); 13131 13132 // STRICT mode 13133 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked(); 13134 CHECK(value->IsFalse()); 13135 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked(); 13136 value = global->Get(context.local(), v8_str("should_throw_setter")) 13137 .ToLocalChecked(); 13138 CHECK(value->IsTrue()); 13139 } 13140 13141 13142 static void ShouldThrowOnErrorQuery( 13143 Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) { 13144 ApiTestFuzzer::Fuzz(); 13145 v8::Isolate* isolate = info.GetIsolate(); 13146 info.GetReturnValue().Set(v8::None); 13147 13148 auto context = isolate->GetCurrentContext(); 13149 Local<Boolean> should_throw_on_error_value = 13150 Boolean::New(isolate, info.ShouldThrowOnError()); 13151 CHECK(context->Global() 13152 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"), 13153 should_throw_on_error_value) 13154 .FromJust()); 13155 } 13156 13157 13158 static void ShouldThrowOnErrorDeleter( 13159 Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) { 13160 ApiTestFuzzer::Fuzz(); 13161 v8::Isolate* isolate = info.GetIsolate(); 13162 info.GetReturnValue().Set(v8::True(isolate)); 13163 13164 auto context = isolate->GetCurrentContext(); 13165 Local<Boolean> should_throw_on_error_value = 13166 Boolean::New(isolate, info.ShouldThrowOnError()); 13167 CHECK(context->Global() 13168 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"), 13169 should_throw_on_error_value) 13170 .FromJust()); 13171 } 13172 13173 13174 static void ShouldThrowOnErrorPropertyEnumerator( 13175 const v8::PropertyCallbackInfo<v8::Array>& info) { 13176 ApiTestFuzzer::Fuzz(); 13177 v8::Isolate* isolate = info.GetIsolate(); 13178 Local<v8::Array> names = v8::Array::New(isolate, 1); 13179 CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust()); 13180 info.GetReturnValue().Set(names); 13181 13182 auto context = isolate->GetCurrentContext(); 13183 Local<Boolean> should_throw_on_error_value = 13184 Boolean::New(isolate, info.ShouldThrowOnError()); 13185 CHECK(context->Global() 13186 ->Set(isolate->GetCurrentContext(), 13187 v8_str("should_throw_enumerator"), 13188 should_throw_on_error_value) 13189 .FromJust()); 13190 } 13191 13192 13193 THREADED_TEST(InterceptorShouldThrowOnError) { 13194 LocalContext context; 13195 v8::Isolate* isolate = context->GetIsolate(); 13196 v8::HandleScope scope(isolate); 13197 Local<Object> global = context->Global(); 13198 13199 auto interceptor_templ = v8::ObjectTemplate::New(isolate); 13200 v8::NamedPropertyHandlerConfiguration handler( 13201 ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>, 13202 ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter, 13203 ShouldThrowOnErrorPropertyEnumerator); 13204 interceptor_templ->SetHandler(handler); 13205 13206 Local<v8::Object> instance = 13207 interceptor_templ->NewInstance(context.local()).ToLocalChecked(); 13208 13209 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust()); 13210 13211 // SLOPPY mode 13212 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); 13213 CHECK(value->IsFalse()); 13214 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked(); 13215 value = global->Get(context.local(), v8_str("should_throw_setter")) 13216 .ToLocalChecked(); 13217 CHECK(value->IsFalse()); 13218 13219 v8_compile("delete o.f")->Run(context.local()).ToLocalChecked(); 13220 value = global->Get(context.local(), v8_str("should_throw_deleter")) 13221 .ToLocalChecked(); 13222 CHECK(value->IsFalse()); 13223 13224 v8_compile("Object.getOwnPropertyNames(o)") 13225 ->Run(context.local()) 13226 .ToLocalChecked(); 13227 value = global->Get(context.local(), v8_str("should_throw_enumerator")) 13228 .ToLocalChecked(); 13229 CHECK(value->IsFalse()); 13230 13231 // STRICT mode 13232 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked(); 13233 CHECK(value->IsFalse()); 13234 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked(); 13235 value = global->Get(context.local(), v8_str("should_throw_setter")) 13236 .ToLocalChecked(); 13237 CHECK(value->IsTrue()); 13238 13239 v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked(); 13240 value = global->Get(context.local(), v8_str("should_throw_deleter")) 13241 .ToLocalChecked(); 13242 CHECK(value->IsTrue()); 13243 13244 v8_compile("'use strict'; Object.getOwnPropertyNames(o)") 13245 ->Run(context.local()) 13246 .ToLocalChecked(); 13247 value = global->Get(context.local(), v8_str("should_throw_enumerator")) 13248 .ToLocalChecked(); 13249 CHECK(value->IsFalse()); 13250 } 13251 13252 13253 static void IsConstructHandler( 13254 const v8::FunctionCallbackInfo<v8::Value>& args) { 13255 ApiTestFuzzer::Fuzz(); 13256 args.GetReturnValue().Set(args.IsConstructCall()); 13257 } 13258 13259 13260 THREADED_TEST(IsConstructCall) { 13261 v8::Isolate* isolate = CcTest::isolate(); 13262 v8::HandleScope scope(isolate); 13263 13264 // Function template with call handler. 13265 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13266 templ->SetCallHandler(IsConstructHandler); 13267 13268 LocalContext context; 13269 13270 CHECK(context->Global() 13271 ->Set(context.local(), v8_str("f"), 13272 templ->GetFunction(context.local()).ToLocalChecked()) 13273 .FromJust()); 13274 Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked(); 13275 CHECK(!value->BooleanValue(context.local()).FromJust()); 13276 value = v8_compile("new f()")->Run(context.local()).ToLocalChecked(); 13277 CHECK(value->BooleanValue(context.local()).FromJust()); 13278 } 13279 13280 static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 13281 ApiTestFuzzer::Fuzz(); 13282 args.GetReturnValue().Set(args.NewTarget()); 13283 } 13284 13285 THREADED_TEST(NewTargetHandler) { 13286 v8::Isolate* isolate = CcTest::isolate(); 13287 v8::HandleScope scope(isolate); 13288 13289 // Function template with call handler. 13290 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13291 templ->SetCallHandler(NewTargetHandler); 13292 13293 LocalContext context; 13294 13295 Local<Function> function = 13296 templ->GetFunction(context.local()).ToLocalChecked(); 13297 CHECK(context->Global() 13298 ->Set(context.local(), v8_str("f"), function) 13299 .FromJust()); 13300 Local<Value> value = CompileRun("f()"); 13301 CHECK(value->IsUndefined()); 13302 value = CompileRun("new f()"); 13303 CHECK(value->IsFunction()); 13304 CHECK(value == function); 13305 Local<Value> subclass = CompileRun("var g = class extends f { }; g"); 13306 CHECK(subclass->IsFunction()); 13307 value = CompileRun("new g()"); 13308 CHECK(value->IsFunction()); 13309 CHECK(value == subclass); 13310 value = CompileRun("Reflect.construct(f, [], Array)"); 13311 CHECK(value->IsFunction()); 13312 CHECK(value == 13313 context->Global() 13314 ->Get(context.local(), v8_str("Array")) 13315 .ToLocalChecked()); 13316 } 13317 13318 THREADED_TEST(ObjectProtoToString) { 13319 v8::Isolate* isolate = CcTest::isolate(); 13320 v8::HandleScope scope(isolate); 13321 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13322 templ->SetClassName(v8_str("MyClass")); 13323 13324 LocalContext context; 13325 13326 Local<String> customized_tostring = v8_str("customized toString"); 13327 13328 // Replace Object.prototype.toString 13329 v8_compile( 13330 "Object.prototype.toString = function() {" 13331 " return 'customized toString';" 13332 "}") 13333 ->Run(context.local()) 13334 .ToLocalChecked(); 13335 13336 // Normal ToString call should call replaced Object.prototype.toString 13337 Local<v8::Object> instance = templ->GetFunction(context.local()) 13338 .ToLocalChecked() 13339 ->NewInstance(context.local()) 13340 .ToLocalChecked(); 13341 Local<String> value = instance->ToString(context.local()).ToLocalChecked(); 13342 CHECK(value->IsString() && 13343 value->Equals(context.local(), customized_tostring).FromJust()); 13344 13345 // ObjectProtoToString should not call replace toString function. 13346 value = instance->ObjectProtoToString(context.local()).ToLocalChecked(); 13347 CHECK(value->IsString() && 13348 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust()); 13349 13350 // Check global 13351 value = 13352 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked(); 13353 CHECK(value->IsString() && 13354 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 13355 13356 // Check ordinary object 13357 Local<Value> object = 13358 v8_compile("new Object()")->Run(context.local()).ToLocalChecked(); 13359 value = object.As<v8::Object>() 13360 ->ObjectProtoToString(context.local()) 13361 .ToLocalChecked(); 13362 CHECK(value->IsString() && 13363 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 13364 } 13365 13366 13367 TEST(ObjectProtoToStringES6) { 13368 LocalContext context; 13369 v8::Isolate* isolate = CcTest::isolate(); 13370 v8::HandleScope scope(isolate); 13371 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13372 templ->SetClassName(v8_str("MyClass")); 13373 13374 Local<String> customized_tostring = v8_str("customized toString"); 13375 13376 // Replace Object.prototype.toString 13377 CompileRun( 13378 "Object.prototype.toString = function() {" 13379 " return 'customized toString';" 13380 "}"); 13381 13382 // Normal ToString call should call replaced Object.prototype.toString 13383 Local<v8::Object> instance = templ->GetFunction(context.local()) 13384 .ToLocalChecked() 13385 ->NewInstance(context.local()) 13386 .ToLocalChecked(); 13387 Local<String> value = instance->ToString(context.local()).ToLocalChecked(); 13388 CHECK(value->IsString() && 13389 value->Equals(context.local(), customized_tostring).FromJust()); 13390 13391 // ObjectProtoToString should not call replace toString function. 13392 value = instance->ObjectProtoToString(context.local()).ToLocalChecked(); 13393 CHECK(value->IsString() && 13394 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust()); 13395 13396 // Check global 13397 value = 13398 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked(); 13399 CHECK(value->IsString() && 13400 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 13401 13402 // Check ordinary object 13403 Local<Value> object = CompileRun("new Object()"); 13404 value = object.As<v8::Object>() 13405 ->ObjectProtoToString(context.local()) 13406 .ToLocalChecked(); 13407 CHECK(value->IsString() && 13408 value->Equals(context.local(), v8_str("[object Object]")).FromJust()); 13409 13410 // Check that ES6 semantics using @@toStringTag work 13411 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate); 13412 13413 #define TEST_TOSTRINGTAG(type, tag, expected) \ 13414 do { \ 13415 object = CompileRun("new " #type "()"); \ 13416 CHECK(object.As<v8::Object>() \ 13417 ->Set(context.local(), toStringTag, v8_str(#tag)) \ 13418 .FromJust()); \ 13419 value = object.As<v8::Object>() \ 13420 ->ObjectProtoToString(context.local()) \ 13421 .ToLocalChecked(); \ 13422 CHECK(value->IsString() && \ 13423 value->Equals(context.local(), v8_str("[object " #expected "]")) \ 13424 .FromJust()); \ 13425 } while (0) 13426 13427 TEST_TOSTRINGTAG(Array, Object, Object); 13428 TEST_TOSTRINGTAG(Object, Arguments, Arguments); 13429 TEST_TOSTRINGTAG(Object, Array, Array); 13430 TEST_TOSTRINGTAG(Object, Boolean, Boolean); 13431 TEST_TOSTRINGTAG(Object, Date, Date); 13432 TEST_TOSTRINGTAG(Object, Error, Error); 13433 TEST_TOSTRINGTAG(Object, Function, Function); 13434 TEST_TOSTRINGTAG(Object, Number, Number); 13435 TEST_TOSTRINGTAG(Object, RegExp, RegExp); 13436 TEST_TOSTRINGTAG(Object, String, String); 13437 TEST_TOSTRINGTAG(Object, Foo, Foo); 13438 13439 #undef TEST_TOSTRINGTAG 13440 13441 Local<v8::RegExp> valueRegExp = 13442 v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone) 13443 .ToLocalChecked(); 13444 Local<Value> valueNumber = v8_num(123); 13445 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol"); 13446 Local<v8::Function> valueFunction = 13447 CompileRun("(function fn() {})").As<v8::Function>(); 13448 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent()); 13449 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent()); 13450 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent()); 13451 13452 #define TEST_TOSTRINGTAG(type, tagValue, expected) \ 13453 do { \ 13454 object = CompileRun("new " #type "()"); \ 13455 CHECK(object.As<v8::Object>() \ 13456 ->Set(context.local(), toStringTag, tagValue) \ 13457 .FromJust()); \ 13458 value = object.As<v8::Object>() \ 13459 ->ObjectProtoToString(context.local()) \ 13460 .ToLocalChecked(); \ 13461 CHECK(value->IsString() && \ 13462 value->Equals(context.local(), v8_str("[object " #expected "]")) \ 13463 .FromJust()); \ 13464 } while (0) 13465 13466 #define TEST_TOSTRINGTAG_TYPES(tagValue) \ 13467 TEST_TOSTRINGTAG(Array, tagValue, Array); \ 13468 TEST_TOSTRINGTAG(Object, tagValue, Object); \ 13469 TEST_TOSTRINGTAG(Function, tagValue, Function); \ 13470 TEST_TOSTRINGTAG(Date, tagValue, Date); \ 13471 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \ 13472 TEST_TOSTRINGTAG(Error, tagValue, Error); \ 13473 13474 // Test non-String-valued @@toStringTag 13475 TEST_TOSTRINGTAG_TYPES(valueRegExp); 13476 TEST_TOSTRINGTAG_TYPES(valueNumber); 13477 TEST_TOSTRINGTAG_TYPES(valueSymbol); 13478 TEST_TOSTRINGTAG_TYPES(valueFunction); 13479 TEST_TOSTRINGTAG_TYPES(valueObject); 13480 TEST_TOSTRINGTAG_TYPES(valueNull); 13481 TEST_TOSTRINGTAG_TYPES(valueUndef); 13482 13483 #undef TEST_TOSTRINGTAG 13484 #undef TEST_TOSTRINGTAG_TYPES 13485 13486 // @@toStringTag getter throws 13487 Local<Value> obj = v8::Object::New(isolate); 13488 obj.As<v8::Object>() 13489 ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter) 13490 .FromJust(); 13491 { 13492 TryCatch try_catch(isolate); 13493 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty()); 13494 CHECK(try_catch.HasCaught()); 13495 } 13496 13497 // @@toStringTag getter does not throw 13498 obj = v8::Object::New(isolate); 13499 obj.As<v8::Object>() 13500 ->SetAccessor(context.local(), toStringTag, 13501 SymbolAccessorGetterReturnsDefault, 0, v8_str("Test")) 13502 .FromJust(); 13503 { 13504 TryCatch try_catch(isolate); 13505 value = obj.As<v8::Object>() 13506 ->ObjectProtoToString(context.local()) 13507 .ToLocalChecked(); 13508 CHECK(value->IsString() && 13509 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13510 CHECK(!try_catch.HasCaught()); 13511 } 13512 13513 // JS @@toStringTag value 13514 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj"); 13515 { 13516 TryCatch try_catch(isolate); 13517 value = obj.As<v8::Object>() 13518 ->ObjectProtoToString(context.local()) 13519 .ToLocalChecked(); 13520 CHECK(value->IsString() && 13521 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13522 CHECK(!try_catch.HasCaught()); 13523 } 13524 13525 // JS @@toStringTag getter throws 13526 obj = CompileRun( 13527 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {" 13528 " get: function() { throw 'Test'; }" 13529 "}); obj"); 13530 { 13531 TryCatch try_catch(isolate); 13532 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty()); 13533 CHECK(try_catch.HasCaught()); 13534 } 13535 13536 // JS @@toStringTag getter does not throw 13537 obj = CompileRun( 13538 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {" 13539 " get: function() { return 'Test'; }" 13540 "}); obj"); 13541 { 13542 TryCatch try_catch(isolate); 13543 value = obj.As<v8::Object>() 13544 ->ObjectProtoToString(context.local()) 13545 .ToLocalChecked(); 13546 CHECK(value->IsString() && 13547 value->Equals(context.local(), v8_str("[object Test]")).FromJust()); 13548 CHECK(!try_catch.HasCaught()); 13549 } 13550 } 13551 13552 13553 THREADED_TEST(ObjectGetConstructorName) { 13554 v8::Isolate* isolate = CcTest::isolate(); 13555 LocalContext context; 13556 v8::HandleScope scope(isolate); 13557 v8_compile( 13558 "function Parent() {};" 13559 "function Child() {};" 13560 "Child.prototype = new Parent();" 13561 "Child.prototype.constructor = Child;" 13562 "var outer = { inner: (0, function() { }) };" 13563 "var p = new Parent();" 13564 "var c = new Child();" 13565 "var x = new outer.inner();" 13566 "var proto = Child.prototype;") 13567 ->Run(context.local()) 13568 .ToLocalChecked(); 13569 13570 Local<v8::Value> p = 13571 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked(); 13572 CHECK(p->IsObject() && 13573 p->ToObject(context.local()) 13574 .ToLocalChecked() 13575 ->GetConstructorName() 13576 ->Equals(context.local(), v8_str("Parent")) 13577 .FromJust()); 13578 13579 Local<v8::Value> c = 13580 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked(); 13581 CHECK(c->IsObject() && 13582 c->ToObject(context.local()) 13583 .ToLocalChecked() 13584 ->GetConstructorName() 13585 ->Equals(context.local(), v8_str("Child")) 13586 .FromJust()); 13587 13588 Local<v8::Value> x = 13589 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked(); 13590 CHECK(x->IsObject() && 13591 x->ToObject(context.local()) 13592 .ToLocalChecked() 13593 ->GetConstructorName() 13594 ->Equals(context.local(), v8_str("outer.inner")) 13595 .FromJust()); 13596 13597 Local<v8::Value> child_prototype = 13598 context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked(); 13599 CHECK(child_prototype->IsObject() && 13600 child_prototype->ToObject(context.local()) 13601 .ToLocalChecked() 13602 ->GetConstructorName() 13603 ->Equals(context.local(), v8_str("Parent")) 13604 .FromJust()); 13605 } 13606 13607 13608 THREADED_TEST(SubclassGetConstructorName) { 13609 v8::Isolate* isolate = CcTest::isolate(); 13610 LocalContext context; 13611 v8::HandleScope scope(isolate); 13612 v8_compile( 13613 "\"use strict\";" 13614 "class Parent {}" 13615 "class Child extends Parent {}" 13616 "var p = new Parent();" 13617 "var c = new Child();") 13618 ->Run(context.local()) 13619 .ToLocalChecked(); 13620 13621 Local<v8::Value> p = 13622 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked(); 13623 CHECK(p->IsObject() && 13624 p->ToObject(context.local()) 13625 .ToLocalChecked() 13626 ->GetConstructorName() 13627 ->Equals(context.local(), v8_str("Parent")) 13628 .FromJust()); 13629 13630 Local<v8::Value> c = 13631 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked(); 13632 CHECK(c->IsObject() && 13633 c->ToObject(context.local()) 13634 .ToLocalChecked() 13635 ->GetConstructorName() 13636 ->Equals(context.local(), v8_str("Child")) 13637 .FromJust()); 13638 } 13639 13640 13641 bool ApiTestFuzzer::fuzzing_ = false; 13642 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0); 13643 int ApiTestFuzzer::active_tests_; 13644 int ApiTestFuzzer::tests_being_run_; 13645 int ApiTestFuzzer::current_; 13646 13647 13648 // We are in a callback and want to switch to another thread (if we 13649 // are currently running the thread fuzzing test). 13650 void ApiTestFuzzer::Fuzz() { 13651 if (!fuzzing_) return; 13652 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 13653 test->ContextSwitch(); 13654 } 13655 13656 13657 // Let the next thread go. Since it is also waiting on the V8 lock it may 13658 // not start immediately. 13659 bool ApiTestFuzzer::NextThread() { 13660 int test_position = GetNextTestNumber(); 13661 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 13662 if (test_position == current_) { 13663 if (kLogThreading) 13664 printf("Stay with %s\n", test_name); 13665 return false; 13666 } 13667 if (kLogThreading) { 13668 printf("Switch from %s to %s\n", 13669 test_name, 13670 RegisterThreadedTest::nth(test_position)->name()); 13671 } 13672 current_ = test_position; 13673 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal(); 13674 return true; 13675 } 13676 13677 13678 void ApiTestFuzzer::Run() { 13679 // When it is our turn... 13680 gate_.Wait(); 13681 { 13682 // ... get the V8 lock and start running the test. 13683 v8::Locker locker(CcTest::isolate()); 13684 CallTest(); 13685 } 13686 // This test finished. 13687 active_ = false; 13688 active_tests_--; 13689 // If it was the last then signal that fact. 13690 if (active_tests_ == 0) { 13691 all_tests_done_.Signal(); 13692 } else { 13693 // Otherwise select a new test and start that. 13694 NextThread(); 13695 } 13696 } 13697 13698 13699 static unsigned linear_congruential_generator; 13700 13701 13702 void ApiTestFuzzer::SetUp(PartOfTest part) { 13703 linear_congruential_generator = i::FLAG_testing_prng_seed; 13704 fuzzing_ = true; 13705 int count = RegisterThreadedTest::count(); 13706 int start = count * part / (LAST_PART + 1); 13707 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 13708 active_tests_ = tests_being_run_ = end - start + 1; 13709 for (int i = 0; i < tests_being_run_; i++) { 13710 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 13711 } 13712 for (int i = 0; i < active_tests_; i++) { 13713 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 13714 } 13715 } 13716 13717 13718 static void CallTestNumber(int test_number) { 13719 (RegisterThreadedTest::nth(test_number)->callback())(); 13720 } 13721 13722 13723 void ApiTestFuzzer::RunAllTests() { 13724 // Set off the first test. 13725 current_ = -1; 13726 NextThread(); 13727 // Wait till they are all done. 13728 all_tests_done_.Wait(); 13729 } 13730 13731 13732 int ApiTestFuzzer::GetNextTestNumber() { 13733 int next_test; 13734 do { 13735 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 13736 linear_congruential_generator *= 1664525u; 13737 linear_congruential_generator += 1013904223u; 13738 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 13739 return next_test; 13740 } 13741 13742 13743 void ApiTestFuzzer::ContextSwitch() { 13744 // If the new thread is the same as the current thread there is nothing to do. 13745 if (NextThread()) { 13746 // Now it can start. 13747 v8::Unlocker unlocker(CcTest::isolate()); 13748 // Wait till someone starts us again. 13749 gate_.Wait(); 13750 // And we're off. 13751 } 13752 } 13753 13754 13755 void ApiTestFuzzer::TearDown() { 13756 fuzzing_ = false; 13757 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 13758 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 13759 if (fuzzer != NULL) fuzzer->Join(); 13760 } 13761 } 13762 13763 13764 // Lets not be needlessly self-referential. 13765 TEST(Threading1) { 13766 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 13767 ApiTestFuzzer::RunAllTests(); 13768 ApiTestFuzzer::TearDown(); 13769 } 13770 13771 13772 TEST(Threading2) { 13773 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 13774 ApiTestFuzzer::RunAllTests(); 13775 ApiTestFuzzer::TearDown(); 13776 } 13777 13778 13779 TEST(Threading3) { 13780 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 13781 ApiTestFuzzer::RunAllTests(); 13782 ApiTestFuzzer::TearDown(); 13783 } 13784 13785 13786 TEST(Threading4) { 13787 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 13788 ApiTestFuzzer::RunAllTests(); 13789 ApiTestFuzzer::TearDown(); 13790 } 13791 13792 13793 void ApiTestFuzzer::CallTest() { 13794 v8::Isolate::Scope scope(CcTest::isolate()); 13795 if (kLogThreading) 13796 printf("Start test %d\n", test_number_); 13797 CallTestNumber(test_number_); 13798 if (kLogThreading) 13799 printf("End test %d\n", test_number_); 13800 } 13801 13802 13803 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 13804 v8::Isolate* isolate = args.GetIsolate(); 13805 CHECK(v8::Locker::IsLocked(isolate)); 13806 ApiTestFuzzer::Fuzz(); 13807 v8::Unlocker unlocker(isolate); 13808 const char* code = "throw 7;"; 13809 { 13810 v8::Locker nested_locker(isolate); 13811 v8::HandleScope scope(isolate); 13812 v8::Local<Value> exception; 13813 { 13814 v8::TryCatch try_catch(isolate); 13815 v8::Local<Value> value = CompileRun(code); 13816 CHECK(value.IsEmpty()); 13817 CHECK(try_catch.HasCaught()); 13818 // Make sure to wrap the exception in a new handle because 13819 // the handle returned from the TryCatch is destroyed 13820 // when the TryCatch is destroyed. 13821 exception = Local<Value>::New(isolate, try_catch.Exception()); 13822 } 13823 args.GetIsolate()->ThrowException(exception); 13824 } 13825 } 13826 13827 13828 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 13829 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13830 ApiTestFuzzer::Fuzz(); 13831 v8::Unlocker unlocker(CcTest::isolate()); 13832 const char* code = "throw 7;"; 13833 { 13834 v8::Locker nested_locker(CcTest::isolate()); 13835 v8::HandleScope scope(args.GetIsolate()); 13836 v8::Local<Value> value = CompileRun(code); 13837 CHECK(value.IsEmpty()); 13838 args.GetReturnValue().Set(v8_str("foo")); 13839 } 13840 } 13841 13842 13843 // These are locking tests that don't need to be run again 13844 // as part of the locking aggregation tests. 13845 TEST(NestedLockers) { 13846 v8::Isolate* isolate = CcTest::isolate(); 13847 v8::Locker locker(isolate); 13848 CHECK(v8::Locker::IsLocked(isolate)); 13849 LocalContext env; 13850 v8::HandleScope scope(env->GetIsolate()); 13851 Local<v8::FunctionTemplate> fun_templ = 13852 v8::FunctionTemplate::New(isolate, ThrowInJS); 13853 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13854 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust()); 13855 Local<Script> script = v8_compile("(function () {" 13856 " try {" 13857 " throw_in_js();" 13858 " return 42;" 13859 " } catch (e) {" 13860 " return e * 13;" 13861 " }" 13862 "})();"); 13863 CHECK_EQ(91, script->Run(env.local()) 13864 .ToLocalChecked() 13865 ->Int32Value(env.local()) 13866 .FromJust()); 13867 } 13868 13869 13870 // These are locking tests that don't need to be run again 13871 // as part of the locking aggregation tests. 13872 TEST(NestedLockersNoTryCatch) { 13873 v8::Locker locker(CcTest::isolate()); 13874 LocalContext env; 13875 v8::HandleScope scope(env->GetIsolate()); 13876 Local<v8::FunctionTemplate> fun_templ = 13877 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch); 13878 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13879 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust()); 13880 Local<Script> script = v8_compile("(function () {" 13881 " try {" 13882 " throw_in_js();" 13883 " return 42;" 13884 " } catch (e) {" 13885 " return e * 13;" 13886 " }" 13887 "})();"); 13888 CHECK_EQ(91, script->Run(env.local()) 13889 .ToLocalChecked() 13890 ->Int32Value(env.local()) 13891 .FromJust()); 13892 } 13893 13894 13895 THREADED_TEST(RecursiveLocking) { 13896 v8::Locker locker(CcTest::isolate()); 13897 { 13898 v8::Locker locker2(CcTest::isolate()); 13899 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13900 } 13901 } 13902 13903 13904 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 13905 ApiTestFuzzer::Fuzz(); 13906 v8::Unlocker unlocker(CcTest::isolate()); 13907 } 13908 13909 13910 THREADED_TEST(LockUnlockLock) { 13911 { 13912 v8::Locker locker(CcTest::isolate()); 13913 v8::HandleScope scope(CcTest::isolate()); 13914 LocalContext env; 13915 Local<v8::FunctionTemplate> fun_templ = 13916 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13917 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13918 CHECK(env->Global() 13919 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun) 13920 .FromJust()); 13921 Local<Script> script = v8_compile("(function () {" 13922 " unlock_for_a_moment();" 13923 " return 42;" 13924 "})();"); 13925 CHECK_EQ(42, script->Run(env.local()) 13926 .ToLocalChecked() 13927 ->Int32Value(env.local()) 13928 .FromJust()); 13929 } 13930 { 13931 v8::Locker locker(CcTest::isolate()); 13932 v8::HandleScope scope(CcTest::isolate()); 13933 LocalContext env; 13934 Local<v8::FunctionTemplate> fun_templ = 13935 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13936 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 13937 CHECK(env->Global() 13938 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun) 13939 .FromJust()); 13940 Local<Script> script = v8_compile("(function () {" 13941 " unlock_for_a_moment();" 13942 " return 42;" 13943 "})();"); 13944 CHECK_EQ(42, script->Run(env.local()) 13945 .ToLocalChecked() 13946 ->Int32Value(env.local()) 13947 .FromJust()); 13948 } 13949 } 13950 13951 13952 static int GetGlobalObjectsCount() { 13953 int count = 0; 13954 i::HeapIterator it(CcTest::heap()); 13955 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 13956 if (object->IsJSGlobalObject()) { 13957 i::JSGlobalObject* g = i::JSGlobalObject::cast(object); 13958 // Skip dummy global object. 13959 if (i::GlobalDictionary::cast(g->properties())->NumberOfElements() != 0) { 13960 count++; 13961 } 13962 } 13963 return count; 13964 } 13965 13966 13967 static void CheckSurvivingGlobalObjectsCount(int expected) { 13968 // We need to collect all garbage twice to be sure that everything 13969 // has been collected. This is because inline caches are cleared in 13970 // the first garbage collection but some of the maps have already 13971 // been marked at that point. Therefore some of the maps are not 13972 // collected until the second garbage collection. 13973 CcTest::heap()->CollectAllGarbage(); 13974 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 13975 int count = GetGlobalObjectsCount(); 13976 #ifdef DEBUG 13977 if (count != expected) CcTest::heap()->TracePathToGlobal(); 13978 #endif 13979 CHECK_EQ(expected, count); 13980 } 13981 13982 13983 TEST(DontLeakGlobalObjects) { 13984 // Regression test for issues 1139850 and 1174891. 13985 13986 i::FLAG_expose_gc = true; 13987 v8::V8::Initialize(); 13988 13989 for (int i = 0; i < 5; i++) { 13990 { v8::HandleScope scope(CcTest::isolate()); 13991 LocalContext context; 13992 } 13993 CcTest::isolate()->ContextDisposedNotification(); 13994 CheckSurvivingGlobalObjectsCount(0); 13995 13996 { v8::HandleScope scope(CcTest::isolate()); 13997 LocalContext context; 13998 v8_compile("Date")->Run(context.local()).ToLocalChecked(); 13999 } 14000 CcTest::isolate()->ContextDisposedNotification(); 14001 CheckSurvivingGlobalObjectsCount(0); 14002 14003 { v8::HandleScope scope(CcTest::isolate()); 14004 LocalContext context; 14005 v8_compile("/aaa/")->Run(context.local()).ToLocalChecked(); 14006 } 14007 CcTest::isolate()->ContextDisposedNotification(); 14008 CheckSurvivingGlobalObjectsCount(0); 14009 14010 { v8::HandleScope scope(CcTest::isolate()); 14011 const char* extension_list[] = { "v8/gc" }; 14012 v8::ExtensionConfiguration extensions(1, extension_list); 14013 LocalContext context(&extensions); 14014 v8_compile("gc();")->Run(context.local()).ToLocalChecked(); 14015 } 14016 CcTest::isolate()->ContextDisposedNotification(); 14017 CheckSurvivingGlobalObjectsCount(0); 14018 } 14019 } 14020 14021 14022 TEST(CopyablePersistent) { 14023 LocalContext context; 14024 v8::Isolate* isolate = context->GetIsolate(); 14025 i::GlobalHandles* globals = 14026 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 14027 int initial_handles = globals->global_handles_count(); 14028 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > 14029 CopyableObject; 14030 { 14031 CopyableObject handle1; 14032 { 14033 v8::HandleScope scope(isolate); 14034 handle1.Reset(isolate, v8::Object::New(isolate)); 14035 } 14036 CHECK_EQ(initial_handles + 1, globals->global_handles_count()); 14037 CopyableObject handle2; 14038 handle2 = handle1; 14039 CHECK(handle1 == handle2); 14040 CHECK_EQ(initial_handles + 2, globals->global_handles_count()); 14041 CopyableObject handle3(handle2); 14042 CHECK(handle1 == handle3); 14043 CHECK_EQ(initial_handles + 3, globals->global_handles_count()); 14044 } 14045 // Verify autodispose 14046 CHECK_EQ(initial_handles, globals->global_handles_count()); 14047 } 14048 14049 14050 static void WeakApiCallback( 14051 const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) { 14052 data.GetParameter()->Reset(); 14053 delete data.GetParameter(); 14054 } 14055 14056 14057 TEST(WeakCallbackApi) { 14058 LocalContext context; 14059 v8::Isolate* isolate = context->GetIsolate(); 14060 i::GlobalHandles* globals = 14061 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 14062 int initial_handles = globals->global_handles_count(); 14063 { 14064 v8::HandleScope scope(isolate); 14065 v8::Local<v8::Object> obj = v8::Object::New(isolate); 14066 CHECK( 14067 obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231)) 14068 .FromJust()); 14069 v8::Persistent<v8::Object>* handle = 14070 new v8::Persistent<v8::Object>(isolate, obj); 14071 handle->SetWeak<v8::Persistent<v8::Object>>( 14072 handle, WeakApiCallback, v8::WeakCallbackType::kParameter); 14073 } 14074 reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage( 14075 i::Heap::kAbortIncrementalMarkingMask); 14076 // Verify disposed. 14077 CHECK_EQ(initial_handles, globals->global_handles_count()); 14078 } 14079 14080 14081 v8::Persistent<v8::Object> some_object; 14082 v8::Persistent<v8::Object> bad_handle; 14083 14084 14085 void NewPersistentHandleCallback2( 14086 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14087 v8::HandleScope scope(data.GetIsolate()); 14088 bad_handle.Reset(data.GetIsolate(), some_object); 14089 } 14090 14091 14092 void NewPersistentHandleCallback1( 14093 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14094 data.GetParameter()->Reset(); 14095 data.SetSecondPassCallback(NewPersistentHandleCallback2); 14096 } 14097 14098 14099 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 14100 LocalContext context; 14101 v8::Isolate* isolate = context->GetIsolate(); 14102 14103 v8::Persistent<v8::Object> handle1, handle2; 14104 { 14105 v8::HandleScope scope(isolate); 14106 some_object.Reset(isolate, v8::Object::New(isolate)); 14107 handle1.Reset(isolate, v8::Object::New(isolate)); 14108 handle2.Reset(isolate, v8::Object::New(isolate)); 14109 } 14110 // Note: order is implementation dependent alas: currently 14111 // global handle nodes are processed by PostGarbageCollectionProcessing 14112 // in reverse allocation order, so if second allocated handle is deleted, 14113 // weak callback of the first handle would be able to 'reallocate' it. 14114 handle1.SetWeak(&handle1, NewPersistentHandleCallback1, 14115 v8::WeakCallbackType::kParameter); 14116 handle2.Reset(); 14117 CcTest::heap()->CollectAllGarbage(); 14118 } 14119 14120 14121 v8::Persistent<v8::Object> to_be_disposed; 14122 14123 14124 void DisposeAndForceGcCallback2( 14125 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14126 to_be_disposed.Reset(); 14127 CcTest::heap()->CollectAllGarbage(); 14128 } 14129 14130 14131 void DisposeAndForceGcCallback1( 14132 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14133 data.GetParameter()->Reset(); 14134 data.SetSecondPassCallback(DisposeAndForceGcCallback2); 14135 } 14136 14137 14138 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 14139 LocalContext context; 14140 v8::Isolate* isolate = context->GetIsolate(); 14141 14142 v8::Persistent<v8::Object> handle1, handle2; 14143 { 14144 v8::HandleScope scope(isolate); 14145 handle1.Reset(isolate, v8::Object::New(isolate)); 14146 handle2.Reset(isolate, v8::Object::New(isolate)); 14147 } 14148 handle1.SetWeak(&handle1, DisposeAndForceGcCallback1, 14149 v8::WeakCallbackType::kParameter); 14150 to_be_disposed.Reset(isolate, handle2); 14151 CcTest::heap()->CollectAllGarbage(); 14152 } 14153 14154 void DisposingCallback( 14155 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14156 data.GetParameter()->Reset(); 14157 } 14158 14159 void HandleCreatingCallback2( 14160 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14161 v8::HandleScope scope(data.GetIsolate()); 14162 v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate())); 14163 } 14164 14165 14166 void HandleCreatingCallback1( 14167 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { 14168 data.GetParameter()->Reset(); 14169 data.SetSecondPassCallback(HandleCreatingCallback2); 14170 } 14171 14172 14173 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 14174 v8::Locker locker(CcTest::isolate()); 14175 LocalContext context; 14176 v8::Isolate* isolate = context->GetIsolate(); 14177 14178 v8::Persistent<v8::Object> handle1, handle2, handle3; 14179 { 14180 v8::HandleScope scope(isolate); 14181 handle3.Reset(isolate, v8::Object::New(isolate)); 14182 handle2.Reset(isolate, v8::Object::New(isolate)); 14183 handle1.Reset(isolate, v8::Object::New(isolate)); 14184 } 14185 handle2.SetWeak(&handle2, DisposingCallback, 14186 v8::WeakCallbackType::kParameter); 14187 handle3.SetWeak(&handle3, HandleCreatingCallback1, 14188 v8::WeakCallbackType::kParameter); 14189 CcTest::heap()->CollectAllGarbage(); 14190 EmptyMessageQueues(isolate); 14191 } 14192 14193 14194 THREADED_TEST(CheckForCrossContextObjectLiterals) { 14195 v8::V8::Initialize(); 14196 14197 const int nof = 2; 14198 const char* sources[nof] = { 14199 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 14200 "Object()" 14201 }; 14202 14203 for (int i = 0; i < nof; i++) { 14204 const char* source = sources[i]; 14205 { v8::HandleScope scope(CcTest::isolate()); 14206 LocalContext context; 14207 CompileRun(source); 14208 } 14209 { v8::HandleScope scope(CcTest::isolate()); 14210 LocalContext context; 14211 CompileRun(source); 14212 } 14213 } 14214 } 14215 14216 14217 static v8::Local<Value> NestedScope(v8::Local<Context> env) { 14218 v8::EscapableHandleScope inner(env->GetIsolate()); 14219 env->Enter(); 14220 v8::Local<Value> three = v8_num(3); 14221 v8::Local<Value> value = inner.Escape(three); 14222 env->Exit(); 14223 return value; 14224 } 14225 14226 14227 THREADED_TEST(NestedHandleScopeAndContexts) { 14228 v8::Isolate* isolate = CcTest::isolate(); 14229 v8::HandleScope outer(isolate); 14230 v8::Local<Context> env = Context::New(isolate); 14231 env->Enter(); 14232 v8::Local<Value> value = NestedScope(env); 14233 v8::Local<String> str(value->ToString(env).ToLocalChecked()); 14234 CHECK(!str.IsEmpty()); 14235 env->Exit(); 14236 } 14237 14238 14239 static bool MatchPointers(void* key1, void* key2) { 14240 return key1 == key2; 14241 } 14242 14243 14244 struct SymbolInfo { 14245 size_t id; 14246 size_t size; 14247 std::string name; 14248 }; 14249 14250 14251 class SetFunctionEntryHookTest { 14252 public: 14253 SetFunctionEntryHookTest() { 14254 CHECK(instance_ == NULL); 14255 instance_ = this; 14256 } 14257 ~SetFunctionEntryHookTest() { 14258 CHECK(instance_ == this); 14259 instance_ = NULL; 14260 } 14261 void Reset() { 14262 symbols_.clear(); 14263 symbol_locations_.clear(); 14264 invocations_.clear(); 14265 } 14266 void RunTest(); 14267 void OnJitEvent(const v8::JitCodeEvent* event); 14268 static void JitEvent(const v8::JitCodeEvent* event) { 14269 CHECK(instance_ != NULL); 14270 instance_->OnJitEvent(event); 14271 } 14272 14273 void OnEntryHook(uintptr_t function, 14274 uintptr_t return_addr_location); 14275 static void EntryHook(uintptr_t function, 14276 uintptr_t return_addr_location) { 14277 CHECK(instance_ != NULL); 14278 instance_->OnEntryHook(function, return_addr_location); 14279 } 14280 14281 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 14282 CHECK(instance_ != NULL); 14283 args.GetReturnValue().Set(v8_num(42)); 14284 } 14285 void RunLoopInNewEnv(v8::Isolate* isolate); 14286 14287 // Records addr as location of symbol. 14288 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 14289 14290 // Finds the symbol containing addr 14291 SymbolInfo* FindSymbolForAddr(i::Address addr); 14292 // Returns the number of invocations where the caller name contains 14293 // \p caller_name and the function name contains \p function_name. 14294 int CountInvocations(const char* caller_name, 14295 const char* function_name); 14296 14297 i::Handle<i::JSFunction> foo_func_; 14298 i::Handle<i::JSFunction> bar_func_; 14299 14300 typedef std::map<size_t, SymbolInfo> SymbolMap; 14301 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 14302 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 14303 SymbolMap symbols_; 14304 SymbolLocationMap symbol_locations_; 14305 InvocationMap invocations_; 14306 14307 static SetFunctionEntryHookTest* instance_; 14308 }; 14309 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 14310 14311 14312 // Returns true if addr is in the range [start, start+len). 14313 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 14314 if (start <= addr && start + len > addr) 14315 return true; 14316 14317 return false; 14318 } 14319 14320 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 14321 SymbolInfo* symbol) { 14322 // Insert the symbol at the new location. 14323 SymbolLocationMap::iterator it = 14324 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 14325 // Now erase symbols to the left and right that overlap this one. 14326 while (it != symbol_locations_.begin()) { 14327 SymbolLocationMap::iterator left = it; 14328 --left; 14329 if (!Overlaps(left->first, left->second->size, addr)) 14330 break; 14331 symbol_locations_.erase(left); 14332 } 14333 14334 // Now erase symbols to the left and right that overlap this one. 14335 while (true) { 14336 SymbolLocationMap::iterator right = it; 14337 ++right; 14338 if (right == symbol_locations_.end()) 14339 break; 14340 if (!Overlaps(addr, symbol->size, right->first)) 14341 break; 14342 symbol_locations_.erase(right); 14343 } 14344 } 14345 14346 14347 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 14348 switch (event->type) { 14349 case v8::JitCodeEvent::CODE_ADDED: { 14350 CHECK(event->code_start != NULL); 14351 CHECK_NE(0, static_cast<int>(event->code_len)); 14352 CHECK(event->name.str != NULL); 14353 size_t symbol_id = symbols_.size(); 14354 14355 // Record the new symbol. 14356 SymbolInfo& info = symbols_[symbol_id]; 14357 info.id = symbol_id; 14358 info.size = event->code_len; 14359 info.name.assign(event->name.str, event->name.str + event->name.len); 14360 14361 // And record it's location. 14362 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 14363 } 14364 break; 14365 14366 case v8::JitCodeEvent::CODE_MOVED: { 14367 // We would like to never see code move that we haven't seen before, 14368 // but the code creation event does not happen until the line endings 14369 // have been calculated (this is so that we can report the line in the 14370 // script at which the function source is found, see 14371 // Compiler::RecordFunctionCompilation) and the line endings 14372 // calculations can cause a GC, which can move the newly created code 14373 // before its existence can be logged. 14374 SymbolLocationMap::iterator it( 14375 symbol_locations_.find( 14376 reinterpret_cast<i::Address>(event->code_start))); 14377 if (it != symbol_locations_.end()) { 14378 // Found a symbol at this location, move it. 14379 SymbolInfo* info = it->second; 14380 symbol_locations_.erase(it); 14381 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 14382 info); 14383 } 14384 } 14385 default: 14386 break; 14387 } 14388 } 14389 14390 void SetFunctionEntryHookTest::OnEntryHook( 14391 uintptr_t function, uintptr_t return_addr_location) { 14392 // Get the function's code object. 14393 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 14394 reinterpret_cast<i::Address>(function)); 14395 CHECK(function_code != NULL); 14396 14397 // Then try and look up the caller's code object. 14398 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 14399 14400 // Count the invocation. 14401 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 14402 SymbolInfo* function_symbol = 14403 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 14404 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 14405 14406 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 14407 // Check that we have a symbol for the "bar" function at the right location. 14408 SymbolLocationMap::iterator it( 14409 symbol_locations_.find(function_code->instruction_start())); 14410 CHECK(it != symbol_locations_.end()); 14411 } 14412 14413 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 14414 // Check that we have a symbol for "foo" at the right location. 14415 SymbolLocationMap::iterator it( 14416 symbol_locations_.find(function_code->instruction_start())); 14417 CHECK(it != symbol_locations_.end()); 14418 } 14419 } 14420 14421 14422 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 14423 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 14424 // Do we have a direct hit on a symbol? 14425 if (it != symbol_locations_.end()) { 14426 if (it->first == addr) 14427 return it->second; 14428 } 14429 14430 // If not a direct hit, it'll have to be the previous symbol. 14431 if (it == symbol_locations_.begin()) 14432 return NULL; 14433 14434 --it; 14435 size_t offs = addr - it->first; 14436 if (offs < it->second->size) 14437 return it->second; 14438 14439 return NULL; 14440 } 14441 14442 14443 int SetFunctionEntryHookTest::CountInvocations( 14444 const char* caller_name, const char* function_name) { 14445 InvocationMap::iterator it(invocations_.begin()); 14446 int invocations = 0; 14447 for (; it != invocations_.end(); ++it) { 14448 SymbolInfo* caller = it->first.first; 14449 SymbolInfo* function = it->first.second; 14450 14451 // Filter out non-matching functions. 14452 if (function_name != NULL) { 14453 if (function->name.find(function_name) == std::string::npos) 14454 continue; 14455 } 14456 14457 // Filter out non-matching callers. 14458 if (caller_name != NULL) { 14459 if (caller == NULL) 14460 continue; 14461 if (caller->name.find(caller_name) == std::string::npos) 14462 continue; 14463 } 14464 14465 // It matches add the invocation count to the tally. 14466 invocations += it->second; 14467 } 14468 14469 return invocations; 14470 } 14471 14472 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 14473 v8::HandleScope outer(isolate); 14474 v8::Local<Context> env = Context::New(isolate); 14475 env->Enter(); 14476 14477 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14478 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback)); 14479 CHECK(env->Global() 14480 ->Set(env, v8_str("obj"), t->NewInstance(env).ToLocalChecked()) 14481 .FromJust()); 14482 14483 const char* script = 14484 "function bar() {\n" 14485 " var sum = 0;\n" 14486 " for (i = 0; i < 100; ++i)\n" 14487 " sum = foo(i);\n" 14488 " return sum;\n" 14489 "}\n" 14490 "function foo(i) { return i * i; }\n" 14491 "// Invoke on the runtime function.\n" 14492 "obj.asdf()"; 14493 CompileRun(script); 14494 bar_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle( 14495 *env->Global()->Get(env, v8_str("bar")).ToLocalChecked())); 14496 CHECK(!bar_func_.is_null()); 14497 14498 foo_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle( 14499 *env->Global()->Get(env, v8_str("foo")).ToLocalChecked())); 14500 CHECK(!foo_func_.is_null()); 14501 14502 v8::Local<v8::Value> value = CompileRun("bar();"); 14503 CHECK(value->IsNumber()); 14504 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14505 14506 // Test the optimized codegen path. 14507 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 14508 "bar();"); 14509 CHECK(value->IsNumber()); 14510 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14511 14512 env->Exit(); 14513 } 14514 14515 14516 void SetFunctionEntryHookTest::RunTest() { 14517 // Work in a new isolate throughout. 14518 v8::Isolate::CreateParams create_params; 14519 create_params.entry_hook = EntryHook; 14520 create_params.code_event_handler = JitEvent; 14521 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14522 v8::Isolate* isolate = v8::Isolate::New(create_params); 14523 14524 { 14525 v8::Isolate::Scope scope(isolate); 14526 14527 RunLoopInNewEnv(isolate); 14528 14529 // Check the expected invocation counts. 14530 if (!i::FLAG_ignition) { 14531 CHECK_EQ(2, CountInvocations(NULL, "bar")); 14532 CHECK_EQ(200, CountInvocations("bar", "foo")); 14533 CHECK_EQ(200, CountInvocations(NULL, "foo")); 14534 } else { 14535 // For ignition we don't see the actual functions being called, instead 14536 // we see the IterpreterEntryTrampoline at least 102 times 14537 // (100 unoptimized calls to foo, and 2 calls to bar). 14538 CHECK_LE(102, CountInvocations(NULL, "InterpreterEntryTrampoline")); 14539 // We should also see the calls to the optimized function foo. 14540 CHECK_EQ(100, CountInvocations(NULL, "foo")); 14541 } 14542 14543 // Verify that we have an entry hook on some specific stubs. 14544 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 14545 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 14546 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 14547 } 14548 isolate->Dispose(); 14549 14550 Reset(); 14551 14552 // Make sure a second isolate is unaffected by the previous entry hook. 14553 create_params = v8::Isolate::CreateParams(); 14554 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14555 isolate = v8::Isolate::New(create_params); 14556 { 14557 v8::Isolate::Scope scope(isolate); 14558 14559 // Reset the entry count to zero and set the entry hook. 14560 RunLoopInNewEnv(isolate); 14561 14562 // We should record no invocations in this isolate. 14563 CHECK_EQ(0, static_cast<int>(invocations_.size())); 14564 } 14565 14566 isolate->Dispose(); 14567 } 14568 14569 14570 TEST(SetFunctionEntryHook) { 14571 // FunctionEntryHook does not work well with experimental natives. 14572 // Experimental natives are compiled during snapshot deserialization. 14573 // This test breaks because InstallGetter (function from snapshot that 14574 // only gets called from experimental natives) is compiled with entry hooks. 14575 i::FLAG_allow_natives_syntax = true; 14576 i::FLAG_turbo_inlining = false; 14577 i::FLAG_use_inlining = false; 14578 14579 SetFunctionEntryHookTest test; 14580 test.RunTest(); 14581 } 14582 14583 static v8::base::HashMap* code_map = NULL; 14584 static v8::base::HashMap* jitcode_line_info = NULL; 14585 static int saw_bar = 0; 14586 static int move_events = 0; 14587 14588 14589 static bool FunctionNameIs(const char* expected, 14590 const v8::JitCodeEvent* event) { 14591 // Log lines for functions are of the general form: 14592 // "LazyCompile:<type><function_name>" or Function:<type><function_name>, 14593 // where the type is one of "*", "~" or "". 14594 static const char* kPreamble; 14595 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) { 14596 kPreamble = "Function:"; 14597 } else { 14598 kPreamble = "LazyCompile:"; 14599 } 14600 static size_t kPreambleLen = strlen(kPreamble); 14601 14602 if (event->name.len < kPreambleLen || 14603 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 14604 return false; 14605 } 14606 14607 const char* tail = event->name.str + kPreambleLen; 14608 size_t tail_len = event->name.len - kPreambleLen; 14609 size_t expected_len = strlen(expected); 14610 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 14611 --tail_len; 14612 ++tail; 14613 } 14614 14615 // Check for tails like 'bar :1'. 14616 if (tail_len > expected_len + 2 && 14617 tail[expected_len] == ' ' && 14618 tail[expected_len + 1] == ':' && 14619 tail[expected_len + 2] && 14620 !strncmp(tail, expected, expected_len)) { 14621 return true; 14622 } 14623 14624 if (tail_len != expected_len) 14625 return false; 14626 14627 return strncmp(tail, expected, expected_len) == 0; 14628 } 14629 14630 14631 static void event_handler(const v8::JitCodeEvent* event) { 14632 CHECK(event != NULL); 14633 CHECK(code_map != NULL); 14634 CHECK(jitcode_line_info != NULL); 14635 14636 class DummyJitCodeLineInfo { 14637 }; 14638 14639 switch (event->type) { 14640 case v8::JitCodeEvent::CODE_ADDED: { 14641 CHECK(event->code_start != NULL); 14642 CHECK_NE(0, static_cast<int>(event->code_len)); 14643 CHECK(event->name.str != NULL); 14644 v8::base::HashMap::Entry* entry = code_map->LookupOrInsert( 14645 event->code_start, i::ComputePointerHash(event->code_start)); 14646 entry->value = reinterpret_cast<void*>(event->code_len); 14647 14648 if (FunctionNameIs("bar", event)) { 14649 ++saw_bar; 14650 } 14651 } 14652 break; 14653 14654 case v8::JitCodeEvent::CODE_MOVED: { 14655 uint32_t hash = i::ComputePointerHash(event->code_start); 14656 // We would like to never see code move that we haven't seen before, 14657 // but the code creation event does not happen until the line endings 14658 // have been calculated (this is so that we can report the line in the 14659 // script at which the function source is found, see 14660 // Compiler::RecordFunctionCompilation) and the line endings 14661 // calculations can cause a GC, which can move the newly created code 14662 // before its existence can be logged. 14663 v8::base::HashMap::Entry* entry = 14664 code_map->Lookup(event->code_start, hash); 14665 if (entry != NULL) { 14666 ++move_events; 14667 14668 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 14669 code_map->Remove(event->code_start, hash); 14670 14671 entry = code_map->LookupOrInsert( 14672 event->new_code_start, 14673 i::ComputePointerHash(event->new_code_start)); 14674 entry->value = reinterpret_cast<void*>(event->code_len); 14675 } 14676 } 14677 break; 14678 14679 case v8::JitCodeEvent::CODE_REMOVED: 14680 // Object/code removal events are currently not dispatched from the GC. 14681 CHECK(false); 14682 break; 14683 14684 // For CODE_START_LINE_INFO_RECORDING event, we will create one 14685 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 14686 // record it in jitcode_line_info. 14687 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 14688 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 14689 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 14690 temp_event->user_data = line_info; 14691 v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert( 14692 line_info, i::ComputePointerHash(line_info)); 14693 entry->value = reinterpret_cast<void*>(line_info); 14694 } 14695 break; 14696 // For these two events, we will check whether the event->user_data 14697 // data structure is created before during CODE_START_LINE_INFO_RECORDING 14698 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 14699 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 14700 CHECK(event->user_data != NULL); 14701 uint32_t hash = i::ComputePointerHash(event->user_data); 14702 v8::base::HashMap::Entry* entry = 14703 jitcode_line_info->Lookup(event->user_data, hash); 14704 CHECK(entry != NULL); 14705 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 14706 } 14707 break; 14708 14709 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 14710 CHECK(event->user_data != NULL); 14711 uint32_t hash = i::ComputePointerHash(event->user_data); 14712 v8::base::HashMap::Entry* entry = 14713 jitcode_line_info->Lookup(event->user_data, hash); 14714 CHECK(entry != NULL); 14715 } 14716 break; 14717 14718 default: 14719 // Impossible event. 14720 CHECK(false); 14721 break; 14722 } 14723 } 14724 14725 14726 UNINITIALIZED_TEST(SetJitCodeEventHandler) { 14727 i::FLAG_stress_compaction = true; 14728 i::FLAG_incremental_marking = false; 14729 if (i::FLAG_never_compact) return; 14730 const char* script = 14731 "function bar() {" 14732 " var sum = 0;" 14733 " for (i = 0; i < 10; ++i)" 14734 " sum = foo(i);" 14735 " return sum;" 14736 "}" 14737 "function foo(i) { return i; };" 14738 "bar();"; 14739 14740 // Run this test in a new isolate to make sure we don't 14741 // have remnants of state from other code. 14742 v8::Isolate::CreateParams create_params; 14743 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 14744 v8::Isolate* isolate = v8::Isolate::New(create_params); 14745 isolate->Enter(); 14746 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 14747 i::Heap* heap = i_isolate->heap(); 14748 14749 // Start with a clean slate. 14750 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare"); 14751 14752 { 14753 v8::HandleScope scope(isolate); 14754 v8::base::HashMap code(MatchPointers); 14755 code_map = &code; 14756 14757 v8::base::HashMap lineinfo(MatchPointers); 14758 jitcode_line_info = &lineinfo; 14759 14760 saw_bar = 0; 14761 move_events = 0; 14762 14763 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 14764 14765 // Generate new code objects sparsely distributed across several 14766 // different fragmented code-space pages. 14767 const int kIterations = 10; 14768 for (int i = 0; i < kIterations; ++i) { 14769 LocalContext env(isolate); 14770 i::AlwaysAllocateScope always_allocate(i_isolate); 14771 i::heap::SimulateFullSpace(i::FLAG_ignition ? heap->old_space() 14772 : heap->code_space()); 14773 CompileRun(script); 14774 14775 // Keep a strong reference to the code object in the handle scope. 14776 i::Handle<i::Code> bar_code( 14777 i::Handle<i::JSFunction>::cast( 14778 v8::Utils::OpenHandle(*env->Global() 14779 ->Get(env.local(), v8_str("bar")) 14780 .ToLocalChecked())) 14781 ->code()); 14782 i::Handle<i::Code> foo_code( 14783 i::Handle<i::JSFunction>::cast( 14784 v8::Utils::OpenHandle(*env->Global() 14785 ->Get(env.local(), v8_str("foo")) 14786 .ToLocalChecked())) 14787 ->code()); 14788 14789 // Clear the compilation cache to get more wastage. 14790 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear(); 14791 } 14792 14793 // Force code movement. 14794 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move"); 14795 14796 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14797 14798 CHECK_LE(kIterations, saw_bar); 14799 CHECK_LT(0, move_events); 14800 14801 code_map = NULL; 14802 jitcode_line_info = NULL; 14803 } 14804 14805 isolate->Exit(); 14806 isolate->Dispose(); 14807 14808 // Do this in a new isolate. 14809 isolate = v8::Isolate::New(create_params); 14810 isolate->Enter(); 14811 14812 // Verify that we get callbacks for existing code objects when we 14813 // request enumeration of existing code. 14814 { 14815 v8::HandleScope scope(isolate); 14816 LocalContext env(isolate); 14817 CompileRun(script); 14818 14819 // Now get code through initial iteration. 14820 v8::base::HashMap code(MatchPointers); 14821 code_map = &code; 14822 14823 v8::base::HashMap lineinfo(MatchPointers); 14824 jitcode_line_info = &lineinfo; 14825 14826 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, 14827 event_handler); 14828 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14829 14830 jitcode_line_info = NULL; 14831 // We expect that we got some events. Note that if we could get code removal 14832 // notifications, we could compare two collections, one created by listening 14833 // from the time of creation of an isolate, and the other by subscribing 14834 // with EnumExisting. 14835 CHECK_LT(0u, code.occupancy()); 14836 14837 code_map = NULL; 14838 } 14839 14840 isolate->Exit(); 14841 isolate->Dispose(); 14842 } 14843 14844 14845 THREADED_TEST(ExternalAllocatedMemory) { 14846 v8::Isolate* isolate = CcTest::isolate(); 14847 v8::HandleScope outer(isolate); 14848 v8::Local<Context> env(Context::New(isolate)); 14849 CHECK(!env.IsEmpty()); 14850 const int64_t kSize = 1024*1024; 14851 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0); 14852 CHECK_EQ(baseline + kSize, 14853 isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); 14854 CHECK_EQ(baseline, 14855 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); 14856 const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1; 14857 CHECK_EQ(baseline + kTriggerGCSize, 14858 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize)); 14859 CHECK_EQ(baseline, 14860 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize)); 14861 } 14862 14863 14864 TEST(Regress51719) { 14865 i::FLAG_incremental_marking = false; 14866 CcTest::InitializeVM(); 14867 14868 const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1; 14869 v8::Isolate* isolate = CcTest::isolate(); 14870 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize); 14871 } 14872 14873 14874 // Regression test for issue 54, object templates with internal fields 14875 // but no accessors or interceptors did not get their internal field 14876 // count set on instances. 14877 THREADED_TEST(Regress54) { 14878 LocalContext context; 14879 v8::Isolate* isolate = context->GetIsolate(); 14880 v8::HandleScope outer(isolate); 14881 static v8::Persistent<v8::ObjectTemplate> templ; 14882 if (templ.IsEmpty()) { 14883 v8::EscapableHandleScope inner(isolate); 14884 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate); 14885 local->SetInternalFieldCount(1); 14886 templ.Reset(isolate, inner.Escape(local)); 14887 } 14888 v8::Local<v8::Object> result = 14889 v8::Local<v8::ObjectTemplate>::New(isolate, templ) 14890 ->NewInstance(context.local()) 14891 .ToLocalChecked(); 14892 CHECK_EQ(1, result->InternalFieldCount()); 14893 } 14894 14895 14896 // If part of the threaded tests, this test makes ThreadingTest fail 14897 // on mac. 14898 TEST(CatchStackOverflow) { 14899 LocalContext context; 14900 v8::HandleScope scope(context->GetIsolate()); 14901 v8::TryCatch try_catch(context->GetIsolate()); 14902 v8::Local<v8::Value> result = CompileRun( 14903 "function f() {" 14904 " return f();" 14905 "}" 14906 "" 14907 "f();"); 14908 CHECK(result.IsEmpty()); 14909 } 14910 14911 14912 static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script, 14913 const char* resource_name, 14914 int line_offset) { 14915 v8::HandleScope scope(CcTest::isolate()); 14916 v8::TryCatch try_catch(CcTest::isolate()); 14917 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 14918 CHECK(script->Run(context).IsEmpty()); 14919 CHECK(try_catch.HasCaught()); 14920 v8::Local<v8::Message> message = try_catch.Message(); 14921 CHECK(!message.IsEmpty()); 14922 CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust()); 14923 CHECK_EQ(91, message->GetStartPosition()); 14924 CHECK_EQ(92, message->GetEndPosition()); 14925 CHECK_EQ(2, message->GetStartColumn(context).FromJust()); 14926 CHECK_EQ(3, message->GetEndColumn(context).FromJust()); 14927 v8::String::Utf8Value line(message->GetSourceLine(context).ToLocalChecked()); 14928 CHECK_EQ(0, strcmp(" throw 'nirk';", *line)); 14929 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 14930 CHECK_EQ(0, strcmp(resource_name, *name)); 14931 } 14932 14933 14934 THREADED_TEST(TryCatchSourceInfo) { 14935 LocalContext context; 14936 v8::HandleScope scope(context->GetIsolate()); 14937 v8::Local<v8::String> source = v8_str( 14938 "function Foo() {\n" 14939 " return Bar();\n" 14940 "}\n" 14941 "\n" 14942 "function Bar() {\n" 14943 " return Baz();\n" 14944 "}\n" 14945 "\n" 14946 "function Baz() {\n" 14947 " throw 'nirk';\n" 14948 "}\n" 14949 "\n" 14950 "Foo();\n"); 14951 14952 const char* resource_name; 14953 v8::Local<v8::Script> script; 14954 resource_name = "test.js"; 14955 script = CompileWithOrigin(source, resource_name); 14956 CheckTryCatchSourceInfo(script, resource_name, 0); 14957 14958 resource_name = "test1.js"; 14959 v8::ScriptOrigin origin1(v8_str(resource_name)); 14960 script = 14961 v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked(); 14962 CheckTryCatchSourceInfo(script, resource_name, 0); 14963 14964 resource_name = "test2.js"; 14965 v8::ScriptOrigin origin2(v8_str(resource_name), 14966 v8::Integer::New(context->GetIsolate(), 7)); 14967 script = 14968 v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked(); 14969 CheckTryCatchSourceInfo(script, resource_name, 7); 14970 } 14971 14972 14973 THREADED_TEST(TryCatchSourceInfoForEOSError) { 14974 LocalContext context; 14975 v8::HandleScope scope(context->GetIsolate()); 14976 v8::TryCatch try_catch(context->GetIsolate()); 14977 CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty()); 14978 CHECK(try_catch.HasCaught()); 14979 v8::Local<v8::Message> message = try_catch.Message(); 14980 CHECK_EQ(1, message->GetLineNumber(context.local()).FromJust()); 14981 CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust()); 14982 } 14983 14984 14985 THREADED_TEST(CompilationCache) { 14986 LocalContext context; 14987 v8::HandleScope scope(context->GetIsolate()); 14988 v8::Local<v8::String> source0 = v8_str("1234"); 14989 v8::Local<v8::String> source1 = v8_str("1234"); 14990 v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js"); 14991 v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js"); 14992 v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0) 14993 .ToLocalChecked(); // different origin 14994 CHECK_EQ(1234, script0->Run(context.local()) 14995 .ToLocalChecked() 14996 ->Int32Value(context.local()) 14997 .FromJust()); 14998 CHECK_EQ(1234, script1->Run(context.local()) 14999 .ToLocalChecked() 15000 ->Int32Value(context.local()) 15001 .FromJust()); 15002 CHECK_EQ(1234, script2->Run(context.local()) 15003 .ToLocalChecked() 15004 ->Int32Value(context.local()) 15005 .FromJust()); 15006 } 15007 15008 15009 static void FunctionNameCallback( 15010 const v8::FunctionCallbackInfo<v8::Value>& args) { 15011 ApiTestFuzzer::Fuzz(); 15012 args.GetReturnValue().Set(v8_num(42)); 15013 } 15014 15015 15016 THREADED_TEST(CallbackFunctionName) { 15017 LocalContext context; 15018 v8::Isolate* isolate = context->GetIsolate(); 15019 v8::HandleScope scope(isolate); 15020 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 15021 t->Set(v8_str("asdf"), 15022 v8::FunctionTemplate::New(isolate, FunctionNameCallback)); 15023 CHECK(context->Global() 15024 ->Set(context.local(), v8_str("obj"), 15025 t->NewInstance(context.local()).ToLocalChecked()) 15026 .FromJust()); 15027 v8::Local<v8::Value> value = CompileRun("obj.asdf.name"); 15028 CHECK(value->IsString()); 15029 v8::String::Utf8Value name(value); 15030 CHECK_EQ(0, strcmp("asdf", *name)); 15031 } 15032 15033 15034 THREADED_TEST(DateAccess) { 15035 LocalContext context; 15036 v8::HandleScope scope(context->GetIsolate()); 15037 v8::Local<v8::Value> date = 15038 v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked(); 15039 CHECK(date->IsDate()); 15040 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 15041 } 15042 15043 void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties, 15044 unsigned index, const char* name) { 15045 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 15046 v8::Local<v8::Value> value = 15047 properties->Get(context, v8::Integer::New(isolate, index)) 15048 .ToLocalChecked(); 15049 CHECK(value->IsSymbol()); 15050 v8::String::Utf8Value symbol_name(Local<Symbol>::Cast(value)->Name()); 15051 CHECK_EQ(0, strcmp(name, *symbol_name)); 15052 } 15053 15054 void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties, 15055 unsigned length, const char* names[]) { 15056 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 15057 CHECK_EQ(length, properties->Length()); 15058 for (unsigned i = 0; i < length; i++) { 15059 v8::Local<v8::Value> value = 15060 properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked(); 15061 if (names[i] == nullptr) { 15062 DCHECK(value->IsSymbol()); 15063 } else { 15064 v8::String::Utf8Value elm(value); 15065 CHECK_EQ(0, strcmp(names[i], *elm)); 15066 } 15067 } 15068 } 15069 15070 void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val, 15071 unsigned length, const char* names[]) { 15072 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 15073 v8::Local<v8::Object> obj = val.As<v8::Object>(); 15074 v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked(); 15075 CheckStringArray(isolate, props, length, names); 15076 } 15077 15078 15079 void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val, 15080 unsigned elmc, const char* elmv[]) { 15081 v8::Local<v8::Context> context = isolate->GetCurrentContext(); 15082 v8::Local<v8::Object> obj = val.As<v8::Object>(); 15083 v8::Local<v8::Array> props = 15084 obj->GetOwnPropertyNames(context).ToLocalChecked(); 15085 CHECK_EQ(elmc, props->Length()); 15086 for (unsigned i = 0; i < elmc; i++) { 15087 v8::String::Utf8Value elm( 15088 props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked()); 15089 CHECK_EQ(0, strcmp(elmv[i], *elm)); 15090 } 15091 } 15092 15093 15094 THREADED_TEST(PropertyEnumeration) { 15095 LocalContext context; 15096 v8::Isolate* isolate = context->GetIsolate(); 15097 v8::HandleScope scope(isolate); 15098 v8::Local<v8::Value> obj = CompileRun( 15099 "var result = [];" 15100 "result[0] = {};" 15101 "result[1] = {a: 1, b: 2};" 15102 "result[2] = [1, 2, 3];" 15103 "var proto = {x: 1, y: 2, z: 3};" 15104 "var x = { __proto__: proto, w: 0, z: 1 };" 15105 "result[3] = x;" 15106 "result;"); 15107 v8::Local<v8::Array> elms = obj.As<v8::Array>(); 15108 CHECK_EQ(4u, elms->Length()); 15109 int elmc0 = 0; 15110 const char** elmv0 = NULL; 15111 CheckProperties( 15112 isolate, 15113 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 15114 elmc0, elmv0); 15115 CheckOwnProperties( 15116 isolate, 15117 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 15118 elmc0, elmv0); 15119 int elmc1 = 2; 15120 const char* elmv1[] = {"a", "b"}; 15121 CheckProperties( 15122 isolate, 15123 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(), 15124 elmc1, elmv1); 15125 CheckOwnProperties( 15126 isolate, 15127 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(), 15128 elmc1, elmv1); 15129 int elmc2 = 3; 15130 const char* elmv2[] = {"0", "1", "2"}; 15131 CheckProperties( 15132 isolate, 15133 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(), 15134 elmc2, elmv2); 15135 CheckOwnProperties( 15136 isolate, 15137 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(), 15138 elmc2, elmv2); 15139 int elmc3 = 4; 15140 const char* elmv3[] = {"w", "z", "x", "y"}; 15141 CheckProperties( 15142 isolate, 15143 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(), 15144 elmc3, elmv3); 15145 int elmc4 = 2; 15146 const char* elmv4[] = {"w", "z"}; 15147 CheckOwnProperties( 15148 isolate, 15149 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(), 15150 elmc4, elmv4); 15151 } 15152 15153 15154 THREADED_TEST(PropertyEnumeration2) { 15155 LocalContext context; 15156 v8::Isolate* isolate = context->GetIsolate(); 15157 v8::HandleScope scope(isolate); 15158 v8::Local<v8::Value> obj = CompileRun( 15159 "var result = [];" 15160 "result[0] = {};" 15161 "result[1] = {a: 1, b: 2};" 15162 "result[2] = [1, 2, 3];" 15163 "var proto = {x: 1, y: 2, z: 3};" 15164 "var x = { __proto__: proto, w: 0, z: 1 };" 15165 "result[3] = x;" 15166 "result;"); 15167 v8::Local<v8::Array> elms = obj.As<v8::Array>(); 15168 CHECK_EQ(4u, elms->Length()); 15169 int elmc0 = 0; 15170 const char** elmv0 = NULL; 15171 CheckProperties( 15172 isolate, 15173 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(), 15174 elmc0, elmv0); 15175 15176 v8::Local<v8::Value> val = 15177 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(); 15178 v8::Local<v8::Array> props = 15179 val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked(); 15180 CHECK_EQ(0u, props->Length()); 15181 for (uint32_t i = 0; i < props->Length(); i++) { 15182 printf("p[%u]\n", i); 15183 } 15184 } 15185 15186 THREADED_TEST(PropertyNames) { 15187 LocalContext context; 15188 v8::Isolate* isolate = context->GetIsolate(); 15189 v8::HandleScope scope(isolate); 15190 v8::Local<v8::Value> result = CompileRun( 15191 "var result = {0: 0, 1: 1, a: 2, b: 3};" 15192 "result[Symbol('symbol')] = true;" 15193 "result.__proto__ = {2: 4, 3: 5, c: 6, d: 7};" 15194 "result;"); 15195 v8::Local<v8::Object> object = result.As<v8::Object>(); 15196 v8::PropertyFilter default_filter = 15197 static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS); 15198 v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE; 15199 15200 v8::Local<v8::Array> properties = 15201 object->GetPropertyNames(context.local()).ToLocalChecked(); 15202 const char* expected_properties1[] = {"0", "1", "a", "b", "2", "3", "c", "d"}; 15203 CheckStringArray(isolate, properties, 8, expected_properties1); 15204 15205 properties = 15206 object 15207 ->GetPropertyNames(context.local(), 15208 v8::KeyCollectionMode::kIncludePrototypes, 15209 default_filter, v8::IndexFilter::kIncludeIndices) 15210 .ToLocalChecked(); 15211 CheckStringArray(isolate, properties, 8, expected_properties1); 15212 15213 properties = object 15214 ->GetPropertyNames(context.local(), 15215 v8::KeyCollectionMode::kIncludePrototypes, 15216 include_symbols_filter, 15217 v8::IndexFilter::kIncludeIndices) 15218 .ToLocalChecked(); 15219 const char* expected_properties1_1[] = {"0", "1", "a", "b", nullptr, 15220 "2", "3", "c", "d"}; 15221 CheckStringArray(isolate, properties, 9, expected_properties1_1); 15222 CheckIsSymbolAt(isolate, properties, 4, "symbol"); 15223 15224 properties = 15225 object 15226 ->GetPropertyNames(context.local(), 15227 v8::KeyCollectionMode::kIncludePrototypes, 15228 default_filter, v8::IndexFilter::kSkipIndices) 15229 .ToLocalChecked(); 15230 const char* expected_properties2[] = {"a", "b", "c", "d"}; 15231 CheckStringArray(isolate, properties, 4, expected_properties2); 15232 15233 properties = object 15234 ->GetPropertyNames(context.local(), 15235 v8::KeyCollectionMode::kIncludePrototypes, 15236 include_symbols_filter, 15237 v8::IndexFilter::kSkipIndices) 15238 .ToLocalChecked(); 15239 const char* expected_properties2_1[] = {"a", "b", nullptr, "c", "d"}; 15240 CheckStringArray(isolate, properties, 5, expected_properties2_1); 15241 CheckIsSymbolAt(isolate, properties, 2, "symbol"); 15242 15243 properties = 15244 object 15245 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly, 15246 default_filter, v8::IndexFilter::kIncludeIndices) 15247 .ToLocalChecked(); 15248 const char* expected_properties3[] = {"0", "1", "a", "b"}; 15249 CheckStringArray(isolate, properties, 4, expected_properties3); 15250 15251 properties = object 15252 ->GetPropertyNames( 15253 context.local(), v8::KeyCollectionMode::kOwnOnly, 15254 include_symbols_filter, v8::IndexFilter::kIncludeIndices) 15255 .ToLocalChecked(); 15256 const char* expected_properties3_1[] = {"0", "1", "a", "b", nullptr}; 15257 CheckStringArray(isolate, properties, 5, expected_properties3_1); 15258 CheckIsSymbolAt(isolate, properties, 4, "symbol"); 15259 15260 properties = 15261 object 15262 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly, 15263 default_filter, v8::IndexFilter::kSkipIndices) 15264 .ToLocalChecked(); 15265 const char* expected_properties4[] = {"a", "b"}; 15266 CheckStringArray(isolate, properties, 2, expected_properties4); 15267 15268 properties = object 15269 ->GetPropertyNames( 15270 context.local(), v8::KeyCollectionMode::kOwnOnly, 15271 include_symbols_filter, v8::IndexFilter::kSkipIndices) 15272 .ToLocalChecked(); 15273 const char* expected_properties4_1[] = {"a", "b", nullptr}; 15274 CheckStringArray(isolate, properties, 3, expected_properties4_1); 15275 CheckIsSymbolAt(isolate, properties, 2, "symbol"); 15276 } 15277 15278 THREADED_TEST(AccessChecksReenabledCorrectly) { 15279 LocalContext context; 15280 v8::Isolate* isolate = context->GetIsolate(); 15281 v8::HandleScope scope(isolate); 15282 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 15283 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 15284 templ->Set(v8_str("a"), v8_str("a")); 15285 // Add more than 8 (see kMaxFastProperties) properties 15286 // so that the constructor will force copying map. 15287 // Cannot sprintf, gcc complains unsafety. 15288 char buf[4]; 15289 for (char i = '0'; i <= '9' ; i++) { 15290 buf[0] = i; 15291 for (char j = '0'; j <= '9'; j++) { 15292 buf[1] = j; 15293 for (char k = '0'; k <= '9'; k++) { 15294 buf[2] = k; 15295 buf[3] = 0; 15296 templ->Set(v8_str(buf), v8::Number::New(isolate, k)); 15297 } 15298 } 15299 } 15300 15301 Local<v8::Object> instance_1 = 15302 templ->NewInstance(context.local()).ToLocalChecked(); 15303 CHECK(context->Global() 15304 ->Set(context.local(), v8_str("obj_1"), instance_1) 15305 .FromJust()); 15306 15307 Local<Value> value_1 = CompileRun("obj_1.a"); 15308 CHECK(value_1.IsEmpty()); 15309 15310 Local<v8::Object> instance_2 = 15311 templ->NewInstance(context.local()).ToLocalChecked(); 15312 CHECK(context->Global() 15313 ->Set(context.local(), v8_str("obj_2"), instance_2) 15314 .FromJust()); 15315 15316 Local<Value> value_2 = CompileRun("obj_2.a"); 15317 CHECK(value_2.IsEmpty()); 15318 } 15319 15320 15321 // Tests that ScriptData can be serialized and deserialized. 15322 TEST(PreCompileSerialization) { 15323 // Producing cached parser data while parsing eagerly is not supported. 15324 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return; 15325 15326 v8::V8::Initialize(); 15327 LocalContext env; 15328 v8::Isolate* isolate = env->GetIsolate(); 15329 HandleScope handle_scope(isolate); 15330 15331 i::FLAG_min_preparse_length = 0; 15332 const char* script = "function foo(a) { return a+1; }"; 15333 v8::ScriptCompiler::Source source(v8_str(script)); 15334 v8::ScriptCompiler::Compile(env.local(), &source, 15335 v8::ScriptCompiler::kProduceParserCache) 15336 .ToLocalChecked(); 15337 // Serialize. 15338 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); 15339 i::byte* serialized_data = i::NewArray<i::byte>(cd->length); 15340 i::MemCopy(serialized_data, cd->data, cd->length); 15341 15342 // Deserialize. 15343 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length); 15344 15345 // Verify that the original is the same as the deserialized. 15346 CHECK_EQ(cd->length, deserialized->length()); 15347 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length)); 15348 15349 delete deserialized; 15350 i::DeleteArray(serialized_data); 15351 } 15352 15353 15354 // This tests that we do not allow dictionary load/call inline caches 15355 // to use functions that have not yet been compiled. The potential 15356 // problem of loading a function that has not yet been compiled can 15357 // arise because we share code between contexts via the compilation 15358 // cache. 15359 THREADED_TEST(DictionaryICLoadedFunction) { 15360 v8::HandleScope scope(CcTest::isolate()); 15361 // Test LoadIC. 15362 for (int i = 0; i < 2; i++) { 15363 LocalContext context; 15364 CHECK(context->Global() 15365 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate())) 15366 .FromJust()); 15367 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust(); 15368 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 15369 } 15370 // Test CallIC. 15371 for (int i = 0; i < 2; i++) { 15372 LocalContext context; 15373 CHECK(context->Global() 15374 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate())) 15375 .FromJust()); 15376 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust(); 15377 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 15378 } 15379 } 15380 15381 15382 // Test that cross-context new calls use the context of the callee to 15383 // create the new JavaScript object. 15384 THREADED_TEST(CrossContextNew) { 15385 v8::Isolate* isolate = CcTest::isolate(); 15386 v8::HandleScope scope(isolate); 15387 v8::Local<Context> context0 = Context::New(isolate); 15388 v8::Local<Context> context1 = Context::New(isolate); 15389 15390 // Allow cross-domain access. 15391 Local<String> token = v8_str("<security token>"); 15392 context0->SetSecurityToken(token); 15393 context1->SetSecurityToken(token); 15394 15395 // Set an 'x' property on the Object prototype and define a 15396 // constructor function in context0. 15397 context0->Enter(); 15398 CompileRun("Object.prototype.x = 42; function C() {};"); 15399 context0->Exit(); 15400 15401 // Call the constructor function from context0 and check that the 15402 // result has the 'x' property. 15403 context1->Enter(); 15404 CHECK(context1->Global() 15405 ->Set(context1, v8_str("other"), context0->Global()) 15406 .FromJust()); 15407 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 15408 CHECK(value->IsInt32()); 15409 CHECK_EQ(42, value->Int32Value(context1).FromJust()); 15410 context1->Exit(); 15411 } 15412 15413 15414 // Verify that we can clone an object 15415 TEST(ObjectClone) { 15416 LocalContext env; 15417 v8::Isolate* isolate = env->GetIsolate(); 15418 v8::HandleScope scope(isolate); 15419 15420 const char* sample = 15421 "var rv = {};" \ 15422 "rv.alpha = 'hello';" \ 15423 "rv.beta = 123;" \ 15424 "rv;"; 15425 15426 // Create an object, verify basics. 15427 Local<Value> val = CompileRun(sample); 15428 CHECK(val->IsObject()); 15429 Local<v8::Object> obj = val.As<v8::Object>(); 15430 obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust(); 15431 15432 CHECK(v8_str("hello") 15433 ->Equals(env.local(), 15434 obj->Get(env.local(), v8_str("alpha")).ToLocalChecked()) 15435 .FromJust()); 15436 CHECK(v8::Integer::New(isolate, 123) 15437 ->Equals(env.local(), 15438 obj->Get(env.local(), v8_str("beta")).ToLocalChecked()) 15439 .FromJust()); 15440 CHECK(v8_str("cloneme") 15441 ->Equals(env.local(), 15442 obj->Get(env.local(), v8_str("gamma")).ToLocalChecked()) 15443 .FromJust()); 15444 15445 // Clone it. 15446 Local<v8::Object> clone = obj->Clone(); 15447 CHECK(v8_str("hello") 15448 ->Equals(env.local(), 15449 clone->Get(env.local(), v8_str("alpha")).ToLocalChecked()) 15450 .FromJust()); 15451 CHECK(v8::Integer::New(isolate, 123) 15452 ->Equals(env.local(), 15453 clone->Get(env.local(), v8_str("beta")).ToLocalChecked()) 15454 .FromJust()); 15455 CHECK(v8_str("cloneme") 15456 ->Equals(env.local(), 15457 clone->Get(env.local(), v8_str("gamma")).ToLocalChecked()) 15458 .FromJust()); 15459 15460 // Set a property on the clone, verify each object. 15461 CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456)) 15462 .FromJust()); 15463 CHECK(v8::Integer::New(isolate, 123) 15464 ->Equals(env.local(), 15465 obj->Get(env.local(), v8_str("beta")).ToLocalChecked()) 15466 .FromJust()); 15467 CHECK(v8::Integer::New(isolate, 456) 15468 ->Equals(env.local(), 15469 clone->Get(env.local(), v8_str("beta")).ToLocalChecked()) 15470 .FromJust()); 15471 } 15472 15473 15474 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource { 15475 public: 15476 explicit OneByteVectorResource(i::Vector<const char> vector) 15477 : data_(vector) {} 15478 virtual ~OneByteVectorResource() {} 15479 virtual size_t length() const { return data_.length(); } 15480 virtual const char* data() const { return data_.start(); } 15481 private: 15482 i::Vector<const char> data_; 15483 }; 15484 15485 15486 class UC16VectorResource : public v8::String::ExternalStringResource { 15487 public: 15488 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 15489 : data_(vector) {} 15490 virtual ~UC16VectorResource() {} 15491 virtual size_t length() const { return data_.length(); } 15492 virtual const i::uc16* data() const { return data_.start(); } 15493 private: 15494 i::Vector<const i::uc16> data_; 15495 }; 15496 15497 15498 static void MorphAString(i::String* string, 15499 OneByteVectorResource* one_byte_resource, 15500 UC16VectorResource* uc16_resource) { 15501 CHECK(i::StringShape(string).IsExternal()); 15502 if (string->IsOneByteRepresentation()) { 15503 // Check old map is not internalized or long. 15504 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map()); 15505 // Morph external string to be TwoByte string. 15506 string->set_map(CcTest::heap()->external_string_map()); 15507 i::ExternalTwoByteString* morphed = 15508 i::ExternalTwoByteString::cast(string); 15509 morphed->set_resource(uc16_resource); 15510 } else { 15511 // Check old map is not internalized or long. 15512 CHECK(string->map() == CcTest::heap()->external_string_map()); 15513 // Morph external string to be one-byte string. 15514 string->set_map(CcTest::heap()->external_one_byte_string_map()); 15515 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string); 15516 morphed->set_resource(one_byte_resource); 15517 } 15518 } 15519 15520 15521 // Test that we can still flatten a string if the components it is built up 15522 // from have been turned into 16 bit strings in the mean time. 15523 THREADED_TEST(MorphCompositeStringTest) { 15524 char utf_buffer[129]; 15525 const char* c_string = "Now is the time for all good men" 15526 " to come to the aid of the party"; 15527 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 15528 { 15529 LocalContext env; 15530 i::Factory* factory = CcTest::i_isolate()->factory(); 15531 v8::HandleScope scope(env->GetIsolate()); 15532 OneByteVectorResource one_byte_resource( 15533 i::Vector<const char>(c_string, i::StrLength(c_string))); 15534 UC16VectorResource uc16_resource( 15535 i::Vector<const uint16_t>(two_byte_string, 15536 i::StrLength(c_string))); 15537 15538 Local<String> lhs( 15539 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 15540 &one_byte_resource).ToHandleChecked())); 15541 Local<String> rhs( 15542 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 15543 &one_byte_resource).ToHandleChecked())); 15544 15545 CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust()); 15546 CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust()); 15547 15548 CompileRun( 15549 "var cons = lhs + rhs;" 15550 "var slice = lhs.substring(1, lhs.length - 1);" 15551 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 15552 15553 CHECK(lhs->IsOneByte()); 15554 CHECK(rhs->IsOneByte()); 15555 15556 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource, 15557 &uc16_resource); 15558 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource, 15559 &uc16_resource); 15560 15561 // This should UTF-8 without flattening, since everything is ASCII. 15562 Local<String> cons = 15563 v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>(); 15564 CHECK_EQ(128, cons->Utf8Length()); 15565 int nchars = -1; 15566 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 15567 CHECK_EQ(128, nchars); 15568 CHECK_EQ(0, strcmp( 15569 utf_buffer, 15570 "Now is the time for all good men to come to the aid of the party" 15571 "Now is the time for all good men to come to the aid of the party")); 15572 15573 // Now do some stuff to make sure the strings are flattened, etc. 15574 CompileRun( 15575 "/[^a-z]/.test(cons);" 15576 "/[^a-z]/.test(slice);" 15577 "/[^a-z]/.test(slice_on_cons);"); 15578 const char* expected_cons = 15579 "Now is the time for all good men to come to the aid of the party" 15580 "Now is the time for all good men to come to the aid of the party"; 15581 const char* expected_slice = 15582 "ow is the time for all good men to come to the aid of the part"; 15583 const char* expected_slice_on_cons = 15584 "ow is the time for all good men to come to the aid of the party" 15585 "Now is the time for all good men to come to the aid of the part"; 15586 CHECK(v8_str(expected_cons) 15587 ->Equals(env.local(), env->Global() 15588 ->Get(env.local(), v8_str("cons")) 15589 .ToLocalChecked()) 15590 .FromJust()); 15591 CHECK(v8_str(expected_slice) 15592 ->Equals(env.local(), env->Global() 15593 ->Get(env.local(), v8_str("slice")) 15594 .ToLocalChecked()) 15595 .FromJust()); 15596 CHECK(v8_str(expected_slice_on_cons) 15597 ->Equals(env.local(), 15598 env->Global() 15599 ->Get(env.local(), v8_str("slice_on_cons")) 15600 .ToLocalChecked()) 15601 .FromJust()); 15602 } 15603 i::DeleteArray(two_byte_string); 15604 } 15605 15606 15607 TEST(CompileExternalTwoByteSource) { 15608 LocalContext context; 15609 v8::HandleScope scope(context->GetIsolate()); 15610 15611 // This is a very short list of sources, which currently is to check for a 15612 // regression caused by r2703. 15613 const char* one_byte_sources[] = { 15614 "0.5", 15615 "-0.5", // This mainly testes PushBack in the Scanner. 15616 "--0.5", // This mainly testes PushBack in the Scanner. 15617 NULL}; 15618 15619 // Compile the sources as external two byte strings. 15620 for (int i = 0; one_byte_sources[i] != NULL; i++) { 15621 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]); 15622 TestResource* uc16_resource = new TestResource(two_byte_string); 15623 v8::Local<v8::String> source = 15624 v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource) 15625 .ToLocalChecked(); 15626 v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>()); 15627 } 15628 } 15629 15630 15631 #ifndef V8_INTERPRETED_REGEXP 15632 15633 struct RegExpInterruptionData { 15634 v8::base::Atomic32 loop_count; 15635 UC16VectorResource* string_resource; 15636 v8::Persistent<v8::String> string; 15637 } regexp_interruption_data; 15638 15639 15640 class RegExpInterruptionThread : public v8::base::Thread { 15641 public: 15642 explicit RegExpInterruptionThread(v8::Isolate* isolate) 15643 : Thread(Options("TimeoutThread")), isolate_(isolate) {} 15644 15645 virtual void Run() { 15646 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0); 15647 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7; 15648 v8::base::NoBarrier_AtomicIncrement( 15649 ®exp_interruption_data.loop_count, 1)) { 15650 // Wait a bit before requesting GC. 15651 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50)); 15652 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); 15653 } 15654 // Wait a bit before terminating. 15655 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50)); 15656 isolate_->TerminateExecution(); 15657 } 15658 15659 private: 15660 v8::Isolate* isolate_; 15661 }; 15662 15663 15664 void RunBeforeGC(v8::Isolate* isolate, v8::GCType type, 15665 v8::GCCallbackFlags flags) { 15666 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) { 15667 return; 15668 } 15669 v8::HandleScope scope(isolate); 15670 v8::Local<v8::String> string = v8::Local<v8::String>::New( 15671 CcTest::isolate(), regexp_interruption_data.string); 15672 string->MakeExternal(regexp_interruption_data.string_resource); 15673 } 15674 15675 15676 // Test that RegExp execution can be interrupted. Specifically, we test 15677 // * interrupting with GC 15678 // * turn the subject string from one-byte internal to two-byte external string 15679 // * force termination 15680 TEST(RegExpInterruption) { 15681 LocalContext env; 15682 v8::HandleScope scope(env->GetIsolate()); 15683 15684 RegExpInterruptionThread timeout_thread(env->GetIsolate()); 15685 15686 env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC); 15687 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 15688 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content); 15689 v8::Local<v8::String> string = v8_str(one_byte_content); 15690 15691 env->Global()->Set(env.local(), v8_str("a"), string).FromJust(); 15692 regexp_interruption_data.string.Reset(env->GetIsolate(), string); 15693 regexp_interruption_data.string_resource = new UC16VectorResource( 15694 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content))); 15695 15696 v8::TryCatch try_catch(env->GetIsolate()); 15697 timeout_thread.Start(); 15698 15699 CompileRun("/((a*)*)*b/.exec(a)"); 15700 CHECK(try_catch.HasTerminated()); 15701 15702 timeout_thread.Join(); 15703 15704 regexp_interruption_data.string.Reset(); 15705 i::DeleteArray(uc16_content); 15706 } 15707 15708 #endif // V8_INTERPRETED_REGEXP 15709 15710 15711 // Test that we cannot set a property on the global object if there 15712 // is a read-only property in the prototype chain. 15713 TEST(ReadOnlyPropertyInGlobalProto) { 15714 v8::Isolate* isolate = CcTest::isolate(); 15715 v8::HandleScope scope(isolate); 15716 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15717 LocalContext context(0, templ); 15718 v8::Local<v8::Object> global = context->Global(); 15719 v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast( 15720 global->Get(context.local(), v8_str("__proto__")).ToLocalChecked()); 15721 global_proto->DefineOwnProperty(context.local(), v8_str("x"), 15722 v8::Integer::New(isolate, 0), v8::ReadOnly) 15723 .FromJust(); 15724 global_proto->DefineOwnProperty(context.local(), v8_str("y"), 15725 v8::Integer::New(isolate, 0), v8::ReadOnly) 15726 .FromJust(); 15727 // Check without 'eval' or 'with'. 15728 v8::Local<v8::Value> res = 15729 CompileRun("function f() { x = 42; return x; }; f()"); 15730 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15731 // Check with 'eval'. 15732 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 15733 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15734 // Check with 'with'. 15735 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 15736 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust()); 15737 } 15738 15739 15740 TEST(CreateDataProperty) { 15741 LocalContext env; 15742 v8::Isolate* isolate = env->GetIsolate(); 15743 v8::HandleScope handle_scope(isolate); 15744 15745 CompileRun( 15746 "var a = {};" 15747 "var b = [];" 15748 "Object.defineProperty(a, 'foo', {value: 23});" 15749 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); 15750 15751 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast( 15752 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 15753 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast( 15754 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 15755 { 15756 // Can't change a non-configurable properties. 15757 v8::TryCatch try_catch(isolate); 15758 CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"), 15759 v8::Integer::New(isolate, 42)).FromJust()); 15760 CHECK(!try_catch.HasCaught()); 15761 CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"), 15762 v8::Integer::New(isolate, 42)).FromJust()); 15763 CHECK(!try_catch.HasCaught()); 15764 v8::Local<v8::Value> val = 15765 obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); 15766 CHECK(val->IsNumber()); 15767 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15768 } 15769 15770 { 15771 // Set a regular property. 15772 v8::TryCatch try_catch(isolate); 15773 CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"), 15774 v8::Integer::New(isolate, 42)).FromJust()); 15775 CHECK(!try_catch.HasCaught()); 15776 v8::Local<v8::Value> val = 15777 obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); 15778 CHECK(val->IsNumber()); 15779 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15780 } 15781 15782 { 15783 // Set an indexed property. 15784 v8::TryCatch try_catch(isolate); 15785 CHECK(obj->CreateDataProperty(env.local(), v8_str("1"), 15786 v8::Integer::New(isolate, 42)).FromJust()); 15787 CHECK(!try_catch.HasCaught()); 15788 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); 15789 CHECK(val->IsNumber()); 15790 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15791 } 15792 15793 { 15794 // Special cases for arrays. 15795 v8::TryCatch try_catch(isolate); 15796 CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"), 15797 v8::Integer::New(isolate, 1)).FromJust()); 15798 CHECK(!try_catch.HasCaught()); 15799 } 15800 { 15801 // Special cases for arrays: index exceeds the array's length 15802 v8::TryCatch try_catch(isolate); 15803 CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23)) 15804 .FromJust()); 15805 CHECK(!try_catch.HasCaught()); 15806 CHECK_EQ(2U, arr->Length()); 15807 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); 15808 CHECK(val->IsNumber()); 15809 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); 15810 15811 // Set an existing entry. 15812 CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42)) 15813 .FromJust()); 15814 CHECK(!try_catch.HasCaught()); 15815 val = arr->Get(env.local(), 0).ToLocalChecked(); 15816 CHECK(val->IsNumber()); 15817 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15818 } 15819 15820 CompileRun("Object.freeze(a);"); 15821 { 15822 // Can't change non-extensible objects. 15823 v8::TryCatch try_catch(isolate); 15824 CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"), 15825 v8::Integer::New(isolate, 42)).FromJust()); 15826 CHECK(!try_catch.HasCaught()); 15827 } 15828 15829 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15830 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 15831 v8::Local<v8::Object> access_checked = 15832 templ->NewInstance(env.local()).ToLocalChecked(); 15833 { 15834 v8::TryCatch try_catch(isolate); 15835 CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"), 15836 v8::Integer::New(isolate, 42)) 15837 .IsNothing()); 15838 CHECK(try_catch.HasCaught()); 15839 } 15840 } 15841 15842 15843 TEST(DefineOwnProperty) { 15844 LocalContext env; 15845 v8::Isolate* isolate = env->GetIsolate(); 15846 v8::HandleScope handle_scope(isolate); 15847 15848 CompileRun( 15849 "var a = {};" 15850 "var b = [];" 15851 "Object.defineProperty(a, 'foo', {value: 23});" 15852 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});"); 15853 15854 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast( 15855 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 15856 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast( 15857 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 15858 { 15859 // Can't change a non-configurable properties. 15860 v8::TryCatch try_catch(isolate); 15861 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"), 15862 v8::Integer::New(isolate, 42)).FromJust()); 15863 CHECK(!try_catch.HasCaught()); 15864 CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"), 15865 v8::Integer::New(isolate, 42)).FromJust()); 15866 CHECK(!try_catch.HasCaught()); 15867 v8::Local<v8::Value> val = 15868 obj->Get(env.local(), v8_str("bar")).ToLocalChecked(); 15869 CHECK(val->IsNumber()); 15870 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15871 } 15872 15873 { 15874 // Set a regular property. 15875 v8::TryCatch try_catch(isolate); 15876 CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"), 15877 v8::Integer::New(isolate, 42)).FromJust()); 15878 CHECK(!try_catch.HasCaught()); 15879 v8::Local<v8::Value> val = 15880 obj->Get(env.local(), v8_str("blub")).ToLocalChecked(); 15881 CHECK(val->IsNumber()); 15882 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15883 } 15884 15885 { 15886 // Set an indexed property. 15887 v8::TryCatch try_catch(isolate); 15888 CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"), 15889 v8::Integer::New(isolate, 42)).FromJust()); 15890 CHECK(!try_catch.HasCaught()); 15891 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked(); 15892 CHECK(val->IsNumber()); 15893 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15894 } 15895 15896 { 15897 // Special cases for arrays. 15898 v8::TryCatch try_catch(isolate); 15899 CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"), 15900 v8::Integer::New(isolate, 1)).FromJust()); 15901 CHECK(!try_catch.HasCaught()); 15902 } 15903 { 15904 // Special cases for arrays: index exceeds the array's length 15905 v8::TryCatch try_catch(isolate); 15906 CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"), 15907 v8::Integer::New(isolate, 23)).FromJust()); 15908 CHECK(!try_catch.HasCaught()); 15909 CHECK_EQ(2U, arr->Length()); 15910 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked(); 15911 CHECK(val->IsNumber()); 15912 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust()); 15913 15914 // Set an existing entry. 15915 CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"), 15916 v8::Integer::New(isolate, 42)).FromJust()); 15917 CHECK(!try_catch.HasCaught()); 15918 val = arr->Get(env.local(), 0).ToLocalChecked(); 15919 CHECK(val->IsNumber()); 15920 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15921 } 15922 15923 { 15924 // Set a non-writable property. 15925 v8::TryCatch try_catch(isolate); 15926 CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"), 15927 v8::Integer::New(isolate, 42), 15928 v8::ReadOnly).FromJust()); 15929 CHECK(!try_catch.HasCaught()); 15930 v8::Local<v8::Value> val = 15931 obj->Get(env.local(), v8_str("lala")).ToLocalChecked(); 15932 CHECK(val->IsNumber()); 15933 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust()); 15934 CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes( 15935 env.local(), v8_str("lala")).FromJust()); 15936 CHECK(!try_catch.HasCaught()); 15937 } 15938 15939 CompileRun("Object.freeze(a);"); 15940 { 15941 // Can't change non-extensible objects. 15942 v8::TryCatch try_catch(isolate); 15943 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"), 15944 v8::Integer::New(isolate, 42)).FromJust()); 15945 CHECK(!try_catch.HasCaught()); 15946 } 15947 15948 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15949 templ->SetAccessCheckCallback(AccessAlwaysBlocked); 15950 v8::Local<v8::Object> access_checked = 15951 templ->NewInstance(env.local()).ToLocalChecked(); 15952 { 15953 v8::TryCatch try_catch(isolate); 15954 CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"), 15955 v8::Integer::New(isolate, 42)) 15956 .IsNothing()); 15957 CHECK(try_catch.HasCaught()); 15958 } 15959 } 15960 15961 15962 THREADED_TEST(GetCurrentContextWhenNotInContext) { 15963 i::Isolate* isolate = CcTest::i_isolate(); 15964 CHECK(isolate != NULL); 15965 CHECK(isolate->context() == NULL); 15966 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 15967 v8::HandleScope scope(v8_isolate); 15968 // The following should not crash, but return an empty handle. 15969 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 15970 CHECK(current.IsEmpty()); 15971 } 15972 15973 15974 // Check that a variable declaration with no explicit initialization 15975 // value does shadow an existing property in the prototype chain. 15976 THREADED_TEST(InitGlobalVarInProtoChain) { 15977 LocalContext context; 15978 v8::HandleScope scope(context->GetIsolate()); 15979 // Introduce a variable in the prototype chain. 15980 CompileRun("__proto__.x = 42"); 15981 v8::Local<v8::Value> result = CompileRun("var x = 43; x"); 15982 CHECK(!result->IsUndefined()); 15983 CHECK_EQ(43, result->Int32Value(context.local()).FromJust()); 15984 } 15985 15986 15987 // Regression test for issue 398. 15988 // If a function is added to an object, creating a constant function 15989 // field, and the result is cloned, replacing the constant function on the 15990 // original should not affect the clone. 15991 // See http://code.google.com/p/v8/issues/detail?id=398 15992 THREADED_TEST(ReplaceConstantFunction) { 15993 LocalContext context; 15994 v8::Isolate* isolate = context->GetIsolate(); 15995 v8::HandleScope scope(isolate); 15996 v8::Local<v8::Object> obj = v8::Object::New(isolate); 15997 v8::Local<v8::FunctionTemplate> func_templ = 15998 v8::FunctionTemplate::New(isolate); 15999 v8::Local<v8::String> foo_string = v8_str("foo"); 16000 obj->Set(context.local(), foo_string, 16001 func_templ->GetFunction(context.local()).ToLocalChecked()) 16002 .FromJust(); 16003 v8::Local<v8::Object> obj_clone = obj->Clone(); 16004 obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust(); 16005 CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined()); 16006 } 16007 16008 16009 static void CheckElementValue(i::Isolate* isolate, 16010 int expected, 16011 i::Handle<i::Object> obj, 16012 int offset) { 16013 i::Object* element = 16014 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked(); 16015 CHECK_EQ(expected, i::Smi::cast(element)->value()); 16016 } 16017 16018 16019 template <class ExternalArrayClass, class ElementType> 16020 static void ObjectWithExternalArrayTestHelper(Local<Context> context, 16021 v8::Local<Object> obj, 16022 int element_count, 16023 i::ExternalArrayType array_type, 16024 int64_t low, int64_t high) { 16025 i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj); 16026 i::Isolate* isolate = jsobj->GetIsolate(); 16027 obj->Set(context, v8_str("field"), 16028 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503)) 16029 .FromJust(); 16030 CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust()); 16031 v8::Local<v8::Value> result = CompileRun("ext_array.field"); 16032 CHECK_EQ(1503, result->Int32Value(context).FromJust()); 16033 result = CompileRun("ext_array[1]"); 16034 CHECK_EQ(1, result->Int32Value(context).FromJust()); 16035 16036 // Check assigned smis 16037 result = CompileRun("for (var i = 0; i < 8; i++) {" 16038 " ext_array[i] = i;" 16039 "}" 16040 "var sum = 0;" 16041 "for (var i = 0; i < 8; i++) {" 16042 " sum += ext_array[i];" 16043 "}" 16044 "sum;"); 16045 16046 CHECK_EQ(28, result->Int32Value(context).FromJust()); 16047 // Check pass through of assigned smis 16048 result = CompileRun("var sum = 0;" 16049 "for (var i = 0; i < 8; i++) {" 16050 " sum += ext_array[i] = ext_array[i] = -i;" 16051 "}" 16052 "sum;"); 16053 CHECK_EQ(-28, result->Int32Value(context).FromJust()); 16054 16055 16056 // Check assigned smis in reverse order 16057 result = CompileRun("for (var i = 8; --i >= 0; ) {" 16058 " ext_array[i] = i;" 16059 "}" 16060 "var sum = 0;" 16061 "for (var i = 0; i < 8; i++) {" 16062 " sum += ext_array[i];" 16063 "}" 16064 "sum;"); 16065 CHECK_EQ(28, result->Int32Value(context).FromJust()); 16066 16067 // Check pass through of assigned HeapNumbers 16068 result = CompileRun("var sum = 0;" 16069 "for (var i = 0; i < 16; i+=2) {" 16070 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 16071 "}" 16072 "sum;"); 16073 CHECK_EQ(-28, result->Int32Value(context).FromJust()); 16074 16075 // Check assigned HeapNumbers 16076 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 16077 " ext_array[i] = (i * 0.5);" 16078 "}" 16079 "var sum = 0;" 16080 "for (var i = 0; i < 16; i+=2) {" 16081 " sum += ext_array[i];" 16082 "}" 16083 "sum;"); 16084 CHECK_EQ(28, result->Int32Value(context).FromJust()); 16085 16086 // Check assigned HeapNumbers in reverse order 16087 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 16088 " ext_array[i] = (i * 0.5);" 16089 "}" 16090 "var sum = 0;" 16091 "for (var i = 0; i < 16; i+=2) {" 16092 " sum += ext_array[i];" 16093 "}" 16094 "sum;"); 16095 CHECK_EQ(28, result->Int32Value(context).FromJust()); 16096 16097 i::ScopedVector<char> test_buf(1024); 16098 16099 // Check legal boundary conditions. 16100 // The repeated loads and stores ensure the ICs are exercised. 16101 const char* boundary_program = 16102 "var res = 0;" 16103 "for (var i = 0; i < 16; i++) {" 16104 " ext_array[i] = %lld;" 16105 " if (i > 8) {" 16106 " res = ext_array[i];" 16107 " }" 16108 "}" 16109 "res;"; 16110 i::SNPrintF(test_buf, 16111 boundary_program, 16112 low); 16113 result = CompileRun(test_buf.start()); 16114 CHECK_EQ(low, result->IntegerValue(context).FromJust()); 16115 16116 i::SNPrintF(test_buf, 16117 boundary_program, 16118 high); 16119 result = CompileRun(test_buf.start()); 16120 CHECK_EQ(high, result->IntegerValue(context).FromJust()); 16121 16122 // Check misprediction of type in IC. 16123 result = CompileRun("var tmp_array = ext_array;" 16124 "var sum = 0;" 16125 "for (var i = 0; i < 8; i++) {" 16126 " tmp_array[i] = i;" 16127 " sum += tmp_array[i];" 16128 " if (i == 4) {" 16129 " tmp_array = {};" 16130 " }" 16131 "}" 16132 "sum;"); 16133 // Force GC to trigger verification. 16134 CcTest::heap()->CollectAllGarbage(); 16135 CHECK_EQ(28, result->Int32Value(context).FromJust()); 16136 16137 // Make sure out-of-range loads do not throw. 16138 i::SNPrintF(test_buf, 16139 "var caught_exception = false;" 16140 "try {" 16141 " ext_array[%d];" 16142 "} catch (e) {" 16143 " caught_exception = true;" 16144 "}" 16145 "caught_exception;", 16146 element_count); 16147 result = CompileRun(test_buf.start()); 16148 CHECK_EQ(false, result->BooleanValue(context).FromJust()); 16149 16150 // Make sure out-of-range stores do not throw. 16151 i::SNPrintF(test_buf, 16152 "var caught_exception = false;" 16153 "try {" 16154 " ext_array[%d] = 1;" 16155 "} catch (e) {" 16156 " caught_exception = true;" 16157 "}" 16158 "caught_exception;", 16159 element_count); 16160 result = CompileRun(test_buf.start()); 16161 CHECK_EQ(false, result->BooleanValue(context).FromJust()); 16162 16163 // Check other boundary conditions, values and operations. 16164 result = CompileRun("for (var i = 0; i < 8; i++) {" 16165 " ext_array[7] = undefined;" 16166 "}" 16167 "ext_array[7];"); 16168 CHECK_EQ(0, result->Int32Value(context).FromJust()); 16169 if (array_type == i::kExternalFloat64Array || 16170 array_type == i::kExternalFloat32Array) { 16171 CHECK(std::isnan( 16172 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number())); 16173 } else { 16174 CheckElementValue(isolate, 0, jsobj, 7); 16175 } 16176 16177 result = CompileRun("for (var i = 0; i < 8; i++) {" 16178 " ext_array[6] = '2.3';" 16179 "}" 16180 "ext_array[6];"); 16181 CHECK_EQ(2, result->Int32Value(context).FromJust()); 16182 CHECK_EQ(2, 16183 static_cast<int>( 16184 i::Object::GetElement( 16185 isolate, jsobj, 6).ToHandleChecked()->Number())); 16186 16187 if (array_type != i::kExternalFloat32Array && 16188 array_type != i::kExternalFloat64Array) { 16189 // Though the specification doesn't state it, be explicit about 16190 // converting NaNs and +/-Infinity to zero. 16191 result = CompileRun("for (var i = 0; i < 8; i++) {" 16192 " ext_array[i] = 5;" 16193 "}" 16194 "for (var i = 0; i < 8; i++) {" 16195 " ext_array[i] = NaN;" 16196 "}" 16197 "ext_array[5];"); 16198 CHECK_EQ(0, result->Int32Value(context).FromJust()); 16199 CheckElementValue(isolate, 0, jsobj, 5); 16200 16201 result = CompileRun("for (var i = 0; i < 8; i++) {" 16202 " ext_array[i] = 5;" 16203 "}" 16204 "for (var i = 0; i < 8; i++) {" 16205 " ext_array[i] = Infinity;" 16206 "}" 16207 "ext_array[5];"); 16208 int expected_value = 16209 (array_type == i::kExternalUint8ClampedArray) ? 255 : 0; 16210 CHECK_EQ(expected_value, result->Int32Value(context).FromJust()); 16211 CheckElementValue(isolate, expected_value, jsobj, 5); 16212 16213 result = CompileRun("for (var i = 0; i < 8; i++) {" 16214 " ext_array[i] = 5;" 16215 "}" 16216 "for (var i = 0; i < 8; i++) {" 16217 " ext_array[i] = -Infinity;" 16218 "}" 16219 "ext_array[5];"); 16220 CHECK_EQ(0, result->Int32Value(context).FromJust()); 16221 CheckElementValue(isolate, 0, jsobj, 5); 16222 16223 // Check truncation behavior of integral arrays. 16224 const char* unsigned_data = 16225 "var source_data = [0.6, 10.6];" 16226 "var expected_results = [0, 10];"; 16227 const char* signed_data = 16228 "var source_data = [0.6, 10.6, -0.6, -10.6];" 16229 "var expected_results = [0, 10, 0, -10];"; 16230 const char* pixel_data = 16231 "var source_data = [0.6, 10.6];" 16232 "var expected_results = [1, 11];"; 16233 bool is_unsigned = (array_type == i::kExternalUint8Array || 16234 array_type == i::kExternalUint16Array || 16235 array_type == i::kExternalUint32Array); 16236 bool is_pixel_data = array_type == i::kExternalUint8ClampedArray; 16237 16238 i::SNPrintF(test_buf, 16239 "%s" 16240 "var all_passed = true;" 16241 "for (var i = 0; i < source_data.length; i++) {" 16242 " for (var j = 0; j < 8; j++) {" 16243 " ext_array[j] = source_data[i];" 16244 " }" 16245 " all_passed = all_passed &&" 16246 " (ext_array[5] == expected_results[i]);" 16247 "}" 16248 "all_passed;", 16249 (is_unsigned ? 16250 unsigned_data : 16251 (is_pixel_data ? pixel_data : signed_data))); 16252 result = CompileRun(test_buf.start()); 16253 CHECK_EQ(true, result->BooleanValue(context).FromJust()); 16254 } 16255 16256 i::Handle<ExternalArrayClass> array(ExternalArrayClass::cast( 16257 i::Handle<i::JSObject>::cast(jsobj)->elements())); 16258 for (int i = 0; i < element_count; i++) { 16259 array->set(i, static_cast<ElementType>(i)); 16260 } 16261 16262 // Test complex assignments 16263 result = CompileRun("function ee_op_test_complex_func(sum) {" 16264 " for (var i = 0; i < 40; ++i) {" 16265 " sum += (ext_array[i] += 1);" 16266 " sum += (ext_array[i] -= 1);" 16267 " } " 16268 " return sum;" 16269 "}" 16270 "sum=0;" 16271 "for (var i=0;i<10000;++i) {" 16272 " sum=ee_op_test_complex_func(sum);" 16273 "}" 16274 "sum;"); 16275 CHECK_EQ(16000000, result->Int32Value(context).FromJust()); 16276 16277 // Test count operations 16278 result = CompileRun("function ee_op_test_count_func(sum) {" 16279 " for (var i = 0; i < 40; ++i) {" 16280 " sum += (++ext_array[i]);" 16281 " sum += (--ext_array[i]);" 16282 " } " 16283 " return sum;" 16284 "}" 16285 "sum=0;" 16286 "for (var i=0;i<10000;++i) {" 16287 " sum=ee_op_test_count_func(sum);" 16288 "}" 16289 "sum;"); 16290 CHECK_EQ(16000000, result->Int32Value(context).FromJust()); 16291 16292 result = CompileRun("ext_array[3] = 33;" 16293 "delete ext_array[3];" 16294 "ext_array[3];"); 16295 CHECK_EQ(33, result->Int32Value(context).FromJust()); 16296 16297 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 16298 "ext_array[2] = 12; ext_array[3] = 13;" 16299 "ext_array.__defineGetter__('2'," 16300 "function() { return 120; });" 16301 "ext_array[2];"); 16302 CHECK_EQ(12, result->Int32Value(context).FromJust()); 16303 16304 result = CompileRun("var js_array = new Array(40);" 16305 "js_array[0] = 77;" 16306 "js_array;"); 16307 CHECK_EQ(77, v8::Object::Cast(*result) 16308 ->Get(context, v8_str("0")) 16309 .ToLocalChecked() 16310 ->Int32Value(context) 16311 .FromJust()); 16312 16313 result = CompileRun("ext_array[1] = 23;" 16314 "ext_array.__proto__ = [];" 16315 "js_array.__proto__ = ext_array;" 16316 "js_array.concat(ext_array);"); 16317 CHECK_EQ(77, v8::Object::Cast(*result) 16318 ->Get(context, v8_str("0")) 16319 .ToLocalChecked() 16320 ->Int32Value(context) 16321 .FromJust()); 16322 CHECK_EQ(23, v8::Object::Cast(*result) 16323 ->Get(context, v8_str("1")) 16324 .ToLocalChecked() 16325 ->Int32Value(context) 16326 .FromJust()); 16327 16328 result = CompileRun("ext_array[1] = 23;"); 16329 CHECK_EQ(23, result->Int32Value(context).FromJust()); 16330 } 16331 16332 16333 template <class FixedTypedArrayClass, i::ElementsKind elements_kind, 16334 class ElementType> 16335 static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type, 16336 ElementType low, ElementType high) { 16337 i::FLAG_allow_natives_syntax = true; 16338 LocalContext context; 16339 i::Isolate* isolate = CcTest::i_isolate(); 16340 i::Factory* factory = isolate->factory(); 16341 v8::HandleScope scope(context->GetIsolate()); 16342 const int kElementCount = 260; 16343 i::Handle<i::JSTypedArray> jsobj = 16344 factory->NewJSTypedArray(elements_kind, kElementCount); 16345 i::Handle<FixedTypedArrayClass> fixed_array( 16346 FixedTypedArrayClass::cast(jsobj->elements())); 16347 CHECK_EQ(FixedTypedArrayClass::kInstanceType, 16348 fixed_array->map()->instance_type()); 16349 CHECK_EQ(kElementCount, fixed_array->length()); 16350 CcTest::heap()->CollectAllGarbage(); 16351 for (int i = 0; i < kElementCount; i++) { 16352 fixed_array->set(i, static_cast<ElementType>(i)); 16353 } 16354 // Force GC to trigger verification. 16355 CcTest::heap()->CollectAllGarbage(); 16356 for (int i = 0; i < kElementCount; i++) { 16357 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)), 16358 static_cast<int64_t>(fixed_array->get_scalar(i))); 16359 } 16360 v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj); 16361 16362 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>( 16363 context.local(), obj, kElementCount, array_type, 16364 static_cast<int64_t>(low), 16365 static_cast<int64_t>(high)); 16366 } 16367 16368 16369 THREADED_TEST(FixedUint8Array) { 16370 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>( 16371 i::kExternalUint8Array, 0x0, 0xFF); 16372 } 16373 16374 16375 THREADED_TEST(FixedUint8ClampedArray) { 16376 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray, 16377 i::UINT8_CLAMPED_ELEMENTS, uint8_t>( 16378 i::kExternalUint8ClampedArray, 0x0, 0xFF); 16379 } 16380 16381 16382 THREADED_TEST(FixedInt8Array) { 16383 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>( 16384 i::kExternalInt8Array, -0x80, 0x7F); 16385 } 16386 16387 16388 THREADED_TEST(FixedUint16Array) { 16389 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>( 16390 i::kExternalUint16Array, 0x0, 0xFFFF); 16391 } 16392 16393 16394 THREADED_TEST(FixedInt16Array) { 16395 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>( 16396 i::kExternalInt16Array, -0x8000, 0x7FFF); 16397 } 16398 16399 16400 THREADED_TEST(FixedUint32Array) { 16401 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>( 16402 i::kExternalUint32Array, 0x0, UINT_MAX); 16403 } 16404 16405 16406 THREADED_TEST(FixedInt32Array) { 16407 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>( 16408 i::kExternalInt32Array, INT_MIN, INT_MAX); 16409 } 16410 16411 16412 THREADED_TEST(FixedFloat32Array) { 16413 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>( 16414 i::kExternalFloat32Array, -500, 500); 16415 } 16416 16417 16418 THREADED_TEST(FixedFloat64Array) { 16419 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>( 16420 i::kExternalFloat64Array, -500, 500); 16421 } 16422 16423 16424 template <typename ElementType, typename TypedArray, class ExternalArrayClass, 16425 class ArrayBufferType> 16426 void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, 16427 int64_t high) { 16428 const int kElementCount = 50; 16429 16430 i::ScopedVector<ElementType> backing_store(kElementCount+2); 16431 16432 LocalContext env; 16433 v8::Isolate* isolate = env->GetIsolate(); 16434 v8::HandleScope handle_scope(isolate); 16435 16436 Local<ArrayBufferType> ab = 16437 ArrayBufferType::New(isolate, backing_store.start(), 16438 (kElementCount + 2) * sizeof(ElementType)); 16439 Local<TypedArray> ta = 16440 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 16441 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 16442 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 16443 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset()); 16444 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength()); 16445 CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust()); 16446 16447 ElementType* data = backing_store.start() + 2; 16448 for (int i = 0; i < kElementCount; i++) { 16449 data[i] = static_cast<ElementType>(i); 16450 } 16451 16452 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16453 env.local(), ta, kElementCount, array_type, low, high); 16454 } 16455 16456 16457 THREADED_TEST(Uint8Array) { 16458 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array, 16459 v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); 16460 } 16461 16462 16463 THREADED_TEST(Int8Array) { 16464 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array, 16465 v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F); 16466 } 16467 16468 16469 THREADED_TEST(Uint16Array) { 16470 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array, 16471 v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF); 16472 } 16473 16474 16475 THREADED_TEST(Int16Array) { 16476 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array, 16477 v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000, 16478 0x7FFF); 16479 } 16480 16481 16482 THREADED_TEST(Uint32Array) { 16483 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array, 16484 v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX); 16485 } 16486 16487 16488 THREADED_TEST(Int32Array) { 16489 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array, 16490 v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN, 16491 INT_MAX); 16492 } 16493 16494 16495 THREADED_TEST(Float32Array) { 16496 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array, 16497 v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500); 16498 } 16499 16500 16501 THREADED_TEST(Float64Array) { 16502 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array, 16503 v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500); 16504 } 16505 16506 16507 THREADED_TEST(Uint8ClampedArray) { 16508 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, 16509 i::FixedUint8ClampedArray, v8::ArrayBuffer>( 16510 i::kExternalUint8ClampedArray, 0, 0xFF); 16511 } 16512 16513 16514 THREADED_TEST(DataView) { 16515 const int kSize = 50; 16516 16517 i::ScopedVector<uint8_t> backing_store(kSize+2); 16518 16519 LocalContext env; 16520 v8::Isolate* isolate = env->GetIsolate(); 16521 v8::HandleScope handle_scope(isolate); 16522 16523 Local<v8::ArrayBuffer> ab = 16524 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 16525 Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize); 16526 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 16527 CHECK_EQ(2u, dv->ByteOffset()); 16528 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 16529 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); 16530 } 16531 16532 16533 THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) { 16534 LocalContext env; 16535 v8::Isolate* isolate = env->GetIsolate(); 16536 v8::HandleScope handle_scope(isolate); 16537 16538 // Make sure the pointer looks like a heap object 16539 uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag); 16540 16541 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store 16542 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8); 16543 16544 // Should not crash 16545 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 16546 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 16547 CcTest::heap()->CollectAllGarbage(); 16548 CcTest::heap()->CollectAllGarbage(); 16549 16550 // Should not move the pointer 16551 CHECK_EQ(ab->GetContents().Data(), store_ptr); 16552 } 16553 16554 16555 THREADED_TEST(SkipArrayBufferDuringScavenge) { 16556 LocalContext env; 16557 v8::Isolate* isolate = env->GetIsolate(); 16558 v8::HandleScope handle_scope(isolate); 16559 16560 // Make sure the pointer looks like a heap object 16561 Local<v8::Object> tmp = v8::Object::New(isolate); 16562 uint8_t* store_ptr = 16563 reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp)); 16564 16565 // Make `store_ptr` point to from space 16566 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 16567 16568 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store 16569 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8); 16570 16571 // Should not crash, 16572 // i.e. backing store pointer should not be treated as a heap object pointer 16573 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 16574 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 16575 16576 // Use `ab` to silence compiler warning 16577 CHECK_EQ(ab->GetContents().Data(), store_ptr); 16578 } 16579 16580 16581 THREADED_TEST(SharedUint8Array) { 16582 i::FLAG_harmony_sharedarraybuffer = true; 16583 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array, 16584 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF); 16585 } 16586 16587 16588 THREADED_TEST(SharedInt8Array) { 16589 i::FLAG_harmony_sharedarraybuffer = true; 16590 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array, 16591 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80, 16592 0x7F); 16593 } 16594 16595 16596 THREADED_TEST(SharedUint16Array) { 16597 i::FLAG_harmony_sharedarraybuffer = true; 16598 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array, 16599 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0, 16600 0xFFFF); 16601 } 16602 16603 16604 THREADED_TEST(SharedInt16Array) { 16605 i::FLAG_harmony_sharedarraybuffer = true; 16606 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array, 16607 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000, 16608 0x7FFF); 16609 } 16610 16611 16612 THREADED_TEST(SharedUint32Array) { 16613 i::FLAG_harmony_sharedarraybuffer = true; 16614 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array, 16615 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0, 16616 UINT_MAX); 16617 } 16618 16619 16620 THREADED_TEST(SharedInt32Array) { 16621 i::FLAG_harmony_sharedarraybuffer = true; 16622 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array, 16623 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN, 16624 INT_MAX); 16625 } 16626 16627 16628 THREADED_TEST(SharedFloat32Array) { 16629 i::FLAG_harmony_sharedarraybuffer = true; 16630 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array, 16631 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500, 16632 500); 16633 } 16634 16635 16636 THREADED_TEST(SharedFloat64Array) { 16637 i::FLAG_harmony_sharedarraybuffer = true; 16638 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array, 16639 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500, 16640 500); 16641 } 16642 16643 16644 THREADED_TEST(SharedUint8ClampedArray) { 16645 i::FLAG_harmony_sharedarraybuffer = true; 16646 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, 16647 i::FixedUint8ClampedArray, v8::SharedArrayBuffer>( 16648 i::kExternalUint8ClampedArray, 0, 0xFF); 16649 } 16650 16651 16652 THREADED_TEST(SharedDataView) { 16653 i::FLAG_harmony_sharedarraybuffer = true; 16654 const int kSize = 50; 16655 16656 i::ScopedVector<uint8_t> backing_store(kSize + 2); 16657 16658 LocalContext env; 16659 v8::Isolate* isolate = env->GetIsolate(); 16660 v8::HandleScope handle_scope(isolate); 16661 16662 Local<v8::SharedArrayBuffer> ab = 16663 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 16664 Local<v8::DataView> dv = 16665 v8::DataView::New(ab, 2, kSize); 16666 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 16667 CHECK_EQ(2u, dv->ByteOffset()); 16668 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 16669 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); 16670 } 16671 16672 16673 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 16674 THREADED_TEST(Is##View) { \ 16675 LocalContext env; \ 16676 v8::Isolate* isolate = env->GetIsolate(); \ 16677 v8::HandleScope handle_scope(isolate); \ 16678 \ 16679 Local<Value> result = CompileRun( \ 16680 "var ab = new ArrayBuffer(128);" \ 16681 "new " #View "(ab)"); \ 16682 CHECK(result->IsArrayBufferView()); \ 16683 CHECK(result->Is##View()); \ 16684 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 16685 } 16686 16687 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 16688 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 16689 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 16690 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 16691 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 16692 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 16693 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 16694 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 16695 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 16696 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 16697 16698 #undef IS_ARRAY_BUFFER_VIEW_TEST 16699 16700 16701 16702 THREADED_TEST(ScriptContextDependence) { 16703 LocalContext c1; 16704 v8::HandleScope scope(c1->GetIsolate()); 16705 const char *source = "foo"; 16706 v8::Local<v8::Script> dep = v8_compile(source); 16707 v8::ScriptCompiler::Source script_source( 16708 v8::String::NewFromUtf8(c1->GetIsolate(), source, 16709 v8::NewStringType::kNormal) 16710 .ToLocalChecked()); 16711 v8::Local<v8::UnboundScript> indep = 16712 v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source) 16713 .ToLocalChecked(); 16714 c1->Global() 16715 ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo", 16716 v8::NewStringType::kNormal) 16717 .ToLocalChecked(), 16718 v8::Integer::New(c1->GetIsolate(), 100)) 16719 .FromJust(); 16720 CHECK_EQ( 16721 dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(), 16722 100); 16723 CHECK_EQ(indep->BindToCurrentContext() 16724 ->Run(c1.local()) 16725 .ToLocalChecked() 16726 ->Int32Value(c1.local()) 16727 .FromJust(), 16728 100); 16729 LocalContext c2; 16730 c2->Global() 16731 ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo", 16732 v8::NewStringType::kNormal) 16733 .ToLocalChecked(), 16734 v8::Integer::New(c2->GetIsolate(), 101)) 16735 .FromJust(); 16736 CHECK_EQ( 16737 dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(), 16738 100); 16739 CHECK_EQ(indep->BindToCurrentContext() 16740 ->Run(c2.local()) 16741 .ToLocalChecked() 16742 ->Int32Value(c2.local()) 16743 .FromJust(), 16744 101); 16745 } 16746 16747 16748 THREADED_TEST(StackTrace) { 16749 LocalContext context; 16750 v8::HandleScope scope(context->GetIsolate()); 16751 v8::TryCatch try_catch(context->GetIsolate()); 16752 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 16753 v8::Local<v8::String> src = v8_str(source); 16754 v8::Local<v8::String> origin = v8_str("stack-trace-test"); 16755 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin)); 16756 CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(), 16757 &script_source) 16758 .ToLocalChecked() 16759 ->BindToCurrentContext() 16760 ->Run(context.local()) 16761 .IsEmpty()); 16762 CHECK(try_catch.HasCaught()); 16763 v8::String::Utf8Value stack( 16764 try_catch.StackTrace(context.local()).ToLocalChecked()); 16765 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 16766 } 16767 16768 16769 // Checks that a StackFrame has certain expected values. 16770 void checkStackFrame(const char* expected_script_name, 16771 const char* expected_func_name, int expected_line_number, 16772 int expected_column, bool is_eval, bool is_constructor, 16773 v8::Local<v8::StackFrame> frame) { 16774 v8::HandleScope scope(CcTest::isolate()); 16775 v8::String::Utf8Value func_name(frame->GetFunctionName()); 16776 v8::String::Utf8Value script_name(frame->GetScriptName()); 16777 if (*script_name == NULL) { 16778 // The situation where there is no associated script, like for evals. 16779 CHECK(expected_script_name == NULL); 16780 } else { 16781 CHECK(strstr(*script_name, expected_script_name) != NULL); 16782 } 16783 CHECK(strstr(*func_name, expected_func_name) != NULL); 16784 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 16785 CHECK_EQ(expected_column, frame->GetColumn()); 16786 CHECK_EQ(is_eval, frame->IsEval()); 16787 CHECK_EQ(is_constructor, frame->IsConstructor()); 16788 } 16789 16790 16791 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 16792 v8::HandleScope scope(args.GetIsolate()); 16793 const char* origin = "capture-stack-trace-test"; 16794 const int kOverviewTest = 1; 16795 const int kDetailedTest = 2; 16796 const int kFunctionName = 3; 16797 const int kDisplayName = 4; 16798 const int kFunctionNameAndDisplayName = 5; 16799 const int kDisplayNameIsNotString = 6; 16800 const int kFunctionNameIsNotString = 7; 16801 16802 CHECK(args.Length() == 1); 16803 16804 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 16805 int testGroup = args[0]->Int32Value(context).FromJust(); 16806 if (testGroup == kOverviewTest) { 16807 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16808 args.GetIsolate(), 10, v8::StackTrace::kOverview); 16809 CHECK_EQ(4, stackTrace->GetFrameCount()); 16810 checkStackFrame(origin, "bar", 2, 10, false, false, 16811 stackTrace->GetFrame(0)); 16812 checkStackFrame(origin, "foo", 6, 3, false, false, 16813 stackTrace->GetFrame(1)); 16814 // This is the source string inside the eval which has the call to foo. 16815 checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2)); 16816 // The last frame is an anonymous function which has the initial eval call. 16817 checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3)); 16818 16819 CHECK(stackTrace->AsArray()->IsArray()); 16820 } else if (testGroup == kDetailedTest) { 16821 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16822 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 16823 CHECK_EQ(4, stackTrace->GetFrameCount()); 16824 checkStackFrame(origin, "bat", 4, 22, false, false, 16825 stackTrace->GetFrame(0)); 16826 checkStackFrame(origin, "baz", 8, 3, false, true, 16827 stackTrace->GetFrame(1)); 16828 bool is_eval = true; 16829 // This is the source string inside the eval which has the call to baz. 16830 checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2)); 16831 // The last frame is an anonymous function which has the initial eval call. 16832 checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3)); 16833 16834 CHECK(stackTrace->AsArray()->IsArray()); 16835 } else if (testGroup == kFunctionName) { 16836 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16837 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16838 CHECK_EQ(3, stackTrace->GetFrameCount()); 16839 checkStackFrame(origin, "function.name", 2, 24, false, false, 16840 stackTrace->GetFrame(0)); 16841 } else if (testGroup == kDisplayName) { 16842 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16843 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16844 CHECK_EQ(3, stackTrace->GetFrameCount()); 16845 checkStackFrame(origin, "function.displayName", 2, 24, false, false, 16846 stackTrace->GetFrame(0)); 16847 } else if (testGroup == kFunctionNameAndDisplayName) { 16848 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16849 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16850 CHECK_EQ(3, stackTrace->GetFrameCount()); 16851 checkStackFrame(origin, "function.displayName", 2, 24, false, false, 16852 stackTrace->GetFrame(0)); 16853 } else if (testGroup == kDisplayNameIsNotString) { 16854 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16855 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16856 CHECK_EQ(3, stackTrace->GetFrameCount()); 16857 checkStackFrame(origin, "function.name", 2, 24, false, false, 16858 stackTrace->GetFrame(0)); 16859 } else if (testGroup == kFunctionNameIsNotString) { 16860 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16861 args.GetIsolate(), 5, v8::StackTrace::kOverview); 16862 CHECK_EQ(3, stackTrace->GetFrameCount()); 16863 checkStackFrame(origin, "f", 2, 24, false, false, stackTrace->GetFrame(0)); 16864 } 16865 } 16866 16867 16868 // Tests the C++ StackTrace API. 16869 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 16870 // THREADED_TEST(CaptureStackTrace) { 16871 TEST(CaptureStackTrace) { 16872 v8::Isolate* isolate = CcTest::isolate(); 16873 v8::HandleScope scope(isolate); 16874 v8::Local<v8::String> origin = v8_str("capture-stack-trace-test"); 16875 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 16876 templ->Set(v8_str("AnalyzeStackInNativeCode"), 16877 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode)); 16878 LocalContext context(0, templ); 16879 16880 // Test getting OVERVIEW information. Should ignore information that is not 16881 // script name, function name, line number, and column offset. 16882 const char *overview_source = 16883 "function bar() {\n" 16884 " var y; AnalyzeStackInNativeCode(1);\n" 16885 "}\n" 16886 "function foo() {\n" 16887 "\n" 16888 " bar();\n" 16889 "}\n" 16890 "var x;eval('new foo();');"; 16891 v8::Local<v8::String> overview_src = v8_str(overview_source); 16892 v8::ScriptCompiler::Source script_source(overview_src, 16893 v8::ScriptOrigin(origin)); 16894 v8::Local<Value> overview_result( 16895 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source) 16896 .ToLocalChecked() 16897 ->BindToCurrentContext() 16898 ->Run(context.local()) 16899 .ToLocalChecked()); 16900 CHECK(!overview_result.IsEmpty()); 16901 CHECK(overview_result->IsObject()); 16902 16903 // Test getting DETAILED information. 16904 const char *detailed_source = 16905 "function bat() {AnalyzeStackInNativeCode(2);\n" 16906 "}\n" 16907 "\n" 16908 "function baz() {\n" 16909 " bat();\n" 16910 "}\n" 16911 "eval('new baz();');"; 16912 v8::Local<v8::String> detailed_src = v8_str(detailed_source); 16913 // Make the script using a non-zero line and column offset. 16914 v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3); 16915 v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5); 16916 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 16917 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin); 16918 v8::Local<v8::UnboundScript> detailed_script( 16919 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2) 16920 .ToLocalChecked()); 16921 v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext() 16922 ->Run(context.local()) 16923 .ToLocalChecked()); 16924 CHECK(!detailed_result.IsEmpty()); 16925 CHECK(detailed_result->IsObject()); 16926 16927 // Test using function.name and function.displayName in stack trace 16928 const char* function_name_source = 16929 "function bar(function_name, display_name, testGroup) {\n" 16930 " var f = function() { AnalyzeStackInNativeCode(testGroup); };\n" 16931 " if (function_name) {\n" 16932 " Object.defineProperty(f, 'name', { value: function_name });\n" 16933 " }\n" 16934 " if (display_name) {\n" 16935 " f.displayName = display_name;" 16936 " }\n" 16937 " f()\n" 16938 "}\n" 16939 "bar('function.name', undefined, 3);\n" 16940 "bar(undefined, 'function.displayName', 4);\n" 16941 "bar('function.name', 'function.displayName', 5);\n" 16942 "bar('function.name', 239, 6);\n" 16943 "bar(239, undefined, 7);\n"; 16944 v8::Local<v8::String> function_name_src = 16945 v8::String::NewFromUtf8(isolate, function_name_source, 16946 v8::NewStringType::kNormal) 16947 .ToLocalChecked(); 16948 v8::ScriptCompiler::Source script_source3(function_name_src, 16949 v8::ScriptOrigin(origin)); 16950 v8::Local<Value> function_name_result( 16951 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3) 16952 .ToLocalChecked() 16953 ->BindToCurrentContext() 16954 ->Run(context.local()) 16955 .ToLocalChecked()); 16956 CHECK(!function_name_result.IsEmpty()); 16957 } 16958 16959 16960 static void StackTraceForUncaughtExceptionListener( 16961 v8::Local<v8::Message> message, v8::Local<Value>) { 16962 report_count++; 16963 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 16964 CHECK_EQ(2, stack_trace->GetFrameCount()); 16965 checkStackFrame("origin", "foo", 2, 3, false, false, 16966 stack_trace->GetFrame(0)); 16967 checkStackFrame("origin", "bar", 5, 3, false, false, 16968 stack_trace->GetFrame(1)); 16969 } 16970 16971 16972 TEST(CaptureStackTraceForUncaughtException) { 16973 report_count = 0; 16974 LocalContext env; 16975 v8::Isolate* isolate = env->GetIsolate(); 16976 v8::HandleScope scope(isolate); 16977 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener); 16978 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 16979 16980 CompileRunWithOrigin( 16981 "function foo() {\n" 16982 " throw 1;\n" 16983 "};\n" 16984 "function bar() {\n" 16985 " foo();\n" 16986 "};", 16987 "origin"); 16988 v8::Local<v8::Object> global = env->Global(); 16989 Local<Value> trouble = 16990 global->Get(env.local(), v8_str("bar")).ToLocalChecked(); 16991 CHECK(trouble->IsFunction()); 16992 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty()); 16993 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 16994 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 16995 CHECK_EQ(1, report_count); 16996 } 16997 16998 16999 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) { 17000 report_count = 0; 17001 LocalContext env; 17002 v8::Isolate* isolate = env->GetIsolate(); 17003 v8::HandleScope scope(isolate); 17004 17005 // Create an Error object first. 17006 CompileRunWithOrigin( 17007 "function foo() {\n" 17008 "e=new Error('err');\n" 17009 "};\n" 17010 "function bar() {\n" 17011 " foo();\n" 17012 "};\n" 17013 "var e;", 17014 "origin"); 17015 v8::Local<v8::Object> global = env->Global(); 17016 Local<Value> trouble = 17017 global->Get(env.local(), v8_str("bar")).ToLocalChecked(); 17018 CHECK(trouble->IsFunction()); 17019 Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).ToLocalChecked(); 17020 17021 // Enable capturing detailed stack trace late, and throw the exception. 17022 // The detailed stack trace should be extracted from the simple stack. 17023 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener); 17024 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17025 CompileRunWithOrigin("throw e", "origin"); 17026 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17027 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 17028 CHECK_EQ(1, report_count); 17029 } 17030 17031 17032 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 17033 LocalContext env; 17034 v8::Isolate* isolate = env->GetIsolate(); 17035 v8::HandleScope scope(isolate); 17036 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024, 17037 v8::StackTrace::kDetailed); 17038 17039 CompileRun( 17040 "var setters = ['column', 'lineNumber', 'scriptName',\n" 17041 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 17042 " 'isConstructor'];\n" 17043 "for (var i = 0; i < setters.length; i++) {\n" 17044 " var prop = setters[i];\n" 17045 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 17046 "}\n"); 17047 CompileRun("throw 'exception';"); 17048 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17049 } 17050 17051 17052 static void StackTraceFunctionNameListener(v8::Local<v8::Message> message, 17053 v8::Local<Value>) { 17054 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17055 CHECK_EQ(5, stack_trace->GetFrameCount()); 17056 checkStackFrame("origin", "foo:0", 4, 7, false, false, 17057 stack_trace->GetFrame(0)); 17058 checkStackFrame("origin", "foo:1", 5, 27, false, false, 17059 stack_trace->GetFrame(1)); 17060 checkStackFrame("origin", "foo", 5, 27, false, false, 17061 stack_trace->GetFrame(2)); 17062 checkStackFrame("origin", "foo", 5, 27, false, false, 17063 stack_trace->GetFrame(3)); 17064 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4)); 17065 } 17066 17067 17068 TEST(GetStackTraceContainsFunctionsWithFunctionName) { 17069 LocalContext env; 17070 v8::Isolate* isolate = env->GetIsolate(); 17071 v8::HandleScope scope(isolate); 17072 17073 CompileRunWithOrigin( 17074 "function gen(name, counter) {\n" 17075 " var f = function foo() {\n" 17076 " if (counter === 0)\n" 17077 " throw 1;\n" 17078 " gen(name, counter - 1)();\n" 17079 " };\n" 17080 " if (counter == 3) {\n" 17081 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n" 17082 " } else {\n" 17083 " Object.defineProperty(f, 'name', {writable:true});\n" 17084 " if (counter == 2)\n" 17085 " f.name = 42;\n" 17086 " else\n" 17087 " f.name = name + ':' + counter;\n" 17088 " }\n" 17089 " return f;\n" 17090 "};", 17091 "origin"); 17092 17093 isolate->AddMessageListener(StackTraceFunctionNameListener); 17094 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17095 CompileRunWithOrigin("gen('foo', 3)();", "origin"); 17096 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17097 isolate->RemoveMessageListeners(StackTraceFunctionNameListener); 17098 } 17099 17100 17101 static void RethrowStackTraceHandler(v8::Local<v8::Message> message, 17102 v8::Local<v8::Value> data) { 17103 // Use the frame where JavaScript is called from. 17104 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17105 CHECK(!stack_trace.IsEmpty()); 17106 int frame_count = stack_trace->GetFrameCount(); 17107 CHECK_EQ(3, frame_count); 17108 int line_number[] = {1, 2, 5}; 17109 for (int i = 0; i < frame_count; i++) { 17110 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17111 } 17112 } 17113 17114 17115 // Test that we only return the stack trace at the site where the exception 17116 // is first thrown (not where it is rethrown). 17117 TEST(RethrowStackTrace) { 17118 LocalContext env; 17119 v8::Isolate* isolate = env->GetIsolate(); 17120 v8::HandleScope scope(isolate); 17121 // We make sure that 17122 // - the stack trace of the ReferenceError in g() is reported. 17123 // - the stack trace is not overwritten when e1 is rethrown by t(). 17124 // - the stack trace of e2 does not overwrite that of e1. 17125 const char* source = 17126 "function g() { error; } \n" 17127 "function f() { g(); } \n" 17128 "function t(e) { throw e; } \n" 17129 "try { \n" 17130 " f(); \n" 17131 "} catch (e1) { \n" 17132 " try { \n" 17133 " error; \n" 17134 " } catch (e2) { \n" 17135 " t(e1); \n" 17136 " } \n" 17137 "} \n"; 17138 isolate->AddMessageListener(RethrowStackTraceHandler); 17139 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17140 CompileRun(source); 17141 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17142 isolate->RemoveMessageListeners(RethrowStackTraceHandler); 17143 } 17144 17145 17146 static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message, 17147 v8::Local<v8::Value> data) { 17148 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17149 CHECK(!stack_trace.IsEmpty()); 17150 int frame_count = stack_trace->GetFrameCount(); 17151 CHECK_EQ(2, frame_count); 17152 int line_number[] = {3, 7}; 17153 for (int i = 0; i < frame_count; i++) { 17154 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17155 } 17156 } 17157 17158 17159 // Test that we do not recognize identity for primitive exceptions. 17160 TEST(RethrowPrimitiveStackTrace) { 17161 LocalContext env; 17162 v8::Isolate* isolate = env->GetIsolate(); 17163 v8::HandleScope scope(isolate); 17164 // We do not capture stack trace for non Error objects on creation time. 17165 // Instead, we capture the stack trace on last throw. 17166 const char* source = 17167 "function g() { throw 404; } \n" 17168 "function f() { g(); } \n" 17169 "function t(e) { throw e; } \n" 17170 "try { \n" 17171 " f(); \n" 17172 "} catch (e1) { \n" 17173 " t(e1) \n" 17174 "} \n"; 17175 isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler); 17176 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17177 CompileRun(source); 17178 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17179 isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 17180 } 17181 17182 17183 static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message, 17184 v8::Local<v8::Value> data) { 17185 // Use the frame where JavaScript is called from. 17186 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17187 CHECK(!stack_trace.IsEmpty()); 17188 CHECK_EQ(1, stack_trace->GetFrameCount()); 17189 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 17190 } 17191 17192 17193 // Test that the stack trace is captured when the error object is created and 17194 // not where it is thrown. 17195 TEST(RethrowExistingStackTrace) { 17196 LocalContext env; 17197 v8::Isolate* isolate = env->GetIsolate(); 17198 v8::HandleScope scope(isolate); 17199 const char* source = 17200 "var e = new Error(); \n" 17201 "throw e; \n"; 17202 isolate->AddMessageListener(RethrowExistingStackTraceHandler); 17203 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17204 CompileRun(source); 17205 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17206 isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler); 17207 } 17208 17209 17210 static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message, 17211 v8::Local<v8::Value> data) { 17212 // Use the frame where JavaScript is called from. 17213 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17214 CHECK(!stack_trace.IsEmpty()); 17215 CHECK_EQ(1, stack_trace->GetFrameCount()); 17216 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 17217 } 17218 17219 17220 // Test that the stack trace is captured where the bogus Error object is thrown. 17221 TEST(RethrowBogusErrorStackTrace) { 17222 LocalContext env; 17223 v8::Isolate* isolate = env->GetIsolate(); 17224 v8::HandleScope scope(isolate); 17225 const char* source = 17226 "var e = {__proto__: new Error()} \n" 17227 "throw e; \n"; 17228 isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler); 17229 isolate->SetCaptureStackTraceForUncaughtExceptions(true); 17230 CompileRun(source); 17231 isolate->SetCaptureStackTraceForUncaughtExceptions(false); 17232 isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 17233 } 17234 17235 17236 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler; 17237 int promise_reject_counter = 0; 17238 int promise_revoke_counter = 0; 17239 int promise_reject_msg_line_number = -1; 17240 int promise_reject_msg_column_number = -1; 17241 int promise_reject_line_number = -1; 17242 int promise_reject_column_number = -1; 17243 int promise_reject_frame_count = -1; 17244 17245 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) { 17246 v8::Local<v8::Object> global = CcTest::global(); 17247 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 17248 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) { 17249 promise_reject_counter++; 17250 global->Set(context, v8_str("rejected"), reject_message.GetPromise()) 17251 .FromJust(); 17252 global->Set(context, v8_str("value"), reject_message.GetValue()).FromJust(); 17253 v8::Local<v8::Message> message = v8::Exception::CreateMessage( 17254 CcTest::isolate(), reject_message.GetValue()); 17255 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace(); 17256 17257 promise_reject_msg_line_number = message->GetLineNumber(context).FromJust(); 17258 promise_reject_msg_column_number = 17259 message->GetStartColumn(context).FromJust() + 1; 17260 17261 if (!stack_trace.IsEmpty()) { 17262 promise_reject_frame_count = stack_trace->GetFrameCount(); 17263 if (promise_reject_frame_count > 0) { 17264 CHECK(stack_trace->GetFrame(0) 17265 ->GetScriptName() 17266 ->Equals(context, v8_str("pro")) 17267 .FromJust()); 17268 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber(); 17269 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn(); 17270 } else { 17271 promise_reject_line_number = -1; 17272 promise_reject_column_number = -1; 17273 } 17274 } 17275 } else { 17276 promise_revoke_counter++; 17277 global->Set(context, v8_str("revoked"), reject_message.GetPromise()) 17278 .FromJust(); 17279 CHECK(reject_message.GetValue().IsEmpty()); 17280 } 17281 } 17282 17283 17284 v8::Local<v8::Promise> GetPromise(const char* name) { 17285 return v8::Local<v8::Promise>::Cast( 17286 CcTest::global() 17287 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name)) 17288 .ToLocalChecked()); 17289 } 17290 17291 17292 v8::Local<v8::Value> RejectValue() { 17293 return CcTest::global() 17294 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value")) 17295 .ToLocalChecked(); 17296 } 17297 17298 17299 void ResetPromiseStates() { 17300 promise_reject_counter = 0; 17301 promise_revoke_counter = 0; 17302 promise_reject_msg_line_number = -1; 17303 promise_reject_msg_column_number = -1; 17304 promise_reject_line_number = -1; 17305 promise_reject_column_number = -1; 17306 promise_reject_frame_count = -1; 17307 17308 v8::Local<v8::Object> global = CcTest::global(); 17309 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 17310 global->Set(context, v8_str("rejected"), v8_str("")).FromJust(); 17311 global->Set(context, v8_str("value"), v8_str("")).FromJust(); 17312 global->Set(context, v8_str("revoked"), v8_str("")).FromJust(); 17313 } 17314 17315 17316 TEST(PromiseRejectCallback) { 17317 LocalContext env; 17318 v8::Isolate* isolate = env->GetIsolate(); 17319 v8::HandleScope scope(isolate); 17320 17321 isolate->SetPromiseRejectCallback(PromiseRejectCallback); 17322 17323 ResetPromiseStates(); 17324 17325 // Create promise p0. 17326 CompileRun( 17327 "var reject; \n" 17328 "var p0 = new Promise( \n" 17329 " function(res, rej) { \n" 17330 " reject = rej; \n" 17331 " } \n" 17332 "); \n"); 17333 CHECK(!GetPromise("p0")->HasHandler()); 17334 CHECK_EQ(0, promise_reject_counter); 17335 CHECK_EQ(0, promise_revoke_counter); 17336 17337 // Add resolve handler (and default reject handler) to p0. 17338 CompileRun("var p1 = p0.then(function(){});"); 17339 CHECK(GetPromise("p0")->HasHandler()); 17340 CHECK(!GetPromise("p1")->HasHandler()); 17341 CHECK_EQ(0, promise_reject_counter); 17342 CHECK_EQ(0, promise_revoke_counter); 17343 17344 // Reject p0. 17345 CompileRun("reject('ppp');"); 17346 CHECK(GetPromise("p0")->HasHandler()); 17347 CHECK(!GetPromise("p1")->HasHandler()); 17348 CHECK_EQ(1, promise_reject_counter); 17349 CHECK_EQ(0, promise_revoke_counter); 17350 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event); 17351 CHECK( 17352 GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust()); 17353 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust()); 17354 17355 // Reject p0 again. Callback is not triggered again. 17356 CompileRun("reject();"); 17357 CHECK(GetPromise("p0")->HasHandler()); 17358 CHECK(!GetPromise("p1")->HasHandler()); 17359 CHECK_EQ(1, promise_reject_counter); 17360 CHECK_EQ(0, promise_revoke_counter); 17361 17362 // Add resolve handler to p1. 17363 CompileRun("var p2 = p1.then(function(){});"); 17364 CHECK(GetPromise("p0")->HasHandler()); 17365 CHECK(GetPromise("p1")->HasHandler()); 17366 CHECK(!GetPromise("p2")->HasHandler()); 17367 CHECK_EQ(2, promise_reject_counter); 17368 CHECK_EQ(1, promise_revoke_counter); 17369 CHECK( 17370 GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust()); 17371 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust()); 17372 CHECK( 17373 GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust()); 17374 17375 ResetPromiseStates(); 17376 17377 // Create promise q0. 17378 CompileRun( 17379 "var q0 = new Promise( \n" 17380 " function(res, rej) { \n" 17381 " reject = rej; \n" 17382 " } \n" 17383 "); \n"); 17384 CHECK(!GetPromise("q0")->HasHandler()); 17385 CHECK_EQ(0, promise_reject_counter); 17386 CHECK_EQ(0, promise_revoke_counter); 17387 17388 // Add reject handler to q0. 17389 CompileRun("var q1 = q0.catch(function() {});"); 17390 CHECK(GetPromise("q0")->HasHandler()); 17391 CHECK(!GetPromise("q1")->HasHandler()); 17392 CHECK_EQ(0, promise_reject_counter); 17393 CHECK_EQ(0, promise_revoke_counter); 17394 17395 // Reject q0. 17396 CompileRun("reject('qq')"); 17397 CHECK(GetPromise("q0")->HasHandler()); 17398 CHECK(!GetPromise("q1")->HasHandler()); 17399 CHECK_EQ(0, promise_reject_counter); 17400 CHECK_EQ(0, promise_revoke_counter); 17401 17402 // Add a new reject handler, which rejects by returning Promise.reject(). 17403 // The returned promise q_ triggers a reject callback at first, only to 17404 // revoke it when returning it causes q2 to be rejected. 17405 CompileRun( 17406 "var q_;" 17407 "var q2 = q0.catch( \n" 17408 " function() { \n" 17409 " q_ = Promise.reject('qqq'); \n" 17410 " return q_; \n" 17411 " } \n" 17412 "); \n"); 17413 CHECK(GetPromise("q0")->HasHandler()); 17414 CHECK(!GetPromise("q1")->HasHandler()); 17415 CHECK(!GetPromise("q2")->HasHandler()); 17416 CHECK(GetPromise("q_")->HasHandler()); 17417 CHECK_EQ(2, promise_reject_counter); 17418 CHECK_EQ(1, promise_revoke_counter); 17419 CHECK( 17420 GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust()); 17421 CHECK( 17422 GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust()); 17423 CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust()); 17424 17425 // Add a reject handler to the resolved q1, which rejects by throwing. 17426 CompileRun( 17427 "var q3 = q1.then( \n" 17428 " function() { \n" 17429 " throw 'qqqq'; \n" 17430 " } \n" 17431 "); \n"); 17432 CHECK(GetPromise("q0")->HasHandler()); 17433 CHECK(GetPromise("q1")->HasHandler()); 17434 CHECK(!GetPromise("q2")->HasHandler()); 17435 CHECK(!GetPromise("q3")->HasHandler()); 17436 CHECK_EQ(3, promise_reject_counter); 17437 CHECK_EQ(1, promise_revoke_counter); 17438 CHECK( 17439 GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust()); 17440 CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust()); 17441 17442 ResetPromiseStates(); 17443 17444 // Create promise r0, which has three handlers, two of which handle rejects. 17445 CompileRun( 17446 "var r0 = new Promise( \n" 17447 " function(res, rej) { \n" 17448 " reject = rej; \n" 17449 " } \n" 17450 "); \n" 17451 "var r1 = r0.catch(function() {}); \n" 17452 "var r2 = r0.then(function() {}); \n" 17453 "var r3 = r0.then(function() {}, \n" 17454 " function() {}); \n"); 17455 CHECK(GetPromise("r0")->HasHandler()); 17456 CHECK(!GetPromise("r1")->HasHandler()); 17457 CHECK(!GetPromise("r2")->HasHandler()); 17458 CHECK(!GetPromise("r3")->HasHandler()); 17459 CHECK_EQ(0, promise_reject_counter); 17460 CHECK_EQ(0, promise_revoke_counter); 17461 17462 // Reject r0. 17463 CompileRun("reject('rrr')"); 17464 CHECK(GetPromise("r0")->HasHandler()); 17465 CHECK(!GetPromise("r1")->HasHandler()); 17466 CHECK(!GetPromise("r2")->HasHandler()); 17467 CHECK(!GetPromise("r3")->HasHandler()); 17468 CHECK_EQ(1, promise_reject_counter); 17469 CHECK_EQ(0, promise_revoke_counter); 17470 CHECK( 17471 GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust()); 17472 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust()); 17473 17474 // Add reject handler to r2. 17475 CompileRun("var r4 = r2.catch(function() {});"); 17476 CHECK(GetPromise("r0")->HasHandler()); 17477 CHECK(!GetPromise("r1")->HasHandler()); 17478 CHECK(GetPromise("r2")->HasHandler()); 17479 CHECK(!GetPromise("r3")->HasHandler()); 17480 CHECK(!GetPromise("r4")->HasHandler()); 17481 CHECK_EQ(1, promise_reject_counter); 17482 CHECK_EQ(1, promise_revoke_counter); 17483 CHECK( 17484 GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust()); 17485 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust()); 17486 17487 // Add reject handlers to r4. 17488 CompileRun("var r5 = r4.then(function() {}, function() {});"); 17489 CHECK(GetPromise("r0")->HasHandler()); 17490 CHECK(!GetPromise("r1")->HasHandler()); 17491 CHECK(GetPromise("r2")->HasHandler()); 17492 CHECK(!GetPromise("r3")->HasHandler()); 17493 CHECK(GetPromise("r4")->HasHandler()); 17494 CHECK(!GetPromise("r5")->HasHandler()); 17495 CHECK_EQ(1, promise_reject_counter); 17496 CHECK_EQ(1, promise_revoke_counter); 17497 17498 ResetPromiseStates(); 17499 17500 // Create promise s0, which has three handlers, none of which handle rejects. 17501 CompileRun( 17502 "var s0 = new Promise( \n" 17503 " function(res, rej) { \n" 17504 " reject = rej; \n" 17505 " } \n" 17506 "); \n" 17507 "var s1 = s0.then(function() {}); \n" 17508 "var s2 = s0.then(function() {}); \n" 17509 "var s3 = s0.then(function() {}); \n"); 17510 CHECK(GetPromise("s0")->HasHandler()); 17511 CHECK(!GetPromise("s1")->HasHandler()); 17512 CHECK(!GetPromise("s2")->HasHandler()); 17513 CHECK(!GetPromise("s3")->HasHandler()); 17514 CHECK_EQ(0, promise_reject_counter); 17515 CHECK_EQ(0, promise_revoke_counter); 17516 17517 // Reject s0. 17518 CompileRun("reject('sss')"); 17519 CHECK(GetPromise("s0")->HasHandler()); 17520 CHECK(!GetPromise("s1")->HasHandler()); 17521 CHECK(!GetPromise("s2")->HasHandler()); 17522 CHECK(!GetPromise("s3")->HasHandler()); 17523 CHECK_EQ(3, promise_reject_counter); 17524 CHECK_EQ(0, promise_revoke_counter); 17525 CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust()); 17526 17527 // Test stack frames. 17528 env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true); 17529 17530 ResetPromiseStates(); 17531 17532 // Create promise t0, which is rejected in the constructor with an error. 17533 CompileRunWithOrigin( 17534 "var t0 = new Promise( \n" 17535 " function(res, rej) { \n" 17536 " reference_error; \n" 17537 " } \n" 17538 "); \n", 17539 "pro", 0, 0); 17540 CHECK(!GetPromise("t0")->HasHandler()); 17541 CHECK_EQ(1, promise_reject_counter); 17542 CHECK_EQ(0, promise_revoke_counter); 17543 CHECK_EQ(2, promise_reject_frame_count); 17544 CHECK_EQ(3, promise_reject_line_number); 17545 CHECK_EQ(5, promise_reject_column_number); 17546 CHECK_EQ(3, promise_reject_msg_line_number); 17547 CHECK_EQ(5, promise_reject_msg_column_number); 17548 17549 ResetPromiseStates(); 17550 17551 // Create promise u0 and chain u1 to it, which is rejected via throw. 17552 CompileRunWithOrigin( 17553 "var u0 = Promise.resolve(); \n" 17554 "var u1 = u0.then( \n" 17555 " function() { \n" 17556 " (function() { \n" 17557 " throw new Error(); \n" 17558 " })(); \n" 17559 " } \n" 17560 " ); \n", 17561 "pro", 0, 0); 17562 CHECK(GetPromise("u0")->HasHandler()); 17563 CHECK(!GetPromise("u1")->HasHandler()); 17564 CHECK_EQ(1, promise_reject_counter); 17565 CHECK_EQ(0, promise_revoke_counter); 17566 CHECK_EQ(2, promise_reject_frame_count); 17567 CHECK_EQ(5, promise_reject_line_number); 17568 CHECK_EQ(23, promise_reject_column_number); 17569 CHECK_EQ(5, promise_reject_msg_line_number); 17570 CHECK_EQ(23, promise_reject_msg_column_number); 17571 17572 // Throw in u3, which handles u1's rejection. 17573 CompileRunWithOrigin( 17574 "function f() { \n" 17575 " return (function() { \n" 17576 " return new Error(); \n" 17577 " })(); \n" 17578 "} \n" 17579 "var u2 = Promise.reject(f()); \n" 17580 "var u3 = u1.catch( \n" 17581 " function() { \n" 17582 " return u2; \n" 17583 " } \n" 17584 " ); \n", 17585 "pro", 0, 0); 17586 CHECK(GetPromise("u0")->HasHandler()); 17587 CHECK(GetPromise("u1")->HasHandler()); 17588 CHECK(GetPromise("u2")->HasHandler()); 17589 CHECK(!GetPromise("u3")->HasHandler()); 17590 CHECK_EQ(3, promise_reject_counter); 17591 CHECK_EQ(2, promise_revoke_counter); 17592 CHECK_EQ(3, promise_reject_frame_count); 17593 CHECK_EQ(3, promise_reject_line_number); 17594 CHECK_EQ(12, promise_reject_column_number); 17595 CHECK_EQ(3, promise_reject_msg_line_number); 17596 CHECK_EQ(12, promise_reject_msg_column_number); 17597 17598 ResetPromiseStates(); 17599 17600 // Create promise rejected promise v0, which is incorrectly handled by v1 17601 // via chaining cycle. 17602 CompileRunWithOrigin( 17603 "var v0 = Promise.reject(); \n" 17604 "var v1 = v0.catch( \n" 17605 " function() { \n" 17606 " return v1; \n" 17607 " } \n" 17608 " ); \n", 17609 "pro", 0, 0); 17610 CHECK(GetPromise("v0")->HasHandler()); 17611 CHECK(!GetPromise("v1")->HasHandler()); 17612 CHECK_EQ(2, promise_reject_counter); 17613 CHECK_EQ(1, promise_revoke_counter); 17614 CHECK_EQ(0, promise_reject_frame_count); 17615 CHECK_EQ(-1, promise_reject_line_number); 17616 CHECK_EQ(-1, promise_reject_column_number); 17617 17618 ResetPromiseStates(); 17619 17620 // Create promise t1, which rejects by throwing syntax error from eval. 17621 CompileRunWithOrigin( 17622 "var t1 = new Promise( \n" 17623 " function(res, rej) { \n" 17624 " var content = '\\n\\\n" 17625 " }'; \n" 17626 " eval(content); \n" 17627 " } \n" 17628 "); \n", 17629 "pro", 0, 0); 17630 CHECK(!GetPromise("t1")->HasHandler()); 17631 CHECK_EQ(1, promise_reject_counter); 17632 CHECK_EQ(0, promise_revoke_counter); 17633 CHECK_EQ(2, promise_reject_frame_count); 17634 CHECK_EQ(5, promise_reject_line_number); 17635 CHECK_EQ(10, promise_reject_column_number); 17636 CHECK_EQ(2, promise_reject_msg_line_number); 17637 CHECK_EQ(7, promise_reject_msg_column_number); 17638 } 17639 17640 17641 void AnalyzeStackOfEvalWithSourceURL( 17642 const v8::FunctionCallbackInfo<v8::Value>& args) { 17643 v8::HandleScope scope(args.GetIsolate()); 17644 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17645 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17646 CHECK_EQ(5, stackTrace->GetFrameCount()); 17647 v8::Local<v8::String> url = v8_str("eval_url"); 17648 for (int i = 0; i < 3; i++) { 17649 v8::Local<v8::String> name = 17650 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17651 CHECK(!name.IsEmpty()); 17652 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17653 } 17654 } 17655 17656 17657 TEST(SourceURLInStackTrace) { 17658 v8::Isolate* isolate = CcTest::isolate(); 17659 v8::HandleScope scope(isolate); 17660 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17661 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 17662 v8::FunctionTemplate::New(isolate, 17663 AnalyzeStackOfEvalWithSourceURL)); 17664 LocalContext context(0, templ); 17665 17666 const char *source = 17667 "function outer() {\n" 17668 "function bar() {\n" 17669 " AnalyzeStackOfEvalWithSourceURL();\n" 17670 "}\n" 17671 "function foo() {\n" 17672 "\n" 17673 " bar();\n" 17674 "}\n" 17675 "foo();\n" 17676 "}\n" 17677 "eval('(' + outer +')()%s');"; 17678 17679 i::ScopedVector<char> code(1024); 17680 i::SNPrintF(code, source, "//# sourceURL=eval_url"); 17681 CHECK(CompileRun(code.start())->IsUndefined()); 17682 i::SNPrintF(code, source, "//@ sourceURL=eval_url"); 17683 CHECK(CompileRun(code.start())->IsUndefined()); 17684 } 17685 17686 17687 static int scriptIdInStack[2]; 17688 17689 void AnalyzeScriptIdInStack( 17690 const v8::FunctionCallbackInfo<v8::Value>& args) { 17691 v8::HandleScope scope(args.GetIsolate()); 17692 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17693 args.GetIsolate(), 10, v8::StackTrace::kScriptId); 17694 CHECK_EQ(2, stackTrace->GetFrameCount()); 17695 for (int i = 0; i < 2; i++) { 17696 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId(); 17697 } 17698 } 17699 17700 17701 TEST(ScriptIdInStackTrace) { 17702 v8::Isolate* isolate = CcTest::isolate(); 17703 v8::HandleScope scope(isolate); 17704 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17705 templ->Set(v8_str("AnalyzeScriptIdInStack"), 17706 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack)); 17707 LocalContext context(0, templ); 17708 17709 v8::Local<v8::String> scriptSource = v8_str( 17710 "function foo() {\n" 17711 " AnalyzeScriptIdInStack();" 17712 "}\n" 17713 "foo();\n"); 17714 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test"); 17715 script->Run(context.local()).ToLocalChecked(); 17716 for (int i = 0; i < 2; i++) { 17717 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); 17718 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId()); 17719 } 17720 } 17721 17722 17723 void AnalyzeStackOfInlineScriptWithSourceURL( 17724 const v8::FunctionCallbackInfo<v8::Value>& args) { 17725 v8::HandleScope scope(args.GetIsolate()); 17726 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17727 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17728 CHECK_EQ(4, stackTrace->GetFrameCount()); 17729 v8::Local<v8::String> url = v8_str("source_url"); 17730 for (int i = 0; i < 3; i++) { 17731 v8::Local<v8::String> name = 17732 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17733 CHECK(!name.IsEmpty()); 17734 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17735 } 17736 } 17737 17738 17739 TEST(InlineScriptWithSourceURLInStackTrace) { 17740 v8::Isolate* isolate = CcTest::isolate(); 17741 v8::HandleScope scope(isolate); 17742 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17743 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 17744 v8::FunctionTemplate::New( 17745 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL)); 17746 LocalContext context(0, templ); 17747 17748 const char *source = 17749 "function outer() {\n" 17750 "function bar() {\n" 17751 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 17752 "}\n" 17753 "function foo() {\n" 17754 "\n" 17755 " bar();\n" 17756 "}\n" 17757 "foo();\n" 17758 "}\n" 17759 "outer()\n%s"; 17760 17761 i::ScopedVector<char> code(1024); 17762 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17763 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17764 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17765 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17766 } 17767 17768 17769 void AnalyzeStackOfDynamicScriptWithSourceURL( 17770 const v8::FunctionCallbackInfo<v8::Value>& args) { 17771 v8::HandleScope scope(args.GetIsolate()); 17772 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17773 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17774 CHECK_EQ(4, stackTrace->GetFrameCount()); 17775 v8::Local<v8::String> url = v8_str("source_url"); 17776 for (int i = 0; i < 3; i++) { 17777 v8::Local<v8::String> name = 17778 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17779 CHECK(!name.IsEmpty()); 17780 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust()); 17781 } 17782 } 17783 17784 17785 TEST(DynamicWithSourceURLInStackTrace) { 17786 v8::Isolate* isolate = CcTest::isolate(); 17787 v8::HandleScope scope(isolate); 17788 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17789 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 17790 v8::FunctionTemplate::New( 17791 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL)); 17792 LocalContext context(0, templ); 17793 17794 const char *source = 17795 "function outer() {\n" 17796 "function bar() {\n" 17797 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 17798 "}\n" 17799 "function foo() {\n" 17800 "\n" 17801 " bar();\n" 17802 "}\n" 17803 "foo();\n" 17804 "}\n" 17805 "outer()\n%s"; 17806 17807 i::ScopedVector<char> code(1024); 17808 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17809 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17810 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17811 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17812 } 17813 17814 17815 TEST(DynamicWithSourceURLInStackTraceString) { 17816 LocalContext context; 17817 v8::HandleScope scope(context->GetIsolate()); 17818 17819 const char *source = 17820 "function outer() {\n" 17821 " function foo() {\n" 17822 " FAIL.FAIL;\n" 17823 " }\n" 17824 " foo();\n" 17825 "}\n" 17826 "outer()\n%s"; 17827 17828 i::ScopedVector<char> code(1024); 17829 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17830 v8::TryCatch try_catch(context->GetIsolate()); 17831 CompileRunWithOrigin(code.start(), "", 0, 0); 17832 CHECK(try_catch.HasCaught()); 17833 v8::String::Utf8Value stack( 17834 try_catch.StackTrace(context.local()).ToLocalChecked()); 17835 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL); 17836 } 17837 17838 17839 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17840 LocalContext context; 17841 v8::HandleScope scope(context->GetIsolate()); 17842 17843 const char *source = 17844 "function outer() {\n" 17845 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n" 17846 " //# sourceURL=source_url\";\n" 17847 " eval(scriptContents);\n" 17848 " foo(); }\n" 17849 "outer();\n" 17850 "//# sourceURL=outer_url"; 17851 17852 v8::TryCatch try_catch(context->GetIsolate()); 17853 CompileRun(source); 17854 CHECK(try_catch.HasCaught()); 17855 17856 Local<v8::Message> message = try_catch.Message(); 17857 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName(); 17858 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url")); 17859 } 17860 17861 17862 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17863 LocalContext context; 17864 v8::HandleScope scope(context->GetIsolate()); 17865 17866 const char *source = 17867 "function outer() {\n" 17868 " var scriptContents = \"function boo(){ boo(); }\\\n" 17869 " //# sourceURL=source_url\";\n" 17870 " eval(scriptContents);\n" 17871 " boo(); }\n" 17872 "outer();\n" 17873 "//# sourceURL=outer_url"; 17874 17875 v8::TryCatch try_catch(context->GetIsolate()); 17876 CompileRun(source); 17877 CHECK(try_catch.HasCaught()); 17878 17879 Local<v8::Message> message = try_catch.Message(); 17880 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName(); 17881 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url")); 17882 } 17883 17884 17885 static void CreateGarbageInOldSpace() { 17886 i::Factory* factory = CcTest::i_isolate()->factory(); 17887 v8::HandleScope scope(CcTest::isolate()); 17888 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate()); 17889 for (int i = 0; i < 1000; i++) { 17890 factory->NewFixedArray(1000, i::TENURED); 17891 } 17892 } 17893 17894 17895 // Test that idle notification can be handled and eventually collects garbage. 17896 TEST(TestIdleNotification) { 17897 if (!i::FLAG_incremental_marking) return; 17898 const intptr_t MB = 1024 * 1024; 17899 const double IdlePauseInSeconds = 1.0; 17900 LocalContext env; 17901 v8::HandleScope scope(env->GetIsolate()); 17902 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17903 CreateGarbageInOldSpace(); 17904 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17905 CHECK_GT(size_with_garbage, initial_size + MB); 17906 bool finished = false; 17907 for (int i = 0; i < 200 && !finished; i++) { 17908 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) { 17909 CcTest::heap()->StartIdleIncrementalMarking(); 17910 } 17911 finished = env->GetIsolate()->IdleNotificationDeadline( 17912 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / 17913 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + 17914 IdlePauseInSeconds); 17915 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) { 17916 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted(); 17917 } 17918 } 17919 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17920 CHECK(finished); 17921 CHECK_LT(final_size, initial_size + 1); 17922 } 17923 17924 17925 TEST(Regress2333) { 17926 LocalContext env; 17927 for (int i = 0; i < 3; i++) { 17928 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 17929 } 17930 } 17931 17932 static uint32_t* stack_limit; 17933 17934 static void GetStackLimitCallback( 17935 const v8::FunctionCallbackInfo<v8::Value>& args) { 17936 stack_limit = reinterpret_cast<uint32_t*>( 17937 CcTest::i_isolate()->stack_guard()->real_climit()); 17938 } 17939 17940 17941 // Uses the address of a local variable to determine the stack top now. 17942 // Given a size, returns an address that is that far from the current 17943 // top of stack. 17944 static uint32_t* ComputeStackLimit(uint32_t size) { 17945 uint32_t* answer = &size - (size / sizeof(size)); 17946 // If the size is very large and the stack is very near the bottom of 17947 // memory then the calculation above may wrap around and give an address 17948 // that is above the (downwards-growing) stack. In that case we return 17949 // a very low address. 17950 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 17951 return answer; 17952 } 17953 17954 17955 // We need at least 165kB for an x64 debug build with clang and ASAN. 17956 static const int stack_breathing_room = 256 * i::KB; 17957 17958 17959 TEST(SetStackLimit) { 17960 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 17961 17962 // Set stack limit. 17963 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17964 17965 // Execute a script. 17966 LocalContext env; 17967 v8::HandleScope scope(env->GetIsolate()); 17968 Local<v8::FunctionTemplate> fun_templ = 17969 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback); 17970 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 17971 CHECK(env->Global() 17972 ->Set(env.local(), v8_str("get_stack_limit"), fun) 17973 .FromJust()); 17974 CompileRun("get_stack_limit();"); 17975 17976 CHECK(stack_limit == set_limit); 17977 } 17978 17979 17980 TEST(SetStackLimitInThread) { 17981 uint32_t* set_limit; 17982 { 17983 v8::Locker locker(CcTest::isolate()); 17984 set_limit = ComputeStackLimit(stack_breathing_room); 17985 17986 // Set stack limit. 17987 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17988 17989 // Execute a script. 17990 v8::HandleScope scope(CcTest::isolate()); 17991 LocalContext env; 17992 Local<v8::FunctionTemplate> fun_templ = 17993 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback); 17994 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 17995 CHECK(env->Global() 17996 ->Set(env.local(), v8_str("get_stack_limit"), fun) 17997 .FromJust()); 17998 CompileRun("get_stack_limit();"); 17999 18000 CHECK(stack_limit == set_limit); 18001 } 18002 { 18003 v8::Locker locker(CcTest::isolate()); 18004 CHECK(stack_limit == set_limit); 18005 } 18006 } 18007 18008 18009 THREADED_TEST(GetHeapStatistics) { 18010 LocalContext c1; 18011 v8::HandleScope scope(c1->GetIsolate()); 18012 v8::HeapStatistics heap_statistics; 18013 CHECK_EQ(0u, heap_statistics.total_heap_size()); 18014 CHECK_EQ(0u, heap_statistics.used_heap_size()); 18015 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 18016 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 18017 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 18018 } 18019 18020 18021 class VisitorImpl : public v8::ExternalResourceVisitor { 18022 public: 18023 explicit VisitorImpl(TestResource** resource) { 18024 for (int i = 0; i < 4; i++) { 18025 resource_[i] = resource[i]; 18026 found_resource_[i] = false; 18027 } 18028 } 18029 virtual ~VisitorImpl() {} 18030 virtual void VisitExternalString(v8::Local<v8::String> string) { 18031 if (!string->IsExternal()) { 18032 CHECK(string->IsExternalOneByte()); 18033 return; 18034 } 18035 v8::String::ExternalStringResource* resource = 18036 string->GetExternalStringResource(); 18037 CHECK(resource); 18038 for (int i = 0; i < 4; i++) { 18039 if (resource_[i] == resource) { 18040 CHECK(!found_resource_[i]); 18041 found_resource_[i] = true; 18042 } 18043 } 18044 } 18045 void CheckVisitedResources() { 18046 for (int i = 0; i < 4; i++) { 18047 CHECK(found_resource_[i]); 18048 } 18049 } 18050 18051 private: 18052 v8::String::ExternalStringResource* resource_[4]; 18053 bool found_resource_[4]; 18054 }; 18055 18056 18057 TEST(ExternalizeOldSpaceTwoByteCons) { 18058 v8::Isolate* isolate = CcTest::isolate(); 18059 LocalContext env; 18060 v8::HandleScope scope(isolate); 18061 v8::Local<v8::String> cons = 18062 CompileRun("'Romeo Montague ' + 'Juliet Capulet'") 18063 ->ToString(env.local()) 18064 .ToLocalChecked(); 18065 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 18066 CcTest::heap()->CollectAllAvailableGarbage(); 18067 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); 18068 18069 TestResource* resource = new TestResource( 18070 AsciiToTwoByteString("Romeo Montague Juliet Capulet")); 18071 cons->MakeExternal(resource); 18072 18073 CHECK(cons->IsExternal()); 18074 CHECK_EQ(resource, cons->GetExternalStringResource()); 18075 String::Encoding encoding; 18076 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 18077 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 18078 } 18079 18080 18081 TEST(ExternalizeOldSpaceOneByteCons) { 18082 v8::Isolate* isolate = CcTest::isolate(); 18083 LocalContext env; 18084 v8::HandleScope scope(isolate); 18085 v8::Local<v8::String> cons = 18086 CompileRun("'Romeo Montague ' + 'Juliet Capulet'") 18087 ->ToString(env.local()) 18088 .ToLocalChecked(); 18089 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 18090 CcTest::heap()->CollectAllAvailableGarbage(); 18091 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons))); 18092 18093 TestOneByteResource* resource = 18094 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet")); 18095 cons->MakeExternal(resource); 18096 18097 CHECK(cons->IsExternalOneByte()); 18098 CHECK_EQ(resource, cons->GetExternalOneByteStringResource()); 18099 String::Encoding encoding; 18100 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 18101 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 18102 } 18103 18104 18105 TEST(VisitExternalStrings) { 18106 v8::Isolate* isolate = CcTest::isolate(); 18107 LocalContext env; 18108 v8::HandleScope scope(isolate); 18109 const char* string = "Some string"; 18110 uint16_t* two_byte_string = AsciiToTwoByteString(string); 18111 TestResource* resource[4]; 18112 resource[0] = new TestResource(two_byte_string); 18113 v8::Local<v8::String> string0 = 18114 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0]) 18115 .ToLocalChecked(); 18116 resource[1] = new TestResource(two_byte_string, NULL, false); 18117 v8::Local<v8::String> string1 = 18118 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1]) 18119 .ToLocalChecked(); 18120 18121 // Externalized symbol. 18122 resource[2] = new TestResource(two_byte_string, NULL, false); 18123 v8::Local<v8::String> string2 = 18124 v8::String::NewFromUtf8(env->GetIsolate(), string, 18125 v8::NewStringType::kInternalized) 18126 .ToLocalChecked(); 18127 CHECK(string2->MakeExternal(resource[2])); 18128 18129 // Symbolized External. 18130 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 18131 v8::Local<v8::String> string3 = 18132 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3]) 18133 .ToLocalChecked(); 18134 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. 18135 // Turn into a symbol. 18136 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 18137 CHECK(!CcTest::i_isolate()->factory()->InternalizeString( 18138 string3_i).is_null()); 18139 CHECK(string3_i->IsInternalizedString()); 18140 18141 // We need to add usages for string* to avoid warnings in GCC 4.7 18142 CHECK(string0->IsExternal()); 18143 CHECK(string1->IsExternal()); 18144 CHECK(string2->IsExternal()); 18145 CHECK(string3->IsExternal()); 18146 18147 VisitorImpl visitor(resource); 18148 isolate->VisitExternalResources(&visitor); 18149 visitor.CheckVisitedResources(); 18150 } 18151 18152 18153 TEST(ExternalStringCollectedAtTearDown) { 18154 int destroyed = 0; 18155 v8::Isolate::CreateParams create_params; 18156 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18157 v8::Isolate* isolate = v8::Isolate::New(create_params); 18158 { v8::Isolate::Scope isolate_scope(isolate); 18159 v8::HandleScope handle_scope(isolate); 18160 const char* s = "One string to test them all, one string to find them."; 18161 TestOneByteResource* inscription = 18162 new TestOneByteResource(i::StrDup(s), &destroyed); 18163 v8::Local<v8::String> ring = 18164 v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked(); 18165 // Ring is still alive. Orcs are roaming freely across our lands. 18166 CHECK_EQ(0, destroyed); 18167 USE(ring); 18168 } 18169 18170 isolate->Dispose(); 18171 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18172 CHECK_EQ(1, destroyed); 18173 } 18174 18175 18176 TEST(ExternalInternalizedStringCollectedAtTearDown) { 18177 int destroyed = 0; 18178 v8::Isolate::CreateParams create_params; 18179 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 18180 v8::Isolate* isolate = v8::Isolate::New(create_params); 18181 { v8::Isolate::Scope isolate_scope(isolate); 18182 LocalContext env(isolate); 18183 v8::HandleScope handle_scope(isolate); 18184 CompileRun("var ring = 'One string to test them all';"); 18185 const char* s = "One string to test them all"; 18186 TestOneByteResource* inscription = 18187 new TestOneByteResource(i::StrDup(s), &destroyed); 18188 v8::Local<v8::String> ring = 18189 CompileRun("ring")->ToString(env.local()).ToLocalChecked(); 18190 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18191 ring->MakeExternal(inscription); 18192 // Ring is still alive. Orcs are roaming freely across our lands. 18193 CHECK_EQ(0, destroyed); 18194 USE(ring); 18195 } 18196 18197 isolate->Dispose(); 18198 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18199 CHECK_EQ(1, destroyed); 18200 } 18201 18202 18203 TEST(ExternalInternalizedStringCollectedAtGC) { 18204 int destroyed = 0; 18205 { LocalContext env; 18206 v8::HandleScope handle_scope(env->GetIsolate()); 18207 CompileRun("var ring = 'One string to test them all';"); 18208 const char* s = "One string to test them all"; 18209 TestOneByteResource* inscription = 18210 new TestOneByteResource(i::StrDup(s), &destroyed); 18211 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>(); 18212 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18213 ring->MakeExternal(inscription); 18214 // Ring is still alive. Orcs are roaming freely across our lands. 18215 CHECK_EQ(0, destroyed); 18216 USE(ring); 18217 } 18218 18219 // Garbage collector deals swift blows to evil. 18220 CcTest::i_isolate()->compilation_cache()->Clear(); 18221 CcTest::heap()->CollectAllAvailableGarbage(); 18222 18223 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18224 CHECK_EQ(1, destroyed); 18225 } 18226 18227 18228 static double DoubleFromBits(uint64_t value) { 18229 double target; 18230 i::MemCopy(&target, &value, sizeof(target)); 18231 return target; 18232 } 18233 18234 18235 static uint64_t DoubleToBits(double value) { 18236 uint64_t target; 18237 i::MemCopy(&target, &value, sizeof(target)); 18238 return target; 18239 } 18240 18241 18242 static double DoubleToDateTime(double input) { 18243 double date_limit = 864e13; 18244 if (std::isnan(input) || input < -date_limit || input > date_limit) { 18245 return std::numeric_limits<double>::quiet_NaN(); 18246 } 18247 return (input < 0) ? -(std::floor(-input)) : std::floor(input); 18248 } 18249 18250 18251 // We don't have a consistent way to write 64-bit constants syntactically, so we 18252 // split them into two 32-bit constants and combine them programmatically. 18253 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 18254 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 18255 } 18256 18257 18258 THREADED_TEST(QuietSignalingNaNs) { 18259 LocalContext context; 18260 v8::Isolate* isolate = context->GetIsolate(); 18261 v8::HandleScope scope(isolate); 18262 v8::TryCatch try_catch(isolate); 18263 18264 // Special double values. 18265 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 18266 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 18267 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 18268 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 18269 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 18270 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 18271 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 18272 18273 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 18274 // on either side of the epoch. 18275 double date_limit = 864e13; 18276 18277 double test_values[] = { 18278 snan, 18279 qnan, 18280 infinity, 18281 max_normal, 18282 date_limit + 1, 18283 date_limit, 18284 min_normal, 18285 max_denormal, 18286 min_denormal, 18287 0, 18288 -0, 18289 -min_denormal, 18290 -max_denormal, 18291 -min_normal, 18292 -date_limit, 18293 -date_limit - 1, 18294 -max_normal, 18295 -infinity, 18296 -qnan, 18297 -snan 18298 }; 18299 int num_test_values = 20; 18300 18301 for (int i = 0; i < num_test_values; i++) { 18302 double test_value = test_values[i]; 18303 18304 // Check that Number::New preserves non-NaNs and quiets SNaNs. 18305 v8::Local<v8::Value> number = v8::Number::New(isolate, test_value); 18306 double stored_number = number->NumberValue(context.local()).FromJust(); 18307 if (!std::isnan(test_value)) { 18308 CHECK_EQ(test_value, stored_number); 18309 } else { 18310 uint64_t stored_bits = DoubleToBits(stored_number); 18311 // Check if quiet nan (bits 51..62 all set). 18312 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 18313 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \ 18314 !defined(USE_SIMULATOR) 18315 // Most significant fraction bit for quiet nan is set to 0 18316 // on MIPS architecture. Allowed by IEEE-754. 18317 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18318 #else 18319 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18320 #endif 18321 } 18322 18323 // Check that Date::New preserves non-NaNs in the date range and 18324 // quiets SNaNs. 18325 v8::Local<v8::Value> date = 18326 v8::Date::New(context.local(), test_value).ToLocalChecked(); 18327 double expected_stored_date = DoubleToDateTime(test_value); 18328 double stored_date = date->NumberValue(context.local()).FromJust(); 18329 if (!std::isnan(expected_stored_date)) { 18330 CHECK_EQ(expected_stored_date, stored_date); 18331 } else { 18332 uint64_t stored_bits = DoubleToBits(stored_date); 18333 // Check if quiet nan (bits 51..62 all set). 18334 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 18335 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \ 18336 !defined(USE_SIMULATOR) 18337 // Most significant fraction bit for quiet nan is set to 0 18338 // on MIPS architecture. Allowed by IEEE-754. 18339 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18340 #else 18341 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18342 #endif 18343 } 18344 } 18345 } 18346 18347 18348 static void SpaghettiIncident( 18349 const v8::FunctionCallbackInfo<v8::Value>& args) { 18350 v8::HandleScope scope(args.GetIsolate()); 18351 v8::TryCatch tc(args.GetIsolate()); 18352 v8::MaybeLocal<v8::String> str( 18353 args[0]->ToString(args.GetIsolate()->GetCurrentContext())); 18354 USE(str); 18355 if (tc.HasCaught()) 18356 tc.ReThrow(); 18357 } 18358 18359 18360 // Test that an exception can be propagated down through a spaghetti 18361 // stack using ReThrow. 18362 THREADED_TEST(SpaghettiStackReThrow) { 18363 v8::Isolate* isolate = CcTest::isolate(); 18364 v8::HandleScope scope(isolate); 18365 LocalContext context; 18366 context->Global() 18367 ->Set(context.local(), v8_str("s"), 18368 v8::FunctionTemplate::New(isolate, SpaghettiIncident) 18369 ->GetFunction(context.local()) 18370 .ToLocalChecked()) 18371 .FromJust(); 18372 v8::TryCatch try_catch(isolate); 18373 CompileRun( 18374 "var i = 0;" 18375 "var o = {" 18376 " toString: function () {" 18377 " if (i == 10) {" 18378 " throw 'Hey!';" 18379 " } else {" 18380 " i++;" 18381 " return s(o);" 18382 " }" 18383 " }" 18384 "};" 18385 "s(o);"); 18386 CHECK(try_catch.HasCaught()); 18387 v8::String::Utf8Value value(try_catch.Exception()); 18388 CHECK_EQ(0, strcmp(*value, "Hey!")); 18389 } 18390 18391 18392 TEST(Regress528) { 18393 v8::V8::Initialize(); 18394 v8::Isolate* isolate = CcTest::isolate(); 18395 i::FLAG_retain_maps_for_n_gc = 0; 18396 v8::HandleScope scope(isolate); 18397 v8::Local<Context> other_context; 18398 int gc_count; 18399 18400 // Create a context used to keep the code from aging in the compilation 18401 // cache. 18402 other_context = Context::New(isolate); 18403 18404 // Context-dependent context data creates reference from the compilation 18405 // cache to the global object. 18406 const char* source_simple = "1"; 18407 { 18408 v8::HandleScope scope(isolate); 18409 v8::Local<Context> context = Context::New(isolate); 18410 18411 context->Enter(); 18412 Local<v8::String> obj = v8_str(""); 18413 context->SetEmbedderData(0, obj); 18414 CompileRun(source_simple); 18415 context->Exit(); 18416 } 18417 isolate->ContextDisposedNotification(); 18418 for (gc_count = 1; gc_count < 10; gc_count++) { 18419 other_context->Enter(); 18420 CompileRun(source_simple); 18421 other_context->Exit(); 18422 CcTest::heap()->CollectAllGarbage(); 18423 if (GetGlobalObjectsCount() == 1) break; 18424 } 18425 CHECK_GE(2, gc_count); 18426 CHECK_EQ(1, GetGlobalObjectsCount()); 18427 18428 // Eval in a function creates reference from the compilation cache to the 18429 // global object. 18430 const char* source_eval = "function f(){eval('1')}; f()"; 18431 { 18432 v8::HandleScope scope(isolate); 18433 v8::Local<Context> context = Context::New(isolate); 18434 18435 context->Enter(); 18436 CompileRun(source_eval); 18437 context->Exit(); 18438 } 18439 isolate->ContextDisposedNotification(); 18440 for (gc_count = 1; gc_count < 10; gc_count++) { 18441 other_context->Enter(); 18442 CompileRun(source_eval); 18443 other_context->Exit(); 18444 CcTest::heap()->CollectAllGarbage(); 18445 if (GetGlobalObjectsCount() == 1) break; 18446 } 18447 CHECK_GE(2, gc_count); 18448 CHECK_EQ(1, GetGlobalObjectsCount()); 18449 18450 // Looking up the line number for an exception creates reference from the 18451 // compilation cache to the global object. 18452 const char* source_exception = "function f(){throw 1;} f()"; 18453 { 18454 v8::HandleScope scope(isolate); 18455 v8::Local<Context> context = Context::New(isolate); 18456 18457 context->Enter(); 18458 v8::TryCatch try_catch(isolate); 18459 CompileRun(source_exception); 18460 CHECK(try_catch.HasCaught()); 18461 v8::Local<v8::Message> message = try_catch.Message(); 18462 CHECK(!message.IsEmpty()); 18463 CHECK_EQ(1, message->GetLineNumber(context).FromJust()); 18464 context->Exit(); 18465 } 18466 isolate->ContextDisposedNotification(); 18467 for (gc_count = 1; gc_count < 10; gc_count++) { 18468 other_context->Enter(); 18469 CompileRun(source_exception); 18470 other_context->Exit(); 18471 CcTest::heap()->CollectAllGarbage(); 18472 if (GetGlobalObjectsCount() == 1) break; 18473 } 18474 CHECK_GE(2, gc_count); 18475 CHECK_EQ(1, GetGlobalObjectsCount()); 18476 18477 isolate->ContextDisposedNotification(); 18478 } 18479 18480 18481 THREADED_TEST(ScriptOrigin) { 18482 LocalContext env; 18483 v8::HandleScope scope(env->GetIsolate()); 18484 v8::ScriptOrigin origin = v8::ScriptOrigin( 18485 v8_str("test"), v8::Integer::New(env->GetIsolate(), 1), 18486 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()), 18487 v8::Local<v8::Integer>(), v8::True(env->GetIsolate()), 18488 v8_str("http://sourceMapUrl"), v8::True(env->GetIsolate())); 18489 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}"); 18490 v8::Script::Compile(env.local(), script, &origin) 18491 .ToLocalChecked() 18492 ->Run(env.local()) 18493 .ToLocalChecked(); 18494 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18495 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18496 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18497 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18498 18499 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 18500 CHECK_EQ(0, strcmp("test", 18501 *v8::String::Utf8Value(script_origin_f.ResourceName()))); 18502 CHECK_EQ( 18503 1, 18504 script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust()); 18505 CHECK(script_origin_f.Options().IsSharedCrossOrigin()); 18506 CHECK(script_origin_f.Options().IsEmbedderDebugScript()); 18507 CHECK(script_origin_f.Options().IsOpaque()); 18508 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined()); 18509 18510 CHECK_EQ(0, strcmp("http://sourceMapUrl", 18511 *v8::String::Utf8Value(script_origin_f.SourceMapUrl()))); 18512 18513 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 18514 CHECK_EQ(0, strcmp("test", 18515 *v8::String::Utf8Value(script_origin_g.ResourceName()))); 18516 CHECK_EQ( 18517 1, 18518 script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust()); 18519 CHECK(script_origin_g.Options().IsSharedCrossOrigin()); 18520 CHECK(script_origin_g.Options().IsEmbedderDebugScript()); 18521 CHECK(script_origin_g.Options().IsOpaque()); 18522 CHECK_EQ(0, strcmp("http://sourceMapUrl", 18523 *v8::String::Utf8Value(script_origin_g.SourceMapUrl()))); 18524 } 18525 18526 18527 THREADED_TEST(FunctionGetInferredName) { 18528 LocalContext env; 18529 v8::HandleScope scope(env->GetIsolate()); 18530 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18531 v8::Local<v8::String> script = 18532 v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 18533 v8::Script::Compile(env.local(), script, &origin) 18534 .ToLocalChecked() 18535 ->Run(env.local()) 18536 .ToLocalChecked(); 18537 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18538 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18539 CHECK_EQ(0, 18540 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()))); 18541 } 18542 18543 18544 THREADED_TEST(FunctionGetDebugName) { 18545 LocalContext env; 18546 v8::HandleScope scope(env->GetIsolate()); 18547 const char* code = 18548 "var error = false;" 18549 "function a() { this.x = 1; };" 18550 "a.displayName = 'display_a';" 18551 "var b = (function() {" 18552 " var f = function() { this.x = 2; };" 18553 " f.displayName = 'display_b';" 18554 " return f;" 18555 "})();" 18556 "var c = function() {};" 18557 "c.__defineGetter__('displayName', function() {" 18558 " error = true;" 18559 " throw new Error();" 18560 "});" 18561 "function d() {};" 18562 "d.__defineGetter__('displayName', function() {" 18563 " error = true;" 18564 " return 'wrong_display_name';" 18565 "});" 18566 "function e() {};" 18567 "e.displayName = 'wrong_display_name';" 18568 "e.__defineSetter__('displayName', function() {" 18569 " error = true;" 18570 " throw new Error();" 18571 "});" 18572 "function f() {};" 18573 "f.displayName = { 'foo': 6, toString: function() {" 18574 " error = true;" 18575 " return 'wrong_display_name';" 18576 "}};" 18577 "var g = function() {" 18578 " arguments.callee.displayName = 'set_in_runtime';" 18579 "}; g();" 18580 "var h = function() {};" 18581 "h.displayName = 'displayName';" 18582 "Object.defineProperty(h, 'name', { value: 'function.name' });" 18583 "var i = function() {};" 18584 "i.displayName = 239;" 18585 "Object.defineProperty(i, 'name', { value: 'function.name' });" 18586 "var j = function() {};" 18587 "Object.defineProperty(j, 'name', { value: 'function.name' });" 18588 "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;" 18589 "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;"; 18590 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18591 v8::Script::Compile(env.local(), v8_str(code), &origin) 18592 .ToLocalChecked() 18593 ->Run(env.local()) 18594 .ToLocalChecked(); 18595 v8::Local<v8::Value> error = 18596 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked(); 18597 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust()); 18598 const char* functions[] = {"a", "display_a", 18599 "b", "display_b", 18600 "c", "c", 18601 "d", "d", 18602 "e", "e", 18603 "f", "f", 18604 "g", "set_in_runtime", 18605 "h", "displayName", 18606 "i", "function.name", 18607 "j", "function.name", 18608 "k", "foo.bar.baz", 18609 "l", "baz"}; 18610 for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) { 18611 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18612 env->Global() 18613 ->Get(env.local(), 18614 v8::String::NewFromUtf8(env->GetIsolate(), functions[i * 2], 18615 v8::NewStringType::kNormal) 18616 .ToLocalChecked()) 18617 .ToLocalChecked()); 18618 CHECK_EQ(0, strcmp(functions[i * 2 + 1], 18619 *v8::String::Utf8Value(f->GetDebugName()))); 18620 } 18621 } 18622 18623 18624 THREADED_TEST(FunctionGetDisplayName) { 18625 LocalContext env; 18626 v8::HandleScope scope(env->GetIsolate()); 18627 const char* code = "var error = false;" 18628 "function a() { this.x = 1; };" 18629 "a.displayName = 'display_a';" 18630 "var b = (function() {" 18631 " var f = function() { this.x = 2; };" 18632 " f.displayName = 'display_b';" 18633 " return f;" 18634 "})();" 18635 "var c = function() {};" 18636 "c.__defineGetter__('displayName', function() {" 18637 " error = true;" 18638 " throw new Error();" 18639 "});" 18640 "function d() {};" 18641 "d.__defineGetter__('displayName', function() {" 18642 " error = true;" 18643 " return 'wrong_display_name';" 18644 "});" 18645 "function e() {};" 18646 "e.displayName = 'wrong_display_name';" 18647 "e.__defineSetter__('displayName', function() {" 18648 " error = true;" 18649 " throw new Error();" 18650 "});" 18651 "function f() {};" 18652 "f.displayName = { 'foo': 6, toString: function() {" 18653 " error = true;" 18654 " return 'wrong_display_name';" 18655 "}};" 18656 "var g = function() {" 18657 " arguments.callee.displayName = 'set_in_runtime';" 18658 "}; g();"; 18659 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18660 v8::Script::Compile(env.local(), v8_str(code), &origin) 18661 .ToLocalChecked() 18662 ->Run(env.local()) 18663 .ToLocalChecked(); 18664 v8::Local<v8::Value> error = 18665 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked(); 18666 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( 18667 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()); 18668 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( 18669 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()); 18670 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( 18671 env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked()); 18672 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( 18673 env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked()); 18674 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( 18675 env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked()); 18676 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18677 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18678 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18679 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18680 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust()); 18681 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName()))); 18682 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName()))); 18683 CHECK(c->GetDisplayName()->IsUndefined()); 18684 CHECK(d->GetDisplayName()->IsUndefined()); 18685 CHECK(e->GetDisplayName()->IsUndefined()); 18686 CHECK(f->GetDisplayName()->IsUndefined()); 18687 CHECK_EQ( 18688 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()))); 18689 } 18690 18691 18692 THREADED_TEST(ScriptLineNumber) { 18693 LocalContext env; 18694 v8::HandleScope scope(env->GetIsolate()); 18695 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18696 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}"); 18697 v8::Script::Compile(env.local(), script, &origin) 18698 .ToLocalChecked() 18699 ->Run(env.local()) 18700 .ToLocalChecked(); 18701 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18702 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18703 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18704 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18705 CHECK_EQ(0, f->GetScriptLineNumber()); 18706 CHECK_EQ(2, g->GetScriptLineNumber()); 18707 } 18708 18709 18710 THREADED_TEST(ScriptColumnNumber) { 18711 LocalContext env; 18712 v8::Isolate* isolate = env->GetIsolate(); 18713 v8::HandleScope scope(isolate); 18714 v8::ScriptOrigin origin = 18715 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3), 18716 v8::Integer::New(isolate, 2)); 18717 v8::Local<v8::String> script = 18718 v8_str("function foo() {}\n\n function bar() {}"); 18719 v8::Script::Compile(env.local(), script, &origin) 18720 .ToLocalChecked() 18721 ->Run(env.local()) 18722 .ToLocalChecked(); 18723 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18724 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked()); 18725 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18726 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked()); 18727 CHECK_EQ(14, foo->GetScriptColumnNumber()); 18728 CHECK_EQ(17, bar->GetScriptColumnNumber()); 18729 } 18730 18731 18732 THREADED_TEST(FunctionIsBuiltin) { 18733 LocalContext env; 18734 v8::Isolate* isolate = env->GetIsolate(); 18735 v8::HandleScope scope(isolate); 18736 v8::Local<v8::Function> f; 18737 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); 18738 CHECK(f->IsBuiltin()); 18739 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); 18740 CHECK(f->IsBuiltin()); 18741 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); 18742 CHECK(f->IsBuiltin()); 18743 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); 18744 CHECK(f->IsBuiltin()); 18745 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); 18746 CHECK(!f->IsBuiltin()); 18747 } 18748 18749 18750 THREADED_TEST(FunctionGetScriptId) { 18751 LocalContext env; 18752 v8::Isolate* isolate = env->GetIsolate(); 18753 v8::HandleScope scope(isolate); 18754 v8::ScriptOrigin origin = 18755 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3), 18756 v8::Integer::New(isolate, 2)); 18757 v8::Local<v8::String> scriptSource = 18758 v8_str("function foo() {}\n\n function bar() {}"); 18759 v8::Local<v8::Script> script( 18760 v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked()); 18761 script->Run(env.local()).ToLocalChecked(); 18762 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18763 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked()); 18764 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18765 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked()); 18766 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId()); 18767 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId()); 18768 } 18769 18770 18771 THREADED_TEST(FunctionGetBoundFunction) { 18772 LocalContext env; 18773 v8::HandleScope scope(env->GetIsolate()); 18774 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test")); 18775 v8::Local<v8::String> script = v8_str( 18776 "var a = new Object();\n" 18777 "a.x = 1;\n" 18778 "function f () { return this.x };\n" 18779 "var g = f.bind(a);\n" 18780 "var b = g();"); 18781 v8::Script::Compile(env.local(), script, &origin) 18782 .ToLocalChecked() 18783 ->Run(env.local()) 18784 .ToLocalChecked(); 18785 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18786 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked()); 18787 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18788 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked()); 18789 CHECK(g->GetBoundFunction()->IsFunction()); 18790 Local<v8::Function> original_function = Local<v8::Function>::Cast( 18791 g->GetBoundFunction()); 18792 CHECK(f->GetName() 18793 ->Equals(env.local(), original_function->GetName()) 18794 .FromJust()); 18795 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber()); 18796 CHECK_EQ(f->GetScriptColumnNumber(), 18797 original_function->GetScriptColumnNumber()); 18798 } 18799 18800 18801 static void GetterWhichReturns42( 18802 Local<String> name, 18803 const v8::PropertyCallbackInfo<v8::Value>& info) { 18804 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18805 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18806 info.GetReturnValue().Set(v8_num(42)); 18807 } 18808 18809 18810 static void SetterWhichSetsYOnThisTo23( 18811 Local<String> name, 18812 Local<Value> value, 18813 const v8::PropertyCallbackInfo<void>& info) { 18814 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18815 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18816 Local<Object>::Cast(info.This()) 18817 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18818 .FromJust(); 18819 } 18820 18821 18822 void FooGetInterceptor(Local<Name> name, 18823 const v8::PropertyCallbackInfo<v8::Value>& info) { 18824 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18825 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18826 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 18827 .FromJust()) { 18828 return; 18829 } 18830 info.GetReturnValue().Set(v8_num(42)); 18831 } 18832 18833 18834 void FooSetInterceptor(Local<Name> name, Local<Value> value, 18835 const v8::PropertyCallbackInfo<v8::Value>& info) { 18836 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18837 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18838 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 18839 .FromJust()) { 18840 return; 18841 } 18842 Local<Object>::Cast(info.This()) 18843 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18844 .FromJust(); 18845 info.GetReturnValue().Set(v8_num(23)); 18846 } 18847 18848 18849 TEST(SetterOnConstructorPrototype) { 18850 v8::Isolate* isolate = CcTest::isolate(); 18851 v8::HandleScope scope(isolate); 18852 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18853 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 18854 SetterWhichSetsYOnThisTo23); 18855 LocalContext context; 18856 CHECK(context->Global() 18857 ->Set(context.local(), v8_str("P"), 18858 templ->NewInstance(context.local()).ToLocalChecked()) 18859 .FromJust()); 18860 CompileRun("function C1() {" 18861 " this.x = 23;" 18862 "};" 18863 "C1.prototype = P;" 18864 "function C2() {" 18865 " this.x = 23" 18866 "};" 18867 "C2.prototype = { };" 18868 "C2.prototype.__proto__ = P;"); 18869 18870 v8::Local<v8::Script> script; 18871 script = v8_compile("new C1();"); 18872 for (int i = 0; i < 10; i++) { 18873 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18874 script->Run(context.local()).ToLocalChecked()); 18875 CHECK_EQ(42, c1->Get(context.local(), v8_str("x")) 18876 .ToLocalChecked() 18877 ->Int32Value(context.local()) 18878 .FromJust()); 18879 CHECK_EQ(23, c1->Get(context.local(), v8_str("y")) 18880 .ToLocalChecked() 18881 ->Int32Value(context.local()) 18882 .FromJust()); 18883 } 18884 18885 script = v8_compile("new C2();"); 18886 for (int i = 0; i < 10; i++) { 18887 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast( 18888 script->Run(context.local()).ToLocalChecked()); 18889 CHECK_EQ(42, c2->Get(context.local(), v8_str("x")) 18890 .ToLocalChecked() 18891 ->Int32Value(context.local()) 18892 .FromJust()); 18893 CHECK_EQ(23, c2->Get(context.local(), v8_str("y")) 18894 .ToLocalChecked() 18895 ->Int32Value(context.local()) 18896 .FromJust()); 18897 } 18898 } 18899 18900 18901 static void NamedPropertySetterWhichSetsYOnThisTo23( 18902 Local<Name> name, Local<Value> value, 18903 const v8::PropertyCallbackInfo<v8::Value>& info) { 18904 if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x")) 18905 .FromJust()) { 18906 Local<Object>::Cast(info.This()) 18907 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23)) 18908 .FromJust(); 18909 } 18910 } 18911 18912 18913 THREADED_TEST(InterceptorOnConstructorPrototype) { 18914 v8::Isolate* isolate = CcTest::isolate(); 18915 v8::HandleScope scope(isolate); 18916 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18917 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 18918 NamedPropertyGetterWhichReturns42, 18919 NamedPropertySetterWhichSetsYOnThisTo23)); 18920 LocalContext context; 18921 CHECK(context->Global() 18922 ->Set(context.local(), v8_str("P"), 18923 templ->NewInstance(context.local()).ToLocalChecked()) 18924 .FromJust()); 18925 CompileRun("function C1() {" 18926 " this.x = 23;" 18927 "};" 18928 "C1.prototype = P;" 18929 "function C2() {" 18930 " this.x = 23" 18931 "};" 18932 "C2.prototype = { };" 18933 "C2.prototype.__proto__ = P;"); 18934 18935 v8::Local<v8::Script> script; 18936 script = v8_compile("new C1();"); 18937 for (int i = 0; i < 10; i++) { 18938 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18939 script->Run(context.local()).ToLocalChecked()); 18940 CHECK_EQ(23, c1->Get(context.local(), v8_str("x")) 18941 .ToLocalChecked() 18942 ->Int32Value(context.local()) 18943 .FromJust()); 18944 CHECK_EQ(42, c1->Get(context.local(), v8_str("y")) 18945 .ToLocalChecked() 18946 ->Int32Value(context.local()) 18947 .FromJust()); 18948 } 18949 18950 script = v8_compile("new C2();"); 18951 for (int i = 0; i < 10; i++) { 18952 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast( 18953 script->Run(context.local()).ToLocalChecked()); 18954 CHECK_EQ(23, c2->Get(context.local(), v8_str("x")) 18955 .ToLocalChecked() 18956 ->Int32Value(context.local()) 18957 .FromJust()); 18958 CHECK_EQ(42, c2->Get(context.local(), v8_str("y")) 18959 .ToLocalChecked() 18960 ->Int32Value(context.local()) 18961 .FromJust()); 18962 } 18963 } 18964 18965 18966 TEST(Regress618) { 18967 const char* source = "function C1() {" 18968 " this.x = 23;" 18969 "};" 18970 "C1.prototype = P;"; 18971 18972 LocalContext context; 18973 v8::Isolate* isolate = context->GetIsolate(); 18974 v8::HandleScope scope(isolate); 18975 v8::Local<v8::Script> script; 18976 18977 // Use a simple object as prototype. 18978 v8::Local<v8::Object> prototype = v8::Object::New(isolate); 18979 prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust(); 18980 CHECK(context->Global() 18981 ->Set(context.local(), v8_str("P"), prototype) 18982 .FromJust()); 18983 18984 // This compile will add the code to the compilation cache. 18985 CompileRun(source); 18986 18987 script = v8_compile("new C1();"); 18988 // Allow enough iterations for the inobject slack tracking logic 18989 // to finalize instance size and install the fast construct stub. 18990 for (int i = 0; i < 256; i++) { 18991 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 18992 script->Run(context.local()).ToLocalChecked()); 18993 CHECK_EQ(23, c1->Get(context.local(), v8_str("x")) 18994 .ToLocalChecked() 18995 ->Int32Value(context.local()) 18996 .FromJust()); 18997 CHECK_EQ(42, c1->Get(context.local(), v8_str("y")) 18998 .ToLocalChecked() 18999 ->Int32Value(context.local()) 19000 .FromJust()); 19001 } 19002 19003 // Use an API object with accessors as prototype. 19004 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 19005 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 19006 SetterWhichSetsYOnThisTo23); 19007 CHECK(context->Global() 19008 ->Set(context.local(), v8_str("P"), 19009 templ->NewInstance(context.local()).ToLocalChecked()) 19010 .FromJust()); 19011 19012 // This compile will get the code from the compilation cache. 19013 CompileRun(source); 19014 19015 script = v8_compile("new C1();"); 19016 for (int i = 0; i < 10; i++) { 19017 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast( 19018 script->Run(context.local()).ToLocalChecked()); 19019 CHECK_EQ(42, c1->Get(context.local(), v8_str("x")) 19020 .ToLocalChecked() 19021 ->Int32Value(context.local()) 19022 .FromJust()); 19023 CHECK_EQ(23, c1->Get(context.local(), v8_str("y")) 19024 .ToLocalChecked() 19025 ->Int32Value(context.local()) 19026 .FromJust()); 19027 } 19028 } 19029 19030 v8::Isolate* gc_callbacks_isolate = NULL; 19031 int prologue_call_count = 0; 19032 int epilogue_call_count = 0; 19033 int prologue_call_count_second = 0; 19034 int epilogue_call_count_second = 0; 19035 int prologue_call_count_alloc = 0; 19036 int epilogue_call_count_alloc = 0; 19037 19038 void PrologueCallback(v8::Isolate* isolate, 19039 v8::GCType, 19040 v8::GCCallbackFlags flags) { 19041 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19042 CHECK_EQ(gc_callbacks_isolate, isolate); 19043 ++prologue_call_count; 19044 } 19045 19046 void EpilogueCallback(v8::Isolate* isolate, 19047 v8::GCType, 19048 v8::GCCallbackFlags flags) { 19049 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19050 CHECK_EQ(gc_callbacks_isolate, isolate); 19051 ++epilogue_call_count; 19052 } 19053 19054 19055 void PrologueCallbackSecond(v8::Isolate* isolate, 19056 v8::GCType, 19057 v8::GCCallbackFlags flags) { 19058 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19059 CHECK_EQ(gc_callbacks_isolate, isolate); 19060 ++prologue_call_count_second; 19061 } 19062 19063 19064 void EpilogueCallbackSecond(v8::Isolate* isolate, 19065 v8::GCType, 19066 v8::GCCallbackFlags flags) { 19067 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19068 CHECK_EQ(gc_callbacks_isolate, isolate); 19069 ++epilogue_call_count_second; 19070 } 19071 19072 19073 void PrologueCallbackAlloc(v8::Isolate* isolate, 19074 v8::GCType, 19075 v8::GCCallbackFlags flags) { 19076 v8::HandleScope scope(isolate); 19077 19078 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19079 CHECK_EQ(gc_callbacks_isolate, isolate); 19080 ++prologue_call_count_alloc; 19081 19082 // Simulate full heap to see if we will reenter this callback 19083 i::heap::SimulateFullSpace(CcTest::heap()->new_space()); 19084 19085 Local<Object> obj = Object::New(isolate); 19086 CHECK(!obj.IsEmpty()); 19087 19088 CcTest::heap()->CollectAllGarbage( 19089 i::Heap::kAbortIncrementalMarkingMask); 19090 } 19091 19092 19093 void EpilogueCallbackAlloc(v8::Isolate* isolate, 19094 v8::GCType, 19095 v8::GCCallbackFlags flags) { 19096 v8::HandleScope scope(isolate); 19097 19098 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 19099 CHECK_EQ(gc_callbacks_isolate, isolate); 19100 ++epilogue_call_count_alloc; 19101 19102 // Simulate full heap to see if we will reenter this callback 19103 i::heap::SimulateFullSpace(CcTest::heap()->new_space()); 19104 19105 Local<Object> obj = Object::New(isolate); 19106 CHECK(!obj.IsEmpty()); 19107 19108 CcTest::heap()->CollectAllGarbage( 19109 i::Heap::kAbortIncrementalMarkingMask); 19110 } 19111 19112 19113 TEST(GCCallbacksOld) { 19114 LocalContext context; 19115 19116 gc_callbacks_isolate = context->GetIsolate(); 19117 19118 context->GetIsolate()->AddGCPrologueCallback(PrologueCallback); 19119 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback); 19120 CHECK_EQ(0, prologue_call_count); 19121 CHECK_EQ(0, epilogue_call_count); 19122 CcTest::heap()->CollectAllGarbage(); 19123 CHECK_EQ(1, prologue_call_count); 19124 CHECK_EQ(1, epilogue_call_count); 19125 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond); 19126 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond); 19127 CcTest::heap()->CollectAllGarbage(); 19128 CHECK_EQ(2, prologue_call_count); 19129 CHECK_EQ(2, epilogue_call_count); 19130 CHECK_EQ(1, prologue_call_count_second); 19131 CHECK_EQ(1, epilogue_call_count_second); 19132 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback); 19133 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback); 19134 CcTest::heap()->CollectAllGarbage(); 19135 CHECK_EQ(2, prologue_call_count); 19136 CHECK_EQ(2, epilogue_call_count); 19137 CHECK_EQ(2, prologue_call_count_second); 19138 CHECK_EQ(2, epilogue_call_count_second); 19139 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond); 19140 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 19141 CcTest::heap()->CollectAllGarbage(); 19142 CHECK_EQ(2, prologue_call_count); 19143 CHECK_EQ(2, epilogue_call_count); 19144 CHECK_EQ(2, prologue_call_count_second); 19145 CHECK_EQ(2, epilogue_call_count_second); 19146 } 19147 19148 19149 TEST(GCCallbacks) { 19150 LocalContext context; 19151 v8::Isolate* isolate = context->GetIsolate(); 19152 gc_callbacks_isolate = isolate; 19153 isolate->AddGCPrologueCallback(PrologueCallback); 19154 isolate->AddGCEpilogueCallback(EpilogueCallback); 19155 CHECK_EQ(0, prologue_call_count); 19156 CHECK_EQ(0, epilogue_call_count); 19157 CcTest::heap()->CollectAllGarbage(); 19158 CHECK_EQ(1, prologue_call_count); 19159 CHECK_EQ(1, epilogue_call_count); 19160 isolate->AddGCPrologueCallback(PrologueCallbackSecond); 19161 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); 19162 CcTest::heap()->CollectAllGarbage(); 19163 CHECK_EQ(2, prologue_call_count); 19164 CHECK_EQ(2, epilogue_call_count); 19165 CHECK_EQ(1, prologue_call_count_second); 19166 CHECK_EQ(1, epilogue_call_count_second); 19167 isolate->RemoveGCPrologueCallback(PrologueCallback); 19168 isolate->RemoveGCEpilogueCallback(EpilogueCallback); 19169 CcTest::heap()->CollectAllGarbage(); 19170 CHECK_EQ(2, prologue_call_count); 19171 CHECK_EQ(2, epilogue_call_count); 19172 CHECK_EQ(2, prologue_call_count_second); 19173 CHECK_EQ(2, epilogue_call_count_second); 19174 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); 19175 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 19176 CcTest::heap()->CollectAllGarbage(); 19177 CHECK_EQ(2, prologue_call_count); 19178 CHECK_EQ(2, epilogue_call_count); 19179 CHECK_EQ(2, prologue_call_count_second); 19180 CHECK_EQ(2, epilogue_call_count_second); 19181 19182 CHECK_EQ(0, prologue_call_count_alloc); 19183 CHECK_EQ(0, epilogue_call_count_alloc); 19184 isolate->AddGCPrologueCallback(PrologueCallbackAlloc); 19185 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc); 19186 CcTest::heap()->CollectAllGarbage( 19187 i::Heap::kAbortIncrementalMarkingMask); 19188 CHECK_EQ(1, prologue_call_count_alloc); 19189 CHECK_EQ(1, epilogue_call_count_alloc); 19190 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc); 19191 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc); 19192 } 19193 19194 19195 THREADED_TEST(TwoByteStringInOneByteCons) { 19196 // See Chromium issue 47824. 19197 LocalContext context; 19198 v8::HandleScope scope(context->GetIsolate()); 19199 19200 const char* init_code = 19201 "var str1 = 'abelspendabel';" 19202 "var str2 = str1 + str1 + str1;" 19203 "str2;"; 19204 Local<Value> result = CompileRun(init_code); 19205 19206 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 19207 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 19208 19209 CHECK(result->IsString()); 19210 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 19211 int length = string->length(); 19212 CHECK(string->IsOneByteRepresentation()); 19213 19214 i::Handle<i::String> flat_string = i::String::Flatten(string); 19215 19216 CHECK(string->IsOneByteRepresentation()); 19217 CHECK(flat_string->IsOneByteRepresentation()); 19218 19219 // Create external resource. 19220 uint16_t* uc16_buffer = new uint16_t[length + 1]; 19221 19222 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 19223 uc16_buffer[length] = 0; 19224 19225 TestResource resource(uc16_buffer); 19226 19227 flat_string->MakeExternal(&resource); 19228 19229 CHECK(flat_string->IsTwoByteRepresentation()); 19230 19231 // If the cons string has been short-circuited, skip the following checks. 19232 if (!string.is_identical_to(flat_string)) { 19233 // At this point, we should have a Cons string which is flat and one-byte, 19234 // with a first half that is a two-byte string (although it only contains 19235 // one-byte characters). This is a valid sequence of steps, and it can 19236 // happen in real pages. 19237 CHECK(string->IsOneByteRepresentation()); 19238 i::ConsString* cons = i::ConsString::cast(*string); 19239 CHECK_EQ(0, cons->second()->length()); 19240 CHECK(cons->first()->IsTwoByteRepresentation()); 19241 } 19242 19243 // Check that some string operations work. 19244 19245 // Atom RegExp. 19246 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 19247 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); 19248 19249 // Nonatom RegExp. 19250 reresult = CompileRun("str2.match(/abe./g).length;"); 19251 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); 19252 19253 reresult = CompileRun("str2.search(/bel/g);"); 19254 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); 19255 19256 reresult = CompileRun("str2.search(/be./g);"); 19257 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); 19258 19259 ExpectTrue("/bel/g.test(str2);"); 19260 19261 ExpectTrue("/be./g.test(str2);"); 19262 19263 reresult = CompileRun("/bel/g.exec(str2);"); 19264 CHECK(!reresult->IsNull()); 19265 19266 reresult = CompileRun("/be./g.exec(str2);"); 19267 CHECK(!reresult->IsNull()); 19268 19269 ExpectString("str2.substring(2, 10);", "elspenda"); 19270 19271 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 19272 19273 ExpectString("str2.charAt(2);", "e"); 19274 19275 ExpectObject("str2.indexOf('els');", indexof); 19276 19277 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 19278 19279 reresult = CompileRun("str2.charCodeAt(2);"); 19280 CHECK_EQ(static_cast<int32_t>('e'), 19281 reresult->Int32Value(context.local()).FromJust()); 19282 } 19283 19284 19285 TEST(ContainsOnlyOneByte) { 19286 v8::V8::Initialize(); 19287 v8::Isolate* isolate = CcTest::isolate(); 19288 v8::HandleScope scope(isolate); 19289 // Make a buffer long enough that it won't automatically be converted. 19290 const int length = 512; 19291 // Ensure word aligned assignment. 19292 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 19293 v8::base::SmartArrayPointer<uintptr_t> aligned_contents( 19294 new uintptr_t[aligned_length]); 19295 uint16_t* string_contents = 19296 reinterpret_cast<uint16_t*>(aligned_contents.get()); 19297 // Set to contain only one byte. 19298 for (int i = 0; i < length-1; i++) { 19299 string_contents[i] = 0x41; 19300 } 19301 string_contents[length-1] = 0; 19302 // Simple case. 19303 Local<String> string = 19304 String::NewExternalTwoByte(isolate, 19305 new TestResource(string_contents, NULL, false)) 19306 .ToLocalChecked(); 19307 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19308 // Counter example. 19309 string = String::NewFromTwoByte(isolate, string_contents, 19310 v8::NewStringType::kNormal) 19311 .ToLocalChecked(); 19312 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19313 // Test left right and balanced cons strings. 19314 Local<String> base = v8_str("a"); 19315 Local<String> left = base; 19316 Local<String> right = base; 19317 for (int i = 0; i < 1000; i++) { 19318 left = String::Concat(base, left); 19319 right = String::Concat(right, base); 19320 } 19321 Local<String> balanced = String::Concat(left, base); 19322 balanced = String::Concat(balanced, right); 19323 Local<String> cons_strings[] = {left, balanced, right}; 19324 Local<String> two_byte = 19325 String::NewExternalTwoByte(isolate, 19326 new TestResource(string_contents, NULL, false)) 19327 .ToLocalChecked(); 19328 USE(two_byte); USE(cons_strings); 19329 for (size_t i = 0; i < arraysize(cons_strings); i++) { 19330 // Base assumptions. 19331 string = cons_strings[i]; 19332 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19333 // Test left and right concatentation. 19334 string = String::Concat(two_byte, cons_strings[i]); 19335 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19336 string = String::Concat(cons_strings[i], two_byte); 19337 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19338 } 19339 // Set bits in different positions 19340 // for strings of different lengths and alignments. 19341 for (int alignment = 0; alignment < 7; alignment++) { 19342 for (int size = 2; alignment + size < length; size *= 2) { 19343 int zero_offset = size + alignment; 19344 string_contents[zero_offset] = 0; 19345 for (int i = 0; i < size; i++) { 19346 int shift = 8 + (i % 7); 19347 string_contents[alignment + i] = 1 << shift; 19348 string = String::NewExternalTwoByte( 19349 isolate, 19350 new TestResource(string_contents + alignment, NULL, false)) 19351 .ToLocalChecked(); 19352 CHECK_EQ(size, string->Length()); 19353 CHECK(!string->ContainsOnlyOneByte()); 19354 string_contents[alignment + i] = 0x41; 19355 } 19356 string_contents[zero_offset] = 0x41; 19357 } 19358 } 19359 } 19360 19361 19362 // Failed access check callback that performs a GC on each invocation. 19363 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 19364 v8::AccessType type, 19365 Local<v8::Value> data) { 19366 CcTest::heap()->CollectAllGarbage(); 19367 CcTest::isolate()->ThrowException( 19368 v8::Exception::Error(v8_str("cross context"))); 19369 } 19370 19371 19372 TEST(GCInFailedAccessCheckCallback) { 19373 // Install a failed access check callback that performs a GC on each 19374 // invocation. Then force the callback to be called from va 19375 19376 v8::V8::Initialize(); 19377 v8::Isolate* isolate = CcTest::isolate(); 19378 19379 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 19380 19381 v8::HandleScope scope(isolate); 19382 19383 // Create an ObjectTemplate for global objects and install access 19384 // check callbacks that will block access. 19385 v8::Local<v8::ObjectTemplate> global_template = 19386 v8::ObjectTemplate::New(isolate); 19387 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 19388 19389 // Create a context and set an x property on it's global object. 19390 LocalContext context0(NULL, global_template); 19391 CHECK(context0->Global() 19392 ->Set(context0.local(), v8_str("x"), v8_num(42)) 19393 .FromJust()); 19394 v8::Local<v8::Object> global0 = context0->Global(); 19395 19396 // Create a context with a different security token so that the 19397 // failed access check callback will be called on each access. 19398 LocalContext context1(NULL, global_template); 19399 CHECK(context1->Global() 19400 ->Set(context1.local(), v8_str("other"), global0) 19401 .FromJust()); 19402 19403 v8::TryCatch try_catch(isolate); 19404 19405 // Get property with failed access check. 19406 CHECK(CompileRun("other.x").IsEmpty()); 19407 CHECK(try_catch.HasCaught()); 19408 try_catch.Reset(); 19409 19410 // Get element with failed access check. 19411 CHECK(CompileRun("other[0]").IsEmpty()); 19412 CHECK(try_catch.HasCaught()); 19413 try_catch.Reset(); 19414 19415 // Set property with failed access check. 19416 CHECK(CompileRun("other.x = new Object()").IsEmpty()); 19417 CHECK(try_catch.HasCaught()); 19418 try_catch.Reset(); 19419 19420 // Set element with failed access check. 19421 CHECK(CompileRun("other[0] = new Object()").IsEmpty()); 19422 CHECK(try_catch.HasCaught()); 19423 try_catch.Reset(); 19424 19425 // Get property attribute with failed access check. 19426 CHECK(CompileRun("\'x\' in other").IsEmpty()); 19427 CHECK(try_catch.HasCaught()); 19428 try_catch.Reset(); 19429 19430 // Get property attribute for element with failed access check. 19431 CHECK(CompileRun("0 in other").IsEmpty()); 19432 CHECK(try_catch.HasCaught()); 19433 try_catch.Reset(); 19434 19435 // Delete property. 19436 CHECK(CompileRun("delete other.x").IsEmpty()); 19437 CHECK(try_catch.HasCaught()); 19438 try_catch.Reset(); 19439 19440 // Delete element. 19441 CHECK(global0->Delete(context1.local(), 0).IsNothing()); 19442 CHECK(try_catch.HasCaught()); 19443 try_catch.Reset(); 19444 19445 // DefineAccessor. 19446 CHECK(global0->SetAccessor(context1.local(), v8_str("x"), GetXValue, NULL, 19447 v8_str("x")) 19448 .IsNothing()); 19449 CHECK(try_catch.HasCaught()); 19450 try_catch.Reset(); 19451 19452 // Define JavaScript accessor. 19453 CHECK(CompileRun( 19454 "Object.prototype.__defineGetter__.call(" 19455 " other, \'x\', function() { return 42; })").IsEmpty()); 19456 CHECK(try_catch.HasCaught()); 19457 try_catch.Reset(); 19458 19459 // LookupAccessor. 19460 CHECK(CompileRun( 19461 "Object.prototype.__lookupGetter__.call(" 19462 " other, \'x\')").IsEmpty()); 19463 CHECK(try_catch.HasCaught()); 19464 try_catch.Reset(); 19465 19466 // HasOwnElement. 19467 CHECK(CompileRun( 19468 "Object.prototype.hasOwnProperty.call(" 19469 "other, \'0\')").IsEmpty()); 19470 CHECK(try_catch.HasCaught()); 19471 try_catch.Reset(); 19472 19473 CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing()); 19474 CHECK(try_catch.HasCaught()); 19475 try_catch.Reset(); 19476 19477 CHECK( 19478 global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing()); 19479 CHECK(try_catch.HasCaught()); 19480 try_catch.Reset(); 19481 19482 CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x")) 19483 .IsNothing()); 19484 CHECK(try_catch.HasCaught()); 19485 try_catch.Reset(); 19486 19487 // Reset the failed access check callback so it does not influence 19488 // the other tests. 19489 isolate->SetFailedAccessCheckCallbackFunction(NULL); 19490 } 19491 19492 19493 TEST(IsolateNewDispose) { 19494 v8::Isolate* current_isolate = CcTest::isolate(); 19495 v8::Isolate::CreateParams create_params; 19496 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19497 v8::Isolate* isolate = v8::Isolate::New(create_params); 19498 CHECK(isolate != NULL); 19499 CHECK(current_isolate != isolate); 19500 CHECK(current_isolate == CcTest::isolate()); 19501 19502 isolate->SetFatalErrorHandler(StoringErrorCallback); 19503 last_location = last_message = NULL; 19504 isolate->Dispose(); 19505 CHECK(!last_location); 19506 CHECK(!last_message); 19507 } 19508 19509 19510 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) { 19511 v8::Isolate::CreateParams create_params; 19512 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19513 v8::Isolate* isolate = v8::Isolate::New(create_params); 19514 { 19515 v8::Isolate::Scope i_scope(isolate); 19516 v8::HandleScope scope(isolate); 19517 LocalContext context(isolate); 19518 // Run something in this isolate. 19519 ExpectTrue("true"); 19520 isolate->SetFatalErrorHandler(StoringErrorCallback); 19521 last_location = last_message = NULL; 19522 // Still entered, should fail. 19523 isolate->Dispose(); 19524 CHECK(last_location); 19525 CHECK(last_message); 19526 } 19527 isolate->Dispose(); 19528 } 19529 19530 19531 static void BreakArrayGuarantees(const char* script) { 19532 v8::Isolate::CreateParams create_params; 19533 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19534 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 19535 isolate1->Enter(); 19536 v8::Persistent<v8::Context> context1; 19537 { 19538 v8::HandleScope scope(isolate1); 19539 context1.Reset(isolate1, Context::New(isolate1)); 19540 } 19541 19542 { 19543 v8::HandleScope scope(isolate1); 19544 v8::Local<v8::Context> context = 19545 v8::Local<v8::Context>::New(isolate1, context1); 19546 v8::Context::Scope context_scope(context); 19547 v8::internal::Isolate* i_isolate = 19548 reinterpret_cast<v8::internal::Isolate*>(isolate1); 19549 CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact()); 19550 // Run something in new isolate. 19551 CompileRun(script); 19552 CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact()); 19553 } 19554 isolate1->Exit(); 19555 isolate1->Dispose(); 19556 } 19557 19558 19559 TEST(VerifyArrayPrototypeGuarantees) { 19560 // Break fast array hole handling by element changes. 19561 BreakArrayGuarantees("[].__proto__[1] = 3;"); 19562 BreakArrayGuarantees("Object.prototype[3] = 'three';"); 19563 BreakArrayGuarantees("Array.prototype.push(1);"); 19564 BreakArrayGuarantees("Array.prototype.unshift(1);"); 19565 // Break fast array hole handling by changing length. 19566 BreakArrayGuarantees("Array.prototype.length = 30;"); 19567 // Break fast array hole handling by prototype structure changes. 19568 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };"); 19569 // By sending elements to dictionary mode. 19570 BreakArrayGuarantees( 19571 "Object.defineProperty(Array.prototype, 0, {" 19572 " get: function() { return 3; }});"); 19573 BreakArrayGuarantees( 19574 "Object.defineProperty(Object.prototype, 0, {" 19575 " get: function() { return 3; }});"); 19576 } 19577 19578 19579 TEST(RunTwoIsolatesOnSingleThread) { 19580 // Run isolate 1. 19581 v8::Isolate::CreateParams create_params; 19582 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19583 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 19584 isolate1->Enter(); 19585 v8::Persistent<v8::Context> context1; 19586 { 19587 v8::HandleScope scope(isolate1); 19588 context1.Reset(isolate1, Context::New(isolate1)); 19589 } 19590 19591 { 19592 v8::HandleScope scope(isolate1); 19593 v8::Local<v8::Context> context = 19594 v8::Local<v8::Context>::New(isolate1, context1); 19595 v8::Context::Scope context_scope(context); 19596 // Run something in new isolate. 19597 CompileRun("var foo = 'isolate 1';"); 19598 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19599 } 19600 19601 // Run isolate 2. 19602 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 19603 v8::Persistent<v8::Context> context2; 19604 19605 { 19606 v8::Isolate::Scope iscope(isolate2); 19607 v8::HandleScope scope(isolate2); 19608 context2.Reset(isolate2, Context::New(isolate2)); 19609 v8::Local<v8::Context> context = 19610 v8::Local<v8::Context>::New(isolate2, context2); 19611 v8::Context::Scope context_scope(context); 19612 19613 // Run something in new isolate. 19614 CompileRun("var foo = 'isolate 2';"); 19615 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19616 } 19617 19618 { 19619 v8::HandleScope scope(isolate1); 19620 v8::Local<v8::Context> context = 19621 v8::Local<v8::Context>::New(isolate1, context1); 19622 v8::Context::Scope context_scope(context); 19623 // Now again in isolate 1 19624 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19625 } 19626 19627 isolate1->Exit(); 19628 19629 // Run some stuff in default isolate. 19630 v8::Persistent<v8::Context> context_default; 19631 { 19632 v8::Isolate* isolate = CcTest::isolate(); 19633 v8::Isolate::Scope iscope(isolate); 19634 v8::HandleScope scope(isolate); 19635 context_default.Reset(isolate, Context::New(isolate)); 19636 } 19637 19638 { 19639 v8::HandleScope scope(CcTest::isolate()); 19640 v8::Local<v8::Context> context = 19641 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19642 v8::Context::Scope context_scope(context); 19643 // Variables in other isolates should be not available, verify there 19644 // is an exception. 19645 ExpectTrue("function f() {" 19646 " try {" 19647 " foo;" 19648 " return false;" 19649 " } catch(e) {" 19650 " return true;" 19651 " }" 19652 "};" 19653 "var isDefaultIsolate = true;" 19654 "f()"); 19655 } 19656 19657 isolate1->Enter(); 19658 19659 { 19660 v8::Isolate::Scope iscope(isolate2); 19661 v8::HandleScope scope(isolate2); 19662 v8::Local<v8::Context> context = 19663 v8::Local<v8::Context>::New(isolate2, context2); 19664 v8::Context::Scope context_scope(context); 19665 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19666 } 19667 19668 { 19669 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19670 v8::Local<v8::Context> context = 19671 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 19672 v8::Context::Scope context_scope(context); 19673 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19674 } 19675 19676 { 19677 v8::Isolate::Scope iscope(isolate2); 19678 context2.Reset(); 19679 } 19680 19681 context1.Reset(); 19682 isolate1->Exit(); 19683 19684 isolate2->SetFatalErrorHandler(StoringErrorCallback); 19685 last_location = last_message = NULL; 19686 19687 isolate1->Dispose(); 19688 CHECK(!last_location); 19689 CHECK(!last_message); 19690 19691 isolate2->Dispose(); 19692 CHECK(!last_location); 19693 CHECK(!last_message); 19694 19695 // Check that default isolate still runs. 19696 { 19697 v8::HandleScope scope(CcTest::isolate()); 19698 v8::Local<v8::Context> context = 19699 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19700 v8::Context::Scope context_scope(context); 19701 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 19702 } 19703 } 19704 19705 19706 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 19707 v8::Isolate::Scope isolate_scope(isolate); 19708 v8::HandleScope scope(isolate); 19709 LocalContext context(isolate); 19710 i::ScopedVector<char> code(1024); 19711 i::SNPrintF(code, "function fib(n) {" 19712 " if (n <= 2) return 1;" 19713 " return fib(n-1) + fib(n-2);" 19714 "}" 19715 "fib(%d)", limit); 19716 Local<Value> value = CompileRun(code.start()); 19717 CHECK(value->IsNumber()); 19718 return static_cast<int>(value->NumberValue(context.local()).FromJust()); 19719 } 19720 19721 class IsolateThread : public v8::base::Thread { 19722 public: 19723 explicit IsolateThread(int fib_limit) 19724 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {} 19725 19726 void Run() { 19727 v8::Isolate::CreateParams create_params; 19728 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19729 v8::Isolate* isolate = v8::Isolate::New(create_params); 19730 result_ = CalcFibonacci(isolate, fib_limit_); 19731 isolate->Dispose(); 19732 } 19733 19734 int result() { return result_; } 19735 19736 private: 19737 int fib_limit_; 19738 int result_; 19739 }; 19740 19741 19742 TEST(MultipleIsolatesOnIndividualThreads) { 19743 IsolateThread thread1(21); 19744 IsolateThread thread2(12); 19745 19746 // Compute some fibonacci numbers on 3 threads in 3 isolates. 19747 thread1.Start(); 19748 thread2.Start(); 19749 19750 int result1 = CalcFibonacci(CcTest::isolate(), 21); 19751 int result2 = CalcFibonacci(CcTest::isolate(), 12); 19752 19753 thread1.Join(); 19754 thread2.Join(); 19755 19756 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 19757 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 19758 CHECK_EQ(result1, 10946); 19759 CHECK_EQ(result2, 144); 19760 CHECK_EQ(result1, thread1.result()); 19761 CHECK_EQ(result2, thread2.result()); 19762 } 19763 19764 19765 TEST(IsolateDifferentContexts) { 19766 v8::Isolate::CreateParams create_params; 19767 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19768 v8::Isolate* isolate = v8::Isolate::New(create_params); 19769 Local<v8::Context> context; 19770 { 19771 v8::Isolate::Scope isolate_scope(isolate); 19772 v8::HandleScope handle_scope(isolate); 19773 context = v8::Context::New(isolate); 19774 v8::Context::Scope context_scope(context); 19775 Local<Value> v = CompileRun("2"); 19776 CHECK(v->IsNumber()); 19777 CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust())); 19778 } 19779 { 19780 v8::Isolate::Scope isolate_scope(isolate); 19781 v8::HandleScope handle_scope(isolate); 19782 context = v8::Context::New(isolate); 19783 v8::Context::Scope context_scope(context); 19784 Local<Value> v = CompileRun("22"); 19785 CHECK(v->IsNumber()); 19786 CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust())); 19787 } 19788 isolate->Dispose(); 19789 } 19790 19791 class InitDefaultIsolateThread : public v8::base::Thread { 19792 public: 19793 enum TestCase { 19794 SetResourceConstraints, 19795 SetFatalHandler, 19796 SetCounterFunction, 19797 SetCreateHistogramFunction, 19798 SetAddHistogramSampleFunction 19799 }; 19800 19801 explicit InitDefaultIsolateThread(TestCase testCase) 19802 : Thread(Options("InitDefaultIsolateThread")), 19803 testCase_(testCase), 19804 result_(false) {} 19805 19806 void Run() { 19807 v8::Isolate::CreateParams create_params; 19808 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 19809 const intptr_t pageSizeMult = 19810 v8::internal::Page::kPageSize / v8::internal::MB; 19811 switch (testCase_) { 19812 case SetResourceConstraints: { 19813 create_params.constraints.set_max_semi_space_size(1 * pageSizeMult); 19814 create_params.constraints.set_max_old_space_size(4 * pageSizeMult); 19815 break; 19816 } 19817 default: 19818 break; 19819 } 19820 v8::Isolate* isolate = v8::Isolate::New(create_params); 19821 isolate->Enter(); 19822 switch (testCase_) { 19823 case SetResourceConstraints: 19824 // Already handled in pre-Isolate-creation block. 19825 break; 19826 19827 case SetFatalHandler: 19828 isolate->SetFatalErrorHandler(NULL); 19829 break; 19830 19831 case SetCounterFunction: 19832 CcTest::isolate()->SetCounterFunction(NULL); 19833 break; 19834 19835 case SetCreateHistogramFunction: 19836 CcTest::isolate()->SetCreateHistogramFunction(NULL); 19837 break; 19838 19839 case SetAddHistogramSampleFunction: 19840 CcTest::isolate()->SetAddHistogramSampleFunction(NULL); 19841 break; 19842 } 19843 isolate->Exit(); 19844 isolate->Dispose(); 19845 result_ = true; 19846 } 19847 19848 bool result() { return result_; } 19849 19850 private: 19851 TestCase testCase_; 19852 bool result_; 19853 }; 19854 19855 19856 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 19857 InitDefaultIsolateThread thread(testCase); 19858 thread.Start(); 19859 thread.Join(); 19860 CHECK_EQ(thread.result(), true); 19861 } 19862 19863 19864 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 19865 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 19866 } 19867 19868 19869 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 19870 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 19871 } 19872 19873 19874 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 19875 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 19876 } 19877 19878 19879 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 19880 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 19881 } 19882 19883 19884 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 19885 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 19886 } 19887 19888 19889 TEST(StringCheckMultipleContexts) { 19890 const char* code = 19891 "(function() { return \"a\".charAt(0); })()"; 19892 19893 { 19894 // Run the code twice in the first context to initialize the call IC. 19895 LocalContext context1; 19896 v8::HandleScope scope(context1->GetIsolate()); 19897 ExpectString(code, "a"); 19898 ExpectString(code, "a"); 19899 } 19900 19901 { 19902 // Change the String.prototype in the second context and check 19903 // that the right function gets called. 19904 LocalContext context2; 19905 v8::HandleScope scope(context2->GetIsolate()); 19906 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 19907 ExpectString(code, "not a"); 19908 } 19909 } 19910 19911 19912 TEST(NumberCheckMultipleContexts) { 19913 const char* code = 19914 "(function() { return (42).toString(); })()"; 19915 19916 { 19917 // Run the code twice in the first context to initialize the call IC. 19918 LocalContext context1; 19919 v8::HandleScope scope(context1->GetIsolate()); 19920 ExpectString(code, "42"); 19921 ExpectString(code, "42"); 19922 } 19923 19924 { 19925 // Change the Number.prototype in the second context and check 19926 // that the right function gets called. 19927 LocalContext context2; 19928 v8::HandleScope scope(context2->GetIsolate()); 19929 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 19930 ExpectString(code, "not 42"); 19931 } 19932 } 19933 19934 19935 TEST(BooleanCheckMultipleContexts) { 19936 const char* code = 19937 "(function() { return true.toString(); })()"; 19938 19939 { 19940 // Run the code twice in the first context to initialize the call IC. 19941 LocalContext context1; 19942 v8::HandleScope scope(context1->GetIsolate()); 19943 ExpectString(code, "true"); 19944 ExpectString(code, "true"); 19945 } 19946 19947 { 19948 // Change the Boolean.prototype in the second context and check 19949 // that the right function gets called. 19950 LocalContext context2; 19951 v8::HandleScope scope(context2->GetIsolate()); 19952 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 19953 ExpectString(code, ""); 19954 } 19955 } 19956 19957 19958 TEST(DontDeleteCellLoadIC) { 19959 const char* function_code = 19960 "function readCell() { while (true) { return cell; } }"; 19961 19962 { 19963 // Run the code twice in the first context to initialize the load 19964 // IC for a don't delete cell. 19965 LocalContext context1; 19966 v8::HandleScope scope(context1->GetIsolate()); 19967 CompileRun("var cell = \"first\";"); 19968 ExpectBoolean("delete cell", false); 19969 CompileRun(function_code); 19970 ExpectString("readCell()", "first"); 19971 ExpectString("readCell()", "first"); 19972 } 19973 19974 { 19975 // Use a deletable cell in the second context. 19976 LocalContext context2; 19977 v8::HandleScope scope(context2->GetIsolate()); 19978 CompileRun("cell = \"second\";"); 19979 CompileRun(function_code); 19980 ExpectString("readCell()", "second"); 19981 ExpectBoolean("delete cell", true); 19982 ExpectString("(function() {" 19983 " try {" 19984 " return readCell();" 19985 " } catch(e) {" 19986 " return e.toString();" 19987 " }" 19988 "})()", 19989 "ReferenceError: cell is not defined"); 19990 CompileRun("cell = \"new_second\";"); 19991 CcTest::heap()->CollectAllGarbage(); 19992 ExpectString("readCell()", "new_second"); 19993 ExpectString("readCell()", "new_second"); 19994 } 19995 } 19996 19997 19998 class Visitor42 : public v8::PersistentHandleVisitor { 19999 public: 20000 explicit Visitor42(v8::Persistent<v8::Object>* object) 20001 : counter_(0), object_(object) { } 20002 20003 virtual void VisitPersistentHandle(Persistent<Value>* value, 20004 uint16_t class_id) { 20005 if (class_id != 42) return; 20006 CHECK_EQ(42, value->WrapperClassId()); 20007 v8::Isolate* isolate = CcTest::isolate(); 20008 v8::HandleScope handle_scope(isolate); 20009 v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 20010 v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_); 20011 CHECK(handle->IsObject()); 20012 CHECK(Local<Object>::Cast(handle) 20013 ->Equals(isolate->GetCurrentContext(), object) 20014 .FromJust()); 20015 ++counter_; 20016 } 20017 20018 int counter_; 20019 v8::Persistent<v8::Object>* object_; 20020 }; 20021 20022 20023 TEST(PersistentHandleVisitor) { 20024 LocalContext context; 20025 v8::Isolate* isolate = context->GetIsolate(); 20026 v8::HandleScope scope(isolate); 20027 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 20028 CHECK_EQ(0, object.WrapperClassId()); 20029 object.SetWrapperClassId(42); 20030 CHECK_EQ(42, object.WrapperClassId()); 20031 20032 Visitor42 visitor(&object); 20033 isolate->VisitHandlesWithClassIds(&visitor); 20034 CHECK_EQ(1, visitor.counter_); 20035 20036 object.Reset(); 20037 } 20038 20039 20040 TEST(WrapperClassId) { 20041 LocalContext context; 20042 v8::Isolate* isolate = context->GetIsolate(); 20043 v8::HandleScope scope(isolate); 20044 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 20045 CHECK_EQ(0, object.WrapperClassId()); 20046 object.SetWrapperClassId(65535); 20047 CHECK_EQ(65535, object.WrapperClassId()); 20048 object.Reset(); 20049 } 20050 20051 20052 TEST(PersistentHandleInNewSpaceVisitor) { 20053 LocalContext context; 20054 v8::Isolate* isolate = context->GetIsolate(); 20055 v8::HandleScope scope(isolate); 20056 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate)); 20057 CHECK_EQ(0, object1.WrapperClassId()); 20058 object1.SetWrapperClassId(42); 20059 CHECK_EQ(42, object1.WrapperClassId()); 20060 20061 CcTest::heap()->CollectAllGarbage(); 20062 CcTest::heap()->CollectAllGarbage(); 20063 20064 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); 20065 CHECK_EQ(0, object2.WrapperClassId()); 20066 object2.SetWrapperClassId(42); 20067 CHECK_EQ(42, object2.WrapperClassId()); 20068 20069 Visitor42 visitor(&object2); 20070 isolate->VisitHandlesForPartialDependence(&visitor); 20071 CHECK_EQ(1, visitor.counter_); 20072 20073 object1.Reset(); 20074 object2.Reset(); 20075 } 20076 20077 20078 TEST(RegExp) { 20079 LocalContext context; 20080 v8::HandleScope scope(context->GetIsolate()); 20081 20082 v8::Local<v8::RegExp> re = 20083 v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone) 20084 .ToLocalChecked(); 20085 CHECK(re->IsRegExp()); 20086 CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust()); 20087 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 20088 20089 re = v8::RegExp::New(context.local(), v8_str("bar"), 20090 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 20091 v8::RegExp::kGlobal)) 20092 .ToLocalChecked(); 20093 CHECK(re->IsRegExp()); 20094 CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust()); 20095 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 20096 static_cast<int>(re->GetFlags())); 20097 20098 re = v8::RegExp::New(context.local(), v8_str("baz"), 20099 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 20100 v8::RegExp::kMultiline)) 20101 .ToLocalChecked(); 20102 CHECK(re->IsRegExp()); 20103 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust()); 20104 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 20105 static_cast<int>(re->GetFlags())); 20106 20107 re = v8::RegExp::New(context.local(), v8_str("baz"), 20108 static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode | 20109 v8::RegExp::kSticky)) 20110 .ToLocalChecked(); 20111 CHECK(re->IsRegExp()); 20112 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust()); 20113 CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky, 20114 static_cast<int>(re->GetFlags())); 20115 20116 re = CompileRun("/quux/").As<v8::RegExp>(); 20117 CHECK(re->IsRegExp()); 20118 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust()); 20119 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 20120 20121 re = CompileRun("/quux/gm").As<v8::RegExp>(); 20122 CHECK(re->IsRegExp()); 20123 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust()); 20124 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 20125 static_cast<int>(re->GetFlags())); 20126 20127 // Override the RegExp constructor and check the API constructor 20128 // still works. 20129 CompileRun("RegExp = function() {}"); 20130 20131 re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone) 20132 .ToLocalChecked(); 20133 CHECK(re->IsRegExp()); 20134 CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust()); 20135 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 20136 20137 re = v8::RegExp::New(context.local(), v8_str("foobarbaz"), 20138 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 20139 v8::RegExp::kMultiline)) 20140 .ToLocalChecked(); 20141 CHECK(re->IsRegExp()); 20142 CHECK( 20143 re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust()); 20144 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 20145 static_cast<int>(re->GetFlags())); 20146 20147 CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust()); 20148 ExpectTrue("re.test('FoobarbaZ')"); 20149 20150 // RegExps are objects on which you can set properties. 20151 re->Set(context.local(), v8_str("property"), 20152 v8::Integer::New(context->GetIsolate(), 32)) 20153 .FromJust(); 20154 v8::Local<v8::Value> value(CompileRun("re.property")); 20155 CHECK_EQ(32, value->Int32Value(context.local()).FromJust()); 20156 20157 v8::TryCatch try_catch(context->GetIsolate()); 20158 CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone) 20159 .IsEmpty()); 20160 CHECK(try_catch.HasCaught()); 20161 CHECK(context->Global() 20162 ->Set(context.local(), v8_str("ex"), try_catch.Exception()) 20163 .FromJust()); 20164 ExpectTrue("ex instanceof SyntaxError"); 20165 } 20166 20167 20168 THREADED_TEST(Equals) { 20169 LocalContext localContext; 20170 v8::HandleScope handleScope(localContext->GetIsolate()); 20171 20172 v8::Local<v8::Object> globalProxy = localContext->Global(); 20173 v8::Local<Value> global = globalProxy->GetPrototype(); 20174 20175 CHECK(global->StrictEquals(global)); 20176 CHECK(!global->StrictEquals(globalProxy)); 20177 CHECK(!globalProxy->StrictEquals(global)); 20178 CHECK(globalProxy->StrictEquals(globalProxy)); 20179 20180 CHECK(global->Equals(localContext.local(), global).FromJust()); 20181 CHECK(!global->Equals(localContext.local(), globalProxy).FromJust()); 20182 CHECK(!globalProxy->Equals(localContext.local(), global).FromJust()); 20183 CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust()); 20184 } 20185 20186 20187 static void Getter(v8::Local<v8::Name> property, 20188 const v8::PropertyCallbackInfo<v8::Value>& info) { 20189 info.GetReturnValue().Set(v8_str("42!")); 20190 } 20191 20192 20193 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 20194 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate()); 20195 result->Set(info.GetIsolate()->GetCurrentContext(), 0, 20196 v8_str("universalAnswer")) 20197 .FromJust(); 20198 info.GetReturnValue().Set(result); 20199 } 20200 20201 20202 TEST(NamedEnumeratorAndForIn) { 20203 LocalContext context; 20204 v8::Isolate* isolate = context->GetIsolate(); 20205 v8::HandleScope handle_scope(isolate); 20206 v8::Context::Scope context_scope(context.local()); 20207 20208 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate); 20209 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL, 20210 NULL, Enumerator)); 20211 CHECK(context->Global() 20212 ->Set(context.local(), v8_str("o"), 20213 tmpl->NewInstance(context.local()).ToLocalChecked()) 20214 .FromJust()); 20215 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast( 20216 CompileRun("var result = []; for (var k in o) result.push(k); result")); 20217 CHECK_EQ(1u, result->Length()); 20218 CHECK(v8_str("universalAnswer") 20219 ->Equals(context.local(), 20220 result->Get(context.local(), 0).ToLocalChecked()) 20221 .FromJust()); 20222 } 20223 20224 20225 TEST(DefinePropertyPostDetach) { 20226 LocalContext context; 20227 v8::HandleScope scope(context->GetIsolate()); 20228 v8::Local<v8::Object> proxy = context->Global(); 20229 v8::Local<v8::Function> define_property = 20230 CompileRun( 20231 "(function() {" 20232 " Object.defineProperty(" 20233 " this," 20234 " 1," 20235 " { configurable: true, enumerable: true, value: 3 });" 20236 "})") 20237 .As<Function>(); 20238 context->DetachGlobal(); 20239 CHECK(define_property->Call(context.local(), proxy, 0, NULL).IsEmpty()); 20240 } 20241 20242 20243 static void InstallContextId(v8::Local<Context> context, int id) { 20244 Context::Scope scope(context); 20245 CHECK(CompileRun("Object.prototype") 20246 .As<Object>() 20247 ->Set(context, v8_str("context_id"), 20248 v8::Integer::New(context->GetIsolate(), id)) 20249 .FromJust()); 20250 } 20251 20252 20253 static void CheckContextId(v8::Local<Object> object, int expected) { 20254 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 20255 CHECK_EQ(expected, object->Get(context, v8_str("context_id")) 20256 .ToLocalChecked() 20257 ->Int32Value(context) 20258 .FromJust()); 20259 } 20260 20261 20262 THREADED_TEST(CreationContext) { 20263 v8::Isolate* isolate = CcTest::isolate(); 20264 HandleScope handle_scope(isolate); 20265 Local<Context> context1 = Context::New(isolate); 20266 InstallContextId(context1, 1); 20267 Local<Context> context2 = Context::New(isolate); 20268 InstallContextId(context2, 2); 20269 Local<Context> context3 = Context::New(isolate); 20270 InstallContextId(context3, 3); 20271 20272 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate); 20273 20274 Local<Object> object1; 20275 Local<Function> func1; 20276 { 20277 Context::Scope scope(context1); 20278 object1 = Object::New(isolate); 20279 func1 = tmpl->GetFunction(context1).ToLocalChecked(); 20280 } 20281 20282 Local<Object> object2; 20283 Local<Function> func2; 20284 { 20285 Context::Scope scope(context2); 20286 object2 = Object::New(isolate); 20287 func2 = tmpl->GetFunction(context2).ToLocalChecked(); 20288 } 20289 20290 Local<Object> instance1; 20291 Local<Object> instance2; 20292 20293 { 20294 Context::Scope scope(context3); 20295 instance1 = func1->NewInstance(context3).ToLocalChecked(); 20296 instance2 = func2->NewInstance(context3).ToLocalChecked(); 20297 } 20298 20299 { 20300 Local<Context> other_context = Context::New(isolate); 20301 Context::Scope scope(other_context); 20302 CHECK(object1->CreationContext() == context1); 20303 CheckContextId(object1, 1); 20304 CHECK(func1->CreationContext() == context1); 20305 CheckContextId(func1, 1); 20306 CHECK(instance1->CreationContext() == context1); 20307 CheckContextId(instance1, 1); 20308 CHECK(object2->CreationContext() == context2); 20309 CheckContextId(object2, 2); 20310 CHECK(func2->CreationContext() == context2); 20311 CheckContextId(func2, 2); 20312 CHECK(instance2->CreationContext() == context2); 20313 CheckContextId(instance2, 2); 20314 } 20315 20316 { 20317 Context::Scope scope(context1); 20318 CHECK(object1->CreationContext() == context1); 20319 CheckContextId(object1, 1); 20320 CHECK(func1->CreationContext() == context1); 20321 CheckContextId(func1, 1); 20322 CHECK(instance1->CreationContext() == context1); 20323 CheckContextId(instance1, 1); 20324 CHECK(object2->CreationContext() == context2); 20325 CheckContextId(object2, 2); 20326 CHECK(func2->CreationContext() == context2); 20327 CheckContextId(func2, 2); 20328 CHECK(instance2->CreationContext() == context2); 20329 CheckContextId(instance2, 2); 20330 } 20331 20332 { 20333 Context::Scope scope(context2); 20334 CHECK(object1->CreationContext() == context1); 20335 CheckContextId(object1, 1); 20336 CHECK(func1->CreationContext() == context1); 20337 CheckContextId(func1, 1); 20338 CHECK(instance1->CreationContext() == context1); 20339 CheckContextId(instance1, 1); 20340 CHECK(object2->CreationContext() == context2); 20341 CheckContextId(object2, 2); 20342 CHECK(func2->CreationContext() == context2); 20343 CheckContextId(func2, 2); 20344 CHECK(instance2->CreationContext() == context2); 20345 CheckContextId(instance2, 2); 20346 } 20347 } 20348 20349 20350 THREADED_TEST(CreationContextOfJsFunction) { 20351 HandleScope handle_scope(CcTest::isolate()); 20352 Local<Context> context = Context::New(CcTest::isolate()); 20353 InstallContextId(context, 1); 20354 20355 Local<Object> function; 20356 { 20357 Context::Scope scope(context); 20358 function = CompileRun("function foo() {}; foo").As<Object>(); 20359 } 20360 20361 Local<Context> other_context = Context::New(CcTest::isolate()); 20362 Context::Scope scope(other_context); 20363 CHECK(function->CreationContext() == context); 20364 CheckContextId(function, 1); 20365 } 20366 20367 20368 THREADED_TEST(CreationContextOfJsBoundFunction) { 20369 HandleScope handle_scope(CcTest::isolate()); 20370 Local<Context> context1 = Context::New(CcTest::isolate()); 20371 InstallContextId(context1, 1); 20372 Local<Context> context2 = Context::New(CcTest::isolate()); 20373 InstallContextId(context2, 2); 20374 20375 Local<Function> target_function; 20376 { 20377 Context::Scope scope(context1); 20378 target_function = CompileRun("function foo() {}; foo").As<Function>(); 20379 } 20380 20381 Local<Function> bound_function1, bound_function2; 20382 { 20383 Context::Scope scope(context2); 20384 CHECK(context2->Global() 20385 ->Set(context2, v8_str("foo"), target_function) 20386 .FromJust()); 20387 bound_function1 = CompileRun("foo.bind(1)").As<Function>(); 20388 bound_function2 = 20389 CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>(); 20390 } 20391 20392 Local<Context> other_context = Context::New(CcTest::isolate()); 20393 Context::Scope scope(other_context); 20394 CHECK(bound_function1->CreationContext() == context1); 20395 CheckContextId(bound_function1, 1); 20396 CHECK(bound_function2->CreationContext() == context1); 20397 CheckContextId(bound_function2, 1); 20398 } 20399 20400 20401 void HasOwnPropertyIndexedPropertyGetter( 20402 uint32_t index, 20403 const v8::PropertyCallbackInfo<v8::Value>& info) { 20404 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 20405 } 20406 20407 20408 void HasOwnPropertyNamedPropertyGetter( 20409 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) { 20410 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 20411 .FromJust()) { 20412 info.GetReturnValue().Set(v8_str("yes")); 20413 } 20414 } 20415 20416 20417 void HasOwnPropertyIndexedPropertyQuery( 20418 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 20419 if (index == 42) info.GetReturnValue().Set(1); 20420 } 20421 20422 20423 void HasOwnPropertyNamedPropertyQuery( 20424 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) { 20425 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 20426 .FromJust()) { 20427 info.GetReturnValue().Set(1); 20428 } 20429 } 20430 20431 20432 void HasOwnPropertyNamedPropertyQuery2( 20433 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) { 20434 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar")) 20435 .FromJust()) { 20436 info.GetReturnValue().Set(1); 20437 } 20438 } 20439 20440 20441 void HasOwnPropertyAccessorGetter( 20442 Local<String> property, 20443 const v8::PropertyCallbackInfo<v8::Value>& info) { 20444 info.GetReturnValue().Set(v8_str("yes")); 20445 } 20446 20447 20448 TEST(HasOwnProperty) { 20449 LocalContext env; 20450 v8::Isolate* isolate = env->GetIsolate(); 20451 v8::HandleScope scope(isolate); 20452 { // Check normal properties and defined getters. 20453 Local<Value> value = CompileRun( 20454 "function Foo() {" 20455 " this.foo = 11;" 20456 " this.__defineGetter__('baz', function() { return 1; });" 20457 "};" 20458 "function Bar() { " 20459 " this.bar = 13;" 20460 " this.__defineGetter__('bla', function() { return 2; });" 20461 "};" 20462 "Bar.prototype = new Foo();" 20463 "new Bar();"); 20464 CHECK(value->IsObject()); 20465 Local<Object> object = value->ToObject(env.local()).ToLocalChecked(); 20466 CHECK(object->Has(env.local(), v8_str("foo")).FromJust()); 20467 CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20468 CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 20469 CHECK(object->Has(env.local(), v8_str("baz")).FromJust()); 20470 CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust()); 20471 CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust()); 20472 } 20473 { // Check named getter interceptors. 20474 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20475 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 20476 HasOwnPropertyNamedPropertyGetter)); 20477 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20478 CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 20479 CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust()); 20480 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20481 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 20482 } 20483 { // Check indexed getter interceptors. 20484 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20485 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 20486 HasOwnPropertyIndexedPropertyGetter)); 20487 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20488 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 20489 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust()); 20490 CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust()); 20491 CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust()); 20492 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20493 } 20494 { // Check named query interceptors. 20495 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20496 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 20497 0, 0, HasOwnPropertyNamedPropertyQuery)); 20498 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20499 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20500 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 20501 } 20502 { // Check indexed query interceptors. 20503 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20504 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 20505 0, 0, HasOwnPropertyIndexedPropertyQuery)); 20506 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20507 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust()); 20508 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust()); 20509 CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust()); 20510 CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust()); 20511 } 20512 { // Check callbacks. 20513 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20514 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 20515 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20516 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20517 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 20518 } 20519 { // Check that query wins on disagreement. 20520 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20521 templ->SetHandler(v8::NamedPropertyHandlerConfiguration( 20522 HasOwnPropertyNamedPropertyGetter, 0, 20523 HasOwnPropertyNamedPropertyQuery2)); 20524 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 20525 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust()); 20526 CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust()); 20527 } 20528 } 20529 20530 20531 TEST(IndexedInterceptorWithStringProto) { 20532 v8::Isolate* isolate = CcTest::isolate(); 20533 v8::HandleScope scope(isolate); 20534 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20535 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( 20536 NULL, NULL, HasOwnPropertyIndexedPropertyQuery)); 20537 LocalContext context; 20538 CHECK(context->Global() 20539 ->Set(context.local(), v8_str("obj"), 20540 templ->NewInstance(context.local()).ToLocalChecked()) 20541 .FromJust()); 20542 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 20543 // These should be intercepted. 20544 CHECK(CompileRun("42 in obj")->BooleanValue(context.local()).FromJust()); 20545 CHECK(CompileRun("'42' in obj")->BooleanValue(context.local()).FromJust()); 20546 // These should fall through to the String prototype. 20547 CHECK(CompileRun("0 in obj")->BooleanValue(context.local()).FromJust()); 20548 CHECK(CompileRun("'0' in obj")->BooleanValue(context.local()).FromJust()); 20549 // And these should both fail. 20550 CHECK(!CompileRun("32 in obj")->BooleanValue(context.local()).FromJust()); 20551 CHECK(!CompileRun("'32' in obj")->BooleanValue(context.local()).FromJust()); 20552 } 20553 20554 20555 void CheckCodeGenerationAllowed() { 20556 Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 20557 Local<Value> result = CompileRun("eval('42')"); 20558 CHECK_EQ(42, result->Int32Value(context).FromJust()); 20559 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20560 CHECK_EQ(42, result->Int32Value(context).FromJust()); 20561 result = CompileRun("var f = new Function('return 42'); f()"); 20562 CHECK_EQ(42, result->Int32Value(context).FromJust()); 20563 } 20564 20565 20566 void CheckCodeGenerationDisallowed() { 20567 TryCatch try_catch(CcTest::isolate()); 20568 20569 Local<Value> result = CompileRun("eval('42')"); 20570 CHECK(result.IsEmpty()); 20571 CHECK(try_catch.HasCaught()); 20572 try_catch.Reset(); 20573 20574 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20575 CHECK(result.IsEmpty()); 20576 CHECK(try_catch.HasCaught()); 20577 try_catch.Reset(); 20578 20579 result = CompileRun("var f = new Function('return 42'); f()"); 20580 CHECK(result.IsEmpty()); 20581 CHECK(try_catch.HasCaught()); 20582 } 20583 20584 20585 bool CodeGenerationAllowed(Local<Context> context) { 20586 ApiTestFuzzer::Fuzz(); 20587 return true; 20588 } 20589 20590 20591 bool CodeGenerationDisallowed(Local<Context> context) { 20592 ApiTestFuzzer::Fuzz(); 20593 return false; 20594 } 20595 20596 20597 THREADED_TEST(AllowCodeGenFromStrings) { 20598 LocalContext context; 20599 v8::HandleScope scope(context->GetIsolate()); 20600 20601 // eval and the Function constructor allowed by default. 20602 CHECK(context->IsCodeGenerationFromStringsAllowed()); 20603 CheckCodeGenerationAllowed(); 20604 20605 // Disallow eval and the Function constructor. 20606 context->AllowCodeGenerationFromStrings(false); 20607 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20608 CheckCodeGenerationDisallowed(); 20609 20610 // Allow again. 20611 context->AllowCodeGenerationFromStrings(true); 20612 CheckCodeGenerationAllowed(); 20613 20614 // Disallow but setting a global callback that will allow the calls. 20615 context->AllowCodeGenerationFromStrings(false); 20616 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 20617 &CodeGenerationAllowed); 20618 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20619 CheckCodeGenerationAllowed(); 20620 20621 // Set a callback that disallows the code generation. 20622 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 20623 &CodeGenerationDisallowed); 20624 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20625 CheckCodeGenerationDisallowed(); 20626 } 20627 20628 20629 TEST(SetErrorMessageForCodeGenFromStrings) { 20630 LocalContext context; 20631 v8::HandleScope scope(context->GetIsolate()); 20632 TryCatch try_catch(context->GetIsolate()); 20633 20634 Local<String> message = v8_str("Message"); 20635 Local<String> expected_message = v8_str("Uncaught EvalError: Message"); 20636 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback( 20637 &CodeGenerationDisallowed); 20638 context->AllowCodeGenerationFromStrings(false); 20639 context->SetErrorMessageForCodeGenerationFromStrings(message); 20640 Local<Value> result = CompileRun("eval('42')"); 20641 CHECK(result.IsEmpty()); 20642 CHECK(try_catch.HasCaught()); 20643 Local<String> actual_message = try_catch.Message()->Get(); 20644 CHECK(expected_message->Equals(context.local(), actual_message).FromJust()); 20645 } 20646 20647 20648 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 20649 } 20650 20651 20652 THREADED_TEST(CallAPIFunctionOnNonObject) { 20653 LocalContext context; 20654 v8::Isolate* isolate = context->GetIsolate(); 20655 v8::HandleScope scope(isolate); 20656 Local<FunctionTemplate> templ = 20657 v8::FunctionTemplate::New(isolate, NonObjectThis); 20658 Local<Function> function = 20659 templ->GetFunction(context.local()).ToLocalChecked(); 20660 CHECK(context->Global() 20661 ->Set(context.local(), v8_str("f"), function) 20662 .FromJust()); 20663 TryCatch try_catch(isolate); 20664 CompileRun("f.call(2)"); 20665 } 20666 20667 20668 // Regression test for issue 1470. 20669 THREADED_TEST(ReadOnlyIndexedProperties) { 20670 v8::Isolate* isolate = CcTest::isolate(); 20671 v8::HandleScope scope(isolate); 20672 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20673 20674 LocalContext context; 20675 Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked(); 20676 CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust()); 20677 obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"), 20678 v8::ReadOnly) 20679 .FromJust(); 20680 obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust(); 20681 CHECK(v8_str("DONT_CHANGE") 20682 ->Equals(context.local(), 20683 obj->Get(context.local(), v8_str("1")).ToLocalChecked()) 20684 .FromJust()); 20685 obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"), 20686 v8::ReadOnly) 20687 .FromJust(); 20688 obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust(); 20689 CHECK(v8_str("DONT_CHANGE") 20690 ->Equals(context.local(), 20691 obj->Get(context.local(), v8_num(2)).ToLocalChecked()) 20692 .FromJust()); 20693 20694 // Test non-smi case. 20695 obj->DefineOwnProperty(context.local(), v8_str("2000000000"), 20696 v8_str("DONT_CHANGE"), v8::ReadOnly) 20697 .FromJust(); 20698 obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust(); 20699 CHECK(v8_str("DONT_CHANGE") 20700 ->Equals(context.local(), 20701 obj->Get(context.local(), v8_str("2000000000")) 20702 .ToLocalChecked()) 20703 .FromJust()); 20704 } 20705 20706 20707 static int CountLiveMapsInMapCache(i::Context* context) { 20708 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache()); 20709 int length = map_cache->length(); 20710 int count = 0; 20711 for (int i = 0; i < length; i++) { 20712 i::Object* value = map_cache->get(i); 20713 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++; 20714 } 20715 return count; 20716 } 20717 20718 20719 THREADED_TEST(Regress1516) { 20720 LocalContext context; 20721 v8::HandleScope scope(context->GetIsolate()); 20722 20723 // Object with 20 properties is not a common case, so it should be removed 20724 // from the cache after GC. 20725 { v8::HandleScope temp_scope(context->GetIsolate()); 20726 CompileRun( 20727 "({" 20728 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, " 20729 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, " 20730 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, " 20731 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, " 20732 "})"); 20733 } 20734 20735 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context()); 20736 CHECK_LE(1, elements); 20737 20738 // We have to abort incremental marking here to abandon black pages. 20739 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 20740 20741 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context())); 20742 } 20743 20744 20745 THREADED_TEST(Regress93759) { 20746 v8::Isolate* isolate = CcTest::isolate(); 20747 HandleScope scope(isolate); 20748 20749 // Template for object with security check. 20750 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate); 20751 no_proto_template->SetAccessCheckCallback(AccessAlwaysBlocked); 20752 20753 // Templates for objects with hidden prototypes and possibly security check. 20754 Local<FunctionTemplate> hidden_proto_template = 20755 v8::FunctionTemplate::New(isolate); 20756 hidden_proto_template->SetHiddenPrototype(true); 20757 20758 Local<FunctionTemplate> protected_hidden_proto_template = 20759 v8::FunctionTemplate::New(isolate); 20760 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallback( 20761 AccessAlwaysBlocked); 20762 protected_hidden_proto_template->SetHiddenPrototype(true); 20763 20764 // Context for "foreign" objects used in test. 20765 Local<Context> context = v8::Context::New(isolate); 20766 context->Enter(); 20767 20768 // Plain object, no security check. 20769 Local<Object> simple_object = Object::New(isolate); 20770 20771 // Object with explicit security check. 20772 Local<Object> protected_object = 20773 no_proto_template->NewInstance(context).ToLocalChecked(); 20774 20775 // JSGlobalProxy object, always have security check. 20776 Local<Object> proxy_object = context->Global(); 20777 20778 // Global object, the prototype of proxy_object. No security checks. 20779 Local<Object> global_object = 20780 proxy_object->GetPrototype()->ToObject(context).ToLocalChecked(); 20781 20782 // Hidden prototype without security check. 20783 Local<Object> hidden_prototype = hidden_proto_template->GetFunction(context) 20784 .ToLocalChecked() 20785 ->NewInstance(context) 20786 .ToLocalChecked(); 20787 Local<Object> object_with_hidden = 20788 Object::New(isolate); 20789 object_with_hidden->SetPrototype(context, hidden_prototype).FromJust(); 20790 20791 context->Exit(); 20792 20793 LocalContext context2; 20794 v8::Local<v8::Object> global = context2->Global(); 20795 20796 // Setup global variables. 20797 CHECK(global->Set(context2.local(), v8_str("simple"), simple_object) 20798 .FromJust()); 20799 CHECK(global->Set(context2.local(), v8_str("protected"), protected_object) 20800 .FromJust()); 20801 CHECK(global->Set(context2.local(), v8_str("global"), global_object) 20802 .FromJust()); 20803 CHECK( 20804 global->Set(context2.local(), v8_str("proxy"), proxy_object).FromJust()); 20805 CHECK(global->Set(context2.local(), v8_str("hidden"), object_with_hidden) 20806 .FromJust()); 20807 20808 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 20809 CHECK(result1->Equals(context2.local(), simple_object->GetPrototype()) 20810 .FromJust()); 20811 20812 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 20813 CHECK(result2->IsNull()); 20814 20815 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 20816 CHECK(result3->Equals(context2.local(), global_object->GetPrototype()) 20817 .FromJust()); 20818 20819 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 20820 CHECK(result4->IsNull()); 20821 20822 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 20823 CHECK(result5->Equals(context2.local(), object_with_hidden->GetPrototype() 20824 ->ToObject(context2.local()) 20825 .ToLocalChecked() 20826 ->GetPrototype()) 20827 .FromJust()); 20828 } 20829 20830 20831 static void TestReceiver(Local<Value> expected_result, 20832 Local<Value> expected_receiver, 20833 const char* code) { 20834 Local<Value> result = CompileRun(code); 20835 Local<Context> context = CcTest::isolate()->GetCurrentContext(); 20836 CHECK(result->IsObject()); 20837 CHECK(expected_receiver 20838 ->Equals(context, 20839 result.As<v8::Object>()->Get(context, 1).ToLocalChecked()) 20840 .FromJust()); 20841 CHECK(expected_result 20842 ->Equals(context, 20843 result.As<v8::Object>()->Get(context, 0).ToLocalChecked()) 20844 .FromJust()); 20845 } 20846 20847 20848 THREADED_TEST(ForeignFunctionReceiver) { 20849 v8::Isolate* isolate = CcTest::isolate(); 20850 HandleScope scope(isolate); 20851 20852 // Create two contexts with different "id" properties ('i' and 'o'). 20853 // Call a function both from its own context and from a the foreign 20854 // context, and see what "this" is bound to (returning both "this" 20855 // and "this.id" for comparison). 20856 20857 Local<Context> foreign_context = v8::Context::New(isolate); 20858 foreign_context->Enter(); 20859 Local<Value> foreign_function = 20860 CompileRun("function func() { return { 0: this.id, " 20861 " 1: this, " 20862 " toString: function() { " 20863 " return this[0];" 20864 " }" 20865 " };" 20866 "}" 20867 "var id = 'i';" 20868 "func;"); 20869 CHECK(foreign_function->IsFunction()); 20870 foreign_context->Exit(); 20871 20872 LocalContext context; 20873 20874 Local<String> password = v8_str("Password"); 20875 // Don't get hit by security checks when accessing foreign_context's 20876 // global receiver (aka. global proxy). 20877 context->SetSecurityToken(password); 20878 foreign_context->SetSecurityToken(password); 20879 20880 Local<String> i = v8_str("i"); 20881 Local<String> o = v8_str("o"); 20882 Local<String> id = v8_str("id"); 20883 20884 CompileRun("function ownfunc() { return { 0: this.id, " 20885 " 1: this, " 20886 " toString: function() { " 20887 " return this[0];" 20888 " }" 20889 " };" 20890 "}" 20891 "var id = 'o';" 20892 "ownfunc"); 20893 CHECK(context->Global() 20894 ->Set(context.local(), v8_str("func"), foreign_function) 20895 .FromJust()); 20896 20897 // Sanity check the contexts. 20898 CHECK( 20899 i->Equals( 20900 context.local(), 20901 foreign_context->Global()->Get(context.local(), id).ToLocalChecked()) 20902 .FromJust()); 20903 CHECK(o->Equals(context.local(), 20904 context->Global()->Get(context.local(), id).ToLocalChecked()) 20905 .FromJust()); 20906 20907 // Checking local function's receiver. 20908 // Calling function using its call/apply methods. 20909 TestReceiver(o, context->Global(), "ownfunc.call()"); 20910 TestReceiver(o, context->Global(), "ownfunc.apply()"); 20911 // Making calls through built-in functions. 20912 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 20913 CHECK( 20914 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")) 20915 .FromJust()); 20916 CHECK( 20917 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")) 20918 .FromJust()); 20919 CHECK( 20920 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")) 20921 .FromJust()); 20922 // Calling with environment record as base. 20923 TestReceiver(o, context->Global(), "ownfunc()"); 20924 // Calling with no base. 20925 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 20926 20927 // Checking foreign function return value. 20928 // Calling function using its call/apply methods. 20929 TestReceiver(i, foreign_context->Global(), "func.call()"); 20930 TestReceiver(i, foreign_context->Global(), "func.apply()"); 20931 // Calling function using another context's call/apply methods. 20932 TestReceiver(i, foreign_context->Global(), 20933 "Function.prototype.call.call(func)"); 20934 TestReceiver(i, foreign_context->Global(), 20935 "Function.prototype.call.apply(func)"); 20936 TestReceiver(i, foreign_context->Global(), 20937 "Function.prototype.apply.call(func)"); 20938 TestReceiver(i, foreign_context->Global(), 20939 "Function.prototype.apply.apply(func)"); 20940 // Making calls through built-in functions. 20941 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 20942 // ToString(func()) is func()[0], i.e., the returned this.id. 20943 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]")) 20944 .FromJust()); 20945 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]")) 20946 .FromJust()); 20947 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]")) 20948 .FromJust()); 20949 20950 // Calling with environment record as base. 20951 TestReceiver(i, foreign_context->Global(), "func()"); 20952 // Calling with no base. 20953 TestReceiver(i, foreign_context->Global(), "(1,func)()"); 20954 } 20955 20956 20957 uint8_t callback_fired = 0; 20958 uint8_t before_call_entered_callback_count1 = 0; 20959 uint8_t before_call_entered_callback_count2 = 0; 20960 20961 20962 void CallCompletedCallback1(v8::Isolate*) { 20963 v8::base::OS::Print("Firing callback 1.\n"); 20964 callback_fired ^= 1; // Toggle first bit. 20965 } 20966 20967 20968 void CallCompletedCallback2(v8::Isolate*) { 20969 v8::base::OS::Print("Firing callback 2.\n"); 20970 callback_fired ^= 2; // Toggle second bit. 20971 } 20972 20973 20974 void BeforeCallEnteredCallback1(v8::Isolate*) { 20975 v8::base::OS::Print("Firing before call entered callback 1.\n"); 20976 before_call_entered_callback_count1++; 20977 } 20978 20979 20980 void BeforeCallEnteredCallback2(v8::Isolate*) { 20981 v8::base::OS::Print("Firing before call entered callback 2.\n"); 20982 before_call_entered_callback_count2++; 20983 } 20984 20985 20986 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 20987 int32_t level = 20988 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust(); 20989 if (level < 3) { 20990 level++; 20991 v8::base::OS::Print("Entering recursion level %d.\n", level); 20992 char script[64]; 20993 i::Vector<char> script_vector(script, sizeof(script)); 20994 i::SNPrintF(script_vector, "recursion(%d)", level); 20995 CompileRun(script_vector.start()); 20996 v8::base::OS::Print("Leaving recursion level %d.\n", level); 20997 CHECK_EQ(0, callback_fired); 20998 } else { 20999 v8::base::OS::Print("Recursion ends.\n"); 21000 CHECK_EQ(0, callback_fired); 21001 } 21002 } 21003 21004 21005 TEST(CallCompletedCallback) { 21006 LocalContext env; 21007 v8::HandleScope scope(env->GetIsolate()); 21008 v8::Local<v8::FunctionTemplate> recursive_runtime = 21009 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall); 21010 env->Global() 21011 ->Set(env.local(), v8_str("recursion"), 21012 recursive_runtime->GetFunction(env.local()).ToLocalChecked()) 21013 .FromJust(); 21014 // Adding the same callback a second time has no effect. 21015 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 21016 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 21017 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); 21018 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1); 21019 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2); 21020 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1); 21021 v8::base::OS::Print("--- Script (1) ---\n"); 21022 callback_fired = 0; 21023 before_call_entered_callback_count1 = 0; 21024 before_call_entered_callback_count2 = 0; 21025 Local<Script> script = 21026 v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked(); 21027 script->Run(env.local()).ToLocalChecked(); 21028 CHECK_EQ(3, callback_fired); 21029 CHECK_EQ(4, before_call_entered_callback_count1); 21030 CHECK_EQ(4, before_call_entered_callback_count2); 21031 21032 v8::base::OS::Print("\n--- Script (2) ---\n"); 21033 callback_fired = 0; 21034 before_call_entered_callback_count1 = 0; 21035 before_call_entered_callback_count2 = 0; 21036 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); 21037 env->GetIsolate()->RemoveBeforeCallEnteredCallback( 21038 BeforeCallEnteredCallback1); 21039 script->Run(env.local()).ToLocalChecked(); 21040 CHECK_EQ(2, callback_fired); 21041 CHECK_EQ(0, before_call_entered_callback_count1); 21042 CHECK_EQ(4, before_call_entered_callback_count2); 21043 21044 v8::base::OS::Print("\n--- Function ---\n"); 21045 callback_fired = 0; 21046 before_call_entered_callback_count1 = 0; 21047 before_call_entered_callback_count2 = 0; 21048 Local<Function> recursive_function = Local<Function>::Cast( 21049 env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked()); 21050 v8::Local<Value> args[] = {v8_num(0)}; 21051 recursive_function->Call(env.local(), env->Global(), 1, args) 21052 .ToLocalChecked(); 21053 CHECK_EQ(2, callback_fired); 21054 CHECK_EQ(0, before_call_entered_callback_count1); 21055 CHECK_EQ(4, before_call_entered_callback_count2); 21056 } 21057 21058 21059 void CallCompletedCallbackNoException(v8::Isolate*) { 21060 v8::HandleScope scope(CcTest::isolate()); 21061 CompileRun("1+1;"); 21062 } 21063 21064 21065 void CallCompletedCallbackException(v8::Isolate*) { 21066 v8::HandleScope scope(CcTest::isolate()); 21067 CompileRun("throw 'second exception';"); 21068 } 21069 21070 21071 TEST(CallCompletedCallbackOneException) { 21072 LocalContext env; 21073 v8::HandleScope scope(env->GetIsolate()); 21074 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException); 21075 CompileRun("throw 'exception';"); 21076 } 21077 21078 21079 TEST(CallCompletedCallbackTwoExceptions) { 21080 LocalContext env; 21081 v8::HandleScope scope(env->GetIsolate()); 21082 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException); 21083 CompileRun("throw 'first exception';"); 21084 } 21085 21086 21087 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) { 21088 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate())); 21089 v8::HandleScope scope(info.GetIsolate()); 21090 v8::MicrotasksScope microtasks(info.GetIsolate(), 21091 v8::MicrotasksScope::kDoNotRunMicrotasks); 21092 CompileRun("ext1Calls++;"); 21093 } 21094 21095 21096 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) { 21097 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate())); 21098 v8::HandleScope scope(info.GetIsolate()); 21099 v8::MicrotasksScope microtasks(info.GetIsolate(), 21100 v8::MicrotasksScope::kDoNotRunMicrotasks); 21101 CompileRun("ext2Calls++;"); 21102 } 21103 21104 21105 void* g_passed_to_three = NULL; 21106 21107 21108 static void MicrotaskThree(void* data) { 21109 g_passed_to_three = data; 21110 } 21111 21112 21113 TEST(EnqueueMicrotask) { 21114 LocalContext env; 21115 v8::HandleScope scope(env->GetIsolate()); 21116 CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate())); 21117 CompileRun( 21118 "var ext1Calls = 0;" 21119 "var ext2Calls = 0;"); 21120 CompileRun("1+1;"); 21121 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21122 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21123 21124 env->GetIsolate()->EnqueueMicrotask( 21125 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21126 CompileRun("1+1;"); 21127 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21128 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21129 21130 env->GetIsolate()->EnqueueMicrotask( 21131 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21132 env->GetIsolate()->EnqueueMicrotask( 21133 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21134 CompileRun("1+1;"); 21135 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21136 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21137 21138 env->GetIsolate()->EnqueueMicrotask( 21139 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21140 CompileRun("1+1;"); 21141 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21142 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21143 21144 CompileRun("1+1;"); 21145 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21146 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21147 21148 g_passed_to_three = NULL; 21149 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree); 21150 CompileRun("1+1;"); 21151 CHECK(!g_passed_to_three); 21152 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21153 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21154 21155 int dummy; 21156 env->GetIsolate()->EnqueueMicrotask( 21157 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21158 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy); 21159 env->GetIsolate()->EnqueueMicrotask( 21160 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21161 CompileRun("1+1;"); 21162 CHECK_EQ(&dummy, g_passed_to_three); 21163 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21164 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21165 g_passed_to_three = NULL; 21166 } 21167 21168 21169 static void MicrotaskExceptionOne( 21170 const v8::FunctionCallbackInfo<Value>& info) { 21171 v8::HandleScope scope(info.GetIsolate()); 21172 CompileRun("exception1Calls++;"); 21173 info.GetIsolate()->ThrowException( 21174 v8::Exception::Error(v8_str("first"))); 21175 } 21176 21177 21178 static void MicrotaskExceptionTwo( 21179 const v8::FunctionCallbackInfo<Value>& info) { 21180 v8::HandleScope scope(info.GetIsolate()); 21181 CompileRun("exception2Calls++;"); 21182 info.GetIsolate()->ThrowException( 21183 v8::Exception::Error(v8_str("second"))); 21184 } 21185 21186 21187 TEST(RunMicrotasksIgnoresThrownExceptions) { 21188 LocalContext env; 21189 v8::Isolate* isolate = env->GetIsolate(); 21190 v8::HandleScope scope(isolate); 21191 CompileRun( 21192 "var exception1Calls = 0;" 21193 "var exception2Calls = 0;"); 21194 isolate->EnqueueMicrotask( 21195 Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked()); 21196 isolate->EnqueueMicrotask( 21197 Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked()); 21198 TryCatch try_catch(isolate); 21199 CompileRun("1+1;"); 21200 CHECK(!try_catch.HasCaught()); 21201 CHECK_EQ(1, 21202 CompileRun("exception1Calls")->Int32Value(env.local()).FromJust()); 21203 CHECK_EQ(1, 21204 CompileRun("exception2Calls")->Int32Value(env.local()).FromJust()); 21205 } 21206 21207 21208 uint8_t microtasks_completed_callback_count = 0; 21209 21210 21211 static void MicrotasksCompletedCallback(v8::Isolate* isolate) { 21212 ++microtasks_completed_callback_count; 21213 } 21214 21215 21216 TEST(SetAutorunMicrotasks) { 21217 LocalContext env; 21218 v8::HandleScope scope(env->GetIsolate()); 21219 env->GetIsolate()->AddMicrotasksCompletedCallback( 21220 &MicrotasksCompletedCallback); 21221 CompileRun( 21222 "var ext1Calls = 0;" 21223 "var ext2Calls = 0;"); 21224 CompileRun("1+1;"); 21225 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21226 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21227 CHECK_EQ(0u, microtasks_completed_callback_count); 21228 21229 env->GetIsolate()->EnqueueMicrotask( 21230 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21231 CompileRun("1+1;"); 21232 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21233 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21234 CHECK_EQ(1u, microtasks_completed_callback_count); 21235 21236 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); 21237 env->GetIsolate()->EnqueueMicrotask( 21238 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21239 env->GetIsolate()->EnqueueMicrotask( 21240 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21241 CompileRun("1+1;"); 21242 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21243 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21244 CHECK_EQ(1u, microtasks_completed_callback_count); 21245 21246 env->GetIsolate()->RunMicrotasks(); 21247 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21248 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21249 CHECK_EQ(2u, microtasks_completed_callback_count); 21250 21251 env->GetIsolate()->EnqueueMicrotask( 21252 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21253 CompileRun("1+1;"); 21254 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21255 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21256 CHECK_EQ(2u, microtasks_completed_callback_count); 21257 21258 env->GetIsolate()->RunMicrotasks(); 21259 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21260 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21261 CHECK_EQ(3u, microtasks_completed_callback_count); 21262 21263 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto); 21264 env->GetIsolate()->EnqueueMicrotask( 21265 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21266 CompileRun("1+1;"); 21267 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21268 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21269 CHECK_EQ(4u, microtasks_completed_callback_count); 21270 21271 env->GetIsolate()->EnqueueMicrotask( 21272 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21273 { 21274 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate()); 21275 CompileRun("1+1;"); 21276 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21277 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21278 CHECK_EQ(4u, microtasks_completed_callback_count); 21279 } 21280 21281 CompileRun("1+1;"); 21282 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21283 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21284 CHECK_EQ(5u, microtasks_completed_callback_count); 21285 21286 env->GetIsolate()->RemoveMicrotasksCompletedCallback( 21287 &MicrotasksCompletedCallback); 21288 env->GetIsolate()->EnqueueMicrotask( 21289 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21290 CompileRun("1+1;"); 21291 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21292 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21293 CHECK_EQ(5u, microtasks_completed_callback_count); 21294 } 21295 21296 21297 TEST(RunMicrotasksWithoutEnteringContext) { 21298 v8::Isolate* isolate = CcTest::isolate(); 21299 HandleScope handle_scope(isolate); 21300 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); 21301 Local<Context> context = Context::New(isolate); 21302 { 21303 Context::Scope context_scope(context); 21304 CompileRun("var ext1Calls = 0;"); 21305 isolate->EnqueueMicrotask( 21306 Function::New(context, MicrotaskOne).ToLocalChecked()); 21307 } 21308 isolate->RunMicrotasks(); 21309 { 21310 Context::Scope context_scope(context); 21311 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust()); 21312 } 21313 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto); 21314 } 21315 21316 21317 TEST(ScopedMicrotasks) { 21318 LocalContext env; 21319 v8::HandleScope handles(env->GetIsolate()); 21320 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); 21321 { 21322 v8::MicrotasksScope scope1(env->GetIsolate(), 21323 v8::MicrotasksScope::kDoNotRunMicrotasks); 21324 env->GetIsolate()->EnqueueMicrotask( 21325 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21326 CompileRun( 21327 "var ext1Calls = 0;" 21328 "var ext2Calls = 0;"); 21329 CompileRun("1+1;"); 21330 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21331 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21332 { 21333 v8::MicrotasksScope scope2(env->GetIsolate(), 21334 v8::MicrotasksScope::kRunMicrotasks); 21335 CompileRun("1+1;"); 21336 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21337 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21338 { 21339 v8::MicrotasksScope scope3(env->GetIsolate(), 21340 v8::MicrotasksScope::kRunMicrotasks); 21341 CompileRun("1+1;"); 21342 CHECK_EQ(0, 21343 CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21344 CHECK_EQ(0, 21345 CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21346 } 21347 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21348 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21349 } 21350 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21351 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21352 env->GetIsolate()->EnqueueMicrotask( 21353 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21354 } 21355 21356 { 21357 v8::MicrotasksScope scope(env->GetIsolate(), 21358 v8::MicrotasksScope::kDoNotRunMicrotasks); 21359 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21360 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21361 } 21362 21363 { 21364 v8::MicrotasksScope scope1(env->GetIsolate(), 21365 v8::MicrotasksScope::kRunMicrotasks); 21366 CompileRun("1+1;"); 21367 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21368 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21369 { 21370 v8::MicrotasksScope scope2(env->GetIsolate(), 21371 v8::MicrotasksScope::kDoNotRunMicrotasks); 21372 } 21373 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21374 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21375 } 21376 21377 { 21378 v8::MicrotasksScope scope(env->GetIsolate(), 21379 v8::MicrotasksScope::kDoNotRunMicrotasks); 21380 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21381 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21382 env->GetIsolate()->EnqueueMicrotask( 21383 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21384 } 21385 21386 { 21387 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate()); 21388 { 21389 v8::MicrotasksScope scope2(env->GetIsolate(), 21390 v8::MicrotasksScope::kRunMicrotasks); 21391 } 21392 v8::MicrotasksScope scope3(env->GetIsolate(), 21393 v8::MicrotasksScope::kDoNotRunMicrotasks); 21394 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21395 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21396 } 21397 21398 { 21399 v8::MicrotasksScope scope1(env->GetIsolate(), 21400 v8::MicrotasksScope::kRunMicrotasks); 21401 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate()); 21402 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21403 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21404 } 21405 21406 { 21407 v8::MicrotasksScope scope(env->GetIsolate(), 21408 v8::MicrotasksScope::kDoNotRunMicrotasks); 21409 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21410 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21411 } 21412 21413 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate()); 21414 21415 { 21416 v8::MicrotasksScope scope(env->GetIsolate(), 21417 v8::MicrotasksScope::kDoNotRunMicrotasks); 21418 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21419 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21420 env->GetIsolate()->EnqueueMicrotask( 21421 Function::New(env.local(), MicrotaskTwo).ToLocalChecked()); 21422 } 21423 21424 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate()); 21425 21426 { 21427 v8::MicrotasksScope scope(env->GetIsolate(), 21428 v8::MicrotasksScope::kDoNotRunMicrotasks); 21429 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21430 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21431 } 21432 21433 env->GetIsolate()->EnqueueMicrotask( 21434 Function::New(env.local(), MicrotaskOne).ToLocalChecked()); 21435 { 21436 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate()); 21437 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate()); 21438 v8::MicrotasksScope scope2(env->GetIsolate(), 21439 v8::MicrotasksScope::kDoNotRunMicrotasks); 21440 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21441 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21442 } 21443 21444 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate()); 21445 21446 { 21447 v8::MicrotasksScope scope(env->GetIsolate(), 21448 v8::MicrotasksScope::kDoNotRunMicrotasks); 21449 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust()); 21450 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust()); 21451 } 21452 21453 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto); 21454 } 21455 21456 #ifdef ENABLE_DISASSEMBLER 21457 // FLAG_test_primary_stub_cache and FLAG_test_secondary_stub_cache are read 21458 // only when ENABLE_DISASSEMBLER is not defined. 21459 21460 namespace { 21461 21462 int probes_counter = 0; 21463 int misses_counter = 0; 21464 int updates_counter = 0; 21465 21466 int* LookupCounter(const char* name) { 21467 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 21468 return &probes_counter; 21469 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 21470 return &misses_counter; 21471 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 21472 return &updates_counter; 21473 } 21474 return NULL; 21475 } 21476 21477 const char* kMegamorphicTestProgram = 21478 "function CreateClass(name) {\n" 21479 " var src = \n" 21480 " ` function ${name}() {};` +\n" 21481 " ` ${name}.prototype.foo = function() {};` +\n" 21482 " ` ${name};\\n`;\n" 21483 " return (0, eval)(src);\n" 21484 "}\n" 21485 "function fooify(obj) { obj.foo(); };\n" 21486 "var objs = [];\n" 21487 "for (var i = 0; i < 6; i++) {\n" 21488 " var Class = CreateClass('Class' + i);\n" 21489 " var obj = new Class();\n" 21490 " objs.push(obj);\n" 21491 "}\n" 21492 "for (var i = 0; i < 10000; i++) {\n" 21493 " for (var obj of objs) {\n" 21494 " fooify(obj);\n" 21495 " }\n" 21496 "}\n"; 21497 21498 void StubCacheHelper(bool primary) { 21499 i::FLAG_native_code_counters = true; 21500 if (primary) { 21501 i::FLAG_test_primary_stub_cache = true; 21502 } else { 21503 i::FLAG_test_secondary_stub_cache = true; 21504 } 21505 i::FLAG_crankshaft = false; 21506 i::FLAG_turbo = false; 21507 v8::Isolate::CreateParams create_params; 21508 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 21509 create_params.counter_lookup_callback = LookupCounter; 21510 v8::Isolate* isolate = v8::Isolate::New(create_params); 21511 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 21512 21513 if (!i_isolate->snapshot_available()) { 21514 // The test is valid only for no-snapshot mode. 21515 v8::Isolate::Scope isolate_scope(isolate); 21516 LocalContext env(isolate); 21517 v8::HandleScope scope(isolate); 21518 21519 int initial_probes = probes_counter; 21520 int initial_misses = misses_counter; 21521 int initial_updates = updates_counter; 21522 CompileRun(kMegamorphicTestProgram); 21523 int probes = probes_counter - initial_probes; 21524 int misses = misses_counter - initial_misses; 21525 int updates = updates_counter - initial_updates; 21526 const int kClassesCount = 6; 21527 // Check that updates and misses counts are bounded. 21528 CHECK_LE(kClassesCount, updates); 21529 CHECK_LT(updates, kClassesCount * 3); 21530 CHECK_LE(1, misses); 21531 CHECK_LT(misses, kClassesCount * 2); 21532 // 2 is for PREMONOMORPHIC and MONOMORPHIC states, 21533 // 4 is for POLYMORPHIC states, 21534 // and all the others probes are for MEGAMORPHIC state. 21535 CHECK_EQ(10000 * kClassesCount - 2 - 4, probes); 21536 } 21537 isolate->Dispose(); 21538 } 21539 21540 } // namespace 21541 21542 UNINITIALIZED_TEST(PrimaryStubCache) { StubCacheHelper(true); } 21543 21544 UNINITIALIZED_TEST(SecondaryStubCache) { StubCacheHelper(false); } 21545 21546 #endif // ENABLE_DISASSEMBLER 21547 21548 #ifdef DEBUG 21549 static int cow_arrays_created_runtime = 0; 21550 21551 21552 static int* LookupCounterCOWArrays(const char* name) { 21553 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) { 21554 return &cow_arrays_created_runtime; 21555 } 21556 return NULL; 21557 } 21558 #endif 21559 21560 21561 TEST(CheckCOWArraysCreatedRuntimeCounter) { 21562 #ifdef DEBUG 21563 i::FLAG_native_code_counters = true; 21564 LocalContext env; 21565 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays); 21566 v8::HandleScope scope(env->GetIsolate()); 21567 int initial_cow_arrays = cow_arrays_created_runtime; 21568 CompileRun("var o = [1, 2, 3];"); 21569 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays); 21570 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};"); 21571 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays); 21572 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};"); 21573 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays); 21574 #endif 21575 } 21576 21577 21578 TEST(StaticGetters) { 21579 LocalContext context; 21580 i::Factory* factory = CcTest::i_isolate()->factory(); 21581 v8::Isolate* isolate = CcTest::isolate(); 21582 v8::HandleScope scope(isolate); 21583 i::Handle<i::Object> undefined_value = factory->undefined_value(); 21584 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 21585 i::Handle<i::Object> null_value = factory->null_value(); 21586 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 21587 i::Handle<i::Object> true_value = factory->true_value(); 21588 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 21589 i::Handle<i::Object> false_value = factory->false_value(); 21590 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 21591 } 21592 21593 21594 UNINITIALIZED_TEST(IsolateEmbedderData) { 21595 CcTest::DisableAutomaticDispose(); 21596 v8::Isolate::CreateParams create_params; 21597 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 21598 v8::Isolate* isolate = v8::Isolate::New(create_params); 21599 isolate->Enter(); 21600 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 21601 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21602 CHECK(!isolate->GetData(slot)); 21603 CHECK(!i_isolate->GetData(slot)); 21604 } 21605 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21606 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21607 isolate->SetData(slot, data); 21608 } 21609 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21610 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21611 CHECK_EQ(data, isolate->GetData(slot)); 21612 CHECK_EQ(data, i_isolate->GetData(slot)); 21613 } 21614 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21615 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21616 isolate->SetData(slot, data); 21617 } 21618 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21619 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21620 CHECK_EQ(data, isolate->GetData(slot)); 21621 CHECK_EQ(data, i_isolate->GetData(slot)); 21622 } 21623 isolate->Exit(); 21624 isolate->Dispose(); 21625 } 21626 21627 21628 TEST(StringEmpty) { 21629 LocalContext context; 21630 i::Factory* factory = CcTest::i_isolate()->factory(); 21631 v8::Isolate* isolate = CcTest::isolate(); 21632 v8::HandleScope scope(isolate); 21633 i::Handle<i::Object> empty_string = factory->empty_string(); 21634 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 21635 } 21636 21637 21638 static int instance_checked_getter_count = 0; 21639 static void InstanceCheckedGetter( 21640 Local<String> name, 21641 const v8::PropertyCallbackInfo<v8::Value>& info) { 21642 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 21643 .FromJust()); 21644 instance_checked_getter_count++; 21645 info.GetReturnValue().Set(v8_num(11)); 21646 } 21647 21648 21649 static int instance_checked_setter_count = 0; 21650 static void InstanceCheckedSetter(Local<String> name, 21651 Local<Value> value, 21652 const v8::PropertyCallbackInfo<void>& info) { 21653 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo")) 21654 .FromJust()); 21655 CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23)) 21656 .FromJust()); 21657 instance_checked_setter_count++; 21658 } 21659 21660 21661 static void CheckInstanceCheckedResult(int getters, int setters, 21662 bool expects_callbacks, 21663 TryCatch* try_catch) { 21664 if (expects_callbacks) { 21665 CHECK(!try_catch->HasCaught()); 21666 CHECK_EQ(getters, instance_checked_getter_count); 21667 CHECK_EQ(setters, instance_checked_setter_count); 21668 } else { 21669 CHECK(try_catch->HasCaught()); 21670 CHECK_EQ(0, instance_checked_getter_count); 21671 CHECK_EQ(0, instance_checked_setter_count); 21672 } 21673 try_catch->Reset(); 21674 } 21675 21676 21677 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 21678 instance_checked_getter_count = 0; 21679 instance_checked_setter_count = 0; 21680 TryCatch try_catch(CcTest::isolate()); 21681 21682 // Test path through generic runtime code. 21683 CompileRun("obj.foo"); 21684 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 21685 CompileRun("obj.foo = 23"); 21686 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 21687 21688 // Test path through generated LoadIC and StoredIC. 21689 CompileRun("function test_get(o) { o.foo; }" 21690 "test_get(obj);"); 21691 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 21692 CompileRun("test_get(obj);"); 21693 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 21694 CompileRun("test_get(obj);"); 21695 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 21696 CompileRun("function test_set(o) { o.foo = 23; }" 21697 "test_set(obj);"); 21698 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 21699 CompileRun("test_set(obj);"); 21700 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 21701 CompileRun("test_set(obj);"); 21702 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 21703 21704 // Test path through optimized code. 21705 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 21706 "test_get(obj);"); 21707 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 21708 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 21709 "test_set(obj);"); 21710 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 21711 21712 // Cleanup so that closures start out fresh in next check. 21713 CompileRun("%DeoptimizeFunction(test_get);" 21714 "%ClearFunctionTypeFeedback(test_get);" 21715 "%DeoptimizeFunction(test_set);" 21716 "%ClearFunctionTypeFeedback(test_set);"); 21717 } 21718 21719 21720 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 21721 v8::internal::FLAG_allow_natives_syntax = true; 21722 LocalContext context; 21723 v8::HandleScope scope(context->GetIsolate()); 21724 21725 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21726 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21727 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter, 21728 Local<Value>(), v8::DEFAULT, v8::None, 21729 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21730 CHECK(context->Global() 21731 ->Set(context.local(), v8_str("f"), 21732 templ->GetFunction(context.local()).ToLocalChecked()) 21733 .FromJust()); 21734 21735 printf("Testing positive ...\n"); 21736 CompileRun("var obj = new f();"); 21737 CHECK(templ->HasInstance( 21738 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21739 CheckInstanceCheckedAccessors(true); 21740 21741 printf("Testing negative ...\n"); 21742 CompileRun("var obj = {};" 21743 "obj.__proto__ = new f();"); 21744 CHECK(!templ->HasInstance( 21745 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21746 CheckInstanceCheckedAccessors(false); 21747 } 21748 21749 21750 static void EmptyInterceptorGetter( 21751 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {} 21752 21753 21754 static void EmptyInterceptorSetter( 21755 Local<String> name, Local<Value> value, 21756 const v8::PropertyCallbackInfo<v8::Value>& info) {} 21757 21758 21759 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 21760 v8::internal::FLAG_allow_natives_syntax = true; 21761 LocalContext context; 21762 v8::HandleScope scope(context->GetIsolate()); 21763 21764 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21765 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21766 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter, 21767 EmptyInterceptorSetter); 21768 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter, 21769 Local<Value>(), v8::DEFAULT, v8::None, 21770 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21771 CHECK(context->Global() 21772 ->Set(context.local(), v8_str("f"), 21773 templ->GetFunction(context.local()).ToLocalChecked()) 21774 .FromJust()); 21775 21776 printf("Testing positive ...\n"); 21777 CompileRun("var obj = new f();"); 21778 CHECK(templ->HasInstance( 21779 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21780 CheckInstanceCheckedAccessors(true); 21781 21782 printf("Testing negative ...\n"); 21783 CompileRun("var obj = {};" 21784 "obj.__proto__ = new f();"); 21785 CHECK(!templ->HasInstance( 21786 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21787 CheckInstanceCheckedAccessors(false); 21788 } 21789 21790 21791 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 21792 v8::internal::FLAG_allow_natives_syntax = true; 21793 LocalContext context; 21794 v8::HandleScope scope(context->GetIsolate()); 21795 21796 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21797 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 21798 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter, 21799 InstanceCheckedSetter, Local<Value>(), v8::DEFAULT, 21800 v8::None, 21801 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21802 CHECK(context->Global() 21803 ->Set(context.local(), v8_str("f"), 21804 templ->GetFunction(context.local()).ToLocalChecked()) 21805 .FromJust()); 21806 21807 printf("Testing positive ...\n"); 21808 CompileRun("var obj = new f();"); 21809 CHECK(templ->HasInstance( 21810 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21811 CheckInstanceCheckedAccessors(true); 21812 21813 printf("Testing negative ...\n"); 21814 CompileRun("var obj = {};" 21815 "obj.__proto__ = new f();"); 21816 CHECK(!templ->HasInstance( 21817 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21818 CheckInstanceCheckedAccessors(false); 21819 21820 printf("Testing positive with modified prototype chain ...\n"); 21821 CompileRun("var obj = new f();" 21822 "var pro = {};" 21823 "pro.__proto__ = obj.__proto__;" 21824 "obj.__proto__ = pro;"); 21825 CHECK(templ->HasInstance( 21826 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked())); 21827 CheckInstanceCheckedAccessors(true); 21828 } 21829 21830 21831 TEST(TryFinallyMessage) { 21832 LocalContext context; 21833 v8::HandleScope scope(context->GetIsolate()); 21834 { 21835 // Test that the original error message is not lost if there is a 21836 // recursive call into Javascript is done in the finally block, e.g. to 21837 // initialize an IC. (crbug.com/129171) 21838 TryCatch try_catch(context->GetIsolate()); 21839 const char* trigger_ic = 21840 "try { \n" 21841 " throw new Error('test'); \n" 21842 "} finally { \n" 21843 " var x = 0; \n" 21844 " x++; \n" // Trigger an IC initialization here. 21845 "} \n"; 21846 CompileRun(trigger_ic); 21847 CHECK(try_catch.HasCaught()); 21848 Local<Message> message = try_catch.Message(); 21849 CHECK(!message.IsEmpty()); 21850 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust()); 21851 } 21852 21853 { 21854 // Test that the original exception message is indeed overwritten if 21855 // a new error is thrown in the finally block. 21856 TryCatch try_catch(context->GetIsolate()); 21857 const char* throw_again = 21858 "try { \n" 21859 " throw new Error('test'); \n" 21860 "} finally { \n" 21861 " var x = 0; \n" 21862 " x++; \n" 21863 " throw new Error('again'); \n" // This is the new uncaught error. 21864 "} \n"; 21865 CompileRun(throw_again); 21866 CHECK(try_catch.HasCaught()); 21867 Local<Message> message = try_catch.Message(); 21868 CHECK(!message.IsEmpty()); 21869 CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust()); 21870 } 21871 } 21872 21873 21874 static void Helper137002(bool do_store, 21875 bool polymorphic, 21876 bool remove_accessor, 21877 bool interceptor) { 21878 LocalContext context; 21879 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate()); 21880 if (interceptor) { 21881 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor, 21882 FooSetInterceptor)); 21883 } else { 21884 templ->SetAccessor(v8_str("foo"), 21885 GetterWhichReturns42, 21886 SetterWhichSetsYOnThisTo23); 21887 } 21888 CHECK(context->Global() 21889 ->Set(context.local(), v8_str("obj"), 21890 templ->NewInstance(context.local()).ToLocalChecked()) 21891 .FromJust()); 21892 21893 // Turn monomorphic on slow object with native accessor, then turn 21894 // polymorphic, finally optimize to create negative lookup and fail. 21895 CompileRun(do_store ? 21896 "function f(x) { x.foo = void 0; }" : 21897 "function f(x) { return x.foo; }"); 21898 CompileRun("obj.y = void 0;"); 21899 if (!interceptor) { 21900 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 21901 } 21902 CompileRun("obj.__proto__ = null;" 21903 "f(obj); f(obj); f(obj);"); 21904 if (polymorphic) { 21905 CompileRun("f({});"); 21906 } 21907 CompileRun("obj.y = void 0;" 21908 "%OptimizeFunctionOnNextCall(f);"); 21909 if (remove_accessor) { 21910 CompileRun("delete obj.foo;"); 21911 } 21912 CompileRun("var result = f(obj);"); 21913 if (do_store) { 21914 CompileRun("result = obj.y;"); 21915 } 21916 if (remove_accessor && !interceptor) { 21917 CHECK(context->Global() 21918 ->Get(context.local(), v8_str("result")) 21919 .ToLocalChecked() 21920 ->IsUndefined()); 21921 } else { 21922 CHECK_EQ(do_store ? 23 : 42, context->Global() 21923 ->Get(context.local(), v8_str("result")) 21924 .ToLocalChecked() 21925 ->Int32Value(context.local()) 21926 .FromJust()); 21927 } 21928 } 21929 21930 21931 THREADED_TEST(Regress137002a) { 21932 i::FLAG_allow_natives_syntax = true; 21933 i::FLAG_compilation_cache = false; 21934 v8::HandleScope scope(CcTest::isolate()); 21935 for (int i = 0; i < 16; i++) { 21936 Helper137002(i & 8, i & 4, i & 2, i & 1); 21937 } 21938 } 21939 21940 21941 THREADED_TEST(Regress137002b) { 21942 i::FLAG_allow_natives_syntax = true; 21943 LocalContext context; 21944 v8::Isolate* isolate = context->GetIsolate(); 21945 v8::HandleScope scope(isolate); 21946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21947 templ->SetAccessor(v8_str("foo"), 21948 GetterWhichReturns42, 21949 SetterWhichSetsYOnThisTo23); 21950 CHECK(context->Global() 21951 ->Set(context.local(), v8_str("obj"), 21952 templ->NewInstance(context.local()).ToLocalChecked()) 21953 .FromJust()); 21954 21955 // Turn monomorphic on slow object with native accessor, then just 21956 // delete the property and fail. 21957 CompileRun("function load(x) { return x.foo; }" 21958 "function store(x) { x.foo = void 0; }" 21959 "function keyed_load(x, key) { return x[key]; }" 21960 // Second version of function has a different source (add void 0) 21961 // so that it does not share code with the first version. This 21962 // ensures that the ICs are monomorphic. 21963 "function load2(x) { void 0; return x.foo; }" 21964 "function store2(x) { void 0; x.foo = void 0; }" 21965 "function keyed_load2(x, key) { void 0; return x[key]; }" 21966 21967 "obj.y = void 0;" 21968 "obj.__proto__ = null;" 21969 "var subobj = {};" 21970 "subobj.y = void 0;" 21971 "subobj.__proto__ = obj;" 21972 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21973 21974 // Make the ICs monomorphic. 21975 "load(obj); load(obj);" 21976 "load2(subobj); load2(subobj);" 21977 "store(obj); store(obj);" 21978 "store2(subobj); store2(subobj);" 21979 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 21980 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 21981 21982 // Actually test the shiny new ICs and better not crash. This 21983 // serves as a regression test for issue 142088 as well. 21984 "load(obj);" 21985 "load2(subobj);" 21986 "store(obj);" 21987 "store2(subobj);" 21988 "keyed_load(obj, 'foo');" 21989 "keyed_load2(subobj, 'foo');" 21990 21991 // Delete the accessor. It better not be called any more now. 21992 "delete obj.foo;" 21993 "obj.y = void 0;" 21994 "subobj.y = void 0;" 21995 21996 "var load_result = load(obj);" 21997 "var load_result2 = load2(subobj);" 21998 "var keyed_load_result = keyed_load(obj, 'foo');" 21999 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 22000 "store(obj);" 22001 "store2(subobj);" 22002 "var y_from_obj = obj.y;" 22003 "var y_from_subobj = subobj.y;"); 22004 CHECK(context->Global() 22005 ->Get(context.local(), v8_str("load_result")) 22006 .ToLocalChecked() 22007 ->IsUndefined()); 22008 CHECK(context->Global() 22009 ->Get(context.local(), v8_str("load_result2")) 22010 .ToLocalChecked() 22011 ->IsUndefined()); 22012 CHECK(context->Global() 22013 ->Get(context.local(), v8_str("keyed_load_result")) 22014 .ToLocalChecked() 22015 ->IsUndefined()); 22016 CHECK(context->Global() 22017 ->Get(context.local(), v8_str("keyed_load_result2")) 22018 .ToLocalChecked() 22019 ->IsUndefined()); 22020 CHECK(context->Global() 22021 ->Get(context.local(), v8_str("y_from_obj")) 22022 .ToLocalChecked() 22023 ->IsUndefined()); 22024 CHECK(context->Global() 22025 ->Get(context.local(), v8_str("y_from_subobj")) 22026 .ToLocalChecked() 22027 ->IsUndefined()); 22028 } 22029 22030 22031 THREADED_TEST(Regress142088) { 22032 i::FLAG_allow_natives_syntax = true; 22033 LocalContext context; 22034 v8::Isolate* isolate = context->GetIsolate(); 22035 v8::HandleScope scope(isolate); 22036 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22037 templ->SetAccessor(v8_str("foo"), 22038 GetterWhichReturns42, 22039 SetterWhichSetsYOnThisTo23); 22040 CHECK(context->Global() 22041 ->Set(context.local(), v8_str("obj"), 22042 templ->NewInstance(context.local()).ToLocalChecked()) 22043 .FromJust()); 22044 22045 CompileRun("function load(x) { return x.foo; }" 22046 "var o = Object.create(obj);" 22047 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 22048 "load(o); load(o); load(o); load(o);"); 22049 } 22050 22051 22052 THREADED_TEST(Regress137496) { 22053 i::FLAG_expose_gc = true; 22054 LocalContext context; 22055 v8::HandleScope scope(context->GetIsolate()); 22056 22057 // Compile a try-finally clause where the finally block causes a GC 22058 // while there still is a message pending for external reporting. 22059 TryCatch try_catch(context->GetIsolate()); 22060 try_catch.SetVerbose(true); 22061 CompileRun("try { throw new Error(); } finally { gc(); }"); 22062 CHECK(try_catch.HasCaught()); 22063 } 22064 22065 22066 THREADED_TEST(Regress157124) { 22067 LocalContext context; 22068 v8::Isolate* isolate = context->GetIsolate(); 22069 v8::HandleScope scope(isolate); 22070 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22071 Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked(); 22072 obj->GetIdentityHash(); 22073 obj->DeletePrivate(context.local(), 22074 v8::Private::ForApi(isolate, v8_str("Bug"))) 22075 .FromJust(); 22076 } 22077 22078 22079 THREADED_TEST(Regress2535) { 22080 LocalContext context; 22081 v8::HandleScope scope(context->GetIsolate()); 22082 Local<Value> set_value = CompileRun("new Set();"); 22083 Local<Object> set_object(Local<Object>::Cast(set_value)); 22084 CHECK_EQ(0, set_object->InternalFieldCount()); 22085 Local<Value> map_value = CompileRun("new Map();"); 22086 Local<Object> map_object(Local<Object>::Cast(map_value)); 22087 CHECK_EQ(0, map_object->InternalFieldCount()); 22088 } 22089 22090 22091 THREADED_TEST(Regress2746) { 22092 LocalContext context; 22093 v8::Isolate* isolate = context->GetIsolate(); 22094 v8::HandleScope scope(isolate); 22095 Local<Object> obj = Object::New(isolate); 22096 Local<v8::Private> key = v8::Private::New(isolate, v8_str("key")); 22097 CHECK( 22098 obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust()); 22099 Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked(); 22100 CHECK(!value.IsEmpty()); 22101 CHECK(value->IsUndefined()); 22102 } 22103 22104 22105 THREADED_TEST(Regress260106) { 22106 LocalContext context; 22107 v8::Isolate* isolate = context->GetIsolate(); 22108 v8::HandleScope scope(isolate); 22109 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, 22110 DummyCallHandler); 22111 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 22112 Local<Function> function = 22113 templ->GetFunction(context.local()).ToLocalChecked(); 22114 CHECK(!function.IsEmpty()); 22115 CHECK(function->IsFunction()); 22116 } 22117 22118 THREADED_TEST(JSONParseObject) { 22119 LocalContext context; 22120 HandleScope scope(context->GetIsolate()); 22121 Local<Value> obj = 22122 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked(); 22123 Local<Object> global = context->Global(); 22124 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 22125 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 22126 } 22127 22128 THREADED_TEST(JSONParseNumber) { 22129 LocalContext context; 22130 HandleScope scope(context->GetIsolate()); 22131 Local<Value> obj = 22132 v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked(); 22133 Local<Object> global = context->Global(); 22134 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 22135 ExpectString("JSON.stringify(obj)", "42"); 22136 } 22137 22138 THREADED_TEST(JSONStringifyObject) { 22139 LocalContext context; 22140 HandleScope scope(context->GetIsolate()); 22141 Local<Value> value = 22142 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked(); 22143 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked(); 22144 Local<Object> global = context->Global(); 22145 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 22146 Local<String> json = 22147 v8::JSON::Stringify(context.local(), obj).ToLocalChecked(); 22148 v8::String::Utf8Value utf8(json); 22149 ExpectString("JSON.stringify(obj)", *utf8); 22150 } 22151 22152 THREADED_TEST(JSONStringifyObjectWithGap) { 22153 LocalContext context; 22154 HandleScope scope(context->GetIsolate()); 22155 Local<Value> value = 22156 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked(); 22157 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked(); 22158 Local<Object> global = context->Global(); 22159 global->Set(context.local(), v8_str("obj"), obj).FromJust(); 22160 Local<String> json = 22161 v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked(); 22162 v8::String::Utf8Value utf8(json); 22163 ExpectString("JSON.stringify(obj, null, '*')", *utf8); 22164 } 22165 22166 #if V8_OS_POSIX && !V8_OS_NACL 22167 class ThreadInterruptTest { 22168 public: 22169 ThreadInterruptTest() : sem_(0), sem_value_(0) { } 22170 ~ThreadInterruptTest() {} 22171 22172 void RunTest() { 22173 InterruptThread i_thread(this); 22174 i_thread.Start(); 22175 22176 sem_.Wait(); 22177 CHECK_EQ(kExpectedValue, sem_value_); 22178 } 22179 22180 private: 22181 static const int kExpectedValue = 1; 22182 22183 class InterruptThread : public v8::base::Thread { 22184 public: 22185 explicit InterruptThread(ThreadInterruptTest* test) 22186 : Thread(Options("InterruptThread")), test_(test) {} 22187 22188 virtual void Run() { 22189 struct sigaction action; 22190 22191 // Ensure that we'll enter waiting condition 22192 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 22193 22194 // Setup signal handler 22195 memset(&action, 0, sizeof(action)); 22196 action.sa_handler = SignalHandler; 22197 sigaction(SIGCHLD, &action, NULL); 22198 22199 // Send signal 22200 kill(getpid(), SIGCHLD); 22201 22202 // Ensure that if wait has returned because of error 22203 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 22204 22205 // Set value and signal semaphore 22206 test_->sem_value_ = 1; 22207 test_->sem_.Signal(); 22208 } 22209 22210 static void SignalHandler(int signal) { 22211 } 22212 22213 private: 22214 ThreadInterruptTest* test_; 22215 }; 22216 22217 v8::base::Semaphore sem_; 22218 volatile int sem_value_; 22219 }; 22220 22221 22222 THREADED_TEST(SemaphoreInterruption) { 22223 ThreadInterruptTest().RunTest(); 22224 } 22225 22226 22227 #endif // V8_OS_POSIX 22228 22229 22230 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 22231 CHECK(false); 22232 } 22233 22234 22235 TEST(JSONStringifyAccessCheck) { 22236 v8::V8::Initialize(); 22237 v8::Isolate* isolate = CcTest::isolate(); 22238 v8::HandleScope scope(isolate); 22239 22240 // Create an ObjectTemplate for global objects and install access 22241 // check callbacks that will block access. 22242 v8::Local<v8::ObjectTemplate> global_template = 22243 v8::ObjectTemplate::New(isolate); 22244 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 22245 22246 // Create a context and set an x property on it's global object. 22247 LocalContext context0(NULL, global_template); 22248 v8::Local<v8::Object> global0 = context0->Global(); 22249 global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust(); 22250 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 22251 22252 for (int i = 0; i < 2; i++) { 22253 if (i == 1) { 22254 // Install a toJSON function on the second run. 22255 v8::Local<v8::FunctionTemplate> toJSON = 22256 v8::FunctionTemplate::New(isolate, UnreachableCallback); 22257 22258 global0->Set(context0.local(), v8_str("toJSON"), 22259 toJSON->GetFunction(context0.local()).ToLocalChecked()) 22260 .FromJust(); 22261 } 22262 // Create a context with a different security token so that the 22263 // failed access check callback will be called on each access. 22264 LocalContext context1(NULL, global_template); 22265 CHECK(context1->Global() 22266 ->Set(context1.local(), v8_str("other"), global0) 22267 .FromJust()); 22268 22269 CHECK(CompileRun("JSON.stringify(other)").IsEmpty()); 22270 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty()); 22271 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty()); 22272 } 22273 } 22274 22275 22276 bool access_check_fail_thrown = false; 22277 bool catch_callback_called = false; 22278 22279 22280 // Failed access check callback that performs a GC on each invocation. 22281 void FailedAccessCheckThrows(Local<v8::Object> target, 22282 v8::AccessType type, 22283 Local<v8::Value> data) { 22284 access_check_fail_thrown = true; 22285 i::PrintF("Access check failed. Error thrown.\n"); 22286 CcTest::isolate()->ThrowException( 22287 v8::Exception::Error(v8_str("cross context"))); 22288 } 22289 22290 22291 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 22292 for (int i = 0; i < args.Length(); i++) { 22293 i::PrintF("%s\n", *String::Utf8Value(args[i])); 22294 } 22295 catch_callback_called = true; 22296 } 22297 22298 22299 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 22300 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); 22301 CHECK( 22302 args[0] 22303 ->ToObject(context) 22304 .ToLocalChecked() 22305 ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked()) 22306 .IsNothing()); 22307 } 22308 22309 22310 void CheckCorrectThrow(const char* script) { 22311 // Test that the script, when wrapped into a try-catch, triggers the catch 22312 // clause due to failed access check throwing an exception. 22313 // The subsequent try-catch should run without any exception. 22314 access_check_fail_thrown = false; 22315 catch_callback_called = false; 22316 i::ScopedVector<char> source(1024); 22317 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 22318 CompileRun(source.start()); 22319 CHECK(access_check_fail_thrown); 22320 CHECK(catch_callback_called); 22321 22322 access_check_fail_thrown = false; 22323 catch_callback_called = false; 22324 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 22325 CHECK(!access_check_fail_thrown); 22326 CHECK(!catch_callback_called); 22327 } 22328 22329 22330 TEST(AccessCheckThrows) { 22331 i::FLAG_allow_natives_syntax = true; 22332 v8::V8::Initialize(); 22333 v8::Isolate* isolate = CcTest::isolate(); 22334 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 22335 v8::HandleScope scope(isolate); 22336 22337 // Create an ObjectTemplate for global objects and install access 22338 // check callbacks that will block access. 22339 v8::Local<v8::ObjectTemplate> global_template = 22340 v8::ObjectTemplate::New(isolate); 22341 global_template->SetAccessCheckCallback(AccessAlwaysBlocked); 22342 22343 // Create a context and set an x property on it's global object. 22344 LocalContext context0(NULL, global_template); 22345 v8::Local<v8::Object> global0 = context0->Global(); 22346 22347 // Create a context with a different security token so that the 22348 // failed access check callback will be called on each access. 22349 LocalContext context1(NULL, global_template); 22350 CHECK(context1->Global() 22351 ->Set(context1.local(), v8_str("other"), global0) 22352 .FromJust()); 22353 22354 v8::Local<v8::FunctionTemplate> catcher_fun = 22355 v8::FunctionTemplate::New(isolate, CatcherCallback); 22356 CHECK(context1->Global() 22357 ->Set(context1.local(), v8_str("catcher"), 22358 catcher_fun->GetFunction(context1.local()).ToLocalChecked()) 22359 .FromJust()); 22360 22361 v8::Local<v8::FunctionTemplate> has_own_property_fun = 22362 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback); 22363 CHECK(context1->Global() 22364 ->Set(context1.local(), v8_str("has_own_property"), 22365 has_own_property_fun->GetFunction(context1.local()) 22366 .ToLocalChecked()) 22367 .FromJust()); 22368 22369 { 22370 v8::TryCatch try_catch(isolate); 22371 access_check_fail_thrown = false; 22372 CompileRun("other.x;"); 22373 CHECK(access_check_fail_thrown); 22374 CHECK(try_catch.HasCaught()); 22375 } 22376 22377 CheckCorrectThrow("other.x"); 22378 CheckCorrectThrow("other[1]"); 22379 CheckCorrectThrow("JSON.stringify(other)"); 22380 CheckCorrectThrow("has_own_property(other, 'x')"); 22381 CheckCorrectThrow("%GetProperty(other, 'x')"); 22382 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)"); 22383 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)"); 22384 CheckCorrectThrow("%DeleteProperty_Sloppy(other, 'x')"); 22385 CheckCorrectThrow("%DeleteProperty_Strict(other, 'x')"); 22386 CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')"); 22387 CheckCorrectThrow("%DeleteProperty_Strict(other, '1')"); 22388 CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')"); 22389 CheckCorrectThrow("%HasProperty('x', other)"); 22390 CheckCorrectThrow("%PropertyIsEnumerable(other, 'x')"); 22391 // PROPERTY_ATTRIBUTES_NONE = 0 22392 CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" 22393 "other, 'x', null, null, 1)"); 22394 22395 // Reset the failed access check callback so it does not influence 22396 // the other tests. 22397 isolate->SetFailedAccessCheckCallbackFunction(NULL); 22398 } 22399 22400 22401 class RequestInterruptTestBase { 22402 public: 22403 RequestInterruptTestBase() 22404 : env_(), 22405 isolate_(env_->GetIsolate()), 22406 sem_(0), 22407 warmup_(20000), 22408 should_continue_(true) { 22409 } 22410 22411 virtual ~RequestInterruptTestBase() { } 22412 22413 virtual void StartInterruptThread() = 0; 22414 22415 virtual void TestBody() = 0; 22416 22417 void RunTest() { 22418 StartInterruptThread(); 22419 22420 v8::HandleScope handle_scope(isolate_); 22421 22422 TestBody(); 22423 22424 // Verify we arrived here because interruptor was called 22425 // not due to a bug causing us to exit the loop too early. 22426 CHECK(!should_continue()); 22427 } 22428 22429 void WakeUpInterruptor() { 22430 sem_.Signal(); 22431 } 22432 22433 bool should_continue() const { return should_continue_; } 22434 22435 bool ShouldContinue() { 22436 if (warmup_ > 0) { 22437 if (--warmup_ == 0) { 22438 WakeUpInterruptor(); 22439 } 22440 } 22441 22442 return should_continue_; 22443 } 22444 22445 static void ShouldContinueCallback( 22446 const v8::FunctionCallbackInfo<Value>& info) { 22447 RequestInterruptTestBase* test = 22448 reinterpret_cast<RequestInterruptTestBase*>( 22449 info.Data().As<v8::External>()->Value()); 22450 info.GetReturnValue().Set(test->ShouldContinue()); 22451 } 22452 22453 LocalContext env_; 22454 v8::Isolate* isolate_; 22455 v8::base::Semaphore sem_; 22456 int warmup_; 22457 bool should_continue_; 22458 }; 22459 22460 22461 class RequestInterruptTestBaseWithSimpleInterrupt 22462 : public RequestInterruptTestBase { 22463 public: 22464 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { } 22465 22466 virtual void StartInterruptThread() { 22467 i_thread.Start(); 22468 } 22469 22470 private: 22471 class InterruptThread : public v8::base::Thread { 22472 public: 22473 explicit InterruptThread(RequestInterruptTestBase* test) 22474 : Thread(Options("RequestInterruptTest")), test_(test) {} 22475 22476 virtual void Run() { 22477 test_->sem_.Wait(); 22478 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 22479 } 22480 22481 static void OnInterrupt(v8::Isolate* isolate, void* data) { 22482 reinterpret_cast<RequestInterruptTestBase*>(data)-> 22483 should_continue_ = false; 22484 } 22485 22486 private: 22487 RequestInterruptTestBase* test_; 22488 }; 22489 22490 InterruptThread i_thread; 22491 }; 22492 22493 22494 class RequestInterruptTestWithFunctionCall 22495 : public RequestInterruptTestBaseWithSimpleInterrupt { 22496 public: 22497 virtual void TestBody() { 22498 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback, 22499 v8::External::New(isolate_, this)) 22500 .ToLocalChecked(); 22501 CHECK(env_->Global() 22502 ->Set(env_.local(), v8_str("ShouldContinue"), func) 22503 .FromJust()); 22504 22505 CompileRun("while (ShouldContinue()) { }"); 22506 } 22507 }; 22508 22509 22510 class RequestInterruptTestWithMethodCall 22511 : public RequestInterruptTestBaseWithSimpleInterrupt { 22512 public: 22513 virtual void TestBody() { 22514 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22515 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22516 proto->Set(v8_str("shouldContinue"), 22517 FunctionTemplate::New(isolate_, ShouldContinueCallback, 22518 v8::External::New(isolate_, this))); 22519 CHECK(env_->Global() 22520 ->Set(env_.local(), v8_str("Klass"), 22521 t->GetFunction(env_.local()).ToLocalChecked()) 22522 .FromJust()); 22523 22524 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22525 } 22526 }; 22527 22528 22529 class RequestInterruptTestWithAccessor 22530 : public RequestInterruptTestBaseWithSimpleInterrupt { 22531 public: 22532 virtual void TestBody() { 22533 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22534 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22535 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New( 22536 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22537 CHECK(env_->Global() 22538 ->Set(env_.local(), v8_str("Klass"), 22539 t->GetFunction(env_.local()).ToLocalChecked()) 22540 .FromJust()); 22541 22542 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22543 } 22544 }; 22545 22546 22547 class RequestInterruptTestWithNativeAccessor 22548 : public RequestInterruptTestBaseWithSimpleInterrupt { 22549 public: 22550 virtual void TestBody() { 22551 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22552 t->InstanceTemplate()->SetNativeDataProperty( 22553 v8_str("shouldContinue"), 22554 &ShouldContinueNativeGetter, 22555 NULL, 22556 v8::External::New(isolate_, this)); 22557 CHECK(env_->Global() 22558 ->Set(env_.local(), v8_str("Klass"), 22559 t->GetFunction(env_.local()).ToLocalChecked()) 22560 .FromJust()); 22561 22562 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22563 } 22564 22565 private: 22566 static void ShouldContinueNativeGetter( 22567 Local<String> property, 22568 const v8::PropertyCallbackInfo<v8::Value>& info) { 22569 RequestInterruptTestBase* test = 22570 reinterpret_cast<RequestInterruptTestBase*>( 22571 info.Data().As<v8::External>()->Value()); 22572 info.GetReturnValue().Set(test->ShouldContinue()); 22573 } 22574 }; 22575 22576 22577 class RequestInterruptTestWithMethodCallAndInterceptor 22578 : public RequestInterruptTestBaseWithSimpleInterrupt { 22579 public: 22580 virtual void TestBody() { 22581 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22582 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22583 proto->Set(v8_str("shouldContinue"), 22584 FunctionTemplate::New(isolate_, ShouldContinueCallback, 22585 v8::External::New(isolate_, this))); 22586 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate(); 22587 instance_template->SetHandler( 22588 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor)); 22589 22590 CHECK(env_->Global() 22591 ->Set(env_.local(), v8_str("Klass"), 22592 t->GetFunction(env_.local()).ToLocalChecked()) 22593 .FromJust()); 22594 22595 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22596 } 22597 22598 private: 22599 static void EmptyInterceptor( 22600 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {} 22601 }; 22602 22603 22604 class RequestInterruptTestWithMathAbs 22605 : public RequestInterruptTestBaseWithSimpleInterrupt { 22606 public: 22607 virtual void TestBody() { 22608 env_->Global() 22609 ->Set(env_.local(), v8_str("WakeUpInterruptor"), 22610 Function::New(env_.local(), WakeUpInterruptorCallback, 22611 v8::External::New(isolate_, this)) 22612 .ToLocalChecked()) 22613 .FromJust(); 22614 22615 env_->Global() 22616 ->Set(env_.local(), v8_str("ShouldContinue"), 22617 Function::New(env_.local(), ShouldContinueCallback, 22618 v8::External::New(isolate_, this)) 22619 .ToLocalChecked()) 22620 .FromJust(); 22621 22622 i::FLAG_allow_natives_syntax = true; 22623 CompileRun("function loopish(o) {" 22624 " var pre = 10;" 22625 " while (o.abs(1) > 0) {" 22626 " if (o.abs(1) >= 0 && !ShouldContinue()) break;" 22627 " if (pre > 0) {" 22628 " if (--pre === 0) WakeUpInterruptor(o === Math);" 22629 " }" 22630 " }" 22631 "}" 22632 "var i = 50;" 22633 "var obj = {abs: function () { return i-- }, x: null};" 22634 "delete obj.x;" 22635 "loopish(obj);" 22636 "%OptimizeFunctionOnNextCall(loopish);" 22637 "loopish(Math);"); 22638 22639 i::FLAG_allow_natives_syntax = false; 22640 } 22641 22642 private: 22643 static void WakeUpInterruptorCallback( 22644 const v8::FunctionCallbackInfo<Value>& info) { 22645 if (!info[0] 22646 ->BooleanValue(info.GetIsolate()->GetCurrentContext()) 22647 .FromJust()) { 22648 return; 22649 } 22650 22651 RequestInterruptTestBase* test = 22652 reinterpret_cast<RequestInterruptTestBase*>( 22653 info.Data().As<v8::External>()->Value()); 22654 test->WakeUpInterruptor(); 22655 } 22656 22657 static void ShouldContinueCallback( 22658 const v8::FunctionCallbackInfo<Value>& info) { 22659 RequestInterruptTestBase* test = 22660 reinterpret_cast<RequestInterruptTestBase*>( 22661 info.Data().As<v8::External>()->Value()); 22662 info.GetReturnValue().Set(test->should_continue()); 22663 } 22664 }; 22665 22666 22667 TEST(RequestInterruptTestWithFunctionCall) { 22668 RequestInterruptTestWithFunctionCall().RunTest(); 22669 } 22670 22671 22672 TEST(RequestInterruptTestWithMethodCall) { 22673 RequestInterruptTestWithMethodCall().RunTest(); 22674 } 22675 22676 22677 TEST(RequestInterruptTestWithAccessor) { 22678 RequestInterruptTestWithAccessor().RunTest(); 22679 } 22680 22681 22682 TEST(RequestInterruptTestWithNativeAccessor) { 22683 RequestInterruptTestWithNativeAccessor().RunTest(); 22684 } 22685 22686 22687 TEST(RequestInterruptTestWithMethodCallAndInterceptor) { 22688 RequestInterruptTestWithMethodCallAndInterceptor().RunTest(); 22689 } 22690 22691 22692 TEST(RequestInterruptTestWithMathAbs) { 22693 RequestInterruptTestWithMathAbs().RunTest(); 22694 } 22695 22696 22697 class RequestMultipleInterrupts : public RequestInterruptTestBase { 22698 public: 22699 RequestMultipleInterrupts() : i_thread(this), counter_(0) {} 22700 22701 virtual void StartInterruptThread() { 22702 i_thread.Start(); 22703 } 22704 22705 virtual void TestBody() { 22706 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback, 22707 v8::External::New(isolate_, this)) 22708 .ToLocalChecked(); 22709 CHECK(env_->Global() 22710 ->Set(env_.local(), v8_str("ShouldContinue"), func) 22711 .FromJust()); 22712 22713 CompileRun("while (ShouldContinue()) { }"); 22714 } 22715 22716 private: 22717 class InterruptThread : public v8::base::Thread { 22718 public: 22719 enum { NUM_INTERRUPTS = 10 }; 22720 explicit InterruptThread(RequestMultipleInterrupts* test) 22721 : Thread(Options("RequestInterruptTest")), test_(test) {} 22722 22723 virtual void Run() { 22724 test_->sem_.Wait(); 22725 for (int i = 0; i < NUM_INTERRUPTS; i++) { 22726 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 22727 } 22728 } 22729 22730 static void OnInterrupt(v8::Isolate* isolate, void* data) { 22731 RequestMultipleInterrupts* test = 22732 reinterpret_cast<RequestMultipleInterrupts*>(data); 22733 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS; 22734 } 22735 22736 private: 22737 RequestMultipleInterrupts* test_; 22738 }; 22739 22740 InterruptThread i_thread; 22741 int counter_; 22742 }; 22743 22744 22745 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); } 22746 22747 22748 static bool interrupt_was_called = false; 22749 22750 22751 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) { 22752 interrupt_was_called = true; 22753 } 22754 22755 22756 TEST(RequestInterruptSmallScripts) { 22757 LocalContext env; 22758 v8::Isolate* isolate = CcTest::isolate(); 22759 v8::HandleScope scope(isolate); 22760 22761 interrupt_was_called = false; 22762 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL); 22763 CompileRun("(function(x){return x;})(1);"); 22764 CHECK(interrupt_was_called); 22765 } 22766 22767 22768 static Local<Value> function_new_expected_env; 22769 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { 22770 CHECK( 22771 function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(), 22772 info.Data()) 22773 .FromJust()); 22774 info.GetReturnValue().Set(17); 22775 } 22776 22777 22778 THREADED_TEST(FunctionNew) { 22779 LocalContext env; 22780 v8::Isolate* isolate = env->GetIsolate(); 22781 v8::HandleScope scope(isolate); 22782 Local<Object> data = v8::Object::New(isolate); 22783 function_new_expected_env = data; 22784 Local<Function> func = 22785 Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked(); 22786 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust()); 22787 Local<Value> result = CompileRun("func();"); 22788 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust()); 22789 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 22790 // Verify function not cached 22791 auto serial_number = handle( 22792 i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func)) 22793 ->shared() 22794 ->get_api_func_data() 22795 ->serial_number()), 22796 i_isolate); 22797 auto cache = i_isolate->template_instantiations_cache(); 22798 CHECK(cache->FindEntry(static_cast<uint32_t>(serial_number->value())) == 22799 i::UnseededNumberDictionary::kNotFound); 22800 // Verify that each Function::New creates a new function instance 22801 Local<Object> data2 = v8::Object::New(isolate); 22802 function_new_expected_env = data2; 22803 Local<Function> func2 = 22804 Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked(); 22805 CHECK(!func2->IsNull()); 22806 CHECK(!func->Equals(env.local(), func2).FromJust()); 22807 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust()); 22808 Local<Value> result2 = CompileRun("func2();"); 22809 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust()); 22810 } 22811 22812 22813 TEST(EscapeableHandleScope) { 22814 HandleScope outer_scope(CcTest::isolate()); 22815 LocalContext context; 22816 const int runs = 10; 22817 Local<String> values[runs]; 22818 for (int i = 0; i < runs; i++) { 22819 v8::EscapableHandleScope inner_scope(CcTest::isolate()); 22820 Local<String> value; 22821 if (i != 0) value = v8_str("escape value"); 22822 values[i] = inner_scope.Escape(value); 22823 } 22824 for (int i = 0; i < runs; i++) { 22825 Local<String> expected; 22826 if (i != 0) { 22827 CHECK(v8_str("escape value") 22828 ->Equals(context.local(), values[i]) 22829 .FromJust()); 22830 } else { 22831 CHECK(values[i].IsEmpty()); 22832 } 22833 } 22834 } 22835 22836 22837 static void SetterWhichExpectsThisAndHolderToDiffer( 22838 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) { 22839 CHECK(info.Holder() != info.This()); 22840 } 22841 22842 22843 TEST(Regress239669) { 22844 LocalContext context; 22845 v8::Isolate* isolate = context->GetIsolate(); 22846 v8::HandleScope scope(isolate); 22847 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22848 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer); 22849 CHECK(context->Global() 22850 ->Set(context.local(), v8_str("P"), 22851 templ->NewInstance(context.local()).ToLocalChecked()) 22852 .FromJust()); 22853 CompileRun( 22854 "function C1() {" 22855 " this.x = 23;" 22856 "};" 22857 "C1.prototype = P;" 22858 "for (var i = 0; i < 4; i++ ) {" 22859 " new C1();" 22860 "}"); 22861 } 22862 22863 22864 class ApiCallOptimizationChecker { 22865 private: 22866 static Local<Object> data; 22867 static Local<Object> receiver; 22868 static Local<Object> holder; 22869 static Local<Object> callee; 22870 static int count; 22871 22872 static void OptimizationCallback( 22873 const v8::FunctionCallbackInfo<v8::Value>& info) { 22874 CHECK(data == info.Data()); 22875 CHECK(receiver == info.This()); 22876 if (info.Length() == 1) { 22877 CHECK(v8_num(1) 22878 ->Equals(info.GetIsolate()->GetCurrentContext(), info[0]) 22879 .FromJust()); 22880 } 22881 CHECK(holder == info.Holder()); 22882 count++; 22883 info.GetReturnValue().Set(v8_str("returned")); 22884 } 22885 22886 public: 22887 enum SignatureType { 22888 kNoSignature, 22889 kSignatureOnReceiver, 22890 kSignatureOnPrototype 22891 }; 22892 22893 void RunAll() { 22894 SignatureType signature_types[] = 22895 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; 22896 for (unsigned i = 0; i < arraysize(signature_types); i++) { 22897 SignatureType signature_type = signature_types[i]; 22898 for (int j = 0; j < 2; j++) { 22899 bool global = j == 0; 22900 int key = signature_type + 22901 arraysize(signature_types) * (global ? 1 : 0); 22902 Run(signature_type, global, key); 22903 } 22904 } 22905 } 22906 22907 void Run(SignatureType signature_type, bool global, int key) { 22908 v8::Isolate* isolate = CcTest::isolate(); 22909 v8::HandleScope scope(isolate); 22910 // Build a template for signature checks. 22911 Local<v8::ObjectTemplate> signature_template; 22912 Local<v8::Signature> signature; 22913 { 22914 Local<v8::FunctionTemplate> parent_template = 22915 FunctionTemplate::New(isolate); 22916 parent_template->SetHiddenPrototype(true); 22917 Local<v8::FunctionTemplate> function_template 22918 = FunctionTemplate::New(isolate); 22919 function_template->Inherit(parent_template); 22920 switch (signature_type) { 22921 case kNoSignature: 22922 break; 22923 case kSignatureOnReceiver: 22924 signature = v8::Signature::New(isolate, function_template); 22925 break; 22926 case kSignatureOnPrototype: 22927 signature = v8::Signature::New(isolate, parent_template); 22928 break; 22929 } 22930 signature_template = function_template->InstanceTemplate(); 22931 } 22932 // Global object must pass checks. 22933 Local<v8::Context> context = 22934 v8::Context::New(isolate, NULL, signature_template); 22935 v8::Context::Scope context_scope(context); 22936 // Install regular object that can pass signature checks. 22937 Local<Object> function_receiver = 22938 signature_template->NewInstance(context).ToLocalChecked(); 22939 CHECK(context->Global() 22940 ->Set(context, v8_str("function_receiver"), function_receiver) 22941 .FromJust()); 22942 // Get the holder objects. 22943 Local<Object> inner_global = 22944 Local<Object>::Cast(context->Global()->GetPrototype()); 22945 // Install functions on hidden prototype object if there is one. 22946 data = Object::New(isolate); 22947 Local<FunctionTemplate> function_template = FunctionTemplate::New( 22948 isolate, OptimizationCallback, data, signature); 22949 Local<Function> function = 22950 function_template->GetFunction(context).ToLocalChecked(); 22951 Local<Object> global_holder = inner_global; 22952 Local<Object> function_holder = function_receiver; 22953 if (signature_type == kSignatureOnPrototype) { 22954 function_holder = Local<Object>::Cast(function_holder->GetPrototype()); 22955 global_holder = Local<Object>::Cast(global_holder->GetPrototype()); 22956 } 22957 global_holder->Set(context, v8_str("g_f"), function).FromJust(); 22958 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); 22959 function_holder->Set(context, v8_str("f"), function).FromJust(); 22960 function_holder->SetAccessorProperty(v8_str("acc"), function, function); 22961 // Initialize expected values. 22962 callee = function; 22963 count = 0; 22964 if (global) { 22965 receiver = context->Global(); 22966 holder = inner_global; 22967 } else { 22968 holder = function_receiver; 22969 // If not using a signature, add something else to the prototype chain 22970 // to test the case that holder != receiver 22971 if (signature_type == kNoSignature) { 22972 receiver = Local<Object>::Cast(CompileRun( 22973 "var receiver_subclass = {};\n" 22974 "receiver_subclass.__proto__ = function_receiver;\n" 22975 "receiver_subclass")); 22976 } else { 22977 receiver = Local<Object>::Cast(CompileRun( 22978 "var receiver_subclass = function_receiver;\n" 22979 "receiver_subclass")); 22980 } 22981 } 22982 // With no signature, the holder is not set. 22983 if (signature_type == kNoSignature) holder = receiver; 22984 // build wrap_function 22985 i::ScopedVector<char> wrap_function(200); 22986 if (global) { 22987 i::SNPrintF( 22988 wrap_function, 22989 "function wrap_f_%d() { var f = g_f; return f(); }\n" 22990 "function wrap_get_%d() { return this.g_acc; }\n" 22991 "function wrap_set_%d() { return this.g_acc = 1; }\n", 22992 key, key, key); 22993 } else { 22994 i::SNPrintF( 22995 wrap_function, 22996 "function wrap_f_%d() { return receiver_subclass.f(); }\n" 22997 "function wrap_get_%d() { return receiver_subclass.acc; }\n" 22998 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", 22999 key, key, key); 23000 } 23001 // build source string 23002 i::ScopedVector<char> source(1000); 23003 i::SNPrintF( 23004 source, 23005 "%s\n" // wrap functions 23006 "function wrap_f() { return wrap_f_%d(); }\n" 23007 "function wrap_get() { return wrap_get_%d(); }\n" 23008 "function wrap_set() { return wrap_set_%d(); }\n" 23009 "check = function(returned) {\n" 23010 " if (returned !== 'returned') { throw returned; }\n" 23011 "}\n" 23012 "\n" 23013 "check(wrap_f());\n" 23014 "check(wrap_f());\n" 23015 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" 23016 "check(wrap_f());\n" 23017 "\n" 23018 "check(wrap_get());\n" 23019 "check(wrap_get());\n" 23020 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" 23021 "check(wrap_get());\n" 23022 "\n" 23023 "check = function(returned) {\n" 23024 " if (returned !== 1) { throw returned; }\n" 23025 "}\n" 23026 "check(wrap_set());\n" 23027 "check(wrap_set());\n" 23028 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" 23029 "check(wrap_set());\n", 23030 wrap_function.start(), key, key, key, key, key, key); 23031 v8::TryCatch try_catch(isolate); 23032 CompileRun(source.start()); 23033 CHECK(!try_catch.HasCaught()); 23034 CHECK_EQ(9, count); 23035 } 23036 }; 23037 23038 23039 Local<Object> ApiCallOptimizationChecker::data; 23040 Local<Object> ApiCallOptimizationChecker::receiver; 23041 Local<Object> ApiCallOptimizationChecker::holder; 23042 Local<Object> ApiCallOptimizationChecker::callee; 23043 int ApiCallOptimizationChecker::count = 0; 23044 23045 23046 TEST(FunctionCallOptimization) { 23047 i::FLAG_allow_natives_syntax = true; 23048 ApiCallOptimizationChecker checker; 23049 checker.RunAll(); 23050 } 23051 23052 23053 TEST(FunctionCallOptimizationMultipleArgs) { 23054 i::FLAG_allow_natives_syntax = true; 23055 LocalContext context; 23056 v8::Isolate* isolate = context->GetIsolate(); 23057 v8::HandleScope scope(isolate); 23058 Local<Object> global = context->Global(); 23059 Local<v8::Function> function = 23060 Function::New(context.local(), Returns42).ToLocalChecked(); 23061 global->Set(context.local(), v8_str("x"), function).FromJust(); 23062 CompileRun( 23063 "function x_wrap() {\n" 23064 " for (var i = 0; i < 5; i++) {\n" 23065 " x(1,2,3);\n" 23066 " }\n" 23067 "}\n" 23068 "x_wrap();\n" 23069 "%OptimizeFunctionOnNextCall(x_wrap);" 23070 "x_wrap();\n"); 23071 } 23072 23073 23074 static void ReturnsSymbolCallback( 23075 const v8::FunctionCallbackInfo<v8::Value>& info) { 23076 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate())); 23077 } 23078 23079 23080 TEST(ApiCallbackCanReturnSymbols) { 23081 i::FLAG_allow_natives_syntax = true; 23082 LocalContext context; 23083 v8::Isolate* isolate = context->GetIsolate(); 23084 v8::HandleScope scope(isolate); 23085 Local<Object> global = context->Global(); 23086 Local<v8::Function> function = 23087 Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked(); 23088 global->Set(context.local(), v8_str("x"), function).FromJust(); 23089 CompileRun( 23090 "function x_wrap() {\n" 23091 " for (var i = 0; i < 5; i++) {\n" 23092 " x();\n" 23093 " }\n" 23094 "}\n" 23095 "x_wrap();\n" 23096 "%OptimizeFunctionOnNextCall(x_wrap);" 23097 "x_wrap();\n"); 23098 } 23099 23100 23101 TEST(EmptyApiCallback) { 23102 LocalContext context; 23103 auto isolate = context->GetIsolate(); 23104 v8::HandleScope scope(isolate); 23105 auto global = context->Global(); 23106 auto function = FunctionTemplate::New(isolate) 23107 ->GetFunction(context.local()) 23108 .ToLocalChecked(); 23109 global->Set(context.local(), v8_str("x"), function).FromJust(); 23110 23111 auto result = CompileRun("x()"); 23112 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 23113 23114 result = CompileRun("x(1,2,3)"); 23115 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 23116 23117 result = CompileRun("x.call(undefined)"); 23118 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 23119 23120 result = CompileRun("x.call(null)"); 23121 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy()); 23122 23123 result = CompileRun("7 + x.call(3) + 11"); 23124 CHECK(result->IsInt32()); 23125 CHECK_EQ(21, result->Int32Value(context.local()).FromJust()); 23126 23127 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11"); 23128 CHECK(result->IsInt32()); 23129 CHECK_EQ(21, result->Int32Value(context.local()).FromJust()); 23130 23131 result = CompileRun("var y = []; x.call(y)"); 23132 CHECK(result->IsArray()); 23133 23134 result = CompileRun("x.call(y, 1, 2, 3, 4)"); 23135 CHECK(result->IsArray()); 23136 } 23137 23138 23139 TEST(SimpleSignatureCheck) { 23140 LocalContext context; 23141 auto isolate = context->GetIsolate(); 23142 v8::HandleScope scope(isolate); 23143 auto global = context->Global(); 23144 auto sig_obj = FunctionTemplate::New(isolate); 23145 auto sig = v8::Signature::New(isolate, sig_obj); 23146 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 23147 global->Set(context.local(), v8_str("sig_obj"), 23148 sig_obj->GetFunction(context.local()).ToLocalChecked()) 23149 .FromJust(); 23150 global->Set(context.local(), v8_str("x"), 23151 x->GetFunction(context.local()).ToLocalChecked()) 23152 .FromJust(); 23153 CompileRun("var s = new sig_obj();"); 23154 { 23155 TryCatch try_catch(isolate); 23156 CompileRun("x()"); 23157 CHECK(try_catch.HasCaught()); 23158 } 23159 { 23160 TryCatch try_catch(isolate); 23161 CompileRun("x.call(1)"); 23162 CHECK(try_catch.HasCaught()); 23163 } 23164 { 23165 TryCatch try_catch(isolate); 23166 auto result = CompileRun("s.x = x; s.x()"); 23167 CHECK(!try_catch.HasCaught()); 23168 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23169 } 23170 { 23171 TryCatch try_catch(isolate); 23172 auto result = CompileRun("x.call(s)"); 23173 CHECK(!try_catch.HasCaught()); 23174 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23175 } 23176 } 23177 23178 23179 TEST(ChainSignatureCheck) { 23180 LocalContext context; 23181 auto isolate = context->GetIsolate(); 23182 v8::HandleScope scope(isolate); 23183 auto global = context->Global(); 23184 auto sig_obj = FunctionTemplate::New(isolate); 23185 auto sig = v8::Signature::New(isolate, sig_obj); 23186 for (int i = 0; i < 4; ++i) { 23187 auto temp = FunctionTemplate::New(isolate); 23188 temp->Inherit(sig_obj); 23189 sig_obj = temp; 23190 } 23191 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 23192 global->Set(context.local(), v8_str("sig_obj"), 23193 sig_obj->GetFunction(context.local()).ToLocalChecked()) 23194 .FromJust(); 23195 global->Set(context.local(), v8_str("x"), 23196 x->GetFunction(context.local()).ToLocalChecked()) 23197 .FromJust(); 23198 CompileRun("var s = new sig_obj();"); 23199 { 23200 TryCatch try_catch(isolate); 23201 CompileRun("x()"); 23202 CHECK(try_catch.HasCaught()); 23203 } 23204 { 23205 TryCatch try_catch(isolate); 23206 CompileRun("x.call(1)"); 23207 CHECK(try_catch.HasCaught()); 23208 } 23209 { 23210 TryCatch try_catch(isolate); 23211 auto result = CompileRun("s.x = x; s.x()"); 23212 CHECK(!try_catch.HasCaught()); 23213 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23214 } 23215 { 23216 TryCatch try_catch(isolate); 23217 auto result = CompileRun("x.call(s)"); 23218 CHECK(!try_catch.HasCaught()); 23219 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23220 } 23221 } 23222 23223 23224 TEST(PrototypeSignatureCheck) { 23225 LocalContext context; 23226 auto isolate = context->GetIsolate(); 23227 v8::HandleScope scope(isolate); 23228 auto global = context->Global(); 23229 auto sig_obj = FunctionTemplate::New(isolate); 23230 sig_obj->SetHiddenPrototype(true); 23231 auto sig = v8::Signature::New(isolate, sig_obj); 23232 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig); 23233 global->Set(context.local(), v8_str("sig_obj"), 23234 sig_obj->GetFunction(context.local()).ToLocalChecked()) 23235 .FromJust(); 23236 global->Set(context.local(), v8_str("x"), 23237 x->GetFunction(context.local()).ToLocalChecked()) 23238 .FromJust(); 23239 CompileRun("s = {}; s.__proto__ = new sig_obj();"); 23240 { 23241 TryCatch try_catch(isolate); 23242 CompileRun("x()"); 23243 CHECK(try_catch.HasCaught()); 23244 } 23245 { 23246 TryCatch try_catch(isolate); 23247 CompileRun("x.call(1)"); 23248 CHECK(try_catch.HasCaught()); 23249 } 23250 { 23251 TryCatch try_catch(isolate); 23252 auto result = CompileRun("s.x = x; s.x()"); 23253 CHECK(!try_catch.HasCaught()); 23254 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23255 } 23256 { 23257 TryCatch try_catch(isolate); 23258 auto result = CompileRun("x.call(s)"); 23259 CHECK(!try_catch.HasCaught()); 23260 CHECK_EQ(42, result->Int32Value(context.local()).FromJust()); 23261 } 23262 } 23263 23264 23265 static const char* last_event_message; 23266 static int last_event_status; 23267 void StoringEventLoggerCallback(const char* message, int status) { 23268 last_event_message = message; 23269 last_event_status = status; 23270 } 23271 23272 23273 TEST(EventLogging) { 23274 v8::Isolate* isolate = CcTest::isolate(); 23275 isolate->SetEventLogger(StoringEventLoggerCallback); 23276 v8::internal::HistogramTimer histogramTimer( 23277 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50, 23278 reinterpret_cast<v8::internal::Isolate*>(isolate)); 23279 histogramTimer.Start(); 23280 CHECK_EQ(0, strcmp("V8.Test", last_event_message)); 23281 CHECK_EQ(0, last_event_status); 23282 histogramTimer.Stop(); 23283 CHECK_EQ(0, strcmp("V8.Test", last_event_message)); 23284 CHECK_EQ(1, last_event_status); 23285 } 23286 23287 23288 TEST(Promises) { 23289 LocalContext context; 23290 v8::Isolate* isolate = context->GetIsolate(); 23291 v8::HandleScope scope(isolate); 23292 23293 // Creation. 23294 Local<v8::Promise::Resolver> pr = 23295 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23296 Local<v8::Promise::Resolver> rr = 23297 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23298 Local<v8::Promise> p = pr->GetPromise(); 23299 Local<v8::Promise> r = rr->GetPromise(); 23300 23301 // IsPromise predicate. 23302 CHECK(p->IsPromise()); 23303 CHECK(r->IsPromise()); 23304 Local<Value> o = v8::Object::New(isolate); 23305 CHECK(!o->IsPromise()); 23306 23307 // Resolution and rejection. 23308 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust(); 23309 CHECK(p->IsPromise()); 23310 rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust(); 23311 CHECK(r->IsPromise()); 23312 } 23313 23314 23315 TEST(PromiseThen) { 23316 LocalContext context; 23317 v8::Isolate* isolate = context->GetIsolate(); 23318 v8::HandleScope scope(isolate); 23319 Local<Object> global = context->Global(); 23320 23321 // Creation. 23322 Local<v8::Promise::Resolver> pr = 23323 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23324 Local<v8::Promise::Resolver> qr = 23325 v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23326 Local<v8::Promise> p = pr->GetPromise(); 23327 Local<v8::Promise> q = qr->GetPromise(); 23328 23329 CHECK(p->IsPromise()); 23330 CHECK(q->IsPromise()); 23331 23332 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust(); 23333 qr->Resolve(context.local(), p).FromJust(); 23334 23335 // Chaining non-pending promises. 23336 CompileRun( 23337 "var x1 = 0;\n" 23338 "var x2 = 0;\n" 23339 "function f1(x) { x1 = x; return x+1 };\n" 23340 "function f2(x) { x2 = x; return x+1 };\n"); 23341 Local<Function> f1 = Local<Function>::Cast( 23342 global->Get(context.local(), v8_str("f1")).ToLocalChecked()); 23343 Local<Function> f2 = Local<Function>::Cast( 23344 global->Get(context.local(), v8_str("f2")).ToLocalChecked()); 23345 23346 // Then 23347 CompileRun("x1 = x2 = 0;"); 23348 q->Then(context.local(), f1).ToLocalChecked(); 23349 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 23350 .ToLocalChecked() 23351 ->Int32Value(context.local()) 23352 .FromJust()); 23353 isolate->RunMicrotasks(); 23354 CHECK_EQ(1, global->Get(context.local(), v8_str("x1")) 23355 .ToLocalChecked() 23356 ->Int32Value(context.local()) 23357 .FromJust()); 23358 23359 // Then 23360 CompileRun("x1 = x2 = 0;"); 23361 pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23362 qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked(); 23363 23364 qr->Resolve(context.local(), pr).FromJust(); 23365 qr->GetPromise() 23366 ->Then(context.local(), f1) 23367 .ToLocalChecked() 23368 ->Then(context.local(), f2) 23369 .ToLocalChecked(); 23370 23371 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 23372 .ToLocalChecked() 23373 ->Int32Value(context.local()) 23374 .FromJust()); 23375 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 23376 .ToLocalChecked() 23377 ->Int32Value(context.local()) 23378 .FromJust()); 23379 isolate->RunMicrotasks(); 23380 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 23381 .ToLocalChecked() 23382 ->Int32Value(context.local()) 23383 .FromJust()); 23384 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 23385 .ToLocalChecked() 23386 ->Int32Value(context.local()) 23387 .FromJust()); 23388 23389 pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust(); 23390 23391 CHECK_EQ(0, global->Get(context.local(), v8_str("x1")) 23392 .ToLocalChecked() 23393 ->Int32Value(context.local()) 23394 .FromJust()); 23395 CHECK_EQ(0, global->Get(context.local(), v8_str("x2")) 23396 .ToLocalChecked() 23397 ->Int32Value(context.local()) 23398 .FromJust()); 23399 isolate->RunMicrotasks(); 23400 CHECK_EQ(3, global->Get(context.local(), v8_str("x1")) 23401 .ToLocalChecked() 23402 ->Int32Value(context.local()) 23403 .FromJust()); 23404 CHECK_EQ(4, global->Get(context.local(), v8_str("x2")) 23405 .ToLocalChecked() 23406 ->Int32Value(context.local()) 23407 .FromJust()); 23408 } 23409 23410 23411 TEST(DisallowJavascriptExecutionScope) { 23412 LocalContext context; 23413 v8::Isolate* isolate = context->GetIsolate(); 23414 v8::HandleScope scope(isolate); 23415 v8::Isolate::DisallowJavascriptExecutionScope no_js( 23416 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 23417 CompileRun("2+2"); 23418 } 23419 23420 23421 TEST(AllowJavascriptExecutionScope) { 23422 LocalContext context; 23423 v8::Isolate* isolate = context->GetIsolate(); 23424 v8::HandleScope scope(isolate); 23425 v8::Isolate::DisallowJavascriptExecutionScope no_js( 23426 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 23427 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 23428 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 23429 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate); 23430 CompileRun("1+1"); 23431 } 23432 } 23433 23434 23435 TEST(ThrowOnJavascriptExecution) { 23436 LocalContext context; 23437 v8::Isolate* isolate = context->GetIsolate(); 23438 v8::HandleScope scope(isolate); 23439 v8::TryCatch try_catch(isolate); 23440 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 23441 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 23442 CompileRun("1+1"); 23443 CHECK(try_catch.HasCaught()); 23444 } 23445 23446 23447 TEST(Regress354123) { 23448 LocalContext current; 23449 v8::Isolate* isolate = current->GetIsolate(); 23450 v8::HandleScope scope(isolate); 23451 23452 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 23453 templ->SetAccessCheckCallback(AccessCounter); 23454 CHECK(current->Global() 23455 ->Set(current.local(), v8_str("friend"), 23456 templ->NewInstance(current.local()).ToLocalChecked()) 23457 .FromJust()); 23458 23459 // Test access using __proto__ from the prototype chain. 23460 access_count = 0; 23461 CompileRun("friend.__proto__ = {};"); 23462 CHECK_EQ(2, access_count); 23463 CompileRun("friend.__proto__;"); 23464 CHECK_EQ(4, access_count); 23465 23466 // Test access using __proto__ as a hijacked function (A). 23467 access_count = 0; 23468 CompileRun("var p = Object.prototype;" 23469 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;" 23470 "f.call(friend, {});"); 23471 CHECK_EQ(1, access_count); 23472 CompileRun("var p = Object.prototype;" 23473 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;" 23474 "f.call(friend);"); 23475 CHECK_EQ(2, access_count); 23476 23477 // Test access using __proto__ as a hijacked function (B). 23478 access_count = 0; 23479 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');" 23480 "f.call(friend, {});"); 23481 CHECK_EQ(1, access_count); 23482 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');" 23483 "f.call(friend);"); 23484 CHECK_EQ(2, access_count); 23485 23486 // Test access using Object.setPrototypeOf reflective method. 23487 access_count = 0; 23488 CompileRun("Object.setPrototypeOf(friend, {});"); 23489 CHECK_EQ(1, access_count); 23490 CompileRun("Object.getPrototypeOf(friend);"); 23491 CHECK_EQ(2, access_count); 23492 } 23493 23494 23495 TEST(CaptureStackTraceForStackOverflow) { 23496 v8::internal::FLAG_stack_size = 150; 23497 LocalContext current; 23498 v8::Isolate* isolate = current->GetIsolate(); 23499 v8::HandleScope scope(isolate); 23500 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, 23501 v8::StackTrace::kDetailed); 23502 v8::TryCatch try_catch(isolate); 23503 CompileRun("(function f(x) { f(x+1); })(0)"); 23504 CHECK(try_catch.HasCaught()); 23505 } 23506 23507 23508 TEST(ScriptNameAndLineNumber) { 23509 LocalContext env; 23510 v8::Isolate* isolate = env->GetIsolate(); 23511 v8::HandleScope scope(isolate); 23512 const char* url = "http://www.foo.com/foo.js"; 23513 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); 23514 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin); 23515 Local<Script> script = 23516 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked(); 23517 Local<Value> script_name = script->GetUnboundScript()->GetScriptName(); 23518 CHECK(!script_name.IsEmpty()); 23519 CHECK(script_name->IsString()); 23520 String::Utf8Value utf8_name(script_name); 23521 CHECK_EQ(0, strcmp(url, *utf8_name)); 23522 int line_number = script->GetUnboundScript()->GetLineNumber(0); 23523 CHECK_EQ(13, line_number); 23524 } 23525 23526 TEST(ScriptPositionInfo) { 23527 LocalContext env; 23528 v8::Isolate* isolate = env->GetIsolate(); 23529 v8::HandleScope scope(isolate); 23530 const char* url = "http://www.foo.com/foo.js"; 23531 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); 23532 v8::ScriptCompiler::Source script_source(v8_str("var foo;\n" 23533 "var bar;\n" 23534 "var fisk = foo + bar;\n"), 23535 origin); 23536 Local<Script> script = 23537 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked(); 23538 23539 i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast( 23540 v8::Utils::OpenHandle(*script->GetUnboundScript())); 23541 CHECK(obj->script()->IsScript()); 23542 23543 i::Handle<i::Script> script1(i::Script::cast(obj->script())); 23544 23545 v8::internal::Script::PositionInfo info; 23546 23547 // With offset. 23548 23549 // Behave as if 0 was passed if position is negative. 23550 CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET)); 23551 CHECK_EQ(13, info.line); 23552 CHECK_EQ(0, info.column); 23553 CHECK_EQ(0, info.line_start); 23554 CHECK_EQ(8, info.line_end); 23555 23556 CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET)); 23557 CHECK_EQ(13, info.line); 23558 CHECK_EQ(0, info.column); 23559 CHECK_EQ(0, info.line_start); 23560 CHECK_EQ(8, info.line_end); 23561 23562 CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET)); 23563 CHECK_EQ(13, info.line); 23564 CHECK_EQ(8, info.column); 23565 CHECK_EQ(0, info.line_start); 23566 CHECK_EQ(8, info.line_end); 23567 23568 CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET)); 23569 CHECK_EQ(14, info.line); 23570 CHECK_EQ(0, info.column); 23571 CHECK_EQ(9, info.line_start); 23572 CHECK_EQ(17, info.line_end); 23573 23574 // Fail when position is larger than script size. 23575 CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET)); 23576 23577 // Without offset. 23578 23579 // Behave as if 0 was passed if position is negative. 23580 CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET)); 23581 CHECK_EQ(0, info.line); 23582 CHECK_EQ(0, info.column); 23583 CHECK_EQ(0, info.line_start); 23584 CHECK_EQ(8, info.line_end); 23585 23586 CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET)); 23587 CHECK_EQ(0, info.line); 23588 CHECK_EQ(0, info.column); 23589 CHECK_EQ(0, info.line_start); 23590 CHECK_EQ(8, info.line_end); 23591 23592 CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET)); 23593 CHECK_EQ(0, info.line); 23594 CHECK_EQ(8, info.column); 23595 CHECK_EQ(0, info.line_start); 23596 CHECK_EQ(8, info.line_end); 23597 23598 CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET)); 23599 CHECK_EQ(1, info.line); 23600 CHECK_EQ(0, info.column); 23601 CHECK_EQ(9, info.line_start); 23602 CHECK_EQ(17, info.line_end); 23603 23604 // Fail when position is larger than script size. 23605 CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET)); 23606 } 23607 23608 void CheckMagicComments(Local<Script> script, const char* expected_source_url, 23609 const char* expected_source_mapping_url) { 23610 if (expected_source_url != NULL) { 23611 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL()); 23612 CHECK_EQ(0, strcmp(expected_source_url, *url)); 23613 } else { 23614 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined()); 23615 } 23616 if (expected_source_mapping_url != NULL) { 23617 v8::String::Utf8Value url( 23618 script->GetUnboundScript()->GetSourceMappingURL()); 23619 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url)); 23620 } else { 23621 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined()); 23622 } 23623 } 23624 23625 void SourceURLHelper(const char* source, const char* expected_source_url, 23626 const char* expected_source_mapping_url) { 23627 Local<Script> script = v8_compile(source); 23628 CheckMagicComments(script, expected_source_url, expected_source_mapping_url); 23629 } 23630 23631 23632 TEST(ScriptSourceURLAndSourceMappingURL) { 23633 LocalContext env; 23634 v8::Isolate* isolate = env->GetIsolate(); 23635 v8::HandleScope scope(isolate); 23636 SourceURLHelper("function foo() {}\n" 23637 "//# sourceURL=bar1.js\n", "bar1.js", NULL); 23638 SourceURLHelper("function foo() {}\n" 23639 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js"); 23640 23641 // Both sourceURL and sourceMappingURL. 23642 SourceURLHelper("function foo() {}\n" 23643 "//# sourceURL=bar3.js\n" 23644 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js"); 23645 23646 // Two source URLs; the first one is ignored. 23647 SourceURLHelper("function foo() {}\n" 23648 "//# sourceURL=ignoreme.js\n" 23649 "//# sourceURL=bar5.js\n", "bar5.js", NULL); 23650 SourceURLHelper("function foo() {}\n" 23651 "//# sourceMappingURL=ignoreme.js\n" 23652 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js"); 23653 23654 // SourceURL or sourceMappingURL in the middle of the script. 23655 SourceURLHelper("function foo() {}\n" 23656 "//# sourceURL=bar7.js\n" 23657 "function baz() {}\n", "bar7.js", NULL); 23658 SourceURLHelper("function foo() {}\n" 23659 "//# sourceMappingURL=bar8.js\n" 23660 "function baz() {}\n", NULL, "bar8.js"); 23661 23662 // Too much whitespace. 23663 SourceURLHelper("function foo() {}\n" 23664 "//# sourceURL=bar9.js\n" 23665 "//# sourceMappingURL=bar10.js\n", NULL, NULL); 23666 SourceURLHelper("function foo() {}\n" 23667 "//# sourceURL =bar11.js\n" 23668 "//# sourceMappingURL =bar12.js\n", NULL, NULL); 23669 23670 // Disallowed characters in value. 23671 SourceURLHelper("function foo() {}\n" 23672 "//# sourceURL=bar13 .js \n" 23673 "//# sourceMappingURL=bar14 .js \n", 23674 NULL, NULL); 23675 SourceURLHelper("function foo() {}\n" 23676 "//# sourceURL=bar15\t.js \n" 23677 "//# sourceMappingURL=bar16\t.js \n", 23678 NULL, NULL); 23679 SourceURLHelper("function foo() {}\n" 23680 "//# sourceURL=bar17'.js \n" 23681 "//# sourceMappingURL=bar18'.js \n", 23682 NULL, NULL); 23683 SourceURLHelper("function foo() {}\n" 23684 "//# sourceURL=bar19\".js \n" 23685 "//# sourceMappingURL=bar20\".js \n", 23686 NULL, NULL); 23687 23688 // Not too much whitespace. 23689 SourceURLHelper("function foo() {}\n" 23690 "//# sourceURL= bar21.js \n" 23691 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js"); 23692 } 23693 23694 23695 TEST(GetOwnPropertyDescriptor) { 23696 LocalContext env; 23697 v8::Isolate* isolate = env->GetIsolate(); 23698 v8::HandleScope scope(isolate); 23699 CompileRun( 23700 "var x = { value : 13};" 23701 "Object.defineProperty(x, 'p0', {value : 12});" 23702 "Object.defineProperty(x, 'p1', {" 23703 " set : function(value) { this.value = value; }," 23704 " get : function() { return this.value; }," 23705 "});"); 23706 Local<Object> x = Local<Object>::Cast( 23707 env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked()); 23708 Local<Value> desc = 23709 x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop")) 23710 .ToLocalChecked(); 23711 CHECK(desc->IsUndefined()); 23712 desc = 23713 x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked(); 23714 CHECK(v8_num(12) 23715 ->Equals(env.local(), Local<Object>::Cast(desc) 23716 ->Get(env.local(), v8_str("value")) 23717 .ToLocalChecked()) 23718 .FromJust()); 23719 desc = 23720 x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked(); 23721 Local<Function> set = 23722 Local<Function>::Cast(Local<Object>::Cast(desc) 23723 ->Get(env.local(), v8_str("set")) 23724 .ToLocalChecked()); 23725 Local<Function> get = 23726 Local<Function>::Cast(Local<Object>::Cast(desc) 23727 ->Get(env.local(), v8_str("get")) 23728 .ToLocalChecked()); 23729 CHECK(v8_num(13) 23730 ->Equals(env.local(), 23731 get->Call(env.local(), x, 0, NULL).ToLocalChecked()) 23732 .FromJust()); 23733 Local<Value> args[] = {v8_num(14)}; 23734 set->Call(env.local(), x, 1, args).ToLocalChecked(); 23735 CHECK(v8_num(14) 23736 ->Equals(env.local(), 23737 get->Call(env.local(), x, 0, NULL).ToLocalChecked()) 23738 .FromJust()); 23739 } 23740 23741 23742 TEST(Regress411877) { 23743 v8::Isolate* isolate = CcTest::isolate(); 23744 v8::HandleScope handle_scope(isolate); 23745 v8::Local<v8::ObjectTemplate> object_template = 23746 v8::ObjectTemplate::New(isolate); 23747 object_template->SetAccessCheckCallback(AccessCounter); 23748 23749 v8::Local<Context> context = Context::New(isolate); 23750 v8::Context::Scope context_scope(context); 23751 23752 CHECK(context->Global() 23753 ->Set(context, v8_str("o"), 23754 object_template->NewInstance(context).ToLocalChecked()) 23755 .FromJust()); 23756 CompileRun("Object.getOwnPropertyNames(o)"); 23757 } 23758 23759 23760 TEST(GetHiddenPropertyTableAfterAccessCheck) { 23761 v8::Isolate* isolate = CcTest::isolate(); 23762 v8::HandleScope handle_scope(isolate); 23763 v8::Local<v8::ObjectTemplate> object_template = 23764 v8::ObjectTemplate::New(isolate); 23765 object_template->SetAccessCheckCallback(AccessCounter); 23766 23767 v8::Local<Context> context = Context::New(isolate); 23768 v8::Context::Scope context_scope(context); 23769 23770 v8::Local<v8::Object> obj = 23771 object_template->NewInstance(context).ToLocalChecked(); 23772 obj->Set(context, v8_str("key"), v8_str("value")).FromJust(); 23773 obj->Delete(context, v8_str("key")).FromJust(); 23774 23775 obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")), 23776 v8_str("hidden value 2")) 23777 .FromJust(); 23778 } 23779 23780 23781 TEST(Regress411793) { 23782 v8::Isolate* isolate = CcTest::isolate(); 23783 v8::HandleScope handle_scope(isolate); 23784 v8::Local<v8::ObjectTemplate> object_template = 23785 v8::ObjectTemplate::New(isolate); 23786 object_template->SetAccessCheckCallback(AccessCounter); 23787 23788 v8::Local<Context> context = Context::New(isolate); 23789 v8::Context::Scope context_scope(context); 23790 23791 CHECK(context->Global() 23792 ->Set(context, v8_str("o"), 23793 object_template->NewInstance(context).ToLocalChecked()) 23794 .FromJust()); 23795 CompileRun( 23796 "Object.defineProperty(o, 'key', " 23797 " { get: function() {}, set: function() {} });"); 23798 } 23799 23800 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream { 23801 public: 23802 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {} 23803 23804 virtual size_t GetMoreData(const uint8_t** src) { 23805 // Unlike in real use cases, this function will never block. 23806 if (chunks_[index_] == NULL) { 23807 return 0; 23808 } 23809 // Copy the data, since the caller takes ownership of it. 23810 size_t len = strlen(chunks_[index_]); 23811 // We don't need to zero-terminate since we return the length. 23812 uint8_t* copy = new uint8_t[len]; 23813 memcpy(copy, chunks_[index_], len); 23814 *src = copy; 23815 ++index_; 23816 return len; 23817 } 23818 23819 // Helper for constructing a string from chunks (the compilation needs it 23820 // too). 23821 static char* FullSourceString(const char** chunks) { 23822 size_t total_len = 0; 23823 for (size_t i = 0; chunks[i] != NULL; ++i) { 23824 total_len += strlen(chunks[i]); 23825 } 23826 char* full_string = new char[total_len + 1]; 23827 size_t offset = 0; 23828 for (size_t i = 0; chunks[i] != NULL; ++i) { 23829 size_t len = strlen(chunks[i]); 23830 memcpy(full_string + offset, chunks[i], len); 23831 offset += len; 23832 } 23833 full_string[total_len] = 0; 23834 return full_string; 23835 } 23836 23837 private: 23838 const char** chunks_; 23839 unsigned index_; 23840 }; 23841 23842 23843 // Helper function for running streaming tests. 23844 void RunStreamingTest(const char** chunks, 23845 v8::ScriptCompiler::StreamedSource::Encoding encoding = 23846 v8::ScriptCompiler::StreamedSource::ONE_BYTE, 23847 bool expected_success = true, 23848 const char* expected_source_url = NULL, 23849 const char* expected_source_mapping_url = NULL) { 23850 LocalContext env; 23851 v8::Isolate* isolate = env->GetIsolate(); 23852 v8::HandleScope scope(isolate); 23853 v8::TryCatch try_catch(isolate); 23854 23855 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks), 23856 encoding); 23857 v8::ScriptCompiler::ScriptStreamingTask* task = 23858 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 23859 23860 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 23861 // task here in the main thread. 23862 task->Run(); 23863 delete task; 23864 23865 // Possible errors are only produced while compiling. 23866 CHECK_EQ(false, try_catch.HasCaught()); 23867 23868 v8::ScriptOrigin origin(v8_str("http://foo.com")); 23869 char* full_source = TestSourceStream::FullSourceString(chunks); 23870 v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile( 23871 env.local(), &source, v8_str(full_source), origin); 23872 if (expected_success) { 23873 CHECK(!script.IsEmpty()); 23874 v8::Local<Value> result( 23875 script.ToLocalChecked()->Run(env.local()).ToLocalChecked()); 23876 // All scripts are supposed to return the fixed value 13 when ran. 23877 CHECK_EQ(13, result->Int32Value(env.local()).FromJust()); 23878 CheckMagicComments(script.ToLocalChecked(), expected_source_url, 23879 expected_source_mapping_url); 23880 } else { 23881 CHECK(script.IsEmpty()); 23882 CHECK(try_catch.HasCaught()); 23883 } 23884 delete[] full_source; 23885 } 23886 23887 23888 TEST(StreamingSimpleScript) { 23889 // This script is unrealistically small, since no one chunk is enough to fill 23890 // the backing buffer of Scanner, let alone overflow it. 23891 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 23892 NULL}; 23893 RunStreamingTest(chunks); 23894 } 23895 23896 23897 TEST(StreamingBiggerScript) { 23898 const char* chunk1 = 23899 "function foo() {\n" 23900 " // Make this chunk sufficiently long so that it will overflow the\n" 23901 " // backing buffer of the Scanner.\n" 23902 " var i = 0;\n" 23903 " var result = 0;\n" 23904 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23905 " result = 0;\n" 23906 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23907 " result = 0;\n" 23908 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23909 " result = 0;\n" 23910 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23911 " return result;\n" 23912 "}\n"; 23913 const char* chunks[] = {chunk1, "foo(); ", NULL}; 23914 RunStreamingTest(chunks); 23915 } 23916 23917 23918 TEST(StreamingScriptWithParseError) { 23919 // Test that parse errors from streamed scripts are propagated correctly. 23920 { 23921 char chunk1[] = 23922 " // This will result in a parse error.\n" 23923 " var if else then foo"; 23924 char chunk2[] = " 13\n"; 23925 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23926 23927 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE, 23928 false); 23929 } 23930 // Test that the next script succeeds normally. 23931 { 23932 char chunk1[] = 23933 " // This will be parsed successfully.\n" 23934 " function foo() { return "; 23935 char chunk2[] = " 13; }\n"; 23936 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23937 23938 RunStreamingTest(chunks); 23939 } 23940 } 23941 23942 23943 TEST(StreamingUtf8Script) { 23944 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers 23945 // don't like it. 23946 const char* chunk1 = 23947 "function foo() {\n" 23948 " // This function will contain an UTF-8 character which is not in\n" 23949 " // ASCII.\n" 23950 " var foob\xec\x92\x81r = 13;\n" 23951 " return foob\xec\x92\x81r;\n" 23952 "}\n"; 23953 const char* chunks[] = {chunk1, "foo(); ", NULL}; 23954 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23955 } 23956 23957 23958 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) { 23959 // A sanity check to prove that the approach of splitting UTF-8 23960 // characters is correct. Here is an UTF-8 character which will take three 23961 // bytes. 23962 const char* reference = "\xec\x92\x81"; 23963 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned. 23964 23965 char chunk1[] = 23966 "function foo() {\n" 23967 " // This function will contain an UTF-8 character which is not in\n" 23968 " // ASCII.\n" 23969 " var foob"; 23970 char chunk2[] = 23971 "XXXr = 13;\n" 23972 " return foob\xec\x92\x81r;\n" 23973 "}\n"; 23974 for (int i = 0; i < 3; ++i) { 23975 chunk2[i] = reference[i]; 23976 } 23977 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23978 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23979 } 23980 23981 23982 TEST(StreamingUtf8ScriptWithSplitCharacters) { 23983 // Stream data where a multi-byte UTF-8 character is split between two data 23984 // chunks. 23985 const char* reference = "\xec\x92\x81"; 23986 char chunk1[] = 23987 "function foo() {\n" 23988 " // This function will contain an UTF-8 character which is not in\n" 23989 " // ASCII.\n" 23990 " var foobX"; 23991 char chunk2[] = 23992 "XXr = 13;\n" 23993 " return foob\xec\x92\x81r;\n" 23994 "}\n"; 23995 chunk1[strlen(chunk1) - 1] = reference[0]; 23996 chunk2[0] = reference[1]; 23997 chunk2[1] = reference[2]; 23998 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23999 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24000 } 24001 24002 24003 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) { 24004 // Tests edge cases which should still be decoded correctly. 24005 24006 // Case 1: a chunk contains only bytes for a split character (and no other 24007 // data). This kind of a chunk would be exceptionally small, but we should 24008 // still decode it correctly. 24009 const char* reference = "\xec\x92\x81"; 24010 // The small chunk is at the beginning of the split character 24011 { 24012 char chunk1[] = 24013 "function foo() {\n" 24014 " // This function will contain an UTF-8 character which is not in\n" 24015 " // ASCII.\n" 24016 " var foob"; 24017 char chunk2[] = "XX"; 24018 char chunk3[] = 24019 "Xr = 13;\n" 24020 " return foob\xec\x92\x81r;\n" 24021 "}\n"; 24022 chunk2[0] = reference[0]; 24023 chunk2[1] = reference[1]; 24024 chunk3[0] = reference[2]; 24025 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 24026 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24027 } 24028 // The small chunk is at the end of a character 24029 { 24030 char chunk1[] = 24031 "function foo() {\n" 24032 " // This function will contain an UTF-8 character which is not in\n" 24033 " // ASCII.\n" 24034 " var foobX"; 24035 char chunk2[] = "XX"; 24036 char chunk3[] = 24037 "r = 13;\n" 24038 " return foob\xec\x92\x81r;\n" 24039 "}\n"; 24040 chunk1[strlen(chunk1) - 1] = reference[0]; 24041 chunk2[0] = reference[1]; 24042 chunk2[1] = reference[2]; 24043 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 24044 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24045 } 24046 // Case 2: the script ends with a multi-byte character. Make sure that it's 24047 // decoded correctly and not just ignored. 24048 { 24049 char chunk1[] = 24050 "var foob\xec\x92\x81 = 13;\n" 24051 "foob\xec\x92\x81"; 24052 const char* chunks[] = {chunk1, NULL}; 24053 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24054 } 24055 } 24056 24057 24058 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { 24059 // Test cases where a UTF-8 character is split over several chunks. Those 24060 // cases are not supported (the embedder should give the data in big enough 24061 // chunks), but we shouldn't crash, just produce a parse error. 24062 const char* reference = "\xec\x92\x81"; 24063 char chunk1[] = 24064 "function foo() {\n" 24065 " // This function will contain an UTF-8 character which is not in\n" 24066 " // ASCII.\n" 24067 " var foobX"; 24068 char chunk2[] = "X"; 24069 char chunk3[] = 24070 "Xr = 13;\n" 24071 " return foob\xec\x92\x81r;\n" 24072 "}\n"; 24073 chunk1[strlen(chunk1) - 1] = reference[0]; 24074 chunk2[0] = reference[1]; 24075 chunk3[0] = reference[2]; 24076 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 24077 24078 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 24079 } 24080 24081 24082 TEST(StreamingProducesParserCache) { 24083 i::FLAG_min_preparse_length = 0; 24084 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 24085 NULL}; 24086 24087 LocalContext env; 24088 v8::Isolate* isolate = env->GetIsolate(); 24089 v8::HandleScope scope(isolate); 24090 24091 v8::ScriptCompiler::StreamedSource source( 24092 new TestSourceStream(chunks), 24093 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 24094 v8::ScriptCompiler::ScriptStreamingTask* task = 24095 v8::ScriptCompiler::StartStreamingScript( 24096 isolate, &source, v8::ScriptCompiler::kProduceParserCache); 24097 24098 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 24099 // task here in the main thread. 24100 task->Run(); 24101 delete task; 24102 24103 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData(); 24104 CHECK(cached_data != NULL); 24105 CHECK(cached_data->data != NULL); 24106 CHECK(!cached_data->rejected); 24107 CHECK_GT(cached_data->length, 0); 24108 } 24109 24110 24111 TEST(StreamingWithDebuggingEnabledLate) { 24112 // The streaming parser can only parse lazily, i.e. inner functions are not 24113 // fully parsed. However, we may compile inner functions eagerly when 24114 // debugging. Make sure that we can deal with this when turning on debugging 24115 // after streaming parser has already finished parsing. 24116 i::FLAG_min_preparse_length = 0; 24117 const char* chunks[] = {"with({x:1}) {", 24118 " var foo = function foo(y) {", 24119 " return x + y;", 24120 " };", 24121 " foo(2);", 24122 "}", 24123 NULL}; 24124 24125 LocalContext env; 24126 v8::Isolate* isolate = env->GetIsolate(); 24127 v8::HandleScope scope(isolate); 24128 v8::TryCatch try_catch(isolate); 24129 24130 v8::ScriptCompiler::StreamedSource source( 24131 new TestSourceStream(chunks), 24132 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 24133 v8::ScriptCompiler::ScriptStreamingTask* task = 24134 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 24135 24136 task->Run(); 24137 delete task; 24138 24139 CHECK(!try_catch.HasCaught()); 24140 24141 v8::ScriptOrigin origin(v8_str("http://foo.com")); 24142 char* full_source = TestSourceStream::FullSourceString(chunks); 24143 24144 EnableDebugger(isolate); 24145 24146 v8::Local<Script> script = 24147 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source), 24148 origin) 24149 .ToLocalChecked(); 24150 24151 Maybe<uint32_t> result = 24152 script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local()); 24153 CHECK_EQ(3U, result.FromMaybe(0)); 24154 24155 delete[] full_source; 24156 24157 DisableDebugger(isolate); 24158 } 24159 24160 24161 TEST(StreamingScriptWithInvalidUtf8) { 24162 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a 24163 // chunk don't produce a crash. 24164 const char* reference = "\xec\x92\x81\x80\x80"; 24165 char chunk1[] = 24166 "function foo() {\n" 24167 " // This function will contain an UTF-8 character which is not in\n" 24168 " // ASCII.\n" 24169 " var foobXXXXX"; // Too many bytes which look like incomplete chars! 24170 char chunk2[] = 24171 "r = 13;\n" 24172 " return foob\xec\x92\x81\x80\x80r;\n" 24173 "}\n"; 24174 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i]; 24175 24176 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 24177 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 24178 } 24179 24180 24181 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) { 24182 // Regression test: Stream data where there are several multi-byte UTF-8 24183 // characters in a sequence and one of them is split between two data chunks. 24184 const char* reference = "\xec\x92\x81"; 24185 char chunk1[] = 24186 "function foo() {\n" 24187 " // This function will contain an UTF-8 character which is not in\n" 24188 " // ASCII.\n" 24189 " var foob\xec\x92\x81X"; 24190 char chunk2[] = 24191 "XXr = 13;\n" 24192 " return foob\xec\x92\x81\xec\x92\x81r;\n" 24193 "}\n"; 24194 chunk1[strlen(chunk1) - 1] = reference[0]; 24195 chunk2[0] = reference[1]; 24196 chunk2[1] = reference[2]; 24197 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 24198 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24199 } 24200 24201 24202 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) { 24203 // Another regression test, similar to the previous one. The difference is 24204 // that the split character is not the last one in the sequence. 24205 const char* reference = "\xec\x92\x81"; 24206 char chunk1[] = 24207 "function foo() {\n" 24208 " // This function will contain an UTF-8 character which is not in\n" 24209 " // ASCII.\n" 24210 " var foobX"; 24211 char chunk2[] = 24212 "XX\xec\x92\x81r = 13;\n" 24213 " return foob\xec\x92\x81\xec\x92\x81r;\n" 24214 "}\n"; 24215 chunk1[strlen(chunk1) - 1] = reference[0]; 24216 chunk2[0] = reference[1]; 24217 chunk2[1] = reference[2]; 24218 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 24219 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 24220 } 24221 24222 24223 TEST(StreamingWithHarmonyScopes) { 24224 // Don't use RunStreamingTest here so that both scripts get to use the same 24225 // LocalContext and HandleScope. 24226 LocalContext env; 24227 v8::Isolate* isolate = env->GetIsolate(); 24228 v8::HandleScope scope(isolate); 24229 24230 // First, run a script with a let variable. 24231 CompileRun("\"use strict\"; let x = 1;"); 24232 24233 // Then stream a script which (erroneously) tries to introduce the same 24234 // variable again. 24235 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL}; 24236 24237 v8::TryCatch try_catch(isolate); 24238 v8::ScriptCompiler::StreamedSource source( 24239 new TestSourceStream(chunks), 24240 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 24241 v8::ScriptCompiler::ScriptStreamingTask* task = 24242 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 24243 task->Run(); 24244 delete task; 24245 24246 // Parsing should succeed (the script will be parsed and compiled in a context 24247 // independent way, so the error is not detected). 24248 CHECK_EQ(false, try_catch.HasCaught()); 24249 24250 v8::ScriptOrigin origin(v8_str("http://foo.com")); 24251 char* full_source = TestSourceStream::FullSourceString(chunks); 24252 v8::Local<Script> script = 24253 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source), 24254 origin) 24255 .ToLocalChecked(); 24256 CHECK(!script.IsEmpty()); 24257 CHECK_EQ(false, try_catch.HasCaught()); 24258 24259 // Running the script exposes the error. 24260 CHECK(script->Run(env.local()).IsEmpty()); 24261 CHECK(try_catch.HasCaught()); 24262 delete[] full_source; 24263 } 24264 24265 24266 TEST(CodeCache) { 24267 v8::Isolate::CreateParams create_params; 24268 create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); 24269 24270 const char* source = "Math.sqrt(4)"; 24271 const char* origin = "code cache test"; 24272 v8::ScriptCompiler::CachedData* cache; 24273 24274 v8::Isolate* isolate1 = v8::Isolate::New(create_params); 24275 { 24276 v8::Isolate::Scope iscope(isolate1); 24277 v8::HandleScope scope(isolate1); 24278 v8::Local<v8::Context> context = v8::Context::New(isolate1); 24279 v8::Context::Scope cscope(context); 24280 v8::Local<v8::String> source_string = v8_str(source); 24281 v8::ScriptOrigin script_origin(v8_str(origin)); 24282 v8::ScriptCompiler::Source source(source_string, script_origin); 24283 v8::ScriptCompiler::CompileOptions option = 24284 v8::ScriptCompiler::kProduceCodeCache; 24285 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked(); 24286 int length = source.GetCachedData()->length; 24287 uint8_t* cache_data = new uint8_t[length]; 24288 memcpy(cache_data, source.GetCachedData()->data, length); 24289 cache = new v8::ScriptCompiler::CachedData( 24290 cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned); 24291 } 24292 isolate1->Dispose(); 24293 24294 v8::Isolate* isolate2 = v8::Isolate::New(create_params); 24295 { 24296 v8::Isolate::Scope iscope(isolate2); 24297 v8::HandleScope scope(isolate2); 24298 v8::Local<v8::Context> context = v8::Context::New(isolate2); 24299 v8::Context::Scope cscope(context); 24300 v8::Local<v8::String> source_string = v8_str(source); 24301 v8::ScriptOrigin script_origin(v8_str(origin)); 24302 v8::ScriptCompiler::Source source(source_string, script_origin, cache); 24303 v8::ScriptCompiler::CompileOptions option = 24304 v8::ScriptCompiler::kConsumeCodeCache; 24305 v8::Local<v8::Script> script; 24306 { 24307 i::DisallowCompilation no_compile( 24308 reinterpret_cast<i::Isolate*>(isolate2)); 24309 script = v8::ScriptCompiler::Compile(context, &source, option) 24310 .ToLocalChecked(); 24311 } 24312 CHECK_EQ(2, script->Run(context) 24313 .ToLocalChecked() 24314 ->ToInt32(context) 24315 .ToLocalChecked() 24316 ->Int32Value(context) 24317 .FromJust()); 24318 } 24319 isolate2->Dispose(); 24320 } 24321 24322 24323 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) { 24324 const char* garbage = "garbage garbage garbage garbage garbage garbage"; 24325 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage); 24326 int length = 16; 24327 v8::ScriptCompiler::CachedData* cached_data = 24328 new v8::ScriptCompiler::CachedData(data, length); 24329 CHECK(!cached_data->rejected); 24330 v8::ScriptOrigin origin(v8_str("origin")); 24331 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data); 24332 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); 24333 v8::Local<v8::Script> script = 24334 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked(); 24335 CHECK(cached_data->rejected); 24336 CHECK_EQ( 24337 42, 24338 script->Run(context).ToLocalChecked()->Int32Value(context).FromJust()); 24339 } 24340 24341 TEST(InvalidParserCacheData) { 24342 v8::V8::Initialize(); 24343 v8::HandleScope scope(CcTest::isolate()); 24344 LocalContext context; 24345 if (i::FLAG_lazy && !(i::FLAG_ignition && i::FLAG_ignition_eager)) { 24346 // Cached parser data is not consumed while parsing eagerly. 24347 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache); 24348 } 24349 } 24350 24351 TEST(InvalidCodeCacheData) { 24352 v8::V8::Initialize(); 24353 v8::HandleScope scope(CcTest::isolate()); 24354 LocalContext context; 24355 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache); 24356 } 24357 24358 24359 TEST(ParserCacheRejectedGracefully) { 24360 // Producing cached parser data while parsing eagerly is not supported. 24361 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return; 24362 24363 i::FLAG_min_preparse_length = 0; 24364 v8::V8::Initialize(); 24365 v8::HandleScope scope(CcTest::isolate()); 24366 LocalContext context; 24367 // Produce valid cached data. 24368 v8::ScriptOrigin origin(v8_str("origin")); 24369 v8::Local<v8::String> source_str = v8_str("function foo() {}"); 24370 v8::ScriptCompiler::Source source(source_str, origin); 24371 v8::Local<v8::Script> script = 24372 v8::ScriptCompiler::Compile(context.local(), &source, 24373 v8::ScriptCompiler::kProduceParserCache) 24374 .ToLocalChecked(); 24375 USE(script); 24376 const v8::ScriptCompiler::CachedData* original_cached_data = 24377 source.GetCachedData(); 24378 CHECK(original_cached_data != NULL); 24379 CHECK(original_cached_data->data != NULL); 24380 CHECK(!original_cached_data->rejected); 24381 CHECK_GT(original_cached_data->length, 0); 24382 // Recompiling the same script with it won't reject the data. 24383 { 24384 v8::ScriptCompiler::Source source_with_cached_data( 24385 source_str, origin, 24386 new v8::ScriptCompiler::CachedData(original_cached_data->data, 24387 original_cached_data->length)); 24388 v8::Local<v8::Script> script = 24389 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data, 24390 v8::ScriptCompiler::kConsumeParserCache) 24391 .ToLocalChecked(); 24392 USE(script); 24393 const v8::ScriptCompiler::CachedData* new_cached_data = 24394 source_with_cached_data.GetCachedData(); 24395 CHECK(new_cached_data != NULL); 24396 CHECK(!new_cached_data->rejected); 24397 } 24398 // Compile an incompatible script with the cached data. The new script doesn't 24399 // have the same starting position for the function as the old one, so the old 24400 // cached data will be incompatible with it and will be rejected. 24401 { 24402 v8::Local<v8::String> incompatible_source_str = 24403 v8_str(" function foo() {}"); 24404 v8::ScriptCompiler::Source source_with_cached_data( 24405 incompatible_source_str, origin, 24406 new v8::ScriptCompiler::CachedData(original_cached_data->data, 24407 original_cached_data->length)); 24408 v8::Local<v8::Script> script = 24409 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data, 24410 v8::ScriptCompiler::kConsumeParserCache) 24411 .ToLocalChecked(); 24412 USE(script); 24413 const v8::ScriptCompiler::CachedData* new_cached_data = 24414 source_with_cached_data.GetCachedData(); 24415 CHECK(new_cached_data != NULL); 24416 CHECK(new_cached_data->rejected); 24417 } 24418 } 24419 24420 24421 TEST(StringConcatOverflow) { 24422 v8::V8::Initialize(); 24423 v8::HandleScope scope(CcTest::isolate()); 24424 RandomLengthOneByteResource* r = 24425 new RandomLengthOneByteResource(i::String::kMaxLength); 24426 v8::Local<v8::String> str = 24427 v8::String::NewExternalOneByte(CcTest::isolate(), r).ToLocalChecked(); 24428 CHECK(!str.IsEmpty()); 24429 v8::TryCatch try_catch(CcTest::isolate()); 24430 v8::Local<v8::String> result = v8::String::Concat(str, str); 24431 CHECK(result.IsEmpty()); 24432 CHECK(!try_catch.HasCaught()); 24433 } 24434 24435 24436 TEST(TurboAsmDisablesNeuter) { 24437 i::FLAG_allow_natives_syntax = true; 24438 v8::V8::Initialize(); 24439 v8::HandleScope scope(CcTest::isolate()); 24440 LocalContext context; 24441 bool should_be_neuterable = !i::FLAG_turbo_asm; 24442 const char* load = 24443 "function Module(stdlib, foreign, heap) {" 24444 " 'use asm';" 24445 " var MEM32 = new stdlib.Int32Array(heap);" 24446 " function load() { return MEM32[0]; }" 24447 " return { load: load };" 24448 "}" 24449 "var buffer = new ArrayBuffer(4);" 24450 "var module = Module(this, {}, buffer);" 24451 "%OptimizeFunctionOnNextCall(module.load);" 24452 "module.load();" 24453 "buffer"; 24454 24455 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>(); 24456 CHECK_EQ(should_be_neuterable, result->IsNeuterable()); 24457 24458 const char* store = 24459 "function Module(stdlib, foreign, heap) {" 24460 " 'use asm';" 24461 " var MEM32 = new stdlib.Int32Array(heap);" 24462 " function store() { MEM32[0] = 0; }" 24463 " return { store: store };" 24464 "}" 24465 "var buffer = new ArrayBuffer(4);" 24466 "var module = Module(this, {}, buffer);" 24467 "%OptimizeFunctionOnNextCall(module.store);" 24468 "module.store();" 24469 "buffer"; 24470 24471 result = CompileRun(store).As<v8::ArrayBuffer>(); 24472 CHECK_EQ(should_be_neuterable, result->IsNeuterable()); 24473 } 24474 24475 24476 TEST(GetPrototypeAccessControl) { 24477 i::FLAG_allow_natives_syntax = true; 24478 v8::Isolate* isolate = CcTest::isolate(); 24479 v8::HandleScope handle_scope(isolate); 24480 LocalContext env; 24481 24482 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); 24483 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked); 24484 24485 CHECK(env->Global() 24486 ->Set(env.local(), v8_str("prohibited"), 24487 obj_template->NewInstance(env.local()).ToLocalChecked()) 24488 .FromJust()); 24489 24490 CHECK(CompileRun( 24491 "function f() { return %_GetPrototype(prohibited); }" 24492 "%OptimizeFunctionOnNextCall(f);" 24493 "f();")->IsNull()); 24494 } 24495 24496 24497 TEST(GetPrototypeHidden) { 24498 i::FLAG_allow_natives_syntax = true; 24499 v8::Isolate* isolate = CcTest::isolate(); 24500 v8::HandleScope handle_scope(isolate); 24501 LocalContext env; 24502 24503 Local<FunctionTemplate> t = FunctionTemplate::New(isolate); 24504 t->SetHiddenPrototype(true); 24505 Local<Object> proto = t->GetFunction(env.local()) 24506 .ToLocalChecked() 24507 ->NewInstance(env.local()) 24508 .ToLocalChecked(); 24509 Local<Object> object = Object::New(isolate); 24510 Local<Object> proto2 = Object::New(isolate); 24511 object->SetPrototype(env.local(), proto).FromJust(); 24512 proto->SetPrototype(env.local(), proto2).FromJust(); 24513 24514 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust()); 24515 CHECK(env->Global()->Set(env.local(), v8_str("proto"), proto).FromJust()); 24516 CHECK(env->Global()->Set(env.local(), v8_str("proto2"), proto2).FromJust()); 24517 24518 v8::Local<v8::Value> result = CompileRun("%_GetPrototype(object)"); 24519 CHECK(result->Equals(env.local(), proto2).FromJust()); 24520 24521 result = CompileRun( 24522 "function f() { return %_GetPrototype(object); }" 24523 "%OptimizeFunctionOnNextCall(f);" 24524 "f()"); 24525 CHECK(result->Equals(env.local(), proto2).FromJust()); 24526 } 24527 24528 24529 TEST(ClassPrototypeCreationContext) { 24530 v8::Isolate* isolate = CcTest::isolate(); 24531 v8::HandleScope handle_scope(isolate); 24532 LocalContext env; 24533 24534 Local<Object> result = Local<Object>::Cast( 24535 CompileRun("'use strict'; class Example { }; Example.prototype")); 24536 CHECK(env.local() == result->CreationContext()); 24537 } 24538 24539 24540 TEST(SimpleStreamingScriptWithSourceURL) { 24541 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n", 24542 "//# sourceURL=bar2.js\n", NULL}; 24543 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, 24544 "bar2.js"); 24545 } 24546 24547 24548 TEST(StreamingScriptWithSplitSourceURL) { 24549 const char* chunks[] = {"function foo() { ret", "urn 13; } f", 24550 "oo();\n//# sourceURL=b", "ar2.js\n", NULL}; 24551 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, 24552 "bar2.js"); 24553 } 24554 24555 24556 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { 24557 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#", 24558 " sourceMappingURL=bar2.js\n", "foo();", NULL}; 24559 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL, 24560 "bar2.js"); 24561 } 24562 24563 24564 TEST(NewStringRangeError) { 24565 v8::Isolate* isolate = CcTest::isolate(); 24566 v8::HandleScope handle_scope(isolate); 24567 const int length = i::String::kMaxLength + 1; 24568 const int buffer_size = length * sizeof(uint16_t); 24569 void* buffer = malloc(buffer_size); 24570 if (buffer == NULL) return; 24571 memset(buffer, 'A', buffer_size); 24572 { 24573 v8::TryCatch try_catch(isolate); 24574 char* data = reinterpret_cast<char*>(buffer); 24575 CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, 24576 length) 24577 .IsEmpty()); 24578 CHECK(!try_catch.HasCaught()); 24579 } 24580 { 24581 v8::TryCatch try_catch(isolate); 24582 uint8_t* data = reinterpret_cast<uint8_t*>(buffer); 24583 CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal, 24584 length) 24585 .IsEmpty()); 24586 CHECK(!try_catch.HasCaught()); 24587 } 24588 { 24589 v8::TryCatch try_catch(isolate); 24590 uint16_t* data = reinterpret_cast<uint16_t*>(buffer); 24591 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal, 24592 length) 24593 .IsEmpty()); 24594 CHECK(!try_catch.HasCaught()); 24595 } 24596 free(buffer); 24597 } 24598 24599 24600 TEST(SealHandleScope) { 24601 v8::Isolate* isolate = CcTest::isolate(); 24602 v8::HandleScope handle_scope(isolate); 24603 LocalContext env; 24604 24605 v8::SealHandleScope seal(isolate); 24606 24607 // Should fail 24608 v8::Local<v8::Object> obj = v8::Object::New(isolate); 24609 24610 USE(obj); 24611 } 24612 24613 24614 TEST(SealHandleScopeNested) { 24615 v8::Isolate* isolate = CcTest::isolate(); 24616 v8::HandleScope handle_scope(isolate); 24617 LocalContext env; 24618 24619 v8::SealHandleScope seal(isolate); 24620 24621 { 24622 v8::HandleScope handle_scope(isolate); 24623 24624 // Should work 24625 v8::Local<v8::Object> obj = v8::Object::New(isolate); 24626 24627 USE(obj); 24628 } 24629 } 24630 24631 24632 static void ExtrasBindingTestRuntimeFunction( 24633 const v8::FunctionCallbackInfo<v8::Value>& args) { 24634 CHECK_EQ( 24635 3, 24636 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust()); 24637 args.GetReturnValue().Set(v8_num(7)); 24638 } 24639 24640 TEST(ExtrasFunctionSource) { 24641 v8::Isolate* isolate = CcTest::isolate(); 24642 v8::HandleScope handle_scope(isolate); 24643 LocalContext env; 24644 24645 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24646 24647 // Functions defined in extras do not expose source code. 24648 auto func = binding->Get(env.local(), v8_str("testFunctionToString")) 24649 .ToLocalChecked() 24650 .As<v8::Function>(); 24651 auto undefined = v8::Undefined(isolate); 24652 auto result = func->Call(env.local(), undefined, 0, {}) 24653 .ToLocalChecked() 24654 .As<v8::String>(); 24655 CHECK(result->StrictEquals(v8_str("function foo() { [native code] }"))); 24656 24657 // Functions defined in extras do not show up in the stack trace. 24658 auto wrapper = binding->Get(env.local(), v8_str("testStackTrace")) 24659 .ToLocalChecked() 24660 .As<v8::Function>(); 24661 CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust()); 24662 ExpectString( 24663 "function f(x) { return wrapper(x) }" 24664 "function g() { return new Error().stack; }" 24665 "f(g)", 24666 "Error\n" 24667 " at g (<anonymous>:1:58)\n" 24668 " at f (<anonymous>:1:24)\n" 24669 " at <anonymous>:1:78"); 24670 } 24671 24672 TEST(ExtrasBindingObject) { 24673 v8::Isolate* isolate = CcTest::isolate(); 24674 v8::HandleScope handle_scope(isolate); 24675 LocalContext env; 24676 24677 // standalone.gypi ensures we include the test-extra.js file, which should 24678 // export the tested functions. 24679 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24680 24681 auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive")) 24682 .ToLocalChecked() 24683 .As<v8::Function>(); 24684 auto undefined = v8::Undefined(isolate); 24685 auto result = func->Call(env.local(), undefined, 0, {}) 24686 .ToLocalChecked() 24687 .As<v8::Number>(); 24688 CHECK_EQ(5, result->Int32Value(env.local()).FromJust()); 24689 24690 v8::Local<v8::FunctionTemplate> runtimeFunction = 24691 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction); 24692 binding->Set(env.local(), v8_str("runtime"), 24693 runtimeFunction->GetFunction(env.local()).ToLocalChecked()) 24694 .FromJust(); 24695 func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime")) 24696 .ToLocalChecked() 24697 .As<v8::Function>(); 24698 result = func->Call(env.local(), undefined, 0, {}) 24699 .ToLocalChecked() 24700 .As<v8::Number>(); 24701 CHECK_EQ(7, result->Int32Value(env.local()).FromJust()); 24702 } 24703 24704 24705 TEST(ExperimentalExtras) { 24706 i::FLAG_experimental_extras = true; 24707 24708 v8::Isolate* isolate = CcTest::isolate(); 24709 v8::HandleScope handle_scope(isolate); 24710 LocalContext env; 24711 24712 // standalone.gypi ensures we include the test-experimental-extra.js file, 24713 // which should export the tested functions. 24714 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24715 24716 auto func = 24717 binding->Get(env.local(), v8_str("testExperimentalExtraShouldReturnTen")) 24718 .ToLocalChecked() 24719 .As<v8::Function>(); 24720 auto undefined = v8::Undefined(isolate); 24721 auto result = func->Call(env.local(), undefined, 0, {}) 24722 .ToLocalChecked() 24723 .As<v8::Number>(); 24724 CHECK_EQ(10, result->Int32Value(env.local()).FromJust()); 24725 24726 v8::Local<v8::FunctionTemplate> runtimeFunction = 24727 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction); 24728 binding->Set(env.local(), v8_str("runtime"), 24729 runtimeFunction->GetFunction(env.local()).ToLocalChecked()) 24730 .FromJust(); 24731 func = binding->Get(env.local(), 24732 v8_str("testExperimentalExtraShouldCallToRuntime")) 24733 .ToLocalChecked() 24734 .As<v8::Function>(); 24735 result = func->Call(env.local(), undefined, 0, {}) 24736 .ToLocalChecked() 24737 .As<v8::Number>(); 24738 CHECK_EQ(7, result->Int32Value(env.local()).FromJust()); 24739 } 24740 24741 24742 TEST(ExtrasUtilsObject) { 24743 LocalContext context; 24744 v8::Isolate* isolate = context->GetIsolate(); 24745 v8::HandleScope handle_scope(isolate); 24746 24747 LocalContext env; 24748 v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); 24749 24750 auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils")) 24751 .ToLocalChecked() 24752 .As<v8::Function>(); 24753 auto undefined = v8::Undefined(isolate); 24754 auto result = func->Call(env.local(), undefined, 0, {}) 24755 .ToLocalChecked() 24756 .As<v8::Object>(); 24757 24758 auto private_symbol = result->Get(env.local(), v8_str("privateSymbol")) 24759 .ToLocalChecked() 24760 .As<v8::Symbol>(); 24761 i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol); 24762 CHECK_EQ(true, ips->IsPrivate()); 24763 24764 CompileRun("var result = 0; function store(x) { result = x; }"); 24765 auto store = CompileRun("store").As<v8::Function>(); 24766 24767 auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise")) 24768 .ToLocalChecked() 24769 .As<v8::Promise>(); 24770 fulfilled_promise->Then(env.local(), store).ToLocalChecked(); 24771 isolate->RunMicrotasks(); 24772 CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust()); 24773 24774 auto fulfilled_promise_2 = 24775 result->Get(env.local(), v8_str("fulfilledPromise2")) 24776 .ToLocalChecked() 24777 .As<v8::Promise>(); 24778 fulfilled_promise_2->Then(env.local(), store).ToLocalChecked(); 24779 isolate->RunMicrotasks(); 24780 CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust()); 24781 24782 auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise")) 24783 .ToLocalChecked() 24784 .As<v8::Promise>(); 24785 rejected_promise->Catch(env.local(), store).ToLocalChecked(); 24786 isolate->RunMicrotasks(); 24787 CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust()); 24788 } 24789 24790 24791 TEST(Map) { 24792 v8::Isolate* isolate = CcTest::isolate(); 24793 v8::HandleScope handle_scope(isolate); 24794 LocalContext env; 24795 24796 v8::Local<v8::Map> map = v8::Map::New(isolate); 24797 CHECK(map->IsObject()); 24798 CHECK(map->IsMap()); 24799 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype"))); 24800 CHECK_EQ(0U, map->Size()); 24801 24802 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])"); 24803 CHECK(val->IsMap()); 24804 map = v8::Local<v8::Map>::Cast(val); 24805 CHECK_EQ(2U, map->Size()); 24806 24807 v8::Local<v8::Array> contents = map->AsArray(); 24808 CHECK_EQ(4U, contents->Length()); 24809 CHECK_EQ( 24810 1, 24811 contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value()); 24812 CHECK_EQ( 24813 2, 24814 contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value()); 24815 CHECK_EQ( 24816 3, 24817 contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value()); 24818 CHECK_EQ( 24819 4, 24820 contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value()); 24821 24822 CHECK_EQ(2U, map->Size()); 24823 24824 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); 24825 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); 24826 24827 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); 24828 CHECK(!map->Has(env.local(), map).FromJust()); 24829 24830 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1)) 24831 .ToLocalChecked() 24832 ->Int32Value(env.local()) 24833 .FromJust()); 24834 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3)) 24835 .ToLocalChecked() 24836 ->Int32Value(env.local()) 24837 .FromJust()); 24838 24839 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42)) 24840 .ToLocalChecked() 24841 ->IsUndefined()); 24842 24843 CHECK(!map->Set(env.local(), map, map).IsEmpty()); 24844 CHECK_EQ(3U, map->Size()); 24845 CHECK(map->Has(env.local(), map).FromJust()); 24846 24847 CHECK(map->Delete(env.local(), map).FromJust()); 24848 CHECK_EQ(2U, map->Size()); 24849 CHECK(!map->Has(env.local(), map).FromJust()); 24850 CHECK(!map->Delete(env.local(), map).FromJust()); 24851 24852 map->Clear(); 24853 CHECK_EQ(0U, map->Size()); 24854 } 24855 24856 24857 TEST(Set) { 24858 v8::Isolate* isolate = CcTest::isolate(); 24859 v8::HandleScope handle_scope(isolate); 24860 LocalContext env; 24861 24862 v8::Local<v8::Set> set = v8::Set::New(isolate); 24863 CHECK(set->IsObject()); 24864 CHECK(set->IsSet()); 24865 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype"))); 24866 CHECK_EQ(0U, set->Size()); 24867 24868 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])"); 24869 CHECK(val->IsSet()); 24870 set = v8::Local<v8::Set>::Cast(val); 24871 CHECK_EQ(2U, set->Size()); 24872 24873 v8::Local<v8::Array> keys = set->AsArray(); 24874 CHECK_EQ(2U, keys->Length()); 24875 CHECK_EQ(1, 24876 keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value()); 24877 CHECK_EQ(2, 24878 keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value()); 24879 24880 CHECK_EQ(2U, set->Size()); 24881 24882 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust()); 24883 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust()); 24884 24885 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust()); 24886 CHECK(!set->Has(env.local(), set).FromJust()); 24887 24888 CHECK(!set->Add(env.local(), set).IsEmpty()); 24889 CHECK_EQ(3U, set->Size()); 24890 CHECK(set->Has(env.local(), set).FromJust()); 24891 24892 CHECK(set->Delete(env.local(), set).FromJust()); 24893 CHECK_EQ(2U, set->Size()); 24894 CHECK(!set->Has(env.local(), set).FromJust()); 24895 CHECK(!set->Delete(env.local(), set).FromJust()); 24896 24897 set->Clear(); 24898 CHECK_EQ(0U, set->Size()); 24899 } 24900 24901 TEST(SetDeleteThenAsArray) { 24902 // https://bugs.chromium.org/p/v8/issues/detail?id=4946 24903 v8::Isolate* isolate = CcTest::isolate(); 24904 v8::HandleScope handle_scope(isolate); 24905 LocalContext env; 24906 24907 // make a Set 24908 v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])"); 24909 v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val); 24910 CHECK_EQ(3U, set->Size()); 24911 24912 // delete the "middle" element (using AsArray to 24913 // determine which element is the "middle" element) 24914 v8::Local<v8::Array> array1 = set->AsArray(); 24915 CHECK_EQ(3U, array1->Length()); 24916 CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked()) 24917 .FromJust()); 24918 24919 // make sure there are no undefined values when we convert to an array again. 24920 v8::Local<v8::Array> array2 = set->AsArray(); 24921 uint32_t length = array2->Length(); 24922 CHECK_EQ(2U, length); 24923 for (uint32_t i = 0; i < length; i++) { 24924 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined()); 24925 } 24926 } 24927 24928 TEST(MapDeleteThenAsArray) { 24929 // https://bugs.chromium.org/p/v8/issues/detail?id=4946 24930 v8::Isolate* isolate = CcTest::isolate(); 24931 v8::HandleScope handle_scope(isolate); 24932 LocalContext env; 24933 24934 // make a Map 24935 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])"); 24936 v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val); 24937 CHECK_EQ(3U, map->Size()); 24938 24939 // delete the "middle" element (using AsArray to 24940 // determine which element is the "middle" element) 24941 v8::Local<v8::Array> array1 = map->AsArray(); 24942 CHECK_EQ(6U, array1->Length()); 24943 // Map::AsArray returns a flat array, so the second key is at index 2. 24944 v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked(); 24945 CHECK(map->Delete(env.local(), key).FromJust()); 24946 24947 // make sure there are no undefined values when we convert to an array again. 24948 v8::Local<v8::Array> array2 = map->AsArray(); 24949 uint32_t length = array2->Length(); 24950 CHECK_EQ(4U, length); 24951 for (uint32_t i = 0; i < length; i++) { 24952 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined()); 24953 } 24954 } 24955 24956 TEST(CompatibleReceiverCheckOnCachedICHandler) { 24957 v8::Isolate* isolate = CcTest::isolate(); 24958 v8::HandleScope scope(isolate); 24959 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate); 24960 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent); 24961 auto returns_42 = 24962 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature); 24963 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42); 24964 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate); 24965 child->Inherit(parent); 24966 LocalContext env; 24967 CHECK(env->Global() 24968 ->Set(env.local(), v8_str("Child"), 24969 child->GetFunction(env.local()).ToLocalChecked()) 24970 .FromJust()); 24971 24972 // Make sure there's a compiled stub for "Child.prototype.age" in the cache. 24973 CompileRun( 24974 "var real = new Child();\n" 24975 "for (var i = 0; i < 3; ++i) {\n" 24976 " real.age;\n" 24977 "}\n"); 24978 24979 // Check that the cached stub is never used. 24980 ExpectInt32( 24981 "var fake = Object.create(Child.prototype);\n" 24982 "var result = 0;\n" 24983 "function test(d) {\n" 24984 " if (d == 3) return;\n" 24985 " try {\n" 24986 " fake.age;\n" 24987 " result = 1;\n" 24988 " } catch (e) {\n" 24989 " }\n" 24990 " test(d+1);\n" 24991 "}\n" 24992 "test(0);\n" 24993 "result;\n", 24994 0); 24995 } 24996 24997 THREADED_TEST(ReceiverConversionForAccessors) { 24998 LocalContext env; 24999 v8::Isolate* isolate = CcTest::isolate(); 25000 v8::HandleScope scope(isolate); 25001 Local<v8::FunctionTemplate> acc = 25002 v8::FunctionTemplate::New(isolate, Returns42); 25003 CHECK(env->Global() 25004 ->Set(env.local(), v8_str("acc"), 25005 acc->GetFunction(env.local()).ToLocalChecked()) 25006 .FromJust()); 25007 25008 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 25009 templ->SetAccessorProperty(v8_str("acc"), acc, acc); 25010 Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked(); 25011 25012 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust()); 25013 CHECK(CompileRun("(p.acc == 42)")->BooleanValue(env.local()).FromJust()); 25014 CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(env.local()).FromJust()); 25015 25016 CHECK(!CompileRun("Number.prototype.__proto__ = p;" 25017 "var a = 1;") 25018 .IsEmpty()); 25019 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust()); 25020 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust()); 25021 25022 CHECK(!CompileRun("Boolean.prototype.__proto__ = p;" 25023 "var a = true;") 25024 .IsEmpty()); 25025 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust()); 25026 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust()); 25027 25028 CHECK(!CompileRun("String.prototype.__proto__ = p;" 25029 "var a = 'foo';") 25030 .IsEmpty()); 25031 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust()); 25032 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust()); 25033 25034 CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(env.local()).FromJust()); 25035 CHECK(CompileRun("acc.call(true)==42")->BooleanValue(env.local()).FromJust()); 25036 CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(env.local()).FromJust()); 25037 CHECK( 25038 CompileRun("acc.call(null) == 42")->BooleanValue(env.local()).FromJust()); 25039 CHECK(CompileRun("acc.call(undefined) == 42") 25040 ->BooleanValue(env.local()) 25041 .FromJust()); 25042 } 25043 25044 class FutexInterruptionThread : public v8::base::Thread { 25045 public: 25046 explicit FutexInterruptionThread(v8::Isolate* isolate) 25047 : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {} 25048 25049 virtual void Run() { 25050 // Wait a bit before terminating. 25051 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100)); 25052 isolate_->TerminateExecution(); 25053 } 25054 25055 private: 25056 v8::Isolate* isolate_; 25057 }; 25058 25059 25060 TEST(FutexInterruption) { 25061 i::FLAG_harmony_sharedarraybuffer = true; 25062 v8::Isolate* isolate = CcTest::isolate(); 25063 v8::HandleScope scope(isolate); 25064 LocalContext env; 25065 25066 FutexInterruptionThread timeout_thread(isolate); 25067 25068 v8::TryCatch try_catch(CcTest::isolate()); 25069 timeout_thread.Start(); 25070 25071 CompileRun( 25072 "var ab = new SharedArrayBuffer(4);" 25073 "var i32a = new Int32Array(ab);" 25074 "Atomics.futexWait(i32a, 0, 0);"); 25075 CHECK(try_catch.HasTerminated()); 25076 timeout_thread.Join(); 25077 } 25078 25079 25080 TEST(EstimatedContextSize) { 25081 v8::Isolate* isolate = CcTest::isolate(); 25082 v8::HandleScope scope(isolate); 25083 LocalContext env; 25084 CHECK(50000 < env->EstimatedSize()); 25085 } 25086 25087 25088 static int nb_uncaught_exception_callback_calls = 0; 25089 25090 25091 bool NoAbortOnUncaughtException(v8::Isolate* isolate) { 25092 ++nb_uncaught_exception_callback_calls; 25093 return false; 25094 } 25095 25096 25097 TEST(AbortOnUncaughtExceptionNoAbort) { 25098 v8::Isolate* isolate = CcTest::isolate(); 25099 v8::HandleScope handle_scope(isolate); 25100 v8::Local<v8::ObjectTemplate> global_template = 25101 v8::ObjectTemplate::New(isolate); 25102 LocalContext env(NULL, global_template); 25103 25104 i::FLAG_abort_on_uncaught_exception = true; 25105 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException); 25106 25107 CompileRun("function boom() { throw new Error(\"boom\") }"); 25108 25109 v8::Local<v8::Object> global_object = env->Global(); 25110 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 25111 global_object->Get(env.local(), v8_str("boom")).ToLocalChecked()); 25112 25113 CHECK(foo->Call(env.local(), global_object, 0, NULL).IsEmpty()); 25114 25115 CHECK_EQ(1, nb_uncaught_exception_callback_calls); 25116 } 25117 25118 25119 TEST(AccessCheckedIsConcatSpreadable) { 25120 v8::Isolate* isolate = CcTest::isolate(); 25121 HandleScope scope(isolate); 25122 LocalContext env; 25123 25124 // Object with access check 25125 Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate); 25126 spreadable_template->SetAccessCheckCallback(AccessBlocker); 25127 spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate), 25128 v8::Boolean::New(isolate, true)); 25129 Local<Object> object = 25130 spreadable_template->NewInstance(env.local()).ToLocalChecked(); 25131 25132 allowed_access = true; 25133 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust()); 25134 object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust(); 25135 object->Set(env.local(), 0U, v8_str("a")).FromJust(); 25136 object->Set(env.local(), 1U, v8_str("b")).FromJust(); 25137 25138 // Access check is allowed, and the object is spread 25139 CompileRun("var result = [].concat(object)"); 25140 ExpectTrue("Array.isArray(result)"); 25141 ExpectString("result[0]", "a"); 25142 ExpectString("result[1]", "b"); 25143 ExpectTrue("result.length === 2"); 25144 ExpectTrue("object[Symbol.isConcatSpreadable]"); 25145 25146 // If access check fails, the value of @@isConcatSpreadable is ignored 25147 allowed_access = false; 25148 CompileRun("var result = [].concat(object)"); 25149 ExpectTrue("Array.isArray(result)"); 25150 ExpectTrue("result[0] === object"); 25151 ExpectTrue("result.length === 1"); 25152 ExpectTrue("object[Symbol.isConcatSpreadable] === undefined"); 25153 } 25154 25155 25156 TEST(AccessCheckedToStringTag) { 25157 v8::Isolate* isolate = CcTest::isolate(); 25158 HandleScope scope(isolate); 25159 LocalContext env; 25160 25161 // Object with access check 25162 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); 25163 object_template->SetAccessCheckCallback(AccessBlocker); 25164 Local<Object> object = 25165 object_template->NewInstance(env.local()).ToLocalChecked(); 25166 25167 allowed_access = true; 25168 env->Global()->Set(env.local(), v8_str("object"), object).FromJust(); 25169 object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello")) 25170 .FromJust(); 25171 25172 // Access check is allowed, and the toStringTag is read 25173 CompileRun("var result = Object.prototype.toString.call(object)"); 25174 ExpectString("result", "[object hello]"); 25175 ExpectString("object[Symbol.toStringTag]", "hello"); 25176 25177 // ToString through the API should succeed too. 25178 String::Utf8Value result_allowed( 25179 object->ObjectProtoToString(env.local()).ToLocalChecked()); 25180 CHECK_EQ(0, strcmp(*result_allowed, "[object hello]")); 25181 25182 // If access check fails, the value of @@toStringTag is ignored 25183 allowed_access = false; 25184 CompileRun("var result = Object.prototype.toString.call(object)"); 25185 ExpectString("result", "[object Object]"); 25186 ExpectTrue("object[Symbol.toStringTag] === undefined"); 25187 25188 // ToString through the API should also fail. 25189 String::Utf8Value result_denied( 25190 object->ObjectProtoToString(env.local()).ToLocalChecked()); 25191 CHECK_EQ(0, strcmp(*result_denied, "[object Object]")); 25192 } 25193 25194 25195 TEST(ObjectTemplateIntrinsics) { 25196 v8::Isolate* isolate = CcTest::isolate(); 25197 v8::HandleScope scope(isolate); 25198 LocalContext env; 25199 25200 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); 25201 object_template->SetIntrinsicDataProperty(v8_str("values"), 25202 v8::kArrayProto_values); 25203 Local<Object> object = 25204 object_template->NewInstance(env.local()).ToLocalChecked(); 25205 25206 CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust()); 25207 ExpectString("typeof obj1.values", "function"); 25208 25209 auto values = Local<Function>::Cast( 25210 object->Get(env.local(), v8_str("values")).ToLocalChecked()); 25211 auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values)); 25212 auto ctx = v8::Utils::OpenHandle(*env.local()); 25213 CHECK_EQ(fn->GetCreationContext(), *ctx); 25214 25215 { 25216 LocalContext env2; 25217 Local<Object> object2 = 25218 object_template->NewInstance(env2.local()).ToLocalChecked(); 25219 CHECK( 25220 env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust()); 25221 ExpectString("typeof obj2.values", "function"); 25222 CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(), 25223 *object2->Get(env2.local(), v8_str("values")).ToLocalChecked()); 25224 25225 auto values2 = Local<Function>::Cast( 25226 object2->Get(env2.local(), v8_str("values")).ToLocalChecked()); 25227 auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2)); 25228 auto ctx2 = v8::Utils::OpenHandle(*env2.local()); 25229 CHECK_EQ(fn2->GetCreationContext(), *ctx2); 25230 } 25231 } 25232 25233 25234 TEST(Proxy) { 25235 LocalContext context; 25236 v8::Isolate* isolate = CcTest::isolate(); 25237 v8::HandleScope scope(isolate); 25238 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>(); 25239 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>(); 25240 25241 v8::Local<v8::Proxy> proxy = 25242 v8::Proxy::New(context.local(), target, handler).ToLocalChecked(); 25243 CHECK(proxy->IsProxy()); 25244 CHECK(!target->IsProxy()); 25245 CHECK(!proxy->IsRevoked()); 25246 CHECK(proxy->GetTarget()->SameValue(target)); 25247 CHECK(proxy->GetHandler()->SameValue(handler)); 25248 25249 proxy->Revoke(); 25250 CHECK(proxy->IsProxy()); 25251 CHECK(!target->IsProxy()); 25252 CHECK(proxy->IsRevoked()); 25253 CHECK(proxy->GetTarget()->SameValue(target)); 25254 CHECK(proxy->GetHandler()->IsNull()); 25255 } 25256 25257 WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter( 25258 v8::Isolate* isolate, WeakCallCounter* counter) { 25259 v8::Locker locker(isolate); 25260 LocalContext env; 25261 HandleScope scope(isolate); 25262 WeakCallCounterAndPersistent<Value>* val = 25263 new WeakCallCounterAndPersistent<Value>(counter); 25264 val->handle.Reset(isolate, Object::New(isolate)); 25265 val->handle.SetWeak(val, &WeakPointerCallback, 25266 v8::WeakCallbackType::kParameter); 25267 return val; 25268 } 25269 25270 class MemoryPressureThread : public v8::base::Thread { 25271 public: 25272 explicit MemoryPressureThread(v8::Isolate* isolate, 25273 v8::MemoryPressureLevel level) 25274 : Thread(Options("MemoryPressureThread")), 25275 isolate_(isolate), 25276 level_(level) {} 25277 25278 virtual void Run() { isolate_->MemoryPressureNotification(level_); } 25279 25280 private: 25281 v8::Isolate* isolate_; 25282 v8::MemoryPressureLevel level_; 25283 }; 25284 25285 TEST(MemoryPressure) { 25286 v8::Isolate* isolate = CcTest::isolate(); 25287 WeakCallCounter counter(1234); 25288 25289 // Check that critical memory pressure notification sets GC interrupt. 25290 auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter); 25291 CHECK(!v8::Locker::IsLocked(isolate)); 25292 { 25293 v8::Locker locker(isolate); 25294 v8::HandleScope scope(isolate); 25295 LocalContext env; 25296 MemoryPressureThread memory_pressure_thread( 25297 isolate, v8::MemoryPressureLevel::kCritical); 25298 memory_pressure_thread.Start(); 25299 memory_pressure_thread.Join(); 25300 // This should trigger GC. 25301 CHECK_EQ(0, counter.NumberOfWeakCalls()); 25302 CompileRun("(function noop() { return 0; })()"); 25303 CHECK_EQ(1, counter.NumberOfWeakCalls()); 25304 } 25305 delete garbage; 25306 // Check that critical memory pressure notification triggers GC. 25307 garbage = CreateGarbageWithWeakCallCounter(isolate, &counter); 25308 { 25309 v8::Locker locker(isolate); 25310 // If isolate is locked, memory pressure notification should trigger GC. 25311 CHECK_EQ(1, counter.NumberOfWeakCalls()); 25312 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical); 25313 CHECK_EQ(2, counter.NumberOfWeakCalls()); 25314 } 25315 delete garbage; 25316 // Check that moderate memory pressure notification sets GC into memory 25317 // optimizing mode. 25318 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate); 25319 CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage()); 25320 // Check that disabling memory pressure returns GC into normal mode. 25321 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone); 25322 CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage()); 25323 } 25324 25325 TEST(SetIntegrityLevel) { 25326 LocalContext context; 25327 v8::Isolate* isolate = CcTest::isolate(); 25328 v8::HandleScope scope(isolate); 25329 25330 v8::Local<v8::Object> obj = v8::Object::New(isolate); 25331 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust()); 25332 25333 v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)"); 25334 CHECK(!is_frozen->BooleanValue(context.local()).FromJust()); 25335 25336 CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen) 25337 .FromJust()); 25338 25339 is_frozen = CompileRun("Object.isFrozen(o)"); 25340 CHECK(is_frozen->BooleanValue(context.local()).FromJust()); 25341 } 25342 25343 TEST(PrivateForApiIsNumber) { 25344 LocalContext context; 25345 v8::Isolate* isolate = CcTest::isolate(); 25346 v8::HandleScope scope(isolate); 25347 25348 // Shouldn't crash. 25349 v8::Private::ForApi(isolate, v8_str("42")); 25350 } 25351