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(