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 "src/v8.h" 34 35 #if V8_OS_POSIX 36 #include <unistd.h> // NOLINT 37 #endif 38 39 #include "include/v8-util.h" 40 #include "src/api.h" 41 #include "src/arguments.h" 42 #include "src/base/platform/platform.h" 43 #include "src/compilation-cache.h" 44 #include "src/cpu-profiler.h" 45 #include "src/execution.h" 46 #include "src/isolate.h" 47 #include "src/objects.h" 48 #include "src/parser.h" 49 #include "src/snapshot.h" 50 #include "src/unicode-inl.h" 51 #include "src/utils.h" 52 #include "src/vm-state.h" 53 #include "test/cctest/cctest.h" 54 55 static const bool kLogThreading = false; 56 57 using ::v8::Boolean; 58 using ::v8::BooleanObject; 59 using ::v8::Context; 60 using ::v8::Extension; 61 using ::v8::Function; 62 using ::v8::FunctionTemplate; 63 using ::v8::Handle; 64 using ::v8::HandleScope; 65 using ::v8::Local; 66 using ::v8::Name; 67 using ::v8::Message; 68 using ::v8::MessageCallback; 69 using ::v8::Object; 70 using ::v8::ObjectTemplate; 71 using ::v8::Persistent; 72 using ::v8::Script; 73 using ::v8::StackTrace; 74 using ::v8::String; 75 using ::v8::Symbol; 76 using ::v8::TryCatch; 77 using ::v8::Undefined; 78 using ::v8::UniqueId; 79 using ::v8::V8; 80 using ::v8::Value; 81 82 83 #define THREADED_PROFILED_TEST(Name) \ 84 static void Test##Name(); \ 85 TEST(Name##WithProfiler) { \ 86 RunWithProfiler(&Test##Name); \ 87 } \ 88 THREADED_TEST(Name) 89 90 91 void RunWithProfiler(void (*test)()) { 92 LocalContext env; 93 v8::HandleScope scope(env->GetIsolate()); 94 v8::Local<v8::String> profile_name = 95 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1"); 96 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 97 98 cpu_profiler->StartProfiling(profile_name); 99 (*test)(); 100 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles(); 101 } 102 103 104 static int signature_callback_count; 105 static Local<Value> signature_expected_receiver; 106 static void IncrementingSignatureCallback( 107 const v8::FunctionCallbackInfo<v8::Value>& args) { 108 ApiTestFuzzer::Fuzz(); 109 signature_callback_count++; 110 CHECK_EQ(signature_expected_receiver, args.Holder()); 111 CHECK_EQ(signature_expected_receiver, args.This()); 112 v8::Handle<v8::Array> result = 113 v8::Array::New(args.GetIsolate(), args.Length()); 114 for (int i = 0; i < args.Length(); i++) 115 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]); 116 args.GetReturnValue().Set(result); 117 } 118 119 120 static void SignatureCallback( 121 const v8::FunctionCallbackInfo<v8::Value>& args) { 122 ApiTestFuzzer::Fuzz(); 123 v8::Handle<v8::Array> result = 124 v8::Array::New(args.GetIsolate(), args.Length()); 125 for (int i = 0; i < args.Length(); i++) { 126 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]); 127 } 128 args.GetReturnValue().Set(result); 129 } 130 131 132 // Tests that call v8::V8::Dispose() cannot be threaded. 133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) { 134 CHECK(v8::V8::Initialize()); 135 CHECK(v8::V8::Dispose()); 136 } 137 138 139 // Tests that call v8::V8::Dispose() cannot be threaded. 140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) { 141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 142 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 143 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 145 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 146 } 147 148 149 THREADED_TEST(Handles) { 150 v8::HandleScope scope(CcTest::isolate()); 151 Local<Context> local_env; 152 { 153 LocalContext env; 154 local_env = env.local(); 155 } 156 157 // Local context should still be live. 158 CHECK(!local_env.IsEmpty()); 159 local_env->Enter(); 160 161 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); 162 CHECK(!undef.IsEmpty()); 163 CHECK(undef->IsUndefined()); 164 165 const char* source = "1 + 2 + 3"; 166 Local<Script> script = v8_compile(source); 167 CHECK_EQ(6, script->Run()->Int32Value()); 168 169 local_env->Exit(); 170 } 171 172 173 THREADED_TEST(IsolateOfContext) { 174 v8::HandleScope scope(CcTest::isolate()); 175 v8::Handle<Context> env = Context::New(CcTest::isolate()); 176 177 CHECK(!env->GetIsolate()->InContext()); 178 CHECK(env->GetIsolate() == CcTest::isolate()); 179 env->Enter(); 180 CHECK(env->GetIsolate()->InContext()); 181 CHECK(env->GetIsolate() == CcTest::isolate()); 182 env->Exit(); 183 CHECK(!env->GetIsolate()->InContext()); 184 CHECK(env->GetIsolate() == CcTest::isolate()); 185 } 186 187 188 static void TestSignature(const char* loop_js, Local<Value> receiver) { 189 i::ScopedVector<char> source(200); 190 i::SNPrintF(source, 191 "for (var i = 0; i < 10; i++) {" 192 " %s" 193 "}", 194 loop_js); 195 signature_callback_count = 0; 196 signature_expected_receiver = receiver; 197 bool expected_to_throw = receiver.IsEmpty(); 198 v8::TryCatch try_catch; 199 CompileRun(source.start()); 200 CHECK_EQ(expected_to_throw, try_catch.HasCaught()); 201 if (!expected_to_throw) { 202 CHECK_EQ(10, signature_callback_count); 203 } else { 204 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 205 try_catch.Exception()->ToString()); 206 } 207 } 208 209 210 THREADED_TEST(ReceiverSignature) { 211 LocalContext env; 212 v8::Isolate* isolate = env->GetIsolate(); 213 v8::HandleScope scope(isolate); 214 // Setup templates. 215 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 216 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun); 217 v8::Handle<v8::FunctionTemplate> callback_sig = 218 v8::FunctionTemplate::New( 219 isolate, IncrementingSignatureCallback, Local<Value>(), sig); 220 v8::Handle<v8::FunctionTemplate> callback = 221 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback); 222 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate); 223 sub_fun->Inherit(fun); 224 v8::Handle<v8::FunctionTemplate> unrel_fun = 225 v8::FunctionTemplate::New(isolate); 226 // Install properties. 227 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); 228 fun_proto->Set(v8_str("prop_sig"), callback_sig); 229 fun_proto->Set(v8_str("prop"), callback); 230 fun_proto->SetAccessorProperty( 231 v8_str("accessor_sig"), callback_sig, callback_sig); 232 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); 233 // Instantiate templates. 234 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance(); 235 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance(); 236 // Setup global variables. 237 env->Global()->Set(v8_str("Fun"), fun->GetFunction()); 238 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); 239 env->Global()->Set(v8_str("fun_instance"), fun_instance); 240 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance); 241 CompileRun( 242 "var accessor_sig_key = 'accessor_sig';" 243 "var accessor_key = 'accessor';" 244 "var prop_sig_key = 'prop_sig';" 245 "var prop_key = 'prop';" 246 "" 247 "function copy_props(obj) {" 248 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" 249 " var source = Fun.prototype;" 250 " for (var i in keys) {" 251 " var key = keys[i];" 252 " var desc = Object.getOwnPropertyDescriptor(source, key);" 253 " Object.defineProperty(obj, key, desc);" 254 " }" 255 "}" 256 "" 257 "var obj = {};" 258 "copy_props(obj);" 259 "var unrel = new UnrelFun();" 260 "copy_props(unrel);"); 261 // Test with and without ICs 262 const char* test_objects[] = { 263 "fun_instance", "sub_fun_instance", "obj", "unrel" }; 264 unsigned bad_signature_start_offset = 2; 265 for (unsigned i = 0; i < arraysize(test_objects); i++) { 266 i::ScopedVector<char> source(200); 267 i::SNPrintF( 268 source, "var test_object = %s; test_object", test_objects[i]); 269 Local<Value> test_object = CompileRun(source.start()); 270 TestSignature("test_object.prop();", test_object); 271 TestSignature("test_object.accessor;", test_object); 272 TestSignature("test_object[accessor_key];", test_object); 273 TestSignature("test_object.accessor = 1;", test_object); 274 TestSignature("test_object[accessor_key] = 1;", test_object); 275 if (i >= bad_signature_start_offset) test_object = Local<Value>(); 276 TestSignature("test_object.prop_sig();", test_object); 277 TestSignature("test_object.accessor_sig;", test_object); 278 TestSignature("test_object[accessor_sig_key];", test_object); 279 TestSignature("test_object.accessor_sig = 1;", test_object); 280 TestSignature("test_object[accessor_sig_key] = 1;", test_object); 281 } 282 } 283 284 285 THREADED_TEST(ArgumentSignature) { 286 LocalContext env; 287 v8::Isolate* isolate = env->GetIsolate(); 288 v8::HandleScope scope(isolate); 289 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate); 290 cons->SetClassName(v8_str("Cons")); 291 v8::Handle<v8::Signature> sig = v8::Signature::New( 292 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons); 293 v8::Handle<v8::FunctionTemplate> fun = 294 v8::FunctionTemplate::New(isolate, 295 SignatureCallback, 296 v8::Handle<Value>(), 297 sig); 298 env->Global()->Set(v8_str("Cons"), cons->GetFunction()); 299 env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); 300 301 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); 302 CHECK(value1->IsTrue()); 303 304 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); 305 CHECK(value2->IsTrue()); 306 307 v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); 308 CHECK(value3->IsTrue()); 309 310 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate); 311 cons1->SetClassName(v8_str("Cons1")); 312 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate); 313 cons2->SetClassName(v8_str("Cons2")); 314 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate); 315 cons3->SetClassName(v8_str("Cons3")); 316 317 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; 318 v8::Handle<v8::Signature> wsig = v8::Signature::New( 319 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args); 320 v8::Handle<v8::FunctionTemplate> fun2 = 321 v8::FunctionTemplate::New(isolate, 322 SignatureCallback, 323 v8::Handle<Value>(), 324 wsig); 325 326 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); 327 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); 328 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); 329 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); 330 v8::Handle<Value> value4 = CompileRun( 331 "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" 332 "'[object Cons1],[object Cons2],[object Cons3]'"); 333 CHECK(value4->IsTrue()); 334 335 v8::Handle<Value> value5 = CompileRun( 336 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); 337 CHECK(value5->IsTrue()); 338 339 v8::Handle<Value> value6 = CompileRun( 340 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); 341 CHECK(value6->IsTrue()); 342 343 v8::Handle<Value> value7 = CompileRun( 344 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " 345 "'[object Cons1],[object Cons2],[object Cons3],d';"); 346 CHECK(value7->IsTrue()); 347 348 v8::Handle<Value> value8 = CompileRun( 349 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); 350 CHECK(value8->IsTrue()); 351 } 352 353 354 THREADED_TEST(HulIgennem) { 355 LocalContext env; 356 v8::Isolate* isolate = env->GetIsolate(); 357 v8::HandleScope scope(isolate); 358 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate); 359 Local<String> undef_str = undef->ToString(); 360 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 361 undef_str->WriteUtf8(value); 362 CHECK_EQ(0, strcmp(value, "undefined")); 363 i::DeleteArray(value); 364 } 365 366 367 THREADED_TEST(Access) { 368 LocalContext env; 369 v8::Isolate* isolate = env->GetIsolate(); 370 v8::HandleScope scope(isolate); 371 Local<v8::Object> obj = v8::Object::New(isolate); 372 Local<Value> foo_before = obj->Get(v8_str("foo")); 373 CHECK(foo_before->IsUndefined()); 374 Local<String> bar_str = v8_str("bar"); 375 obj->Set(v8_str("foo"), bar_str); 376 Local<Value> foo_after = obj->Get(v8_str("foo")); 377 CHECK(!foo_after->IsUndefined()); 378 CHECK(foo_after->IsString()); 379 CHECK_EQ(bar_str, foo_after); 380 } 381 382 383 THREADED_TEST(AccessElement) { 384 LocalContext env; 385 v8::HandleScope scope(env->GetIsolate()); 386 Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 387 Local<Value> before = obj->Get(1); 388 CHECK(before->IsUndefined()); 389 Local<String> bar_str = v8_str("bar"); 390 obj->Set(1, bar_str); 391 Local<Value> after = obj->Get(1); 392 CHECK(!after->IsUndefined()); 393 CHECK(after->IsString()); 394 CHECK_EQ(bar_str, after); 395 396 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 397 CHECK_EQ(v8_str("a"), value->Get(0)); 398 CHECK_EQ(v8_str("b"), value->Get(1)); 399 } 400 401 402 THREADED_TEST(Script) { 403 LocalContext env; 404 v8::HandleScope scope(env->GetIsolate()); 405 const char* source = "1 + 2 + 3"; 406 Local<Script> script = v8_compile(source); 407 CHECK_EQ(6, script->Run()->Int32Value()); 408 } 409 410 411 class TestResource: public String::ExternalStringResource { 412 public: 413 explicit TestResource(uint16_t* data, int* counter = NULL, 414 bool owning_data = true) 415 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) { 416 while (data[length_]) ++length_; 417 } 418 419 ~TestResource() { 420 if (owning_data_) i::DeleteArray(data_); 421 if (counter_ != NULL) ++*counter_; 422 } 423 424 const uint16_t* data() const { 425 return data_; 426 } 427 428 size_t length() const { 429 return length_; 430 } 431 432 private: 433 uint16_t* data_; 434 size_t length_; 435 int* counter_; 436 bool owning_data_; 437 }; 438 439 440 class TestOneByteResource : public String::ExternalOneByteStringResource { 441 public: 442 explicit TestOneByteResource(const char* data, int* counter = NULL, 443 size_t offset = 0) 444 : orig_data_(data), 445 data_(data + offset), 446 length_(strlen(data) - offset), 447 counter_(counter) {} 448 449 ~TestOneByteResource() { 450 i::DeleteArray(orig_data_); 451 if (counter_ != NULL) ++*counter_; 452 } 453 454 const char* data() const { 455 return data_; 456 } 457 458 size_t length() const { 459 return length_; 460 } 461 462 private: 463 const char* orig_data_; 464 const char* data_; 465 size_t length_; 466 int* counter_; 467 }; 468 469 470 THREADED_TEST(ScriptUsingStringResource) { 471 int dispose_count = 0; 472 const char* c_source = "1 + 2 * 3"; 473 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 474 { 475 LocalContext env; 476 v8::HandleScope scope(env->GetIsolate()); 477 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 478 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 479 Local<Script> script = v8_compile(source); 480 Local<Value> value = script->Run(); 481 CHECK(value->IsNumber()); 482 CHECK_EQ(7, value->Int32Value()); 483 CHECK(source->IsExternal()); 484 CHECK_EQ(resource, 485 static_cast<TestResource*>(source->GetExternalStringResource())); 486 String::Encoding encoding = String::UNKNOWN_ENCODING; 487 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 488 source->GetExternalStringResourceBase(&encoding)); 489 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 490 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 491 CHECK_EQ(0, dispose_count); 492 } 493 CcTest::i_isolate()->compilation_cache()->Clear(); 494 CcTest::heap()->CollectAllAvailableGarbage(); 495 CHECK_EQ(1, dispose_count); 496 } 497 498 499 THREADED_TEST(ScriptUsingOneByteStringResource) { 500 int dispose_count = 0; 501 const char* c_source = "1 + 2 * 3"; 502 { 503 LocalContext env; 504 v8::HandleScope scope(env->GetIsolate()); 505 TestOneByteResource* resource = 506 new TestOneByteResource(i::StrDup(c_source), &dispose_count); 507 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 508 CHECK(source->IsExternalOneByte()); 509 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 510 source->GetExternalOneByteStringResource()); 511 String::Encoding encoding = String::UNKNOWN_ENCODING; 512 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 513 source->GetExternalStringResourceBase(&encoding)); 514 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 515 Local<Script> script = v8_compile(source); 516 Local<Value> value = script->Run(); 517 CHECK(value->IsNumber()); 518 CHECK_EQ(7, value->Int32Value()); 519 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 520 CHECK_EQ(0, dispose_count); 521 } 522 CcTest::i_isolate()->compilation_cache()->Clear(); 523 CcTest::heap()->CollectAllAvailableGarbage(); 524 CHECK_EQ(1, dispose_count); 525 } 526 527 528 THREADED_TEST(ScriptMakingExternalString) { 529 int dispose_count = 0; 530 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 531 { 532 LocalContext env; 533 v8::HandleScope scope(env->GetIsolate()); 534 Local<String> source = 535 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 536 // Trigger GCs so that the newly allocated string moves to old gen. 537 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 538 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 539 CHECK_EQ(source->IsExternal(), false); 540 CHECK_EQ(source->IsExternalOneByte(), false); 541 String::Encoding encoding = String::UNKNOWN_ENCODING; 542 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); 543 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 544 bool success = source->MakeExternal(new TestResource(two_byte_source, 545 &dispose_count)); 546 CHECK(success); 547 Local<Script> script = v8_compile(source); 548 Local<Value> value = script->Run(); 549 CHECK(value->IsNumber()); 550 CHECK_EQ(7, value->Int32Value()); 551 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 552 CHECK_EQ(0, dispose_count); 553 } 554 CcTest::i_isolate()->compilation_cache()->Clear(); 555 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 556 CHECK_EQ(1, dispose_count); 557 } 558 559 560 THREADED_TEST(ScriptMakingExternalOneByteString) { 561 int dispose_count = 0; 562 const char* c_source = "1 + 2 * 3"; 563 { 564 LocalContext env; 565 v8::HandleScope scope(env->GetIsolate()); 566 Local<String> source = v8_str(c_source); 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 bool success = source->MakeExternal( 571 new TestOneByteResource(i::StrDup(c_source), &dispose_count)); 572 CHECK(success); 573 Local<Script> script = v8_compile(source); 574 Local<Value> value = script->Run(); 575 CHECK(value->IsNumber()); 576 CHECK_EQ(7, value->Int32Value()); 577 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 578 CHECK_EQ(0, dispose_count); 579 } 580 CcTest::i_isolate()->compilation_cache()->Clear(); 581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 582 CHECK_EQ(1, dispose_count); 583 } 584 585 586 TEST(MakingExternalStringConditions) { 587 LocalContext env; 588 v8::HandleScope scope(env->GetIsolate()); 589 590 // Free some space in the new space so that we can check freshness. 591 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 592 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 593 594 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 595 Local<String> small_string = 596 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 597 i::DeleteArray(two_byte_string); 598 599 // We should refuse to externalize newly created small string. 600 CHECK(!small_string->CanMakeExternal()); 601 // Trigger GCs so that the newly allocated string moves to old gen. 602 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 604 // Old space strings should be accepted. 605 CHECK(small_string->CanMakeExternal()); 606 607 two_byte_string = AsciiToTwoByteString("small string 2"); 608 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 609 i::DeleteArray(two_byte_string); 610 611 // We should refuse externalizing newly created small string. 612 CHECK(!small_string->CanMakeExternal()); 613 for (int i = 0; i < 100; i++) { 614 String::Value value(small_string); 615 } 616 // Frequently used strings should be accepted. 617 CHECK(small_string->CanMakeExternal()); 618 619 const int buf_size = 10 * 1024; 620 char* buf = i::NewArray<char>(buf_size); 621 memset(buf, 'a', buf_size); 622 buf[buf_size - 1] = '\0'; 623 624 two_byte_string = AsciiToTwoByteString(buf); 625 Local<String> large_string = 626 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 627 i::DeleteArray(buf); 628 i::DeleteArray(two_byte_string); 629 // Large strings should be immediately accepted. 630 CHECK(large_string->CanMakeExternal()); 631 } 632 633 634 TEST(MakingExternalOneByteStringConditions) { 635 LocalContext env; 636 v8::HandleScope scope(env->GetIsolate()); 637 638 // Free some space in the new space so that we can check freshness. 639 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 640 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 641 642 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1"); 643 // We should refuse to externalize newly created small string. 644 CHECK(!small_string->CanMakeExternal()); 645 // Trigger GCs so that the newly allocated string moves to old gen. 646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 648 // Old space strings should be accepted. 649 CHECK(small_string->CanMakeExternal()); 650 651 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2"); 652 // We should refuse externalizing newly created small string. 653 CHECK(!small_string->CanMakeExternal()); 654 for (int i = 0; i < 100; i++) { 655 String::Value value(small_string); 656 } 657 // Frequently used strings should be accepted. 658 CHECK(small_string->CanMakeExternal()); 659 660 const int buf_size = 10 * 1024; 661 char* buf = i::NewArray<char>(buf_size); 662 memset(buf, 'a', buf_size); 663 buf[buf_size - 1] = '\0'; 664 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf); 665 i::DeleteArray(buf); 666 // Large strings should be immediately accepted. 667 CHECK(large_string->CanMakeExternal()); 668 } 669 670 671 TEST(MakingExternalUnalignedOneByteString) { 672 LocalContext env; 673 v8::HandleScope scope(env->GetIsolate()); 674 675 CompileRun("function cons(a, b) { return a + b; }" 676 "function slice(a) { return a.substring(1); }"); 677 // Create a cons string that will land in old pointer space. 678 Local<String> cons = Local<String>::Cast(CompileRun( 679 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 680 // Create a sliced string that will land in old pointer space. 681 Local<String> slice = Local<String>::Cast(CompileRun( 682 "slice('abcdefghijklmnopqrstuvwxyz');")); 683 684 // Trigger GCs so that the newly allocated string moves to old gen. 685 SimulateFullSpace(CcTest::heap()->old_pointer_space()); 686 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 687 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 688 689 // Turn into external string with unaligned resource data. 690 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 691 bool success = 692 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1)); 693 CHECK(success); 694 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 695 success = 696 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1)); 697 CHECK(success); 698 699 // Trigger GCs and force evacuation. 700 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 701 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 702 } 703 704 705 THREADED_TEST(UsingExternalString) { 706 i::Factory* factory = CcTest::i_isolate()->factory(); 707 { 708 v8::HandleScope scope(CcTest::isolate()); 709 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 710 Local<String> string = String::NewExternal( 711 CcTest::isolate(), new TestResource(two_byte_string)); 712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 713 // Trigger GCs so that the newly allocated string moves to old gen. 714 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 716 i::Handle<i::String> isymbol = 717 factory->InternalizeString(istring); 718 CHECK(isymbol->IsInternalizedString()); 719 } 720 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 722 } 723 724 725 THREADED_TEST(UsingExternalOneByteString) { 726 i::Factory* factory = CcTest::i_isolate()->factory(); 727 { 728 v8::HandleScope scope(CcTest::isolate()); 729 const char* one_byte_string = "test string"; 730 Local<String> string = String::NewExternal( 731 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string))); 732 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 733 // Trigger GCs so that the newly allocated string moves to old gen. 734 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 736 i::Handle<i::String> isymbol = 737 factory->InternalizeString(istring); 738 CHECK(isymbol->IsInternalizedString()); 739 } 740 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 742 } 743 744 745 THREADED_TEST(ScavengeExternalString) { 746 i::FLAG_stress_compaction = false; 747 i::FLAG_gc_global = false; 748 int dispose_count = 0; 749 bool in_new_space = false; 750 { 751 v8::HandleScope scope(CcTest::isolate()); 752 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 753 Local<String> string = String::NewExternal( 754 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count)); 755 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 756 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 757 in_new_space = CcTest::heap()->InNewSpace(*istring); 758 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 759 CHECK_EQ(0, dispose_count); 760 } 761 CcTest::heap()->CollectGarbage( 762 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 763 CHECK_EQ(1, dispose_count); 764 } 765 766 767 THREADED_TEST(ScavengeExternalOneByteString) { 768 i::FLAG_stress_compaction = false; 769 i::FLAG_gc_global = false; 770 int dispose_count = 0; 771 bool in_new_space = false; 772 { 773 v8::HandleScope scope(CcTest::isolate()); 774 const char* one_byte_string = "test string"; 775 Local<String> string = String::NewExternal( 776 CcTest::isolate(), 777 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count)); 778 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 779 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 780 in_new_space = CcTest::heap()->InNewSpace(*istring); 781 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 782 CHECK_EQ(0, dispose_count); 783 } 784 CcTest::heap()->CollectGarbage( 785 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 786 CHECK_EQ(1, dispose_count); 787 } 788 789 790 class TestOneByteResourceWithDisposeControl : public TestOneByteResource { 791 public: 792 // Only used by non-threaded tests, so it can use static fields. 793 static int dispose_calls; 794 static int dispose_count; 795 796 TestOneByteResourceWithDisposeControl(const char* data, bool dispose) 797 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {} 798 799 void Dispose() { 800 ++dispose_calls; 801 if (dispose_) delete this; 802 } 803 private: 804 bool dispose_; 805 }; 806 807 808 int TestOneByteResourceWithDisposeControl::dispose_count = 0; 809 int TestOneByteResourceWithDisposeControl::dispose_calls = 0; 810 811 812 TEST(ExternalStringWithDisposeHandling) { 813 const char* c_source = "1 + 2 * 3"; 814 815 // Use a stack allocated external string resource allocated object. 816 TestOneByteResourceWithDisposeControl::dispose_count = 0; 817 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 818 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 819 { 820 LocalContext env; 821 v8::HandleScope scope(env->GetIsolate()); 822 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack); 823 Local<Script> script = v8_compile(source); 824 Local<Value> value = script->Run(); 825 CHECK(value->IsNumber()); 826 CHECK_EQ(7, value->Int32Value()); 827 CcTest::heap()->CollectAllAvailableGarbage(); 828 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 829 } 830 CcTest::i_isolate()->compilation_cache()->Clear(); 831 CcTest::heap()->CollectAllAvailableGarbage(); 832 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 833 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 834 835 // Use a heap allocated external string resource allocated object. 836 TestOneByteResourceWithDisposeControl::dispose_count = 0; 837 TestOneByteResourceWithDisposeControl::dispose_calls = 0; 838 TestOneByteResource* res_heap = 839 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true); 840 { 841 LocalContext env; 842 v8::HandleScope scope(env->GetIsolate()); 843 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap); 844 Local<Script> script = v8_compile(source); 845 Local<Value> value = script->Run(); 846 CHECK(value->IsNumber()); 847 CHECK_EQ(7, value->Int32Value()); 848 CcTest::heap()->CollectAllAvailableGarbage(); 849 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count); 850 } 851 CcTest::i_isolate()->compilation_cache()->Clear(); 852 CcTest::heap()->CollectAllAvailableGarbage(); 853 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls); 854 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count); 855 } 856 857 858 THREADED_TEST(StringConcat) { 859 { 860 LocalContext env; 861 v8::HandleScope scope(env->GetIsolate()); 862 const char* one_byte_string_1 = "function a_times_t"; 863 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 864 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 865 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 866 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 867 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 868 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 869 Local<String> left = v8_str(one_byte_string_1); 870 871 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 872 Local<String> right = 873 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 874 i::DeleteArray(two_byte_source); 875 876 Local<String> source = String::Concat(left, right); 877 right = String::NewExternal( 878 env->GetIsolate(), 879 new TestOneByteResource(i::StrDup(one_byte_extern_1))); 880 source = String::Concat(source, right); 881 right = String::NewExternal( 882 env->GetIsolate(), 883 new TestResource(AsciiToTwoByteString(two_byte_extern_1))); 884 source = String::Concat(source, right); 885 right = v8_str(one_byte_string_2); 886 source = String::Concat(source, right); 887 888 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 889 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 890 i::DeleteArray(two_byte_source); 891 892 source = String::Concat(source, right); 893 right = String::NewExternal( 894 env->GetIsolate(), 895 new TestResource(AsciiToTwoByteString(two_byte_extern_2))); 896 source = String::Concat(source, right); 897 Local<Script> script = v8_compile(source); 898 Local<Value> value = script->Run(); 899 CHECK(value->IsNumber()); 900 CHECK_EQ(68, value->Int32Value()); 901 } 902 CcTest::i_isolate()->compilation_cache()->Clear(); 903 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 904 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 905 } 906 907 908 THREADED_TEST(GlobalProperties) { 909 LocalContext env; 910 v8::HandleScope scope(env->GetIsolate()); 911 v8::Handle<v8::Object> global = env->Global(); 912 global->Set(v8_str("pi"), v8_num(3.1415926)); 913 Local<Value> pi = global->Get(v8_str("pi")); 914 CHECK_EQ(3.1415926, pi->NumberValue()); 915 } 916 917 918 template<typename T> 919 static void CheckReturnValue(const T& t, i::Address callback) { 920 v8::ReturnValue<v8::Value> rv = t.GetReturnValue(); 921 i::Object** o = *reinterpret_cast<i::Object***>(&rv); 922 CHECK_EQ(CcTest::isolate(), t.GetIsolate()); 923 CHECK_EQ(t.GetIsolate(), rv.GetIsolate()); 924 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 925 // Verify reset 926 bool is_runtime = (*o)->IsTheHole(); 927 rv.Set(true); 928 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined()); 929 rv.Set(v8::Handle<v8::Object>()); 930 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 931 CHECK_EQ(is_runtime, (*o)->IsTheHole()); 932 933 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate()); 934 // If CPU profiler is active check that when API callback is invoked 935 // VMState is set to EXTERNAL. 936 if (isolate->cpu_profiler()->is_profiling()) { 937 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state()); 938 CHECK(isolate->external_callback_scope()); 939 CHECK_EQ(callback, isolate->external_callback_scope()->callback()); 940 } 941 } 942 943 944 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 945 i::Address callback) { 946 ApiTestFuzzer::Fuzz(); 947 CheckReturnValue(info, callback); 948 info.GetReturnValue().Set(v8_str("bad value")); 949 info.GetReturnValue().Set(v8_num(102)); 950 } 951 952 953 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 954 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 955 } 956 957 958 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 959 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 960 } 961 962 static void construct_callback( 963 const v8::FunctionCallbackInfo<Value>& info) { 964 ApiTestFuzzer::Fuzz(); 965 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 966 info.This()->Set(v8_str("x"), v8_num(1)); 967 info.This()->Set(v8_str("y"), v8_num(2)); 968 info.GetReturnValue().Set(v8_str("bad value")); 969 info.GetReturnValue().Set(info.This()); 970 } 971 972 973 static void Return239Callback( 974 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 975 ApiTestFuzzer::Fuzz(); 976 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 977 info.GetReturnValue().Set(v8_str("bad value")); 978 info.GetReturnValue().Set(v8_num(239)); 979 } 980 981 982 template<typename Handler> 983 static void TestFunctionTemplateInitializer(Handler handler, 984 Handler handler_2) { 985 // Test constructor calls. 986 { 987 LocalContext env; 988 v8::Isolate* isolate = env->GetIsolate(); 989 v8::HandleScope scope(isolate); 990 991 Local<v8::FunctionTemplate> fun_templ = 992 v8::FunctionTemplate::New(isolate, handler); 993 Local<Function> fun = fun_templ->GetFunction(); 994 env->Global()->Set(v8_str("obj"), fun); 995 Local<Script> script = v8_compile("obj()"); 996 for (int i = 0; i < 30; i++) { 997 CHECK_EQ(102, script->Run()->Int32Value()); 998 } 999 } 1000 // Use SetCallHandler to initialize a function template, should work like 1001 // the previous one. 1002 { 1003 LocalContext env; 1004 v8::Isolate* isolate = env->GetIsolate(); 1005 v8::HandleScope scope(isolate); 1006 1007 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 1008 fun_templ->SetCallHandler(handler_2); 1009 Local<Function> fun = fun_templ->GetFunction(); 1010 env->Global()->Set(v8_str("obj"), fun); 1011 Local<Script> script = v8_compile("obj()"); 1012 for (int i = 0; i < 30; i++) { 1013 CHECK_EQ(102, script->Run()->Int32Value()); 1014 } 1015 } 1016 } 1017 1018 1019 template<typename Constructor, typename Accessor> 1020 static void TestFunctionTemplateAccessor(Constructor constructor, 1021 Accessor accessor) { 1022 LocalContext env; 1023 v8::HandleScope scope(env->GetIsolate()); 1024 1025 Local<v8::FunctionTemplate> fun_templ = 1026 v8::FunctionTemplate::New(env->GetIsolate(), constructor); 1027 fun_templ->SetClassName(v8_str("funky")); 1028 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 1029 Local<Function> fun = fun_templ->GetFunction(); 1030 env->Global()->Set(v8_str("obj"), fun); 1031 Local<Value> result = v8_compile("(new obj()).toString()")->Run(); 1032 CHECK_EQ(v8_str("[object funky]"), result); 1033 CompileRun("var obj_instance = new obj();"); 1034 Local<Script> script; 1035 script = v8_compile("obj_instance.x"); 1036 for (int i = 0; i < 30; i++) { 1037 CHECK_EQ(1, script->Run()->Int32Value()); 1038 } 1039 script = v8_compile("obj_instance.m"); 1040 for (int i = 0; i < 30; i++) { 1041 CHECK_EQ(239, script->Run()->Int32Value()); 1042 } 1043 } 1044 1045 1046 THREADED_PROFILED_TEST(FunctionTemplate) { 1047 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 1048 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 1049 } 1050 1051 1052 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1053 ApiTestFuzzer::Fuzz(); 1054 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1055 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1056 } 1057 1058 1059 template<typename Callback> 1060 static void TestSimpleCallback(Callback callback) { 1061 LocalContext env; 1062 v8::Isolate* isolate = env->GetIsolate(); 1063 v8::HandleScope scope(isolate); 1064 1065 v8::Handle<v8::ObjectTemplate> object_template = 1066 v8::ObjectTemplate::New(isolate); 1067 object_template->Set(isolate, "callback", 1068 v8::FunctionTemplate::New(isolate, callback)); 1069 v8::Local<v8::Object> object = object_template->NewInstance(); 1070 (*env)->Global()->Set(v8_str("callback_object"), object); 1071 v8::Handle<v8::Script> script; 1072 script = v8_compile("callback_object.callback(17)"); 1073 for (int i = 0; i < 30; i++) { 1074 CHECK_EQ(51424, script->Run()->Int32Value()); 1075 } 1076 script = v8_compile("callback_object.callback(17, 24)"); 1077 for (int i = 0; i < 30; i++) { 1078 CHECK_EQ(51425, script->Run()->Int32Value()); 1079 } 1080 } 1081 1082 1083 THREADED_PROFILED_TEST(SimpleCallback) { 1084 TestSimpleCallback(SimpleCallback); 1085 } 1086 1087 1088 template<typename T> 1089 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1090 1091 // constant return values 1092 static int32_t fast_return_value_int32 = 471; 1093 static uint32_t fast_return_value_uint32 = 571; 1094 static const double kFastReturnValueDouble = 2.7; 1095 // variable return values 1096 static bool fast_return_value_bool = false; 1097 enum ReturnValueOddball { 1098 kNullReturnValue, 1099 kUndefinedReturnValue, 1100 kEmptyStringReturnValue 1101 }; 1102 static ReturnValueOddball fast_return_value_void; 1103 static bool fast_return_value_object_is_empty = false; 1104 1105 // Helper function to avoid compiler error: insufficient contextual information 1106 // to determine type when applying FUNCTION_ADDR to a template function. 1107 static i::Address address_of(v8::FunctionCallback callback) { 1108 return FUNCTION_ADDR(callback); 1109 } 1110 1111 template<> 1112 void FastReturnValueCallback<int32_t>( 1113 const v8::FunctionCallbackInfo<v8::Value>& info) { 1114 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1115 info.GetReturnValue().Set(fast_return_value_int32); 1116 } 1117 1118 template<> 1119 void FastReturnValueCallback<uint32_t>( 1120 const v8::FunctionCallbackInfo<v8::Value>& info) { 1121 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1122 info.GetReturnValue().Set(fast_return_value_uint32); 1123 } 1124 1125 template<> 1126 void FastReturnValueCallback<double>( 1127 const v8::FunctionCallbackInfo<v8::Value>& info) { 1128 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1129 info.GetReturnValue().Set(kFastReturnValueDouble); 1130 } 1131 1132 template<> 1133 void FastReturnValueCallback<bool>( 1134 const v8::FunctionCallbackInfo<v8::Value>& info) { 1135 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1136 info.GetReturnValue().Set(fast_return_value_bool); 1137 } 1138 1139 template<> 1140 void FastReturnValueCallback<void>( 1141 const v8::FunctionCallbackInfo<v8::Value>& info) { 1142 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1143 switch (fast_return_value_void) { 1144 case kNullReturnValue: 1145 info.GetReturnValue().SetNull(); 1146 break; 1147 case kUndefinedReturnValue: 1148 info.GetReturnValue().SetUndefined(); 1149 break; 1150 case kEmptyStringReturnValue: 1151 info.GetReturnValue().SetEmptyString(); 1152 break; 1153 } 1154 } 1155 1156 template<> 1157 void FastReturnValueCallback<Object>( 1158 const v8::FunctionCallbackInfo<v8::Value>& info) { 1159 v8::Handle<v8::Object> object; 1160 if (!fast_return_value_object_is_empty) { 1161 object = Object::New(info.GetIsolate()); 1162 } 1163 info.GetReturnValue().Set(object); 1164 } 1165 1166 template<typename T> 1167 Handle<Value> TestFastReturnValues() { 1168 LocalContext env; 1169 v8::Isolate* isolate = env->GetIsolate(); 1170 v8::EscapableHandleScope scope(isolate); 1171 v8::Handle<v8::ObjectTemplate> object_template = 1172 v8::ObjectTemplate::New(isolate); 1173 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1174 object_template->Set(isolate, "callback", 1175 v8::FunctionTemplate::New(isolate, callback)); 1176 v8::Local<v8::Object> object = object_template->NewInstance(); 1177 (*env)->Global()->Set(v8_str("callback_object"), object); 1178 return scope.Escape(CompileRun("callback_object.callback()")); 1179 } 1180 1181 1182 THREADED_PROFILED_TEST(FastReturnValues) { 1183 LocalContext env; 1184 v8::HandleScope scope(CcTest::isolate()); 1185 v8::Handle<v8::Value> value; 1186 // check int32_t and uint32_t 1187 int32_t int_values[] = { 1188 0, 234, -723, 1189 i::Smi::kMinValue, i::Smi::kMaxValue 1190 }; 1191 for (size_t i = 0; i < arraysize(int_values); i++) { 1192 for (int modifier = -1; modifier <= 1; modifier++) { 1193 int int_value = int_values[i] + modifier; 1194 // check int32_t 1195 fast_return_value_int32 = int_value; 1196 value = TestFastReturnValues<int32_t>(); 1197 CHECK(value->IsInt32()); 1198 CHECK(fast_return_value_int32 == value->Int32Value()); 1199 // check uint32_t 1200 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1201 value = TestFastReturnValues<uint32_t>(); 1202 CHECK(value->IsUint32()); 1203 CHECK(fast_return_value_uint32 == value->Uint32Value()); 1204 } 1205 } 1206 // check double 1207 value = TestFastReturnValues<double>(); 1208 CHECK(value->IsNumber()); 1209 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value()); 1210 // check bool values 1211 for (int i = 0; i < 2; i++) { 1212 fast_return_value_bool = i == 0; 1213 value = TestFastReturnValues<bool>(); 1214 CHECK(value->IsBoolean()); 1215 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value()); 1216 } 1217 // check oddballs 1218 ReturnValueOddball oddballs[] = { 1219 kNullReturnValue, 1220 kUndefinedReturnValue, 1221 kEmptyStringReturnValue 1222 }; 1223 for (size_t i = 0; i < arraysize(oddballs); i++) { 1224 fast_return_value_void = oddballs[i]; 1225 value = TestFastReturnValues<void>(); 1226 switch (fast_return_value_void) { 1227 case kNullReturnValue: 1228 CHECK(value->IsNull()); 1229 break; 1230 case kUndefinedReturnValue: 1231 CHECK(value->IsUndefined()); 1232 break; 1233 case kEmptyStringReturnValue: 1234 CHECK(value->IsString()); 1235 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1236 break; 1237 } 1238 } 1239 // check handles 1240 fast_return_value_object_is_empty = false; 1241 value = TestFastReturnValues<Object>(); 1242 CHECK(value->IsObject()); 1243 fast_return_value_object_is_empty = true; 1244 value = TestFastReturnValues<Object>(); 1245 CHECK(value->IsUndefined()); 1246 } 1247 1248 1249 THREADED_TEST(FunctionTemplateSetLength) { 1250 LocalContext env; 1251 v8::Isolate* isolate = env->GetIsolate(); 1252 v8::HandleScope scope(isolate); 1253 { 1254 Local<v8::FunctionTemplate> fun_templ = 1255 v8::FunctionTemplate::New(isolate, 1256 handle_callback, 1257 Handle<v8::Value>(), 1258 Handle<v8::Signature>(), 1259 23); 1260 Local<Function> fun = fun_templ->GetFunction(); 1261 env->Global()->Set(v8_str("obj"), fun); 1262 Local<Script> script = v8_compile("obj.length"); 1263 CHECK_EQ(23, script->Run()->Int32Value()); 1264 } 1265 { 1266 Local<v8::FunctionTemplate> fun_templ = 1267 v8::FunctionTemplate::New(isolate, handle_callback); 1268 fun_templ->SetLength(22); 1269 Local<Function> fun = fun_templ->GetFunction(); 1270 env->Global()->Set(v8_str("obj"), fun); 1271 Local<Script> script = v8_compile("obj.length"); 1272 CHECK_EQ(22, script->Run()->Int32Value()); 1273 } 1274 { 1275 // Without setting length it defaults to 0. 1276 Local<v8::FunctionTemplate> fun_templ = 1277 v8::FunctionTemplate::New(isolate, handle_callback); 1278 Local<Function> fun = fun_templ->GetFunction(); 1279 env->Global()->Set(v8_str("obj"), fun); 1280 Local<Script> script = v8_compile("obj.length"); 1281 CHECK_EQ(0, script->Run()->Int32Value()); 1282 } 1283 } 1284 1285 1286 static void* expected_ptr; 1287 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1288 void* ptr = v8::External::Cast(*args.Data())->Value(); 1289 CHECK_EQ(expected_ptr, ptr); 1290 args.GetReturnValue().Set(true); 1291 } 1292 1293 1294 static void TestExternalPointerWrapping() { 1295 LocalContext env; 1296 v8::Isolate* isolate = env->GetIsolate(); 1297 v8::HandleScope scope(isolate); 1298 1299 v8::Handle<v8::Value> data = 1300 v8::External::New(isolate, expected_ptr); 1301 1302 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 1303 obj->Set(v8_str("func"), 1304 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction()); 1305 env->Global()->Set(v8_str("obj"), obj); 1306 1307 CHECK(CompileRun( 1308 "function foo() {\n" 1309 " for (var i = 0; i < 13; i++) obj.func();\n" 1310 "}\n" 1311 "foo(), true")->BooleanValue()); 1312 } 1313 1314 1315 THREADED_TEST(ExternalWrap) { 1316 // Check heap allocated object. 1317 int* ptr = new int; 1318 expected_ptr = ptr; 1319 TestExternalPointerWrapping(); 1320 delete ptr; 1321 1322 // Check stack allocated object. 1323 int foo; 1324 expected_ptr = &foo; 1325 TestExternalPointerWrapping(); 1326 1327 // Check not aligned addresses. 1328 const int n = 100; 1329 char* s = new char[n]; 1330 for (int i = 0; i < n; i++) { 1331 expected_ptr = s + i; 1332 TestExternalPointerWrapping(); 1333 } 1334 1335 delete[] s; 1336 1337 // Check several invalid addresses. 1338 expected_ptr = reinterpret_cast<void*>(1); 1339 TestExternalPointerWrapping(); 1340 1341 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1342 TestExternalPointerWrapping(); 1343 1344 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1345 TestExternalPointerWrapping(); 1346 1347 #if defined(V8_HOST_ARCH_X64) 1348 // Check a value with a leading 1 bit in x64 Smi encoding. 1349 expected_ptr = reinterpret_cast<void*>(0x400000000); 1350 TestExternalPointerWrapping(); 1351 1352 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1353 TestExternalPointerWrapping(); 1354 1355 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1356 TestExternalPointerWrapping(); 1357 #endif 1358 } 1359 1360 1361 THREADED_TEST(FindInstanceInPrototypeChain) { 1362 LocalContext env; 1363 v8::Isolate* isolate = env->GetIsolate(); 1364 v8::HandleScope scope(isolate); 1365 1366 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate); 1367 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate); 1368 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate); 1369 derived->Inherit(base); 1370 1371 Local<v8::Function> base_function = base->GetFunction(); 1372 Local<v8::Function> derived_function = derived->GetFunction(); 1373 Local<v8::Function> other_function = other->GetFunction(); 1374 1375 Local<v8::Object> base_instance = base_function->NewInstance(); 1376 Local<v8::Object> derived_instance = derived_function->NewInstance(); 1377 Local<v8::Object> derived_instance2 = derived_function->NewInstance(); 1378 Local<v8::Object> other_instance = other_function->NewInstance(); 1379 derived_instance2->Set(v8_str("__proto__"), derived_instance); 1380 other_instance->Set(v8_str("__proto__"), derived_instance2); 1381 1382 // base_instance is only an instance of base. 1383 CHECK_EQ(base_instance, 1384 base_instance->FindInstanceInPrototypeChain(base)); 1385 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1386 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1387 1388 // derived_instance is an instance of base and derived. 1389 CHECK_EQ(derived_instance, 1390 derived_instance->FindInstanceInPrototypeChain(base)); 1391 CHECK_EQ(derived_instance, 1392 derived_instance->FindInstanceInPrototypeChain(derived)); 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_EQ(derived_instance2, 1401 other_instance->FindInstanceInPrototypeChain(base)); 1402 CHECK_EQ(derived_instance2, 1403 other_instance->FindInstanceInPrototypeChain(derived)); 1404 CHECK_EQ(other_instance, 1405 other_instance->FindInstanceInPrototypeChain(other)); 1406 } 1407 1408 1409 THREADED_TEST(TinyInteger) { 1410 LocalContext env; 1411 v8::Isolate* isolate = env->GetIsolate(); 1412 v8::HandleScope scope(isolate); 1413 1414 int32_t value = 239; 1415 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1416 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1417 1418 value_obj = v8::Integer::New(isolate, value); 1419 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1420 } 1421 1422 1423 THREADED_TEST(BigSmiInteger) { 1424 LocalContext env; 1425 v8::HandleScope scope(env->GetIsolate()); 1426 v8::Isolate* isolate = CcTest::isolate(); 1427 1428 int32_t value = i::Smi::kMaxValue; 1429 // We cannot add one to a Smi::kMaxValue without wrapping. 1430 if (i::SmiValuesAre31Bits()) { 1431 CHECK(i::Smi::IsValid(value)); 1432 CHECK(!i::Smi::IsValid(value + 1)); 1433 1434 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1435 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1436 1437 value_obj = v8::Integer::New(isolate, value); 1438 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1439 } 1440 } 1441 1442 1443 THREADED_TEST(BigInteger) { 1444 LocalContext env; 1445 v8::HandleScope scope(env->GetIsolate()); 1446 v8::Isolate* isolate = CcTest::isolate(); 1447 1448 // We cannot add one to a Smi::kMaxValue without wrapping. 1449 if (i::SmiValuesAre31Bits()) { 1450 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1451 // The code will not be run in that case, due to the "if" guard. 1452 int32_t value = 1453 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1454 CHECK(value > i::Smi::kMaxValue); 1455 CHECK(!i::Smi::IsValid(value)); 1456 1457 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value); 1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1459 1460 value_obj = v8::Integer::New(isolate, value); 1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1462 } 1463 } 1464 1465 1466 THREADED_TEST(TinyUnsignedInteger) { 1467 LocalContext env; 1468 v8::HandleScope scope(env->GetIsolate()); 1469 v8::Isolate* isolate = CcTest::isolate(); 1470 1471 uint32_t value = 239; 1472 1473 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1474 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1475 1476 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1477 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1478 } 1479 1480 1481 THREADED_TEST(BigUnsignedSmiInteger) { 1482 LocalContext env; 1483 v8::HandleScope scope(env->GetIsolate()); 1484 v8::Isolate* isolate = CcTest::isolate(); 1485 1486 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1487 CHECK(i::Smi::IsValid(value)); 1488 CHECK(!i::Smi::IsValid(value + 1)); 1489 1490 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1491 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1492 1493 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1494 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1495 } 1496 1497 1498 THREADED_TEST(BigUnsignedInteger) { 1499 LocalContext env; 1500 v8::HandleScope scope(env->GetIsolate()); 1501 v8::Isolate* isolate = CcTest::isolate(); 1502 1503 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1504 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1505 CHECK(!i::Smi::IsValid(value)); 1506 1507 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1509 1510 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1512 } 1513 1514 1515 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1516 LocalContext env; 1517 v8::HandleScope scope(env->GetIsolate()); 1518 v8::Isolate* isolate = CcTest::isolate(); 1519 1520 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1521 uint32_t value = INT32_MAX_AS_UINT + 1; 1522 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1523 1524 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1525 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1526 1527 value_obj = v8::Integer::NewFromUnsigned(isolate, value); 1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1529 } 1530 1531 1532 THREADED_TEST(IsNativeError) { 1533 LocalContext env; 1534 v8::HandleScope scope(env->GetIsolate()); 1535 v8::Handle<Value> syntax_error = CompileRun( 1536 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1537 CHECK(syntax_error->IsNativeError()); 1538 v8::Handle<Value> not_error = CompileRun("{a:42}"); 1539 CHECK(!not_error->IsNativeError()); 1540 v8::Handle<Value> not_object = CompileRun("42"); 1541 CHECK(!not_object->IsNativeError()); 1542 } 1543 1544 1545 THREADED_TEST(ArgumentsObject) { 1546 LocalContext env; 1547 v8::HandleScope scope(env->GetIsolate()); 1548 v8::Handle<Value> arguments_object = 1549 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;"); 1550 CHECK(arguments_object->IsArgumentsObject()); 1551 v8::Handle<Value> array = CompileRun("[1,2,3]"); 1552 CHECK(!array->IsArgumentsObject()); 1553 v8::Handle<Value> object = CompileRun("{a:42}"); 1554 CHECK(!object->IsArgumentsObject()); 1555 } 1556 1557 1558 THREADED_TEST(IsMapOrSet) { 1559 LocalContext env; 1560 v8::HandleScope scope(env->GetIsolate()); 1561 v8::Handle<Value> map = CompileRun("new Map()"); 1562 v8::Handle<Value> set = CompileRun("new Set()"); 1563 v8::Handle<Value> weak_map = CompileRun("new WeakMap()"); 1564 v8::Handle<Value> weak_set = CompileRun("new WeakSet()"); 1565 CHECK(map->IsMap()); 1566 CHECK(set->IsSet()); 1567 CHECK(weak_map->IsWeakMap()); 1568 CHECK(weak_set->IsWeakSet()); 1569 1570 CHECK(!map->IsSet()); 1571 CHECK(!map->IsWeakMap()); 1572 CHECK(!map->IsWeakSet()); 1573 1574 CHECK(!set->IsMap()); 1575 CHECK(!set->IsWeakMap()); 1576 CHECK(!set->IsWeakSet()); 1577 1578 CHECK(!weak_map->IsMap()); 1579 CHECK(!weak_map->IsSet()); 1580 CHECK(!weak_map->IsWeakSet()); 1581 1582 CHECK(!weak_set->IsMap()); 1583 CHECK(!weak_set->IsSet()); 1584 CHECK(!weak_set->IsWeakMap()); 1585 1586 v8::Handle<Value> object = CompileRun("{a:42}"); 1587 CHECK(!object->IsMap()); 1588 CHECK(!object->IsSet()); 1589 CHECK(!object->IsWeakMap()); 1590 CHECK(!object->IsWeakSet()); 1591 } 1592 1593 1594 THREADED_TEST(StringObject) { 1595 LocalContext env; 1596 v8::HandleScope scope(env->GetIsolate()); 1597 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); 1598 CHECK(boxed_string->IsStringObject()); 1599 v8::Handle<Value> unboxed_string = CompileRun("\"test\""); 1600 CHECK(!unboxed_string->IsStringObject()); 1601 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); 1602 CHECK(!boxed_not_string->IsStringObject()); 1603 v8::Handle<Value> not_object = CompileRun("0"); 1604 CHECK(!not_object->IsStringObject()); 1605 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1606 CHECK(!as_boxed.IsEmpty()); 1607 Local<v8::String> the_string = as_boxed->ValueOf(); 1608 CHECK(!the_string.IsEmpty()); 1609 ExpectObject("\"test\"", the_string); 1610 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1611 CHECK(new_boxed_string->IsStringObject()); 1612 as_boxed = new_boxed_string.As<v8::StringObject>(); 1613 the_string = as_boxed->ValueOf(); 1614 CHECK(!the_string.IsEmpty()); 1615 ExpectObject("\"test\"", the_string); 1616 } 1617 1618 1619 THREADED_TEST(NumberObject) { 1620 LocalContext env; 1621 v8::HandleScope scope(env->GetIsolate()); 1622 v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); 1623 CHECK(boxed_number->IsNumberObject()); 1624 v8::Handle<Value> unboxed_number = CompileRun("42"); 1625 CHECK(!unboxed_number->IsNumberObject()); 1626 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1627 CHECK(!boxed_not_number->IsNumberObject()); 1628 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1629 CHECK(!as_boxed.IsEmpty()); 1630 double the_number = as_boxed->ValueOf(); 1631 CHECK_EQ(42.0, the_number); 1632 v8::Handle<v8::Value> new_boxed_number = 1633 v8::NumberObject::New(env->GetIsolate(), 43); 1634 CHECK(new_boxed_number->IsNumberObject()); 1635 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1636 the_number = as_boxed->ValueOf(); 1637 CHECK_EQ(43.0, the_number); 1638 } 1639 1640 1641 THREADED_TEST(BooleanObject) { 1642 LocalContext env; 1643 v8::HandleScope scope(env->GetIsolate()); 1644 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1645 CHECK(boxed_boolean->IsBooleanObject()); 1646 v8::Handle<Value> unboxed_boolean = CompileRun("true"); 1647 CHECK(!unboxed_boolean->IsBooleanObject()); 1648 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1649 CHECK(!boxed_not_boolean->IsBooleanObject()); 1650 v8::Handle<v8::BooleanObject> as_boxed = 1651 boxed_boolean.As<v8::BooleanObject>(); 1652 CHECK(!as_boxed.IsEmpty()); 1653 bool the_boolean = as_boxed->ValueOf(); 1654 CHECK_EQ(true, the_boolean); 1655 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); 1656 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); 1657 CHECK(boxed_true->IsBooleanObject()); 1658 CHECK(boxed_false->IsBooleanObject()); 1659 as_boxed = boxed_true.As<v8::BooleanObject>(); 1660 CHECK_EQ(true, as_boxed->ValueOf()); 1661 as_boxed = boxed_false.As<v8::BooleanObject>(); 1662 CHECK_EQ(false, as_boxed->ValueOf()); 1663 } 1664 1665 1666 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1667 LocalContext env; 1668 v8::HandleScope scope(env->GetIsolate()); 1669 1670 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); 1671 CHECK(primitive_false->IsBoolean()); 1672 CHECK(!primitive_false->IsBooleanObject()); 1673 CHECK(!primitive_false->BooleanValue()); 1674 CHECK(!primitive_false->IsTrue()); 1675 CHECK(primitive_false->IsFalse()); 1676 1677 Local<Value> false_value = BooleanObject::New(false); 1678 CHECK(!false_value->IsBoolean()); 1679 CHECK(false_value->IsBooleanObject()); 1680 CHECK(false_value->BooleanValue()); 1681 CHECK(!false_value->IsTrue()); 1682 CHECK(!false_value->IsFalse()); 1683 1684 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1685 CHECK(!false_boolean_object->IsBoolean()); 1686 CHECK(false_boolean_object->IsBooleanObject()); 1687 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1688 // CHECK(false_boolean_object->BooleanValue()); 1689 CHECK(!false_boolean_object->ValueOf()); 1690 CHECK(!false_boolean_object->IsTrue()); 1691 CHECK(!false_boolean_object->IsFalse()); 1692 1693 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); 1694 CHECK(primitive_true->IsBoolean()); 1695 CHECK(!primitive_true->IsBooleanObject()); 1696 CHECK(primitive_true->BooleanValue()); 1697 CHECK(primitive_true->IsTrue()); 1698 CHECK(!primitive_true->IsFalse()); 1699 1700 Local<Value> true_value = BooleanObject::New(true); 1701 CHECK(!true_value->IsBoolean()); 1702 CHECK(true_value->IsBooleanObject()); 1703 CHECK(true_value->BooleanValue()); 1704 CHECK(!true_value->IsTrue()); 1705 CHECK(!true_value->IsFalse()); 1706 1707 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1708 CHECK(!true_boolean_object->IsBoolean()); 1709 CHECK(true_boolean_object->IsBooleanObject()); 1710 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1711 // CHECK(true_boolean_object->BooleanValue()); 1712 CHECK(true_boolean_object->ValueOf()); 1713 CHECK(!true_boolean_object->IsTrue()); 1714 CHECK(!true_boolean_object->IsFalse()); 1715 } 1716 1717 1718 THREADED_TEST(Number) { 1719 LocalContext env; 1720 v8::HandleScope scope(env->GetIsolate()); 1721 double PI = 3.1415926; 1722 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI); 1723 CHECK_EQ(PI, pi_obj->NumberValue()); 1724 } 1725 1726 1727 THREADED_TEST(ToNumber) { 1728 LocalContext env; 1729 v8::Isolate* isolate = CcTest::isolate(); 1730 v8::HandleScope scope(isolate); 1731 Local<String> str = v8_str("3.1415926"); 1732 CHECK_EQ(3.1415926, str->NumberValue()); 1733 v8::Handle<v8::Boolean> t = v8::True(isolate); 1734 CHECK_EQ(1.0, t->NumberValue()); 1735 v8::Handle<v8::Boolean> f = v8::False(isolate); 1736 CHECK_EQ(0.0, f->NumberValue()); 1737 } 1738 1739 1740 THREADED_TEST(Date) { 1741 LocalContext env; 1742 v8::HandleScope scope(env->GetIsolate()); 1743 double PI = 3.1415926; 1744 Local<Value> date = v8::Date::New(env->GetIsolate(), PI); 1745 CHECK_EQ(3.0, date->NumberValue()); 1746 date.As<v8::Date>()->Set(v8_str("property"), 1747 v8::Integer::New(env->GetIsolate(), 42)); 1748 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value()); 1749 } 1750 1751 1752 THREADED_TEST(Boolean) { 1753 LocalContext env; 1754 v8::Isolate* isolate = env->GetIsolate(); 1755 v8::HandleScope scope(isolate); 1756 v8::Handle<v8::Boolean> t = v8::True(isolate); 1757 CHECK(t->Value()); 1758 v8::Handle<v8::Boolean> f = v8::False(isolate); 1759 CHECK(!f->Value()); 1760 v8::Handle<v8::Primitive> u = v8::Undefined(isolate); 1761 CHECK(!u->BooleanValue()); 1762 v8::Handle<v8::Primitive> n = v8::Null(isolate); 1763 CHECK(!n->BooleanValue()); 1764 v8::Handle<String> str1 = v8_str(""); 1765 CHECK(!str1->BooleanValue()); 1766 v8::Handle<String> str2 = v8_str("x"); 1767 CHECK(str2->BooleanValue()); 1768 CHECK(!v8::Number::New(isolate, 0)->BooleanValue()); 1769 CHECK(v8::Number::New(isolate, -1)->BooleanValue()); 1770 CHECK(v8::Number::New(isolate, 1)->BooleanValue()); 1771 CHECK(v8::Number::New(isolate, 42)->BooleanValue()); 1772 CHECK(!v8_compile("NaN")->Run()->BooleanValue()); 1773 } 1774 1775 1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1777 ApiTestFuzzer::Fuzz(); 1778 args.GetReturnValue().Set(v8_num(13.4)); 1779 } 1780 1781 1782 static void GetM(Local<String> name, 1783 const v8::PropertyCallbackInfo<v8::Value>& info) { 1784 ApiTestFuzzer::Fuzz(); 1785 info.GetReturnValue().Set(v8_num(876)); 1786 } 1787 1788 1789 THREADED_TEST(GlobalPrototype) { 1790 v8::Isolate* isolate = CcTest::isolate(); 1791 v8::HandleScope scope(isolate); 1792 v8::Handle<v8::FunctionTemplate> func_templ = 1793 v8::FunctionTemplate::New(isolate); 1794 func_templ->PrototypeTemplate()->Set( 1795 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler)); 1796 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1797 templ->Set(isolate, "x", v8_num(200)); 1798 templ->SetAccessor(v8_str("m"), GetM); 1799 LocalContext env(0, templ); 1800 v8::Handle<Script> script(v8_compile("dummy()")); 1801 v8::Handle<Value> result(script->Run()); 1802 CHECK_EQ(13.4, result->NumberValue()); 1803 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); 1804 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value()); 1805 } 1806 1807 1808 THREADED_TEST(ObjectTemplate) { 1809 v8::Isolate* isolate = CcTest::isolate(); 1810 v8::HandleScope scope(isolate); 1811 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate); 1812 templ1->Set(isolate, "x", v8_num(10)); 1813 templ1->Set(isolate, "y", v8_num(13)); 1814 LocalContext env; 1815 Local<v8::Object> instance1 = templ1->NewInstance(); 1816 env->Global()->Set(v8_str("p"), instance1); 1817 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); 1818 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); 1819 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); 1820 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); 1821 Local<ObjectTemplate> templ2 = fun->InstanceTemplate(); 1822 templ2->Set(isolate, "a", v8_num(12)); 1823 templ2->Set(isolate, "b", templ1); 1824 Local<v8::Object> instance2 = templ2->NewInstance(); 1825 env->Global()->Set(v8_str("q"), instance2); 1826 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); 1827 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); 1828 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); 1829 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue()); 1830 } 1831 1832 1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 1834 ApiTestFuzzer::Fuzz(); 1835 args.GetReturnValue().Set(v8_num(17.2)); 1836 } 1837 1838 1839 static void GetKnurd(Local<String> property, 1840 const v8::PropertyCallbackInfo<v8::Value>& info) { 1841 ApiTestFuzzer::Fuzz(); 1842 info.GetReturnValue().Set(v8_num(15.2)); 1843 } 1844 1845 1846 THREADED_TEST(DescriptorInheritance) { 1847 v8::Isolate* isolate = CcTest::isolate(); 1848 v8::HandleScope scope(isolate); 1849 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate); 1850 super->PrototypeTemplate()->Set(isolate, "flabby", 1851 v8::FunctionTemplate::New(isolate, 1852 GetFlabby)); 1853 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14)); 1854 1855 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1856 1857 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate); 1858 base1->Inherit(super); 1859 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1)); 1860 1861 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate); 1862 base2->Inherit(super); 1863 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1)); 1864 1865 LocalContext env; 1866 1867 env->Global()->Set(v8_str("s"), super->GetFunction()); 1868 env->Global()->Set(v8_str("base1"), base1->GetFunction()); 1869 env->Global()->Set(v8_str("base2"), base2->GetFunction()); 1870 1871 // Checks right __proto__ chain. 1872 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); 1873 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); 1874 1875 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); 1876 1877 // Instance accessor should not be visible on function object or its prototype 1878 CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); 1879 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); 1880 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); 1881 1882 env->Global()->Set(v8_str("obj"), 1883 base1->GetFunction()->NewInstance()); 1884 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); 1885 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); 1886 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); 1887 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); 1888 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); 1889 1890 env->Global()->Set(v8_str("obj2"), 1891 base2->GetFunction()->NewInstance()); 1892 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); 1893 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); 1894 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); 1895 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); 1896 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); 1897 1898 // base1 and base2 cannot cross reference to each's prototype 1899 CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); 1900 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined()); 1901 } 1902 1903 1904 int echo_named_call_count; 1905 1906 1907 static void EchoNamedProperty(Local<String> name, 1908 const v8::PropertyCallbackInfo<v8::Value>& info) { 1909 ApiTestFuzzer::Fuzz(); 1910 CHECK_EQ(v8_str("data"), info.Data()); 1911 echo_named_call_count++; 1912 info.GetReturnValue().Set(name); 1913 } 1914 1915 1916 // Helper functions for Interceptor/Accessor interaction tests 1917 1918 void SimpleAccessorGetter(Local<String> name, 1919 const v8::PropertyCallbackInfo<v8::Value>& info) { 1920 Handle<Object> self = Handle<Object>::Cast(info.This()); 1921 info.GetReturnValue().Set( 1922 self->Get(String::Concat(v8_str("accessor_"), name))); 1923 } 1924 1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 1926 const v8::PropertyCallbackInfo<void>& info) { 1927 Handle<Object> self = Handle<Object>::Cast(info.This()); 1928 self->Set(String::Concat(v8_str("accessor_"), name), value); 1929 } 1930 1931 void SymbolAccessorGetter(Local<Name> name, 1932 const v8::PropertyCallbackInfo<v8::Value>& info) { 1933 CHECK(name->IsSymbol()); 1934 Local<Symbol> sym = Local<Symbol>::Cast(name); 1935 if (sym->Name()->IsUndefined()) 1936 return; 1937 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info); 1938 } 1939 1940 void SymbolAccessorSetter(Local<Name> name, Local<Value> value, 1941 const v8::PropertyCallbackInfo<void>& info) { 1942 CHECK(name->IsSymbol()); 1943 Local<Symbol> sym = Local<Symbol>::Cast(name); 1944 if (sym->Name()->IsUndefined()) 1945 return; 1946 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info); 1947 } 1948 1949 void EmptyInterceptorGetter(Local<String> name, 1950 const v8::PropertyCallbackInfo<v8::Value>& info) { 1951 } 1952 1953 void EmptyInterceptorSetter(Local<String> name, 1954 Local<Value> value, 1955 const v8::PropertyCallbackInfo<v8::Value>& info) { 1956 } 1957 1958 void InterceptorGetter(Local<String> name, 1959 const v8::PropertyCallbackInfo<v8::Value>& info) { 1960 // Intercept names that start with 'interceptor_'. 1961 String::Utf8Value utf8(name); 1962 char* name_str = *utf8; 1963 char prefix[] = "interceptor_"; 1964 int i; 1965 for (i = 0; name_str[i] && prefix[i]; ++i) { 1966 if (name_str[i] != prefix[i]) return; 1967 } 1968 Handle<Object> self = Handle<Object>::Cast(info.This()); 1969 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i))); 1970 } 1971 1972 void InterceptorSetter(Local<String> name, 1973 Local<Value> value, 1974 const v8::PropertyCallbackInfo<v8::Value>& info) { 1975 // Intercept accesses that set certain integer values, for which the name does 1976 // not start with 'accessor_'. 1977 String::Utf8Value utf8(name); 1978 char* name_str = *utf8; 1979 char prefix[] = "accessor_"; 1980 int i; 1981 for (i = 0; name_str[i] && prefix[i]; ++i) { 1982 if (name_str[i] != prefix[i]) break; 1983 } 1984 if (!prefix[i]) return; 1985 1986 if (value->IsInt32() && value->Int32Value() < 10000) { 1987 Handle<Object> self = Handle<Object>::Cast(info.This()); 1988 self->SetHiddenValue(name, value); 1989 info.GetReturnValue().Set(value); 1990 } 1991 } 1992 1993 void AddAccessor(Handle<FunctionTemplate> templ, 1994 Handle<String> name, 1995 v8::AccessorGetterCallback getter, 1996 v8::AccessorSetterCallback setter) { 1997 templ->PrototypeTemplate()->SetAccessor(name, getter, setter); 1998 } 1999 2000 void AddInterceptor(Handle<FunctionTemplate> templ, 2001 v8::NamedPropertyGetterCallback getter, 2002 v8::NamedPropertySetterCallback setter) { 2003 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter); 2004 } 2005 2006 2007 void AddAccessor(Handle<FunctionTemplate> templ, 2008 Handle<Name> name, 2009 v8::AccessorNameGetterCallback getter, 2010 v8::AccessorNameSetterCallback setter) { 2011 templ->PrototypeTemplate()->SetAccessor(name, getter, setter); 2012 } 2013 2014 2015 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { 2016 v8::HandleScope scope(CcTest::isolate()); 2017 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2018 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2019 child->Inherit(parent); 2020 AddAccessor(parent, v8_str("age"), 2021 SimpleAccessorGetter, SimpleAccessorSetter); 2022 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 2023 LocalContext env; 2024 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2025 CompileRun("var child = new Child;" 2026 "child.age = 10;"); 2027 ExpectBoolean("child.hasOwnProperty('age')", false); 2028 ExpectInt32("child.age", 10); 2029 ExpectInt32("child.accessor_age", 10); 2030 } 2031 2032 2033 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { 2034 v8::Isolate* isolate = CcTest::isolate(); 2035 v8::HandleScope scope(isolate); 2036 LocalContext env; 2037 v8::Local<v8::Value> res = CompileRun("var a = []; a;"); 2038 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res))); 2039 CHECK(a->map()->instance_descriptors()->IsFixedArray()); 2040 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2041 CompileRun("Object.defineProperty(a, 'length', { writable: false });"); 2042 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); 2043 // But we should still have an ExecutableAccessorInfo. 2044 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 2045 i::LookupResult lookup(i_isolate); 2046 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); 2047 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR); 2048 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state()); 2049 CHECK(it.GetAccessors()->IsExecutableAccessorInfo()); 2050 } 2051 2052 2053 THREADED_TEST(EmptyInterceptorBreakTransitions) { 2054 v8::HandleScope scope(CcTest::isolate()); 2055 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2056 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 2057 LocalContext env; 2058 env->Global()->Set(v8_str("Constructor"), templ->GetFunction()); 2059 CompileRun("var o1 = new Constructor;" 2060 "o1.a = 1;" // Ensure a and x share the descriptor array. 2061 "Object.defineProperty(o1, 'x', {value: 10});"); 2062 CompileRun("var o2 = new Constructor;" 2063 "o2.a = 1;" 2064 "Object.defineProperty(o2, 'x', {value: 10});"); 2065 } 2066 2067 2068 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) { 2069 v8::Isolate* isolate = CcTest::isolate(); 2070 v8::HandleScope scope(isolate); 2071 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate); 2072 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate); 2073 child->Inherit(parent); 2074 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 2075 LocalContext env; 2076 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2077 CompileRun("var child = new Child;" 2078 "var parent = child.__proto__;" 2079 "Object.defineProperty(parent, 'age', " 2080 " {get: function(){ return this.accessor_age; }, " 2081 " set: function(v){ this.accessor_age = v; }, " 2082 " enumerable: true, configurable: true});" 2083 "child.age = 10;"); 2084 ExpectBoolean("child.hasOwnProperty('age')", false); 2085 ExpectInt32("child.age", 10); 2086 ExpectInt32("child.accessor_age", 10); 2087 } 2088 2089 2090 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) { 2091 v8::Isolate* isolate = CcTest::isolate(); 2092 v8::HandleScope scope(isolate); 2093 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate); 2094 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate); 2095 child->Inherit(parent); 2096 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 2097 LocalContext env; 2098 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2099 CompileRun("var child = new Child;" 2100 "var parent = child.__proto__;" 2101 "parent.name = 'Alice';"); 2102 ExpectBoolean("child.hasOwnProperty('name')", false); 2103 ExpectString("child.name", "Alice"); 2104 CompileRun("child.name = 'Bob';"); 2105 ExpectString("child.name", "Bob"); 2106 ExpectBoolean("child.hasOwnProperty('name')", true); 2107 ExpectString("parent.name", "Alice"); 2108 } 2109 2110 2111 THREADED_TEST(SwitchFromInterceptorToAccessor) { 2112 v8::HandleScope scope(CcTest::isolate()); 2113 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2114 AddAccessor(templ, v8_str("age"), 2115 SimpleAccessorGetter, SimpleAccessorSetter); 2116 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2117 LocalContext env; 2118 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2119 CompileRun("var obj = new Obj;" 2120 "function setAge(i){ obj.age = i; };" 2121 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2122 // All i < 10000 go to the interceptor. 2123 ExpectInt32("obj.interceptor_age", 9999); 2124 // The last i goes to the accessor. 2125 ExpectInt32("obj.accessor_age", 10000); 2126 } 2127 2128 2129 THREADED_TEST(SwitchFromAccessorToInterceptor) { 2130 v8::HandleScope scope(CcTest::isolate()); 2131 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2132 AddAccessor(templ, v8_str("age"), 2133 SimpleAccessorGetter, SimpleAccessorSetter); 2134 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2135 LocalContext env; 2136 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2137 CompileRun("var obj = new Obj;" 2138 "function setAge(i){ obj.age = i; };" 2139 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2140 // All i >= 10000 go to the accessor. 2141 ExpectInt32("obj.accessor_age", 10000); 2142 // The last i goes to the interceptor. 2143 ExpectInt32("obj.interceptor_age", 9999); 2144 } 2145 2146 2147 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) { 2148 v8::HandleScope scope(CcTest::isolate()); 2149 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2150 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2151 child->Inherit(parent); 2152 AddAccessor(parent, v8_str("age"), 2153 SimpleAccessorGetter, SimpleAccessorSetter); 2154 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2155 LocalContext env; 2156 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2157 CompileRun("var child = new Child;" 2158 "function setAge(i){ child.age = i; };" 2159 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2160 // All i < 10000 go to the interceptor. 2161 ExpectInt32("child.interceptor_age", 9999); 2162 // The last i goes to the accessor. 2163 ExpectInt32("child.accessor_age", 10000); 2164 } 2165 2166 2167 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) { 2168 v8::HandleScope scope(CcTest::isolate()); 2169 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2170 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2171 child->Inherit(parent); 2172 AddAccessor(parent, v8_str("age"), 2173 SimpleAccessorGetter, SimpleAccessorSetter); 2174 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2175 LocalContext env; 2176 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2177 CompileRun("var child = new Child;" 2178 "function setAge(i){ child.age = i; };" 2179 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2180 // All i >= 10000 go to the accessor. 2181 ExpectInt32("child.accessor_age", 10000); 2182 // The last i goes to the interceptor. 2183 ExpectInt32("child.interceptor_age", 9999); 2184 } 2185 2186 2187 THREADED_TEST(SwitchFromInterceptorToJSAccessor) { 2188 v8::HandleScope scope(CcTest::isolate()); 2189 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2190 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2191 LocalContext env; 2192 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2193 CompileRun("var obj = new Obj;" 2194 "function setter(i) { this.accessor_age = i; };" 2195 "function getter() { return this.accessor_age; };" 2196 "function setAge(i) { obj.age = i; };" 2197 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2198 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2199 // All i < 10000 go to the interceptor. 2200 ExpectInt32("obj.interceptor_age", 9999); 2201 // The last i goes to the JavaScript accessor. 2202 ExpectInt32("obj.accessor_age", 10000); 2203 // The installed JavaScript getter is still intact. 2204 // This last part is a regression test for issue 1651 and relies on the fact 2205 // that both interceptor and accessor are being installed on the same object. 2206 ExpectInt32("obj.age", 10000); 2207 ExpectBoolean("obj.hasOwnProperty('age')", true); 2208 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2209 } 2210 2211 2212 THREADED_TEST(SwitchFromJSAccessorToInterceptor) { 2213 v8::HandleScope scope(CcTest::isolate()); 2214 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 2215 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2216 LocalContext env; 2217 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2218 CompileRun("var obj = new Obj;" 2219 "function setter(i) { this.accessor_age = i; };" 2220 "function getter() { return this.accessor_age; };" 2221 "function setAge(i) { obj.age = i; };" 2222 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2223 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2224 // All i >= 10000 go to the accessor. 2225 ExpectInt32("obj.accessor_age", 10000); 2226 // The last i goes to the interceptor. 2227 ExpectInt32("obj.interceptor_age", 9999); 2228 // The installed JavaScript getter is still intact. 2229 // This last part is a regression test for issue 1651 and relies on the fact 2230 // that both interceptor and accessor are being installed on the same object. 2231 ExpectInt32("obj.age", 10000); 2232 ExpectBoolean("obj.hasOwnProperty('age')", true); 2233 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2234 } 2235 2236 2237 THREADED_TEST(SwitchFromInterceptorToProperty) { 2238 v8::HandleScope scope(CcTest::isolate()); 2239 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2240 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2241 child->Inherit(parent); 2242 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2243 LocalContext env; 2244 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2245 CompileRun("var child = new Child;" 2246 "function setAge(i){ child.age = i; };" 2247 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2248 // All i < 10000 go to the interceptor. 2249 ExpectInt32("child.interceptor_age", 9999); 2250 // The last i goes to child's own property. 2251 ExpectInt32("child.age", 10000); 2252 } 2253 2254 2255 THREADED_TEST(SwitchFromPropertyToInterceptor) { 2256 v8::HandleScope scope(CcTest::isolate()); 2257 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate()); 2258 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate()); 2259 child->Inherit(parent); 2260 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2261 LocalContext env; 2262 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2263 CompileRun("var child = new Child;" 2264 "function setAge(i){ child.age = i; };" 2265 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2266 // All i >= 10000 go to child's own property. 2267 ExpectInt32("child.age", 10000); 2268 // The last i goes to the interceptor. 2269 ExpectInt32("child.interceptor_age", 9999); 2270 } 2271 2272 2273 THREADED_TEST(NamedPropertyHandlerGetter) { 2274 echo_named_call_count = 0; 2275 v8::HandleScope scope(CcTest::isolate()); 2276 v8::Handle<v8::FunctionTemplate> templ = 2277 v8::FunctionTemplate::New(CcTest::isolate()); 2278 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty, 2279 0, 0, 0, 0, 2280 v8_str("data")); 2281 LocalContext env; 2282 env->Global()->Set(v8_str("obj"), 2283 templ->GetFunction()->NewInstance()); 2284 CHECK_EQ(echo_named_call_count, 0); 2285 v8_compile("obj.x")->Run(); 2286 CHECK_EQ(echo_named_call_count, 1); 2287 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;"; 2288 v8::Handle<Value> str = CompileRun(code); 2289 String::Utf8Value value(str); 2290 CHECK_EQ(*value, "oddlepoddle"); 2291 // Check default behavior 2292 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10); 2293 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue()); 2294 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); 2295 } 2296 2297 2298 int echo_indexed_call_count = 0; 2299 2300 2301 static void EchoIndexedProperty( 2302 uint32_t index, 2303 const v8::PropertyCallbackInfo<v8::Value>& info) { 2304 ApiTestFuzzer::Fuzz(); 2305 CHECK_EQ(v8_num(637), info.Data()); 2306 echo_indexed_call_count++; 2307 info.GetReturnValue().Set(v8_num(index)); 2308 } 2309 2310 2311 THREADED_TEST(IndexedPropertyHandlerGetter) { 2312 v8::Isolate* isolate = CcTest::isolate(); 2313 v8::HandleScope scope(isolate); 2314 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2315 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty, 2316 0, 0, 0, 0, 2317 v8_num(637)); 2318 LocalContext env; 2319 env->Global()->Set(v8_str("obj"), 2320 templ->GetFunction()->NewInstance()); 2321 Local<Script> script = v8_compile("obj[900]"); 2322 CHECK_EQ(script->Run()->Int32Value(), 900); 2323 } 2324 2325 2326 v8::Handle<v8::Object> bottom; 2327 2328 static void CheckThisIndexedPropertyHandler( 2329 uint32_t index, 2330 const v8::PropertyCallbackInfo<v8::Value>& info) { 2331 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler)); 2332 ApiTestFuzzer::Fuzz(); 2333 CHECK(info.This()->Equals(bottom)); 2334 } 2335 2336 static void CheckThisNamedPropertyHandler( 2337 Local<String> name, 2338 const v8::PropertyCallbackInfo<v8::Value>& info) { 2339 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler)); 2340 ApiTestFuzzer::Fuzz(); 2341 CHECK(info.This()->Equals(bottom)); 2342 } 2343 2344 void CheckThisIndexedPropertySetter( 2345 uint32_t index, 2346 Local<Value> value, 2347 const v8::PropertyCallbackInfo<v8::Value>& info) { 2348 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter)); 2349 ApiTestFuzzer::Fuzz(); 2350 CHECK(info.This()->Equals(bottom)); 2351 } 2352 2353 2354 void CheckThisNamedPropertySetter( 2355 Local<String> property, 2356 Local<Value> value, 2357 const v8::PropertyCallbackInfo<v8::Value>& info) { 2358 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter)); 2359 ApiTestFuzzer::Fuzz(); 2360 CHECK(info.This()->Equals(bottom)); 2361 } 2362 2363 void CheckThisIndexedPropertyQuery( 2364 uint32_t index, 2365 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2366 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery)); 2367 ApiTestFuzzer::Fuzz(); 2368 CHECK(info.This()->Equals(bottom)); 2369 } 2370 2371 2372 void CheckThisNamedPropertyQuery( 2373 Local<String> property, 2374 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2375 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery)); 2376 ApiTestFuzzer::Fuzz(); 2377 CHECK(info.This()->Equals(bottom)); 2378 } 2379 2380 2381 void CheckThisIndexedPropertyDeleter( 2382 uint32_t index, 2383 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2384 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter)); 2385 ApiTestFuzzer::Fuzz(); 2386 CHECK(info.This()->Equals(bottom)); 2387 } 2388 2389 2390 void CheckThisNamedPropertyDeleter( 2391 Local<String> property, 2392 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2393 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter)); 2394 ApiTestFuzzer::Fuzz(); 2395 CHECK(info.This()->Equals(bottom)); 2396 } 2397 2398 2399 void CheckThisIndexedPropertyEnumerator( 2400 const v8::PropertyCallbackInfo<v8::Array>& info) { 2401 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator)); 2402 ApiTestFuzzer::Fuzz(); 2403 CHECK(info.This()->Equals(bottom)); 2404 } 2405 2406 2407 void CheckThisNamedPropertyEnumerator( 2408 const v8::PropertyCallbackInfo<v8::Array>& info) { 2409 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator)); 2410 ApiTestFuzzer::Fuzz(); 2411 CHECK(info.This()->Equals(bottom)); 2412 } 2413 2414 2415 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) { 2416 LocalContext env; 2417 v8::Isolate* isolate = env->GetIsolate(); 2418 v8::HandleScope scope(isolate); 2419 2420 // Set up a prototype chain with three interceptors. 2421 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2422 templ->InstanceTemplate()->SetIndexedPropertyHandler( 2423 CheckThisIndexedPropertyHandler, 2424 CheckThisIndexedPropertySetter, 2425 CheckThisIndexedPropertyQuery, 2426 CheckThisIndexedPropertyDeleter, 2427 CheckThisIndexedPropertyEnumerator); 2428 2429 templ->InstanceTemplate()->SetNamedPropertyHandler( 2430 CheckThisNamedPropertyHandler, 2431 CheckThisNamedPropertySetter, 2432 CheckThisNamedPropertyQuery, 2433 CheckThisNamedPropertyDeleter, 2434 CheckThisNamedPropertyEnumerator); 2435 2436 bottom = templ->GetFunction()->NewInstance(); 2437 Local<v8::Object> top = templ->GetFunction()->NewInstance(); 2438 Local<v8::Object> middle = templ->GetFunction()->NewInstance(); 2439 2440 bottom->SetPrototype(middle); 2441 middle->SetPrototype(top); 2442 env->Global()->Set(v8_str("obj"), bottom); 2443 2444 // Indexed and named get. 2445 CompileRun("obj[0]"); 2446 CompileRun("obj.x"); 2447 2448 // Indexed and named set. 2449 CompileRun("obj[1] = 42"); 2450 CompileRun("obj.y = 42"); 2451 2452 // Indexed and named query. 2453 CompileRun("0 in obj"); 2454 CompileRun("'x' in obj"); 2455 2456 // Indexed and named deleter. 2457 CompileRun("delete obj[0]"); 2458 CompileRun("delete obj.x"); 2459 2460 // Enumerators. 2461 CompileRun("for (var p in obj) ;"); 2462 } 2463 2464 2465 static void PrePropertyHandlerGet( 2466 Local<String> key, 2467 const v8::PropertyCallbackInfo<v8::Value>& info) { 2468 ApiTestFuzzer::Fuzz(); 2469 if (v8_str("pre")->Equals(key)) { 2470 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre")); 2471 } 2472 } 2473 2474 2475 static void PrePropertyHandlerQuery( 2476 Local<String> key, 2477 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2478 if (v8_str("pre")->Equals(key)) { 2479 info.GetReturnValue().Set(static_cast<int32_t>(v8::None)); 2480 } 2481 } 2482 2483 2484 THREADED_TEST(PrePropertyHandler) { 2485 v8::Isolate* isolate = CcTest::isolate(); 2486 v8::HandleScope scope(isolate); 2487 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 2488 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet, 2489 0, 2490 PrePropertyHandlerQuery); 2491 LocalContext env(NULL, desc->InstanceTemplate()); 2492 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';"); 2493 v8::Handle<Value> result_pre = CompileRun("pre"); 2494 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre); 2495 v8::Handle<Value> result_on = CompileRun("on"); 2496 CHECK_EQ(v8_str("Object: on"), result_on); 2497 v8::Handle<Value> result_post = CompileRun("post"); 2498 CHECK(result_post.IsEmpty()); 2499 } 2500 2501 2502 THREADED_TEST(UndefinedIsNotEnumerable) { 2503 LocalContext env; 2504 v8::HandleScope scope(env->GetIsolate()); 2505 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)"); 2506 CHECK(result->IsFalse()); 2507 } 2508 2509 2510 v8::Handle<Script> call_recursively_script; 2511 static const int kTargetRecursionDepth = 200; // near maximum 2512 2513 2514 static void CallScriptRecursivelyCall( 2515 const v8::FunctionCallbackInfo<v8::Value>& args) { 2516 ApiTestFuzzer::Fuzz(); 2517 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2518 if (depth == kTargetRecursionDepth) return; 2519 args.This()->Set(v8_str("depth"), 2520 v8::Integer::New(args.GetIsolate(), depth + 1)); 2521 args.GetReturnValue().Set(call_recursively_script->Run()); 2522 } 2523 2524 2525 static void CallFunctionRecursivelyCall( 2526 const v8::FunctionCallbackInfo<v8::Value>& args) { 2527 ApiTestFuzzer::Fuzz(); 2528 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2529 if (depth == kTargetRecursionDepth) { 2530 printf("[depth = %d]\n", depth); 2531 return; 2532 } 2533 args.This()->Set(v8_str("depth"), 2534 v8::Integer::New(args.GetIsolate(), depth + 1)); 2535 v8::Handle<Value> function = 2536 args.This()->Get(v8_str("callFunctionRecursively")); 2537 args.GetReturnValue().Set( 2538 function.As<Function>()->Call(args.This(), 0, NULL)); 2539 } 2540 2541 2542 THREADED_TEST(DeepCrossLanguageRecursion) { 2543 v8::Isolate* isolate = CcTest::isolate(); 2544 v8::HandleScope scope(isolate); 2545 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 2546 global->Set(v8_str("callScriptRecursively"), 2547 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall)); 2548 global->Set(v8_str("callFunctionRecursively"), 2549 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall)); 2550 LocalContext env(NULL, global); 2551 2552 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); 2553 call_recursively_script = v8_compile("callScriptRecursively()"); 2554 call_recursively_script->Run(); 2555 call_recursively_script = v8::Handle<Script>(); 2556 2557 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0)); 2558 CompileRun("callFunctionRecursively()"); 2559 } 2560 2561 2562 static void ThrowingPropertyHandlerGet( 2563 Local<String> key, 2564 const v8::PropertyCallbackInfo<v8::Value>& info) { 2565 ApiTestFuzzer::Fuzz(); 2566 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key)); 2567 } 2568 2569 2570 static void ThrowingPropertyHandlerSet( 2571 Local<String> key, 2572 Local<Value>, 2573 const v8::PropertyCallbackInfo<v8::Value>& info) { 2574 info.GetIsolate()->ThrowException(key); 2575 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2576 } 2577 2578 2579 THREADED_TEST(CallbackExceptionRegression) { 2580 v8::Isolate* isolate = CcTest::isolate(); 2581 v8::HandleScope scope(isolate); 2582 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 2583 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet, 2584 ThrowingPropertyHandlerSet); 2585 LocalContext env; 2586 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 2587 v8::Handle<Value> otto = CompileRun( 2588 "try { with (obj) { otto; } } catch (e) { e; }"); 2589 CHECK_EQ(v8_str("otto"), otto); 2590 v8::Handle<Value> netto = CompileRun( 2591 "try { with (obj) { netto = 4; } } catch (e) { e; }"); 2592 CHECK_EQ(v8_str("netto"), netto); 2593 } 2594 2595 2596 THREADED_TEST(FunctionPrototype) { 2597 v8::Isolate* isolate = CcTest::isolate(); 2598 v8::HandleScope scope(isolate); 2599 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate); 2600 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2601 LocalContext env; 2602 env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); 2603 Local<Script> script = v8_compile("Foo.prototype.plak"); 2604 CHECK_EQ(script->Run()->Int32Value(), 321); 2605 } 2606 2607 2608 THREADED_TEST(InternalFields) { 2609 LocalContext env; 2610 v8::Isolate* isolate = env->GetIsolate(); 2611 v8::HandleScope scope(isolate); 2612 2613 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2614 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2615 instance_templ->SetInternalFieldCount(1); 2616 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2617 CHECK_EQ(1, obj->InternalFieldCount()); 2618 CHECK(obj->GetInternalField(0)->IsUndefined()); 2619 obj->SetInternalField(0, v8_num(17)); 2620 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value()); 2621 } 2622 2623 2624 THREADED_TEST(GlobalObjectInternalFields) { 2625 v8::Isolate* isolate = CcTest::isolate(); 2626 v8::HandleScope scope(isolate); 2627 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 2628 global_template->SetInternalFieldCount(1); 2629 LocalContext env(NULL, global_template); 2630 v8::Handle<v8::Object> global_proxy = env->Global(); 2631 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2632 CHECK_EQ(1, global->InternalFieldCount()); 2633 CHECK(global->GetInternalField(0)->IsUndefined()); 2634 global->SetInternalField(0, v8_num(17)); 2635 CHECK_EQ(17, global->GetInternalField(0)->Int32Value()); 2636 } 2637 2638 2639 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2640 LocalContext env; 2641 v8::HandleScope scope(CcTest::isolate()); 2642 2643 v8::Local<v8::Object> global = env->Global(); 2644 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value")); 2645 CHECK(global->HasRealIndexedProperty(0)); 2646 } 2647 2648 2649 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, 2650 void* value) { 2651 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2652 obj->SetAlignedPointerInInternalField(0, value); 2653 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2654 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2655 } 2656 2657 2658 THREADED_TEST(InternalFieldsAlignedPointers) { 2659 LocalContext env; 2660 v8::Isolate* isolate = env->GetIsolate(); 2661 v8::HandleScope scope(isolate); 2662 2663 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 2664 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2665 instance_templ->SetInternalFieldCount(1); 2666 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2667 CHECK_EQ(1, obj->InternalFieldCount()); 2668 2669 CheckAlignedPointerInInternalField(obj, NULL); 2670 2671 int* heap_allocated = new int[100]; 2672 CheckAlignedPointerInInternalField(obj, heap_allocated); 2673 delete[] heap_allocated; 2674 2675 int stack_allocated[100]; 2676 CheckAlignedPointerInInternalField(obj, stack_allocated); 2677 2678 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2679 CheckAlignedPointerInInternalField(obj, huge); 2680 2681 v8::UniquePersistent<v8::Object> persistent(isolate, obj); 2682 CHECK_EQ(1, Object::InternalFieldCount(persistent)); 2683 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0)); 2684 } 2685 2686 2687 static void CheckAlignedPointerInEmbedderData(LocalContext* env, 2688 int index, 2689 void* value) { 2690 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2691 (*env)->SetAlignedPointerInEmbedderData(index, value); 2692 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2693 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2694 } 2695 2696 2697 static void* AlignedTestPointer(int i) { 2698 return reinterpret_cast<void*>(i * 1234); 2699 } 2700 2701 2702 THREADED_TEST(EmbedderDataAlignedPointers) { 2703 LocalContext env; 2704 v8::HandleScope scope(env->GetIsolate()); 2705 2706 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2707 2708 int* heap_allocated = new int[100]; 2709 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2710 delete[] heap_allocated; 2711 2712 int stack_allocated[100]; 2713 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2714 2715 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2716 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2717 2718 // Test growing of the embedder data's backing store. 2719 for (int i = 0; i < 100; i++) { 2720 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2721 } 2722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2723 for (int i = 0; i < 100; i++) { 2724 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2725 } 2726 } 2727 2728 2729 static void CheckEmbedderData(LocalContext* env, 2730 int index, 2731 v8::Handle<Value> data) { 2732 (*env)->SetEmbedderData(index, data); 2733 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2734 } 2735 2736 2737 THREADED_TEST(EmbedderData) { 2738 LocalContext env; 2739 v8::Isolate* isolate = env->GetIsolate(); 2740 v8::HandleScope scope(isolate); 2741 2742 CheckEmbedderData( 2743 &env, 3, 2744 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps")); 2745 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate, 2746 "over the lazy dog.")); 2747 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345)); 2748 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true)); 2749 } 2750 2751 2752 THREADED_TEST(IdentityHash) { 2753 LocalContext env; 2754 v8::Isolate* isolate = env->GetIsolate(); 2755 v8::HandleScope scope(isolate); 2756 2757 // Ensure that the test starts with an fresh heap to test whether the hash 2758 // code is based on the address. 2759 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2760 Local<v8::Object> obj = v8::Object::New(isolate); 2761 int hash = obj->GetIdentityHash(); 2762 int hash1 = obj->GetIdentityHash(); 2763 CHECK_EQ(hash, hash1); 2764 int hash2 = v8::Object::New(isolate)->GetIdentityHash(); 2765 // Since the identity hash is essentially a random number two consecutive 2766 // objects should not be assigned the same hash code. If the test below fails 2767 // the random number generator should be evaluated. 2768 CHECK_NE(hash, hash2); 2769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2770 int hash3 = v8::Object::New(isolate)->GetIdentityHash(); 2771 // Make sure that the identity hash is not based on the initial address of 2772 // the object alone. If the test below fails the random number generator 2773 // should be evaluated. 2774 CHECK_NE(hash, hash3); 2775 int hash4 = obj->GetIdentityHash(); 2776 CHECK_EQ(hash, hash4); 2777 2778 // Check identity hashes behaviour in the presence of JS accessors. 2779 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2780 { 2781 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2782 Local<v8::Object> o1 = v8::Object::New(isolate); 2783 Local<v8::Object> o2 = v8::Object::New(isolate); 2784 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2785 } 2786 { 2787 CompileRun( 2788 "function cnst() { return 42; };\n" 2789 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2790 Local<v8::Object> o1 = v8::Object::New(isolate); 2791 Local<v8::Object> o2 = v8::Object::New(isolate); 2792 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2793 } 2794 } 2795 2796 2797 THREADED_TEST(GlobalProxyIdentityHash) { 2798 LocalContext env; 2799 v8::Isolate* isolate = env->GetIsolate(); 2800 v8::HandleScope scope(isolate); 2801 Handle<Object> global_proxy = env->Global(); 2802 int hash1 = global_proxy->GetIdentityHash(); 2803 // Hash should be retained after being detached. 2804 env->DetachGlobal(); 2805 int hash2 = global_proxy->GetIdentityHash(); 2806 CHECK_EQ(hash1, hash2); 2807 { 2808 // Re-attach global proxy to a new context, hash should stay the same. 2809 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy); 2810 int hash3 = global_proxy->GetIdentityHash(); 2811 CHECK_EQ(hash1, hash3); 2812 } 2813 } 2814 2815 2816 THREADED_TEST(SymbolProperties) { 2817 LocalContext env; 2818 v8::Isolate* isolate = env->GetIsolate(); 2819 v8::HandleScope scope(isolate); 2820 2821 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2822 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2823 v8::Local<v8::Symbol> sym2 = 2824 v8::Symbol::New(isolate, v8_str("my-symbol")); 2825 v8::Local<v8::Symbol> sym3 = 2826 v8::Symbol::New(isolate, v8_str("sym3")); 2827 2828 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2829 2830 // Check basic symbol functionality. 2831 CHECK(sym1->IsSymbol()); 2832 CHECK(sym2->IsSymbol()); 2833 CHECK(!obj->IsSymbol()); 2834 2835 CHECK(sym1->Equals(sym1)); 2836 CHECK(sym2->Equals(sym2)); 2837 CHECK(!sym1->Equals(sym2)); 2838 CHECK(!sym2->Equals(sym1)); 2839 CHECK(sym1->StrictEquals(sym1)); 2840 CHECK(sym2->StrictEquals(sym2)); 2841 CHECK(!sym1->StrictEquals(sym2)); 2842 CHECK(!sym2->StrictEquals(sym1)); 2843 2844 CHECK(sym2->Name()->Equals(v8_str("my-symbol"))); 2845 2846 v8::Local<v8::Value> sym_val = sym2; 2847 CHECK(sym_val->IsSymbol()); 2848 CHECK(sym_val->Equals(sym2)); 2849 CHECK(sym_val->StrictEquals(sym2)); 2850 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2)); 2851 2852 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2853 CHECK(sym_obj->IsSymbolObject()); 2854 CHECK(!sym2->IsSymbolObject()); 2855 CHECK(!obj->IsSymbolObject()); 2856 CHECK(!sym_obj->Equals(sym2)); 2857 CHECK(!sym_obj->StrictEquals(sym2)); 2858 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj)); 2859 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2)); 2860 2861 // Make sure delete of a non-existent symbol property works. 2862 CHECK(obj->Delete(sym1)); 2863 CHECK(!obj->Has(sym1)); 2864 2865 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503))); 2866 CHECK(obj->Has(sym1)); 2867 CHECK_EQ(1503, obj->Get(sym1)->Int32Value()); 2868 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002))); 2869 CHECK(obj->Has(sym1)); 2870 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2871 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1)); 2872 2873 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2874 int num_props = obj->GetPropertyNames()->Length(); 2875 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"), 2876 v8::Integer::New(isolate, 20))); 2877 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2878 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2879 2880 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2881 2882 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter)); 2883 CHECK(obj->Get(sym3)->IsUndefined()); 2884 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42))); 2885 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42))); 2886 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals( 2887 v8::Integer::New(isolate, 42))); 2888 2889 // Add another property and delete it afterwards to force the object in 2890 // slow case. 2891 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008))); 2892 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2893 CHECK_EQ(2008, obj->Get(sym2)->Int32Value()); 2894 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2895 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length()); 2896 2897 CHECK(obj->Has(sym1)); 2898 CHECK(obj->Has(sym2)); 2899 CHECK(obj->Has(sym3)); 2900 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3"))); 2901 CHECK(obj->Delete(sym2)); 2902 CHECK(obj->Has(sym1)); 2903 CHECK(!obj->Has(sym2)); 2904 CHECK(obj->Has(sym3)); 2905 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3"))); 2906 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2907 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42))); 2908 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals( 2909 v8::Integer::New(isolate, 42))); 2910 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length()); 2911 2912 // Symbol properties are inherited. 2913 v8::Local<v8::Object> child = v8::Object::New(isolate); 2914 child->SetPrototype(obj); 2915 CHECK(child->Has(sym1)); 2916 CHECK_EQ(2002, child->Get(sym1)->Int32Value()); 2917 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42))); 2918 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals( 2919 v8::Integer::New(isolate, 42))); 2920 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2921 } 2922 2923 2924 THREADED_TEST(SymbolTemplateProperties) { 2925 LocalContext env; 2926 v8::Isolate* isolate = env->GetIsolate(); 2927 v8::HandleScope scope(isolate); 2928 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate); 2929 v8::Local<v8::Name> name = v8::Symbol::New(isolate); 2930 CHECK(!name.IsEmpty()); 2931 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate)); 2932 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance(); 2933 CHECK(!new_instance.IsEmpty()); 2934 CHECK(new_instance->Has(name)); 2935 } 2936 2937 2938 THREADED_TEST(PrivateProperties) { 2939 LocalContext env; 2940 v8::Isolate* isolate = env->GetIsolate(); 2941 v8::HandleScope scope(isolate); 2942 2943 v8::Local<v8::Object> obj = v8::Object::New(isolate); 2944 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 2945 v8::Local<v8::Private> priv2 = 2946 v8::Private::New(isolate, v8_str("my-private")); 2947 2948 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2949 2950 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private"))); 2951 2952 // Make sure delete of a non-existent private symbol property works. 2953 CHECK(obj->DeletePrivate(priv1)); 2954 CHECK(!obj->HasPrivate(priv1)); 2955 2956 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503))); 2957 CHECK(obj->HasPrivate(priv1)); 2958 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value()); 2959 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002))); 2960 CHECK(obj->HasPrivate(priv1)); 2961 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2962 2963 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2964 int num_props = obj->GetPropertyNames()->Length(); 2965 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"), 2966 v8::Integer::New(isolate, 20))); 2967 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2968 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2969 2970 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2971 2972 // Add another property and delete it afterwards to force the object in 2973 // slow case. 2974 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008))); 2975 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2976 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value()); 2977 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2978 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2979 2980 CHECK(obj->HasPrivate(priv1)); 2981 CHECK(obj->HasPrivate(priv2)); 2982 CHECK(obj->DeletePrivate(priv2)); 2983 CHECK(obj->HasPrivate(priv1)); 2984 CHECK(!obj->HasPrivate(priv2)); 2985 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2986 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2987 2988 // Private properties are inherited (for the time being). 2989 v8::Local<v8::Object> child = v8::Object::New(isolate); 2990 child->SetPrototype(obj); 2991 CHECK(child->HasPrivate(priv1)); 2992 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value()); 2993 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2994 } 2995 2996 2997 THREADED_TEST(GlobalSymbols) { 2998 LocalContext env; 2999 v8::Isolate* isolate = env->GetIsolate(); 3000 v8::HandleScope scope(isolate); 3001 3002 v8::Local<String> name = v8_str("my-symbol"); 3003 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name); 3004 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name); 3005 CHECK(glob2->SameValue(glob)); 3006 3007 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name); 3008 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name); 3009 CHECK(glob_api2->SameValue(glob_api)); 3010 CHECK(!glob_api->SameValue(glob)); 3011 3012 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name); 3013 CHECK(!sym->SameValue(glob)); 3014 3015 CompileRun("var sym2 = Symbol.for('my-symbol')"); 3016 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2")); 3017 CHECK(sym2->SameValue(glob)); 3018 CHECK(!sym2->SameValue(glob_api)); 3019 } 3020 3021 3022 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*), 3023 const char* name) { 3024 LocalContext env; 3025 v8::Isolate* isolate = env->GetIsolate(); 3026 v8::HandleScope scope(isolate); 3027 3028 v8::Local<v8::Symbol> symbol = getter(isolate); 3029 std::string script = std::string("var sym = ") + name; 3030 CompileRun(script.c_str()); 3031 v8::Local<Value> value = env->Global()->Get(v8_str("sym")); 3032 3033 CHECK(!value.IsEmpty()); 3034 CHECK(!symbol.IsEmpty()); 3035 CHECK(value->SameValue(symbol)); 3036 } 3037 3038 3039 THREADED_TEST(WellKnownSymbols) { 3040 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator"); 3041 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables"); 3042 } 3043 3044 3045 THREADED_TEST(GlobalPrivates) { 3046 LocalContext env; 3047 v8::Isolate* isolate = env->GetIsolate(); 3048 v8::HandleScope scope(isolate); 3049 3050 v8::Local<String> name = v8_str("my-private"); 3051 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name); 3052 v8::Local<v8::Object> obj = v8::Object::New(isolate); 3053 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3))); 3054 3055 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name); 3056 CHECK(obj->HasPrivate(glob2)); 3057 3058 v8::Local<v8::Private> priv = v8::Private::New(isolate, name); 3059 CHECK(!obj->HasPrivate(priv)); 3060 3061 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')"); 3062 v8::Local<Value> intern = env->Global()->Get(v8_str("intern")); 3063 CHECK(!obj->Has(intern)); 3064 } 3065 3066 3067 class ScopedArrayBufferContents { 3068 public: 3069 explicit ScopedArrayBufferContents( 3070 const v8::ArrayBuffer::Contents& contents) 3071 : contents_(contents) {} 3072 ~ScopedArrayBufferContents() { free(contents_.Data()); } 3073 void* Data() const { return contents_.Data(); } 3074 size_t ByteLength() const { return contents_.ByteLength(); } 3075 private: 3076 const v8::ArrayBuffer::Contents contents_; 3077 }; 3078 3079 template <typename T> 3080 static void CheckInternalFieldsAreZero(v8::Handle<T> value) { 3081 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 3082 for (int i = 0; i < value->InternalFieldCount(); i++) { 3083 CHECK_EQ(0, value->GetInternalField(i)->Int32Value()); 3084 } 3085 } 3086 3087 3088 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 3089 LocalContext env; 3090 v8::Isolate* isolate = env->GetIsolate(); 3091 v8::HandleScope handle_scope(isolate); 3092 3093 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024); 3094 CheckInternalFieldsAreZero(ab); 3095 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 3096 CHECK(!ab->IsExternal()); 3097 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3098 3099 ScopedArrayBufferContents ab_contents(ab->Externalize()); 3100 CHECK(ab->IsExternal()); 3101 3102 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 3103 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 3104 DCHECK(data != NULL); 3105 env->Global()->Set(v8_str("ab"), ab); 3106 3107 v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); 3108 CHECK_EQ(1024, result->Int32Value()); 3109 3110 result = CompileRun("var u8 = new Uint8Array(ab);" 3111 "u8[0] = 0xFF;" 3112 "u8[1] = 0xAA;" 3113 "u8.length"); 3114 CHECK_EQ(1024, result->Int32Value()); 3115 CHECK_EQ(0xFF, data[0]); 3116 CHECK_EQ(0xAA, data[1]); 3117 data[0] = 0xCC; 3118 data[1] = 0x11; 3119 result = CompileRun("u8[0] + u8[1]"); 3120 CHECK_EQ(0xDD, result->Int32Value()); 3121 } 3122 3123 3124 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 3125 LocalContext env; 3126 v8::Isolate* isolate = env->GetIsolate(); 3127 v8::HandleScope handle_scope(isolate); 3128 3129 3130 v8::Local<v8::Value> result = 3131 CompileRun("var ab1 = new ArrayBuffer(2);" 3132 "var u8_a = new Uint8Array(ab1);" 3133 "u8_a[0] = 0xAA;" 3134 "u8_a[1] = 0xFF; u8_a.buffer"); 3135 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 3136 CheckInternalFieldsAreZero(ab1); 3137 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 3138 CHECK(!ab1->IsExternal()); 3139 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 3140 CHECK(ab1->IsExternal()); 3141 3142 result = CompileRun("ab1.byteLength"); 3143 CHECK_EQ(2, result->Int32Value()); 3144 result = CompileRun("u8_a[0]"); 3145 CHECK_EQ(0xAA, result->Int32Value()); 3146 result = CompileRun("u8_a[1]"); 3147 CHECK_EQ(0xFF, result->Int32Value()); 3148 result = CompileRun("var u8_b = new Uint8Array(ab1);" 3149 "u8_b[0] = 0xBB;" 3150 "u8_a[0]"); 3151 CHECK_EQ(0xBB, result->Int32Value()); 3152 result = CompileRun("u8_b[1]"); 3153 CHECK_EQ(0xFF, result->Int32Value()); 3154 3155 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 3156 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 3157 CHECK_EQ(0xBB, ab1_data[0]); 3158 CHECK_EQ(0xFF, ab1_data[1]); 3159 ab1_data[0] = 0xCC; 3160 ab1_data[1] = 0x11; 3161 result = CompileRun("u8_a[0] + u8_a[1]"); 3162 CHECK_EQ(0xDD, result->Int32Value()); 3163 } 3164 3165 3166 THREADED_TEST(ArrayBuffer_External) { 3167 LocalContext env; 3168 v8::Isolate* isolate = env->GetIsolate(); 3169 v8::HandleScope handle_scope(isolate); 3170 3171 i::ScopedVector<uint8_t> my_data(100); 3172 memset(my_data.start(), 0, 100); 3173 Local<v8::ArrayBuffer> ab3 = 3174 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 3175 CheckInternalFieldsAreZero(ab3); 3176 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 3177 CHECK(ab3->IsExternal()); 3178 3179 env->Global()->Set(v8_str("ab3"), ab3); 3180 3181 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength"); 3182 CHECK_EQ(100, result->Int32Value()); 3183 3184 result = CompileRun("var u8_b = new Uint8Array(ab3);" 3185 "u8_b[0] = 0xBB;" 3186 "u8_b[1] = 0xCC;" 3187 "u8_b.length"); 3188 CHECK_EQ(100, result->Int32Value()); 3189 CHECK_EQ(0xBB, my_data[0]); 3190 CHECK_EQ(0xCC, my_data[1]); 3191 my_data[0] = 0xCC; 3192 my_data[1] = 0x11; 3193 result = CompileRun("u8_b[0] + u8_b[1]"); 3194 CHECK_EQ(0xDD, result->Int32Value()); 3195 } 3196 3197 3198 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) { 3199 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 3200 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 3201 } 3202 3203 3204 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) { 3205 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 3206 CHECK_EQ(0, static_cast<int>(ta->Length())); 3207 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 3208 } 3209 3210 3211 static void CheckIsTypedArrayVarNeutered(const char* name) { 3212 i::ScopedVector<char> source(1024); 3213 i::SNPrintF(source, 3214 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 3215 name, name, name); 3216 CHECK(CompileRun(source.start())->IsTrue()); 3217 v8::Handle<v8::TypedArray> ta = 3218 v8::Handle<v8::TypedArray>::Cast(CompileRun(name)); 3219 CheckIsNeutered(ta); 3220 } 3221 3222 3223 template <typename TypedArray, int kElementSize> 3224 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab, 3225 int byteOffset, 3226 int length) { 3227 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 3228 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 3229 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 3230 CHECK_EQ(length, static_cast<int>(ta->Length())); 3231 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 3232 return ta; 3233 } 3234 3235 3236 THREADED_TEST(ArrayBuffer_NeuteringApi) { 3237 LocalContext env; 3238 v8::Isolate* isolate = env->GetIsolate(); 3239 v8::HandleScope handle_scope(isolate); 3240 3241 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024); 3242 3243 v8::Handle<v8::Uint8Array> u8a = 3244 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 3245 v8::Handle<v8::Uint8ClampedArray> u8c = 3246 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 3247 v8::Handle<v8::Int8Array> i8a = 3248 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 3249 3250 v8::Handle<v8::Uint16Array> u16a = 3251 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 3252 v8::Handle<v8::Int16Array> i16a = 3253 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 3254 3255 v8::Handle<v8::Uint32Array> u32a = 3256 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 3257 v8::Handle<v8::Int32Array> i32a = 3258 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 3259 3260 v8::Handle<v8::Float32Array> f32a = 3261 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 3262 v8::Handle<v8::Float64Array> f64a = 3263 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 3264 3265 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 3266 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 3267 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 3268 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 3269 3270 ScopedArrayBufferContents contents(buffer->Externalize()); 3271 buffer->Neuter(); 3272 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 3273 CheckIsNeutered(u8a); 3274 CheckIsNeutered(u8c); 3275 CheckIsNeutered(i8a); 3276 CheckIsNeutered(u16a); 3277 CheckIsNeutered(i16a); 3278 CheckIsNeutered(u32a); 3279 CheckIsNeutered(i32a); 3280 CheckIsNeutered(f32a); 3281 CheckIsNeutered(f64a); 3282 CheckDataViewIsNeutered(dv); 3283 } 3284 3285 3286 THREADED_TEST(ArrayBuffer_NeuteringScript) { 3287 LocalContext env; 3288 v8::Isolate* isolate = env->GetIsolate(); 3289 v8::HandleScope handle_scope(isolate); 3290 3291 CompileRun( 3292 "var ab = new ArrayBuffer(1024);" 3293 "var u8a = new Uint8Array(ab, 1, 1023);" 3294 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 3295 "var i8a = new Int8Array(ab, 1, 1023);" 3296 "var u16a = new Uint16Array(ab, 2, 511);" 3297 "var i16a = new Int16Array(ab, 2, 511);" 3298 "var u32a = new Uint32Array(ab, 4, 255);" 3299 "var i32a = new Int32Array(ab, 4, 255);" 3300 "var f32a = new Float32Array(ab, 4, 255);" 3301 "var f64a = new Float64Array(ab, 8, 127);" 3302 "var dv = new DataView(ab, 1, 1023);"); 3303 3304 v8::Handle<v8::ArrayBuffer> ab = 3305 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 3306 3307 v8::Handle<v8::DataView> dv = 3308 v8::Handle<v8::DataView>::Cast(CompileRun("dv")); 3309 3310 ScopedArrayBufferContents contents(ab->Externalize()); 3311 ab->Neuter(); 3312 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 3313 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value()); 3314 3315 CheckIsTypedArrayVarNeutered("u8a"); 3316 CheckIsTypedArrayVarNeutered("u8c"); 3317 CheckIsTypedArrayVarNeutered("i8a"); 3318 CheckIsTypedArrayVarNeutered("u16a"); 3319 CheckIsTypedArrayVarNeutered("i16a"); 3320 CheckIsTypedArrayVarNeutered("u32a"); 3321 CheckIsTypedArrayVarNeutered("i32a"); 3322 CheckIsTypedArrayVarNeutered("f32a"); 3323 CheckIsTypedArrayVarNeutered("f64a"); 3324 3325 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 3326 CheckDataViewIsNeutered(dv); 3327 } 3328 3329 3330 3331 THREADED_TEST(HiddenProperties) { 3332 LocalContext env; 3333 v8::Isolate* isolate = env->GetIsolate(); 3334 v8::HandleScope scope(isolate); 3335 3336 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3337 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3338 v8::Local<v8::String> empty = v8_str(""); 3339 v8::Local<v8::String> prop_name = v8_str("prop_name"); 3340 3341 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3342 3343 // Make sure delete of a non-existent hidden value works 3344 CHECK(obj->DeleteHiddenValue(key)); 3345 3346 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503))); 3347 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value()); 3348 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002))); 3349 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3350 3351 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3352 3353 // Make sure we do not find the hidden property. 3354 CHECK(!obj->Has(empty)); 3355 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3356 CHECK(obj->Get(empty)->IsUndefined()); 3357 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3358 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003))); 3359 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3360 CHECK_EQ(2003, obj->Get(empty)->Int32Value()); 3361 3362 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3363 3364 // Add another property and delete it afterwards to force the object in 3365 // slow case. 3366 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008))); 3367 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3368 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value()); 3369 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3370 CHECK(obj->Delete(prop_name)); 3371 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3372 3373 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3374 3375 CHECK(obj->SetHiddenValue(key, Handle<Value>())); 3376 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3377 3378 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002))); 3379 CHECK(obj->DeleteHiddenValue(key)); 3380 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3381 } 3382 3383 3384 THREADED_TEST(Regress97784) { 3385 // Regression test for crbug.com/97784 3386 // Messing with the Object.prototype should not have effect on 3387 // hidden properties. 3388 LocalContext env; 3389 v8::HandleScope scope(env->GetIsolate()); 3390 3391 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate()); 3392 v8::Local<v8::String> key = v8_str("hidden"); 3393 3394 CompileRun( 3395 "set_called = false;" 3396 "Object.defineProperty(" 3397 " Object.prototype," 3398 " 'hidden'," 3399 " {get: function() { return 45; }," 3400 " set: function() { set_called = true; }})"); 3401 3402 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3403 // Make sure that the getter and setter from Object.prototype is not invoked. 3404 // If it did we would have full access to the hidden properties in 3405 // the accessor. 3406 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42))); 3407 ExpectFalse("set_called"); 3408 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value()); 3409 } 3410 3411 3412 static bool interceptor_for_hidden_properties_called; 3413 static void InterceptorForHiddenProperties( 3414 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 3415 interceptor_for_hidden_properties_called = true; 3416 } 3417 3418 3419 THREADED_TEST(HiddenPropertiesWithInterceptors) { 3420 LocalContext context; 3421 v8::Isolate* isolate = context->GetIsolate(); 3422 v8::HandleScope scope(isolate); 3423 3424 interceptor_for_hidden_properties_called = false; 3425 3426 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3427 3428 // Associate an interceptor with an object and start setting hidden values. 3429 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 3430 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 3431 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties); 3432 Local<v8::Function> function = fun_templ->GetFunction(); 3433 Local<v8::Object> obj = function->NewInstance(); 3434 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302))); 3435 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value()); 3436 CHECK(!interceptor_for_hidden_properties_called); 3437 } 3438 3439 3440 THREADED_TEST(External) { 3441 v8::HandleScope scope(CcTest::isolate()); 3442 int x = 3; 3443 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x); 3444 LocalContext env; 3445 env->Global()->Set(v8_str("ext"), ext); 3446 Local<Value> reext_obj = CompileRun("this.ext"); 3447 v8::Handle<v8::External> reext = reext_obj.As<v8::External>(); 3448 int* ptr = static_cast<int*>(reext->Value()); 3449 CHECK_EQ(x, 3); 3450 *ptr = 10; 3451 CHECK_EQ(x, 10); 3452 3453 // Make sure unaligned pointers are wrapped properly. 3454 char* data = i::StrDup("0123456789"); 3455 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]); 3456 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]); 3457 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]); 3458 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]); 3459 3460 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3461 CHECK_EQ('0', *char_ptr); 3462 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3463 CHECK_EQ('1', *char_ptr); 3464 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3465 CHECK_EQ('2', *char_ptr); 3466 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3467 CHECK_EQ('3', *char_ptr); 3468 i::DeleteArray(data); 3469 } 3470 3471 3472 THREADED_TEST(GlobalHandle) { 3473 v8::Isolate* isolate = CcTest::isolate(); 3474 v8::Persistent<String> global; 3475 { 3476 v8::HandleScope scope(isolate); 3477 global.Reset(isolate, v8_str("str")); 3478 } 3479 { 3480 v8::HandleScope scope(isolate); 3481 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3482 } 3483 global.Reset(); 3484 { 3485 v8::HandleScope scope(isolate); 3486 global.Reset(isolate, v8_str("str")); 3487 } 3488 { 3489 v8::HandleScope scope(isolate); 3490 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3491 } 3492 global.Reset(); 3493 } 3494 3495 3496 THREADED_TEST(ResettingGlobalHandle) { 3497 v8::Isolate* isolate = CcTest::isolate(); 3498 v8::Persistent<String> global; 3499 { 3500 v8::HandleScope scope(isolate); 3501 global.Reset(isolate, v8_str("str")); 3502 } 3503 v8::internal::GlobalHandles* global_handles = 3504 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3505 int initial_handle_count = global_handles->global_handles_count(); 3506 { 3507 v8::HandleScope scope(isolate); 3508 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3509 } 3510 { 3511 v8::HandleScope scope(isolate); 3512 global.Reset(isolate, v8_str("longer")); 3513 } 3514 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3515 { 3516 v8::HandleScope scope(isolate); 3517 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3518 } 3519 global.Reset(); 3520 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3521 } 3522 3523 3524 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3525 v8::Isolate* isolate = CcTest::isolate(); 3526 v8::Persistent<String> global; 3527 { 3528 v8::HandleScope scope(isolate); 3529 global.Reset(isolate, v8_str("str")); 3530 } 3531 v8::internal::GlobalHandles* global_handles = 3532 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3533 int initial_handle_count = global_handles->global_handles_count(); 3534 { 3535 v8::HandleScope scope(isolate); 3536 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3537 } 3538 { 3539 v8::HandleScope scope(isolate); 3540 Local<String> empty; 3541 global.Reset(isolate, empty); 3542 } 3543 CHECK(global.IsEmpty()); 3544 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3545 } 3546 3547 3548 template<class T> 3549 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) { 3550 return unique.Pass(); 3551 } 3552 3553 3554 template<class T> 3555 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate, 3556 const v8::Persistent<T> & global) { 3557 v8::UniquePersistent<String> unique(isolate, global); 3558 return unique.Pass(); 3559 } 3560 3561 3562 THREADED_TEST(UniquePersistent) { 3563 v8::Isolate* isolate = CcTest::isolate(); 3564 v8::Persistent<String> global; 3565 { 3566 v8::HandleScope scope(isolate); 3567 global.Reset(isolate, v8_str("str")); 3568 } 3569 v8::internal::GlobalHandles* global_handles = 3570 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3571 int initial_handle_count = global_handles->global_handles_count(); 3572 { 3573 v8::UniquePersistent<String> unique(isolate, global); 3574 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3575 // Test assignment via Pass 3576 { 3577 v8::UniquePersistent<String> copy = unique.Pass(); 3578 CHECK(unique.IsEmpty()); 3579 CHECK(copy == global); 3580 CHECK_EQ(initial_handle_count + 1, 3581 global_handles->global_handles_count()); 3582 unique = copy.Pass(); 3583 } 3584 // Test ctor via Pass 3585 { 3586 v8::UniquePersistent<String> copy(unique.Pass()); 3587 CHECK(unique.IsEmpty()); 3588 CHECK(copy == global); 3589 CHECK_EQ(initial_handle_count + 1, 3590 global_handles->global_handles_count()); 3591 unique = copy.Pass(); 3592 } 3593 // Test pass through function call 3594 { 3595 v8::UniquePersistent<String> copy = PassUnique(unique.Pass()); 3596 CHECK(unique.IsEmpty()); 3597 CHECK(copy == global); 3598 CHECK_EQ(initial_handle_count + 1, 3599 global_handles->global_handles_count()); 3600 unique = copy.Pass(); 3601 } 3602 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3603 } 3604 // Test pass from function call 3605 { 3606 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global); 3607 CHECK(unique == global); 3608 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3609 } 3610 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3611 global.Reset(); 3612 } 3613 3614 3615 template<typename K, typename V> 3616 class WeakStdMapTraits : public v8::StdMapTraits<K, V> { 3617 public: 3618 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> > 3619 MapType; 3620 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak; 3621 struct WeakCallbackDataType { 3622 MapType* map; 3623 K key; 3624 }; 3625 static WeakCallbackDataType* WeakCallbackParameter( 3626 MapType* map, const K& key, Local<V> value) { 3627 WeakCallbackDataType* data = new WeakCallbackDataType; 3628 data->map = map; 3629 data->key = key; 3630 return data; 3631 } 3632 static MapType* MapFromWeakCallbackData( 3633 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) { 3634 return data.GetParameter()->map; 3635 } 3636 static K KeyFromWeakCallbackData( 3637 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) { 3638 return data.GetParameter()->key; 3639 } 3640 static void DisposeCallbackData(WeakCallbackDataType* data) { 3641 delete data; 3642 } 3643 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value, 3644 K key) { } 3645 }; 3646 3647 3648 template<typename Map> 3649 static void TestPersistentValueMap() { 3650 LocalContext env; 3651 v8::Isolate* isolate = env->GetIsolate(); 3652 Map map(isolate); 3653 v8::internal::GlobalHandles* global_handles = 3654 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3655 int initial_handle_count = global_handles->global_handles_count(); 3656 CHECK_EQ(0, static_cast<int>(map.Size())); 3657 { 3658 HandleScope scope(isolate); 3659 Local<v8::Object> obj = map.Get(7); 3660 CHECK(obj.IsEmpty()); 3661 Local<v8::Object> expected = v8::Object::New(isolate); 3662 map.Set(7, expected); 3663 CHECK_EQ(1, static_cast<int>(map.Size())); 3664 obj = map.Get(7); 3665 CHECK_EQ(expected, obj); 3666 { 3667 typename Map::PersistentValueReference ref = map.GetReference(7); 3668 CHECK_EQ(expected, ref.NewLocal(isolate)); 3669 } 3670 v8::UniquePersistent<v8::Object> removed = map.Remove(7); 3671 CHECK_EQ(0, static_cast<int>(map.Size())); 3672 CHECK(expected == removed); 3673 removed = map.Remove(7); 3674 CHECK(removed.IsEmpty()); 3675 map.Set(8, expected); 3676 CHECK_EQ(1, static_cast<int>(map.Size())); 3677 map.Set(8, expected); 3678 CHECK_EQ(1, static_cast<int>(map.Size())); 3679 { 3680 typename Map::PersistentValueReference ref; 3681 Local<v8::Object> expected2 = v8::Object::New(isolate); 3682 removed = map.Set(8, 3683 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref); 3684 CHECK_EQ(1, static_cast<int>(map.Size())); 3685 CHECK(expected == removed); 3686 CHECK_EQ(expected2, ref.NewLocal(isolate)); 3687 } 3688 } 3689 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3690 if (map.IsWeak()) { 3691 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()-> 3692 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3693 } else { 3694 map.Clear(); 3695 } 3696 CHECK_EQ(0, static_cast<int>(map.Size())); 3697 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3698 } 3699 3700 3701 TEST(PersistentValueMap) { 3702 // Default case, w/o weak callbacks: 3703 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >(); 3704 3705 // Custom traits with weak callbacks: 3706 typedef v8::PersistentValueMap<int, v8::Object, 3707 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap; 3708 TestPersistentValueMap<WeakPersistentValueMap>(); 3709 } 3710 3711 3712 TEST(PersistentValueVector) { 3713 LocalContext env; 3714 v8::Isolate* isolate = env->GetIsolate(); 3715 v8::internal::GlobalHandles* global_handles = 3716 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3717 int handle_count = global_handles->global_handles_count(); 3718 HandleScope scope(isolate); 3719 3720 v8::PersistentValueVector<v8::Object> vector(isolate); 3721 3722 Local<v8::Object> obj1 = v8::Object::New(isolate); 3723 Local<v8::Object> obj2 = v8::Object::New(isolate); 3724 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate)); 3725 3726 CHECK(vector.IsEmpty()); 3727 CHECK_EQ(0, static_cast<int>(vector.Size())); 3728 3729 vector.ReserveCapacity(3); 3730 CHECK(vector.IsEmpty()); 3731 3732 vector.Append(obj1); 3733 vector.Append(obj2); 3734 vector.Append(obj1); 3735 vector.Append(obj3.Pass()); 3736 vector.Append(obj1); 3737 3738 CHECK(!vector.IsEmpty()); 3739 CHECK_EQ(5, static_cast<int>(vector.Size())); 3740 CHECK(obj3.IsEmpty()); 3741 CHECK_EQ(obj1, vector.Get(0)); 3742 CHECK_EQ(obj1, vector.Get(2)); 3743 CHECK_EQ(obj1, vector.Get(4)); 3744 CHECK_EQ(obj2, vector.Get(1)); 3745 3746 CHECK_EQ(5 + handle_count, global_handles->global_handles_count()); 3747 3748 vector.Clear(); 3749 CHECK(vector.IsEmpty()); 3750 CHECK_EQ(0, static_cast<int>(vector.Size())); 3751 CHECK_EQ(handle_count, global_handles->global_handles_count()); 3752 } 3753 3754 3755 THREADED_TEST(GlobalHandleUpcast) { 3756 v8::Isolate* isolate = CcTest::isolate(); 3757 v8::HandleScope scope(isolate); 3758 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str")); 3759 v8::Persistent<String> global_string(isolate, local); 3760 v8::Persistent<Value>& global_value = 3761 v8::Persistent<Value>::Cast(global_string); 3762 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 3763 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 3764 global_string.Reset(); 3765 } 3766 3767 3768 THREADED_TEST(HandleEquality) { 3769 v8::Isolate* isolate = CcTest::isolate(); 3770 v8::Persistent<String> global1; 3771 v8::Persistent<String> global2; 3772 { 3773 v8::HandleScope scope(isolate); 3774 global1.Reset(isolate, v8_str("str")); 3775 global2.Reset(isolate, v8_str("str2")); 3776 } 3777 CHECK_EQ(global1 == global1, true); 3778 CHECK_EQ(global1 != global1, false); 3779 { 3780 v8::HandleScope scope(isolate); 3781 Local<String> local1 = Local<String>::New(isolate, global1); 3782 Local<String> local2 = Local<String>::New(isolate, global2); 3783 3784 CHECK_EQ(global1 == local1, true); 3785 CHECK_EQ(global1 != local1, false); 3786 CHECK_EQ(local1 == global1, true); 3787 CHECK_EQ(local1 != global1, false); 3788 3789 CHECK_EQ(global1 == local2, false); 3790 CHECK_EQ(global1 != local2, true); 3791 CHECK_EQ(local2 == global1, false); 3792 CHECK_EQ(local2 != global1, true); 3793 3794 CHECK_EQ(local1 == local2, false); 3795 CHECK_EQ(local1 != local2, true); 3796 3797 Local<String> anotherLocal1 = Local<String>::New(isolate, global1); 3798 CHECK_EQ(local1 == anotherLocal1, true); 3799 CHECK_EQ(local1 != anotherLocal1, false); 3800 } 3801 global1.Reset(); 3802 global2.Reset(); 3803 } 3804 3805 3806 THREADED_TEST(LocalHandle) { 3807 v8::HandleScope scope(CcTest::isolate()); 3808 v8::Local<String> local = 3809 v8::Local<String>::New(CcTest::isolate(), v8_str("str")); 3810 CHECK_EQ(local->Length(), 3); 3811 } 3812 3813 3814 class WeakCallCounter { 3815 public: 3816 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } 3817 int id() { return id_; } 3818 void increment() { number_of_weak_calls_++; } 3819 int NumberOfWeakCalls() { return number_of_weak_calls_; } 3820 private: 3821 int id_; 3822 int number_of_weak_calls_; 3823 }; 3824 3825 3826 template<typename T> 3827 struct WeakCallCounterAndPersistent { 3828 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) 3829 : counter(counter) {} 3830 WeakCallCounter* counter; 3831 v8::Persistent<T> handle; 3832 }; 3833 3834 3835 template <typename T> 3836 static void WeakPointerCallback( 3837 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) { 3838 CHECK_EQ(1234, data.GetParameter()->counter->id()); 3839 data.GetParameter()->counter->increment(); 3840 data.GetParameter()->handle.Reset(); 3841 } 3842 3843 3844 template<typename T> 3845 static UniqueId MakeUniqueId(const Persistent<T>& p) { 3846 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 3847 } 3848 3849 3850 THREADED_TEST(ApiObjectGroups) { 3851 LocalContext env; 3852 v8::Isolate* iso = env->GetIsolate(); 3853 HandleScope scope(iso); 3854 3855 WeakCallCounter counter(1234); 3856 3857 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3858 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3859 WeakCallCounterAndPersistent<Value> g1c1(&counter); 3860 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3861 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3862 WeakCallCounterAndPersistent<Value> g2c1(&counter); 3863 3864 { 3865 HandleScope scope(iso); 3866 g1s1.handle.Reset(iso, Object::New(iso)); 3867 g1s2.handle.Reset(iso, Object::New(iso)); 3868 g1c1.handle.Reset(iso, Object::New(iso)); 3869 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3870 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3871 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3872 3873 g2s1.handle.Reset(iso, Object::New(iso)); 3874 g2s2.handle.Reset(iso, Object::New(iso)); 3875 g2c1.handle.Reset(iso, Object::New(iso)); 3876 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3877 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3878 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3879 } 3880 3881 WeakCallCounterAndPersistent<Value> root(&counter); 3882 root.handle.Reset(iso, g1s1.handle); // make a root. 3883 3884 // Connect group 1 and 2, make a cycle. 3885 { 3886 HandleScope scope(iso); 3887 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())-> 3888 Set(0, Local<Value>::New(iso, g2s2.handle))); 3889 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())-> 3890 Set(0, Local<Value>::New(iso, g1s1.handle))); 3891 } 3892 3893 { 3894 UniqueId id1 = MakeUniqueId(g1s1.handle); 3895 UniqueId id2 = MakeUniqueId(g2s2.handle); 3896 iso->SetObjectGroupId(g1s1.handle, id1); 3897 iso->SetObjectGroupId(g1s2.handle, id1); 3898 iso->SetReferenceFromGroup(id1, g1c1.handle); 3899 iso->SetObjectGroupId(g2s1.handle, id2); 3900 iso->SetObjectGroupId(g2s2.handle, id2); 3901 iso->SetReferenceFromGroup(id2, g2c1.handle); 3902 } 3903 // Do a single full GC, ensure incremental marking is stopped. 3904 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3905 iso)->heap(); 3906 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3907 3908 // All object should be alive. 3909 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3910 3911 // Weaken the root. 3912 root.handle.SetWeak(&root, &WeakPointerCallback); 3913 // But make children strong roots---all the objects (except for children) 3914 // should be collectable now. 3915 g1c1.handle.ClearWeak(); 3916 g2c1.handle.ClearWeak(); 3917 3918 // Groups are deleted, rebuild groups. 3919 { 3920 UniqueId id1 = MakeUniqueId(g1s1.handle); 3921 UniqueId id2 = MakeUniqueId(g2s2.handle); 3922 iso->SetObjectGroupId(g1s1.handle, id1); 3923 iso->SetObjectGroupId(g1s2.handle, id1); 3924 iso->SetReferenceFromGroup(id1, g1c1.handle); 3925 iso->SetObjectGroupId(g2s1.handle, id2); 3926 iso->SetObjectGroupId(g2s2.handle, id2); 3927 iso->SetReferenceFromGroup(id2, g2c1.handle); 3928 } 3929 3930 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3931 3932 // All objects should be gone. 5 global handles in total. 3933 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3934 3935 // And now make children weak again and collect them. 3936 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3937 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3938 3939 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3940 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3941 } 3942 3943 3944 THREADED_TEST(ApiObjectGroupsForSubtypes) { 3945 LocalContext env; 3946 v8::Isolate* iso = env->GetIsolate(); 3947 HandleScope scope(iso); 3948 3949 WeakCallCounter counter(1234); 3950 3951 WeakCallCounterAndPersistent<Object> g1s1(&counter); 3952 WeakCallCounterAndPersistent<String> g1s2(&counter); 3953 WeakCallCounterAndPersistent<String> g1c1(&counter); 3954 WeakCallCounterAndPersistent<Object> g2s1(&counter); 3955 WeakCallCounterAndPersistent<String> g2s2(&counter); 3956 WeakCallCounterAndPersistent<String> g2c1(&counter); 3957 3958 { 3959 HandleScope scope(iso); 3960 g1s1.handle.Reset(iso, Object::New(iso)); 3961 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1")); 3962 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2")); 3963 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3964 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3965 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3966 3967 g2s1.handle.Reset(iso, Object::New(iso)); 3968 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3")); 3969 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4")); 3970 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3971 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3972 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3973 } 3974 3975 WeakCallCounterAndPersistent<Value> root(&counter); 3976 root.handle.Reset(iso, g1s1.handle); // make a root. 3977 3978 // Connect group 1 and 2, make a cycle. 3979 { 3980 HandleScope scope(iso); 3981 CHECK(Local<Object>::New(iso, g1s1.handle) 3982 ->Set(0, Local<Object>::New(iso, g2s1.handle))); 3983 CHECK(Local<Object>::New(iso, g2s1.handle) 3984 ->Set(0, Local<Object>::New(iso, g1s1.handle))); 3985 } 3986 3987 { 3988 UniqueId id1 = MakeUniqueId(g1s1.handle); 3989 UniqueId id2 = MakeUniqueId(g2s2.handle); 3990 iso->SetObjectGroupId(g1s1.handle, id1); 3991 iso->SetObjectGroupId(g1s2.handle, id1); 3992 iso->SetReference(g1s1.handle, g1c1.handle); 3993 iso->SetObjectGroupId(g2s1.handle, id2); 3994 iso->SetObjectGroupId(g2s2.handle, id2); 3995 iso->SetReferenceFromGroup(id2, g2c1.handle); 3996 } 3997 // Do a single full GC, ensure incremental marking is stopped. 3998 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3999 iso)->heap(); 4000 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4001 4002 // All object should be alive. 4003 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4004 4005 // Weaken the root. 4006 root.handle.SetWeak(&root, &WeakPointerCallback); 4007 // But make children strong roots---all the objects (except for children) 4008 // should be collectable now. 4009 g1c1.handle.ClearWeak(); 4010 g2c1.handle.ClearWeak(); 4011 4012 // Groups are deleted, rebuild groups. 4013 { 4014 UniqueId id1 = MakeUniqueId(g1s1.handle); 4015 UniqueId id2 = MakeUniqueId(g2s2.handle); 4016 iso->SetObjectGroupId(g1s1.handle, id1); 4017 iso->SetObjectGroupId(g1s2.handle, id1); 4018 iso->SetReference(g1s1.handle, g1c1.handle); 4019 iso->SetObjectGroupId(g2s1.handle, id2); 4020 iso->SetObjectGroupId(g2s2.handle, id2); 4021 iso->SetReferenceFromGroup(id2, g2c1.handle); 4022 } 4023 4024 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4025 4026 // All objects should be gone. 5 global handles in total. 4027 CHECK_EQ(5, counter.NumberOfWeakCalls()); 4028 4029 // And now make children weak again and collect them. 4030 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 4031 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 4032 4033 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4034 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4035 } 4036 4037 4038 THREADED_TEST(ApiObjectGroupsCycle) { 4039 LocalContext env; 4040 v8::Isolate* iso = env->GetIsolate(); 4041 HandleScope scope(iso); 4042 4043 WeakCallCounter counter(1234); 4044 4045 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4046 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4047 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4048 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4049 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4050 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4051 WeakCallCounterAndPersistent<Value> g4s1(&counter); 4052 WeakCallCounterAndPersistent<Value> g4s2(&counter); 4053 4054 { 4055 HandleScope scope(iso); 4056 g1s1.handle.Reset(iso, Object::New(iso)); 4057 g1s2.handle.Reset(iso, Object::New(iso)); 4058 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 4059 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 4060 CHECK(g1s1.handle.IsWeak()); 4061 CHECK(g1s2.handle.IsWeak()); 4062 4063 g2s1.handle.Reset(iso, Object::New(iso)); 4064 g2s2.handle.Reset(iso, Object::New(iso)); 4065 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 4066 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 4067 CHECK(g2s1.handle.IsWeak()); 4068 CHECK(g2s2.handle.IsWeak()); 4069 4070 g3s1.handle.Reset(iso, Object::New(iso)); 4071 g3s2.handle.Reset(iso, Object::New(iso)); 4072 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 4073 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 4074 CHECK(g3s1.handle.IsWeak()); 4075 CHECK(g3s2.handle.IsWeak()); 4076 4077 g4s1.handle.Reset(iso, Object::New(iso)); 4078 g4s2.handle.Reset(iso, Object::New(iso)); 4079 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback); 4080 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback); 4081 CHECK(g4s1.handle.IsWeak()); 4082 CHECK(g4s2.handle.IsWeak()); 4083 } 4084 4085 WeakCallCounterAndPersistent<Value> root(&counter); 4086 root.handle.Reset(iso, g1s1.handle); // make a root. 4087 4088 // Connect groups. We're building the following cycle: 4089 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4090 // groups. 4091 { 4092 UniqueId id1 = MakeUniqueId(g1s1.handle); 4093 UniqueId id2 = MakeUniqueId(g2s1.handle); 4094 UniqueId id3 = MakeUniqueId(g3s1.handle); 4095 UniqueId id4 = MakeUniqueId(g4s1.handle); 4096 iso->SetObjectGroupId(g1s1.handle, id1); 4097 iso->SetObjectGroupId(g1s2.handle, id1); 4098 iso->SetReferenceFromGroup(id1, g2s1.handle); 4099 iso->SetObjectGroupId(g2s1.handle, id2); 4100 iso->SetObjectGroupId(g2s2.handle, id2); 4101 iso->SetReferenceFromGroup(id2, g3s1.handle); 4102 iso->SetObjectGroupId(g3s1.handle, id3); 4103 iso->SetObjectGroupId(g3s2.handle, id3); 4104 iso->SetReferenceFromGroup(id3, g4s1.handle); 4105 iso->SetObjectGroupId(g4s1.handle, id4); 4106 iso->SetObjectGroupId(g4s2.handle, id4); 4107 iso->SetReferenceFromGroup(id4, g1s1.handle); 4108 } 4109 // Do a single full GC 4110 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 4111 iso)->heap(); 4112 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4113 4114 // All object should be alive. 4115 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4116 4117 // Weaken the root. 4118 root.handle.SetWeak(&root, &WeakPointerCallback); 4119 4120 // Groups are deleted, rebuild groups. 4121 { 4122 UniqueId id1 = MakeUniqueId(g1s1.handle); 4123 UniqueId id2 = MakeUniqueId(g2s1.handle); 4124 UniqueId id3 = MakeUniqueId(g3s1.handle); 4125 UniqueId id4 = MakeUniqueId(g4s1.handle); 4126 iso->SetObjectGroupId(g1s1.handle, id1); 4127 iso->SetObjectGroupId(g1s2.handle, id1); 4128 iso->SetReferenceFromGroup(id1, g2s1.handle); 4129 iso->SetObjectGroupId(g2s1.handle, id2); 4130 iso->SetObjectGroupId(g2s2.handle, id2); 4131 iso->SetReferenceFromGroup(id2, g3s1.handle); 4132 iso->SetObjectGroupId(g3s1.handle, id3); 4133 iso->SetObjectGroupId(g3s2.handle, id3); 4134 iso->SetReferenceFromGroup(id3, g4s1.handle); 4135 iso->SetObjectGroupId(g4s1.handle, id4); 4136 iso->SetObjectGroupId(g4s2.handle, id4); 4137 iso->SetReferenceFromGroup(id4, g1s1.handle); 4138 } 4139 4140 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 4141 4142 // All objects should be gone. 9 global handles in total. 4143 CHECK_EQ(9, counter.NumberOfWeakCalls()); 4144 } 4145 4146 4147 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures 4148 // on the buildbots, so was made non-threaded for the time being. 4149 TEST(ApiObjectGroupsCycleForScavenger) { 4150 i::FLAG_stress_compaction = false; 4151 i::FLAG_gc_global = false; 4152 LocalContext env; 4153 v8::Isolate* iso = env->GetIsolate(); 4154 HandleScope scope(iso); 4155 4156 WeakCallCounter counter(1234); 4157 4158 WeakCallCounterAndPersistent<Value> g1s1(&counter); 4159 WeakCallCounterAndPersistent<Value> g1s2(&counter); 4160 WeakCallCounterAndPersistent<Value> g2s1(&counter); 4161 WeakCallCounterAndPersistent<Value> g2s2(&counter); 4162 WeakCallCounterAndPersistent<Value> g3s1(&counter); 4163 WeakCallCounterAndPersistent<Value> g3s2(&counter); 4164 4165 { 4166 HandleScope scope(iso); 4167 g1s1.handle.Reset(iso, Object::New(iso)); 4168 g1s2.handle.Reset(iso, Object::New(iso)); 4169 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 4170 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 4171 4172 g2s1.handle.Reset(iso, Object::New(iso)); 4173 g2s2.handle.Reset(iso, Object::New(iso)); 4174 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 4175 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 4176 4177 g3s1.handle.Reset(iso, Object::New(iso)); 4178 g3s2.handle.Reset(iso, Object::New(iso)); 4179 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 4180 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 4181 } 4182 4183 // Make a root. 4184 WeakCallCounterAndPersistent<Value> root(&counter); 4185 root.handle.Reset(iso, g1s1.handle); 4186 root.handle.MarkPartiallyDependent(); 4187 4188 // Connect groups. We're building the following cycle: 4189 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 4190 // groups. 4191 { 4192 HandleScope handle_scope(iso); 4193 g1s1.handle.MarkPartiallyDependent(); 4194 g1s2.handle.MarkPartiallyDependent(); 4195 g2s1.handle.MarkPartiallyDependent(); 4196 g2s2.handle.MarkPartiallyDependent(); 4197 g3s1.handle.MarkPartiallyDependent(); 4198 g3s2.handle.MarkPartiallyDependent(); 4199 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4200 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4201 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 4202 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 4203 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4204 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4205 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 4206 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 4207 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4208 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4209 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 4210 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 4211 } 4212 4213 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 4214 iso)->heap(); 4215 heap->CollectAllGarbage(i::Heap::kNoGCFlags); 4216 4217 // All objects should be alive. 4218 CHECK_EQ(0, counter.NumberOfWeakCalls()); 4219 4220 // Weaken the root. 4221 root.handle.SetWeak(&root, &WeakPointerCallback); 4222 root.handle.MarkPartiallyDependent(); 4223 4224 // Groups are deleted, rebuild groups. 4225 { 4226 HandleScope handle_scope(iso); 4227 g1s1.handle.MarkPartiallyDependent(); 4228 g1s2.handle.MarkPartiallyDependent(); 4229 g2s1.handle.MarkPartiallyDependent(); 4230 g2s2.handle.MarkPartiallyDependent(); 4231 g3s1.handle.MarkPartiallyDependent(); 4232 g3s2.handle.MarkPartiallyDependent(); 4233 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 4234 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 4235 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 4236 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 4237 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 4238 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 4239 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 4240 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 4241 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 4242 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 4243 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 4244 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 4245 } 4246 4247 heap->CollectAllGarbage(i::Heap::kNoGCFlags); 4248 4249 // All objects should be gone. 7 global handles in total. 4250 CHECK_EQ(7, counter.NumberOfWeakCalls()); 4251 } 4252 4253 4254 THREADED_TEST(ScriptException) { 4255 LocalContext env; 4256 v8::HandleScope scope(env->GetIsolate()); 4257 Local<Script> script = v8_compile("throw 'panama!';"); 4258 v8::TryCatch try_catch; 4259 Local<Value> result = script->Run(); 4260 CHECK(result.IsEmpty()); 4261 CHECK(try_catch.HasCaught()); 4262 String::Utf8Value exception_value(try_catch.Exception()); 4263 CHECK_EQ(*exception_value, "panama!"); 4264 } 4265 4266 4267 TEST(TryCatchCustomException) { 4268 LocalContext env; 4269 v8::HandleScope scope(env->GetIsolate()); 4270 v8::TryCatch try_catch; 4271 CompileRun("function CustomError() { this.a = 'b'; }" 4272 "(function f() { throw new CustomError(); })();"); 4273 CHECK(try_catch.HasCaught()); 4274 CHECK(try_catch.Exception()->ToObject()-> 4275 Get(v8_str("a"))->Equals(v8_str("b"))); 4276 } 4277 4278 4279 bool message_received; 4280 4281 4282 static void check_message_0(v8::Handle<v8::Message> message, 4283 v8::Handle<Value> data) { 4284 CHECK_EQ(5.76, data->NumberValue()); 4285 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); 4286 CHECK(!message->IsSharedCrossOrigin()); 4287 message_received = true; 4288 } 4289 4290 4291 THREADED_TEST(MessageHandler0) { 4292 message_received = false; 4293 v8::HandleScope scope(CcTest::isolate()); 4294 CHECK(!message_received); 4295 LocalContext context; 4296 v8::V8::AddMessageListener(check_message_0, v8_num(5.76)); 4297 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75"); 4298 script->Run(); 4299 CHECK(message_received); 4300 // clear out the message listener 4301 v8::V8::RemoveMessageListeners(check_message_0); 4302 } 4303 4304 4305 static void check_message_1(v8::Handle<v8::Message> message, 4306 v8::Handle<Value> data) { 4307 CHECK(data->IsNumber()); 4308 CHECK_EQ(1337, data->Int32Value()); 4309 CHECK(!message->IsSharedCrossOrigin()); 4310 message_received = true; 4311 } 4312 4313 4314 TEST(MessageHandler1) { 4315 message_received = false; 4316 v8::HandleScope scope(CcTest::isolate()); 4317 CHECK(!message_received); 4318 v8::V8::AddMessageListener(check_message_1); 4319 LocalContext context; 4320 CompileRun("throw 1337;"); 4321 CHECK(message_received); 4322 // clear out the message listener 4323 v8::V8::RemoveMessageListeners(check_message_1); 4324 } 4325 4326 4327 static void check_message_2(v8::Handle<v8::Message> message, 4328 v8::Handle<Value> data) { 4329 LocalContext context; 4330 CHECK(data->IsObject()); 4331 v8::Local<v8::Value> hidden_property = 4332 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); 4333 CHECK(v8_str("hidden value")->Equals(hidden_property)); 4334 CHECK(!message->IsSharedCrossOrigin()); 4335 message_received = true; 4336 } 4337 4338 4339 TEST(MessageHandler2) { 4340 message_received = false; 4341 v8::HandleScope scope(CcTest::isolate()); 4342 CHECK(!message_received); 4343 v8::V8::AddMessageListener(check_message_2); 4344 LocalContext context; 4345 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 4346 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), 4347 v8_str("hidden value")); 4348 context->Global()->Set(v8_str("error"), error); 4349 CompileRun("throw error;"); 4350 CHECK(message_received); 4351 // clear out the message listener 4352 v8::V8::RemoveMessageListeners(check_message_2); 4353 } 4354 4355 4356 static void check_message_3(v8::Handle<v8::Message> message, 4357 v8::Handle<Value> data) { 4358 CHECK(message->IsSharedCrossOrigin()); 4359 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); 4360 message_received = true; 4361 } 4362 4363 4364 TEST(MessageHandler3) { 4365 message_received = false; 4366 v8::Isolate* isolate = CcTest::isolate(); 4367 v8::HandleScope scope(isolate); 4368 CHECK(!message_received); 4369 v8::V8::AddMessageListener(check_message_3); 4370 LocalContext context; 4371 v8::ScriptOrigin origin = 4372 v8::ScriptOrigin(v8_str("6.75"), 4373 v8::Integer::New(isolate, 1), 4374 v8::Integer::New(isolate, 2), 4375 v8::True(isolate)); 4376 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4377 &origin); 4378 script->Run(); 4379 CHECK(message_received); 4380 // clear out the message listener 4381 v8::V8::RemoveMessageListeners(check_message_3); 4382 } 4383 4384 4385 static void check_message_4(v8::Handle<v8::Message> message, 4386 v8::Handle<Value> data) { 4387 CHECK(!message->IsSharedCrossOrigin()); 4388 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); 4389 message_received = true; 4390 } 4391 4392 4393 TEST(MessageHandler4) { 4394 message_received = false; 4395 v8::Isolate* isolate = CcTest::isolate(); 4396 v8::HandleScope scope(isolate); 4397 CHECK(!message_received); 4398 v8::V8::AddMessageListener(check_message_4); 4399 LocalContext context; 4400 v8::ScriptOrigin origin = 4401 v8::ScriptOrigin(v8_str("6.75"), 4402 v8::Integer::New(isolate, 1), 4403 v8::Integer::New(isolate, 2), 4404 v8::False(isolate)); 4405 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4406 &origin); 4407 script->Run(); 4408 CHECK(message_received); 4409 // clear out the message listener 4410 v8::V8::RemoveMessageListeners(check_message_4); 4411 } 4412 4413 4414 static void check_message_5a(v8::Handle<v8::Message> message, 4415 v8::Handle<Value> data) { 4416 CHECK(message->IsSharedCrossOrigin()); 4417 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); 4418 message_received = true; 4419 } 4420 4421 4422 static void check_message_5b(v8::Handle<v8::Message> message, 4423 v8::Handle<Value> data) { 4424 CHECK(!message->IsSharedCrossOrigin()); 4425 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); 4426 message_received = true; 4427 } 4428 4429 4430 TEST(MessageHandler5) { 4431 message_received = false; 4432 v8::Isolate* isolate = CcTest::isolate(); 4433 v8::HandleScope scope(isolate); 4434 CHECK(!message_received); 4435 v8::V8::AddMessageListener(check_message_5a); 4436 LocalContext context; 4437 v8::ScriptOrigin origin = 4438 v8::ScriptOrigin(v8_str("6.75"), 4439 v8::Integer::New(isolate, 1), 4440 v8::Integer::New(isolate, 2), 4441 v8::True(isolate)); 4442 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4443 &origin); 4444 script->Run(); 4445 CHECK(message_received); 4446 // clear out the message listener 4447 v8::V8::RemoveMessageListeners(check_message_5a); 4448 4449 message_received = false; 4450 v8::V8::AddMessageListener(check_message_5b); 4451 origin = 4452 v8::ScriptOrigin(v8_str("6.75"), 4453 v8::Integer::New(isolate, 1), 4454 v8::Integer::New(isolate, 2), 4455 v8::False(isolate)); 4456 script = Script::Compile(v8_str("throw 'error'"), 4457 &origin); 4458 script->Run(); 4459 CHECK(message_received); 4460 // clear out the message listener 4461 v8::V8::RemoveMessageListeners(check_message_5b); 4462 } 4463 4464 4465 THREADED_TEST(GetSetProperty) { 4466 LocalContext context; 4467 v8::Isolate* isolate = context->GetIsolate(); 4468 v8::HandleScope scope(isolate); 4469 context->Global()->Set(v8_str("foo"), v8_num(14)); 4470 context->Global()->Set(v8_str("12"), v8_num(92)); 4471 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32)); 4472 context->Global()->Set(v8_num(13), v8_num(56)); 4473 Local<Value> foo = CompileRun("this.foo"); 4474 CHECK_EQ(14, foo->Int32Value()); 4475 Local<Value> twelve = CompileRun("this[12]"); 4476 CHECK_EQ(92, twelve->Int32Value()); 4477 Local<Value> sixteen = CompileRun("this[16]"); 4478 CHECK_EQ(32, sixteen->Int32Value()); 4479 Local<Value> thirteen = CompileRun("this[13]"); 4480 CHECK_EQ(56, thirteen->Int32Value()); 4481 CHECK_EQ(92, 4482 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value()); 4483 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value()); 4484 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value()); 4485 CHECK_EQ(32, 4486 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value()); 4487 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value()); 4488 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value()); 4489 CHECK_EQ(56, 4490 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value()); 4491 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value()); 4492 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value()); 4493 } 4494 4495 4496 THREADED_TEST(PropertyAttributes) { 4497 LocalContext context; 4498 v8::HandleScope scope(context->GetIsolate()); 4499 // none 4500 Local<String> prop = v8_str("none"); 4501 context->Global()->Set(prop, v8_num(7)); 4502 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4503 // read-only 4504 prop = v8_str("read_only"); 4505 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly); 4506 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4507 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); 4508 CompileRun("read_only = 9"); 4509 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4510 context->Global()->Set(prop, v8_num(10)); 4511 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4512 // dont-delete 4513 prop = v8_str("dont_delete"); 4514 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete); 4515 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4516 CompileRun("delete dont_delete"); 4517 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4518 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); 4519 // dont-enum 4520 prop = v8_str("dont_enum"); 4521 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum); 4522 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); 4523 // absent 4524 prop = v8_str("absent"); 4525 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4526 Local<Value> fake_prop = v8_num(1); 4527 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); 4528 // exception 4529 TryCatch try_catch; 4530 Local<Value> exception = 4531 CompileRun("({ toString: function() { throw 'exception';} })"); 4532 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); 4533 CHECK(try_catch.HasCaught()); 4534 String::Utf8Value exception_value(try_catch.Exception()); 4535 CHECK_EQ("exception", *exception_value); 4536 try_catch.Reset(); 4537 } 4538 4539 4540 THREADED_TEST(Array) { 4541 LocalContext context; 4542 v8::HandleScope scope(context->GetIsolate()); 4543 Local<v8::Array> array = v8::Array::New(context->GetIsolate()); 4544 CHECK_EQ(0, array->Length()); 4545 CHECK(array->Get(0)->IsUndefined()); 4546 CHECK(!array->Has(0)); 4547 CHECK(array->Get(100)->IsUndefined()); 4548 CHECK(!array->Has(100)); 4549 array->Set(2, v8_num(7)); 4550 CHECK_EQ(3, array->Length()); 4551 CHECK(!array->Has(0)); 4552 CHECK(!array->Has(1)); 4553 CHECK(array->Has(2)); 4554 CHECK_EQ(7, array->Get(2)->Int32Value()); 4555 Local<Value> obj = CompileRun("[1, 2, 3]"); 4556 Local<v8::Array> arr = obj.As<v8::Array>(); 4557 CHECK_EQ(3, arr->Length()); 4558 CHECK_EQ(1, arr->Get(0)->Int32Value()); 4559 CHECK_EQ(2, arr->Get(1)->Int32Value()); 4560 CHECK_EQ(3, arr->Get(2)->Int32Value()); 4561 array = v8::Array::New(context->GetIsolate(), 27); 4562 CHECK_EQ(27, array->Length()); 4563 array = v8::Array::New(context->GetIsolate(), -27); 4564 CHECK_EQ(0, array->Length()); 4565 } 4566 4567 4568 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 4569 v8::EscapableHandleScope scope(args.GetIsolate()); 4570 ApiTestFuzzer::Fuzz(); 4571 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); 4572 for (int i = 0; i < args.Length(); i++) 4573 result->Set(i, args[i]); 4574 args.GetReturnValue().Set(scope.Escape(result)); 4575 } 4576 4577 4578 THREADED_TEST(Vector) { 4579 v8::Isolate* isolate = CcTest::isolate(); 4580 v8::HandleScope scope(isolate); 4581 Local<ObjectTemplate> global = ObjectTemplate::New(isolate); 4582 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF)); 4583 LocalContext context(0, global); 4584 4585 const char* fun = "f()"; 4586 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 4587 CHECK_EQ(0, a0->Length()); 4588 4589 const char* fun2 = "f(11)"; 4590 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 4591 CHECK_EQ(1, a1->Length()); 4592 CHECK_EQ(11, a1->Get(0)->Int32Value()); 4593 4594 const char* fun3 = "f(12, 13)"; 4595 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 4596 CHECK_EQ(2, a2->Length()); 4597 CHECK_EQ(12, a2->Get(0)->Int32Value()); 4598 CHECK_EQ(13, a2->Get(1)->Int32Value()); 4599 4600 const char* fun4 = "f(14, 15, 16)"; 4601 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 4602 CHECK_EQ(3, a3->Length()); 4603 CHECK_EQ(14, a3->Get(0)->Int32Value()); 4604 CHECK_EQ(15, a3->Get(1)->Int32Value()); 4605 CHECK_EQ(16, a3->Get(2)->Int32Value()); 4606 4607 const char* fun5 = "f(17, 18, 19, 20)"; 4608 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 4609 CHECK_EQ(4, a4->Length()); 4610 CHECK_EQ(17, a4->Get(0)->Int32Value()); 4611 CHECK_EQ(18, a4->Get(1)->Int32Value()); 4612 CHECK_EQ(19, a4->Get(2)->Int32Value()); 4613 CHECK_EQ(20, a4->Get(3)->Int32Value()); 4614 } 4615 4616 4617 THREADED_TEST(FunctionCall) { 4618 LocalContext context; 4619 v8::Isolate* isolate = context->GetIsolate(); 4620 v8::HandleScope scope(isolate); 4621 CompileRun( 4622 "function Foo() {" 4623 " var result = [];" 4624 " for (var i = 0; i < arguments.length; i++) {" 4625 " result.push(arguments[i]);" 4626 " }" 4627 " return result;" 4628 "}" 4629 "function ReturnThisSloppy() {" 4630 " return this;" 4631 "}" 4632 "function ReturnThisStrict() {" 4633 " 'use strict';" 4634 " return this;" 4635 "}"); 4636 Local<Function> Foo = 4637 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4638 Local<Function> ReturnThisSloppy = 4639 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy"))); 4640 Local<Function> ReturnThisStrict = 4641 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict"))); 4642 4643 v8::Handle<Value>* args0 = NULL; 4644 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0)); 4645 CHECK_EQ(0, a0->Length()); 4646 4647 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4648 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1)); 4649 CHECK_EQ(1, a1->Length()); 4650 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4651 4652 v8::Handle<Value> args2[] = { v8_num(2.2), 4653 v8_num(3.3) }; 4654 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2)); 4655 CHECK_EQ(2, a2->Length()); 4656 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4657 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4658 4659 v8::Handle<Value> args3[] = { v8_num(4.4), 4660 v8_num(5.5), 4661 v8_num(6.6) }; 4662 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3)); 4663 CHECK_EQ(3, a3->Length()); 4664 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4665 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4666 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4667 4668 v8::Handle<Value> args4[] = { v8_num(7.7), 4669 v8_num(8.8), 4670 v8_num(9.9), 4671 v8_num(10.11) }; 4672 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4)); 4673 CHECK_EQ(4, a4->Length()); 4674 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4675 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4676 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4677 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue()); 4678 4679 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL); 4680 CHECK(r1->StrictEquals(context->Global())); 4681 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL); 4682 CHECK(r2->StrictEquals(context->Global())); 4683 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL); 4684 CHECK(r3->IsNumberObject()); 4685 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf()); 4686 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL); 4687 CHECK(r4->IsStringObject()); 4688 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 4689 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL); 4690 CHECK(r5->IsBooleanObject()); 4691 CHECK(r5.As<v8::BooleanObject>()->ValueOf()); 4692 4693 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL); 4694 CHECK(r6->IsUndefined()); 4695 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL); 4696 CHECK(r7->IsNull()); 4697 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL); 4698 CHECK(r8->StrictEquals(v8_num(42))); 4699 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL); 4700 CHECK(r9->StrictEquals(v8_str("hello"))); 4701 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL); 4702 CHECK(r10->StrictEquals(v8::True(isolate))); 4703 } 4704 4705 4706 THREADED_TEST(ConstructCall) { 4707 LocalContext context; 4708 v8::Isolate* isolate = context->GetIsolate(); 4709 v8::HandleScope scope(isolate); 4710 CompileRun( 4711 "function Foo() {" 4712 " var result = [];" 4713 " for (var i = 0; i < arguments.length; i++) {" 4714 " result.push(arguments[i]);" 4715 " }" 4716 " return result;" 4717 "}"); 4718 Local<Function> Foo = 4719 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4720 4721 v8::Handle<Value>* args0 = NULL; 4722 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0)); 4723 CHECK_EQ(0, a0->Length()); 4724 4725 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4726 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1)); 4727 CHECK_EQ(1, a1->Length()); 4728 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4729 4730 v8::Handle<Value> args2[] = { v8_num(2.2), 4731 v8_num(3.3) }; 4732 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2)); 4733 CHECK_EQ(2, a2->Length()); 4734 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4735 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4736 4737 v8::Handle<Value> args3[] = { v8_num(4.4), 4738 v8_num(5.5), 4739 v8_num(6.6) }; 4740 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3)); 4741 CHECK_EQ(3, a3->Length()); 4742 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4743 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4744 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4745 4746 v8::Handle<Value> args4[] = { v8_num(7.7), 4747 v8_num(8.8), 4748 v8_num(9.9), 4749 v8_num(10.11) }; 4750 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4)); 4751 CHECK_EQ(4, a4->Length()); 4752 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue()); 4753 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue()); 4754 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue()); 4755 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue()); 4756 } 4757 4758 4759 static void CheckUncle(v8::TryCatch* try_catch) { 4760 CHECK(try_catch->HasCaught()); 4761 String::Utf8Value str_value(try_catch->Exception()); 4762 CHECK_EQ(*str_value, "uncle?"); 4763 try_catch->Reset(); 4764 } 4765 4766 4767 THREADED_TEST(ConversionNumber) { 4768 LocalContext env; 4769 v8::HandleScope scope(env->GetIsolate()); 4770 // Very large number. 4771 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4772 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4773 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value()); 4774 CHECK_EQ(0, obj->ToInt32()->Value()); 4775 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned. 4776 // Large number. 4777 CompileRun("var obj = -1234567890123;"); 4778 obj = env->Global()->Get(v8_str("obj")); 4779 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value()); 4780 CHECK_EQ(-1912276171, obj->ToInt32()->Value()); 4781 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT 4782 // Small positive integer. 4783 CompileRun("var obj = 42;"); 4784 obj = env->Global()->Get(v8_str("obj")); 4785 CHECK_EQ(42.0, obj->ToNumber()->Value()); 4786 CHECK_EQ(42, obj->ToInt32()->Value()); 4787 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4788 // Negative integer. 4789 CompileRun("var obj = -37;"); 4790 obj = env->Global()->Get(v8_str("obj")); 4791 CHECK_EQ(-37.0, obj->ToNumber()->Value()); 4792 CHECK_EQ(-37, obj->ToInt32()->Value()); 4793 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT 4794 // Positive non-int32 integer. 4795 CompileRun("var obj = 0x81234567;"); 4796 obj = env->Global()->Get(v8_str("obj")); 4797 CHECK_EQ(2166572391.0, obj->ToNumber()->Value()); 4798 CHECK_EQ(-2128394905, obj->ToInt32()->Value()); 4799 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT 4800 // Fraction. 4801 CompileRun("var obj = 42.3;"); 4802 obj = env->Global()->Get(v8_str("obj")); 4803 CHECK_EQ(42.3, obj->ToNumber()->Value()); 4804 CHECK_EQ(42, obj->ToInt32()->Value()); 4805 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4806 // Large negative fraction. 4807 CompileRun("var obj = -5726623061.75;"); 4808 obj = env->Global()->Get(v8_str("obj")); 4809 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value()); 4810 CHECK_EQ(-1431655765, obj->ToInt32()->Value()); 4811 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT 4812 } 4813 4814 4815 THREADED_TEST(isNumberType) { 4816 LocalContext env; 4817 v8::HandleScope scope(env->GetIsolate()); 4818 // Very large number. 4819 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4820 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4821 CHECK(!obj->IsInt32()); 4822 CHECK(!obj->IsUint32()); 4823 // Large negative number. 4824 CompileRun("var obj = -1234567890123;"); 4825 obj = env->Global()->Get(v8_str("obj")); 4826 CHECK(!obj->IsInt32()); 4827 CHECK(!obj->IsUint32()); 4828 // Small positive integer. 4829 CompileRun("var obj = 42;"); 4830 obj = env->Global()->Get(v8_str("obj")); 4831 CHECK(obj->IsInt32()); 4832 CHECK(obj->IsUint32()); 4833 // Negative integer. 4834 CompileRun("var obj = -37;"); 4835 obj = env->Global()->Get(v8_str("obj")); 4836 CHECK(obj->IsInt32()); 4837 CHECK(!obj->IsUint32()); 4838 // Positive non-int32 integer. 4839 CompileRun("var obj = 0x81234567;"); 4840 obj = env->Global()->Get(v8_str("obj")); 4841 CHECK(!obj->IsInt32()); 4842 CHECK(obj->IsUint32()); 4843 // Fraction. 4844 CompileRun("var obj = 42.3;"); 4845 obj = env->Global()->Get(v8_str("obj")); 4846 CHECK(!obj->IsInt32()); 4847 CHECK(!obj->IsUint32()); 4848 // Large negative fraction. 4849 CompileRun("var obj = -5726623061.75;"); 4850 obj = env->Global()->Get(v8_str("obj")); 4851 CHECK(!obj->IsInt32()); 4852 CHECK(!obj->IsUint32()); 4853 // Positive zero 4854 CompileRun("var obj = 0.0;"); 4855 obj = env->Global()->Get(v8_str("obj")); 4856 CHECK(obj->IsInt32()); 4857 CHECK(obj->IsUint32()); 4858 // Positive zero 4859 CompileRun("var obj = -0.0;"); 4860 obj = env->Global()->Get(v8_str("obj")); 4861 CHECK(!obj->IsInt32()); 4862 CHECK(!obj->IsUint32()); 4863 } 4864 4865 4866 THREADED_TEST(ConversionException) { 4867 LocalContext env; 4868 v8::Isolate* isolate = env->GetIsolate(); 4869 v8::HandleScope scope(isolate); 4870 CompileRun( 4871 "function TestClass() { };" 4872 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 4873 "var obj = new TestClass();"); 4874 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4875 4876 v8::TryCatch try_catch; 4877 4878 Local<Value> to_string_result = obj->ToString(); 4879 CHECK(to_string_result.IsEmpty()); 4880 CheckUncle(&try_catch); 4881 4882 Local<Value> to_number_result = obj->ToNumber(); 4883 CHECK(to_number_result.IsEmpty()); 4884 CheckUncle(&try_catch); 4885 4886 Local<Value> to_integer_result = obj->ToInteger(); 4887 CHECK(to_integer_result.IsEmpty()); 4888 CheckUncle(&try_catch); 4889 4890 Local<Value> to_uint32_result = obj->ToUint32(); 4891 CHECK(to_uint32_result.IsEmpty()); 4892 CheckUncle(&try_catch); 4893 4894 Local<Value> to_int32_result = obj->ToInt32(); 4895 CHECK(to_int32_result.IsEmpty()); 4896 CheckUncle(&try_catch); 4897 4898 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(); 4899 CHECK(to_object_result.IsEmpty()); 4900 CHECK(try_catch.HasCaught()); 4901 try_catch.Reset(); 4902 4903 int32_t int32_value = obj->Int32Value(); 4904 CHECK_EQ(0, int32_value); 4905 CheckUncle(&try_catch); 4906 4907 uint32_t uint32_value = obj->Uint32Value(); 4908 CHECK_EQ(0, uint32_value); 4909 CheckUncle(&try_catch); 4910 4911 double number_value = obj->NumberValue(); 4912 CHECK_NE(0, std::isnan(number_value)); 4913 CheckUncle(&try_catch); 4914 4915 int64_t integer_value = obj->IntegerValue(); 4916 CHECK_EQ(0.0, static_cast<double>(integer_value)); 4917 CheckUncle(&try_catch); 4918 } 4919 4920 4921 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 4922 ApiTestFuzzer::Fuzz(); 4923 args.GetIsolate()->ThrowException(v8_str("konto")); 4924 } 4925 4926 4927 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 4928 if (args.Length() < 1) { 4929 args.GetReturnValue().Set(false); 4930 return; 4931 } 4932 v8::HandleScope scope(args.GetIsolate()); 4933 v8::TryCatch try_catch; 4934 Local<Value> result = CompileRun(args[0]->ToString()); 4935 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 4936 args.GetReturnValue().Set(try_catch.HasCaught()); 4937 } 4938 4939 4940 THREADED_TEST(APICatch) { 4941 v8::Isolate* isolate = CcTest::isolate(); 4942 v8::HandleScope scope(isolate); 4943 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4944 templ->Set(v8_str("ThrowFromC"), 4945 v8::FunctionTemplate::New(isolate, ThrowFromC)); 4946 LocalContext context(0, templ); 4947 CompileRun( 4948 "var thrown = false;" 4949 "try {" 4950 " ThrowFromC();" 4951 "} catch (e) {" 4952 " thrown = true;" 4953 "}"); 4954 Local<Value> thrown = context->Global()->Get(v8_str("thrown")); 4955 CHECK(thrown->BooleanValue()); 4956 } 4957 4958 4959 THREADED_TEST(APIThrowTryCatch) { 4960 v8::Isolate* isolate = CcTest::isolate(); 4961 v8::HandleScope scope(isolate); 4962 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4963 templ->Set(v8_str("ThrowFromC"), 4964 v8::FunctionTemplate::New(isolate, ThrowFromC)); 4965 LocalContext context(0, templ); 4966 v8::TryCatch try_catch; 4967 CompileRun("ThrowFromC();"); 4968 CHECK(try_catch.HasCaught()); 4969 } 4970 4971 4972 // Test that a try-finally block doesn't shadow a try-catch block 4973 // when setting up an external handler. 4974 // 4975 // BUG(271): Some of the exception propagation does not work on the 4976 // ARM simulator because the simulator separates the C++ stack and the 4977 // JS stack. This test therefore fails on the simulator. The test is 4978 // not threaded to allow the threading tests to run on the simulator. 4979 TEST(TryCatchInTryFinally) { 4980 v8::Isolate* isolate = CcTest::isolate(); 4981 v8::HandleScope scope(isolate); 4982 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 4983 templ->Set(v8_str("CCatcher"), 4984 v8::FunctionTemplate::New(isolate, CCatcher)); 4985 LocalContext context(0, templ); 4986 Local<Value> result = CompileRun("try {" 4987 " try {" 4988 " CCatcher('throw 7;');" 4989 " } finally {" 4990 " }" 4991 "} catch (e) {" 4992 "}"); 4993 CHECK(result->IsTrue()); 4994 } 4995 4996 4997 static void check_reference_error_message( 4998 v8::Handle<v8::Message> message, 4999 v8::Handle<v8::Value> data) { 5000 const char* reference_error = "Uncaught ReferenceError: asdf is not defined"; 5001 CHECK(message->Get()->Equals(v8_str(reference_error))); 5002 } 5003 5004 5005 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) { 5006 ApiTestFuzzer::Fuzz(); 5007 CHECK(false); 5008 } 5009 5010 5011 // Test that overwritten methods are not invoked on uncaught exception 5012 // formatting. However, they are invoked when performing normal error 5013 // string conversions. 5014 TEST(APIThrowMessageOverwrittenToString) { 5015 v8::Isolate* isolate = CcTest::isolate(); 5016 v8::HandleScope scope(isolate); 5017 v8::V8::AddMessageListener(check_reference_error_message); 5018 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5019 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail)); 5020 LocalContext context(NULL, templ); 5021 CompileRun("asdf;"); 5022 CompileRun("var limit = {};" 5023 "limit.valueOf = fail;" 5024 "Error.stackTraceLimit = limit;"); 5025 CompileRun("asdf"); 5026 CompileRun("Array.prototype.pop = fail;"); 5027 CompileRun("Object.prototype.hasOwnProperty = fail;"); 5028 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); 5029 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); 5030 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); 5031 CompileRun("ReferenceError.prototype.toString =" 5032 " function() { return 'Whoops' }"); 5033 CompileRun("asdf;"); 5034 CompileRun("ReferenceError.prototype.constructor.name = void 0;"); 5035 CompileRun("asdf;"); 5036 CompileRun("ReferenceError.prototype.constructor = void 0;"); 5037 CompileRun("asdf;"); 5038 CompileRun("ReferenceError.prototype.__proto__ = new Object();"); 5039 CompileRun("asdf;"); 5040 CompileRun("ReferenceError.prototype = new Object();"); 5041 CompileRun("asdf;"); 5042 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }"); 5043 CHECK(string->Equals(v8_str("Whoops"))); 5044 CompileRun("ReferenceError.prototype.constructor = new Object();" 5045 "ReferenceError.prototype.constructor.name = 1;" 5046 "Number.prototype.toString = function() { return 'Whoops'; };" 5047 "ReferenceError.prototype.toString = Object.prototype.toString;"); 5048 CompileRun("asdf;"); 5049 v8::V8::RemoveMessageListeners(check_reference_error_message); 5050 } 5051 5052 5053 static void check_custom_error_tostring( 5054 v8::Handle<v8::Message> message, 5055 v8::Handle<v8::Value> data) { 5056 const char* uncaught_error = "Uncaught MyError toString"; 5057 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 5058 } 5059 5060 5061 TEST(CustomErrorToString) { 5062 LocalContext context; 5063 v8::HandleScope scope(context->GetIsolate()); 5064 v8::V8::AddMessageListener(check_custom_error_tostring); 5065 CompileRun( 5066 "function MyError(name, message) { " 5067 " this.name = name; " 5068 " this.message = message; " 5069 "} " 5070 "MyError.prototype = Object.create(Error.prototype); " 5071 "MyError.prototype.toString = function() { " 5072 " return 'MyError toString'; " 5073 "}; " 5074 "throw new MyError('my name', 'my message'); "); 5075 v8::V8::RemoveMessageListeners(check_custom_error_tostring); 5076 } 5077 5078 5079 static void check_custom_error_message( 5080 v8::Handle<v8::Message> message, 5081 v8::Handle<v8::Value> data) { 5082 const char* uncaught_error = "Uncaught MyError: my message"; 5083 printf("%s\n", *v8::String::Utf8Value(message->Get())); 5084 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 5085 } 5086 5087 5088 TEST(CustomErrorMessage) { 5089 LocalContext context; 5090 v8::HandleScope scope(context->GetIsolate()); 5091 v8::V8::AddMessageListener(check_custom_error_message); 5092 5093 // Handlebars. 5094 CompileRun( 5095 "function MyError(msg) { " 5096 " this.name = 'MyError'; " 5097 " this.message = msg; " 5098 "} " 5099 "MyError.prototype = new Error(); " 5100 "throw new MyError('my message'); "); 5101 5102 // Closure. 5103 CompileRun( 5104 "function MyError(msg) { " 5105 " this.name = 'MyError'; " 5106 " this.message = msg; " 5107 "} " 5108 "inherits = function(childCtor, parentCtor) { " 5109 " function tempCtor() {}; " 5110 " tempCtor.prototype = parentCtor.prototype; " 5111 " childCtor.superClass_ = parentCtor.prototype; " 5112 " childCtor.prototype = new tempCtor(); " 5113 " childCtor.prototype.constructor = childCtor; " 5114 "}; " 5115 "inherits(MyError, Error); " 5116 "throw new MyError('my message'); "); 5117 5118 // Object.create. 5119 CompileRun( 5120 "function MyError(msg) { " 5121 " this.name = 'MyError'; " 5122 " this.message = msg; " 5123 "} " 5124 "MyError.prototype = Object.create(Error.prototype); " 5125 "throw new MyError('my message'); "); 5126 5127 v8::V8::RemoveMessageListeners(check_custom_error_message); 5128 } 5129 5130 5131 static void receive_message(v8::Handle<v8::Message> message, 5132 v8::Handle<v8::Value> data) { 5133 message->Get(); 5134 message_received = true; 5135 } 5136 5137 5138 TEST(APIThrowMessage) { 5139 message_received = false; 5140 v8::Isolate* isolate = CcTest::isolate(); 5141 v8::HandleScope scope(isolate); 5142 v8::V8::AddMessageListener(receive_message); 5143 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5144 templ->Set(v8_str("ThrowFromC"), 5145 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5146 LocalContext context(0, templ); 5147 CompileRun("ThrowFromC();"); 5148 CHECK(message_received); 5149 v8::V8::RemoveMessageListeners(receive_message); 5150 } 5151 5152 5153 TEST(APIThrowMessageAndVerboseTryCatch) { 5154 message_received = false; 5155 v8::Isolate* isolate = CcTest::isolate(); 5156 v8::HandleScope scope(isolate); 5157 v8::V8::AddMessageListener(receive_message); 5158 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5159 templ->Set(v8_str("ThrowFromC"), 5160 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5161 LocalContext context(0, templ); 5162 v8::TryCatch try_catch; 5163 try_catch.SetVerbose(true); 5164 Local<Value> result = CompileRun("ThrowFromC();"); 5165 CHECK(try_catch.HasCaught()); 5166 CHECK(result.IsEmpty()); 5167 CHECK(message_received); 5168 v8::V8::RemoveMessageListeners(receive_message); 5169 } 5170 5171 5172 TEST(APIStackOverflowAndVerboseTryCatch) { 5173 message_received = false; 5174 LocalContext context; 5175 v8::HandleScope scope(context->GetIsolate()); 5176 v8::V8::AddMessageListener(receive_message); 5177 v8::TryCatch try_catch; 5178 try_catch.SetVerbose(true); 5179 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 5180 CHECK(try_catch.HasCaught()); 5181 CHECK(result.IsEmpty()); 5182 CHECK(message_received); 5183 v8::V8::RemoveMessageListeners(receive_message); 5184 } 5185 5186 5187 THREADED_TEST(ExternalScriptException) { 5188 v8::Isolate* isolate = CcTest::isolate(); 5189 v8::HandleScope scope(isolate); 5190 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5191 templ->Set(v8_str("ThrowFromC"), 5192 v8::FunctionTemplate::New(isolate, ThrowFromC)); 5193 LocalContext context(0, templ); 5194 5195 v8::TryCatch try_catch; 5196 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';"); 5197 CHECK(result.IsEmpty()); 5198 CHECK(try_catch.HasCaught()); 5199 String::Utf8Value exception_value(try_catch.Exception()); 5200 CHECK_EQ("konto", *exception_value); 5201 } 5202 5203 5204 5205 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 5206 ApiTestFuzzer::Fuzz(); 5207 CHECK_EQ(4, args.Length()); 5208 int count = args[0]->Int32Value(); 5209 int cInterval = args[2]->Int32Value(); 5210 if (count == 0) { 5211 args.GetIsolate()->ThrowException(v8_str("FromC")); 5212 return; 5213 } else { 5214 Local<v8::Object> global = 5215 args.GetIsolate()->GetCurrentContext()->Global(); 5216 Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); 5217 v8::Handle<Value> argv[] = { v8_num(count - 1), 5218 args[1], 5219 args[2], 5220 args[3] }; 5221 if (count % cInterval == 0) { 5222 v8::TryCatch try_catch; 5223 Local<Value> result = fun.As<Function>()->Call(global, 4, argv); 5224 int expected = args[3]->Int32Value(); 5225 if (try_catch.HasCaught()) { 5226 CHECK_EQ(expected, count); 5227 CHECK(result.IsEmpty()); 5228 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 5229 } else { 5230 CHECK_NE(expected, count); 5231 } 5232 args.GetReturnValue().Set(result); 5233 return; 5234 } else { 5235 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv)); 5236 return; 5237 } 5238 } 5239 } 5240 5241 5242 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 5243 ApiTestFuzzer::Fuzz(); 5244 CHECK_EQ(3, args.Length()); 5245 bool equality = args[0]->BooleanValue(); 5246 int count = args[1]->Int32Value(); 5247 int expected = args[2]->Int32Value(); 5248 if (equality) { 5249 CHECK_EQ(count, expected); 5250 } else { 5251 CHECK_NE(count, expected); 5252 } 5253 } 5254 5255 5256 THREADED_TEST(EvalInTryFinally) { 5257 LocalContext context; 5258 v8::HandleScope scope(context->GetIsolate()); 5259 v8::TryCatch try_catch; 5260 CompileRun("(function() {" 5261 " try {" 5262 " eval('asldkf (*&^&*^');" 5263 " } finally {" 5264 " return;" 5265 " }" 5266 "})()"); 5267 CHECK(!try_catch.HasCaught()); 5268 } 5269 5270 5271 // This test works by making a stack of alternating JavaScript and C 5272 // activations. These activations set up exception handlers with regular 5273 // intervals, one interval for C activations and another for JavaScript 5274 // activations. When enough activations have been created an exception is 5275 // thrown and we check that the right activation catches the exception and that 5276 // no other activations do. The right activation is always the topmost one with 5277 // a handler, regardless of whether it is in JavaScript or C. 5278 // 5279 // The notation used to describe a test case looks like this: 5280 // 5281 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5282 // 5283 // Each entry is an activation, either JS or C. The index is the count at that 5284 // level. Stars identify activations with exception handlers, the @ identifies 5285 // the exception handler that should catch the exception. 5286 // 5287 // BUG(271): Some of the exception propagation does not work on the 5288 // ARM simulator because the simulator separates the C++ stack and the 5289 // JS stack. This test therefore fails on the simulator. The test is 5290 // not threaded to allow the threading tests to run on the simulator. 5291 TEST(ExceptionOrder) { 5292 v8::Isolate* isolate = CcTest::isolate(); 5293 v8::HandleScope scope(isolate); 5294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5295 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck)); 5296 templ->Set(v8_str("CThrowCountDown"), 5297 v8::FunctionTemplate::New(isolate, CThrowCountDown)); 5298 LocalContext context(0, templ); 5299 CompileRun( 5300 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 5301 " if (count == 0) throw 'FromJS';" 5302 " if (count % jsInterval == 0) {" 5303 " try {" 5304 " var value = CThrowCountDown(count - 1," 5305 " jsInterval," 5306 " cInterval," 5307 " expected);" 5308 " check(false, count, expected);" 5309 " return value;" 5310 " } catch (e) {" 5311 " check(true, count, expected);" 5312 " }" 5313 " } else {" 5314 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 5315 " }" 5316 "}"); 5317 Local<Function> fun = 5318 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown"))); 5319 5320 const int argc = 4; 5321 // count jsInterval cInterval expected 5322 5323 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5324 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) }; 5325 fun->Call(fun, argc, a0); 5326 5327 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 5328 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) }; 5329 fun->Call(fun, argc, a1); 5330 5331 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 5332 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) }; 5333 fun->Call(fun, argc, a2); 5334 5335 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 5336 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) }; 5337 fun->Call(fun, argc, a3); 5338 5339 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 5340 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) }; 5341 fun->Call(fun, argc, a4); 5342 5343 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 5344 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) }; 5345 fun->Call(fun, argc, a5); 5346 } 5347 5348 5349 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 5350 ApiTestFuzzer::Fuzz(); 5351 CHECK_EQ(1, args.Length()); 5352 args.GetIsolate()->ThrowException(args[0]); 5353 } 5354 5355 5356 THREADED_TEST(ThrowValues) { 5357 v8::Isolate* isolate = CcTest::isolate(); 5358 v8::HandleScope scope(isolate); 5359 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5360 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue)); 5361 LocalContext context(0, templ); 5362 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 5363 "function Run(obj) {" 5364 " try {" 5365 " Throw(obj);" 5366 " } catch (e) {" 5367 " return e;" 5368 " }" 5369 " return 'no exception';" 5370 "}" 5371 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 5372 CHECK_EQ(5, result->Length()); 5373 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString()); 5374 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber()); 5375 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value()); 5376 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber()); 5377 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value()); 5378 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull()); 5379 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined()); 5380 } 5381 5382 5383 THREADED_TEST(CatchZero) { 5384 LocalContext context; 5385 v8::HandleScope scope(context->GetIsolate()); 5386 v8::TryCatch try_catch; 5387 CHECK(!try_catch.HasCaught()); 5388 CompileRun("throw 10"); 5389 CHECK(try_catch.HasCaught()); 5390 CHECK_EQ(10, try_catch.Exception()->Int32Value()); 5391 try_catch.Reset(); 5392 CHECK(!try_catch.HasCaught()); 5393 CompileRun("throw 0"); 5394 CHECK(try_catch.HasCaught()); 5395 CHECK_EQ(0, try_catch.Exception()->Int32Value()); 5396 } 5397 5398 5399 THREADED_TEST(CatchExceptionFromWith) { 5400 LocalContext context; 5401 v8::HandleScope scope(context->GetIsolate()); 5402 v8::TryCatch try_catch; 5403 CHECK(!try_catch.HasCaught()); 5404 CompileRun("var o = {}; with (o) { throw 42; }"); 5405 CHECK(try_catch.HasCaught()); 5406 } 5407 5408 5409 THREADED_TEST(TryCatchAndFinallyHidingException) { 5410 LocalContext context; 5411 v8::HandleScope scope(context->GetIsolate()); 5412 v8::TryCatch try_catch; 5413 CHECK(!try_catch.HasCaught()); 5414 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 5415 CompileRun("f({toString: function() { throw 42; }});"); 5416 CHECK(!try_catch.HasCaught()); 5417 } 5418 5419 5420 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 5421 v8::TryCatch try_catch; 5422 } 5423 5424 5425 THREADED_TEST(TryCatchAndFinally) { 5426 LocalContext context; 5427 v8::Isolate* isolate = context->GetIsolate(); 5428 v8::HandleScope scope(isolate); 5429 context->Global()->Set( 5430 v8_str("native_with_try_catch"), 5431 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction()); 5432 v8::TryCatch try_catch; 5433 CHECK(!try_catch.HasCaught()); 5434 CompileRun( 5435 "try {\n" 5436 " throw new Error('a');\n" 5437 "} finally {\n" 5438 " native_with_try_catch();\n" 5439 "}\n"); 5440 CHECK(try_catch.HasCaught()); 5441 } 5442 5443 5444 static void TryCatchNested1Helper(int depth) { 5445 if (depth > 0) { 5446 v8::TryCatch try_catch; 5447 try_catch.SetVerbose(true); 5448 TryCatchNested1Helper(depth - 1); 5449 CHECK(try_catch.HasCaught()); 5450 try_catch.ReThrow(); 5451 } else { 5452 CcTest::isolate()->ThrowException(v8_str("E1")); 5453 } 5454 } 5455 5456 5457 static void TryCatchNested2Helper(int depth) { 5458 if (depth > 0) { 5459 v8::TryCatch try_catch; 5460 try_catch.SetVerbose(true); 5461 TryCatchNested2Helper(depth - 1); 5462 CHECK(try_catch.HasCaught()); 5463 try_catch.ReThrow(); 5464 } else { 5465 CompileRun("throw 'E2';"); 5466 } 5467 } 5468 5469 5470 TEST(TryCatchNested) { 5471 v8::V8::Initialize(); 5472 LocalContext context; 5473 v8::HandleScope scope(context->GetIsolate()); 5474 5475 { 5476 // Test nested try-catch with a native throw in the end. 5477 v8::TryCatch try_catch; 5478 TryCatchNested1Helper(5); 5479 CHECK(try_catch.HasCaught()); 5480 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1")); 5481 } 5482 5483 { 5484 // Test nested try-catch with a JavaScript throw in the end. 5485 v8::TryCatch try_catch; 5486 TryCatchNested2Helper(5); 5487 CHECK(try_catch.HasCaught()); 5488 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2")); 5489 } 5490 } 5491 5492 5493 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 5494 CHECK(try_catch->HasCaught()); 5495 Handle<Message> message = try_catch->Message(); 5496 Handle<Value> resource = message->GetScriptOrigin().ResourceName(); 5497 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 5498 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()), 5499 "Uncaught Error: a")); 5500 CHECK_EQ(1, message->GetLineNumber()); 5501 CHECK_EQ(6, message->GetStartColumn()); 5502 } 5503 5504 5505 void TryCatchMixedNestingHelper( 5506 const v8::FunctionCallbackInfo<v8::Value>& args) { 5507 ApiTestFuzzer::Fuzz(); 5508 v8::TryCatch try_catch; 5509 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 5510 CHECK(try_catch.HasCaught()); 5511 TryCatchMixedNestingCheck(&try_catch); 5512 try_catch.ReThrow(); 5513 } 5514 5515 5516 // This test ensures that an outer TryCatch in the following situation: 5517 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 5518 // does not clobber the Message object generated for the inner TryCatch. 5519 // This exercises the ability of TryCatch.ReThrow() to restore the 5520 // inner pending Message before throwing the exception again. 5521 TEST(TryCatchMixedNesting) { 5522 v8::Isolate* isolate = CcTest::isolate(); 5523 v8::HandleScope scope(isolate); 5524 v8::V8::Initialize(); 5525 v8::TryCatch try_catch; 5526 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5527 templ->Set(v8_str("TryCatchMixedNestingHelper"), 5528 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper)); 5529 LocalContext context(0, templ); 5530 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 5531 TryCatchMixedNestingCheck(&try_catch); 5532 } 5533 5534 5535 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) { 5536 ApiTestFuzzer::Fuzz(); 5537 v8::TryCatch try_catch; 5538 args.GetIsolate()->ThrowException(v8_str("boom")); 5539 CHECK(try_catch.HasCaught()); 5540 } 5541 5542 5543 TEST(TryCatchNative) { 5544 v8::Isolate* isolate = CcTest::isolate(); 5545 v8::HandleScope scope(isolate); 5546 v8::V8::Initialize(); 5547 v8::TryCatch try_catch; 5548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5549 templ->Set(v8_str("TryCatchNativeHelper"), 5550 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper)); 5551 LocalContext context(0, templ); 5552 CompileRun("TryCatchNativeHelper();"); 5553 CHECK(!try_catch.HasCaught()); 5554 } 5555 5556 5557 void TryCatchNativeResetHelper( 5558 const v8::FunctionCallbackInfo<v8::Value>& args) { 5559 ApiTestFuzzer::Fuzz(); 5560 v8::TryCatch try_catch; 5561 args.GetIsolate()->ThrowException(v8_str("boom")); 5562 CHECK(try_catch.HasCaught()); 5563 try_catch.Reset(); 5564 CHECK(!try_catch.HasCaught()); 5565 } 5566 5567 5568 TEST(TryCatchNativeReset) { 5569 v8::Isolate* isolate = CcTest::isolate(); 5570 v8::HandleScope scope(isolate); 5571 v8::V8::Initialize(); 5572 v8::TryCatch try_catch; 5573 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5574 templ->Set(v8_str("TryCatchNativeResetHelper"), 5575 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper)); 5576 LocalContext context(0, templ); 5577 CompileRun("TryCatchNativeResetHelper();"); 5578 CHECK(!try_catch.HasCaught()); 5579 } 5580 5581 5582 THREADED_TEST(Equality) { 5583 LocalContext context; 5584 v8::Isolate* isolate = context->GetIsolate(); 5585 v8::HandleScope scope(context->GetIsolate()); 5586 // Check that equality works at all before relying on CHECK_EQ 5587 CHECK(v8_str("a")->Equals(v8_str("a"))); 5588 CHECK(!v8_str("a")->Equals(v8_str("b"))); 5589 5590 CHECK_EQ(v8_str("a"), v8_str("a")); 5591 CHECK_NE(v8_str("a"), v8_str("b")); 5592 CHECK_EQ(v8_num(1), v8_num(1)); 5593 CHECK_EQ(v8_num(1.00), v8_num(1)); 5594 CHECK_NE(v8_num(1), v8_num(2)); 5595 5596 // Assume String is not internalized. 5597 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 5598 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 5599 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 5600 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 5601 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 5602 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); 5603 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value()); 5604 CHECK(!not_a_number->StrictEquals(not_a_number)); 5605 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); 5606 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); 5607 5608 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 5609 v8::Persistent<v8::Object> alias(isolate, obj); 5610 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 5611 alias.Reset(); 5612 5613 CHECK(v8_str("a")->SameValue(v8_str("a"))); 5614 CHECK(!v8_str("a")->SameValue(v8_str("b"))); 5615 CHECK(!v8_str("5")->SameValue(v8_num(5))); 5616 CHECK(v8_num(1)->SameValue(v8_num(1))); 5617 CHECK(!v8_num(1)->SameValue(v8_num(2))); 5618 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0))); 5619 CHECK(not_a_number->SameValue(not_a_number)); 5620 CHECK(v8::False(isolate)->SameValue(v8::False(isolate))); 5621 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate))); 5622 } 5623 5624 5625 THREADED_TEST(MultiRun) { 5626 LocalContext context; 5627 v8::HandleScope scope(context->GetIsolate()); 5628 Local<Script> script = v8_compile("x"); 5629 for (int i = 0; i < 10; i++) 5630 script->Run(); 5631 } 5632 5633 5634 static void GetXValue(Local<String> name, 5635 const v8::PropertyCallbackInfo<v8::Value>& info) { 5636 ApiTestFuzzer::Fuzz(); 5637 CHECK_EQ(info.Data(), v8_str("donut")); 5638 CHECK_EQ(name, v8_str("x")); 5639 info.GetReturnValue().Set(name); 5640 } 5641 5642 5643 THREADED_TEST(SimplePropertyRead) { 5644 LocalContext context; 5645 v8::Isolate* isolate = context->GetIsolate(); 5646 v8::HandleScope scope(isolate); 5647 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5648 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5649 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5650 Local<Script> script = v8_compile("obj.x"); 5651 for (int i = 0; i < 10; i++) { 5652 Local<Value> result = script->Run(); 5653 CHECK_EQ(result, v8_str("x")); 5654 } 5655 } 5656 5657 5658 THREADED_TEST(DefinePropertyOnAPIAccessor) { 5659 LocalContext context; 5660 v8::Isolate* isolate = context->GetIsolate(); 5661 v8::HandleScope scope(isolate); 5662 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5663 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5664 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5665 5666 // Uses getOwnPropertyDescriptor to check the configurable status 5667 Local<Script> script_desc = v8_compile( 5668 "var prop = Object.getOwnPropertyDescriptor( " 5669 "obj, 'x');" 5670 "prop.configurable;"); 5671 Local<Value> result = script_desc->Run(); 5672 CHECK_EQ(result->BooleanValue(), true); 5673 5674 // Redefine get - but still configurable 5675 Local<Script> script_define = v8_compile( 5676 "var desc = { get: function(){return 42; }," 5677 " configurable: true };" 5678 "Object.defineProperty(obj, 'x', desc);" 5679 "obj.x"); 5680 result = script_define->Run(); 5681 CHECK_EQ(result, v8_num(42)); 5682 5683 // Check that the accessor is still configurable 5684 result = script_desc->Run(); 5685 CHECK_EQ(result->BooleanValue(), true); 5686 5687 // Redefine to a non-configurable 5688 script_define = v8_compile( 5689 "var desc = { get: function(){return 43; }," 5690 " configurable: false };" 5691 "Object.defineProperty(obj, 'x', desc);" 5692 "obj.x"); 5693 result = script_define->Run(); 5694 CHECK_EQ(result, v8_num(43)); 5695 result = script_desc->Run(); 5696 CHECK_EQ(result->BooleanValue(), false); 5697 5698 // Make sure that it is not possible to redefine again 5699 v8::TryCatch try_catch; 5700 result = script_define->Run(); 5701 CHECK(try_catch.HasCaught()); 5702 String::Utf8Value exception_value(try_catch.Exception()); 5703 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5704 } 5705 5706 5707 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 5708 v8::Isolate* isolate = CcTest::isolate(); 5709 v8::HandleScope scope(isolate); 5710 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5711 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5712 LocalContext context; 5713 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5714 5715 Local<Script> script_desc = v8_compile( 5716 "var prop =" 5717 "Object.getOwnPropertyDescriptor( " 5718 "obj, 'x');" 5719 "prop.configurable;"); 5720 Local<Value> result = script_desc->Run(); 5721 CHECK_EQ(result->BooleanValue(), true); 5722 5723 Local<Script> script_define = v8_compile( 5724 "var desc = {get: function(){return 42; }," 5725 " configurable: true };" 5726 "Object.defineProperty(obj, 'x', desc);" 5727 "obj.x"); 5728 result = script_define->Run(); 5729 CHECK_EQ(result, v8_num(42)); 5730 5731 5732 result = script_desc->Run(); 5733 CHECK_EQ(result->BooleanValue(), true); 5734 5735 5736 script_define = v8_compile( 5737 "var desc = {get: function(){return 43; }," 5738 " configurable: false };" 5739 "Object.defineProperty(obj, 'x', desc);" 5740 "obj.x"); 5741 result = script_define->Run(); 5742 CHECK_EQ(result, v8_num(43)); 5743 result = script_desc->Run(); 5744 5745 CHECK_EQ(result->BooleanValue(), false); 5746 5747 v8::TryCatch try_catch; 5748 result = script_define->Run(); 5749 CHECK(try_catch.HasCaught()); 5750 String::Utf8Value exception_value(try_catch.Exception()); 5751 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5752 } 5753 5754 5755 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context, 5756 char const* name) { 5757 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name))); 5758 } 5759 5760 5761 THREADED_TEST(DefineAPIAccessorOnObject) { 5762 v8::Isolate* isolate = CcTest::isolate(); 5763 v8::HandleScope scope(isolate); 5764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5765 LocalContext context; 5766 5767 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5768 CompileRun("var obj2 = {};"); 5769 5770 CHECK(CompileRun("obj1.x")->IsUndefined()); 5771 CHECK(CompileRun("obj2.x")->IsUndefined()); 5772 5773 CHECK(GetGlobalProperty(&context, "obj1")-> 5774 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5775 5776 ExpectString("obj1.x", "x"); 5777 CHECK(CompileRun("obj2.x")->IsUndefined()); 5778 5779 CHECK(GetGlobalProperty(&context, "obj2")-> 5780 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5781 5782 ExpectString("obj1.x", "x"); 5783 ExpectString("obj2.x", "x"); 5784 5785 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5786 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5787 5788 CompileRun("Object.defineProperty(obj1, 'x'," 5789 "{ get: function() { return 'y'; }, configurable: true })"); 5790 5791 ExpectString("obj1.x", "y"); 5792 ExpectString("obj2.x", "x"); 5793 5794 CompileRun("Object.defineProperty(obj2, 'x'," 5795 "{ get: function() { return 'y'; }, configurable: true })"); 5796 5797 ExpectString("obj1.x", "y"); 5798 ExpectString("obj2.x", "y"); 5799 5800 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5801 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5802 5803 CHECK(GetGlobalProperty(&context, "obj1")-> 5804 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5805 CHECK(GetGlobalProperty(&context, "obj2")-> 5806 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5807 5808 ExpectString("obj1.x", "x"); 5809 ExpectString("obj2.x", "x"); 5810 5811 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5812 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5813 5814 // Define getters/setters, but now make them not configurable. 5815 CompileRun("Object.defineProperty(obj1, 'x'," 5816 "{ get: function() { return 'z'; }, configurable: false })"); 5817 CompileRun("Object.defineProperty(obj2, 'x'," 5818 "{ get: function() { return 'z'; }, configurable: false })"); 5819 5820 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5821 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5822 5823 ExpectString("obj1.x", "z"); 5824 ExpectString("obj2.x", "z"); 5825 5826 CHECK(!GetGlobalProperty(&context, "obj1")-> 5827 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5828 CHECK(!GetGlobalProperty(&context, "obj2")-> 5829 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5830 5831 ExpectString("obj1.x", "z"); 5832 ExpectString("obj2.x", "z"); 5833 } 5834 5835 5836 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 5837 v8::Isolate* isolate = CcTest::isolate(); 5838 v8::HandleScope scope(isolate); 5839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5840 LocalContext context; 5841 5842 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5843 CompileRun("var obj2 = {};"); 5844 5845 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5846 v8_str("x"), 5847 GetXValue, NULL, 5848 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5849 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5850 v8_str("x"), 5851 GetXValue, NULL, 5852 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5853 5854 ExpectString("obj1.x", "x"); 5855 ExpectString("obj2.x", "x"); 5856 5857 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5858 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5859 5860 CHECK(!GetGlobalProperty(&context, "obj1")-> 5861 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5862 CHECK(!GetGlobalProperty(&context, "obj2")-> 5863 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5864 5865 { 5866 v8::TryCatch try_catch; 5867 CompileRun("Object.defineProperty(obj1, 'x'," 5868 "{get: function() { return 'func'; }})"); 5869 CHECK(try_catch.HasCaught()); 5870 String::Utf8Value exception_value(try_catch.Exception()); 5871 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5872 } 5873 { 5874 v8::TryCatch try_catch; 5875 CompileRun("Object.defineProperty(obj2, 'x'," 5876 "{get: function() { return 'func'; }})"); 5877 CHECK(try_catch.HasCaught()); 5878 String::Utf8Value exception_value(try_catch.Exception()); 5879 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5880 } 5881 } 5882 5883 5884 static void Get239Value(Local<String> name, 5885 const v8::PropertyCallbackInfo<v8::Value>& info) { 5886 ApiTestFuzzer::Fuzz(); 5887 CHECK_EQ(info.Data(), v8_str("donut")); 5888 CHECK_EQ(name, v8_str("239")); 5889 info.GetReturnValue().Set(name); 5890 } 5891 5892 5893 THREADED_TEST(ElementAPIAccessor) { 5894 v8::Isolate* isolate = CcTest::isolate(); 5895 v8::HandleScope scope(isolate); 5896 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5897 LocalContext context; 5898 5899 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5900 CompileRun("var obj2 = {};"); 5901 5902 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5903 v8_str("239"), 5904 Get239Value, NULL, 5905 v8_str("donut"))); 5906 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5907 v8_str("239"), 5908 Get239Value, NULL, 5909 v8_str("donut"))); 5910 5911 ExpectString("obj1[239]", "239"); 5912 ExpectString("obj2[239]", "239"); 5913 ExpectString("obj1['239']", "239"); 5914 ExpectString("obj2['239']", "239"); 5915 } 5916 5917 5918 v8::Persistent<Value> xValue; 5919 5920 5921 static void SetXValue(Local<String> name, 5922 Local<Value> value, 5923 const v8::PropertyCallbackInfo<void>& info) { 5924 CHECK_EQ(value, v8_num(4)); 5925 CHECK_EQ(info.Data(), v8_str("donut")); 5926 CHECK_EQ(name, v8_str("x")); 5927 CHECK(xValue.IsEmpty()); 5928 xValue.Reset(info.GetIsolate(), value); 5929 } 5930 5931 5932 THREADED_TEST(SimplePropertyWrite) { 5933 v8::Isolate* isolate = CcTest::isolate(); 5934 v8::HandleScope scope(isolate); 5935 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5936 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 5937 LocalContext context; 5938 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5939 Local<Script> script = v8_compile("obj.x = 4"); 5940 for (int i = 0; i < 10; i++) { 5941 CHECK(xValue.IsEmpty()); 5942 script->Run(); 5943 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5944 xValue.Reset(); 5945 } 5946 } 5947 5948 5949 THREADED_TEST(SetterOnly) { 5950 v8::Isolate* isolate = CcTest::isolate(); 5951 v8::HandleScope scope(isolate); 5952 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5953 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 5954 LocalContext context; 5955 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5956 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 5957 for (int i = 0; i < 10; i++) { 5958 CHECK(xValue.IsEmpty()); 5959 script->Run(); 5960 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5961 xValue.Reset(); 5962 } 5963 } 5964 5965 5966 THREADED_TEST(NoAccessors) { 5967 v8::Isolate* isolate = CcTest::isolate(); 5968 v8::HandleScope scope(isolate); 5969 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5970 templ->SetAccessor(v8_str("x"), 5971 static_cast<v8::AccessorGetterCallback>(NULL), 5972 NULL, 5973 v8_str("donut")); 5974 LocalContext context; 5975 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5976 Local<Script> script = v8_compile("obj.x = 4; obj.x"); 5977 for (int i = 0; i < 10; i++) { 5978 script->Run(); 5979 } 5980 } 5981 5982 5983 static void XPropertyGetter(Local<String> property, 5984 const v8::PropertyCallbackInfo<v8::Value>& info) { 5985 ApiTestFuzzer::Fuzz(); 5986 CHECK(info.Data()->IsUndefined()); 5987 info.GetReturnValue().Set(property); 5988 } 5989 5990 5991 THREADED_TEST(NamedInterceptorPropertyRead) { 5992 v8::Isolate* isolate = CcTest::isolate(); 5993 v8::HandleScope scope(isolate); 5994 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 5995 templ->SetNamedPropertyHandler(XPropertyGetter); 5996 LocalContext context; 5997 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5998 Local<Script> script = v8_compile("obj.x"); 5999 for (int i = 0; i < 10; i++) { 6000 Local<Value> result = script->Run(); 6001 CHECK_EQ(result, v8_str("x")); 6002 } 6003 } 6004 6005 6006 THREADED_TEST(NamedInterceptorDictionaryIC) { 6007 v8::Isolate* isolate = CcTest::isolate(); 6008 v8::HandleScope scope(isolate); 6009 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6010 templ->SetNamedPropertyHandler(XPropertyGetter); 6011 LocalContext context; 6012 // Create an object with a named interceptor. 6013 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance()); 6014 Local<Script> script = v8_compile("interceptor_obj.x"); 6015 for (int i = 0; i < 10; i++) { 6016 Local<Value> result = script->Run(); 6017 CHECK_EQ(result, v8_str("x")); 6018 } 6019 // Create a slow case object and a function accessing a property in 6020 // that slow case object (with dictionary probing in generated 6021 // code). Then force object with a named interceptor into slow-case, 6022 // pass it to the function, and check that the interceptor is called 6023 // instead of accessing the local property. 6024 Local<Value> result = 6025 CompileRun("function get_x(o) { return o.x; };" 6026 "var obj = { x : 42, y : 0 };" 6027 "delete obj.y;" 6028 "for (var i = 0; i < 10; i++) get_x(obj);" 6029 "interceptor_obj.x = 42;" 6030 "interceptor_obj.y = 10;" 6031 "delete interceptor_obj.y;" 6032 "get_x(interceptor_obj)"); 6033 CHECK_EQ(result, v8_str("x")); 6034 } 6035 6036 6037 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) { 6038 v8::Isolate* isolate = CcTest::isolate(); 6039 v8::HandleScope scope(isolate); 6040 v8::Local<Context> context1 = Context::New(isolate); 6041 6042 context1->Enter(); 6043 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6044 templ->SetNamedPropertyHandler(XPropertyGetter); 6045 // Create an object with a named interceptor. 6046 v8::Local<v8::Object> object = templ->NewInstance(); 6047 context1->Global()->Set(v8_str("interceptor_obj"), object); 6048 6049 // Force the object into the slow case. 6050 CompileRun("interceptor_obj.y = 0;" 6051 "delete interceptor_obj.y;"); 6052 context1->Exit(); 6053 6054 { 6055 // Introduce the object into a different context. 6056 // Repeat named loads to exercise ICs. 6057 LocalContext context2; 6058 context2->Global()->Set(v8_str("interceptor_obj"), object); 6059 Local<Value> result = 6060 CompileRun("function get_x(o) { return o.x; }" 6061 "interceptor_obj.x = 42;" 6062 "for (var i=0; i != 10; i++) {" 6063 " get_x(interceptor_obj);" 6064 "}" 6065 "get_x(interceptor_obj)"); 6066 // Check that the interceptor was actually invoked. 6067 CHECK_EQ(result, v8_str("x")); 6068 } 6069 6070 // Return to the original context and force some object to the slow case 6071 // to cause the NormalizedMapCache to verify. 6072 context1->Enter(); 6073 CompileRun("var obj = { x : 0 }; delete obj.x;"); 6074 context1->Exit(); 6075 } 6076 6077 6078 static void SetXOnPrototypeGetter( 6079 Local<String> property, 6080 const v8::PropertyCallbackInfo<v8::Value>& info) { 6081 // Set x on the prototype object and do not handle the get request. 6082 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype(); 6083 proto.As<v8::Object>()->Set(v8_str("x"), 6084 v8::Integer::New(info.GetIsolate(), 23)); 6085 } 6086 6087 6088 // This is a regression test for http://crbug.com/20104. Map 6089 // transitions should not interfere with post interceptor lookup. 6090 THREADED_TEST(NamedInterceptorMapTransitionRead) { 6091 v8::Isolate* isolate = CcTest::isolate(); 6092 v8::HandleScope scope(isolate); 6093 Local<v8::FunctionTemplate> function_template = 6094 v8::FunctionTemplate::New(isolate); 6095 Local<v8::ObjectTemplate> instance_template 6096 = function_template->InstanceTemplate(); 6097 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter); 6098 LocalContext context; 6099 context->Global()->Set(v8_str("F"), function_template->GetFunction()); 6100 // Create an instance of F and introduce a map transition for x. 6101 CompileRun("var o = new F(); o.x = 23;"); 6102 // Create an instance of F and invoke the getter. The result should be 23. 6103 Local<Value> result = CompileRun("o = new F(); o.x"); 6104 CHECK_EQ(result->Int32Value(), 23); 6105 } 6106 6107 6108 static void IndexedPropertyGetter( 6109 uint32_t index, 6110 const v8::PropertyCallbackInfo<v8::Value>& info) { 6111 ApiTestFuzzer::Fuzz(); 6112 if (index == 37) { 6113 info.GetReturnValue().Set(v8_num(625)); 6114 } 6115 } 6116 6117 6118 static void IndexedPropertySetter( 6119 uint32_t index, 6120 Local<Value> value, 6121 const v8::PropertyCallbackInfo<v8::Value>& info) { 6122 ApiTestFuzzer::Fuzz(); 6123 if (index == 39) { 6124 info.GetReturnValue().Set(value); 6125 } 6126 } 6127 6128 6129 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { 6130 v8::Isolate* isolate = CcTest::isolate(); 6131 v8::HandleScope scope(isolate); 6132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6133 templ->SetIndexedPropertyHandler(IndexedPropertyGetter, 6134 IndexedPropertySetter); 6135 LocalContext context; 6136 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6137 Local<Script> getter_script = v8_compile( 6138 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"); 6139 Local<Script> setter_script = v8_compile( 6140 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" 6141 "obj[17] = 23;" 6142 "obj.foo;"); 6143 Local<Script> interceptor_setter_script = v8_compile( 6144 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" 6145 "obj[39] = 47;" 6146 "obj.foo;"); // This setter should not run, due to the interceptor. 6147 Local<Script> interceptor_getter_script = v8_compile( 6148 "obj[37];"); 6149 Local<Value> result = getter_script->Run(); 6150 CHECK_EQ(v8_num(5), result); 6151 result = setter_script->Run(); 6152 CHECK_EQ(v8_num(23), result); 6153 result = interceptor_setter_script->Run(); 6154 CHECK_EQ(v8_num(23), result); 6155 result = interceptor_getter_script->Run(); 6156 CHECK_EQ(v8_num(625), result); 6157 } 6158 6159 6160 static void UnboxedDoubleIndexedPropertyGetter( 6161 uint32_t index, 6162 const v8::PropertyCallbackInfo<v8::Value>& info) { 6163 ApiTestFuzzer::Fuzz(); 6164 if (index < 25) { 6165 info.GetReturnValue().Set(v8_num(index)); 6166 } 6167 } 6168 6169 6170 static void UnboxedDoubleIndexedPropertySetter( 6171 uint32_t index, 6172 Local<Value> value, 6173 const v8::PropertyCallbackInfo<v8::Value>& info) { 6174 ApiTestFuzzer::Fuzz(); 6175 if (index < 25) { 6176 info.GetReturnValue().Set(v8_num(index)); 6177 } 6178 } 6179 6180 6181 void UnboxedDoubleIndexedPropertyEnumerator( 6182 const v8::PropertyCallbackInfo<v8::Array>& info) { 6183 // Force the list of returned keys to be stored in a FastDoubleArray. 6184 Local<Script> indexed_property_names_script = v8_compile( 6185 "keys = new Array(); keys[125000] = 1;" 6186 "for(i = 0; i < 80000; i++) { keys[i] = i; };" 6187 "keys.length = 25; keys;"); 6188 Local<Value> result = indexed_property_names_script->Run(); 6189 info.GetReturnValue().Set(Local<v8::Array>::Cast(result)); 6190 } 6191 6192 6193 // Make sure that the the interceptor code in the runtime properly handles 6194 // merging property name lists for double-array-backed arrays. 6195 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { 6196 v8::Isolate* isolate = CcTest::isolate(); 6197 v8::HandleScope scope(isolate); 6198 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6199 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter, 6200 UnboxedDoubleIndexedPropertySetter, 6201 0, 6202 0, 6203 UnboxedDoubleIndexedPropertyEnumerator); 6204 LocalContext context; 6205 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6206 // When obj is created, force it to be Stored in a FastDoubleArray. 6207 Local<Script> create_unboxed_double_script = v8_compile( 6208 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } " 6209 "key_count = 0; " 6210 "for (x in obj) {key_count++;};" 6211 "obj;"); 6212 Local<Value> result = create_unboxed_double_script->Run(); 6213 CHECK(result->ToObject()->HasRealIndexedProperty(2000)); 6214 Local<Script> key_count_check = v8_compile("key_count;"); 6215 result = key_count_check->Run(); 6216 CHECK_EQ(v8_num(40013), result); 6217 } 6218 6219 6220 void SloppyArgsIndexedPropertyEnumerator( 6221 const v8::PropertyCallbackInfo<v8::Array>& info) { 6222 // Force the list of returned keys to be stored in a Arguments object. 6223 Local<Script> indexed_property_names_script = v8_compile( 6224 "function f(w,x) {" 6225 " return arguments;" 6226 "}" 6227 "keys = f(0, 1, 2, 3);" 6228 "keys;"); 6229 Local<Object> result = 6230 Local<Object>::Cast(indexed_property_names_script->Run()); 6231 // Have to populate the handle manually, as it's not Cast-able. 6232 i::Handle<i::JSObject> o = 6233 v8::Utils::OpenHandle<Object, i::JSObject>(result); 6234 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o)); 6235 info.GetReturnValue().Set(v8::Utils::ToLocal(array)); 6236 } 6237 6238 6239 static void SloppyIndexedPropertyGetter( 6240 uint32_t index, 6241 const v8::PropertyCallbackInfo<v8::Value>& info) { 6242 ApiTestFuzzer::Fuzz(); 6243 if (index < 4) { 6244 info.GetReturnValue().Set(v8_num(index)); 6245 } 6246 } 6247 6248 6249 // Make sure that the the interceptor code in the runtime properly handles 6250 // merging property name lists for non-string arguments arrays. 6251 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) { 6252 v8::Isolate* isolate = CcTest::isolate(); 6253 v8::HandleScope scope(isolate); 6254 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6255 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter, 6256 0, 6257 0, 6258 0, 6259 SloppyArgsIndexedPropertyEnumerator); 6260 LocalContext context; 6261 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6262 Local<Script> create_args_script = v8_compile( 6263 "var key_count = 0;" 6264 "for (x in obj) {key_count++;} key_count;"); 6265 Local<Value> result = create_args_script->Run(); 6266 CHECK_EQ(v8_num(4), result); 6267 } 6268 6269 6270 static void IdentityIndexedPropertyGetter( 6271 uint32_t index, 6272 const v8::PropertyCallbackInfo<v8::Value>& info) { 6273 info.GetReturnValue().Set(index); 6274 } 6275 6276 6277 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) { 6278 v8::Isolate* isolate = CcTest::isolate(); 6279 v8::HandleScope scope(isolate); 6280 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6281 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6282 6283 LocalContext context; 6284 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6285 6286 // Check fast object case. 6287 const char* fast_case_code = 6288 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()"; 6289 ExpectString(fast_case_code, "0"); 6290 6291 // Check slow case. 6292 const char* slow_case_code = 6293 "obj.x = 1; delete obj.x;" 6294 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()"; 6295 ExpectString(slow_case_code, "1"); 6296 } 6297 6298 6299 THREADED_TEST(IndexedInterceptorWithNoSetter) { 6300 v8::Isolate* isolate = CcTest::isolate(); 6301 v8::HandleScope scope(isolate); 6302 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6303 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6304 6305 LocalContext context; 6306 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 6307 6308 const char* code = 6309 "try {" 6310 " obj[0] = 239;" 6311 " for (var i = 0; i < 100; i++) {" 6312 " var v = obj[0];" 6313 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;" 6314 " }" 6315 " 'PASSED'" 6316 "} catch(e) {" 6317 " e" 6318 "}"; 6319 ExpectString(code, "PASSED"); 6320 } 6321 6322 6323 THREADED_TEST(IndexedInterceptorWithAccessorCheck) { 6324 v8::Isolate* isolate = CcTest::isolate(); 6325 v8::HandleScope scope(isolate); 6326 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6327 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6328 6329 LocalContext context; 6330 Local<v8::Object> obj = templ->NewInstance(); 6331 obj->TurnOnAccessCheck(); 6332 context->Global()->Set(v8_str("obj"), obj); 6333 6334 const char* code = 6335 "var result = 'PASSED';" 6336 "for (var i = 0; i < 100; i++) {" 6337 " try {" 6338 " var v = obj[0];" 6339 " result = 'Wrong value ' + v + ' at iteration ' + i;" 6340 " break;" 6341 " } catch (e) {" 6342 " /* pass */" 6343 " }" 6344 "}" 6345 "result"; 6346 ExpectString(code, "PASSED"); 6347 } 6348 6349 6350 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { 6351 i::FLAG_allow_natives_syntax = true; 6352 v8::Isolate* isolate = CcTest::isolate(); 6353 v8::HandleScope scope(isolate); 6354 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6355 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6356 6357 LocalContext context; 6358 Local<v8::Object> obj = templ->NewInstance(); 6359 context->Global()->Set(v8_str("obj"), obj); 6360 6361 const char* code = 6362 "var result = 'PASSED';" 6363 "for (var i = 0; i < 100; i++) {" 6364 " var expected = i;" 6365 " if (i == 5) {" 6366 " %EnableAccessChecks(obj);" 6367 " }" 6368 " try {" 6369 " var v = obj[i];" 6370 " if (i == 5) {" 6371 " result = 'Should not have reached this!';" 6372 " break;" 6373 " } else if (v != expected) {" 6374 " result = 'Wrong value ' + v + ' at iteration ' + i;" 6375 " break;" 6376 " }" 6377 " } catch (e) {" 6378 " if (i != 5) {" 6379 " result = e;" 6380 " }" 6381 " }" 6382 " if (i == 5) %DisableAccessChecks(obj);" 6383 "}" 6384 "result"; 6385 ExpectString(code, "PASSED"); 6386 } 6387 6388 6389 THREADED_TEST(IndexedInterceptorWithDifferentIndices) { 6390 v8::Isolate* isolate = CcTest::isolate(); 6391 v8::HandleScope scope(isolate); 6392 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6393 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6394 6395 LocalContext context; 6396 Local<v8::Object> obj = templ->NewInstance(); 6397 context->Global()->Set(v8_str("obj"), obj); 6398 6399 const char* code = 6400 "try {" 6401 " for (var i = 0; i < 100; i++) {" 6402 " var v = obj[i];" 6403 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6404 " }" 6405 " 'PASSED'" 6406 "} catch(e) {" 6407 " e" 6408 "}"; 6409 ExpectString(code, "PASSED"); 6410 } 6411 6412 6413 THREADED_TEST(IndexedInterceptorWithNegativeIndices) { 6414 v8::Isolate* isolate = CcTest::isolate(); 6415 v8::HandleScope scope(isolate); 6416 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6417 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6418 6419 LocalContext context; 6420 Local<v8::Object> obj = templ->NewInstance(); 6421 context->Global()->Set(v8_str("obj"), obj); 6422 6423 const char* code = 6424 "try {" 6425 " for (var i = 0; i < 100; i++) {" 6426 " var expected = i;" 6427 " var key = i;" 6428 " if (i == 25) {" 6429 " key = -1;" 6430 " expected = undefined;" 6431 " }" 6432 " if (i == 50) {" 6433 " /* probe minimal Smi number on 32-bit platforms */" 6434 " key = -(1 << 30);" 6435 " expected = undefined;" 6436 " }" 6437 " if (i == 75) {" 6438 " /* probe minimal Smi number on 64-bit platforms */" 6439 " key = 1 << 31;" 6440 " expected = undefined;" 6441 " }" 6442 " var v = obj[key];" 6443 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6444 " }" 6445 " 'PASSED'" 6446 "} catch(e) {" 6447 " e" 6448 "}"; 6449 ExpectString(code, "PASSED"); 6450 } 6451 6452 6453 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) { 6454 v8::Isolate* isolate = CcTest::isolate(); 6455 v8::HandleScope scope(isolate); 6456 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6457 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6458 6459 LocalContext context; 6460 Local<v8::Object> obj = templ->NewInstance(); 6461 context->Global()->Set(v8_str("obj"), obj); 6462 6463 const char* code = 6464 "try {" 6465 " for (var i = 0; i < 100; i++) {" 6466 " var expected = i;" 6467 " var key = i;" 6468 " if (i == 50) {" 6469 " key = 'foobar';" 6470 " expected = undefined;" 6471 " }" 6472 " var v = obj[key];" 6473 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6474 " }" 6475 " 'PASSED'" 6476 "} catch(e) {" 6477 " e" 6478 "}"; 6479 ExpectString(code, "PASSED"); 6480 } 6481 6482 6483 THREADED_TEST(IndexedInterceptorGoingMegamorphic) { 6484 v8::Isolate* isolate = CcTest::isolate(); 6485 v8::HandleScope scope(isolate); 6486 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6487 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6488 6489 LocalContext context; 6490 Local<v8::Object> obj = templ->NewInstance(); 6491 context->Global()->Set(v8_str("obj"), obj); 6492 6493 const char* code = 6494 "var original = obj;" 6495 "try {" 6496 " for (var i = 0; i < 100; i++) {" 6497 " var expected = i;" 6498 " if (i == 50) {" 6499 " obj = {50: 'foobar'};" 6500 " expected = 'foobar';" 6501 " }" 6502 " var v = obj[i];" 6503 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6504 " if (i == 50) obj = original;" 6505 " }" 6506 " 'PASSED'" 6507 "} catch(e) {" 6508 " e" 6509 "}"; 6510 ExpectString(code, "PASSED"); 6511 } 6512 6513 6514 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) { 6515 v8::Isolate* isolate = CcTest::isolate(); 6516 v8::HandleScope scope(isolate); 6517 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6518 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6519 6520 LocalContext context; 6521 Local<v8::Object> obj = templ->NewInstance(); 6522 context->Global()->Set(v8_str("obj"), obj); 6523 6524 const char* code = 6525 "var original = obj;" 6526 "try {" 6527 " for (var i = 0; i < 100; i++) {" 6528 " var expected = i;" 6529 " if (i == 5) {" 6530 " obj = 239;" 6531 " expected = undefined;" 6532 " }" 6533 " var v = obj[i];" 6534 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6535 " if (i == 5) obj = original;" 6536 " }" 6537 " 'PASSED'" 6538 "} catch(e) {" 6539 " e" 6540 "}"; 6541 ExpectString(code, "PASSED"); 6542 } 6543 6544 6545 THREADED_TEST(IndexedInterceptorOnProto) { 6546 v8::Isolate* isolate = CcTest::isolate(); 6547 v8::HandleScope scope(isolate); 6548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6549 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6550 6551 LocalContext context; 6552 Local<v8::Object> obj = templ->NewInstance(); 6553 context->Global()->Set(v8_str("obj"), obj); 6554 6555 const char* code = 6556 "var o = {__proto__: obj};" 6557 "try {" 6558 " for (var i = 0; i < 100; i++) {" 6559 " var v = o[i];" 6560 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6561 " }" 6562 " 'PASSED'" 6563 "} catch(e) {" 6564 " e" 6565 "}"; 6566 ExpectString(code, "PASSED"); 6567 } 6568 6569 6570 THREADED_TEST(MultiContexts) { 6571 v8::Isolate* isolate = CcTest::isolate(); 6572 v8::HandleScope scope(isolate); 6573 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6574 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate, 6575 DummyCallHandler)); 6576 6577 Local<String> password = v8_str("Password"); 6578 6579 // Create an environment 6580 LocalContext context0(0, templ); 6581 context0->SetSecurityToken(password); 6582 v8::Handle<v8::Object> global0 = context0->Global(); 6583 global0->Set(v8_str("custom"), v8_num(1234)); 6584 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6585 6586 // Create an independent environment 6587 LocalContext context1(0, templ); 6588 context1->SetSecurityToken(password); 6589 v8::Handle<v8::Object> global1 = context1->Global(); 6590 global1->Set(v8_str("custom"), v8_num(1234)); 6591 CHECK_NE(global0, global1); 6592 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6593 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value()); 6594 6595 // Now create a new context with the old global 6596 LocalContext context2(0, templ, global1); 6597 context2->SetSecurityToken(password); 6598 v8::Handle<v8::Object> global2 = context2->Global(); 6599 CHECK_EQ(global1, global2); 6600 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value()); 6601 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value()); 6602 } 6603 6604 6605 THREADED_TEST(FunctionPrototypeAcrossContexts) { 6606 // Make sure that functions created by cloning boilerplates cannot 6607 // communicate through their __proto__ field. 6608 6609 v8::HandleScope scope(CcTest::isolate()); 6610 6611 LocalContext env0; 6612 v8::Handle<v8::Object> global0 = 6613 env0->Global(); 6614 v8::Handle<v8::Object> object0 = 6615 global0->Get(v8_str("Object")).As<v8::Object>(); 6616 v8::Handle<v8::Object> tostring0 = 6617 object0->Get(v8_str("toString")).As<v8::Object>(); 6618 v8::Handle<v8::Object> proto0 = 6619 tostring0->Get(v8_str("__proto__")).As<v8::Object>(); 6620 proto0->Set(v8_str("custom"), v8_num(1234)); 6621 6622 LocalContext env1; 6623 v8::Handle<v8::Object> global1 = 6624 env1->Global(); 6625 v8::Handle<v8::Object> object1 = 6626 global1->Get(v8_str("Object")).As<v8::Object>(); 6627 v8::Handle<v8::Object> tostring1 = 6628 object1->Get(v8_str("toString")).As<v8::Object>(); 6629 v8::Handle<v8::Object> proto1 = 6630 tostring1->Get(v8_str("__proto__")).As<v8::Object>(); 6631 CHECK(!proto1->Has(v8_str("custom"))); 6632 } 6633 6634 6635 THREADED_TEST(Regress892105) { 6636 // Make sure that object and array literals created by cloning 6637 // boilerplates cannot communicate through their __proto__ 6638 // field. This is rather difficult to check, but we try to add stuff 6639 // to Object.prototype and Array.prototype and create a new 6640 // environment. This should succeed. 6641 6642 v8::HandleScope scope(CcTest::isolate()); 6643 6644 Local<String> source = v8_str("Object.prototype.obj = 1234;" 6645 "Array.prototype.arr = 4567;" 6646 "8901"); 6647 6648 LocalContext env0; 6649 Local<Script> script0 = v8_compile(source); 6650 CHECK_EQ(8901.0, script0->Run()->NumberValue()); 6651 6652 LocalContext env1; 6653 Local<Script> script1 = v8_compile(source); 6654 CHECK_EQ(8901.0, script1->Run()->NumberValue()); 6655 } 6656 6657 6658 THREADED_TEST(UndetectableObject) { 6659 LocalContext env; 6660 v8::HandleScope scope(env->GetIsolate()); 6661 6662 Local<v8::FunctionTemplate> desc = 6663 v8::FunctionTemplate::New(env->GetIsolate()); 6664 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6665 6666 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6667 env->Global()->Set(v8_str("undetectable"), obj); 6668 6669 ExpectString("undetectable.toString()", "[object Object]"); 6670 ExpectString("typeof undetectable", "undefined"); 6671 ExpectString("typeof(undetectable)", "undefined"); 6672 ExpectBoolean("typeof undetectable == 'undefined'", true); 6673 ExpectBoolean("typeof undetectable == 'object'", false); 6674 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6675 ExpectBoolean("!undetectable", true); 6676 6677 ExpectObject("true&&undetectable", obj); 6678 ExpectBoolean("false&&undetectable", false); 6679 ExpectBoolean("true||undetectable", true); 6680 ExpectObject("false||undetectable", obj); 6681 6682 ExpectObject("undetectable&&true", obj); 6683 ExpectObject("undetectable&&false", obj); 6684 ExpectBoolean("undetectable||true", true); 6685 ExpectBoolean("undetectable||false", false); 6686 6687 ExpectBoolean("undetectable==null", true); 6688 ExpectBoolean("null==undetectable", true); 6689 ExpectBoolean("undetectable==undefined", true); 6690 ExpectBoolean("undefined==undetectable", true); 6691 ExpectBoolean("undetectable==undetectable", true); 6692 6693 6694 ExpectBoolean("undetectable===null", false); 6695 ExpectBoolean("null===undetectable", false); 6696 ExpectBoolean("undetectable===undefined", false); 6697 ExpectBoolean("undefined===undetectable", false); 6698 ExpectBoolean("undetectable===undetectable", true); 6699 } 6700 6701 6702 THREADED_TEST(VoidLiteral) { 6703 LocalContext env; 6704 v8::Isolate* isolate = env->GetIsolate(); 6705 v8::HandleScope scope(isolate); 6706 6707 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6708 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6709 6710 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6711 env->Global()->Set(v8_str("undetectable"), obj); 6712 6713 ExpectBoolean("undefined == void 0", true); 6714 ExpectBoolean("undetectable == void 0", true); 6715 ExpectBoolean("null == void 0", true); 6716 ExpectBoolean("undefined === void 0", true); 6717 ExpectBoolean("undetectable === void 0", false); 6718 ExpectBoolean("null === void 0", false); 6719 6720 ExpectBoolean("void 0 == undefined", true); 6721 ExpectBoolean("void 0 == undetectable", true); 6722 ExpectBoolean("void 0 == null", true); 6723 ExpectBoolean("void 0 === undefined", true); 6724 ExpectBoolean("void 0 === undetectable", false); 6725 ExpectBoolean("void 0 === null", false); 6726 6727 ExpectString("(function() {" 6728 " try {" 6729 " return x === void 0;" 6730 " } catch(e) {" 6731 " return e.toString();" 6732 " }" 6733 "})()", 6734 "ReferenceError: x is not defined"); 6735 ExpectString("(function() {" 6736 " try {" 6737 " return void 0 === x;" 6738 " } catch(e) {" 6739 " return e.toString();" 6740 " }" 6741 "})()", 6742 "ReferenceError: x is not defined"); 6743 } 6744 6745 6746 THREADED_TEST(ExtensibleOnUndetectable) { 6747 LocalContext env; 6748 v8::Isolate* isolate = env->GetIsolate(); 6749 v8::HandleScope scope(isolate); 6750 6751 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate); 6752 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6753 6754 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6755 env->Global()->Set(v8_str("undetectable"), obj); 6756 6757 Local<String> source = v8_str("undetectable.x = 42;" 6758 "undetectable.x"); 6759 6760 Local<Script> script = v8_compile(source); 6761 6762 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run()); 6763 6764 ExpectBoolean("Object.isExtensible(undetectable)", true); 6765 6766 source = v8_str("Object.preventExtensions(undetectable);"); 6767 script = v8_compile(source); 6768 script->Run(); 6769 ExpectBoolean("Object.isExtensible(undetectable)", false); 6770 6771 source = v8_str("undetectable.y = 2000;"); 6772 script = v8_compile(source); 6773 script->Run(); 6774 ExpectBoolean("undetectable.y == undefined", true); 6775 } 6776 6777 6778 6779 THREADED_TEST(UndetectableString) { 6780 LocalContext env; 6781 v8::HandleScope scope(env->GetIsolate()); 6782 6783 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6784 String::kUndetectableString); 6785 env->Global()->Set(v8_str("undetectable"), obj); 6786 6787 ExpectString("undetectable", "foo"); 6788 ExpectString("typeof undetectable", "undefined"); 6789 ExpectString("typeof(undetectable)", "undefined"); 6790 ExpectBoolean("typeof undetectable == 'undefined'", true); 6791 ExpectBoolean("typeof undetectable == 'string'", false); 6792 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6793 ExpectBoolean("!undetectable", true); 6794 6795 ExpectObject("true&&undetectable", obj); 6796 ExpectBoolean("false&&undetectable", false); 6797 ExpectBoolean("true||undetectable", true); 6798 ExpectObject("false||undetectable", obj); 6799 6800 ExpectObject("undetectable&&true", obj); 6801 ExpectObject("undetectable&&false", obj); 6802 ExpectBoolean("undetectable||true", true); 6803 ExpectBoolean("undetectable||false", false); 6804 6805 ExpectBoolean("undetectable==null", true); 6806 ExpectBoolean("null==undetectable", true); 6807 ExpectBoolean("undetectable==undefined", true); 6808 ExpectBoolean("undefined==undetectable", true); 6809 ExpectBoolean("undetectable==undetectable", true); 6810 6811 6812 ExpectBoolean("undetectable===null", false); 6813 ExpectBoolean("null===undetectable", false); 6814 ExpectBoolean("undetectable===undefined", false); 6815 ExpectBoolean("undefined===undetectable", false); 6816 ExpectBoolean("undetectable===undetectable", true); 6817 } 6818 6819 6820 TEST(UndetectableOptimized) { 6821 i::FLAG_allow_natives_syntax = true; 6822 LocalContext env; 6823 v8::HandleScope scope(env->GetIsolate()); 6824 6825 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6826 String::kUndetectableString); 6827 env->Global()->Set(v8_str("undetectable"), obj); 6828 env->Global()->Set(v8_str("detectable"), v8_str("bar")); 6829 6830 ExpectString( 6831 "function testBranch() {" 6832 " if (!%_IsUndetectableObject(undetectable)) throw 1;" 6833 " if (%_IsUndetectableObject(detectable)) throw 2;" 6834 "}\n" 6835 "function testBool() {" 6836 " var b1 = !%_IsUndetectableObject(undetectable);" 6837 " var b2 = %_IsUndetectableObject(detectable);" 6838 " if (b1) throw 3;" 6839 " if (b2) throw 4;" 6840 " return b1 == b2;" 6841 "}\n" 6842 "%OptimizeFunctionOnNextCall(testBranch);" 6843 "%OptimizeFunctionOnNextCall(testBool);" 6844 "for (var i = 0; i < 10; i++) {" 6845 " testBranch();" 6846 " testBool();" 6847 "}\n" 6848 "\"PASS\"", 6849 "PASS"); 6850 } 6851 6852 6853 // The point of this test is type checking. We run it only so compilers 6854 // don't complain about an unused function. 6855 TEST(PersistentHandles) { 6856 LocalContext env; 6857 v8::Isolate* isolate = CcTest::isolate(); 6858 v8::HandleScope scope(isolate); 6859 Local<String> str = v8_str("foo"); 6860 v8::Persistent<String> p_str(isolate, str); 6861 p_str.Reset(); 6862 Local<Script> scr = v8_compile(""); 6863 v8::Persistent<Script> p_scr(isolate, scr); 6864 p_scr.Reset(); 6865 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 6866 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 6867 p_templ.Reset(); 6868 } 6869 6870 6871 static void HandleLogDelegator( 6872 const v8::FunctionCallbackInfo<v8::Value>& args) { 6873 ApiTestFuzzer::Fuzz(); 6874 } 6875 6876 6877 THREADED_TEST(GlobalObjectTemplate) { 6878 v8::Isolate* isolate = CcTest::isolate(); 6879 v8::HandleScope handle_scope(isolate); 6880 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 6881 global_template->Set(v8_str("JSNI_Log"), 6882 v8::FunctionTemplate::New(isolate, HandleLogDelegator)); 6883 v8::Local<Context> context = Context::New(isolate, 0, global_template); 6884 Context::Scope context_scope(context); 6885 CompileRun("JSNI_Log('LOG')"); 6886 } 6887 6888 6889 static const char* kSimpleExtensionSource = 6890 "function Foo() {" 6891 " return 4;" 6892 "}"; 6893 6894 6895 TEST(SimpleExtensions) { 6896 v8::HandleScope handle_scope(CcTest::isolate()); 6897 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 6898 const char* extension_names[] = { "simpletest" }; 6899 v8::ExtensionConfiguration extensions(1, extension_names); 6900 v8::Handle<Context> context = 6901 Context::New(CcTest::isolate(), &extensions); 6902 Context::Scope lock(context); 6903 v8::Handle<Value> result = CompileRun("Foo()"); 6904 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 6905 } 6906 6907 6908 static const char* kStackTraceFromExtensionSource = 6909 "function foo() {" 6910 " throw new Error();" 6911 "}" 6912 "function bar() {" 6913 " foo();" 6914 "}"; 6915 6916 6917 TEST(StackTraceInExtension) { 6918 v8::HandleScope handle_scope(CcTest::isolate()); 6919 v8::RegisterExtension(new Extension("stacktracetest", 6920 kStackTraceFromExtensionSource)); 6921 const char* extension_names[] = { "stacktracetest" }; 6922 v8::ExtensionConfiguration extensions(1, extension_names); 6923 v8::Handle<Context> context = 6924 Context::New(CcTest::isolate(), &extensions); 6925 Context::Scope lock(context); 6926 CompileRun("function user() { bar(); }" 6927 "var error;" 6928 "try{ user(); } catch (e) { error = e; }"); 6929 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value()); 6930 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value()); 6931 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value()); 6932 } 6933 6934 6935 TEST(NullExtensions) { 6936 v8::HandleScope handle_scope(CcTest::isolate()); 6937 v8::RegisterExtension(new Extension("nulltest", NULL)); 6938 const char* extension_names[] = { "nulltest" }; 6939 v8::ExtensionConfiguration extensions(1, extension_names); 6940 v8::Handle<Context> context = 6941 Context::New(CcTest::isolate(), &extensions); 6942 Context::Scope lock(context); 6943 v8::Handle<Value> result = CompileRun("1+3"); 6944 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 6945 } 6946 6947 6948 static const char* kEmbeddedExtensionSource = 6949 "function Ret54321(){return 54321;}~~@@$" 6950 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 6951 static const int kEmbeddedExtensionSourceValidLen = 34; 6952 6953 6954 TEST(ExtensionMissingSourceLength) { 6955 v8::HandleScope handle_scope(CcTest::isolate()); 6956 v8::RegisterExtension(new Extension("srclentest_fail", 6957 kEmbeddedExtensionSource)); 6958 const char* extension_names[] = { "srclentest_fail" }; 6959 v8::ExtensionConfiguration extensions(1, extension_names); 6960 v8::Handle<Context> context = 6961 Context::New(CcTest::isolate(), &extensions); 6962 CHECK_EQ(0, *context); 6963 } 6964 6965 6966 TEST(ExtensionWithSourceLength) { 6967 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 6968 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 6969 v8::HandleScope handle_scope(CcTest::isolate()); 6970 i::ScopedVector<char> extension_name(32); 6971 i::SNPrintF(extension_name, "ext #%d", source_len); 6972 v8::RegisterExtension(new Extension(extension_name.start(), 6973 kEmbeddedExtensionSource, 0, 0, 6974 source_len)); 6975 const char* extension_names[1] = { extension_name.start() }; 6976 v8::ExtensionConfiguration extensions(1, extension_names); 6977 v8::Handle<Context> context = 6978 Context::New(CcTest::isolate(), &extensions); 6979 if (source_len == kEmbeddedExtensionSourceValidLen) { 6980 Context::Scope lock(context); 6981 v8::Handle<Value> result = CompileRun("Ret54321()"); 6982 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result); 6983 } else { 6984 // Anything but exactly the right length should fail to compile. 6985 CHECK_EQ(0, *context); 6986 } 6987 } 6988 } 6989 6990 6991 static const char* kEvalExtensionSource1 = 6992 "function UseEval1() {" 6993 " var x = 42;" 6994 " return eval('x');" 6995 "}"; 6996 6997 6998 static const char* kEvalExtensionSource2 = 6999 "(function() {" 7000 " var x = 42;" 7001 " function e() {" 7002 " return eval('x');" 7003 " }" 7004 " this.UseEval2 = e;" 7005 "})()"; 7006 7007 7008 TEST(UseEvalFromExtension) { 7009 v8::HandleScope handle_scope(CcTest::isolate()); 7010 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 7011 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 7012 const char* extension_names[] = { "evaltest1", "evaltest2" }; 7013 v8::ExtensionConfiguration extensions(2, extension_names); 7014 v8::Handle<Context> context = 7015 Context::New(CcTest::isolate(), &extensions); 7016 Context::Scope lock(context); 7017 v8::Handle<Value> result = CompileRun("UseEval1()"); 7018 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 7019 result = CompileRun("UseEval2()"); 7020 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 7021 } 7022 7023 7024 static const char* kWithExtensionSource1 = 7025 "function UseWith1() {" 7026 " var x = 42;" 7027 " with({x:87}) { return x; }" 7028 "}"; 7029 7030 7031 7032 static const char* kWithExtensionSource2 = 7033 "(function() {" 7034 " var x = 42;" 7035 " function e() {" 7036 " with ({x:87}) { return x; }" 7037 " }" 7038 " this.UseWith2 = e;" 7039 "})()"; 7040 7041 7042 TEST(UseWithFromExtension) { 7043 v8::HandleScope handle_scope(CcTest::isolate()); 7044 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 7045 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 7046 const char* extension_names[] = { "withtest1", "withtest2" }; 7047 v8::ExtensionConfiguration extensions(2, extension_names); 7048 v8::Handle<Context> context = 7049 Context::New(CcTest::isolate(), &extensions); 7050 Context::Scope lock(context); 7051 v8::Handle<Value> result = CompileRun("UseWith1()"); 7052 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87)); 7053 result = CompileRun("UseWith2()"); 7054 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87)); 7055 } 7056 7057 7058 TEST(AutoExtensions) { 7059 v8::HandleScope handle_scope(CcTest::isolate()); 7060 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 7061 extension->set_auto_enable(true); 7062 v8::RegisterExtension(extension); 7063 v8::Handle<Context> context = 7064 Context::New(CcTest::isolate()); 7065 Context::Scope lock(context); 7066 v8::Handle<Value> result = CompileRun("Foo()"); 7067 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4)); 7068 } 7069 7070 7071 static const char* kSyntaxErrorInExtensionSource = 7072 "["; 7073 7074 7075 // Test that a syntax error in an extension does not cause a fatal 7076 // error but results in an empty context. 7077 TEST(SyntaxErrorExtensions) { 7078 v8::HandleScope handle_scope(CcTest::isolate()); 7079 v8::RegisterExtension(new Extension("syntaxerror", 7080 kSyntaxErrorInExtensionSource)); 7081 const char* extension_names[] = { "syntaxerror" }; 7082 v8::ExtensionConfiguration extensions(1, extension_names); 7083 v8::Handle<Context> context = 7084 Context::New(CcTest::isolate(), &extensions); 7085 CHECK(context.IsEmpty()); 7086 } 7087 7088 7089 static const char* kExceptionInExtensionSource = 7090 "throw 42"; 7091 7092 7093 // Test that an exception when installing an extension does not cause 7094 // a fatal error but results in an empty context. 7095 TEST(ExceptionExtensions) { 7096 v8::HandleScope handle_scope(CcTest::isolate()); 7097 v8::RegisterExtension(new Extension("exception", 7098 kExceptionInExtensionSource)); 7099 const char* extension_names[] = { "exception" }; 7100 v8::ExtensionConfiguration extensions(1, extension_names); 7101 v8::Handle<Context> context = 7102 Context::New(CcTest::isolate(), &extensions); 7103 CHECK(context.IsEmpty()); 7104 } 7105 7106 7107 static const char* kNativeCallInExtensionSource = 7108 "function call_runtime_last_index_of(x) {" 7109 " return %StringLastIndexOf(x, 'bob', 10);" 7110 "}"; 7111 7112 7113 static const char* kNativeCallTest = 7114 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 7115 7116 // Test that a native runtime calls are supported in extensions. 7117 TEST(NativeCallInExtensions) { 7118 v8::HandleScope handle_scope(CcTest::isolate()); 7119 v8::RegisterExtension(new Extension("nativecall", 7120 kNativeCallInExtensionSource)); 7121 const char* extension_names[] = { "nativecall" }; 7122 v8::ExtensionConfiguration extensions(1, extension_names); 7123 v8::Handle<Context> context = 7124 Context::New(CcTest::isolate(), &extensions); 7125 Context::Scope lock(context); 7126 v8::Handle<Value> result = CompileRun(kNativeCallTest); 7127 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3)); 7128 } 7129 7130 7131 class NativeFunctionExtension : public Extension { 7132 public: 7133 NativeFunctionExtension(const char* name, 7134 const char* source, 7135 v8::FunctionCallback fun = &Echo) 7136 : Extension(name, source), 7137 function_(fun) { } 7138 7139 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 7140 v8::Isolate* isolate, 7141 v8::Handle<v8::String> name) { 7142 return v8::FunctionTemplate::New(isolate, function_); 7143 } 7144 7145 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 7146 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 7147 } 7148 private: 7149 v8::FunctionCallback function_; 7150 }; 7151 7152 7153 TEST(NativeFunctionDeclaration) { 7154 v8::HandleScope handle_scope(CcTest::isolate()); 7155 const char* name = "nativedecl"; 7156 v8::RegisterExtension(new NativeFunctionExtension(name, 7157 "native function foo();")); 7158 const char* extension_names[] = { name }; 7159 v8::ExtensionConfiguration extensions(1, extension_names); 7160 v8::Handle<Context> context = 7161 Context::New(CcTest::isolate(), &extensions); 7162 Context::Scope lock(context); 7163 v8::Handle<Value> result = CompileRun("foo(42);"); 7164 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42)); 7165 } 7166 7167 7168 TEST(NativeFunctionDeclarationError) { 7169 v8::HandleScope handle_scope(CcTest::isolate()); 7170 const char* name = "nativedeclerr"; 7171 // Syntax error in extension code. 7172 v8::RegisterExtension(new NativeFunctionExtension(name, 7173 "native\nfunction foo();")); 7174 const char* extension_names[] = { name }; 7175 v8::ExtensionConfiguration extensions(1, extension_names); 7176 v8::Handle<Context> context = 7177 Context::New(CcTest::isolate(), &extensions); 7178 CHECK(context.IsEmpty()); 7179 } 7180 7181 7182 TEST(NativeFunctionDeclarationErrorEscape) { 7183 v8::HandleScope handle_scope(CcTest::isolate()); 7184 const char* name = "nativedeclerresc"; 7185 // Syntax error in extension code - escape code in "native" means that 7186 // it's not treated as a keyword. 7187 v8::RegisterExtension(new NativeFunctionExtension( 7188 name, 7189 "nativ\\u0065 function foo();")); 7190 const char* extension_names[] = { name }; 7191 v8::ExtensionConfiguration extensions(1, extension_names); 7192 v8::Handle<Context> context = 7193 Context::New(CcTest::isolate(), &extensions); 7194 CHECK(context.IsEmpty()); 7195 } 7196 7197 7198 static void CheckDependencies(const char* name, const char* expected) { 7199 v8::HandleScope handle_scope(CcTest::isolate()); 7200 v8::ExtensionConfiguration config(1, &name); 7201 LocalContext context(&config); 7202 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected), 7203 context->Global()->Get(v8_str("loaded"))); 7204 } 7205 7206 7207 /* 7208 * Configuration: 7209 * 7210 * /-- B <--\ 7211 * A <- -- D <-- E 7212 * \-- C <--/ 7213 */ 7214 THREADED_TEST(ExtensionDependency) { 7215 static const char* kEDeps[] = { "D" }; 7216 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 7217 static const char* kDDeps[] = { "B", "C" }; 7218 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 7219 static const char* kBCDeps[] = { "A" }; 7220 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 7221 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 7222 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 7223 CheckDependencies("A", "undefinedA"); 7224 CheckDependencies("B", "undefinedAB"); 7225 CheckDependencies("C", "undefinedAC"); 7226 CheckDependencies("D", "undefinedABCD"); 7227 CheckDependencies("E", "undefinedABCDE"); 7228 v8::HandleScope handle_scope(CcTest::isolate()); 7229 static const char* exts[2] = { "C", "E" }; 7230 v8::ExtensionConfiguration config(2, exts); 7231 LocalContext context(&config); 7232 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded"))); 7233 } 7234 7235 7236 static const char* kExtensionTestScript = 7237 "native function A();" 7238 "native function B();" 7239 "native function C();" 7240 "function Foo(i) {" 7241 " if (i == 0) return A();" 7242 " if (i == 1) return B();" 7243 " if (i == 2) return C();" 7244 "}"; 7245 7246 7247 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 7248 ApiTestFuzzer::Fuzz(); 7249 if (args.IsConstructCall()) { 7250 args.This()->Set(v8_str("data"), args.Data()); 7251 args.GetReturnValue().SetNull(); 7252 return; 7253 } 7254 args.GetReturnValue().Set(args.Data()); 7255 } 7256 7257 7258 class FunctionExtension : public Extension { 7259 public: 7260 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { } 7261 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 7262 v8::Isolate* isolate, 7263 v8::Handle<String> name); 7264 }; 7265 7266 7267 static int lookup_count = 0; 7268 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate( 7269 v8::Isolate* isolate, v8::Handle<String> name) { 7270 lookup_count++; 7271 if (name->Equals(v8_str("A"))) { 7272 return v8::FunctionTemplate::New( 7273 isolate, CallFun, v8::Integer::New(isolate, 8)); 7274 } else if (name->Equals(v8_str("B"))) { 7275 return v8::FunctionTemplate::New( 7276 isolate, CallFun, v8::Integer::New(isolate, 7)); 7277 } else if (name->Equals(v8_str("C"))) { 7278 return v8::FunctionTemplate::New( 7279 isolate, CallFun, v8::Integer::New(isolate, 6)); 7280 } else { 7281 return v8::Handle<v8::FunctionTemplate>(); 7282 } 7283 } 7284 7285 7286 THREADED_TEST(FunctionLookup) { 7287 v8::RegisterExtension(new FunctionExtension()); 7288 v8::HandleScope handle_scope(CcTest::isolate()); 7289 static const char* exts[1] = { "functiontest" }; 7290 v8::ExtensionConfiguration config(1, exts); 7291 LocalContext context(&config); 7292 CHECK_EQ(3, lookup_count); 7293 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8), 7294 CompileRun("Foo(0)")); 7295 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7), 7296 CompileRun("Foo(1)")); 7297 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6), 7298 CompileRun("Foo(2)")); 7299 } 7300 7301 7302 THREADED_TEST(NativeFunctionConstructCall) { 7303 v8::RegisterExtension(new FunctionExtension()); 7304 v8::HandleScope handle_scope(CcTest::isolate()); 7305 static const char* exts[1] = { "functiontest" }; 7306 v8::ExtensionConfiguration config(1, exts); 7307 LocalContext context(&config); 7308 for (int i = 0; i < 10; i++) { 7309 // Run a few times to ensure that allocation of objects doesn't 7310 // change behavior of a constructor function. 7311 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8), 7312 CompileRun("(new A()).data")); 7313 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7), 7314 CompileRun("(new B()).data")); 7315 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6), 7316 CompileRun("(new C()).data")); 7317 } 7318 } 7319 7320 7321 static const char* last_location; 7322 static const char* last_message; 7323 void StoringErrorCallback(const char* location, const char* message) { 7324 if (last_location == NULL) { 7325 last_location = location; 7326 last_message = message; 7327 } 7328 } 7329 7330 7331 // ErrorReporting creates a circular extensions configuration and 7332 // tests that the fatal error handler gets called. This renders V8 7333 // unusable and therefore this test cannot be run in parallel. 7334 TEST(ErrorReporting) { 7335 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 7336 static const char* aDeps[] = { "B" }; 7337 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 7338 static const char* bDeps[] = { "A" }; 7339 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 7340 last_location = NULL; 7341 v8::ExtensionConfiguration config(1, bDeps); 7342 v8::Handle<Context> context = 7343 Context::New(CcTest::isolate(), &config); 7344 CHECK(context.IsEmpty()); 7345 CHECK_NE(last_location, NULL); 7346 } 7347 7348 7349 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, 7350 v8::Handle<Value> data) { 7351 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined()); 7352 CHECK_EQ(v8::Undefined(CcTest::isolate()), 7353 message->GetScriptOrigin().ResourceName()); 7354 message->GetLineNumber(); 7355 message->GetSourceLine(); 7356 } 7357 7358 7359 THREADED_TEST(ErrorWithMissingScriptInfo) { 7360 LocalContext context; 7361 v8::HandleScope scope(context->GetIsolate()); 7362 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); 7363 CompileRun("throw Error()"); 7364 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); 7365 } 7366 7367 7368 struct FlagAndPersistent { 7369 bool flag; 7370 v8::Persistent<v8::Object> handle; 7371 }; 7372 7373 7374 static void DisposeAndSetFlag( 7375 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7376 data.GetParameter()->handle.Reset(); 7377 data.GetParameter()->flag = true; 7378 } 7379 7380 7381 THREADED_TEST(IndependentWeakHandle) { 7382 v8::Isolate* iso = CcTest::isolate(); 7383 v8::HandleScope scope(iso); 7384 v8::Handle<Context> context = Context::New(iso); 7385 Context::Scope context_scope(context); 7386 7387 FlagAndPersistent object_a, object_b; 7388 7389 { 7390 v8::HandleScope handle_scope(iso); 7391 object_a.handle.Reset(iso, v8::Object::New(iso)); 7392 object_b.handle.Reset(iso, v8::Object::New(iso)); 7393 } 7394 7395 object_a.flag = false; 7396 object_b.flag = false; 7397 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag); 7398 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag); 7399 CHECK(!object_b.handle.IsIndependent()); 7400 object_a.handle.MarkIndependent(); 7401 object_b.handle.MarkIndependent(); 7402 CHECK(object_b.handle.IsIndependent()); 7403 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7404 CHECK(object_a.flag); 7405 CHECK(object_b.flag); 7406 } 7407 7408 7409 static void InvokeScavenge() { 7410 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7411 } 7412 7413 7414 static void InvokeMarkSweep() { 7415 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7416 } 7417 7418 7419 static void ForceScavenge( 7420 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7421 data.GetParameter()->handle.Reset(); 7422 data.GetParameter()->flag = true; 7423 InvokeScavenge(); 7424 } 7425 7426 7427 static void ForceMarkSweep( 7428 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7429 data.GetParameter()->handle.Reset(); 7430 data.GetParameter()->flag = true; 7431 InvokeMarkSweep(); 7432 } 7433 7434 7435 THREADED_TEST(GCFromWeakCallbacks) { 7436 v8::Isolate* isolate = CcTest::isolate(); 7437 v8::HandleScope scope(isolate); 7438 v8::Handle<Context> context = Context::New(isolate); 7439 Context::Scope context_scope(context); 7440 7441 static const int kNumberOfGCTypes = 2; 7442 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback 7443 Callback; 7444 Callback gc_forcing_callback[kNumberOfGCTypes] = 7445 {&ForceScavenge, &ForceMarkSweep}; 7446 7447 typedef void (*GCInvoker)(); 7448 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 7449 7450 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 7451 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 7452 FlagAndPersistent object; 7453 { 7454 v8::HandleScope handle_scope(isolate); 7455 object.handle.Reset(isolate, v8::Object::New(isolate)); 7456 } 7457 object.flag = false; 7458 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]); 7459 object.handle.MarkIndependent(); 7460 invoke_gc[outer_gc](); 7461 CHECK(object.flag); 7462 } 7463 } 7464 } 7465 7466 7467 static void RevivingCallback( 7468 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7469 data.GetParameter()->handle.ClearWeak(); 7470 data.GetParameter()->flag = true; 7471 } 7472 7473 7474 THREADED_TEST(IndependentHandleRevival) { 7475 v8::Isolate* isolate = CcTest::isolate(); 7476 v8::HandleScope scope(isolate); 7477 v8::Handle<Context> context = Context::New(isolate); 7478 Context::Scope context_scope(context); 7479 7480 FlagAndPersistent object; 7481 { 7482 v8::HandleScope handle_scope(isolate); 7483 v8::Local<v8::Object> o = v8::Object::New(isolate); 7484 object.handle.Reset(isolate, o); 7485 o->Set(v8_str("x"), v8::Integer::New(isolate, 1)); 7486 v8::Local<String> y_str = v8_str("y"); 7487 o->Set(y_str, y_str); 7488 } 7489 object.flag = false; 7490 object.handle.SetWeak(&object, &RevivingCallback); 7491 object.handle.MarkIndependent(); 7492 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 7493 CHECK(object.flag); 7494 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 7495 { 7496 v8::HandleScope handle_scope(isolate); 7497 v8::Local<v8::Object> o = 7498 v8::Local<v8::Object>::New(isolate, object.handle); 7499 v8::Local<String> y_str = v8_str("y"); 7500 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x"))); 7501 CHECK(o->Get(y_str)->Equals(y_str)); 7502 } 7503 } 7504 7505 7506 v8::Handle<Function> args_fun; 7507 7508 7509 static void ArgumentsTestCallback( 7510 const v8::FunctionCallbackInfo<v8::Value>& args) { 7511 ApiTestFuzzer::Fuzz(); 7512 v8::Isolate* isolate = args.GetIsolate(); 7513 CHECK_EQ(args_fun, args.Callee()); 7514 CHECK_EQ(3, args.Length()); 7515 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]); 7516 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]); 7517 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]); 7518 CHECK_EQ(v8::Undefined(isolate), args[3]); 7519 v8::HandleScope scope(args.GetIsolate()); 7520 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7521 } 7522 7523 7524 THREADED_TEST(Arguments) { 7525 v8::Isolate* isolate = CcTest::isolate(); 7526 v8::HandleScope scope(isolate); 7527 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate); 7528 global->Set(v8_str("f"), 7529 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback)); 7530 LocalContext context(NULL, global); 7531 args_fun = context->Global()->Get(v8_str("f")).As<Function>(); 7532 v8_compile("f(1, 2, 3)")->Run(); 7533 } 7534 7535 7536 static void NoBlockGetterX(Local<String> name, 7537 const v8::PropertyCallbackInfo<v8::Value>&) { 7538 } 7539 7540 7541 static void NoBlockGetterI(uint32_t index, 7542 const v8::PropertyCallbackInfo<v8::Value>&) { 7543 } 7544 7545 7546 static void PDeleter(Local<String> name, 7547 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7548 if (!name->Equals(v8_str("foo"))) { 7549 return; // not intercepted 7550 } 7551 7552 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7553 } 7554 7555 7556 static void IDeleter(uint32_t index, 7557 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7558 if (index != 2) { 7559 return; // not intercepted 7560 } 7561 7562 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7563 } 7564 7565 7566 THREADED_TEST(Deleter) { 7567 v8::Isolate* isolate = CcTest::isolate(); 7568 v8::HandleScope scope(isolate); 7569 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7570 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL); 7571 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL); 7572 LocalContext context; 7573 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7574 CompileRun( 7575 "k.foo = 'foo';" 7576 "k.bar = 'bar';" 7577 "k[2] = 2;" 7578 "k[4] = 4;"); 7579 CHECK(v8_compile("delete k.foo")->Run()->IsFalse()); 7580 CHECK(v8_compile("delete k.bar")->Run()->IsTrue()); 7581 7582 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo")); 7583 CHECK(v8_compile("k.bar")->Run()->IsUndefined()); 7584 7585 CHECK(v8_compile("delete k[2]")->Run()->IsFalse()); 7586 CHECK(v8_compile("delete k[4]")->Run()->IsTrue()); 7587 7588 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2)); 7589 CHECK(v8_compile("k[4]")->Run()->IsUndefined()); 7590 } 7591 7592 7593 static void GetK(Local<String> name, 7594 const v8::PropertyCallbackInfo<v8::Value>& info) { 7595 ApiTestFuzzer::Fuzz(); 7596 if (name->Equals(v8_str("foo")) || 7597 name->Equals(v8_str("bar")) || 7598 name->Equals(v8_str("baz"))) { 7599 info.GetReturnValue().SetUndefined(); 7600 } 7601 } 7602 7603 7604 static void IndexedGetK(uint32_t index, 7605 const v8::PropertyCallbackInfo<v8::Value>& info) { 7606 ApiTestFuzzer::Fuzz(); 7607 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined(); 7608 } 7609 7610 7611 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7612 ApiTestFuzzer::Fuzz(); 7613 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3); 7614 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo")); 7615 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar")); 7616 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz")); 7617 info.GetReturnValue().Set(result); 7618 } 7619 7620 7621 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7622 ApiTestFuzzer::Fuzz(); 7623 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 7624 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0")); 7625 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1")); 7626 info.GetReturnValue().Set(result); 7627 } 7628 7629 7630 THREADED_TEST(Enumerators) { 7631 v8::Isolate* isolate = CcTest::isolate(); 7632 v8::HandleScope scope(isolate); 7633 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7634 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); 7635 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); 7636 LocalContext context; 7637 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7638 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 7639 "k[10] = 0;" 7640 "k.a = 0;" 7641 "k[5] = 0;" 7642 "k.b = 0;" 7643 "k[4294967295] = 0;" 7644 "k.c = 0;" 7645 "k[4294967296] = 0;" 7646 "k.d = 0;" 7647 "k[140000] = 0;" 7648 "k.e = 0;" 7649 "k[30000000000] = 0;" 7650 "k.f = 0;" 7651 "var result = [];" 7652 "for (var prop in k) {" 7653 " result.push(prop);" 7654 "}" 7655 "result")); 7656 // Check that we get all the property names returned including the 7657 // ones from the enumerators in the right order: indexed properties 7658 // in numerical order, indexed interceptor properties, named 7659 // properties in insertion order, named interceptor properties. 7660 // This order is not mandated by the spec, so this test is just 7661 // documenting our behavior. 7662 CHECK_EQ(17, result->Length()); 7663 // Indexed properties in numerical order. 7664 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0))); 7665 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1))); 7666 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2))); 7667 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3))); 7668 // Indexed interceptor properties in the order they are returned 7669 // from the enumerator interceptor. 7670 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4))); 7671 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5))); 7672 // Named properties in insertion order. 7673 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6))); 7674 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7))); 7675 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8))); 7676 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9))); 7677 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10))); 7678 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11))); 7679 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12))); 7680 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13))); 7681 // Named interceptor properties. 7682 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14))); 7683 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15))); 7684 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16))); 7685 } 7686 7687 7688 int p_getter_count; 7689 int p_getter_count2; 7690 7691 7692 static void PGetter(Local<String> name, 7693 const v8::PropertyCallbackInfo<v8::Value>& info) { 7694 ApiTestFuzzer::Fuzz(); 7695 p_getter_count++; 7696 v8::Handle<v8::Object> global = 7697 info.GetIsolate()->GetCurrentContext()->Global(); 7698 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7699 if (name->Equals(v8_str("p1"))) { 7700 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7701 } else if (name->Equals(v8_str("p2"))) { 7702 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7703 } else if (name->Equals(v8_str("p3"))) { 7704 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7705 } else if (name->Equals(v8_str("p4"))) { 7706 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7707 } 7708 } 7709 7710 7711 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) { 7712 ApiTestFuzzer::Fuzz(); 7713 LocalContext context; 7714 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 7715 CompileRun( 7716 "o1.__proto__ = { };" 7717 "var o2 = { __proto__: o1 };" 7718 "var o3 = { __proto__: o2 };" 7719 "var o4 = { __proto__: o3 };" 7720 "for (var i = 0; i < 10; i++) o4.p4;" 7721 "for (var i = 0; i < 10; i++) o3.p3;" 7722 "for (var i = 0; i < 10; i++) o2.p2;" 7723 "for (var i = 0; i < 10; i++) o1.p1;"); 7724 } 7725 7726 7727 static void PGetter2(Local<String> name, 7728 const v8::PropertyCallbackInfo<v8::Value>& info) { 7729 ApiTestFuzzer::Fuzz(); 7730 p_getter_count2++; 7731 v8::Handle<v8::Object> global = 7732 info.GetIsolate()->GetCurrentContext()->Global(); 7733 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7734 if (name->Equals(v8_str("p1"))) { 7735 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7736 } else if (name->Equals(v8_str("p2"))) { 7737 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7738 } else if (name->Equals(v8_str("p3"))) { 7739 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7740 } else if (name->Equals(v8_str("p4"))) { 7741 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7742 } 7743 } 7744 7745 7746 THREADED_TEST(GetterHolders) { 7747 v8::Isolate* isolate = CcTest::isolate(); 7748 v8::HandleScope scope(isolate); 7749 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7750 obj->SetAccessor(v8_str("p1"), PGetter); 7751 obj->SetAccessor(v8_str("p2"), PGetter); 7752 obj->SetAccessor(v8_str("p3"), PGetter); 7753 obj->SetAccessor(v8_str("p4"), PGetter); 7754 p_getter_count = 0; 7755 RunHolderTest(obj); 7756 CHECK_EQ(40, p_getter_count); 7757 } 7758 7759 7760 THREADED_TEST(PreInterceptorHolders) { 7761 v8::Isolate* isolate = CcTest::isolate(); 7762 v8::HandleScope scope(isolate); 7763 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 7764 obj->SetNamedPropertyHandler(PGetter2); 7765 p_getter_count2 = 0; 7766 RunHolderTest(obj); 7767 CHECK_EQ(40, p_getter_count2); 7768 } 7769 7770 7771 THREADED_TEST(ObjectInstantiation) { 7772 v8::Isolate* isolate = CcTest::isolate(); 7773 v8::HandleScope scope(isolate); 7774 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 7775 templ->SetAccessor(v8_str("t"), PGetter2); 7776 LocalContext context; 7777 context->Global()->Set(v8_str("o"), templ->NewInstance()); 7778 for (int i = 0; i < 100; i++) { 7779 v8::HandleScope inner_scope(CcTest::isolate()); 7780 v8::Handle<v8::Object> obj = templ->NewInstance(); 7781 CHECK_NE(obj, context->Global()->Get(v8_str("o"))); 7782 context->Global()->Set(v8_str("o2"), obj); 7783 v8::Handle<Value> value = 7784 CompileRun("o.__proto__ === o2.__proto__"); 7785 CHECK_EQ(v8::True(isolate), value); 7786 context->Global()->Set(v8_str("o"), obj); 7787 } 7788 } 7789 7790 7791 static int StrCmp16(uint16_t* a, uint16_t* b) { 7792 while (true) { 7793 if (*a == 0 && *b == 0) return 0; 7794 if (*a != *b) return 0 + *a - *b; 7795 a++; 7796 b++; 7797 } 7798 } 7799 7800 7801 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 7802 while (true) { 7803 if (n-- == 0) return 0; 7804 if (*a == 0 && *b == 0) return 0; 7805 if (*a != *b) return 0 + *a - *b; 7806 a++; 7807 b++; 7808 } 7809 } 7810 7811 7812 int GetUtf8Length(Handle<String> str) { 7813 int len = str->Utf8Length(); 7814 if (len < 0) { 7815 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 7816 i::String::Flatten(istr); 7817 len = str->Utf8Length(); 7818 } 7819 return len; 7820 } 7821 7822 7823 THREADED_TEST(StringWrite) { 7824 LocalContext context; 7825 v8::HandleScope scope(context->GetIsolate()); 7826 v8::Handle<String> str = v8_str("abcde"); 7827 // abc<Icelandic eth><Unicode snowman>. 7828 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203"); 7829 v8::Handle<String> str3 = v8::String::NewFromUtf8( 7830 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7); 7831 // "ab" + lead surrogate + "cd" + trail surrogate + "ef" 7832 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 }; 7833 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte( 7834 context->GetIsolate(), orphans, v8::String::kNormalString, 8); 7835 // single lead surrogate 7836 uint16_t lead[1] = { 0xd800 }; 7837 v8::Handle<String> lead_str = v8::String::NewFromTwoByte( 7838 context->GetIsolate(), lead, v8::String::kNormalString, 1); 7839 // single trail surrogate 7840 uint16_t trail[1] = { 0xdc00 }; 7841 v8::Handle<String> trail_str = v8::String::NewFromTwoByte( 7842 context->GetIsolate(), trail, v8::String::kNormalString, 1); 7843 // surrogate pair 7844 uint16_t pair[2] = { 0xd800, 0xdc00 }; 7845 v8::Handle<String> pair_str = v8::String::NewFromTwoByte( 7846 context->GetIsolate(), pair, v8::String::kNormalString, 2); 7847 const int kStride = 4; // Must match stride in for loops in JS below. 7848 CompileRun( 7849 "var left = '';" 7850 "for (var i = 0; i < 0xd800; i += 4) {" 7851 " left = left + String.fromCharCode(i);" 7852 "}"); 7853 CompileRun( 7854 "var right = '';" 7855 "for (var i = 0; i < 0xd800; i += 4) {" 7856 " right = String.fromCharCode(i) + right;" 7857 "}"); 7858 v8::Handle<v8::Object> global = context->Global(); 7859 Handle<String> left_tree = global->Get(v8_str("left")).As<String>(); 7860 Handle<String> right_tree = global->Get(v8_str("right")).As<String>(); 7861 7862 CHECK_EQ(5, str2->Length()); 7863 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 7864 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 7865 7866 char buf[100]; 7867 char utf8buf[0xd800 * 3]; 7868 uint16_t wbuf[100]; 7869 int len; 7870 int charlen; 7871 7872 memset(utf8buf, 0x1, 1000); 7873 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7874 CHECK_EQ(9, len); 7875 CHECK_EQ(5, charlen); 7876 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7877 7878 memset(utf8buf, 0x1, 1000); 7879 len = str2->WriteUtf8(utf8buf, 8, &charlen); 7880 CHECK_EQ(8, len); 7881 CHECK_EQ(5, charlen); 7882 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 7883 7884 memset(utf8buf, 0x1, 1000); 7885 len = str2->WriteUtf8(utf8buf, 7, &charlen); 7886 CHECK_EQ(5, len); 7887 CHECK_EQ(4, charlen); 7888 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7889 7890 memset(utf8buf, 0x1, 1000); 7891 len = str2->WriteUtf8(utf8buf, 6, &charlen); 7892 CHECK_EQ(5, len); 7893 CHECK_EQ(4, charlen); 7894 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7895 7896 memset(utf8buf, 0x1, 1000); 7897 len = str2->WriteUtf8(utf8buf, 5, &charlen); 7898 CHECK_EQ(5, len); 7899 CHECK_EQ(4, charlen); 7900 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7901 7902 memset(utf8buf, 0x1, 1000); 7903 len = str2->WriteUtf8(utf8buf, 4, &charlen); 7904 CHECK_EQ(3, len); 7905 CHECK_EQ(3, charlen); 7906 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7907 7908 memset(utf8buf, 0x1, 1000); 7909 len = str2->WriteUtf8(utf8buf, 3, &charlen); 7910 CHECK_EQ(3, len); 7911 CHECK_EQ(3, charlen); 7912 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7913 7914 memset(utf8buf, 0x1, 1000); 7915 len = str2->WriteUtf8(utf8buf, 2, &charlen); 7916 CHECK_EQ(2, len); 7917 CHECK_EQ(2, charlen); 7918 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 7919 7920 // allow orphan surrogates by default 7921 memset(utf8buf, 0x1, 1000); 7922 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7923 CHECK_EQ(13, len); 7924 CHECK_EQ(8, charlen); 7925 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef")); 7926 7927 // replace orphan surrogates with unicode replacement character 7928 memset(utf8buf, 0x1, 1000); 7929 len = orphans_str->WriteUtf8(utf8buf, 7930 sizeof(utf8buf), 7931 &charlen, 7932 String::REPLACE_INVALID_UTF8); 7933 CHECK_EQ(13, len); 7934 CHECK_EQ(8, charlen); 7935 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef")); 7936 7937 // replace single lead surrogate with unicode replacement character 7938 memset(utf8buf, 0x1, 1000); 7939 len = lead_str->WriteUtf8(utf8buf, 7940 sizeof(utf8buf), 7941 &charlen, 7942 String::REPLACE_INVALID_UTF8); 7943 CHECK_EQ(4, len); 7944 CHECK_EQ(1, charlen); 7945 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 7946 7947 // replace single trail surrogate with unicode replacement character 7948 memset(utf8buf, 0x1, 1000); 7949 len = trail_str->WriteUtf8(utf8buf, 7950 sizeof(utf8buf), 7951 &charlen, 7952 String::REPLACE_INVALID_UTF8); 7953 CHECK_EQ(4, len); 7954 CHECK_EQ(1, charlen); 7955 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275")); 7956 7957 // do not replace / write anything if surrogate pair does not fit the buffer 7958 // space 7959 memset(utf8buf, 0x1, 1000); 7960 len = pair_str->WriteUtf8(utf8buf, 7961 3, 7962 &charlen, 7963 String::REPLACE_INVALID_UTF8); 7964 CHECK_EQ(0, len); 7965 CHECK_EQ(0, charlen); 7966 7967 memset(utf8buf, 0x1, sizeof(utf8buf)); 7968 len = GetUtf8Length(left_tree); 7969 int utf8_expected = 7970 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 7971 CHECK_EQ(utf8_expected, len); 7972 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7973 CHECK_EQ(utf8_expected, len); 7974 CHECK_EQ(0xd800 / kStride, charlen); 7975 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 7976 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 7977 CHECK_EQ(0xc0 - kStride, 7978 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 7979 CHECK_EQ(1, utf8buf[utf8_expected]); 7980 7981 memset(utf8buf, 0x1, sizeof(utf8buf)); 7982 len = GetUtf8Length(right_tree); 7983 CHECK_EQ(utf8_expected, len); 7984 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7985 CHECK_EQ(utf8_expected, len); 7986 CHECK_EQ(0xd800 / kStride, charlen); 7987 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 7988 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 7989 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 7990 CHECK_EQ(1, utf8buf[utf8_expected]); 7991 7992 memset(buf, 0x1, sizeof(buf)); 7993 memset(wbuf, 0x1, sizeof(wbuf)); 7994 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7995 CHECK_EQ(5, len); 7996 len = str->Write(wbuf); 7997 CHECK_EQ(5, len); 7998 CHECK_EQ(0, strcmp("abcde", buf)); 7999 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8000 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 8001 8002 memset(buf, 0x1, sizeof(buf)); 8003 memset(wbuf, 0x1, sizeof(wbuf)); 8004 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 8005 CHECK_EQ(4, len); 8006 len = str->Write(wbuf, 0, 4); 8007 CHECK_EQ(4, len); 8008 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 8009 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 8010 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 8011 8012 memset(buf, 0x1, sizeof(buf)); 8013 memset(wbuf, 0x1, sizeof(wbuf)); 8014 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 8015 CHECK_EQ(5, len); 8016 len = str->Write(wbuf, 0, 5); 8017 CHECK_EQ(5, len); 8018 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 8019 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 8020 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 8021 8022 memset(buf, 0x1, sizeof(buf)); 8023 memset(wbuf, 0x1, sizeof(wbuf)); 8024 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 8025 CHECK_EQ(5, len); 8026 len = str->Write(wbuf, 0, 6); 8027 CHECK_EQ(5, len); 8028 CHECK_EQ(0, strcmp("abcde", buf)); 8029 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8030 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 8031 8032 memset(buf, 0x1, sizeof(buf)); 8033 memset(wbuf, 0x1, sizeof(wbuf)); 8034 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 8035 CHECK_EQ(1, len); 8036 len = str->Write(wbuf, 4, -1); 8037 CHECK_EQ(1, len); 8038 CHECK_EQ(0, strcmp("e", buf)); 8039 uint16_t answer5[] = {'e', '\0'}; 8040 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8041 8042 memset(buf, 0x1, sizeof(buf)); 8043 memset(wbuf, 0x1, sizeof(wbuf)); 8044 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 8045 CHECK_EQ(1, len); 8046 len = str->Write(wbuf, 4, 6); 8047 CHECK_EQ(1, len); 8048 CHECK_EQ(0, strcmp("e", buf)); 8049 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 8050 8051 memset(buf, 0x1, sizeof(buf)); 8052 memset(wbuf, 0x1, sizeof(wbuf)); 8053 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 8054 CHECK_EQ(1, len); 8055 len = str->Write(wbuf, 4, 1); 8056 CHECK_EQ(1, len); 8057 CHECK_EQ(0, strncmp("e\1", buf, 2)); 8058 uint16_t answer6[] = {'e', 0x101}; 8059 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 8060 8061 memset(buf, 0x1, sizeof(buf)); 8062 memset(wbuf, 0x1, sizeof(wbuf)); 8063 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 8064 CHECK_EQ(1, len); 8065 len = str->Write(wbuf, 3, 1); 8066 CHECK_EQ(1, len); 8067 CHECK_EQ(0, strncmp("d\1", buf, 2)); 8068 uint16_t answer7[] = {'d', 0x101}; 8069 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 8070 8071 memset(wbuf, 0x1, sizeof(wbuf)); 8072 wbuf[5] = 'X'; 8073 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 8074 CHECK_EQ(5, len); 8075 CHECK_EQ('X', wbuf[5]); 8076 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 8077 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 8078 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 8079 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 8080 wbuf[5] = '\0'; 8081 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 8082 8083 memset(buf, 0x1, sizeof(buf)); 8084 buf[5] = 'X'; 8085 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 8086 0, 8087 6, 8088 String::NO_NULL_TERMINATION); 8089 CHECK_EQ(5, len); 8090 CHECK_EQ('X', buf[5]); 8091 CHECK_EQ(0, strncmp("abcde", buf, 5)); 8092 CHECK_NE(0, strcmp("abcde", buf)); 8093 buf[5] = '\0'; 8094 CHECK_EQ(0, strcmp("abcde", buf)); 8095 8096 memset(utf8buf, 0x1, sizeof(utf8buf)); 8097 utf8buf[8] = 'X'; 8098 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8099 String::NO_NULL_TERMINATION); 8100 CHECK_EQ(8, len); 8101 CHECK_EQ('X', utf8buf[8]); 8102 CHECK_EQ(5, charlen); 8103 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 8104 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8105 utf8buf[8] = '\0'; 8106 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 8107 8108 memset(utf8buf, 0x1, sizeof(utf8buf)); 8109 utf8buf[5] = 'X'; 8110 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 8111 String::NO_NULL_TERMINATION); 8112 CHECK_EQ(5, len); 8113 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 8114 CHECK_EQ(5, charlen); 8115 utf8buf[5] = '\0'; 8116 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 8117 8118 memset(buf, 0x1, sizeof(buf)); 8119 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8120 CHECK_EQ(7, len); 8121 CHECK_EQ(0, strcmp("abc", buf)); 8122 CHECK_EQ(0, buf[3]); 8123 CHECK_EQ(0, strcmp("def", buf + 4)); 8124 8125 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8126 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8127 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 8128 } 8129 8130 8131 static void Utf16Helper( 8132 LocalContext& context, // NOLINT 8133 const char* name, 8134 const char* lengths_name, 8135 int len) { 8136 Local<v8::Array> a = 8137 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 8138 Local<v8::Array> alens = 8139 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 8140 for (int i = 0; i < len; i++) { 8141 Local<v8::String> string = 8142 Local<v8::String>::Cast(a->Get(i)); 8143 Local<v8::Number> expected_len = 8144 Local<v8::Number>::Cast(alens->Get(i)); 8145 int length = GetUtf8Length(string); 8146 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 8147 } 8148 } 8149 8150 8151 static uint16_t StringGet(Handle<String> str, int index) { 8152 i::Handle<i::String> istring = 8153 v8::Utils::OpenHandle(String::Cast(*str)); 8154 return istring->Get(index); 8155 } 8156 8157 8158 static void WriteUtf8Helper( 8159 LocalContext& context, // NOLINT 8160 const char* name, 8161 const char* lengths_name, 8162 int len) { 8163 Local<v8::Array> b = 8164 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 8165 Local<v8::Array> alens = 8166 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 8167 char buffer[1000]; 8168 char buffer2[1000]; 8169 for (int i = 0; i < len; i++) { 8170 Local<v8::String> string = 8171 Local<v8::String>::Cast(b->Get(i)); 8172 Local<v8::Number> expected_len = 8173 Local<v8::Number>::Cast(alens->Get(i)); 8174 int utf8_length = static_cast<int>(expected_len->Value()); 8175 for (int j = utf8_length + 1; j >= 0; j--) { 8176 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer)); 8177 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2)); 8178 int nchars; 8179 int utf8_written = 8180 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS); 8181 int utf8_written2 = 8182 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION); 8183 CHECK_GE(utf8_length + 1, utf8_written); 8184 CHECK_GE(utf8_length, utf8_written2); 8185 for (int k = 0; k < utf8_written2; k++) { 8186 CHECK_EQ(buffer[k], buffer2[k]); 8187 } 8188 CHECK(nchars * 3 >= utf8_written - 1); 8189 CHECK(nchars <= utf8_written); 8190 if (j == utf8_length + 1) { 8191 CHECK_EQ(utf8_written2, utf8_length); 8192 CHECK_EQ(utf8_written2 + 1, utf8_written); 8193 } 8194 CHECK_EQ(buffer[utf8_written], 42); 8195 if (j > utf8_length) { 8196 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0); 8197 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42); 8198 Handle<String> roundtrip = v8_str(buffer); 8199 CHECK(roundtrip->Equals(string)); 8200 } else { 8201 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42); 8202 } 8203 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42); 8204 if (nchars >= 2) { 8205 uint16_t trail = StringGet(string, nchars - 1); 8206 uint16_t lead = StringGet(string, nchars - 2); 8207 if (((lead & 0xfc00) == 0xd800) && 8208 ((trail & 0xfc00) == 0xdc00)) { 8209 unsigned char u1 = buffer2[utf8_written2 - 4]; 8210 unsigned char u2 = buffer2[utf8_written2 - 3]; 8211 unsigned char u3 = buffer2[utf8_written2 - 2]; 8212 unsigned char u4 = buffer2[utf8_written2 - 1]; 8213 CHECK_EQ((u1 & 0xf8), 0xf0); 8214 CHECK_EQ((u2 & 0xc0), 0x80); 8215 CHECK_EQ((u3 & 0xc0), 0x80); 8216 CHECK_EQ((u4 & 0xc0), 0x80); 8217 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff); 8218 CHECK_EQ((u4 & 0x3f), (c & 0x3f)); 8219 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f)); 8220 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f)); 8221 CHECK_EQ((u1 & 0x3), c >> 18); 8222 } 8223 } 8224 } 8225 } 8226 } 8227 8228 8229 THREADED_TEST(Utf16) { 8230 LocalContext context; 8231 v8::HandleScope scope(context->GetIsolate()); 8232 CompileRun( 8233 "var pad = '01234567890123456789';" 8234 "var p = [];" 8235 "var plens = [20, 3, 3];" 8236 "p.push('01234567890123456789');" 8237 "var lead = 0xd800;" 8238 "var trail = 0xdc00;" 8239 "p.push(String.fromCharCode(0xd800));" 8240 "p.push(String.fromCharCode(0xdc00));" 8241 "var a = [];" 8242 "var b = [];" 8243 "var c = [];" 8244 "var alens = [];" 8245 "for (var i = 0; i < 3; i++) {" 8246 " p[1] = String.fromCharCode(lead++);" 8247 " for (var j = 0; j < 3; j++) {" 8248 " p[2] = String.fromCharCode(trail++);" 8249 " a.push(p[i] + p[j]);" 8250 " b.push(p[i] + p[j]);" 8251 " c.push(p[i] + p[j]);" 8252 " alens.push(plens[i] + plens[j]);" 8253 " }" 8254 "}" 8255 "alens[5] -= 2;" // Here the surrogate pairs match up. 8256 "var a2 = [];" 8257 "var b2 = [];" 8258 "var c2 = [];" 8259 "var a2lens = [];" 8260 "for (var m = 0; m < 9; m++) {" 8261 " for (var n = 0; n < 9; n++) {" 8262 " a2.push(a[m] + a[n]);" 8263 " b2.push(b[m] + b[n]);" 8264 " var newc = 'x' + c[m] + c[n] + 'y';" 8265 " c2.push(newc.substring(1, newc.length - 1));" 8266 " var utf = alens[m] + alens[n];" // And here. 8267 // The 'n's that start with 0xdc.. are 6-8 8268 // The 'm's that end with 0xd8.. are 1, 4 and 7 8269 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 8270 " a2lens.push(utf);" 8271 " }" 8272 "}"); 8273 Utf16Helper(context, "a", "alens", 9); 8274 Utf16Helper(context, "a2", "a2lens", 81); 8275 WriteUtf8Helper(context, "b", "alens", 9); 8276 WriteUtf8Helper(context, "b2", "a2lens", 81); 8277 WriteUtf8Helper(context, "c2", "a2lens", 81); 8278 } 8279 8280 8281 static bool SameSymbol(Handle<String> s1, Handle<String> s2) { 8282 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 8283 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 8284 return *is1 == *is2; 8285 } 8286 8287 static void SameSymbolHelper(v8::Isolate* isolate, const char* a, 8288 const char* b) { 8289 Handle<String> symbol1 = 8290 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString); 8291 Handle<String> symbol2 = 8292 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString); 8293 CHECK(SameSymbol(symbol1, symbol2)); 8294 } 8295 8296 8297 THREADED_TEST(Utf16Symbol) { 8298 LocalContext context; 8299 v8::HandleScope scope(context->GetIsolate()); 8300 8301 Handle<String> symbol1 = v8::String::NewFromUtf8( 8302 context->GetIsolate(), "abc", v8::String::kInternalizedString); 8303 Handle<String> symbol2 = v8::String::NewFromUtf8( 8304 context->GetIsolate(), "abc", v8::String::kInternalizedString); 8305 CHECK(SameSymbol(symbol1, symbol2)); 8306 8307 SameSymbolHelper(context->GetIsolate(), 8308 "\360\220\220\205", // 4 byte encoding. 8309 "\355\240\201\355\260\205"); // 2 3-byte surrogates. 8310 SameSymbolHelper(context->GetIsolate(), 8311 "\355\240\201\355\260\206", // 2 3-byte surrogates. 8312 "\360\220\220\206"); // 4 byte encoding. 8313 SameSymbolHelper(context->GetIsolate(), 8314 "x\360\220\220\205", // 4 byte encoding. 8315 "x\355\240\201\355\260\205"); // 2 3-byte surrogates. 8316 SameSymbolHelper(context->GetIsolate(), 8317 "x\355\240\201\355\260\206", // 2 3-byte surrogates. 8318 "x\360\220\220\206"); // 4 byte encoding. 8319 CompileRun( 8320 "var sym0 = 'benedictus';" 8321 "var sym0b = 'S\303\270ren';" 8322 "var sym1 = '\355\240\201\355\260\207';" 8323 "var sym2 = '\360\220\220\210';" 8324 "var sym3 = 'x\355\240\201\355\260\207';" 8325 "var sym4 = 'x\360\220\220\210';" 8326 "if (sym1.length != 2) throw sym1;" 8327 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 8328 "if (sym2.length != 2) throw sym2;" 8329 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 8330 "if (sym3.length != 3) throw sym3;" 8331 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 8332 "if (sym4.length != 3) throw sym4;" 8333 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 8334 Handle<String> sym0 = v8::String::NewFromUtf8( 8335 context->GetIsolate(), "benedictus", v8::String::kInternalizedString); 8336 Handle<String> sym0b = v8::String::NewFromUtf8( 8337 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString); 8338 Handle<String> sym1 = 8339 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207", 8340 v8::String::kInternalizedString); 8341 Handle<String> sym2 = 8342 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210", 8343 v8::String::kInternalizedString); 8344 Handle<String> sym3 = v8::String::NewFromUtf8( 8345 context->GetIsolate(), "x\355\240\201\355\260\207", 8346 v8::String::kInternalizedString); 8347 Handle<String> sym4 = 8348 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210", 8349 v8::String::kInternalizedString); 8350 v8::Local<v8::Object> global = context->Global(); 8351 Local<Value> s0 = global->Get(v8_str("sym0")); 8352 Local<Value> s0b = global->Get(v8_str("sym0b")); 8353 Local<Value> s1 = global->Get(v8_str("sym1")); 8354 Local<Value> s2 = global->Get(v8_str("sym2")); 8355 Local<Value> s3 = global->Get(v8_str("sym3")); 8356 Local<Value> s4 = global->Get(v8_str("sym4")); 8357 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0))); 8358 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b))); 8359 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1))); 8360 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2))); 8361 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3))); 8362 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4))); 8363 } 8364 8365 8366 THREADED_TEST(ToArrayIndex) { 8367 LocalContext context; 8368 v8::Isolate* isolate = context->GetIsolate(); 8369 v8::HandleScope scope(isolate); 8370 8371 v8::Handle<String> str = v8_str("42"); 8372 v8::Handle<v8::Uint32> index = str->ToArrayIndex(); 8373 CHECK(!index.IsEmpty()); 8374 CHECK_EQ(42.0, index->Uint32Value()); 8375 str = v8_str("42asdf"); 8376 index = str->ToArrayIndex(); 8377 CHECK(index.IsEmpty()); 8378 str = v8_str("-42"); 8379 index = str->ToArrayIndex(); 8380 CHECK(index.IsEmpty()); 8381 str = v8_str("4294967295"); 8382 index = str->ToArrayIndex(); 8383 CHECK(!index.IsEmpty()); 8384 CHECK_EQ(4294967295.0, index->Uint32Value()); 8385 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1); 8386 index = num->ToArrayIndex(); 8387 CHECK(!index.IsEmpty()); 8388 CHECK_EQ(1.0, index->Uint32Value()); 8389 num = v8::Number::New(isolate, -1); 8390 index = num->ToArrayIndex(); 8391 CHECK(index.IsEmpty()); 8392 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 8393 index = obj->ToArrayIndex(); 8394 CHECK(index.IsEmpty()); 8395 } 8396 8397 8398 THREADED_TEST(ErrorConstruction) { 8399 LocalContext context; 8400 v8::HandleScope scope(context->GetIsolate()); 8401 8402 v8::Handle<String> foo = v8_str("foo"); 8403 v8::Handle<String> message = v8_str("message"); 8404 v8::Handle<Value> range_error = v8::Exception::RangeError(foo); 8405 CHECK(range_error->IsObject()); 8406 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo)); 8407 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo); 8408 CHECK(reference_error->IsObject()); 8409 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo)); 8410 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo); 8411 CHECK(syntax_error->IsObject()); 8412 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo)); 8413 v8::Handle<Value> type_error = v8::Exception::TypeError(foo); 8414 CHECK(type_error->IsObject()); 8415 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo)); 8416 v8::Handle<Value> error = v8::Exception::Error(foo); 8417 CHECK(error->IsObject()); 8418 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo)); 8419 } 8420 8421 8422 static void YGetter(Local<String> name, 8423 const v8::PropertyCallbackInfo<v8::Value>& info) { 8424 ApiTestFuzzer::Fuzz(); 8425 info.GetReturnValue().Set(v8_num(10)); 8426 } 8427 8428 8429 static void YSetter(Local<String> name, 8430 Local<Value> value, 8431 const v8::PropertyCallbackInfo<void>& info) { 8432 Local<Object> this_obj = Local<Object>::Cast(info.This()); 8433 if (this_obj->Has(name)) this_obj->Delete(name); 8434 this_obj->Set(name, value); 8435 } 8436 8437 8438 THREADED_TEST(DeleteAccessor) { 8439 v8::Isolate* isolate = CcTest::isolate(); 8440 v8::HandleScope scope(isolate); 8441 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 8442 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 8443 LocalContext context; 8444 v8::Handle<v8::Object> holder = obj->NewInstance(); 8445 context->Global()->Set(v8_str("holder"), holder); 8446 v8::Handle<Value> result = CompileRun( 8447 "holder.y = 11; holder.y = 12; holder.y"); 8448 CHECK_EQ(12, result->Uint32Value()); 8449 } 8450 8451 8452 THREADED_TEST(TypeSwitch) { 8453 v8::Isolate* isolate = CcTest::isolate(); 8454 v8::HandleScope scope(isolate); 8455 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate); 8456 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate); 8457 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate); 8458 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 }; 8459 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs); 8460 LocalContext context; 8461 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate); 8462 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance(); 8463 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance(); 8464 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance(); 8465 for (int i = 0; i < 10; i++) { 8466 CHECK_EQ(0, type_switch->match(obj0)); 8467 CHECK_EQ(1, type_switch->match(obj1)); 8468 CHECK_EQ(2, type_switch->match(obj2)); 8469 CHECK_EQ(3, type_switch->match(obj3)); 8470 CHECK_EQ(3, type_switch->match(obj3)); 8471 CHECK_EQ(2, type_switch->match(obj2)); 8472 CHECK_EQ(1, type_switch->match(obj1)); 8473 CHECK_EQ(0, type_switch->match(obj0)); 8474 } 8475 } 8476 8477 8478 static int trouble_nesting = 0; 8479 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 8480 ApiTestFuzzer::Fuzz(); 8481 trouble_nesting++; 8482 8483 // Call a JS function that throws an uncaught exception. 8484 Local<v8::Object> arg_this = 8485 args.GetIsolate()->GetCurrentContext()->Global(); 8486 Local<Value> trouble_callee = (trouble_nesting == 3) ? 8487 arg_this->Get(v8_str("trouble_callee")) : 8488 arg_this->Get(v8_str("trouble_caller")); 8489 CHECK(trouble_callee->IsFunction()); 8490 args.GetReturnValue().Set( 8491 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL)); 8492 } 8493 8494 8495 static int report_count = 0; 8496 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>, 8497 v8::Handle<Value>) { 8498 report_count++; 8499 } 8500 8501 8502 // Counts uncaught exceptions, but other tests running in parallel 8503 // also have uncaught exceptions. 8504 TEST(ApiUncaughtException) { 8505 report_count = 0; 8506 LocalContext env; 8507 v8::Isolate* isolate = env->GetIsolate(); 8508 v8::HandleScope scope(isolate); 8509 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener); 8510 8511 Local<v8::FunctionTemplate> fun = 8512 v8::FunctionTemplate::New(isolate, TroubleCallback); 8513 v8::Local<v8::Object> global = env->Global(); 8514 global->Set(v8_str("trouble"), fun->GetFunction()); 8515 8516 CompileRun( 8517 "function trouble_callee() {" 8518 " var x = null;" 8519 " return x.foo;" 8520 "};" 8521 "function trouble_caller() {" 8522 " trouble();" 8523 "};"); 8524 Local<Value> trouble = global->Get(v8_str("trouble")); 8525 CHECK(trouble->IsFunction()); 8526 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee")); 8527 CHECK(trouble_callee->IsFunction()); 8528 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller")); 8529 CHECK(trouble_caller->IsFunction()); 8530 Function::Cast(*trouble_caller)->Call(global, 0, NULL); 8531 CHECK_EQ(1, report_count); 8532 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener); 8533 } 8534 8535 static const char* script_resource_name = "ExceptionInNativeScript.js"; 8536 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, 8537 v8::Handle<Value>) { 8538 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName(); 8539 CHECK(!name_val.IsEmpty() && name_val->IsString()); 8540 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 8541 CHECK_EQ(script_resource_name, *name); 8542 CHECK_EQ(3, message->GetLineNumber()); 8543 v8::String::Utf8Value source_line(message->GetSourceLine()); 8544 CHECK_EQ(" new o.foo();", *source_line); 8545 } 8546 8547 8548 TEST(ExceptionInNativeScript) { 8549 LocalContext env; 8550 v8::Isolate* isolate = env->GetIsolate(); 8551 v8::HandleScope scope(isolate); 8552 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener); 8553 8554 Local<v8::FunctionTemplate> fun = 8555 v8::FunctionTemplate::New(isolate, TroubleCallback); 8556 v8::Local<v8::Object> global = env->Global(); 8557 global->Set(v8_str("trouble"), fun->GetFunction()); 8558 8559 CompileRunWithOrigin( 8560 "function trouble() {\n" 8561 " var o = {};\n" 8562 " new o.foo();\n" 8563 "};", 8564 script_resource_name); 8565 Local<Value> trouble = global->Get(v8_str("trouble")); 8566 CHECK(trouble->IsFunction()); 8567 Function::Cast(*trouble)->Call(global, 0, NULL); 8568 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener); 8569 } 8570 8571 8572 TEST(CompilationErrorUsingTryCatchHandler) { 8573 LocalContext env; 8574 v8::HandleScope scope(env->GetIsolate()); 8575 v8::TryCatch try_catch; 8576 v8_compile("This doesn't &*&@#$&*^ compile."); 8577 CHECK_NE(NULL, *try_catch.Exception()); 8578 CHECK(try_catch.HasCaught()); 8579 } 8580 8581 8582 TEST(TryCatchFinallyUsingTryCatchHandler) { 8583 LocalContext env; 8584 v8::HandleScope scope(env->GetIsolate()); 8585 v8::TryCatch try_catch; 8586 CompileRun("try { throw ''; } catch (e) {}"); 8587 CHECK(!try_catch.HasCaught()); 8588 CompileRun("try { throw ''; } finally {}"); 8589 CHECK(try_catch.HasCaught()); 8590 try_catch.Reset(); 8591 CompileRun( 8592 "(function() {" 8593 "try { throw ''; } finally { return; }" 8594 "})()"); 8595 CHECK(!try_catch.HasCaught()); 8596 CompileRun( 8597 "(function()" 8598 " { try { throw ''; } finally { throw 0; }" 8599 "})()"); 8600 CHECK(try_catch.HasCaught()); 8601 } 8602 8603 8604 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) { 8605 v8::HandleScope scope(args.GetIsolate()); 8606 CompileRun(args[0]->ToString()); 8607 } 8608 8609 8610 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { 8611 v8::Isolate* isolate = CcTest::isolate(); 8612 v8::HandleScope scope(isolate); 8613 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 8614 templ->Set(v8_str("CEvaluate"), 8615 v8::FunctionTemplate::New(isolate, CEvaluate)); 8616 LocalContext context(0, templ); 8617 v8::TryCatch try_catch; 8618 CompileRun("try {" 8619 " CEvaluate('throw 1;');" 8620 "} finally {" 8621 "}"); 8622 CHECK(try_catch.HasCaught()); 8623 CHECK(!try_catch.Message().IsEmpty()); 8624 String::Utf8Value exception_value(try_catch.Exception()); 8625 CHECK_EQ(*exception_value, "1"); 8626 try_catch.Reset(); 8627 CompileRun("try {" 8628 " CEvaluate('throw 1;');" 8629 "} finally {" 8630 " throw 2;" 8631 "}"); 8632 CHECK(try_catch.HasCaught()); 8633 CHECK(!try_catch.Message().IsEmpty()); 8634 String::Utf8Value finally_exception_value(try_catch.Exception()); 8635 CHECK_EQ(*finally_exception_value, "2"); 8636 } 8637 8638 8639 // For use within the TestSecurityHandler() test. 8640 static bool g_security_callback_result = false; 8641 static bool NamedSecurityTestCallback(Local<v8::Object> global, 8642 Local<Value> name, 8643 v8::AccessType type, 8644 Local<Value> data) { 8645 printf("a\n"); 8646 // Always allow read access. 8647 if (type == v8::ACCESS_GET) 8648 return true; 8649 8650 // Sometimes allow other access. 8651 return g_security_callback_result; 8652 } 8653 8654 8655 static bool IndexedSecurityTestCallback(Local<v8::Object> global, 8656 uint32_t key, 8657 v8::AccessType type, 8658 Local<Value> data) { 8659 printf("b\n"); 8660 // Always allow read access. 8661 if (type == v8::ACCESS_GET) 8662 return true; 8663 8664 // Sometimes allow other access. 8665 return g_security_callback_result; 8666 } 8667 8668 8669 // SecurityHandler can't be run twice 8670 TEST(SecurityHandler) { 8671 v8::Isolate* isolate = CcTest::isolate(); 8672 v8::HandleScope scope0(isolate); 8673 v8::Handle<v8::ObjectTemplate> global_template = 8674 v8::ObjectTemplate::New(isolate); 8675 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, 8676 IndexedSecurityTestCallback); 8677 // Create an environment 8678 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template); 8679 context0->Enter(); 8680 8681 v8::Handle<v8::Object> global0 = context0->Global(); 8682 v8::Handle<Script> script0 = v8_compile("foo = 111"); 8683 script0->Run(); 8684 global0->Set(v8_str("0"), v8_num(999)); 8685 v8::Handle<Value> foo0 = global0->Get(v8_str("foo")); 8686 CHECK_EQ(111, foo0->Int32Value()); 8687 v8::Handle<Value> z0 = global0->Get(v8_str("0")); 8688 CHECK_EQ(999, z0->Int32Value()); 8689 8690 // Create another environment, should fail security checks. 8691 v8::HandleScope scope1(isolate); 8692 8693 v8::Handle<Context> context1 = 8694 Context::New(isolate, NULL, global_template); 8695 context1->Enter(); 8696 8697 v8::Handle<v8::Object> global1 = context1->Global(); 8698 global1->Set(v8_str("othercontext"), global0); 8699 // This set will fail the security check. 8700 v8::Handle<Script> script1 = 8701 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 8702 script1->Run(); 8703 // This read will pass the security check. 8704 v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); 8705 CHECK_EQ(111, foo1->Int32Value()); 8706 // This read will pass the security check. 8707 v8::Handle<Value> z1 = global0->Get(v8_str("0")); 8708 CHECK_EQ(999, z1->Int32Value()); 8709 8710 // Create another environment, should pass security checks. 8711 { g_security_callback_result = true; // allow security handler to pass. 8712 v8::HandleScope scope2(isolate); 8713 LocalContext context2; 8714 v8::Handle<v8::Object> global2 = context2->Global(); 8715 global2->Set(v8_str("othercontext"), global0); 8716 v8::Handle<Script> script2 = 8717 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 8718 script2->Run(); 8719 v8::Handle<Value> foo2 = global0->Get(v8_str("foo")); 8720 CHECK_EQ(333, foo2->Int32Value()); 8721 v8::Handle<Value> z2 = global0->Get(v8_str("0")); 8722 CHECK_EQ(888, z2->Int32Value()); 8723 } 8724 8725 context1->Exit(); 8726 context0->Exit(); 8727 } 8728 8729 8730 THREADED_TEST(SecurityChecks) { 8731 LocalContext env1; 8732 v8::HandleScope handle_scope(env1->GetIsolate()); 8733 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8734 8735 Local<Value> foo = v8_str("foo"); 8736 Local<Value> bar = v8_str("bar"); 8737 8738 // Set to the same domain. 8739 env1->SetSecurityToken(foo); 8740 8741 // Create a function in env1. 8742 CompileRun("spy=function(){return spy;}"); 8743 Local<Value> spy = env1->Global()->Get(v8_str("spy")); 8744 CHECK(spy->IsFunction()); 8745 8746 // Create another function accessing global objects. 8747 CompileRun("spy2=function(){return new this.Array();}"); 8748 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2")); 8749 CHECK(spy2->IsFunction()); 8750 8751 // Switch to env2 in the same domain and invoke spy on env2. 8752 { 8753 env2->SetSecurityToken(foo); 8754 // Enter env2 8755 Context::Scope scope_env2(env2); 8756 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL); 8757 CHECK(result->IsFunction()); 8758 } 8759 8760 { 8761 env2->SetSecurityToken(bar); 8762 Context::Scope scope_env2(env2); 8763 8764 // Call cross_domain_call, it should throw an exception 8765 v8::TryCatch try_catch; 8766 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); 8767 CHECK(try_catch.HasCaught()); 8768 } 8769 } 8770 8771 8772 // Regression test case for issue 1183439. 8773 THREADED_TEST(SecurityChecksForPrototypeChain) { 8774 LocalContext current; 8775 v8::HandleScope scope(current->GetIsolate()); 8776 v8::Handle<Context> other = Context::New(current->GetIsolate()); 8777 8778 // Change context to be able to get to the Object function in the 8779 // other context without hitting the security checks. 8780 v8::Local<Value> other_object; 8781 { Context::Scope scope(other); 8782 other_object = other->Global()->Get(v8_str("Object")); 8783 other->Global()->Set(v8_num(42), v8_num(87)); 8784 } 8785 8786 current->Global()->Set(v8_str("other"), other->Global()); 8787 CHECK(v8_compile("other")->Run()->Equals(other->Global())); 8788 8789 // Make sure the security check fails here and we get an undefined 8790 // result instead of getting the Object function. Repeat in a loop 8791 // to make sure to exercise the IC code. 8792 v8::Local<Script> access_other0 = v8_compile("other.Object"); 8793 v8::Local<Script> access_other1 = v8_compile("other[42]"); 8794 for (int i = 0; i < 5; i++) { 8795 CHECK(access_other0->Run().IsEmpty()); 8796 CHECK(access_other1->Run().IsEmpty()); 8797 } 8798 8799 // Create an object that has 'other' in its prototype chain and make 8800 // sure we cannot access the Object function indirectly through 8801 // that. Repeat in a loop to make sure to exercise the IC code. 8802 v8_compile("function F() { };" 8803 "F.prototype = other;" 8804 "var f = new F();")->Run(); 8805 v8::Local<Script> access_f0 = v8_compile("f.Object"); 8806 v8::Local<Script> access_f1 = v8_compile("f[42]"); 8807 for (int j = 0; j < 5; j++) { 8808 CHECK(access_f0->Run().IsEmpty()); 8809 CHECK(access_f1->Run().IsEmpty()); 8810 } 8811 8812 // Now it gets hairy: Set the prototype for the other global object 8813 // to be the current global object. The prototype chain for 'f' now 8814 // goes through 'other' but ends up in the current global object. 8815 { Context::Scope scope(other); 8816 other->Global()->Set(v8_str("__proto__"), current->Global()); 8817 } 8818 // Set a named and an index property on the current global 8819 // object. To force the lookup to go through the other global object, 8820 // the properties must not exist in the other global object. 8821 current->Global()->Set(v8_str("foo"), v8_num(100)); 8822 current->Global()->Set(v8_num(99), v8_num(101)); 8823 // Try to read the properties from f and make sure that the access 8824 // gets stopped by the security checks on the other global object. 8825 Local<Script> access_f2 = v8_compile("f.foo"); 8826 Local<Script> access_f3 = v8_compile("f[99]"); 8827 for (int k = 0; k < 5; k++) { 8828 CHECK(access_f2->Run().IsEmpty()); 8829 CHECK(access_f3->Run().IsEmpty()); 8830 } 8831 } 8832 8833 8834 static bool named_security_check_with_gc_called; 8835 8836 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global, 8837 Local<Value> name, 8838 v8::AccessType type, 8839 Local<Value> data) { 8840 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 8841 named_security_check_with_gc_called = true; 8842 return true; 8843 } 8844 8845 8846 static bool indexed_security_check_with_gc_called; 8847 8848 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global, 8849 uint32_t key, 8850 v8::AccessType type, 8851 Local<Value> data) { 8852 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 8853 indexed_security_check_with_gc_called = true; 8854 return true; 8855 } 8856 8857 8858 TEST(SecurityTestGCAllowed) { 8859 v8::Isolate* isolate = CcTest::isolate(); 8860 v8::HandleScope handle_scope(isolate); 8861 v8::Handle<v8::ObjectTemplate> object_template = 8862 v8::ObjectTemplate::New(isolate); 8863 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC, 8864 IndexedSecurityTestCallbackWithGC); 8865 8866 v8::Handle<Context> context = Context::New(isolate); 8867 v8::Context::Scope context_scope(context); 8868 8869 context->Global()->Set(v8_str("obj"), object_template->NewInstance()); 8870 8871 named_security_check_with_gc_called = false; 8872 CompileRun("obj.foo = new String(1001);"); 8873 CHECK(named_security_check_with_gc_called); 8874 8875 indexed_security_check_with_gc_called = false; 8876 CompileRun("obj[0] = new String(1002);"); 8877 CHECK(indexed_security_check_with_gc_called); 8878 8879 named_security_check_with_gc_called = false; 8880 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001"))); 8881 CHECK(named_security_check_with_gc_called); 8882 8883 indexed_security_check_with_gc_called = false; 8884 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002"))); 8885 CHECK(indexed_security_check_with_gc_called); 8886 } 8887 8888 8889 THREADED_TEST(CrossDomainDelete) { 8890 LocalContext env1; 8891 v8::HandleScope handle_scope(env1->GetIsolate()); 8892 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8893 8894 Local<Value> foo = v8_str("foo"); 8895 Local<Value> bar = v8_str("bar"); 8896 8897 // Set to the same domain. 8898 env1->SetSecurityToken(foo); 8899 env2->SetSecurityToken(foo); 8900 8901 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8902 env2->Global()->Set(v8_str("env1"), env1->Global()); 8903 8904 // Change env2 to a different domain and delete env1.prop. 8905 env2->SetSecurityToken(bar); 8906 { 8907 Context::Scope scope_env2(env2); 8908 Local<Value> result = 8909 CompileRun("delete env1.prop"); 8910 CHECK(result.IsEmpty()); 8911 } 8912 8913 // Check that env1.prop still exists. 8914 Local<Value> v = env1->Global()->Get(v8_str("prop")); 8915 CHECK(v->IsNumber()); 8916 CHECK_EQ(3, v->Int32Value()); 8917 } 8918 8919 8920 THREADED_TEST(CrossDomainIsPropertyEnumerable) { 8921 LocalContext env1; 8922 v8::HandleScope handle_scope(env1->GetIsolate()); 8923 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8924 8925 Local<Value> foo = v8_str("foo"); 8926 Local<Value> bar = v8_str("bar"); 8927 8928 // Set to the same domain. 8929 env1->SetSecurityToken(foo); 8930 env2->SetSecurityToken(foo); 8931 8932 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8933 env2->Global()->Set(v8_str("env1"), env1->Global()); 8934 8935 // env1.prop is enumerable in env2. 8936 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 8937 { 8938 Context::Scope scope_env2(env2); 8939 Local<Value> result = CompileRun(test); 8940 CHECK(result->IsTrue()); 8941 } 8942 8943 // Change env2 to a different domain and test again. 8944 env2->SetSecurityToken(bar); 8945 { 8946 Context::Scope scope_env2(env2); 8947 Local<Value> result = CompileRun(test); 8948 CHECK(result.IsEmpty()); 8949 } 8950 } 8951 8952 8953 THREADED_TEST(CrossDomainForIn) { 8954 LocalContext env1; 8955 v8::HandleScope handle_scope(env1->GetIsolate()); 8956 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8957 8958 Local<Value> foo = v8_str("foo"); 8959 Local<Value> bar = v8_str("bar"); 8960 8961 // Set to the same domain. 8962 env1->SetSecurityToken(foo); 8963 env2->SetSecurityToken(foo); 8964 8965 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8966 env2->Global()->Set(v8_str("env1"), env1->Global()); 8967 8968 // Change env2 to a different domain and set env1's global object 8969 // as the __proto__ of an object in env2 and enumerate properties 8970 // in for-in. It shouldn't enumerate properties on env1's global 8971 // object. 8972 env2->SetSecurityToken(bar); 8973 { 8974 Context::Scope scope_env2(env2); 8975 Local<Value> result = CompileRun( 8976 "(function() {" 8977 " var obj = { '__proto__': env1 };" 8978 " try {" 8979 " for (var p in obj) {" 8980 " if (p == 'prop') return false;" 8981 " }" 8982 " return false;" 8983 " } catch (e) {" 8984 " return true;" 8985 " }" 8986 "})()"); 8987 CHECK(result->IsTrue()); 8988 } 8989 } 8990 8991 8992 TEST(ContextDetachGlobal) { 8993 LocalContext env1; 8994 v8::HandleScope handle_scope(env1->GetIsolate()); 8995 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8996 8997 Local<v8::Object> global1 = env1->Global(); 8998 8999 Local<Value> foo = v8_str("foo"); 9000 9001 // Set to the same domain. 9002 env1->SetSecurityToken(foo); 9003 env2->SetSecurityToken(foo); 9004 9005 // Enter env2 9006 env2->Enter(); 9007 9008 // Create a function in env2 and add a reference to it in env1. 9009 Local<v8::Object> global2 = env2->Global(); 9010 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1)); 9011 CompileRun("function getProp() {return prop;}"); 9012 9013 env1->Global()->Set(v8_str("getProp"), 9014 global2->Get(v8_str("getProp"))); 9015 9016 // Detach env2's global, and reuse the global object of env2 9017 env2->Exit(); 9018 env2->DetachGlobal(); 9019 9020 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 9021 0, 9022 v8::Handle<v8::ObjectTemplate>(), 9023 global2); 9024 env3->SetSecurityToken(v8_str("bar")); 9025 env3->Enter(); 9026 9027 Local<v8::Object> global3 = env3->Global(); 9028 CHECK_EQ(global2, global3); 9029 CHECK(global3->Get(v8_str("prop"))->IsUndefined()); 9030 CHECK(global3->Get(v8_str("getProp"))->IsUndefined()); 9031 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1)); 9032 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2)); 9033 env3->Exit(); 9034 9035 // Call getProp in env1, and it should return the value 1 9036 { 9037 Local<Value> get_prop = global1->Get(v8_str("getProp")); 9038 CHECK(get_prop->IsFunction()); 9039 v8::TryCatch try_catch; 9040 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); 9041 CHECK(!try_catch.HasCaught()); 9042 CHECK_EQ(1, r->Int32Value()); 9043 } 9044 9045 // Check that env3 is not accessible from env1 9046 { 9047 Local<Value> r = global3->Get(v8_str("prop2")); 9048 CHECK(r.IsEmpty()); 9049 } 9050 } 9051 9052 9053 TEST(DetachGlobal) { 9054 LocalContext env1; 9055 v8::HandleScope scope(env1->GetIsolate()); 9056 9057 // Create second environment. 9058 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 9059 9060 Local<Value> foo = v8_str("foo"); 9061 9062 // Set same security token for env1 and env2. 9063 env1->SetSecurityToken(foo); 9064 env2->SetSecurityToken(foo); 9065 9066 // Create a property on the global object in env2. 9067 { 9068 v8::Context::Scope scope(env2); 9069 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42)); 9070 } 9071 9072 // Create a reference to env2 global from env1 global. 9073 env1->Global()->Set(v8_str("other"), env2->Global()); 9074 9075 // Check that we have access to other.p in env2 from env1. 9076 Local<Value> result = CompileRun("other.p"); 9077 CHECK(result->IsInt32()); 9078 CHECK_EQ(42, result->Int32Value()); 9079 9080 // Hold on to global from env2 and detach global from env2. 9081 Local<v8::Object> global2 = env2->Global(); 9082 env2->DetachGlobal(); 9083 9084 // Check that the global has been detached. No other.p property can 9085 // be found. 9086 result = CompileRun("other.p"); 9087 CHECK(result.IsEmpty()); 9088 9089 // Reuse global2 for env3. 9090 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 9091 0, 9092 v8::Handle<v8::ObjectTemplate>(), 9093 global2); 9094 CHECK_EQ(global2, env3->Global()); 9095 9096 // Start by using the same security token for env3 as for env1 and env2. 9097 env3->SetSecurityToken(foo); 9098 9099 // Create a property on the global object in env3. 9100 { 9101 v8::Context::Scope scope(env3); 9102 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24)); 9103 } 9104 9105 // Check that other.p is now the property in env3 and that we have access. 9106 result = CompileRun("other.p"); 9107 CHECK(result->IsInt32()); 9108 CHECK_EQ(24, result->Int32Value()); 9109 9110 // Change security token for env3 to something different from env1 and env2. 9111 env3->SetSecurityToken(v8_str("bar")); 9112 9113 // Check that we do not have access to other.p in env1. |other| is now 9114 // the global object for env3 which has a different security token, 9115 // so access should be blocked. 9116 result = CompileRun("other.p"); 9117 CHECK(result.IsEmpty()); 9118 } 9119 9120 9121 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) { 9122 info.GetReturnValue().Set( 9123 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x"))); 9124 } 9125 9126 9127 TEST(DetachedAccesses) { 9128 LocalContext env1; 9129 v8::HandleScope scope(env1->GetIsolate()); 9130 9131 // Create second environment. 9132 Local<ObjectTemplate> inner_global_template = 9133 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate(); 9134 inner_global_template ->SetAccessorProperty( 9135 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX)); 9136 v8::Local<Context> env2 = 9137 Context::New(env1->GetIsolate(), NULL, inner_global_template); 9138 9139 Local<Value> foo = v8_str("foo"); 9140 9141 // Set same security token for env1 and env2. 9142 env1->SetSecurityToken(foo); 9143 env2->SetSecurityToken(foo); 9144 9145 env1->Global()->Set(v8_str("x"), v8_str("env1_x")); 9146 9147 { 9148 v8::Context::Scope scope(env2); 9149 env2->Global()->Set(v8_str("x"), v8_str("env2_x")); 9150 CompileRun( 9151 "function bound_x() { return x; }" 9152 "function get_x() { return this.x; }" 9153 "function get_x_w() { return (function() {return this.x;})(); }"); 9154 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x")); 9155 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x")); 9156 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w")); 9157 env1->Global()->Set( 9158 v8_str("this_x"), 9159 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get")); 9160 } 9161 9162 Local<Object> env2_global = env2->Global(); 9163 env2_global->TurnOnAccessCheck(); 9164 env2->DetachGlobal(); 9165 9166 Local<Value> result; 9167 result = CompileRun("bound_x()"); 9168 CHECK_EQ(v8_str("env2_x"), result); 9169 result = CompileRun("get_x()"); 9170 CHECK(result.IsEmpty()); 9171 result = CompileRun("get_x_w()"); 9172 CHECK(result.IsEmpty()); 9173 result = CompileRun("this_x()"); 9174 CHECK_EQ(v8_str("env2_x"), result); 9175 9176 // Reattach env2's proxy 9177 env2 = Context::New(env1->GetIsolate(), 9178 0, 9179 v8::Handle<v8::ObjectTemplate>(), 9180 env2_global); 9181 env2->SetSecurityToken(foo); 9182 { 9183 v8::Context::Scope scope(env2); 9184 env2->Global()->Set(v8_str("x"), v8_str("env3_x")); 9185 env2->Global()->Set(v8_str("env1"), env1->Global()); 9186 result = CompileRun( 9187 "results = [];" 9188 "for (var i = 0; i < 4; i++ ) {" 9189 " results.push(env1.bound_x());" 9190 " results.push(env1.get_x());" 9191 " results.push(env1.get_x_w());" 9192 " results.push(env1.this_x());" 9193 "}" 9194 "results"); 9195 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9196 CHECK_EQ(16, results->Length()); 9197 for (int i = 0; i < 16; i += 4) { 9198 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 9199 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1)); 9200 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 9201 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 9202 } 9203 } 9204 9205 result = CompileRun( 9206 "results = [];" 9207 "for (var i = 0; i < 4; i++ ) {" 9208 " results.push(bound_x());" 9209 " results.push(get_x());" 9210 " results.push(get_x_w());" 9211 " results.push(this_x());" 9212 "}" 9213 "results"); 9214 Local<v8::Array> results = Local<v8::Array>::Cast(result); 9215 CHECK_EQ(16, results->Length()); 9216 for (int i = 0; i < 16; i += 4) { 9217 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 9218 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1)); 9219 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 9220 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 9221 } 9222 9223 result = CompileRun( 9224 "results = [];" 9225 "for (var i = 0; i < 4; i++ ) {" 9226 " results.push(this.bound_x());" 9227 " results.push(this.get_x());" 9228 " results.push(this.get_x_w());" 9229 " results.push(this.this_x());" 9230 "}" 9231 "results"); 9232 results = Local<v8::Array>::Cast(result); 9233 CHECK_EQ(16, results->Length()); 9234 for (int i = 0; i < 16; i += 4) { 9235 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0)); 9236 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1)); 9237 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2)); 9238 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3)); 9239 } 9240 } 9241 9242 9243 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; 9244 static bool NamedAccessBlocker(Local<v8::Object> global, 9245 Local<Value> name, 9246 v8::AccessType type, 9247 Local<Value> data) { 9248 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 9249 allowed_access_type[type]; 9250 } 9251 9252 9253 static bool IndexedAccessBlocker(Local<v8::Object> global, 9254 uint32_t key, 9255 v8::AccessType type, 9256 Local<Value> data) { 9257 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 9258 allowed_access_type[type]; 9259 } 9260 9261 9262 static int g_echo_value = -1; 9263 9264 9265 static void EchoGetter( 9266 Local<String> name, 9267 const v8::PropertyCallbackInfo<v8::Value>& info) { 9268 info.GetReturnValue().Set(v8_num(g_echo_value)); 9269 } 9270 9271 9272 static void EchoSetter(Local<String> name, 9273 Local<Value> value, 9274 const v8::PropertyCallbackInfo<void>&) { 9275 if (value->IsNumber()) 9276 g_echo_value = value->Int32Value(); 9277 } 9278 9279 9280 static void UnreachableGetter( 9281 Local<String> name, 9282 const v8::PropertyCallbackInfo<v8::Value>& info) { 9283 CHECK(false); // This function should not be called.. 9284 } 9285 9286 9287 static void UnreachableSetter(Local<String>, 9288 Local<Value>, 9289 const v8::PropertyCallbackInfo<void>&) { 9290 CHECK(false); // This function should nto be called. 9291 } 9292 9293 9294 static void UnreachableFunction( 9295 const v8::FunctionCallbackInfo<v8::Value>& info) { 9296 CHECK(false); // This function should not be called.. 9297 } 9298 9299 9300 TEST(AccessControl) { 9301 v8::Isolate* isolate = CcTest::isolate(); 9302 v8::HandleScope handle_scope(isolate); 9303 v8::Handle<v8::ObjectTemplate> global_template = 9304 v8::ObjectTemplate::New(isolate); 9305 9306 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 9307 IndexedAccessBlocker); 9308 9309 // Add an accessor accessible by cross-domain JS code. 9310 global_template->SetAccessor( 9311 v8_str("accessible_prop"), 9312 EchoGetter, EchoSetter, 9313 v8::Handle<Value>(), 9314 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9315 9316 9317 // Add an accessor that is not accessible by cross-domain JS code. 9318 global_template->SetAccessor(v8_str("blocked_prop"), 9319 UnreachableGetter, UnreachableSetter, 9320 v8::Handle<Value>(), 9321 v8::DEFAULT); 9322 9323 global_template->SetAccessorProperty( 9324 v8_str("blocked_js_prop"), 9325 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9326 v8::FunctionTemplate::New(isolate, UnreachableFunction), 9327 v8::None, 9328 v8::DEFAULT); 9329 9330 // Create an environment 9331 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9332 context0->Enter(); 9333 9334 v8::Handle<v8::Object> global0 = context0->Global(); 9335 9336 // Define a property with JS getter and setter. 9337 CompileRun( 9338 "function getter() { return 'getter'; };\n" 9339 "function setter() { return 'setter'; }\n" 9340 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 9341 9342 Local<Value> getter = global0->Get(v8_str("getter")); 9343 Local<Value> setter = global0->Get(v8_str("setter")); 9344 9345 // And define normal element. 9346 global0->Set(239, v8_str("239")); 9347 9348 // Define an element with JS getter and setter. 9349 CompileRun( 9350 "function el_getter() { return 'el_getter'; };\n" 9351 "function el_setter() { return 'el_setter'; };\n" 9352 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 9353 9354 Local<Value> el_getter = global0->Get(v8_str("el_getter")); 9355 Local<Value> el_setter = global0->Get(v8_str("el_setter")); 9356 9357 v8::HandleScope scope1(isolate); 9358 9359 v8::Local<Context> context1 = Context::New(isolate); 9360 context1->Enter(); 9361 9362 v8::Handle<v8::Object> global1 = context1->Global(); 9363 global1->Set(v8_str("other"), global0); 9364 9365 // Access blocked property. 9366 CompileRun("other.blocked_prop = 1"); 9367 9368 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9369 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 9370 .IsEmpty()); 9371 CHECK( 9372 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty()); 9373 9374 // Access blocked element. 9375 CHECK(CompileRun("other[239] = 1").IsEmpty()); 9376 9377 CHECK(CompileRun("other[239]").IsEmpty()); 9378 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty()); 9379 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty()); 9380 9381 // Enable ACCESS_HAS 9382 allowed_access_type[v8::ACCESS_HAS] = true; 9383 CHECK(CompileRun("other[239]").IsEmpty()); 9384 // ... and now we can get the descriptor... 9385 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value") 9386 .IsEmpty()); 9387 // ... and enumerate the property. 9388 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 9389 allowed_access_type[v8::ACCESS_HAS] = false; 9390 9391 // Access a property with JS accessor. 9392 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty()); 9393 9394 CHECK(CompileRun("other.js_accessor_p").IsEmpty()); 9395 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')") 9396 .IsEmpty()); 9397 9398 // Enable both ACCESS_HAS and ACCESS_GET. 9399 allowed_access_type[v8::ACCESS_HAS] = true; 9400 allowed_access_type[v8::ACCESS_GET] = true; 9401 9402 ExpectString("other.js_accessor_p", "getter"); 9403 ExpectObject( 9404 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 9405 ExpectObject( 9406 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 9407 ExpectUndefined( 9408 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 9409 9410 allowed_access_type[v8::ACCESS_HAS] = false; 9411 allowed_access_type[v8::ACCESS_GET] = false; 9412 9413 // Access an element with JS accessor. 9414 CHECK(CompileRun("other[42] = 2").IsEmpty()); 9415 9416 CHECK(CompileRun("other[42]").IsEmpty()); 9417 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty()); 9418 9419 // Enable both ACCESS_HAS and ACCESS_GET. 9420 allowed_access_type[v8::ACCESS_HAS] = true; 9421 allowed_access_type[v8::ACCESS_GET] = true; 9422 9423 ExpectString("other[42]", "el_getter"); 9424 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 9425 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 9426 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 9427 9428 allowed_access_type[v8::ACCESS_HAS] = false; 9429 allowed_access_type[v8::ACCESS_GET] = false; 9430 9431 v8::Handle<Value> value; 9432 9433 // Access accessible property 9434 value = CompileRun("other.accessible_prop = 3"); 9435 CHECK(value->IsNumber()); 9436 CHECK_EQ(3, value->Int32Value()); 9437 CHECK_EQ(3, g_echo_value); 9438 9439 value = CompileRun("other.accessible_prop"); 9440 CHECK(value->IsNumber()); 9441 CHECK_EQ(3, value->Int32Value()); 9442 9443 value = CompileRun( 9444 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 9445 CHECK(value->IsNumber()); 9446 CHECK_EQ(3, value->Int32Value()); 9447 9448 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 9449 CHECK(value->IsTrue()); 9450 9451 // Enumeration doesn't enumerate accessors from inaccessible objects in 9452 // the prototype chain even if the accessors are in themselves accessible. 9453 value = CompileRun( 9454 "(function() {" 9455 " var obj = { '__proto__': other };" 9456 " try {" 9457 " for (var p in obj) {" 9458 " if (p == 'accessible_prop' ||" 9459 " p == 'blocked_js_prop' ||" 9460 " p == 'blocked_js_prop') {" 9461 " return false;" 9462 " }" 9463 " }" 9464 " return false;" 9465 " } catch (e) {" 9466 " return true;" 9467 " }" 9468 "})()"); 9469 CHECK(value->IsTrue()); 9470 9471 context1->Exit(); 9472 context0->Exit(); 9473 } 9474 9475 9476 TEST(AccessControlES5) { 9477 v8::Isolate* isolate = CcTest::isolate(); 9478 v8::HandleScope handle_scope(isolate); 9479 v8::Handle<v8::ObjectTemplate> global_template = 9480 v8::ObjectTemplate::New(isolate); 9481 9482 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 9483 IndexedAccessBlocker); 9484 9485 // Add accessible accessor. 9486 global_template->SetAccessor( 9487 v8_str("accessible_prop"), 9488 EchoGetter, EchoSetter, 9489 v8::Handle<Value>(), 9490 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9491 9492 9493 // Add an accessor that is not accessible by cross-domain JS code. 9494 global_template->SetAccessor(v8_str("blocked_prop"), 9495 UnreachableGetter, UnreachableSetter, 9496 v8::Handle<Value>(), 9497 v8::DEFAULT); 9498 9499 // Create an environment 9500 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9501 context0->Enter(); 9502 9503 v8::Handle<v8::Object> global0 = context0->Global(); 9504 9505 v8::Local<Context> context1 = Context::New(isolate); 9506 context1->Enter(); 9507 v8::Handle<v8::Object> global1 = context1->Global(); 9508 global1->Set(v8_str("other"), global0); 9509 9510 // Regression test for issue 1154. 9511 CHECK(CompileRun("Object.keys(other)").IsEmpty()); 9512 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9513 9514 // Regression test for issue 1027. 9515 CompileRun("Object.defineProperty(\n" 9516 " other, 'blocked_prop', {configurable: false})"); 9517 CHECK(CompileRun("other.blocked_prop").IsEmpty()); 9518 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')") 9519 .IsEmpty()); 9520 9521 // Regression test for issue 1171. 9522 ExpectTrue("Object.isExtensible(other)"); 9523 CompileRun("Object.preventExtensions(other)"); 9524 ExpectTrue("Object.isExtensible(other)"); 9525 9526 // Object.seal and Object.freeze. 9527 CompileRun("Object.freeze(other)"); 9528 ExpectTrue("Object.isExtensible(other)"); 9529 9530 CompileRun("Object.seal(other)"); 9531 ExpectTrue("Object.isExtensible(other)"); 9532 9533 // Regression test for issue 1250. 9534 // Make sure that we can set the accessible accessors value using normal 9535 // assignment. 9536 CompileRun("other.accessible_prop = 42"); 9537 CHECK_EQ(42, g_echo_value); 9538 9539 v8::Handle<Value> value; 9540 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); 9541 value = CompileRun("other.accessible_prop == 42"); 9542 CHECK(value->IsTrue()); 9543 } 9544 9545 9546 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name, 9547 v8::AccessType type, Local<Value> data) { 9548 return false; 9549 } 9550 9551 9552 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key, 9553 v8::AccessType type, Local<Value> data) { 9554 return false; 9555 } 9556 9557 9558 THREADED_TEST(AccessControlGetOwnPropertyNames) { 9559 v8::Isolate* isolate = CcTest::isolate(); 9560 v8::HandleScope handle_scope(isolate); 9561 v8::Handle<v8::ObjectTemplate> obj_template = 9562 v8::ObjectTemplate::New(isolate); 9563 9564 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 9565 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed, 9566 BlockEverythingIndexed); 9567 9568 // Create an environment 9569 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 9570 context0->Enter(); 9571 9572 v8::Handle<v8::Object> global0 = context0->Global(); 9573 9574 v8::HandleScope scope1(CcTest::isolate()); 9575 9576 v8::Local<Context> context1 = Context::New(isolate); 9577 context1->Enter(); 9578 9579 v8::Handle<v8::Object> global1 = context1->Global(); 9580 global1->Set(v8_str("other"), global0); 9581 global1->Set(v8_str("object"), obj_template->NewInstance()); 9582 9583 v8::Handle<Value> value; 9584 9585 // Attempt to get the property names of the other global object and 9586 // of an object that requires access checks. Accessing the other 9587 // global object should be blocked by access checks on the global 9588 // proxy object. Accessing the object that requires access checks 9589 // is blocked by the access checks on the object itself. 9590 value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); 9591 CHECK(value.IsEmpty()); 9592 9593 value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); 9594 CHECK(value.IsEmpty()); 9595 9596 context1->Exit(); 9597 context0->Exit(); 9598 } 9599 9600 9601 TEST(SuperAccessControl) { 9602 i::FLAG_harmony_classes = true; 9603 v8::Isolate* isolate = CcTest::isolate(); 9604 v8::HandleScope handle_scope(isolate); 9605 v8::Handle<v8::ObjectTemplate> obj_template = 9606 v8::ObjectTemplate::New(isolate); 9607 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed, 9608 BlockEverythingIndexed); 9609 LocalContext env; 9610 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); 9611 9612 v8::TryCatch try_catch; 9613 CompileRun( 9614 "function f() { return super.hasOwnProperty; };" 9615 "var m = f.toMethod(prohibited);" 9616 "m();"); 9617 CHECK(try_catch.HasCaught()); 9618 } 9619 9620 9621 static void IndexedPropertyEnumerator( 9622 const v8::PropertyCallbackInfo<v8::Array>& info) { 9623 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9624 result->Set(0, v8::Integer::New(info.GetIsolate(), 7)); 9625 result->Set(1, v8::Object::New(info.GetIsolate())); 9626 info.GetReturnValue().Set(result); 9627 } 9628 9629 9630 static void NamedPropertyEnumerator( 9631 const v8::PropertyCallbackInfo<v8::Array>& info) { 9632 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9633 result->Set(0, v8_str("x")); 9634 result->Set(1, v8::Object::New(info.GetIsolate())); 9635 info.GetReturnValue().Set(result); 9636 } 9637 9638 9639 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { 9640 v8::Isolate* isolate = CcTest::isolate(); 9641 v8::HandleScope handle_scope(isolate); 9642 v8::Handle<v8::ObjectTemplate> obj_template = 9643 v8::ObjectTemplate::New(isolate); 9644 9645 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7)); 9646 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42)); 9647 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, 9648 IndexedPropertyEnumerator); 9649 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL, 9650 NamedPropertyEnumerator); 9651 9652 LocalContext context; 9653 v8::Handle<v8::Object> global = context->Global(); 9654 global->Set(v8_str("object"), obj_template->NewInstance()); 9655 9656 v8::Handle<v8::Value> result = 9657 CompileRun("Object.getOwnPropertyNames(object)"); 9658 CHECK(result->IsArray()); 9659 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result); 9660 CHECK_EQ(3, result_array->Length()); 9661 CHECK(result_array->Get(0)->IsString()); 9662 CHECK(result_array->Get(1)->IsString()); 9663 CHECK(result_array->Get(2)->IsString()); 9664 CHECK_EQ(v8_str("7"), result_array->Get(0)); 9665 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1)); 9666 CHECK_EQ(v8_str("x"), result_array->Get(2)); 9667 } 9668 9669 9670 static void ConstTenGetter(Local<String> name, 9671 const v8::PropertyCallbackInfo<v8::Value>& info) { 9672 info.GetReturnValue().Set(v8_num(10)); 9673 } 9674 9675 9676 THREADED_TEST(CrossDomainAccessors) { 9677 v8::Isolate* isolate = CcTest::isolate(); 9678 v8::HandleScope handle_scope(isolate); 9679 9680 v8::Handle<v8::FunctionTemplate> func_template = 9681 v8::FunctionTemplate::New(isolate); 9682 9683 v8::Handle<v8::ObjectTemplate> global_template = 9684 func_template->InstanceTemplate(); 9685 9686 v8::Handle<v8::ObjectTemplate> proto_template = 9687 func_template->PrototypeTemplate(); 9688 9689 // Add an accessor to proto that's accessible by cross-domain JS code. 9690 proto_template->SetAccessor(v8_str("accessible"), 9691 ConstTenGetter, 0, 9692 v8::Handle<Value>(), 9693 v8::ALL_CAN_READ); 9694 9695 // Add an accessor that is not accessible by cross-domain JS code. 9696 global_template->SetAccessor(v8_str("unreachable"), 9697 UnreachableGetter, 0, 9698 v8::Handle<Value>(), 9699 v8::DEFAULT); 9700 9701 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9702 context0->Enter(); 9703 9704 Local<v8::Object> global = context0->Global(); 9705 // Add a normal property that shadows 'accessible' 9706 global->Set(v8_str("accessible"), v8_num(11)); 9707 9708 // Enter a new context. 9709 v8::HandleScope scope1(CcTest::isolate()); 9710 v8::Local<Context> context1 = Context::New(isolate); 9711 context1->Enter(); 9712 9713 v8::Handle<v8::Object> global1 = context1->Global(); 9714 global1->Set(v8_str("other"), global); 9715 9716 // Should return 10, instead of 11 9717 v8::Handle<Value> value = v8_compile("other.accessible")->Run(); 9718 CHECK(value->IsNumber()); 9719 CHECK_EQ(10, value->Int32Value()); 9720 9721 value = v8_compile("other.unreachable")->Run(); 9722 CHECK(value.IsEmpty()); 9723 9724 context1->Exit(); 9725 context0->Exit(); 9726 } 9727 9728 9729 static int named_access_count = 0; 9730 static int indexed_access_count = 0; 9731 9732 static bool NamedAccessCounter(Local<v8::Object> global, 9733 Local<Value> name, 9734 v8::AccessType type, 9735 Local<Value> data) { 9736 named_access_count++; 9737 return true; 9738 } 9739 9740 9741 static bool IndexedAccessCounter(Local<v8::Object> global, 9742 uint32_t key, 9743 v8::AccessType type, 9744 Local<Value> data) { 9745 indexed_access_count++; 9746 return true; 9747 } 9748 9749 9750 // This one is too easily disturbed by other tests. 9751 TEST(AccessControlIC) { 9752 named_access_count = 0; 9753 indexed_access_count = 0; 9754 9755 v8::Isolate* isolate = CcTest::isolate(); 9756 v8::HandleScope handle_scope(isolate); 9757 9758 // Create an environment. 9759 v8::Local<Context> context0 = Context::New(isolate); 9760 context0->Enter(); 9761 9762 // Create an object that requires access-check functions to be 9763 // called for cross-domain access. 9764 v8::Handle<v8::ObjectTemplate> object_template = 9765 v8::ObjectTemplate::New(isolate); 9766 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9767 IndexedAccessCounter); 9768 Local<v8::Object> object = object_template->NewInstance(); 9769 9770 v8::HandleScope scope1(isolate); 9771 9772 // Create another environment. 9773 v8::Local<Context> context1 = Context::New(isolate); 9774 context1->Enter(); 9775 9776 // Make easy access to the object from the other environment. 9777 v8::Handle<v8::Object> global1 = context1->Global(); 9778 global1->Set(v8_str("obj"), object); 9779 9780 v8::Handle<Value> value; 9781 9782 // Check that the named access-control function is called every time. 9783 CompileRun("function testProp(obj) {" 9784 " for (var i = 0; i < 10; i++) obj.prop = 1;" 9785 " for (var j = 0; j < 10; j++) obj.prop;" 9786 " return obj.prop" 9787 "}"); 9788 value = CompileRun("testProp(obj)"); 9789 CHECK(value->IsNumber()); 9790 CHECK_EQ(1, value->Int32Value()); 9791 CHECK_EQ(21, named_access_count); 9792 9793 // Check that the named access-control function is called every time. 9794 CompileRun("var p = 'prop';" 9795 "function testKeyed(obj) {" 9796 " for (var i = 0; i < 10; i++) obj[p] = 1;" 9797 " for (var j = 0; j < 10; j++) obj[p];" 9798 " return obj[p];" 9799 "}"); 9800 // Use obj which requires access checks. No inline caching is used 9801 // in that case. 9802 value = CompileRun("testKeyed(obj)"); 9803 CHECK(value->IsNumber()); 9804 CHECK_EQ(1, value->Int32Value()); 9805 CHECK_EQ(42, named_access_count); 9806 // Force the inline caches into generic state and try again. 9807 CompileRun("testKeyed({ a: 0 })"); 9808 CompileRun("testKeyed({ b: 0 })"); 9809 value = CompileRun("testKeyed(obj)"); 9810 CHECK(value->IsNumber()); 9811 CHECK_EQ(1, value->Int32Value()); 9812 CHECK_EQ(63, named_access_count); 9813 9814 // Check that the indexed access-control function is called every time. 9815 CompileRun("function testIndexed(obj) {" 9816 " for (var i = 0; i < 10; i++) obj[0] = 1;" 9817 " for (var j = 0; j < 10; j++) obj[0];" 9818 " return obj[0]" 9819 "}"); 9820 value = CompileRun("testIndexed(obj)"); 9821 CHECK(value->IsNumber()); 9822 CHECK_EQ(1, value->Int32Value()); 9823 CHECK_EQ(21, indexed_access_count); 9824 // Force the inline caches into generic state. 9825 CompileRun("testIndexed(new Array(1))"); 9826 // Test that the indexed access check is called. 9827 value = CompileRun("testIndexed(obj)"); 9828 CHECK(value->IsNumber()); 9829 CHECK_EQ(1, value->Int32Value()); 9830 CHECK_EQ(42, indexed_access_count); 9831 9832 // Check that the named access check is called when invoking 9833 // functions on an object that requires access checks. 9834 CompileRun("obj.f = function() {}"); 9835 CompileRun("function testCallNormal(obj) {" 9836 " for (var i = 0; i < 10; i++) obj.f();" 9837 "}"); 9838 CompileRun("testCallNormal(obj)"); 9839 CHECK_EQ(74, named_access_count); 9840 9841 // Force obj into slow case. 9842 value = CompileRun("delete obj.prop"); 9843 CHECK(value->BooleanValue()); 9844 // Force inline caches into dictionary probing mode. 9845 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 9846 // Test that the named access check is called. 9847 value = CompileRun("testProp(obj);"); 9848 CHECK(value->IsNumber()); 9849 CHECK_EQ(1, value->Int32Value()); 9850 CHECK_EQ(96, named_access_count); 9851 9852 // Force the call inline cache into dictionary probing mode. 9853 CompileRun("o.f = function() {}; testCallNormal(o)"); 9854 // Test that the named access check is still called for each 9855 // invocation of the function. 9856 value = CompileRun("testCallNormal(obj)"); 9857 CHECK_EQ(106, named_access_count); 9858 9859 context1->Exit(); 9860 context0->Exit(); 9861 } 9862 9863 9864 static bool NamedAccessFlatten(Local<v8::Object> global, 9865 Local<Value> name, 9866 v8::AccessType type, 9867 Local<Value> data) { 9868 char buf[100]; 9869 int len; 9870 9871 CHECK(name->IsString()); 9872 9873 memset(buf, 0x1, sizeof(buf)); 9874 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 9875 CHECK_EQ(4, len); 9876 9877 uint16_t buf2[100]; 9878 9879 memset(buf, 0x1, sizeof(buf)); 9880 len = name.As<String>()->Write(buf2); 9881 CHECK_EQ(4, len); 9882 9883 return true; 9884 } 9885 9886 9887 static bool IndexedAccessFlatten(Local<v8::Object> global, 9888 uint32_t key, 9889 v8::AccessType type, 9890 Local<Value> data) { 9891 return true; 9892 } 9893 9894 9895 // Regression test. In access checks, operations that may cause 9896 // garbage collection are not allowed. It used to be the case that 9897 // using the Write operation on a string could cause a garbage 9898 // collection due to flattening of the string. This is no longer the 9899 // case. 9900 THREADED_TEST(AccessControlFlatten) { 9901 named_access_count = 0; 9902 indexed_access_count = 0; 9903 9904 v8::Isolate* isolate = CcTest::isolate(); 9905 v8::HandleScope handle_scope(isolate); 9906 9907 // Create an environment. 9908 v8::Local<Context> context0 = Context::New(isolate); 9909 context0->Enter(); 9910 9911 // Create an object that requires access-check functions to be 9912 // called for cross-domain access. 9913 v8::Handle<v8::ObjectTemplate> object_template = 9914 v8::ObjectTemplate::New(isolate); 9915 object_template->SetAccessCheckCallbacks(NamedAccessFlatten, 9916 IndexedAccessFlatten); 9917 Local<v8::Object> object = object_template->NewInstance(); 9918 9919 v8::HandleScope scope1(isolate); 9920 9921 // Create another environment. 9922 v8::Local<Context> context1 = Context::New(isolate); 9923 context1->Enter(); 9924 9925 // Make easy access to the object from the other environment. 9926 v8::Handle<v8::Object> global1 = context1->Global(); 9927 global1->Set(v8_str("obj"), object); 9928 9929 v8::Handle<Value> value; 9930 9931 value = v8_compile("var p = 'as' + 'df';")->Run(); 9932 value = v8_compile("obj[p];")->Run(); 9933 9934 context1->Exit(); 9935 context0->Exit(); 9936 } 9937 9938 9939 static void AccessControlNamedGetter( 9940 Local<String>, 9941 const v8::PropertyCallbackInfo<v8::Value>& info) { 9942 info.GetReturnValue().Set(42); 9943 } 9944 9945 9946 static void AccessControlNamedSetter( 9947 Local<String>, 9948 Local<Value> value, 9949 const v8::PropertyCallbackInfo<v8::Value>& info) { 9950 info.GetReturnValue().Set(value); 9951 } 9952 9953 9954 static void AccessControlIndexedGetter( 9955 uint32_t index, 9956 const v8::PropertyCallbackInfo<v8::Value>& info) { 9957 info.GetReturnValue().Set(v8_num(42)); 9958 } 9959 9960 9961 static void AccessControlIndexedSetter( 9962 uint32_t, 9963 Local<Value> value, 9964 const v8::PropertyCallbackInfo<v8::Value>& info) { 9965 info.GetReturnValue().Set(value); 9966 } 9967 9968 9969 THREADED_TEST(AccessControlInterceptorIC) { 9970 named_access_count = 0; 9971 indexed_access_count = 0; 9972 9973 v8::Isolate* isolate = CcTest::isolate(); 9974 v8::HandleScope handle_scope(isolate); 9975 9976 // Create an environment. 9977 v8::Local<Context> context0 = Context::New(isolate); 9978 context0->Enter(); 9979 9980 // Create an object that requires access-check functions to be 9981 // called for cross-domain access. The object also has interceptors 9982 // interceptor. 9983 v8::Handle<v8::ObjectTemplate> object_template = 9984 v8::ObjectTemplate::New(isolate); 9985 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9986 IndexedAccessCounter); 9987 object_template->SetNamedPropertyHandler(AccessControlNamedGetter, 9988 AccessControlNamedSetter); 9989 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter, 9990 AccessControlIndexedSetter); 9991 Local<v8::Object> object = object_template->NewInstance(); 9992 9993 v8::HandleScope scope1(isolate); 9994 9995 // Create another environment. 9996 v8::Local<Context> context1 = Context::New(isolate); 9997 context1->Enter(); 9998 9999 // Make easy access to the object from the other environment. 10000 v8::Handle<v8::Object> global1 = context1->Global(); 10001 global1->Set(v8_str("obj"), object); 10002 10003 v8::Handle<Value> value; 10004 10005 // Check that the named access-control function is called every time 10006 // eventhough there is an interceptor on the object. 10007 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run(); 10008 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;" 10009 "obj.x")->Run(); 10010 CHECK(value->IsNumber()); 10011 CHECK_EQ(42, value->Int32Value()); 10012 CHECK_EQ(21, named_access_count); 10013 10014 value = v8_compile("var p = 'x';")->Run(); 10015 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run(); 10016 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];" 10017 "obj[p]")->Run(); 10018 CHECK(value->IsNumber()); 10019 CHECK_EQ(42, value->Int32Value()); 10020 CHECK_EQ(42, named_access_count); 10021 10022 // Check that the indexed access-control function is called every 10023 // time eventhough there is an interceptor on the object. 10024 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run(); 10025 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];" 10026 "obj[0]")->Run(); 10027 CHECK(value->IsNumber()); 10028 CHECK_EQ(42, value->Int32Value()); 10029 CHECK_EQ(21, indexed_access_count); 10030 10031 context1->Exit(); 10032 context0->Exit(); 10033 } 10034 10035 10036 THREADED_TEST(Version) { 10037 v8::V8::GetVersion(); 10038 } 10039 10040 10041 static void InstanceFunctionCallback( 10042 const v8::FunctionCallbackInfo<v8::Value>& args) { 10043 ApiTestFuzzer::Fuzz(); 10044 args.GetReturnValue().Set(v8_num(12)); 10045 } 10046 10047 10048 THREADED_TEST(InstanceProperties) { 10049 LocalContext context; 10050 v8::Isolate* isolate = context->GetIsolate(); 10051 v8::HandleScope handle_scope(isolate); 10052 10053 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10054 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10055 10056 instance->Set(v8_str("x"), v8_num(42)); 10057 instance->Set(v8_str("f"), 10058 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback)); 10059 10060 Local<Value> o = t->GetFunction()->NewInstance(); 10061 10062 context->Global()->Set(v8_str("i"), o); 10063 Local<Value> value = CompileRun("i.x"); 10064 CHECK_EQ(42, value->Int32Value()); 10065 10066 value = CompileRun("i.f()"); 10067 CHECK_EQ(12, value->Int32Value()); 10068 } 10069 10070 10071 static void GlobalObjectInstancePropertiesGet( 10072 Local<String> key, 10073 const v8::PropertyCallbackInfo<v8::Value>&) { 10074 ApiTestFuzzer::Fuzz(); 10075 } 10076 10077 10078 THREADED_TEST(GlobalObjectInstanceProperties) { 10079 v8::Isolate* isolate = CcTest::isolate(); 10080 v8::HandleScope handle_scope(isolate); 10081 10082 Local<Value> global_object; 10083 10084 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10085 t->InstanceTemplate()->SetNamedPropertyHandler( 10086 GlobalObjectInstancePropertiesGet); 10087 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10088 instance_template->Set(v8_str("x"), v8_num(42)); 10089 instance_template->Set(v8_str("f"), 10090 v8::FunctionTemplate::New(isolate, 10091 InstanceFunctionCallback)); 10092 10093 // The script to check how Crankshaft compiles missing global function 10094 // invocations. function g is not defined and should throw on call. 10095 const char* script = 10096 "function wrapper(call) {" 10097 " var x = 0, y = 1;" 10098 " for (var i = 0; i < 1000; i++) {" 10099 " x += i * 100;" 10100 " y += i * 100;" 10101 " }" 10102 " if (call) g();" 10103 "}" 10104 "for (var i = 0; i < 17; i++) wrapper(false);" 10105 "var thrown = 0;" 10106 "try { wrapper(true); } catch (e) { thrown = 1; };" 10107 "thrown"; 10108 10109 { 10110 LocalContext env(NULL, instance_template); 10111 // Hold on to the global object so it can be used again in another 10112 // environment initialization. 10113 global_object = env->Global(); 10114 10115 Local<Value> value = CompileRun("x"); 10116 CHECK_EQ(42, value->Int32Value()); 10117 value = CompileRun("f()"); 10118 CHECK_EQ(12, value->Int32Value()); 10119 value = CompileRun(script); 10120 CHECK_EQ(1, value->Int32Value()); 10121 } 10122 10123 { 10124 // Create new environment reusing the global object. 10125 LocalContext env(NULL, instance_template, global_object); 10126 Local<Value> value = CompileRun("x"); 10127 CHECK_EQ(42, value->Int32Value()); 10128 value = CompileRun("f()"); 10129 CHECK_EQ(12, value->Int32Value()); 10130 value = CompileRun(script); 10131 CHECK_EQ(1, value->Int32Value()); 10132 } 10133 } 10134 10135 10136 THREADED_TEST(CallKnownGlobalReceiver) { 10137 v8::Isolate* isolate = CcTest::isolate(); 10138 v8::HandleScope handle_scope(isolate); 10139 10140 Local<Value> global_object; 10141 10142 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10143 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10144 10145 // The script to check that we leave global object not 10146 // global object proxy on stack when we deoptimize from inside 10147 // arguments evaluation. 10148 // To provoke error we need to both force deoptimization 10149 // from arguments evaluation and to force CallIC to take 10150 // CallIC_Miss code path that can't cope with global proxy. 10151 const char* script = 10152 "function bar(x, y) { try { } finally { } }" 10153 "function baz(x) { try { } finally { } }" 10154 "function bom(x) { try { } finally { } }" 10155 "function foo(x) { bar([x], bom(2)); }" 10156 "for (var i = 0; i < 10000; i++) foo(1);" 10157 "foo"; 10158 10159 Local<Value> foo; 10160 { 10161 LocalContext env(NULL, instance_template); 10162 // Hold on to the global object so it can be used again in another 10163 // environment initialization. 10164 global_object = env->Global(); 10165 foo = CompileRun(script); 10166 } 10167 10168 { 10169 // Create new environment reusing the global object. 10170 LocalContext env(NULL, instance_template, global_object); 10171 env->Global()->Set(v8_str("foo"), foo); 10172 CompileRun("foo()"); 10173 } 10174 } 10175 10176 10177 static void ShadowFunctionCallback( 10178 const v8::FunctionCallbackInfo<v8::Value>& args) { 10179 ApiTestFuzzer::Fuzz(); 10180 args.GetReturnValue().Set(v8_num(42)); 10181 } 10182 10183 10184 static int shadow_y; 10185 static int shadow_y_setter_call_count; 10186 static int shadow_y_getter_call_count; 10187 10188 10189 static void ShadowYSetter(Local<String>, 10190 Local<Value>, 10191 const v8::PropertyCallbackInfo<void>&) { 10192 shadow_y_setter_call_count++; 10193 shadow_y = 42; 10194 } 10195 10196 10197 static void ShadowYGetter(Local<String> name, 10198 const v8::PropertyCallbackInfo<v8::Value>& info) { 10199 ApiTestFuzzer::Fuzz(); 10200 shadow_y_getter_call_count++; 10201 info.GetReturnValue().Set(v8_num(shadow_y)); 10202 } 10203 10204 10205 static void ShadowIndexedGet(uint32_t index, 10206 const v8::PropertyCallbackInfo<v8::Value>&) { 10207 } 10208 10209 10210 static void ShadowNamedGet(Local<String> key, 10211 const v8::PropertyCallbackInfo<v8::Value>&) { 10212 } 10213 10214 10215 THREADED_TEST(ShadowObject) { 10216 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 10217 v8::Isolate* isolate = CcTest::isolate(); 10218 v8::HandleScope handle_scope(isolate); 10219 10220 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); 10221 LocalContext context(NULL, global_template); 10222 10223 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10224 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet); 10225 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet); 10226 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 10227 Local<ObjectTemplate> instance = t->InstanceTemplate(); 10228 10229 proto->Set(v8_str("f"), 10230 v8::FunctionTemplate::New(isolate, 10231 ShadowFunctionCallback, 10232 Local<Value>())); 10233 proto->Set(v8_str("x"), v8_num(12)); 10234 10235 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 10236 10237 Local<Value> o = t->GetFunction()->NewInstance(); 10238 context->Global()->Set(v8_str("__proto__"), o); 10239 10240 Local<Value> value = 10241 CompileRun("this.propertyIsEnumerable(0)"); 10242 CHECK(value->IsBoolean()); 10243 CHECK(!value->BooleanValue()); 10244 10245 value = CompileRun("x"); 10246 CHECK_EQ(12, value->Int32Value()); 10247 10248 value = CompileRun("f()"); 10249 CHECK_EQ(42, value->Int32Value()); 10250 10251 CompileRun("y = 43"); 10252 CHECK_EQ(1, shadow_y_setter_call_count); 10253 value = CompileRun("y"); 10254 CHECK_EQ(1, shadow_y_getter_call_count); 10255 CHECK_EQ(42, value->Int32Value()); 10256 } 10257 10258 10259 THREADED_TEST(HiddenPrototype) { 10260 LocalContext context; 10261 v8::Isolate* isolate = context->GetIsolate(); 10262 v8::HandleScope handle_scope(isolate); 10263 10264 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10265 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10266 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10267 t1->SetHiddenPrototype(true); 10268 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10269 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10270 t2->SetHiddenPrototype(true); 10271 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10272 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10273 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10274 10275 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 10276 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10277 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10278 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10279 10280 // Setting the prototype on an object skips hidden prototypes. 10281 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10282 o0->Set(v8_str("__proto__"), o1); 10283 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10284 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10285 o0->Set(v8_str("__proto__"), o2); 10286 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10287 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10288 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10289 o0->Set(v8_str("__proto__"), o3); 10290 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10291 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10292 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10293 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 10294 10295 // Getting the prototype of o0 should get the first visible one 10296 // which is o3. Therefore, z should not be defined on the prototype 10297 // object. 10298 Local<Value> proto = o0->Get(v8_str("__proto__")); 10299 CHECK(proto->IsObject()); 10300 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined()); 10301 } 10302 10303 10304 THREADED_TEST(HiddenPrototypeSet) { 10305 LocalContext context; 10306 v8::Isolate* isolate = context->GetIsolate(); 10307 v8::HandleScope handle_scope(isolate); 10308 10309 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate); 10310 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate); 10311 ht->SetHiddenPrototype(true); 10312 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate); 10313 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10314 10315 Local<v8::Object> o = ot->GetFunction()->NewInstance(); 10316 Local<v8::Object> h = ht->GetFunction()->NewInstance(); 10317 Local<v8::Object> p = pt->GetFunction()->NewInstance(); 10318 o->Set(v8_str("__proto__"), h); 10319 h->Set(v8_str("__proto__"), p); 10320 10321 // Setting a property that exists on the hidden prototype goes there. 10322 o->Set(v8_str("x"), v8_num(7)); 10323 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value()); 10324 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value()); 10325 CHECK(p->Get(v8_str("x"))->IsUndefined()); 10326 10327 // Setting a new property should not be forwarded to the hidden prototype. 10328 o->Set(v8_str("y"), v8_num(6)); 10329 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value()); 10330 CHECK(h->Get(v8_str("y"))->IsUndefined()); 10331 CHECK(p->Get(v8_str("y"))->IsUndefined()); 10332 10333 // Setting a property that only exists on a prototype of the hidden prototype 10334 // is treated normally again. 10335 p->Set(v8_str("z"), v8_num(8)); 10336 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value()); 10337 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 10338 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 10339 o->Set(v8_str("z"), v8_num(9)); 10340 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value()); 10341 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 10342 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 10343 } 10344 10345 10346 // Regression test for issue 2457. 10347 THREADED_TEST(HiddenPrototypeIdentityHash) { 10348 LocalContext context; 10349 v8::HandleScope handle_scope(context->GetIsolate()); 10350 10351 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate()); 10352 t->SetHiddenPrototype(true); 10353 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 10354 Handle<Object> p = t->GetFunction()->NewInstance(); 10355 Handle<Object> o = Object::New(context->GetIsolate()); 10356 o->SetPrototype(p); 10357 10358 int hash = o->GetIdentityHash(); 10359 USE(hash); 10360 o->Set(v8_str("foo"), v8_num(42)); 10361 DCHECK_EQ(hash, o->GetIdentityHash()); 10362 } 10363 10364 10365 THREADED_TEST(SetPrototype) { 10366 LocalContext context; 10367 v8::Isolate* isolate = context->GetIsolate(); 10368 v8::HandleScope handle_scope(isolate); 10369 10370 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate); 10371 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 10372 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10373 t1->SetHiddenPrototype(true); 10374 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 10375 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10376 t2->SetHiddenPrototype(true); 10377 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 10378 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10379 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 10380 10381 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 10382 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10383 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10384 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10385 10386 // Setting the prototype on an object does not skip hidden prototypes. 10387 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10388 CHECK(o0->SetPrototype(o1)); 10389 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10390 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10391 CHECK(o1->SetPrototype(o2)); 10392 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10393 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10394 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10395 CHECK(o2->SetPrototype(o3)); 10396 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 10397 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 10398 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 10399 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 10400 10401 // Getting the prototype of o0 should get the first visible one 10402 // which is o3. Therefore, z should not be defined on the prototype 10403 // object. 10404 Local<Value> proto = o0->Get(v8_str("__proto__")); 10405 CHECK(proto->IsObject()); 10406 CHECK_EQ(proto.As<v8::Object>(), o3); 10407 10408 // However, Object::GetPrototype ignores hidden prototype. 10409 Local<Value> proto0 = o0->GetPrototype(); 10410 CHECK(proto0->IsObject()); 10411 CHECK_EQ(proto0.As<v8::Object>(), o1); 10412 10413 Local<Value> proto1 = o1->GetPrototype(); 10414 CHECK(proto1->IsObject()); 10415 CHECK_EQ(proto1.As<v8::Object>(), o2); 10416 10417 Local<Value> proto2 = o2->GetPrototype(); 10418 CHECK(proto2->IsObject()); 10419 CHECK_EQ(proto2.As<v8::Object>(), o3); 10420 } 10421 10422 10423 // Getting property names of an object with a prototype chain that 10424 // triggers dictionary elements in GetOwnPropertyNames() shouldn't 10425 // crash the runtime. 10426 THREADED_TEST(Regress91517) { 10427 i::FLAG_allow_natives_syntax = true; 10428 LocalContext context; 10429 v8::Isolate* isolate = context->GetIsolate(); 10430 v8::HandleScope handle_scope(isolate); 10431 10432 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10433 t1->SetHiddenPrototype(true); 10434 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 10435 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10436 t2->SetHiddenPrototype(true); 10437 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 10438 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate)); 10439 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 10440 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); 10441 t3->SetHiddenPrototype(true); 10442 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 10443 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate); 10444 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 10445 10446 // Force dictionary-based properties. 10447 i::ScopedVector<char> name_buf(1024); 10448 for (int i = 1; i <= 1000; i++) { 10449 i::SNPrintF(name_buf, "sdf%d", i); 10450 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 10451 } 10452 10453 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10454 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10455 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 10456 Local<v8::Object> o4 = t4->GetFunction()->NewInstance(); 10457 10458 // Create prototype chain of hidden prototypes. 10459 CHECK(o4->SetPrototype(o3)); 10460 CHECK(o3->SetPrototype(o2)); 10461 CHECK(o2->SetPrototype(o1)); 10462 10463 // Call the runtime version of GetOwnPropertyNames() on the natively 10464 // created object through JavaScript. 10465 context->Global()->Set(v8_str("obj"), o4); 10466 // PROPERTY_ATTRIBUTES_NONE = 0 10467 CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); 10468 10469 ExpectInt32("names.length", 1006); 10470 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10471 ExpectTrue("names.indexOf(\"boo\") >= 0"); 10472 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10473 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 10474 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 10475 ExpectFalse("names[1005] == undefined"); 10476 } 10477 10478 10479 // Getting property names of an object with a hidden and inherited 10480 // prototype should not duplicate the accessor properties inherited. 10481 THREADED_TEST(Regress269562) { 10482 i::FLAG_allow_natives_syntax = true; 10483 LocalContext context; 10484 v8::HandleScope handle_scope(context->GetIsolate()); 10485 10486 Local<v8::FunctionTemplate> t1 = 10487 v8::FunctionTemplate::New(context->GetIsolate()); 10488 t1->SetHiddenPrototype(true); 10489 10490 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate(); 10491 i1->SetAccessor(v8_str("foo"), 10492 SimpleAccessorGetter, SimpleAccessorSetter); 10493 i1->SetAccessor(v8_str("bar"), 10494 SimpleAccessorGetter, SimpleAccessorSetter); 10495 i1->SetAccessor(v8_str("baz"), 10496 SimpleAccessorGetter, SimpleAccessorSetter); 10497 i1->Set(v8_str("n1"), v8_num(1)); 10498 i1->Set(v8_str("n2"), v8_num(2)); 10499 10500 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 10501 Local<v8::FunctionTemplate> t2 = 10502 v8::FunctionTemplate::New(context->GetIsolate()); 10503 t2->SetHiddenPrototype(true); 10504 10505 // Inherit from t1 and mark prototype as hidden. 10506 t2->Inherit(t1); 10507 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4)); 10508 10509 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 10510 CHECK(o2->SetPrototype(o1)); 10511 10512 v8::Local<v8::Symbol> sym = 10513 v8::Symbol::New(context->GetIsolate(), v8_str("s1")); 10514 o1->Set(sym, v8_num(3)); 10515 o1->SetHiddenValue( 10516 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013)); 10517 10518 // Call the runtime version of GetOwnPropertyNames() on 10519 // the natively created object through JavaScript. 10520 context->Global()->Set(v8_str("obj"), o2); 10521 context->Global()->Set(v8_str("sym"), sym); 10522 // PROPERTY_ATTRIBUTES_NONE = 0 10523 CompileRun("var names = %GetOwnPropertyNames(obj, 0);"); 10524 10525 ExpectInt32("names.length", 7); 10526 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10527 ExpectTrue("names.indexOf(\"bar\") >= 0"); 10528 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10529 ExpectTrue("names.indexOf(\"n1\") >= 0"); 10530 ExpectTrue("names.indexOf(\"n2\") >= 0"); 10531 ExpectTrue("names.indexOf(sym) >= 0"); 10532 ExpectTrue("names.indexOf(\"mine\") >= 0"); 10533 } 10534 10535 10536 THREADED_TEST(FunctionReadOnlyPrototype) { 10537 LocalContext context; 10538 v8::Isolate* isolate = context->GetIsolate(); 10539 v8::HandleScope handle_scope(isolate); 10540 10541 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10542 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10543 t1->ReadOnlyPrototype(); 10544 context->Global()->Set(v8_str("func1"), t1->GetFunction()); 10545 // Configured value of ReadOnly flag. 10546 CHECK(CompileRun( 10547 "(function() {" 10548 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 10549 " return (descriptor['writable'] == false);" 10550 "})()")->BooleanValue()); 10551 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value()); 10552 CHECK_EQ(42, 10553 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value()); 10554 10555 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); 10556 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42)); 10557 context->Global()->Set(v8_str("func2"), t2->GetFunction()); 10558 // Default value of ReadOnly flag. 10559 CHECK(CompileRun( 10560 "(function() {" 10561 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 10562 " return (descriptor['writable'] == true);" 10563 "})()")->BooleanValue()); 10564 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value()); 10565 } 10566 10567 10568 THREADED_TEST(SetPrototypeThrows) { 10569 LocalContext context; 10570 v8::Isolate* isolate = context->GetIsolate(); 10571 v8::HandleScope handle_scope(isolate); 10572 10573 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 10574 10575 Local<v8::Object> o0 = t->GetFunction()->NewInstance(); 10576 Local<v8::Object> o1 = t->GetFunction()->NewInstance(); 10577 10578 CHECK(o0->SetPrototype(o1)); 10579 // If setting the prototype leads to the cycle, SetPrototype should 10580 // return false and keep VM in sane state. 10581 v8::TryCatch try_catch; 10582 CHECK(!o1->SetPrototype(o0)); 10583 CHECK(!try_catch.HasCaught()); 10584 DCHECK(!CcTest::i_isolate()->has_pending_exception()); 10585 10586 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); 10587 } 10588 10589 10590 THREADED_TEST(FunctionRemovePrototype) { 10591 LocalContext context; 10592 v8::Isolate* isolate = context->GetIsolate(); 10593 v8::HandleScope handle_scope(isolate); 10594 10595 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate); 10596 t1->RemovePrototype(); 10597 Local<v8::Function> fun = t1->GetFunction(); 10598 context->Global()->Set(v8_str("fun"), fun); 10599 CHECK(!CompileRun("'prototype' in fun")->BooleanValue()); 10600 10601 v8::TryCatch try_catch; 10602 CompileRun("new fun()"); 10603 CHECK(try_catch.HasCaught()); 10604 10605 try_catch.Reset(); 10606 fun->NewInstance(); 10607 CHECK(try_catch.HasCaught()); 10608 } 10609 10610 10611 THREADED_TEST(GetterSetterExceptions) { 10612 LocalContext context; 10613 v8::Isolate* isolate = context->GetIsolate(); 10614 v8::HandleScope handle_scope(isolate); 10615 CompileRun( 10616 "function Foo() { };" 10617 "function Throw() { throw 5; };" 10618 "var x = { };" 10619 "x.__defineSetter__('set', Throw);" 10620 "x.__defineGetter__('get', Throw);"); 10621 Local<v8::Object> x = 10622 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); 10623 v8::TryCatch try_catch; 10624 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10625 x->Get(v8_str("get")); 10626 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10627 x->Get(v8_str("get")); 10628 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10629 x->Get(v8_str("get")); 10630 x->Set(v8_str("set"), v8::Integer::New(isolate, 8)); 10631 x->Get(v8_str("get")); 10632 } 10633 10634 10635 THREADED_TEST(Constructor) { 10636 LocalContext context; 10637 v8::Isolate* isolate = context->GetIsolate(); 10638 v8::HandleScope handle_scope(isolate); 10639 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 10640 templ->SetClassName(v8_str("Fun")); 10641 Local<Function> cons = templ->GetFunction(); 10642 context->Global()->Set(v8_str("Fun"), cons); 10643 Local<v8::Object> inst = cons->NewInstance(); 10644 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst)); 10645 CHECK(obj->IsJSObject()); 10646 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 10647 CHECK(value->BooleanValue()); 10648 } 10649 10650 10651 static void ConstructorCallback( 10652 const v8::FunctionCallbackInfo<v8::Value>& args) { 10653 ApiTestFuzzer::Fuzz(); 10654 Local<Object> This; 10655 10656 if (args.IsConstructCall()) { 10657 Local<Object> Holder = args.Holder(); 10658 This = Object::New(args.GetIsolate()); 10659 Local<Value> proto = Holder->GetPrototype(); 10660 if (proto->IsObject()) { 10661 This->SetPrototype(proto); 10662 } 10663 } else { 10664 This = args.This(); 10665 } 10666 10667 This->Set(v8_str("a"), args[0]); 10668 args.GetReturnValue().Set(This); 10669 } 10670 10671 10672 static void FakeConstructorCallback( 10673 const v8::FunctionCallbackInfo<v8::Value>& args) { 10674 ApiTestFuzzer::Fuzz(); 10675 args.GetReturnValue().Set(args[0]); 10676 } 10677 10678 10679 THREADED_TEST(ConstructorForObject) { 10680 LocalContext context; 10681 v8::Isolate* isolate = context->GetIsolate(); 10682 v8::HandleScope handle_scope(isolate); 10683 10684 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10685 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 10686 Local<Object> instance = instance_template->NewInstance(); 10687 context->Global()->Set(v8_str("obj"), instance); 10688 v8::TryCatch try_catch; 10689 Local<Value> value; 10690 CHECK(!try_catch.HasCaught()); 10691 10692 // Call the Object's constructor with a 32-bit signed integer. 10693 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 10694 CHECK(!try_catch.HasCaught()); 10695 CHECK(value->IsInt32()); 10696 CHECK_EQ(28, value->Int32Value()); 10697 10698 Local<Value> args1[] = { v8_num(28) }; 10699 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); 10700 CHECK(value_obj1->IsObject()); 10701 Local<Object> object1 = Local<Object>::Cast(value_obj1); 10702 value = object1->Get(v8_str("a")); 10703 CHECK(value->IsInt32()); 10704 CHECK(!try_catch.HasCaught()); 10705 CHECK_EQ(28, value->Int32Value()); 10706 10707 // Call the Object's constructor with a String. 10708 value = CompileRun( 10709 "(function() { var o = new obj('tipli'); return o.a; })()"); 10710 CHECK(!try_catch.HasCaught()); 10711 CHECK(value->IsString()); 10712 String::Utf8Value string_value1(value->ToString()); 10713 CHECK_EQ("tipli", *string_value1); 10714 10715 Local<Value> args2[] = { v8_str("tipli") }; 10716 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); 10717 CHECK(value_obj2->IsObject()); 10718 Local<Object> object2 = Local<Object>::Cast(value_obj2); 10719 value = object2->Get(v8_str("a")); 10720 CHECK(!try_catch.HasCaught()); 10721 CHECK(value->IsString()); 10722 String::Utf8Value string_value2(value->ToString()); 10723 CHECK_EQ("tipli", *string_value2); 10724 10725 // Call the Object's constructor with a Boolean. 10726 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 10727 CHECK(!try_catch.HasCaught()); 10728 CHECK(value->IsBoolean()); 10729 CHECK_EQ(true, value->BooleanValue()); 10730 10731 Handle<Value> args3[] = { v8::True(isolate) }; 10732 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); 10733 CHECK(value_obj3->IsObject()); 10734 Local<Object> object3 = Local<Object>::Cast(value_obj3); 10735 value = object3->Get(v8_str("a")); 10736 CHECK(!try_catch.HasCaught()); 10737 CHECK(value->IsBoolean()); 10738 CHECK_EQ(true, value->BooleanValue()); 10739 10740 // Call the Object's constructor with undefined. 10741 Handle<Value> args4[] = { v8::Undefined(isolate) }; 10742 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); 10743 CHECK(value_obj4->IsObject()); 10744 Local<Object> object4 = Local<Object>::Cast(value_obj4); 10745 value = object4->Get(v8_str("a")); 10746 CHECK(!try_catch.HasCaught()); 10747 CHECK(value->IsUndefined()); 10748 10749 // Call the Object's constructor with null. 10750 Handle<Value> args5[] = { v8::Null(isolate) }; 10751 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); 10752 CHECK(value_obj5->IsObject()); 10753 Local<Object> object5 = Local<Object>::Cast(value_obj5); 10754 value = object5->Get(v8_str("a")); 10755 CHECK(!try_catch.HasCaught()); 10756 CHECK(value->IsNull()); 10757 } 10758 10759 // Check exception handling when there is no constructor set for the Object. 10760 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10761 Local<Object> instance = instance_template->NewInstance(); 10762 context->Global()->Set(v8_str("obj2"), instance); 10763 v8::TryCatch try_catch; 10764 Local<Value> value; 10765 CHECK(!try_catch.HasCaught()); 10766 10767 value = CompileRun("new obj2(28)"); 10768 CHECK(try_catch.HasCaught()); 10769 String::Utf8Value exception_value1(try_catch.Exception()); 10770 CHECK_EQ("TypeError: object is not a function", *exception_value1); 10771 try_catch.Reset(); 10772 10773 Local<Value> args[] = { v8_num(29) }; 10774 value = instance->CallAsConstructor(1, args); 10775 CHECK(try_catch.HasCaught()); 10776 String::Utf8Value exception_value2(try_catch.Exception()); 10777 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); 10778 try_catch.Reset(); 10779 } 10780 10781 // Check the case when constructor throws exception. 10782 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10783 instance_template->SetCallAsFunctionHandler(ThrowValue); 10784 Local<Object> instance = instance_template->NewInstance(); 10785 context->Global()->Set(v8_str("obj3"), instance); 10786 v8::TryCatch try_catch; 10787 Local<Value> value; 10788 CHECK(!try_catch.HasCaught()); 10789 10790 value = CompileRun("new obj3(22)"); 10791 CHECK(try_catch.HasCaught()); 10792 String::Utf8Value exception_value1(try_catch.Exception()); 10793 CHECK_EQ("22", *exception_value1); 10794 try_catch.Reset(); 10795 10796 Local<Value> args[] = { v8_num(23) }; 10797 value = instance->CallAsConstructor(1, args); 10798 CHECK(try_catch.HasCaught()); 10799 String::Utf8Value exception_value2(try_catch.Exception()); 10800 CHECK_EQ("23", *exception_value2); 10801 try_catch.Reset(); 10802 } 10803 10804 // Check whether constructor returns with an object or non-object. 10805 { Local<FunctionTemplate> function_template = 10806 FunctionTemplate::New(isolate, FakeConstructorCallback); 10807 Local<Function> function = function_template->GetFunction(); 10808 Local<Object> instance1 = function; 10809 context->Global()->Set(v8_str("obj4"), instance1); 10810 v8::TryCatch try_catch; 10811 Local<Value> value; 10812 CHECK(!try_catch.HasCaught()); 10813 10814 CHECK(instance1->IsObject()); 10815 CHECK(instance1->IsFunction()); 10816 10817 value = CompileRun("new obj4(28)"); 10818 CHECK(!try_catch.HasCaught()); 10819 CHECK(value->IsObject()); 10820 10821 Local<Value> args1[] = { v8_num(28) }; 10822 value = instance1->CallAsConstructor(1, args1); 10823 CHECK(!try_catch.HasCaught()); 10824 CHECK(value->IsObject()); 10825 10826 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 10827 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 10828 Local<Object> instance2 = instance_template->NewInstance(); 10829 context->Global()->Set(v8_str("obj5"), instance2); 10830 CHECK(!try_catch.HasCaught()); 10831 10832 CHECK(instance2->IsObject()); 10833 CHECK(!instance2->IsFunction()); 10834 10835 value = CompileRun("new obj5(28)"); 10836 CHECK(!try_catch.HasCaught()); 10837 CHECK(!value->IsObject()); 10838 10839 Local<Value> args2[] = { v8_num(28) }; 10840 value = instance2->CallAsConstructor(1, args2); 10841 CHECK(!try_catch.HasCaught()); 10842 CHECK(!value->IsObject()); 10843 } 10844 } 10845 10846 10847 THREADED_TEST(FunctionDescriptorException) { 10848 LocalContext context; 10849 v8::Isolate* isolate = context->GetIsolate(); 10850 v8::HandleScope handle_scope(isolate); 10851 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 10852 templ->SetClassName(v8_str("Fun")); 10853 Local<Function> cons = templ->GetFunction(); 10854 context->Global()->Set(v8_str("Fun"), cons); 10855 Local<Value> value = CompileRun( 10856 "function test() {" 10857 " try {" 10858 " (new Fun()).blah()" 10859 " } catch (e) {" 10860 " var str = String(e);" 10861 // " if (str.indexOf('TypeError') == -1) return 1;" 10862 // " if (str.indexOf('[object Fun]') != -1) return 2;" 10863 // " if (str.indexOf('#<Fun>') == -1) return 3;" 10864 " return 0;" 10865 " }" 10866 " return 4;" 10867 "}" 10868 "test();"); 10869 CHECK_EQ(0, value->Int32Value()); 10870 } 10871 10872 10873 THREADED_TEST(EvalAliasedDynamic) { 10874 LocalContext current; 10875 v8::HandleScope scope(current->GetIsolate()); 10876 10877 // Tests where aliased eval can only be resolved dynamically. 10878 Local<Script> script = v8_compile( 10879 "function f(x) { " 10880 " var foo = 2;" 10881 " with (x) { return eval('foo'); }" 10882 "}" 10883 "foo = 0;" 10884 "result1 = f(new Object());" 10885 "result2 = f(this);" 10886 "var x = new Object();" 10887 "x.eval = function(x) { return 1; };" 10888 "result3 = f(x);"); 10889 script->Run(); 10890 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value()); 10891 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); 10892 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); 10893 10894 v8::TryCatch try_catch; 10895 script = v8_compile( 10896 "function f(x) { " 10897 " var bar = 2;" 10898 " with (x) { return eval('bar'); }" 10899 "}" 10900 "result4 = f(this)"); 10901 script->Run(); 10902 CHECK(!try_catch.HasCaught()); 10903 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value()); 10904 10905 try_catch.Reset(); 10906 } 10907 10908 10909 THREADED_TEST(CrossEval) { 10910 v8::HandleScope scope(CcTest::isolate()); 10911 LocalContext other; 10912 LocalContext current; 10913 10914 Local<String> token = v8_str("<security token>"); 10915 other->SetSecurityToken(token); 10916 current->SetSecurityToken(token); 10917 10918 // Set up reference from current to other. 10919 current->Global()->Set(v8_str("other"), other->Global()); 10920 10921 // Check that new variables are introduced in other context. 10922 Local<Script> script = v8_compile("other.eval('var foo = 1234')"); 10923 script->Run(); 10924 Local<Value> foo = other->Global()->Get(v8_str("foo")); 10925 CHECK_EQ(1234, foo->Int32Value()); 10926 CHECK(!current->Global()->Has(v8_str("foo"))); 10927 10928 // Check that writing to non-existing properties introduces them in 10929 // the other context. 10930 script = v8_compile("other.eval('na = 1234')"); 10931 script->Run(); 10932 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value()); 10933 CHECK(!current->Global()->Has(v8_str("na"))); 10934 10935 // Check that global variables in current context are not visible in other 10936 // context. 10937 v8::TryCatch try_catch; 10938 script = v8_compile("var bar = 42; other.eval('bar');"); 10939 Local<Value> result = script->Run(); 10940 CHECK(try_catch.HasCaught()); 10941 try_catch.Reset(); 10942 10943 // Check that local variables in current context are not visible in other 10944 // context. 10945 script = v8_compile( 10946 "(function() { " 10947 " var baz = 87;" 10948 " return other.eval('baz');" 10949 "})();"); 10950 result = script->Run(); 10951 CHECK(try_catch.HasCaught()); 10952 try_catch.Reset(); 10953 10954 // Check that global variables in the other environment are visible 10955 // when evaluting code. 10956 other->Global()->Set(v8_str("bis"), v8_num(1234)); 10957 script = v8_compile("other.eval('bis')"); 10958 CHECK_EQ(1234, script->Run()->Int32Value()); 10959 CHECK(!try_catch.HasCaught()); 10960 10961 // Check that the 'this' pointer points to the global object evaluating 10962 // code. 10963 other->Global()->Set(v8_str("t"), other->Global()); 10964 script = v8_compile("other.eval('this == t')"); 10965 result = script->Run(); 10966 CHECK(result->IsTrue()); 10967 CHECK(!try_catch.HasCaught()); 10968 10969 // Check that variables introduced in with-statement are not visible in 10970 // other context. 10971 script = v8_compile("with({x:2}){other.eval('x')}"); 10972 result = script->Run(); 10973 CHECK(try_catch.HasCaught()); 10974 try_catch.Reset(); 10975 10976 // Check that you cannot use 'eval.call' with another object than the 10977 // current global object. 10978 script = v8_compile("other.y = 1; eval.call(other, 'y')"); 10979 result = script->Run(); 10980 CHECK(try_catch.HasCaught()); 10981 } 10982 10983 10984 // Test that calling eval in a context which has been detached from 10985 // its global throws an exception. This behavior is consistent with 10986 // other JavaScript implementations. 10987 THREADED_TEST(EvalInDetachedGlobal) { 10988 v8::Isolate* isolate = CcTest::isolate(); 10989 v8::HandleScope scope(isolate); 10990 10991 v8::Local<Context> context0 = Context::New(isolate); 10992 v8::Local<Context> context1 = Context::New(isolate); 10993 10994 // Set up function in context0 that uses eval from context0. 10995 context0->Enter(); 10996 v8::Handle<v8::Value> fun = 10997 CompileRun("var x = 42;" 10998 "(function() {" 10999 " var e = eval;" 11000 " return function(s) { return e(s); }" 11001 "})()"); 11002 context0->Exit(); 11003 11004 // Put the function into context1 and call it before and after 11005 // detaching the global. Before detaching, the call succeeds and 11006 // after detaching and exception is thrown. 11007 context1->Enter(); 11008 context1->Global()->Set(v8_str("fun"), fun); 11009 v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); 11010 CHECK_EQ(42, x_value->Int32Value()); 11011 context0->DetachGlobal(); 11012 v8::TryCatch catcher; 11013 x_value = CompileRun("fun('x')"); 11014 CHECK(x_value.IsEmpty()); 11015 CHECK(catcher.HasCaught()); 11016 context1->Exit(); 11017 } 11018 11019 11020 THREADED_TEST(CrossLazyLoad) { 11021 v8::HandleScope scope(CcTest::isolate()); 11022 LocalContext other; 11023 LocalContext current; 11024 11025 Local<String> token = v8_str("<security token>"); 11026 other->SetSecurityToken(token); 11027 current->SetSecurityToken(token); 11028 11029 // Set up reference from current to other. 11030 current->Global()->Set(v8_str("other"), other->Global()); 11031 11032 // Trigger lazy loading in other context. 11033 Local<Script> script = v8_compile("other.eval('new Date(42)')"); 11034 Local<Value> value = script->Run(); 11035 CHECK_EQ(42.0, value->NumberValue()); 11036 } 11037 11038 11039 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 11040 ApiTestFuzzer::Fuzz(); 11041 if (args.IsConstructCall()) { 11042 if (args[0]->IsInt32()) { 11043 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value())); 11044 return; 11045 } 11046 } 11047 11048 args.GetReturnValue().Set(args[0]); 11049 } 11050 11051 11052 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 11053 args.GetReturnValue().Set(args.This()); 11054 } 11055 11056 11057 // Test that a call handler can be set for objects which will allow 11058 // non-function objects created through the API to be called as 11059 // functions. 11060 THREADED_TEST(CallAsFunction) { 11061 LocalContext context; 11062 v8::Isolate* isolate = context->GetIsolate(); 11063 v8::HandleScope scope(isolate); 11064 11065 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11066 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11067 instance_template->SetCallAsFunctionHandler(call_as_function); 11068 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11069 context->Global()->Set(v8_str("obj"), instance); 11070 v8::TryCatch try_catch; 11071 Local<Value> value; 11072 CHECK(!try_catch.HasCaught()); 11073 11074 value = CompileRun("obj(42)"); 11075 CHECK(!try_catch.HasCaught()); 11076 CHECK_EQ(42, value->Int32Value()); 11077 11078 value = CompileRun("(function(o){return o(49)})(obj)"); 11079 CHECK(!try_catch.HasCaught()); 11080 CHECK_EQ(49, value->Int32Value()); 11081 11082 // test special case of call as function 11083 value = CompileRun("[obj]['0'](45)"); 11084 CHECK(!try_catch.HasCaught()); 11085 CHECK_EQ(45, value->Int32Value()); 11086 11087 value = CompileRun("obj.call = Function.prototype.call;" 11088 "obj.call(null, 87)"); 11089 CHECK(!try_catch.HasCaught()); 11090 CHECK_EQ(87, value->Int32Value()); 11091 11092 // Regression tests for bug #1116356: Calling call through call/apply 11093 // must work for non-function receivers. 11094 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 11095 value = CompileRun(apply_99); 11096 CHECK(!try_catch.HasCaught()); 11097 CHECK_EQ(99, value->Int32Value()); 11098 11099 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 11100 value = CompileRun(call_17); 11101 CHECK(!try_catch.HasCaught()); 11102 CHECK_EQ(17, value->Int32Value()); 11103 11104 // Check that the call-as-function handler can be called through 11105 // new. 11106 value = CompileRun("new obj(43)"); 11107 CHECK(!try_catch.HasCaught()); 11108 CHECK_EQ(-43, value->Int32Value()); 11109 11110 // Check that the call-as-function handler can be called through 11111 // the API. 11112 v8::Handle<Value> args[] = { v8_num(28) }; 11113 value = instance->CallAsFunction(instance, 1, args); 11114 CHECK(!try_catch.HasCaught()); 11115 CHECK_EQ(28, value->Int32Value()); 11116 } 11117 11118 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11119 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 11120 USE(instance_template); 11121 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11122 context->Global()->Set(v8_str("obj2"), instance); 11123 v8::TryCatch try_catch; 11124 Local<Value> value; 11125 CHECK(!try_catch.HasCaught()); 11126 11127 // Call an object without call-as-function handler through the JS 11128 value = CompileRun("obj2(28)"); 11129 CHECK(value.IsEmpty()); 11130 CHECK(try_catch.HasCaught()); 11131 String::Utf8Value exception_value1(try_catch.Exception()); 11132 // TODO(verwaest): Better message 11133 CHECK_EQ("TypeError: object is not a function", 11134 *exception_value1); 11135 try_catch.Reset(); 11136 11137 // Call an object without call-as-function handler through the API 11138 value = CompileRun("obj2(28)"); 11139 v8::Handle<Value> args[] = { v8_num(28) }; 11140 value = instance->CallAsFunction(instance, 1, args); 11141 CHECK(value.IsEmpty()); 11142 CHECK(try_catch.HasCaught()); 11143 String::Utf8Value exception_value2(try_catch.Exception()); 11144 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); 11145 try_catch.Reset(); 11146 } 11147 11148 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11149 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11150 instance_template->SetCallAsFunctionHandler(ThrowValue); 11151 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11152 context->Global()->Set(v8_str("obj3"), instance); 11153 v8::TryCatch try_catch; 11154 Local<Value> value; 11155 CHECK(!try_catch.HasCaught()); 11156 11157 // Catch the exception which is thrown by call-as-function handler 11158 value = CompileRun("obj3(22)"); 11159 CHECK(try_catch.HasCaught()); 11160 String::Utf8Value exception_value1(try_catch.Exception()); 11161 CHECK_EQ("22", *exception_value1); 11162 try_catch.Reset(); 11163 11164 v8::Handle<Value> args[] = { v8_num(23) }; 11165 value = instance->CallAsFunction(instance, 1, args); 11166 CHECK(try_catch.HasCaught()); 11167 String::Utf8Value exception_value2(try_catch.Exception()); 11168 CHECK_EQ("23", *exception_value2); 11169 try_catch.Reset(); 11170 } 11171 11172 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate); 11173 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 11174 instance_template->SetCallAsFunctionHandler(ReturnThis); 11175 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 11176 11177 Local<v8::Value> a1 = 11178 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11179 CHECK(a1->StrictEquals(instance)); 11180 Local<v8::Value> a2 = 11181 instance->CallAsFunction(v8::Null(isolate), 0, NULL); 11182 CHECK(a2->StrictEquals(instance)); 11183 Local<v8::Value> a3 = 11184 instance->CallAsFunction(v8_num(42), 0, NULL); 11185 CHECK(a3->StrictEquals(instance)); 11186 Local<v8::Value> a4 = 11187 instance->CallAsFunction(v8_str("hello"), 0, NULL); 11188 CHECK(a4->StrictEquals(instance)); 11189 Local<v8::Value> a5 = 11190 instance->CallAsFunction(v8::True(isolate), 0, NULL); 11191 CHECK(a5->StrictEquals(instance)); 11192 } 11193 11194 { CompileRun( 11195 "function ReturnThisSloppy() {" 11196 " return this;" 11197 "}" 11198 "function ReturnThisStrict() {" 11199 " 'use strict';" 11200 " return this;" 11201 "}"); 11202 Local<Function> ReturnThisSloppy = 11203 Local<Function>::Cast( 11204 context->Global()->Get(v8_str("ReturnThisSloppy"))); 11205 Local<Function> ReturnThisStrict = 11206 Local<Function>::Cast( 11207 context->Global()->Get(v8_str("ReturnThisStrict"))); 11208 11209 Local<v8::Value> a1 = 11210 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11211 CHECK(a1->StrictEquals(context->Global())); 11212 Local<v8::Value> a2 = 11213 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL); 11214 CHECK(a2->StrictEquals(context->Global())); 11215 Local<v8::Value> a3 = 11216 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL); 11217 CHECK(a3->IsNumberObject()); 11218 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf()); 11219 Local<v8::Value> a4 = 11220 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL); 11221 CHECK(a4->IsStringObject()); 11222 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 11223 Local<v8::Value> a5 = 11224 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL); 11225 CHECK(a5->IsBooleanObject()); 11226 CHECK(a5.As<v8::BooleanObject>()->ValueOf()); 11227 11228 Local<v8::Value> a6 = 11229 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL); 11230 CHECK(a6->IsUndefined()); 11231 Local<v8::Value> a7 = 11232 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL); 11233 CHECK(a7->IsNull()); 11234 Local<v8::Value> a8 = 11235 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL); 11236 CHECK(a8->StrictEquals(v8_num(42))); 11237 Local<v8::Value> a9 = 11238 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL); 11239 CHECK(a9->StrictEquals(v8_str("hello"))); 11240 Local<v8::Value> a10 = 11241 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL); 11242 CHECK(a10->StrictEquals(v8::True(isolate))); 11243 } 11244 } 11245 11246 11247 // Check whether a non-function object is callable. 11248 THREADED_TEST(CallableObject) { 11249 LocalContext context; 11250 v8::Isolate* isolate = context->GetIsolate(); 11251 v8::HandleScope scope(isolate); 11252 11253 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11254 instance_template->SetCallAsFunctionHandler(call_as_function); 11255 Local<Object> instance = instance_template->NewInstance(); 11256 v8::TryCatch try_catch; 11257 11258 CHECK(instance->IsCallable()); 11259 CHECK(!try_catch.HasCaught()); 11260 } 11261 11262 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate); 11263 Local<Object> instance = instance_template->NewInstance(); 11264 v8::TryCatch try_catch; 11265 11266 CHECK(!instance->IsCallable()); 11267 CHECK(!try_catch.HasCaught()); 11268 } 11269 11270 { Local<FunctionTemplate> function_template = 11271 FunctionTemplate::New(isolate, call_as_function); 11272 Local<Function> function = function_template->GetFunction(); 11273 Local<Object> instance = function; 11274 v8::TryCatch try_catch; 11275 11276 CHECK(instance->IsCallable()); 11277 CHECK(!try_catch.HasCaught()); 11278 } 11279 11280 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate); 11281 Local<Function> function = function_template->GetFunction(); 11282 Local<Object> instance = function; 11283 v8::TryCatch try_catch; 11284 11285 CHECK(instance->IsCallable()); 11286 CHECK(!try_catch.HasCaught()); 11287 } 11288 } 11289 11290 11291 static int Recurse(v8::Isolate* isolate, int depth, int iterations) { 11292 v8::HandleScope scope(isolate); 11293 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate); 11294 for (int i = 0; i < iterations; i++) { 11295 Local<v8::Number> n(v8::Integer::New(isolate, 42)); 11296 } 11297 return Recurse(isolate, depth - 1, iterations); 11298 } 11299 11300 11301 THREADED_TEST(HandleIteration) { 11302 static const int kIterations = 500; 11303 static const int kNesting = 200; 11304 LocalContext context; 11305 v8::Isolate* isolate = context->GetIsolate(); 11306 v8::HandleScope scope0(isolate); 11307 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11308 { 11309 v8::HandleScope scope1(isolate); 11310 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11311 for (int i = 0; i < kIterations; i++) { 11312 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11313 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate)); 11314 } 11315 11316 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11317 { 11318 v8::HandleScope scope2(CcTest::isolate()); 11319 for (int j = 0; j < kIterations; j++) { 11320 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42)); 11321 CHECK_EQ(j + 1 + kIterations, 11322 v8::HandleScope::NumberOfHandles(isolate)); 11323 } 11324 } 11325 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate)); 11326 } 11327 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate)); 11328 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations)); 11329 } 11330 11331 11332 static void InterceptorHasOwnPropertyGetter( 11333 Local<String> name, 11334 const v8::PropertyCallbackInfo<v8::Value>& info) { 11335 ApiTestFuzzer::Fuzz(); 11336 } 11337 11338 11339 THREADED_TEST(InterceptorHasOwnProperty) { 11340 LocalContext context; 11341 v8::Isolate* isolate = context->GetIsolate(); 11342 v8::HandleScope scope(isolate); 11343 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 11344 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 11345 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter); 11346 Local<Function> function = fun_templ->GetFunction(); 11347 context->Global()->Set(v8_str("constructor"), function); 11348 v8::Handle<Value> value = CompileRun( 11349 "var o = new constructor();" 11350 "o.hasOwnProperty('ostehaps');"); 11351 CHECK_EQ(false, value->BooleanValue()); 11352 value = CompileRun( 11353 "o.ostehaps = 42;" 11354 "o.hasOwnProperty('ostehaps');"); 11355 CHECK_EQ(true, value->BooleanValue()); 11356 value = CompileRun( 11357 "var p = new constructor();" 11358 "p.hasOwnProperty('ostehaps');"); 11359 CHECK_EQ(false, value->BooleanValue()); 11360 } 11361 11362 11363 static void InterceptorHasOwnPropertyGetterGC( 11364 Local<String> name, 11365 const v8::PropertyCallbackInfo<v8::Value>& info) { 11366 ApiTestFuzzer::Fuzz(); 11367 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 11368 } 11369 11370 11371 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { 11372 LocalContext context; 11373 v8::Isolate* isolate = context->GetIsolate(); 11374 v8::HandleScope scope(isolate); 11375 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 11376 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 11377 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); 11378 Local<Function> function = fun_templ->GetFunction(); 11379 context->Global()->Set(v8_str("constructor"), function); 11380 // Let's first make some stuff so we can be sure to get a good GC. 11381 CompileRun( 11382 "function makestr(size) {" 11383 " switch (size) {" 11384 " case 1: return 'f';" 11385 " case 2: return 'fo';" 11386 " case 3: return 'foo';" 11387 " }" 11388 " return makestr(size >> 1) + makestr((size + 1) >> 1);" 11389 "}" 11390 "var x = makestr(12345);" 11391 "x = makestr(31415);" 11392 "x = makestr(23456);"); 11393 v8::Handle<Value> value = CompileRun( 11394 "var o = new constructor();" 11395 "o.__proto__ = new String(x);" 11396 "o.hasOwnProperty('ostehaps');"); 11397 CHECK_EQ(false, value->BooleanValue()); 11398 } 11399 11400 11401 typedef void (*NamedPropertyGetter)( 11402 Local<String> property, 11403 const v8::PropertyCallbackInfo<v8::Value>& info); 11404 11405 11406 static void CheckInterceptorLoadIC(NamedPropertyGetter getter, 11407 const char* source, 11408 int expected) { 11409 v8::Isolate* isolate = CcTest::isolate(); 11410 v8::HandleScope scope(isolate); 11411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11412 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data")); 11413 LocalContext context; 11414 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11415 v8::Handle<Value> value = CompileRun(source); 11416 CHECK_EQ(expected, value->Int32Value()); 11417 } 11418 11419 11420 static void InterceptorLoadICGetter( 11421 Local<String> name, 11422 const v8::PropertyCallbackInfo<v8::Value>& info) { 11423 ApiTestFuzzer::Fuzz(); 11424 v8::Isolate* isolate = CcTest::isolate(); 11425 CHECK_EQ(isolate, info.GetIsolate()); 11426 CHECK_EQ(v8_str("data"), info.Data()); 11427 CHECK_EQ(v8_str("x"), name); 11428 info.GetReturnValue().Set(v8::Integer::New(isolate, 42)); 11429 } 11430 11431 11432 // This test should hit the load IC for the interceptor case. 11433 THREADED_TEST(InterceptorLoadIC) { 11434 CheckInterceptorLoadIC(InterceptorLoadICGetter, 11435 "var result = 0;" 11436 "for (var i = 0; i < 1000; i++) {" 11437 " result = o.x;" 11438 "}", 11439 42); 11440 } 11441 11442 11443 // Below go several tests which verify that JITing for various 11444 // configurations of interceptor and explicit fields works fine 11445 // (those cases are special cased to get better performance). 11446 11447 static void InterceptorLoadXICGetter( 11448 Local<String> name, 11449 const v8::PropertyCallbackInfo<v8::Value>& info) { 11450 ApiTestFuzzer::Fuzz(); 11451 info.GetReturnValue().Set( 11452 v8_str("x")->Equals(name) ? 11453 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) : 11454 v8::Handle<v8::Value>()); 11455 } 11456 11457 11458 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { 11459 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11460 "var result = 0;" 11461 "o.y = 239;" 11462 "for (var i = 0; i < 1000; i++) {" 11463 " result = o.y;" 11464 "}", 11465 239); 11466 } 11467 11468 11469 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) { 11470 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11471 "var result = 0;" 11472 "o.__proto__ = { 'y': 239 };" 11473 "for (var i = 0; i < 1000; i++) {" 11474 " result = o.y + o.x;" 11475 "}", 11476 239 + 42); 11477 } 11478 11479 11480 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) { 11481 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11482 "var result = 0;" 11483 "o.__proto__.y = 239;" 11484 "for (var i = 0; i < 1000; i++) {" 11485 " result = o.y + o.x;" 11486 "}", 11487 239 + 42); 11488 } 11489 11490 11491 THREADED_TEST(InterceptorLoadICUndefined) { 11492 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11493 "var result = 0;" 11494 "for (var i = 0; i < 1000; i++) {" 11495 " result = (o.y == undefined) ? 239 : 42;" 11496 "}", 11497 239); 11498 } 11499 11500 11501 THREADED_TEST(InterceptorLoadICWithOverride) { 11502 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11503 "fst = new Object(); fst.__proto__ = o;" 11504 "snd = new Object(); snd.__proto__ = fst;" 11505 "var result1 = 0;" 11506 "for (var i = 0; i < 1000; i++) {" 11507 " result1 = snd.x;" 11508 "}" 11509 "fst.x = 239;" 11510 "var result = 0;" 11511 "for (var i = 0; i < 1000; i++) {" 11512 " result = snd.x;" 11513 "}" 11514 "result + result1", 11515 239 + 42); 11516 } 11517 11518 11519 // Test the case when we stored field into 11520 // a stub, but interceptor produced value on its own. 11521 THREADED_TEST(InterceptorLoadICFieldNotNeeded) { 11522 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11523 "proto = new Object();" 11524 "o.__proto__ = proto;" 11525 "proto.x = 239;" 11526 "for (var i = 0; i < 1000; i++) {" 11527 " o.x;" 11528 // Now it should be ICed and keep a reference to x defined on proto 11529 "}" 11530 "var result = 0;" 11531 "for (var i = 0; i < 1000; i++) {" 11532 " result += o.x;" 11533 "}" 11534 "result;", 11535 42 * 1000); 11536 } 11537 11538 11539 // Test the case when we stored field into 11540 // a stub, but it got invalidated later on. 11541 THREADED_TEST(InterceptorLoadICInvalidatedField) { 11542 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11543 "proto1 = new Object();" 11544 "proto2 = new Object();" 11545 "o.__proto__ = proto1;" 11546 "proto1.__proto__ = proto2;" 11547 "proto2.y = 239;" 11548 "for (var i = 0; i < 1000; i++) {" 11549 " o.y;" 11550 // Now it should be ICed and keep a reference to y defined on proto2 11551 "}" 11552 "proto1.y = 42;" 11553 "var result = 0;" 11554 "for (var i = 0; i < 1000; i++) {" 11555 " result += o.y;" 11556 "}" 11557 "result;", 11558 42 * 1000); 11559 } 11560 11561 11562 static int interceptor_load_not_handled_calls = 0; 11563 static void InterceptorLoadNotHandled( 11564 Local<String> name, 11565 const v8::PropertyCallbackInfo<v8::Value>& info) { 11566 ++interceptor_load_not_handled_calls; 11567 } 11568 11569 11570 // Test how post-interceptor lookups are done in the non-cacheable 11571 // case: the interceptor should not be invoked during this lookup. 11572 THREADED_TEST(InterceptorLoadICPostInterceptor) { 11573 interceptor_load_not_handled_calls = 0; 11574 CheckInterceptorLoadIC(InterceptorLoadNotHandled, 11575 "receiver = new Object();" 11576 "receiver.__proto__ = o;" 11577 "proto = new Object();" 11578 "/* Make proto a slow-case object. */" 11579 "for (var i = 0; i < 1000; i++) {" 11580 " proto[\"xxxxxxxx\" + i] = [];" 11581 "}" 11582 "proto.x = 17;" 11583 "o.__proto__ = proto;" 11584 "var result = 0;" 11585 "for (var i = 0; i < 1000; i++) {" 11586 " result += receiver.x;" 11587 "}" 11588 "result;", 11589 17 * 1000); 11590 CHECK_EQ(1000, interceptor_load_not_handled_calls); 11591 } 11592 11593 11594 // Test the case when we stored field into 11595 // a stub, but it got invalidated later on due to override on 11596 // global object which is between interceptor and fields' holders. 11597 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) { 11598 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11599 "o.__proto__ = this;" // set a global to be a proto of o. 11600 "this.__proto__.y = 239;" 11601 "for (var i = 0; i < 10; i++) {" 11602 " if (o.y != 239) throw 'oops: ' + o.y;" 11603 // Now it should be ICed and keep a reference to y defined on field_holder. 11604 "}" 11605 "this.y = 42;" // Assign on a global. 11606 "var result = 0;" 11607 "for (var i = 0; i < 10; i++) {" 11608 " result += o.y;" 11609 "}" 11610 "result;", 11611 42 * 10); 11612 } 11613 11614 11615 static void SetOnThis(Local<String> name, 11616 Local<Value> value, 11617 const v8::PropertyCallbackInfo<void>& info) { 11618 Local<Object>::Cast(info.This())->ForceSet(name, value); 11619 } 11620 11621 11622 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) { 11623 v8::Isolate* isolate = CcTest::isolate(); 11624 v8::HandleScope scope(isolate); 11625 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11626 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11627 templ->SetAccessor(v8_str("y"), Return239Callback); 11628 LocalContext context; 11629 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11630 11631 // Check the case when receiver and interceptor's holder 11632 // are the same objects. 11633 v8::Handle<Value> value = CompileRun( 11634 "var result = 0;" 11635 "for (var i = 0; i < 7; i++) {" 11636 " result = o.y;" 11637 "}"); 11638 CHECK_EQ(239, value->Int32Value()); 11639 11640 // Check the case when interceptor's holder is in proto chain 11641 // of receiver. 11642 value = CompileRun( 11643 "r = { __proto__: o };" 11644 "var result = 0;" 11645 "for (var i = 0; i < 7; i++) {" 11646 " result = r.y;" 11647 "}"); 11648 CHECK_EQ(239, value->Int32Value()); 11649 } 11650 11651 11652 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) { 11653 v8::Isolate* isolate = CcTest::isolate(); 11654 v8::HandleScope scope(isolate); 11655 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11656 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11657 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11658 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11659 11660 LocalContext context; 11661 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11662 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11663 11664 // Check the case when receiver and interceptor's holder 11665 // are the same objects. 11666 v8::Handle<Value> value = CompileRun( 11667 "o.__proto__ = p;" 11668 "var result = 0;" 11669 "for (var i = 0; i < 7; i++) {" 11670 " result = o.x + o.y;" 11671 "}"); 11672 CHECK_EQ(239 + 42, value->Int32Value()); 11673 11674 // Check the case when interceptor's holder is in proto chain 11675 // of receiver. 11676 value = CompileRun( 11677 "r = { __proto__: o };" 11678 "var result = 0;" 11679 "for (var i = 0; i < 7; i++) {" 11680 " result = r.x + r.y;" 11681 "}"); 11682 CHECK_EQ(239 + 42, value->Int32Value()); 11683 } 11684 11685 11686 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) { 11687 v8::Isolate* isolate = CcTest::isolate(); 11688 v8::HandleScope scope(isolate); 11689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11690 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11691 templ->SetAccessor(v8_str("y"), Return239Callback); 11692 11693 LocalContext context; 11694 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11695 11696 v8::Handle<Value> value = CompileRun( 11697 "fst = new Object(); fst.__proto__ = o;" 11698 "snd = new Object(); snd.__proto__ = fst;" 11699 "var result1 = 0;" 11700 "for (var i = 0; i < 7; i++) {" 11701 " result1 = snd.x;" 11702 "}" 11703 "fst.x = 239;" 11704 "var result = 0;" 11705 "for (var i = 0; i < 7; i++) {" 11706 " result = snd.x;" 11707 "}" 11708 "result + result1"); 11709 CHECK_EQ(239 + 42, value->Int32Value()); 11710 } 11711 11712 11713 // Test the case when we stored callback into 11714 // a stub, but interceptor produced value on its own. 11715 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) { 11716 v8::Isolate* isolate = CcTest::isolate(); 11717 v8::HandleScope scope(isolate); 11718 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11719 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11720 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11721 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11722 11723 LocalContext context; 11724 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11725 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11726 11727 v8::Handle<Value> value = CompileRun( 11728 "o.__proto__ = p;" 11729 "for (var i = 0; i < 7; i++) {" 11730 " o.x;" 11731 // Now it should be ICed and keep a reference to x defined on p 11732 "}" 11733 "var result = 0;" 11734 "for (var i = 0; i < 7; i++) {" 11735 " result += o.x;" 11736 "}" 11737 "result"); 11738 CHECK_EQ(42 * 7, value->Int32Value()); 11739 } 11740 11741 11742 // Test the case when we stored callback into 11743 // a stub, but it got invalidated later on. 11744 THREADED_TEST(InterceptorLoadICInvalidatedCallback) { 11745 v8::Isolate* isolate = CcTest::isolate(); 11746 v8::HandleScope scope(isolate); 11747 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11748 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11749 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11750 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11751 11752 LocalContext context; 11753 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11754 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11755 11756 v8::Handle<Value> value = CompileRun( 11757 "inbetween = new Object();" 11758 "o.__proto__ = inbetween;" 11759 "inbetween.__proto__ = p;" 11760 "for (var i = 0; i < 10; i++) {" 11761 " o.y;" 11762 // Now it should be ICed and keep a reference to y defined on p 11763 "}" 11764 "inbetween.y = 42;" 11765 "var result = 0;" 11766 "for (var i = 0; i < 10; i++) {" 11767 " result += o.y;" 11768 "}" 11769 "result"); 11770 CHECK_EQ(42 * 10, value->Int32Value()); 11771 } 11772 11773 11774 // Test the case when we stored callback into 11775 // a stub, but it got invalidated later on due to override on 11776 // global object which is between interceptor and callbacks' holders. 11777 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) { 11778 v8::Isolate* isolate = CcTest::isolate(); 11779 v8::HandleScope scope(isolate); 11780 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 11781 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11782 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate); 11783 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11784 11785 LocalContext context; 11786 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11787 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11788 11789 v8::Handle<Value> value = CompileRun( 11790 "o.__proto__ = this;" 11791 "this.__proto__ = p;" 11792 "for (var i = 0; i < 10; i++) {" 11793 " if (o.y != 239) throw 'oops: ' + o.y;" 11794 // Now it should be ICed and keep a reference to y defined on p 11795 "}" 11796 "this.y = 42;" 11797 "var result = 0;" 11798 "for (var i = 0; i < 10; i++) {" 11799 " result += o.y;" 11800 "}" 11801 "result"); 11802 CHECK_EQ(42 * 10, value->Int32Value()); 11803 } 11804 11805 11806 static void InterceptorLoadICGetter0( 11807 Local<String> name, 11808 const v8::PropertyCallbackInfo<v8::Value>& info) { 11809 ApiTestFuzzer::Fuzz(); 11810 CHECK(v8_str("x")->Equals(name)); 11811 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0)); 11812 } 11813 11814 11815 THREADED_TEST(InterceptorReturningZero) { 11816 CheckInterceptorLoadIC(InterceptorLoadICGetter0, 11817 "o.x == undefined ? 1 : 0", 11818 0); 11819 } 11820 11821 11822 static void InterceptorStoreICSetter( 11823 Local<String> key, 11824 Local<Value> value, 11825 const v8::PropertyCallbackInfo<v8::Value>& info) { 11826 CHECK(v8_str("x")->Equals(key)); 11827 CHECK_EQ(42, value->Int32Value()); 11828 info.GetReturnValue().Set(value); 11829 } 11830 11831 11832 // This test should hit the store IC for the interceptor case. 11833 THREADED_TEST(InterceptorStoreIC) { 11834 v8::Isolate* isolate = CcTest::isolate(); 11835 v8::HandleScope scope(isolate); 11836 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11837 templ->SetNamedPropertyHandler(InterceptorLoadICGetter, 11838 InterceptorStoreICSetter, 11839 0, 0, 0, v8_str("data")); 11840 LocalContext context; 11841 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11842 CompileRun( 11843 "for (var i = 0; i < 1000; i++) {" 11844 " o.x = 42;" 11845 "}"); 11846 } 11847 11848 11849 THREADED_TEST(InterceptorStoreICWithNoSetter) { 11850 v8::Isolate* isolate = CcTest::isolate(); 11851 v8::HandleScope scope(isolate); 11852 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11853 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11854 LocalContext context; 11855 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11856 v8::Handle<Value> value = CompileRun( 11857 "for (var i = 0; i < 1000; i++) {" 11858 " o.y = 239;" 11859 "}" 11860 "42 + o.y"); 11861 CHECK_EQ(239 + 42, value->Int32Value()); 11862 } 11863 11864 11865 11866 11867 v8::Handle<Value> call_ic_function; 11868 v8::Handle<Value> call_ic_function2; 11869 v8::Handle<Value> call_ic_function3; 11870 11871 static void InterceptorCallICGetter( 11872 Local<String> name, 11873 const v8::PropertyCallbackInfo<v8::Value>& info) { 11874 ApiTestFuzzer::Fuzz(); 11875 CHECK(v8_str("x")->Equals(name)); 11876 info.GetReturnValue().Set(call_ic_function); 11877 } 11878 11879 11880 // This test should hit the call IC for the interceptor case. 11881 THREADED_TEST(InterceptorCallIC) { 11882 v8::Isolate* isolate = CcTest::isolate(); 11883 v8::HandleScope scope(isolate); 11884 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11885 templ->SetNamedPropertyHandler(InterceptorCallICGetter); 11886 LocalContext context; 11887 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11888 call_ic_function = 11889 v8_compile("function f(x) { return x + 1; }; f")->Run(); 11890 v8::Handle<Value> value = CompileRun( 11891 "var result = 0;" 11892 "for (var i = 0; i < 1000; i++) {" 11893 " result = o.x(41);" 11894 "}"); 11895 CHECK_EQ(42, value->Int32Value()); 11896 } 11897 11898 11899 // This test checks that if interceptor doesn't provide 11900 // a value, we can fetch regular value. 11901 THREADED_TEST(InterceptorCallICSeesOthers) { 11902 v8::Isolate* isolate = CcTest::isolate(); 11903 v8::HandleScope scope(isolate); 11904 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11905 templ->SetNamedPropertyHandler(NoBlockGetterX); 11906 LocalContext context; 11907 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11908 v8::Handle<Value> value = CompileRun( 11909 "o.x = function f(x) { return x + 1; };" 11910 "var result = 0;" 11911 "for (var i = 0; i < 7; i++) {" 11912 " result = o.x(41);" 11913 "}"); 11914 CHECK_EQ(42, value->Int32Value()); 11915 } 11916 11917 11918 static v8::Handle<Value> call_ic_function4; 11919 static void InterceptorCallICGetter4( 11920 Local<String> name, 11921 const v8::PropertyCallbackInfo<v8::Value>& info) { 11922 ApiTestFuzzer::Fuzz(); 11923 CHECK(v8_str("x")->Equals(name)); 11924 info.GetReturnValue().Set(call_ic_function4); 11925 } 11926 11927 11928 // This test checks that if interceptor provides a function, 11929 // even if we cached shadowed variant, interceptor's function 11930 // is invoked 11931 THREADED_TEST(InterceptorCallICCacheableNotNeeded) { 11932 v8::Isolate* isolate = CcTest::isolate(); 11933 v8::HandleScope scope(isolate); 11934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11935 templ->SetNamedPropertyHandler(InterceptorCallICGetter4); 11936 LocalContext context; 11937 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11938 call_ic_function4 = 11939 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11940 v8::Handle<Value> value = CompileRun( 11941 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };" 11942 "var result = 0;" 11943 "for (var i = 0; i < 1000; i++) {" 11944 " result = o.x(42);" 11945 "}"); 11946 CHECK_EQ(41, value->Int32Value()); 11947 } 11948 11949 11950 // Test the case when we stored cacheable lookup into 11951 // a stub, but it got invalidated later on 11952 THREADED_TEST(InterceptorCallICInvalidatedCacheable) { 11953 v8::Isolate* isolate = CcTest::isolate(); 11954 v8::HandleScope scope(isolate); 11955 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11956 templ->SetNamedPropertyHandler(NoBlockGetterX); 11957 LocalContext context; 11958 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11959 v8::Handle<Value> value = CompileRun( 11960 "proto1 = new Object();" 11961 "proto2 = new Object();" 11962 "o.__proto__ = proto1;" 11963 "proto1.__proto__ = proto2;" 11964 "proto2.y = function(x) { return x + 1; };" 11965 // Invoke it many times to compile a stub 11966 "for (var i = 0; i < 7; i++) {" 11967 " o.y(42);" 11968 "}" 11969 "proto1.y = function(x) { return x - 1; };" 11970 "var result = 0;" 11971 "for (var i = 0; i < 7; i++) {" 11972 " result += o.y(42);" 11973 "}"); 11974 CHECK_EQ(41 * 7, value->Int32Value()); 11975 } 11976 11977 11978 // This test checks that if interceptor doesn't provide a function, 11979 // cached constant function is used 11980 THREADED_TEST(InterceptorCallICConstantFunctionUsed) { 11981 v8::Isolate* isolate = CcTest::isolate(); 11982 v8::HandleScope scope(isolate); 11983 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 11984 templ->SetNamedPropertyHandler(NoBlockGetterX); 11985 LocalContext context; 11986 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11987 v8::Handle<Value> value = CompileRun( 11988 "function inc(x) { return x + 1; };" 11989 "inc(1);" 11990 "o.x = inc;" 11991 "var result = 0;" 11992 "for (var i = 0; i < 1000; i++) {" 11993 " result = o.x(42);" 11994 "}"); 11995 CHECK_EQ(43, value->Int32Value()); 11996 } 11997 11998 11999 static v8::Handle<Value> call_ic_function5; 12000 static void InterceptorCallICGetter5( 12001 Local<String> name, 12002 const v8::PropertyCallbackInfo<v8::Value>& info) { 12003 ApiTestFuzzer::Fuzz(); 12004 if (v8_str("x")->Equals(name)) 12005 info.GetReturnValue().Set(call_ic_function5); 12006 } 12007 12008 12009 // This test checks that if interceptor provides a function, 12010 // even if we cached constant function, interceptor's function 12011 // is invoked 12012 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { 12013 v8::Isolate* isolate = CcTest::isolate(); 12014 v8::HandleScope scope(isolate); 12015 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12016 templ->SetNamedPropertyHandler(InterceptorCallICGetter5); 12017 LocalContext context; 12018 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12019 call_ic_function5 = 12020 v8_compile("function f(x) { return x - 1; }; f")->Run(); 12021 v8::Handle<Value> value = CompileRun( 12022 "function inc(x) { return x + 1; };" 12023 "inc(1);" 12024 "o.x = inc;" 12025 "var result = 0;" 12026 "for (var i = 0; i < 1000; i++) {" 12027 " result = o.x(42);" 12028 "}"); 12029 CHECK_EQ(41, value->Int32Value()); 12030 } 12031 12032 12033 static v8::Handle<Value> call_ic_function6; 12034 static void InterceptorCallICGetter6( 12035 Local<String> name, 12036 const v8::PropertyCallbackInfo<v8::Value>& info) { 12037 ApiTestFuzzer::Fuzz(); 12038 if (v8_str("x")->Equals(name)) 12039 info.GetReturnValue().Set(call_ic_function6); 12040 } 12041 12042 12043 // Same test as above, except the code is wrapped in a function 12044 // to test the optimized compiler. 12045 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) { 12046 i::FLAG_allow_natives_syntax = true; 12047 v8::Isolate* isolate = CcTest::isolate(); 12048 v8::HandleScope scope(isolate); 12049 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12050 templ->SetNamedPropertyHandler(InterceptorCallICGetter6); 12051 LocalContext context; 12052 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12053 call_ic_function6 = 12054 v8_compile("function f(x) { return x - 1; }; f")->Run(); 12055 v8::Handle<Value> value = CompileRun( 12056 "function inc(x) { return x + 1; };" 12057 "inc(1);" 12058 "o.x = inc;" 12059 "function test() {" 12060 " var result = 0;" 12061 " for (var i = 0; i < 1000; i++) {" 12062 " result = o.x(42);" 12063 " }" 12064 " return result;" 12065 "};" 12066 "test();" 12067 "test();" 12068 "test();" 12069 "%OptimizeFunctionOnNextCall(test);" 12070 "test()"); 12071 CHECK_EQ(41, value->Int32Value()); 12072 } 12073 12074 12075 // Test the case when we stored constant function into 12076 // a stub, but it got invalidated later on 12077 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { 12078 v8::Isolate* isolate = CcTest::isolate(); 12079 v8::HandleScope scope(isolate); 12080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12081 templ->SetNamedPropertyHandler(NoBlockGetterX); 12082 LocalContext context; 12083 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12084 v8::Handle<Value> value = CompileRun( 12085 "function inc(x) { return x + 1; };" 12086 "inc(1);" 12087 "proto1 = new Object();" 12088 "proto2 = new Object();" 12089 "o.__proto__ = proto1;" 12090 "proto1.__proto__ = proto2;" 12091 "proto2.y = inc;" 12092 // Invoke it many times to compile a stub 12093 "for (var i = 0; i < 7; i++) {" 12094 " o.y(42);" 12095 "}" 12096 "proto1.y = function(x) { return x - 1; };" 12097 "var result = 0;" 12098 "for (var i = 0; i < 7; i++) {" 12099 " result += o.y(42);" 12100 "}"); 12101 CHECK_EQ(41 * 7, value->Int32Value()); 12102 } 12103 12104 12105 // Test the case when we stored constant function into 12106 // a stub, but it got invalidated later on due to override on 12107 // global object which is between interceptor and constant function' holders. 12108 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) { 12109 v8::Isolate* isolate = CcTest::isolate(); 12110 v8::HandleScope scope(isolate); 12111 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12112 templ->SetNamedPropertyHandler(NoBlockGetterX); 12113 LocalContext context; 12114 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12115 v8::Handle<Value> value = CompileRun( 12116 "function inc(x) { return x + 1; };" 12117 "inc(1);" 12118 "o.__proto__ = this;" 12119 "this.__proto__.y = inc;" 12120 // Invoke it many times to compile a stub 12121 "for (var i = 0; i < 7; i++) {" 12122 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);" 12123 "}" 12124 "this.y = function(x) { return x - 1; };" 12125 "var result = 0;" 12126 "for (var i = 0; i < 7; i++) {" 12127 " result += o.y(42);" 12128 "}"); 12129 CHECK_EQ(41 * 7, value->Int32Value()); 12130 } 12131 12132 12133 // Test the case when actual function to call sits on global object. 12134 THREADED_TEST(InterceptorCallICCachedFromGlobal) { 12135 v8::Isolate* isolate = CcTest::isolate(); 12136 v8::HandleScope scope(isolate); 12137 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12138 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12139 12140 LocalContext context; 12141 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12142 12143 v8::Handle<Value> value = CompileRun( 12144 "try {" 12145 " o.__proto__ = this;" 12146 " for (var i = 0; i < 10; i++) {" 12147 " var v = o.parseFloat('239');" 12148 " if (v != 239) throw v;" 12149 // Now it should be ICed and keep a reference to parseFloat. 12150 " }" 12151 " var result = 0;" 12152 " for (var i = 0; i < 10; i++) {" 12153 " result += o.parseFloat('239');" 12154 " }" 12155 " result" 12156 "} catch(e) {" 12157 " e" 12158 "};"); 12159 CHECK_EQ(239 * 10, value->Int32Value()); 12160 } 12161 12162 static void InterceptorCallICFastApi( 12163 Local<String> name, 12164 const v8::PropertyCallbackInfo<v8::Value>& info) { 12165 ApiTestFuzzer::Fuzz(); 12166 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 12167 int* call_count = 12168 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 12169 ++(*call_count); 12170 if ((*call_count) % 20 == 0) { 12171 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 12172 } 12173 } 12174 12175 static void FastApiCallback_TrivialSignature( 12176 const v8::FunctionCallbackInfo<v8::Value>& args) { 12177 ApiTestFuzzer::Fuzz(); 12178 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 12179 v8::Isolate* isolate = CcTest::isolate(); 12180 CHECK_EQ(isolate, args.GetIsolate()); 12181 CHECK_EQ(args.This(), args.Holder()); 12182 CHECK(args.Data()->Equals(v8_str("method_data"))); 12183 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 12184 } 12185 12186 static void FastApiCallback_SimpleSignature( 12187 const v8::FunctionCallbackInfo<v8::Value>& args) { 12188 ApiTestFuzzer::Fuzz(); 12189 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 12190 v8::Isolate* isolate = CcTest::isolate(); 12191 CHECK_EQ(isolate, args.GetIsolate()); 12192 CHECK_EQ(args.This()->GetPrototype(), args.Holder()); 12193 CHECK(args.Data()->Equals(v8_str("method_data"))); 12194 // Note, we're using HasRealNamedProperty instead of Has to avoid 12195 // invoking the interceptor again. 12196 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo"))); 12197 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 12198 } 12199 12200 12201 // Helper to maximize the odds of object moving. 12202 static void GenerateSomeGarbage() { 12203 CompileRun( 12204 "var garbage;" 12205 "for (var i = 0; i < 1000; i++) {" 12206 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 12207 "}" 12208 "garbage = undefined;"); 12209 } 12210 12211 12212 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 12213 static int count = 0; 12214 if (count++ % 3 == 0) { 12215 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 12216 // This should move the stub 12217 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 12218 } 12219 } 12220 12221 12222 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 12223 LocalContext context; 12224 v8::Isolate* isolate = context->GetIsolate(); 12225 v8::HandleScope scope(isolate); 12226 v8::Handle<v8::ObjectTemplate> nativeobject_templ = 12227 v8::ObjectTemplate::New(isolate); 12228 nativeobject_templ->Set(isolate, "callback", 12229 v8::FunctionTemplate::New(isolate, 12230 DirectApiCallback)); 12231 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 12232 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 12233 // call the api function multiple times to ensure direct call stub creation. 12234 CompileRun( 12235 "function f() {" 12236 " for (var i = 1; i <= 30; i++) {" 12237 " nativeobject.callback();" 12238 " }" 12239 "}" 12240 "f();"); 12241 } 12242 12243 12244 void ThrowingDirectApiCallback( 12245 const v8::FunctionCallbackInfo<v8::Value>& args) { 12246 args.GetIsolate()->ThrowException(v8_str("g")); 12247 } 12248 12249 12250 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 12251 LocalContext context; 12252 v8::Isolate* isolate = context->GetIsolate(); 12253 v8::HandleScope scope(isolate); 12254 v8::Handle<v8::ObjectTemplate> nativeobject_templ = 12255 v8::ObjectTemplate::New(isolate); 12256 nativeobject_templ->Set(isolate, "callback", 12257 v8::FunctionTemplate::New(isolate, 12258 ThrowingDirectApiCallback)); 12259 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 12260 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 12261 // call the api function multiple times to ensure direct call stub creation. 12262 v8::Handle<Value> result = CompileRun( 12263 "var result = '';" 12264 "function f() {" 12265 " for (var i = 1; i <= 5; i++) {" 12266 " try { nativeobject.callback(); } catch (e) { result += e; }" 12267 " }" 12268 "}" 12269 "f(); result;"); 12270 CHECK_EQ(v8_str("ggggg"), result); 12271 } 12272 12273 12274 static Handle<Value> DoDirectGetter() { 12275 if (++p_getter_count % 3 == 0) { 12276 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 12277 GenerateSomeGarbage(); 12278 } 12279 return v8_str("Direct Getter Result"); 12280 } 12281 12282 static void DirectGetterCallback( 12283 Local<String> name, 12284 const v8::PropertyCallbackInfo<v8::Value>& info) { 12285 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 12286 info.GetReturnValue().Set(DoDirectGetter()); 12287 } 12288 12289 12290 template<typename Accessor> 12291 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 12292 LocalContext context; 12293 v8::Isolate* isolate = context->GetIsolate(); 12294 v8::HandleScope scope(isolate); 12295 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12296 obj->SetAccessor(v8_str("p1"), accessor); 12297 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 12298 p_getter_count = 0; 12299 v8::Handle<v8::Value> result = CompileRun( 12300 "function f() {" 12301 " for (var i = 0; i < 30; i++) o1.p1;" 12302 " return o1.p1" 12303 "}" 12304 "f();"); 12305 CHECK_EQ(v8_str("Direct Getter Result"), result); 12306 CHECK_EQ(31, p_getter_count); 12307 } 12308 12309 12310 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 12311 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 12312 } 12313 12314 12315 void ThrowingDirectGetterCallback( 12316 Local<String> name, 12317 const v8::PropertyCallbackInfo<v8::Value>& info) { 12318 info.GetIsolate()->ThrowException(v8_str("g")); 12319 } 12320 12321 12322 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 12323 LocalContext context; 12324 v8::Isolate* isolate = context->GetIsolate(); 12325 v8::HandleScope scope(isolate); 12326 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate); 12327 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 12328 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 12329 v8::Handle<Value> result = CompileRun( 12330 "var result = '';" 12331 "for (var i = 0; i < 5; i++) {" 12332 " try { o1.p1; } catch (e) { result += e; }" 12333 "}" 12334 "result;"); 12335 CHECK_EQ(v8_str("ggggg"), result); 12336 } 12337 12338 12339 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 12340 int interceptor_call_count = 0; 12341 v8::Isolate* isolate = CcTest::isolate(); 12342 v8::HandleScope scope(isolate); 12343 v8::Handle<v8::FunctionTemplate> fun_templ = 12344 v8::FunctionTemplate::New(isolate); 12345 v8::Handle<v8::FunctionTemplate> method_templ = 12346 v8::FunctionTemplate::New(isolate, 12347 FastApiCallback_TrivialSignature, 12348 v8_str("method_data"), 12349 v8::Handle<v8::Signature>()); 12350 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12351 proto_templ->Set(v8_str("method"), method_templ); 12352 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12353 templ->SetNamedPropertyHandler( 12354 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12355 v8::External::New(isolate, &interceptor_call_count)); 12356 LocalContext context; 12357 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12358 GenerateSomeGarbage(); 12359 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12360 CompileRun( 12361 "var result = 0;" 12362 "for (var i = 0; i < 100; i++) {" 12363 " result = o.method(41);" 12364 "}"); 12365 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12366 CHECK_EQ(100, interceptor_call_count); 12367 } 12368 12369 12370 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 12371 int interceptor_call_count = 0; 12372 v8::Isolate* isolate = CcTest::isolate(); 12373 v8::HandleScope scope(isolate); 12374 v8::Handle<v8::FunctionTemplate> fun_templ = 12375 v8::FunctionTemplate::New(isolate); 12376 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12377 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12378 v8::Signature::New(isolate, fun_templ)); 12379 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12380 proto_templ->Set(v8_str("method"), method_templ); 12381 fun_templ->SetHiddenPrototype(true); 12382 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12383 templ->SetNamedPropertyHandler( 12384 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12385 v8::External::New(isolate, &interceptor_call_count)); 12386 LocalContext context; 12387 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12388 GenerateSomeGarbage(); 12389 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12390 CompileRun( 12391 "o.foo = 17;" 12392 "var receiver = {};" 12393 "receiver.__proto__ = o;" 12394 "var result = 0;" 12395 "for (var i = 0; i < 100; i++) {" 12396 " result = receiver.method(41);" 12397 "}"); 12398 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12399 CHECK_EQ(100, interceptor_call_count); 12400 } 12401 12402 12403 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 12404 int interceptor_call_count = 0; 12405 v8::Isolate* isolate = CcTest::isolate(); 12406 v8::HandleScope scope(isolate); 12407 v8::Handle<v8::FunctionTemplate> fun_templ = 12408 v8::FunctionTemplate::New(isolate); 12409 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12410 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12411 v8::Signature::New(isolate, fun_templ)); 12412 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12413 proto_templ->Set(v8_str("method"), method_templ); 12414 fun_templ->SetHiddenPrototype(true); 12415 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12416 templ->SetNamedPropertyHandler( 12417 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12418 v8::External::New(isolate, &interceptor_call_count)); 12419 LocalContext context; 12420 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12421 GenerateSomeGarbage(); 12422 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12423 CompileRun( 12424 "o.foo = 17;" 12425 "var receiver = {};" 12426 "receiver.__proto__ = o;" 12427 "var result = 0;" 12428 "var saved_result = 0;" 12429 "for (var i = 0; i < 100; i++) {" 12430 " result = receiver.method(41);" 12431 " if (i == 50) {" 12432 " saved_result = result;" 12433 " receiver = {method: function(x) { return x - 1 }};" 12434 " }" 12435 "}"); 12436 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12437 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12438 CHECK_GE(interceptor_call_count, 50); 12439 } 12440 12441 12442 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 12443 int interceptor_call_count = 0; 12444 v8::Isolate* isolate = CcTest::isolate(); 12445 v8::HandleScope scope(isolate); 12446 v8::Handle<v8::FunctionTemplate> fun_templ = 12447 v8::FunctionTemplate::New(isolate); 12448 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12449 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12450 v8::Signature::New(isolate, fun_templ)); 12451 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12452 proto_templ->Set(v8_str("method"), method_templ); 12453 fun_templ->SetHiddenPrototype(true); 12454 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12455 templ->SetNamedPropertyHandler( 12456 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12457 v8::External::New(isolate, &interceptor_call_count)); 12458 LocalContext context; 12459 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12460 GenerateSomeGarbage(); 12461 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12462 CompileRun( 12463 "o.foo = 17;" 12464 "var receiver = {};" 12465 "receiver.__proto__ = o;" 12466 "var result = 0;" 12467 "var saved_result = 0;" 12468 "for (var i = 0; i < 100; i++) {" 12469 " result = receiver.method(41);" 12470 " if (i == 50) {" 12471 " saved_result = result;" 12472 " o.method = function(x) { return x - 1 };" 12473 " }" 12474 "}"); 12475 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12476 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12477 CHECK_GE(interceptor_call_count, 50); 12478 } 12479 12480 12481 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 12482 int interceptor_call_count = 0; 12483 v8::Isolate* isolate = CcTest::isolate(); 12484 v8::HandleScope scope(isolate); 12485 v8::Handle<v8::FunctionTemplate> fun_templ = 12486 v8::FunctionTemplate::New(isolate); 12487 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12488 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12489 v8::Signature::New(isolate, fun_templ)); 12490 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12491 proto_templ->Set(v8_str("method"), method_templ); 12492 fun_templ->SetHiddenPrototype(true); 12493 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12494 templ->SetNamedPropertyHandler( 12495 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12496 v8::External::New(isolate, &interceptor_call_count)); 12497 LocalContext context; 12498 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12499 GenerateSomeGarbage(); 12500 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12501 v8::TryCatch try_catch; 12502 CompileRun( 12503 "o.foo = 17;" 12504 "var receiver = {};" 12505 "receiver.__proto__ = o;" 12506 "var result = 0;" 12507 "var saved_result = 0;" 12508 "for (var i = 0; i < 100; i++) {" 12509 " result = receiver.method(41);" 12510 " if (i == 50) {" 12511 " saved_result = result;" 12512 " receiver = 333;" 12513 " }" 12514 "}"); 12515 CHECK(try_catch.HasCaught()); 12516 // TODO(verwaest): Adjust message. 12517 CHECK_EQ(v8_str("TypeError: undefined is not a function"), 12518 try_catch.Exception()->ToString()); 12519 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12520 CHECK_GE(interceptor_call_count, 50); 12521 } 12522 12523 12524 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 12525 int interceptor_call_count = 0; 12526 v8::Isolate* isolate = CcTest::isolate(); 12527 v8::HandleScope scope(isolate); 12528 v8::Handle<v8::FunctionTemplate> fun_templ = 12529 v8::FunctionTemplate::New(isolate); 12530 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12531 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12532 v8::Signature::New(isolate, fun_templ)); 12533 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12534 proto_templ->Set(v8_str("method"), method_templ); 12535 fun_templ->SetHiddenPrototype(true); 12536 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 12537 templ->SetNamedPropertyHandler( 12538 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 12539 v8::External::New(isolate, &interceptor_call_count)); 12540 LocalContext context; 12541 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12542 GenerateSomeGarbage(); 12543 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12544 v8::TryCatch try_catch; 12545 CompileRun( 12546 "o.foo = 17;" 12547 "var receiver = {};" 12548 "receiver.__proto__ = o;" 12549 "var result = 0;" 12550 "var saved_result = 0;" 12551 "for (var i = 0; i < 100; i++) {" 12552 " result = receiver.method(41);" 12553 " if (i == 50) {" 12554 " saved_result = result;" 12555 " receiver = {method: receiver.method};" 12556 " }" 12557 "}"); 12558 CHECK(try_catch.HasCaught()); 12559 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 12560 try_catch.Exception()->ToString()); 12561 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12562 CHECK_GE(interceptor_call_count, 50); 12563 } 12564 12565 12566 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 12567 v8::Isolate* isolate = CcTest::isolate(); 12568 v8::HandleScope scope(isolate); 12569 v8::Handle<v8::FunctionTemplate> fun_templ = 12570 v8::FunctionTemplate::New(isolate); 12571 v8::Handle<v8::FunctionTemplate> method_templ = 12572 v8::FunctionTemplate::New(isolate, 12573 FastApiCallback_TrivialSignature, 12574 v8_str("method_data"), 12575 v8::Handle<v8::Signature>()); 12576 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12577 proto_templ->Set(v8_str("method"), method_templ); 12578 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12579 USE(templ); 12580 LocalContext context; 12581 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12582 GenerateSomeGarbage(); 12583 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12584 CompileRun( 12585 "var result = 0;" 12586 "for (var i = 0; i < 100; i++) {" 12587 " result = o.method(41);" 12588 "}"); 12589 12590 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12591 } 12592 12593 12594 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 12595 v8::Isolate* isolate = CcTest::isolate(); 12596 v8::HandleScope scope(isolate); 12597 v8::Handle<v8::FunctionTemplate> fun_templ = 12598 v8::FunctionTemplate::New(isolate); 12599 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12600 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12601 v8::Signature::New(isolate, fun_templ)); 12602 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12603 proto_templ->Set(v8_str("method"), method_templ); 12604 fun_templ->SetHiddenPrototype(true); 12605 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12606 CHECK(!templ.IsEmpty()); 12607 LocalContext context; 12608 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12609 GenerateSomeGarbage(); 12610 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12611 CompileRun( 12612 "o.foo = 17;" 12613 "var receiver = {};" 12614 "receiver.__proto__ = o;" 12615 "var result = 0;" 12616 "for (var i = 0; i < 100; i++) {" 12617 " result = receiver.method(41);" 12618 "}"); 12619 12620 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12621 } 12622 12623 12624 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 12625 v8::Isolate* isolate = CcTest::isolate(); 12626 v8::HandleScope scope(isolate); 12627 v8::Handle<v8::FunctionTemplate> fun_templ = 12628 v8::FunctionTemplate::New(isolate); 12629 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12630 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12631 v8::Signature::New(isolate, fun_templ)); 12632 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12633 proto_templ->Set(v8_str("method"), method_templ); 12634 fun_templ->SetHiddenPrototype(true); 12635 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12636 CHECK(!templ.IsEmpty()); 12637 LocalContext context; 12638 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12639 GenerateSomeGarbage(); 12640 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12641 CompileRun( 12642 "o.foo = 17;" 12643 "var receiver = {};" 12644 "receiver.__proto__ = o;" 12645 "var result = 0;" 12646 "var saved_result = 0;" 12647 "for (var i = 0; i < 100; i++) {" 12648 " result = receiver.method(41);" 12649 " if (i == 50) {" 12650 " saved_result = result;" 12651 " receiver = {method: function(x) { return x - 1 }};" 12652 " }" 12653 "}"); 12654 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12655 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12656 } 12657 12658 12659 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 12660 v8::Isolate* isolate = CcTest::isolate(); 12661 v8::HandleScope scope(isolate); 12662 v8::Handle<v8::FunctionTemplate> fun_templ = 12663 v8::FunctionTemplate::New(isolate); 12664 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12665 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12666 v8::Signature::New(isolate, fun_templ)); 12667 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12668 proto_templ->Set(v8_str("method"), method_templ); 12669 fun_templ->SetHiddenPrototype(true); 12670 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12671 CHECK(!templ.IsEmpty()); 12672 LocalContext context; 12673 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12674 GenerateSomeGarbage(); 12675 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12676 v8::TryCatch try_catch; 12677 CompileRun( 12678 "o.foo = 17;" 12679 "var receiver = {};" 12680 "receiver.__proto__ = o;" 12681 "var result = 0;" 12682 "var saved_result = 0;" 12683 "for (var i = 0; i < 100; i++) {" 12684 " result = receiver.method(41);" 12685 " if (i == 50) {" 12686 " saved_result = result;" 12687 " receiver = 333;" 12688 " }" 12689 "}"); 12690 CHECK(try_catch.HasCaught()); 12691 // TODO(verwaest): Adjust message. 12692 CHECK_EQ(v8_str("TypeError: undefined is not a function"), 12693 try_catch.Exception()->ToString()); 12694 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12695 } 12696 12697 12698 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 12699 v8::Isolate* isolate = CcTest::isolate(); 12700 v8::HandleScope scope(isolate); 12701 v8::Handle<v8::FunctionTemplate> fun_templ = 12702 v8::FunctionTemplate::New(isolate); 12703 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12704 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"), 12705 v8::Signature::New(isolate, fun_templ)); 12706 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12707 proto_templ->Set(v8_str("method"), method_templ); 12708 fun_templ->SetHiddenPrototype(true); 12709 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12710 CHECK(!templ.IsEmpty()); 12711 LocalContext context; 12712 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12713 GenerateSomeGarbage(); 12714 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12715 v8::TryCatch try_catch; 12716 CompileRun( 12717 "o.foo = 17;" 12718 "var receiver = {};" 12719 "receiver.__proto__ = o;" 12720 "var result = 0;" 12721 "var saved_result = 0;" 12722 "for (var i = 0; i < 100; i++) {" 12723 " result = receiver.method(41);" 12724 " if (i == 50) {" 12725 " saved_result = result;" 12726 " receiver = Object.create(receiver);" 12727 " }" 12728 "}"); 12729 CHECK(try_catch.HasCaught()); 12730 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 12731 try_catch.Exception()->ToString()); 12732 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12733 } 12734 12735 12736 v8::Handle<Value> keyed_call_ic_function; 12737 12738 static void InterceptorKeyedCallICGetter( 12739 Local<String> name, 12740 const v8::PropertyCallbackInfo<v8::Value>& info) { 12741 ApiTestFuzzer::Fuzz(); 12742 if (v8_str("x")->Equals(name)) { 12743 info.GetReturnValue().Set(keyed_call_ic_function); 12744 } 12745 } 12746 12747 12748 // Test the case when we stored cacheable lookup into 12749 // a stub, but the function name changed (to another cacheable function). 12750 THREADED_TEST(InterceptorKeyedCallICKeyChange1) { 12751 v8::Isolate* isolate = CcTest::isolate(); 12752 v8::HandleScope scope(isolate); 12753 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12754 templ->SetNamedPropertyHandler(NoBlockGetterX); 12755 LocalContext context; 12756 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12757 CompileRun( 12758 "proto = new Object();" 12759 "proto.y = function(x) { return x + 1; };" 12760 "proto.z = function(x) { return x - 1; };" 12761 "o.__proto__ = proto;" 12762 "var result = 0;" 12763 "var method = 'y';" 12764 "for (var i = 0; i < 10; i++) {" 12765 " if (i == 5) { method = 'z'; };" 12766 " result += o[method](41);" 12767 "}"); 12768 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12769 } 12770 12771 12772 // Test the case when we stored cacheable lookup into 12773 // a stub, but the function name changed (and the new function is present 12774 // both before and after the interceptor in the prototype chain). 12775 THREADED_TEST(InterceptorKeyedCallICKeyChange2) { 12776 v8::Isolate* isolate = CcTest::isolate(); 12777 v8::HandleScope scope(isolate); 12778 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12779 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); 12780 LocalContext context; 12781 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); 12782 keyed_call_ic_function = 12783 v8_compile("function f(x) { return x - 1; }; f")->Run(); 12784 CompileRun( 12785 "o = new Object();" 12786 "proto2 = new Object();" 12787 "o.y = function(x) { return x + 1; };" 12788 "proto2.y = function(x) { return x + 2; };" 12789 "o.__proto__ = proto1;" 12790 "proto1.__proto__ = proto2;" 12791 "var result = 0;" 12792 "var method = 'x';" 12793 "for (var i = 0; i < 10; i++) {" 12794 " if (i == 5) { method = 'y'; };" 12795 " result += o[method](41);" 12796 "}"); 12797 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12798 } 12799 12800 12801 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit 12802 // on the global object. 12803 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { 12804 v8::Isolate* isolate = CcTest::isolate(); 12805 v8::HandleScope scope(isolate); 12806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12807 templ->SetNamedPropertyHandler(NoBlockGetterX); 12808 LocalContext context; 12809 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12810 CompileRun( 12811 "function inc(x) { return x + 1; };" 12812 "inc(1);" 12813 "function dec(x) { return x - 1; };" 12814 "dec(1);" 12815 "o.__proto__ = this;" 12816 "this.__proto__.x = inc;" 12817 "this.__proto__.y = dec;" 12818 "var result = 0;" 12819 "var method = 'x';" 12820 "for (var i = 0; i < 10; i++) {" 12821 " if (i == 5) { method = 'y'; };" 12822 " result += o[method](41);" 12823 "}"); 12824 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12825 } 12826 12827 12828 // Test the case when actual function to call sits on global object. 12829 THREADED_TEST(InterceptorKeyedCallICFromGlobal) { 12830 v8::Isolate* isolate = CcTest::isolate(); 12831 v8::HandleScope scope(isolate); 12832 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12833 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12834 LocalContext context; 12835 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12836 12837 CompileRun( 12838 "function len(x) { return x.length; };" 12839 "o.__proto__ = this;" 12840 "var m = 'parseFloat';" 12841 "var result = 0;" 12842 "for (var i = 0; i < 10; i++) {" 12843 " if (i == 5) {" 12844 " m = 'len';" 12845 " saved_result = result;" 12846 " };" 12847 " result = o[m]('239');" 12848 "}"); 12849 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); 12850 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12851 } 12852 12853 12854 // Test the map transition before the interceptor. 12855 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { 12856 v8::Isolate* isolate = CcTest::isolate(); 12857 v8::HandleScope scope(isolate); 12858 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12859 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12860 LocalContext context; 12861 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); 12862 12863 CompileRun( 12864 "var o = new Object();" 12865 "o.__proto__ = proto;" 12866 "o.method = function(x) { return x + 1; };" 12867 "var m = 'method';" 12868 "var result = 0;" 12869 "for (var i = 0; i < 10; i++) {" 12870 " if (i == 5) { o.method = function(x) { return x - 1; }; };" 12871 " result += o[m](41);" 12872 "}"); 12873 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12874 } 12875 12876 12877 // Test the map transition after the interceptor. 12878 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { 12879 v8::Isolate* isolate = CcTest::isolate(); 12880 v8::HandleScope scope(isolate); 12881 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate); 12882 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12883 LocalContext context; 12884 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12885 12886 CompileRun( 12887 "var proto = new Object();" 12888 "o.__proto__ = proto;" 12889 "proto.method = function(x) { return x + 1; };" 12890 "var m = 'method';" 12891 "var result = 0;" 12892 "for (var i = 0; i < 10; i++) {" 12893 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" 12894 " result += o[m](41);" 12895 "}"); 12896 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12897 } 12898 12899 12900 static int interceptor_call_count = 0; 12901 12902 static void InterceptorICRefErrorGetter( 12903 Local<String> name, 12904 const v8::PropertyCallbackInfo<v8::Value>& info) { 12905 ApiTestFuzzer::Fuzz(); 12906 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { 12907 info.GetReturnValue().Set(call_ic_function2); 12908 } 12909 } 12910 12911 12912 // This test should hit load and call ICs for the interceptor case. 12913 // Once in a while, the interceptor will reply that a property was not 12914 // found in which case we should get a reference error. 12915 THREADED_TEST(InterceptorICReferenceErrors) { 12916 v8::Isolate* isolate = CcTest::isolate(); 12917 v8::HandleScope scope(isolate); 12918 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12919 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter); 12920 LocalContext context(0, templ, v8::Handle<Value>()); 12921 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); 12922 v8::Handle<Value> value = CompileRun( 12923 "function f() {" 12924 " for (var i = 0; i < 1000; i++) {" 12925 " try { x; } catch(e) { return true; }" 12926 " }" 12927 " return false;" 12928 "};" 12929 "f();"); 12930 CHECK_EQ(true, value->BooleanValue()); 12931 interceptor_call_count = 0; 12932 value = CompileRun( 12933 "function g() {" 12934 " for (var i = 0; i < 1000; i++) {" 12935 " try { x(42); } catch(e) { return true; }" 12936 " }" 12937 " return false;" 12938 "};" 12939 "g();"); 12940 CHECK_EQ(true, value->BooleanValue()); 12941 } 12942 12943 12944 static int interceptor_ic_exception_get_count = 0; 12945 12946 static void InterceptorICExceptionGetter( 12947 Local<String> name, 12948 const v8::PropertyCallbackInfo<v8::Value>& info) { 12949 ApiTestFuzzer::Fuzz(); 12950 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { 12951 info.GetReturnValue().Set(call_ic_function3); 12952 } 12953 if (interceptor_ic_exception_get_count == 20) { 12954 info.GetIsolate()->ThrowException(v8_num(42)); 12955 return; 12956 } 12957 } 12958 12959 12960 // Test interceptor load/call IC where the interceptor throws an 12961 // exception once in a while. 12962 THREADED_TEST(InterceptorICGetterExceptions) { 12963 interceptor_ic_exception_get_count = 0; 12964 v8::Isolate* isolate = CcTest::isolate(); 12965 v8::HandleScope scope(isolate); 12966 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 12967 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter); 12968 LocalContext context(0, templ, v8::Handle<Value>()); 12969 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); 12970 v8::Handle<Value> value = CompileRun( 12971 "function f() {" 12972 " for (var i = 0; i < 100; i++) {" 12973 " try { x; } catch(e) { return true; }" 12974 " }" 12975 " return false;" 12976 "};" 12977 "f();"); 12978 CHECK_EQ(true, value->BooleanValue()); 12979 interceptor_ic_exception_get_count = 0; 12980 value = CompileRun( 12981 "function f() {" 12982 " for (var i = 0; i < 100; i++) {" 12983 " try { x(42); } catch(e) { return true; }" 12984 " }" 12985 " return false;" 12986 "};" 12987 "f();"); 12988 CHECK_EQ(true, value->BooleanValue()); 12989 } 12990 12991 12992 static int interceptor_ic_exception_set_count = 0; 12993 12994 static void InterceptorICExceptionSetter( 12995 Local<String> key, 12996 Local<Value> value, 12997 const v8::PropertyCallbackInfo<v8::Value>& info) { 12998 ApiTestFuzzer::Fuzz(); 12999 if (++interceptor_ic_exception_set_count > 20) { 13000 info.GetIsolate()->ThrowException(v8_num(42)); 13001 } 13002 } 13003 13004 13005 // Test interceptor store IC where the interceptor throws an exception 13006 // once in a while. 13007 THREADED_TEST(InterceptorICSetterExceptions) { 13008 interceptor_ic_exception_set_count = 0; 13009 v8::Isolate* isolate = CcTest::isolate(); 13010 v8::HandleScope scope(isolate); 13011 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 13012 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter); 13013 LocalContext context(0, templ, v8::Handle<Value>()); 13014 v8::Handle<Value> value = CompileRun( 13015 "function f() {" 13016 " for (var i = 0; i < 100; i++) {" 13017 " try { x = 42; } catch(e) { return true; }" 13018 " }" 13019 " return false;" 13020 "};" 13021 "f();"); 13022 CHECK_EQ(true, value->BooleanValue()); 13023 } 13024 13025 13026 // Test that we ignore null interceptors. 13027 THREADED_TEST(NullNamedInterceptor) { 13028 v8::Isolate* isolate = CcTest::isolate(); 13029 v8::HandleScope scope(isolate); 13030 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 13031 templ->SetNamedPropertyHandler( 13032 static_cast<v8::NamedPropertyGetterCallback>(0)); 13033 LocalContext context; 13034 templ->Set(CcTest::isolate(), "x", v8_num(42)); 13035 v8::Handle<v8::Object> obj = templ->NewInstance(); 13036 context->Global()->Set(v8_str("obj"), obj); 13037 v8::Handle<Value> value = CompileRun("obj.x"); 13038 CHECK(value->IsInt32()); 13039 CHECK_EQ(42, value->Int32Value()); 13040 } 13041 13042 13043 // Test that we ignore null interceptors. 13044 THREADED_TEST(NullIndexedInterceptor) { 13045 v8::Isolate* isolate = CcTest::isolate(); 13046 v8::HandleScope scope(isolate); 13047 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate); 13048 templ->SetIndexedPropertyHandler( 13049 static_cast<v8::IndexedPropertyGetterCallback>(0)); 13050 LocalContext context; 13051 templ->Set(CcTest::isolate(), "42", v8_num(42)); 13052 v8::Handle<v8::Object> obj = templ->NewInstance(); 13053 context->Global()->Set(v8_str("obj"), obj); 13054 v8::Handle<Value> value = CompileRun("obj[42]"); 13055 CHECK(value->IsInt32()); 13056 CHECK_EQ(42, value->Int32Value()); 13057 } 13058 13059 13060 THREADED_TEST(NamedPropertyHandlerGetterAttributes) { 13061 v8::Isolate* isolate = CcTest::isolate(); 13062 v8::HandleScope scope(isolate); 13063 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13064 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter); 13065 LocalContext env; 13066 env->Global()->Set(v8_str("obj"), 13067 templ->GetFunction()->NewInstance()); 13068 ExpectTrue("obj.x === 42"); 13069 ExpectTrue("!obj.propertyIsEnumerable('x')"); 13070 } 13071 13072 13073 static void ThrowingGetter(Local<String> name, 13074 const v8::PropertyCallbackInfo<v8::Value>& info) { 13075 ApiTestFuzzer::Fuzz(); 13076 info.GetIsolate()->ThrowException(Handle<Value>()); 13077 info.GetReturnValue().SetUndefined(); 13078 } 13079 13080 13081 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 13082 LocalContext context; 13083 HandleScope scope(context->GetIsolate()); 13084 13085 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 13086 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 13087 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 13088 13089 Local<Object> instance = templ->GetFunction()->NewInstance(); 13090 13091 Local<Object> another = Object::New(context->GetIsolate()); 13092 another->SetPrototype(instance); 13093 13094 Local<Object> with_js_getter = CompileRun( 13095 "o = {};\n" 13096 "o.__defineGetter__('f', function() { throw undefined; });\n" 13097 "o\n").As<Object>(); 13098 CHECK(!with_js_getter.IsEmpty()); 13099 13100 TryCatch try_catch; 13101 13102 Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); 13103 CHECK(try_catch.HasCaught()); 13104 try_catch.Reset(); 13105 CHECK(result.IsEmpty()); 13106 13107 result = another->GetRealNamedProperty(v8_str("f")); 13108 CHECK(try_catch.HasCaught()); 13109 try_catch.Reset(); 13110 CHECK(result.IsEmpty()); 13111 13112 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); 13113 CHECK(try_catch.HasCaught()); 13114 try_catch.Reset(); 13115 CHECK(result.IsEmpty()); 13116 13117 result = another->Get(v8_str("f")); 13118 CHECK(try_catch.HasCaught()); 13119 try_catch.Reset(); 13120 CHECK(result.IsEmpty()); 13121 13122 result = with_js_getter->GetRealNamedProperty(v8_str("f")); 13123 CHECK(try_catch.HasCaught()); 13124 try_catch.Reset(); 13125 CHECK(result.IsEmpty()); 13126 13127 result = with_js_getter->Get(v8_str("f")); 13128 CHECK(try_catch.HasCaught()); 13129 try_catch.Reset(); 13130 CHECK(result.IsEmpty()); 13131 } 13132 13133 13134 static void ThrowingCallbackWithTryCatch( 13135 const v8::FunctionCallbackInfo<v8::Value>& args) { 13136 TryCatch try_catch; 13137 // Verboseness is important: it triggers message delivery which can call into 13138 // external code. 13139 try_catch.SetVerbose(true); 13140 CompileRun("throw 'from JS';"); 13141 CHECK(try_catch.HasCaught()); 13142 CHECK(!CcTest::i_isolate()->has_pending_exception()); 13143 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 13144 } 13145 13146 13147 static int call_depth; 13148 13149 13150 static void WithTryCatch(Handle<Message> message, Handle<Value> data) { 13151 TryCatch try_catch; 13152 } 13153 13154 13155 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) { 13156 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 13157 } 13158 13159 13160 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) { 13161 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi")); 13162 } 13163 13164 13165 static void WebKitLike(Handle<Message> message, Handle<Value> data) { 13166 Handle<String> errorMessageString = message->Get(); 13167 CHECK(!errorMessageString.IsEmpty()); 13168 message->GetStackTrace(); 13169 message->GetScriptOrigin().ResourceName(); 13170 } 13171 13172 13173 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 13174 LocalContext context; 13175 v8::Isolate* isolate = context->GetIsolate(); 13176 HandleScope scope(isolate); 13177 13178 Local<Function> func = 13179 FunctionTemplate::New(isolate, 13180 ThrowingCallbackWithTryCatch)->GetFunction(); 13181 context->Global()->Set(v8_str("func"), func); 13182 13183 MessageCallback callbacks[] = 13184 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 13185 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 13186 MessageCallback callback = callbacks[i]; 13187 if (callback != NULL) { 13188 V8::AddMessageListener(callback); 13189 } 13190 // Some small number to control number of times message handler should 13191 // throw an exception. 13192 call_depth = 5; 13193 ExpectFalse( 13194 "var thrown = false;\n" 13195 "try { func(); } catch(e) { thrown = true; }\n" 13196 "thrown\n"); 13197 if (callback != NULL) { 13198 V8::RemoveMessageListeners(callback); 13199 } 13200 } 13201 } 13202 13203 13204 static void ParentGetter(Local<String> name, 13205 const v8::PropertyCallbackInfo<v8::Value>& info) { 13206 ApiTestFuzzer::Fuzz(); 13207 info.GetReturnValue().Set(v8_num(1)); 13208 } 13209 13210 13211 static void ChildGetter(Local<String> name, 13212 const v8::PropertyCallbackInfo<v8::Value>& info) { 13213 ApiTestFuzzer::Fuzz(); 13214 info.GetReturnValue().Set(v8_num(42)); 13215 } 13216 13217 13218 THREADED_TEST(Overriding) { 13219 LocalContext context; 13220 v8::Isolate* isolate = context->GetIsolate(); 13221 v8::HandleScope scope(isolate); 13222 13223 // Parent template. 13224 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate); 13225 Local<ObjectTemplate> parent_instance_templ = 13226 parent_templ->InstanceTemplate(); 13227 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 13228 13229 // Template that inherits from the parent template. 13230 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate); 13231 Local<ObjectTemplate> child_instance_templ = 13232 child_templ->InstanceTemplate(); 13233 child_templ->Inherit(parent_templ); 13234 // Override 'f'. The child version of 'f' should get called for child 13235 // instances. 13236 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 13237 // Add 'g' twice. The 'g' added last should get called for instances. 13238 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 13239 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 13240 13241 // Add 'h' as an accessor to the proto template with ReadOnly attributes 13242 // so 'h' can be shadowed on the instance object. 13243 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 13244 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 13245 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 13246 13247 // Add 'i' as an accessor to the instance template with ReadOnly attributes 13248 // but the attribute does not have effect because it is duplicated with 13249 // NULL setter. 13250 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 13251 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 13252 13253 13254 13255 // Instantiate the child template. 13256 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance(); 13257 13258 // Check that the child function overrides the parent one. 13259 context->Global()->Set(v8_str("o"), instance); 13260 Local<Value> value = v8_compile("o.f")->Run(); 13261 // Check that the 'g' that was added last is hit. 13262 CHECK_EQ(42, value->Int32Value()); 13263 value = v8_compile("o.g")->Run(); 13264 CHECK_EQ(42, value->Int32Value()); 13265 13266 // Check that 'h' cannot be shadowed. 13267 value = v8_compile("o.h = 3; o.h")->Run(); 13268 CHECK_EQ(1, value->Int32Value()); 13269 13270 // Check that 'i' cannot be shadowed or changed. 13271 value = v8_compile("o.i = 3; o.i")->Run(); 13272 CHECK_EQ(42, value->Int32Value()); 13273 } 13274 13275 13276 static void IsConstructHandler( 13277 const v8::FunctionCallbackInfo<v8::Value>& args) { 13278 ApiTestFuzzer::Fuzz(); 13279 args.GetReturnValue().Set(args.IsConstructCall()); 13280 } 13281 13282 13283 THREADED_TEST(IsConstructCall) { 13284 v8::Isolate* isolate = CcTest::isolate(); 13285 v8::HandleScope scope(isolate); 13286 13287 // Function template with call handler. 13288 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13289 templ->SetCallHandler(IsConstructHandler); 13290 13291 LocalContext context; 13292 13293 context->Global()->Set(v8_str("f"), templ->GetFunction()); 13294 Local<Value> value = v8_compile("f()")->Run(); 13295 CHECK(!value->BooleanValue()); 13296 value = v8_compile("new f()")->Run(); 13297 CHECK(value->BooleanValue()); 13298 } 13299 13300 13301 THREADED_TEST(ObjectProtoToString) { 13302 v8::Isolate* isolate = CcTest::isolate(); 13303 v8::HandleScope scope(isolate); 13304 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 13305 templ->SetClassName(v8_str("MyClass")); 13306 13307 LocalContext context; 13308 13309 Local<String> customized_tostring = v8_str("customized toString"); 13310 13311 // Replace Object.prototype.toString 13312 v8_compile("Object.prototype.toString = function() {" 13313 " return 'customized toString';" 13314 "}")->Run(); 13315 13316 // Normal ToString call should call replaced Object.prototype.toString 13317 Local<v8::Object> instance = templ->GetFunction()->NewInstance(); 13318 Local<String> value = instance->ToString(); 13319 CHECK(value->IsString() && value->Equals(customized_tostring)); 13320 13321 // ObjectProtoToString should not call replace toString function. 13322 value = instance->ObjectProtoToString(); 13323 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]"))); 13324 13325 // Check global 13326 value = context->Global()->ObjectProtoToString(); 13327 CHECK(value->IsString() && value->Equals(v8_str("[object global]"))); 13328 13329 // Check ordinary object 13330 Local<Value> object = v8_compile("new Object()")->Run(); 13331 value = object.As<v8::Object>()->ObjectProtoToString(); 13332 CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); 13333 } 13334 13335 13336 THREADED_TEST(ObjectGetConstructorName) { 13337 LocalContext context; 13338 v8::HandleScope scope(context->GetIsolate()); 13339 v8_compile("function Parent() {};" 13340 "function Child() {};" 13341 "Child.prototype = new Parent();" 13342 "var outer = { inner: function() { } };" 13343 "var p = new Parent();" 13344 "var c = new Child();" 13345 "var x = new outer.inner();")->Run(); 13346 13347 Local<v8::Value> p = context->Global()->Get(v8_str("p")); 13348 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals( 13349 v8_str("Parent"))); 13350 13351 Local<v8::Value> c = context->Global()->Get(v8_str("c")); 13352 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals( 13353 v8_str("Child"))); 13354 13355 Local<v8::Value> x = context->Global()->Get(v8_str("x")); 13356 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals( 13357 v8_str("outer.inner"))); 13358 } 13359 13360 13361 bool ApiTestFuzzer::fuzzing_ = false; 13362 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0); 13363 int ApiTestFuzzer::active_tests_; 13364 int ApiTestFuzzer::tests_being_run_; 13365 int ApiTestFuzzer::current_; 13366 13367 13368 // We are in a callback and want to switch to another thread (if we 13369 // are currently running the thread fuzzing test). 13370 void ApiTestFuzzer::Fuzz() { 13371 if (!fuzzing_) return; 13372 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 13373 test->ContextSwitch(); 13374 } 13375 13376 13377 // Let the next thread go. Since it is also waiting on the V8 lock it may 13378 // not start immediately. 13379 bool ApiTestFuzzer::NextThread() { 13380 int test_position = GetNextTestNumber(); 13381 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 13382 if (test_position == current_) { 13383 if (kLogThreading) 13384 printf("Stay with %s\n", test_name); 13385 return false; 13386 } 13387 if (kLogThreading) { 13388 printf("Switch from %s to %s\n", 13389 test_name, 13390 RegisterThreadedTest::nth(test_position)->name()); 13391 } 13392 current_ = test_position; 13393 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal(); 13394 return true; 13395 } 13396 13397 13398 void ApiTestFuzzer::Run() { 13399 // When it is our turn... 13400 gate_.Wait(); 13401 { 13402 // ... get the V8 lock and start running the test. 13403 v8::Locker locker(CcTest::isolate()); 13404 CallTest(); 13405 } 13406 // This test finished. 13407 active_ = false; 13408 active_tests_--; 13409 // If it was the last then signal that fact. 13410 if (active_tests_ == 0) { 13411 all_tests_done_.Signal(); 13412 } else { 13413 // Otherwise select a new test and start that. 13414 NextThread(); 13415 } 13416 } 13417 13418 13419 static unsigned linear_congruential_generator; 13420 13421 13422 void ApiTestFuzzer::SetUp(PartOfTest part) { 13423 linear_congruential_generator = i::FLAG_testing_prng_seed; 13424 fuzzing_ = true; 13425 int count = RegisterThreadedTest::count(); 13426 int start = count * part / (LAST_PART + 1); 13427 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 13428 active_tests_ = tests_being_run_ = end - start + 1; 13429 for (int i = 0; i < tests_being_run_; i++) { 13430 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 13431 } 13432 for (int i = 0; i < active_tests_; i++) { 13433 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 13434 } 13435 } 13436 13437 13438 static void CallTestNumber(int test_number) { 13439 (RegisterThreadedTest::nth(test_number)->callback())(); 13440 } 13441 13442 13443 void ApiTestFuzzer::RunAllTests() { 13444 // Set off the first test. 13445 current_ = -1; 13446 NextThread(); 13447 // Wait till they are all done. 13448 all_tests_done_.Wait(); 13449 } 13450 13451 13452 int ApiTestFuzzer::GetNextTestNumber() { 13453 int next_test; 13454 do { 13455 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 13456 linear_congruential_generator *= 1664525u; 13457 linear_congruential_generator += 1013904223u; 13458 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 13459 return next_test; 13460 } 13461 13462 13463 void ApiTestFuzzer::ContextSwitch() { 13464 // If the new thread is the same as the current thread there is nothing to do. 13465 if (NextThread()) { 13466 // Now it can start. 13467 v8::Unlocker unlocker(CcTest::isolate()); 13468 // Wait till someone starts us again. 13469 gate_.Wait(); 13470 // And we're off. 13471 } 13472 } 13473 13474 13475 void ApiTestFuzzer::TearDown() { 13476 fuzzing_ = false; 13477 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 13478 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 13479 if (fuzzer != NULL) fuzzer->Join(); 13480 } 13481 } 13482 13483 13484 // Lets not be needlessly self-referential. 13485 TEST(Threading1) { 13486 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 13487 ApiTestFuzzer::RunAllTests(); 13488 ApiTestFuzzer::TearDown(); 13489 } 13490 13491 13492 TEST(Threading2) { 13493 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 13494 ApiTestFuzzer::RunAllTests(); 13495 ApiTestFuzzer::TearDown(); 13496 } 13497 13498 13499 TEST(Threading3) { 13500 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 13501 ApiTestFuzzer::RunAllTests(); 13502 ApiTestFuzzer::TearDown(); 13503 } 13504 13505 13506 TEST(Threading4) { 13507 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 13508 ApiTestFuzzer::RunAllTests(); 13509 ApiTestFuzzer::TearDown(); 13510 } 13511 13512 13513 void ApiTestFuzzer::CallTest() { 13514 v8::Isolate::Scope scope(CcTest::isolate()); 13515 if (kLogThreading) 13516 printf("Start test %d\n", test_number_); 13517 CallTestNumber(test_number_); 13518 if (kLogThreading) 13519 printf("End test %d\n", test_number_); 13520 } 13521 13522 13523 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 13524 v8::Isolate* isolate = args.GetIsolate(); 13525 CHECK(v8::Locker::IsLocked(isolate)); 13526 ApiTestFuzzer::Fuzz(); 13527 v8::Unlocker unlocker(isolate); 13528 const char* code = "throw 7;"; 13529 { 13530 v8::Locker nested_locker(isolate); 13531 v8::HandleScope scope(isolate); 13532 v8::Handle<Value> exception; 13533 { v8::TryCatch try_catch; 13534 v8::Handle<Value> value = CompileRun(code); 13535 CHECK(value.IsEmpty()); 13536 CHECK(try_catch.HasCaught()); 13537 // Make sure to wrap the exception in a new handle because 13538 // the handle returned from the TryCatch is destroyed 13539 // when the TryCatch is destroyed. 13540 exception = Local<Value>::New(isolate, try_catch.Exception()); 13541 } 13542 args.GetIsolate()->ThrowException(exception); 13543 } 13544 } 13545 13546 13547 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 13548 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13549 ApiTestFuzzer::Fuzz(); 13550 v8::Unlocker unlocker(CcTest::isolate()); 13551 const char* code = "throw 7;"; 13552 { 13553 v8::Locker nested_locker(CcTest::isolate()); 13554 v8::HandleScope scope(args.GetIsolate()); 13555 v8::Handle<Value> value = CompileRun(code); 13556 CHECK(value.IsEmpty()); 13557 args.GetReturnValue().Set(v8_str("foo")); 13558 } 13559 } 13560 13561 13562 // These are locking tests that don't need to be run again 13563 // as part of the locking aggregation tests. 13564 TEST(NestedLockers) { 13565 v8::Isolate* isolate = CcTest::isolate(); 13566 v8::Locker locker(isolate); 13567 CHECK(v8::Locker::IsLocked(isolate)); 13568 LocalContext env; 13569 v8::HandleScope scope(env->GetIsolate()); 13570 Local<v8::FunctionTemplate> fun_templ = 13571 v8::FunctionTemplate::New(isolate, ThrowInJS); 13572 Local<Function> fun = fun_templ->GetFunction(); 13573 env->Global()->Set(v8_str("throw_in_js"), fun); 13574 Local<Script> script = v8_compile("(function () {" 13575 " try {" 13576 " throw_in_js();" 13577 " return 42;" 13578 " } catch (e) {" 13579 " return e * 13;" 13580 " }" 13581 "})();"); 13582 CHECK_EQ(91, script->Run()->Int32Value()); 13583 } 13584 13585 13586 // These are locking tests that don't need to be run again 13587 // as part of the locking aggregation tests. 13588 TEST(NestedLockersNoTryCatch) { 13589 v8::Locker locker(CcTest::isolate()); 13590 LocalContext env; 13591 v8::HandleScope scope(env->GetIsolate()); 13592 Local<v8::FunctionTemplate> fun_templ = 13593 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch); 13594 Local<Function> fun = fun_templ->GetFunction(); 13595 env->Global()->Set(v8_str("throw_in_js"), fun); 13596 Local<Script> script = v8_compile("(function () {" 13597 " try {" 13598 " throw_in_js();" 13599 " return 42;" 13600 " } catch (e) {" 13601 " return e * 13;" 13602 " }" 13603 "})();"); 13604 CHECK_EQ(91, script->Run()->Int32Value()); 13605 } 13606 13607 13608 THREADED_TEST(RecursiveLocking) { 13609 v8::Locker locker(CcTest::isolate()); 13610 { 13611 v8::Locker locker2(CcTest::isolate()); 13612 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13613 } 13614 } 13615 13616 13617 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 13618 ApiTestFuzzer::Fuzz(); 13619 v8::Unlocker unlocker(CcTest::isolate()); 13620 } 13621 13622 13623 THREADED_TEST(LockUnlockLock) { 13624 { 13625 v8::Locker locker(CcTest::isolate()); 13626 v8::HandleScope scope(CcTest::isolate()); 13627 LocalContext env; 13628 Local<v8::FunctionTemplate> fun_templ = 13629 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13630 Local<Function> fun = fun_templ->GetFunction(); 13631 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13632 Local<Script> script = v8_compile("(function () {" 13633 " unlock_for_a_moment();" 13634 " return 42;" 13635 "})();"); 13636 CHECK_EQ(42, script->Run()->Int32Value()); 13637 } 13638 { 13639 v8::Locker locker(CcTest::isolate()); 13640 v8::HandleScope scope(CcTest::isolate()); 13641 LocalContext env; 13642 Local<v8::FunctionTemplate> fun_templ = 13643 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment); 13644 Local<Function> fun = fun_templ->GetFunction(); 13645 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13646 Local<Script> script = v8_compile("(function () {" 13647 " unlock_for_a_moment();" 13648 " return 42;" 13649 "})();"); 13650 CHECK_EQ(42, script->Run()->Int32Value()); 13651 } 13652 } 13653 13654 13655 static int GetGlobalObjectsCount() { 13656 int count = 0; 13657 i::HeapIterator it(CcTest::heap()); 13658 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 13659 if (object->IsJSGlobalObject()) count++; 13660 return count; 13661 } 13662 13663 13664 static void CheckSurvivingGlobalObjectsCount(int expected) { 13665 // We need to collect all garbage twice to be sure that everything 13666 // has been collected. This is because inline caches are cleared in 13667 // the first garbage collection but some of the maps have already 13668 // been marked at that point. Therefore some of the maps are not 13669 // collected until the second garbage collection. 13670 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13671 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 13672 int count = GetGlobalObjectsCount(); 13673 #ifdef DEBUG 13674 if (count != expected) CcTest::heap()->TracePathToGlobal(); 13675 #endif 13676 CHECK_EQ(expected, count); 13677 } 13678 13679 13680 TEST(DontLeakGlobalObjects) { 13681 // Regression test for issues 1139850 and 1174891. 13682 13683 i::FLAG_expose_gc = true; 13684 v8::V8::Initialize(); 13685 13686 for (int i = 0; i < 5; i++) { 13687 { v8::HandleScope scope(CcTest::isolate()); 13688 LocalContext context; 13689 } 13690 CcTest::isolate()->ContextDisposedNotification(); 13691 CheckSurvivingGlobalObjectsCount(0); 13692 13693 { v8::HandleScope scope(CcTest::isolate()); 13694 LocalContext context; 13695 v8_compile("Date")->Run(); 13696 } 13697 CcTest::isolate()->ContextDisposedNotification(); 13698 CheckSurvivingGlobalObjectsCount(0); 13699 13700 { v8::HandleScope scope(CcTest::isolate()); 13701 LocalContext context; 13702 v8_compile("/aaa/")->Run(); 13703 } 13704 CcTest::isolate()->ContextDisposedNotification(); 13705 CheckSurvivingGlobalObjectsCount(0); 13706 13707 { v8::HandleScope scope(CcTest::isolate()); 13708 const char* extension_list[] = { "v8/gc" }; 13709 v8::ExtensionConfiguration extensions(1, extension_list); 13710 LocalContext context(&extensions); 13711 v8_compile("gc();")->Run(); 13712 } 13713 CcTest::isolate()->ContextDisposedNotification(); 13714 CheckSurvivingGlobalObjectsCount(0); 13715 } 13716 } 13717 13718 13719 TEST(CopyablePersistent) { 13720 LocalContext context; 13721 v8::Isolate* isolate = context->GetIsolate(); 13722 i::GlobalHandles* globals = 13723 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13724 int initial_handles = globals->global_handles_count(); 13725 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > 13726 CopyableObject; 13727 { 13728 CopyableObject handle1; 13729 { 13730 v8::HandleScope scope(isolate); 13731 handle1.Reset(isolate, v8::Object::New(isolate)); 13732 } 13733 CHECK_EQ(initial_handles + 1, globals->global_handles_count()); 13734 CopyableObject handle2; 13735 handle2 = handle1; 13736 CHECK(handle1 == handle2); 13737 CHECK_EQ(initial_handles + 2, globals->global_handles_count()); 13738 CopyableObject handle3(handle2); 13739 CHECK(handle1 == handle3); 13740 CHECK_EQ(initial_handles + 3, globals->global_handles_count()); 13741 } 13742 // Verify autodispose 13743 CHECK_EQ(initial_handles, globals->global_handles_count()); 13744 } 13745 13746 13747 static void WeakApiCallback( 13748 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) { 13749 Local<Value> value = data.GetValue()->Get(v8_str("key")); 13750 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value())); 13751 data.GetParameter()->Reset(); 13752 delete data.GetParameter(); 13753 } 13754 13755 13756 TEST(WeakCallbackApi) { 13757 LocalContext context; 13758 v8::Isolate* isolate = context->GetIsolate(); 13759 i::GlobalHandles* globals = 13760 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13761 int initial_handles = globals->global_handles_count(); 13762 { 13763 v8::HandleScope scope(isolate); 13764 v8::Local<v8::Object> obj = v8::Object::New(isolate); 13765 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231)); 13766 v8::Persistent<v8::Object>* handle = 13767 new v8::Persistent<v8::Object>(isolate, obj); 13768 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle, 13769 WeakApiCallback); 13770 } 13771 reinterpret_cast<i::Isolate*>(isolate)->heap()-> 13772 CollectAllGarbage(i::Heap::kNoGCFlags); 13773 // Verify disposed. 13774 CHECK_EQ(initial_handles, globals->global_handles_count()); 13775 } 13776 13777 13778 v8::Persistent<v8::Object> some_object; 13779 v8::Persistent<v8::Object> bad_handle; 13780 13781 void NewPersistentHandleCallback( 13782 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13783 v8::HandleScope scope(data.GetIsolate()); 13784 bad_handle.Reset(data.GetIsolate(), some_object); 13785 data.GetParameter()->Reset(); 13786 } 13787 13788 13789 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 13790 LocalContext context; 13791 v8::Isolate* isolate = context->GetIsolate(); 13792 13793 v8::Persistent<v8::Object> handle1, handle2; 13794 { 13795 v8::HandleScope scope(isolate); 13796 some_object.Reset(isolate, v8::Object::New(isolate)); 13797 handle1.Reset(isolate, v8::Object::New(isolate)); 13798 handle2.Reset(isolate, v8::Object::New(isolate)); 13799 } 13800 // Note: order is implementation dependent alas: currently 13801 // global handle nodes are processed by PostGarbageCollectionProcessing 13802 // in reverse allocation order, so if second allocated handle is deleted, 13803 // weak callback of the first handle would be able to 'reallocate' it. 13804 handle1.SetWeak(&handle1, NewPersistentHandleCallback); 13805 handle2.Reset(); 13806 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13807 } 13808 13809 13810 v8::Persistent<v8::Object> to_be_disposed; 13811 13812 void DisposeAndForceGcCallback( 13813 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13814 to_be_disposed.Reset(); 13815 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13816 data.GetParameter()->Reset(); 13817 } 13818 13819 13820 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 13821 LocalContext context; 13822 v8::Isolate* isolate = context->GetIsolate(); 13823 13824 v8::Persistent<v8::Object> handle1, handle2; 13825 { 13826 v8::HandleScope scope(isolate); 13827 handle1.Reset(isolate, v8::Object::New(isolate)); 13828 handle2.Reset(isolate, v8::Object::New(isolate)); 13829 } 13830 handle1.SetWeak(&handle1, DisposeAndForceGcCallback); 13831 to_be_disposed.Reset(isolate, handle2); 13832 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13833 } 13834 13835 void DisposingCallback( 13836 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13837 data.GetParameter()->Reset(); 13838 } 13839 13840 void HandleCreatingCallback( 13841 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13842 v8::HandleScope scope(data.GetIsolate()); 13843 v8::Persistent<v8::Object>(data.GetIsolate(), 13844 v8::Object::New(data.GetIsolate())); 13845 data.GetParameter()->Reset(); 13846 } 13847 13848 13849 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 13850 LocalContext context; 13851 v8::Isolate* isolate = context->GetIsolate(); 13852 13853 v8::Persistent<v8::Object> handle1, handle2, handle3; 13854 { 13855 v8::HandleScope scope(isolate); 13856 handle3.Reset(isolate, v8::Object::New(isolate)); 13857 handle2.Reset(isolate, v8::Object::New(isolate)); 13858 handle1.Reset(isolate, v8::Object::New(isolate)); 13859 } 13860 handle2.SetWeak(&handle2, DisposingCallback); 13861 handle3.SetWeak(&handle3, HandleCreatingCallback); 13862 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13863 } 13864 13865 13866 THREADED_TEST(CheckForCrossContextObjectLiterals) { 13867 v8::V8::Initialize(); 13868 13869 const int nof = 2; 13870 const char* sources[nof] = { 13871 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 13872 "Object()" 13873 }; 13874 13875 for (int i = 0; i < nof; i++) { 13876 const char* source = sources[i]; 13877 { v8::HandleScope scope(CcTest::isolate()); 13878 LocalContext context; 13879 CompileRun(source); 13880 } 13881 { v8::HandleScope scope(CcTest::isolate()); 13882 LocalContext context; 13883 CompileRun(source); 13884 } 13885 } 13886 } 13887 13888 13889 static v8::Handle<Value> NestedScope(v8::Local<Context> env) { 13890 v8::EscapableHandleScope inner(env->GetIsolate()); 13891 env->Enter(); 13892 v8::Local<Value> three = v8_num(3); 13893 v8::Local<Value> value = inner.Escape(three); 13894 env->Exit(); 13895 return value; 13896 } 13897 13898 13899 THREADED_TEST(NestedHandleScopeAndContexts) { 13900 v8::Isolate* isolate = CcTest::isolate(); 13901 v8::HandleScope outer(isolate); 13902 v8::Local<Context> env = Context::New(isolate); 13903 env->Enter(); 13904 v8::Handle<Value> value = NestedScope(env); 13905 v8::Handle<String> str(value->ToString()); 13906 CHECK(!str.IsEmpty()); 13907 env->Exit(); 13908 } 13909 13910 13911 static bool MatchPointers(void* key1, void* key2) { 13912 return key1 == key2; 13913 } 13914 13915 13916 struct SymbolInfo { 13917 size_t id; 13918 size_t size; 13919 std::string name; 13920 }; 13921 13922 13923 class SetFunctionEntryHookTest { 13924 public: 13925 SetFunctionEntryHookTest() { 13926 CHECK(instance_ == NULL); 13927 instance_ = this; 13928 } 13929 ~SetFunctionEntryHookTest() { 13930 CHECK(instance_ == this); 13931 instance_ = NULL; 13932 } 13933 void Reset() { 13934 symbols_.clear(); 13935 symbol_locations_.clear(); 13936 invocations_.clear(); 13937 } 13938 void RunTest(); 13939 void OnJitEvent(const v8::JitCodeEvent* event); 13940 static void JitEvent(const v8::JitCodeEvent* event) { 13941 CHECK(instance_ != NULL); 13942 instance_->OnJitEvent(event); 13943 } 13944 13945 void OnEntryHook(uintptr_t function, 13946 uintptr_t return_addr_location); 13947 static void EntryHook(uintptr_t function, 13948 uintptr_t return_addr_location) { 13949 CHECK(instance_ != NULL); 13950 instance_->OnEntryHook(function, return_addr_location); 13951 } 13952 13953 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 13954 CHECK(instance_ != NULL); 13955 args.GetReturnValue().Set(v8_num(42)); 13956 } 13957 void RunLoopInNewEnv(v8::Isolate* isolate); 13958 13959 // Records addr as location of symbol. 13960 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 13961 13962 // Finds the symbol containing addr 13963 SymbolInfo* FindSymbolForAddr(i::Address addr); 13964 // Returns the number of invocations where the caller name contains 13965 // \p caller_name and the function name contains \p function_name. 13966 int CountInvocations(const char* caller_name, 13967 const char* function_name); 13968 13969 i::Handle<i::JSFunction> foo_func_; 13970 i::Handle<i::JSFunction> bar_func_; 13971 13972 typedef std::map<size_t, SymbolInfo> SymbolMap; 13973 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 13974 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 13975 SymbolMap symbols_; 13976 SymbolLocationMap symbol_locations_; 13977 InvocationMap invocations_; 13978 13979 static SetFunctionEntryHookTest* instance_; 13980 }; 13981 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 13982 13983 13984 // Returns true if addr is in the range [start, start+len). 13985 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 13986 if (start <= addr && start + len > addr) 13987 return true; 13988 13989 return false; 13990 } 13991 13992 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 13993 SymbolInfo* symbol) { 13994 // Insert the symbol at the new location. 13995 SymbolLocationMap::iterator it = 13996 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 13997 // Now erase symbols to the left and right that overlap this one. 13998 while (it != symbol_locations_.begin()) { 13999 SymbolLocationMap::iterator left = it; 14000 --left; 14001 if (!Overlaps(left->first, left->second->size, addr)) 14002 break; 14003 symbol_locations_.erase(left); 14004 } 14005 14006 // Now erase symbols to the left and right that overlap this one. 14007 while (true) { 14008 SymbolLocationMap::iterator right = it; 14009 ++right; 14010 if (right == symbol_locations_.end()) 14011 break; 14012 if (!Overlaps(addr, symbol->size, right->first)) 14013 break; 14014 symbol_locations_.erase(right); 14015 } 14016 } 14017 14018 14019 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 14020 switch (event->type) { 14021 case v8::JitCodeEvent::CODE_ADDED: { 14022 CHECK(event->code_start != NULL); 14023 CHECK_NE(0, static_cast<int>(event->code_len)); 14024 CHECK(event->name.str != NULL); 14025 size_t symbol_id = symbols_.size(); 14026 14027 // Record the new symbol. 14028 SymbolInfo& info = symbols_[symbol_id]; 14029 info.id = symbol_id; 14030 info.size = event->code_len; 14031 info.name.assign(event->name.str, event->name.str + event->name.len); 14032 14033 // And record it's location. 14034 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 14035 } 14036 break; 14037 14038 case v8::JitCodeEvent::CODE_MOVED: { 14039 // We would like to never see code move that we haven't seen before, 14040 // but the code creation event does not happen until the line endings 14041 // have been calculated (this is so that we can report the line in the 14042 // script at which the function source is found, see 14043 // Compiler::RecordFunctionCompilation) and the line endings 14044 // calculations can cause a GC, which can move the newly created code 14045 // before its existence can be logged. 14046 SymbolLocationMap::iterator it( 14047 symbol_locations_.find( 14048 reinterpret_cast<i::Address>(event->code_start))); 14049 if (it != symbol_locations_.end()) { 14050 // Found a symbol at this location, move it. 14051 SymbolInfo* info = it->second; 14052 symbol_locations_.erase(it); 14053 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 14054 info); 14055 } 14056 } 14057 default: 14058 break; 14059 } 14060 } 14061 14062 void SetFunctionEntryHookTest::OnEntryHook( 14063 uintptr_t function, uintptr_t return_addr_location) { 14064 // Get the function's code object. 14065 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 14066 reinterpret_cast<i::Address>(function)); 14067 CHECK(function_code != NULL); 14068 14069 // Then try and look up the caller's code object. 14070 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 14071 14072 // Count the invocation. 14073 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 14074 SymbolInfo* function_symbol = 14075 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 14076 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 14077 14078 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 14079 // Check that we have a symbol for the "bar" function at the right location. 14080 SymbolLocationMap::iterator it( 14081 symbol_locations_.find(function_code->instruction_start())); 14082 CHECK(it != symbol_locations_.end()); 14083 } 14084 14085 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 14086 // Check that we have a symbol for "foo" at the right location. 14087 SymbolLocationMap::iterator it( 14088 symbol_locations_.find(function_code->instruction_start())); 14089 CHECK(it != symbol_locations_.end()); 14090 } 14091 } 14092 14093 14094 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 14095 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 14096 // Do we have a direct hit on a symbol? 14097 if (it != symbol_locations_.end()) { 14098 if (it->first == addr) 14099 return it->second; 14100 } 14101 14102 // If not a direct hit, it'll have to be the previous symbol. 14103 if (it == symbol_locations_.begin()) 14104 return NULL; 14105 14106 --it; 14107 size_t offs = addr - it->first; 14108 if (offs < it->second->size) 14109 return it->second; 14110 14111 return NULL; 14112 } 14113 14114 14115 int SetFunctionEntryHookTest::CountInvocations( 14116 const char* caller_name, const char* function_name) { 14117 InvocationMap::iterator it(invocations_.begin()); 14118 int invocations = 0; 14119 for (; it != invocations_.end(); ++it) { 14120 SymbolInfo* caller = it->first.first; 14121 SymbolInfo* function = it->first.second; 14122 14123 // Filter out non-matching functions. 14124 if (function_name != NULL) { 14125 if (function->name.find(function_name) == std::string::npos) 14126 continue; 14127 } 14128 14129 // Filter out non-matching callers. 14130 if (caller_name != NULL) { 14131 if (caller == NULL) 14132 continue; 14133 if (caller->name.find(caller_name) == std::string::npos) 14134 continue; 14135 } 14136 14137 // It matches add the invocation count to the tally. 14138 invocations += it->second; 14139 } 14140 14141 return invocations; 14142 } 14143 14144 14145 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 14146 v8::HandleScope outer(isolate); 14147 v8::Local<Context> env = Context::New(isolate); 14148 env->Enter(); 14149 14150 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14151 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback)); 14152 env->Global()->Set(v8_str("obj"), t->NewInstance()); 14153 14154 const char* script = 14155 "function bar() {\n" 14156 " var sum = 0;\n" 14157 " for (i = 0; i < 100; ++i)\n" 14158 " sum = foo(i);\n" 14159 " return sum;\n" 14160 "}\n" 14161 "function foo(i) { return i * i; }\n" 14162 "// Invoke on the runtime function.\n" 14163 "obj.asdf()"; 14164 CompileRun(script); 14165 bar_func_ = i::Handle<i::JSFunction>::cast( 14166 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar")))); 14167 DCHECK(!bar_func_.is_null()); 14168 14169 foo_func_ = 14170 i::Handle<i::JSFunction>::cast( 14171 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo")))); 14172 DCHECK(!foo_func_.is_null()); 14173 14174 v8::Handle<v8::Value> value = CompileRun("bar();"); 14175 CHECK(value->IsNumber()); 14176 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14177 14178 // Test the optimized codegen path. 14179 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 14180 "bar();"); 14181 CHECK(value->IsNumber()); 14182 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 14183 14184 env->Exit(); 14185 } 14186 14187 14188 void SetFunctionEntryHookTest::RunTest() { 14189 // Work in a new isolate throughout. 14190 v8::Isolate::CreateParams create_params; 14191 create_params.entry_hook = EntryHook; 14192 create_params.code_event_handler = JitEvent; 14193 v8::Isolate* isolate = v8::Isolate::New(create_params); 14194 14195 { 14196 v8::Isolate::Scope scope(isolate); 14197 14198 RunLoopInNewEnv(isolate); 14199 14200 // Check the exepected invocation counts. 14201 CHECK_EQ(2, CountInvocations(NULL, "bar")); 14202 CHECK_EQ(200, CountInvocations("bar", "foo")); 14203 CHECK_EQ(200, CountInvocations(NULL, "foo")); 14204 14205 // Verify that we have an entry hook on some specific stubs. 14206 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 14207 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 14208 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 14209 } 14210 isolate->Dispose(); 14211 14212 Reset(); 14213 14214 // Make sure a second isolate is unaffected by the previous entry hook. 14215 isolate = v8::Isolate::New(); 14216 { 14217 v8::Isolate::Scope scope(isolate); 14218 14219 // Reset the entry count to zero and set the entry hook. 14220 RunLoopInNewEnv(isolate); 14221 14222 // We should record no invocations in this isolate. 14223 CHECK_EQ(0, static_cast<int>(invocations_.size())); 14224 } 14225 14226 isolate->Dispose(); 14227 } 14228 14229 14230 TEST(SetFunctionEntryHook) { 14231 // FunctionEntryHook does not work well with experimental natives. 14232 // Experimental natives are compiled during snapshot deserialization. 14233 // This test breaks because InstallGetter (function from snapshot that 14234 // only gets called from experimental natives) is compiled with entry hooks. 14235 i::FLAG_allow_natives_syntax = true; 14236 i::FLAG_use_inlining = false; 14237 14238 SetFunctionEntryHookTest test; 14239 test.RunTest(); 14240 } 14241 14242 14243 static i::HashMap* code_map = NULL; 14244 static i::HashMap* jitcode_line_info = NULL; 14245 static int saw_bar = 0; 14246 static int move_events = 0; 14247 14248 14249 static bool FunctionNameIs(const char* expected, 14250 const v8::JitCodeEvent* event) { 14251 // Log lines for functions are of the general form: 14252 // "LazyCompile:<type><function_name>", where the type is one of 14253 // "*", "~" or "". 14254 static const char kPreamble[] = "LazyCompile:"; 14255 static size_t kPreambleLen = sizeof(kPreamble) - 1; 14256 14257 if (event->name.len < sizeof(kPreamble) - 1 || 14258 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 14259 return false; 14260 } 14261 14262 const char* tail = event->name.str + kPreambleLen; 14263 size_t tail_len = event->name.len - kPreambleLen; 14264 size_t expected_len = strlen(expected); 14265 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 14266 --tail_len; 14267 ++tail; 14268 } 14269 14270 // Check for tails like 'bar :1'. 14271 if (tail_len > expected_len + 2 && 14272 tail[expected_len] == ' ' && 14273 tail[expected_len + 1] == ':' && 14274 tail[expected_len + 2] && 14275 !strncmp(tail, expected, expected_len)) { 14276 return true; 14277 } 14278 14279 if (tail_len != expected_len) 14280 return false; 14281 14282 return strncmp(tail, expected, expected_len) == 0; 14283 } 14284 14285 14286 static void event_handler(const v8::JitCodeEvent* event) { 14287 CHECK(event != NULL); 14288 CHECK(code_map != NULL); 14289 CHECK(jitcode_line_info != NULL); 14290 14291 class DummyJitCodeLineInfo { 14292 }; 14293 14294 switch (event->type) { 14295 case v8::JitCodeEvent::CODE_ADDED: { 14296 CHECK(event->code_start != NULL); 14297 CHECK_NE(0, static_cast<int>(event->code_len)); 14298 CHECK(event->name.str != NULL); 14299 i::HashMap::Entry* entry = 14300 code_map->Lookup(event->code_start, 14301 i::ComputePointerHash(event->code_start), 14302 true); 14303 entry->value = reinterpret_cast<void*>(event->code_len); 14304 14305 if (FunctionNameIs("bar", event)) { 14306 ++saw_bar; 14307 } 14308 } 14309 break; 14310 14311 case v8::JitCodeEvent::CODE_MOVED: { 14312 uint32_t hash = i::ComputePointerHash(event->code_start); 14313 // We would like to never see code move that we haven't seen before, 14314 // but the code creation event does not happen until the line endings 14315 // have been calculated (this is so that we can report the line in the 14316 // script at which the function source is found, see 14317 // Compiler::RecordFunctionCompilation) and the line endings 14318 // calculations can cause a GC, which can move the newly created code 14319 // before its existence can be logged. 14320 i::HashMap::Entry* entry = 14321 code_map->Lookup(event->code_start, hash, false); 14322 if (entry != NULL) { 14323 ++move_events; 14324 14325 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 14326 code_map->Remove(event->code_start, hash); 14327 14328 entry = code_map->Lookup(event->new_code_start, 14329 i::ComputePointerHash(event->new_code_start), 14330 true); 14331 CHECK(entry != NULL); 14332 entry->value = reinterpret_cast<void*>(event->code_len); 14333 } 14334 } 14335 break; 14336 14337 case v8::JitCodeEvent::CODE_REMOVED: 14338 // Object/code removal events are currently not dispatched from the GC. 14339 CHECK(false); 14340 break; 14341 14342 // For CODE_START_LINE_INFO_RECORDING event, we will create one 14343 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 14344 // record it in jitcode_line_info. 14345 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 14346 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 14347 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 14348 temp_event->user_data = line_info; 14349 i::HashMap::Entry* entry = 14350 jitcode_line_info->Lookup(line_info, 14351 i::ComputePointerHash(line_info), 14352 true); 14353 entry->value = reinterpret_cast<void*>(line_info); 14354 } 14355 break; 14356 // For these two events, we will check whether the event->user_data 14357 // data structure is created before during CODE_START_LINE_INFO_RECORDING 14358 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 14359 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 14360 CHECK(event->user_data != NULL); 14361 uint32_t hash = i::ComputePointerHash(event->user_data); 14362 i::HashMap::Entry* entry = 14363 jitcode_line_info->Lookup(event->user_data, hash, false); 14364 CHECK(entry != NULL); 14365 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 14366 } 14367 break; 14368 14369 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 14370 CHECK(event->user_data != NULL); 14371 uint32_t hash = i::ComputePointerHash(event->user_data); 14372 i::HashMap::Entry* entry = 14373 jitcode_line_info->Lookup(event->user_data, hash, false); 14374 CHECK(entry != NULL); 14375 } 14376 break; 14377 14378 default: 14379 // Impossible event. 14380 CHECK(false); 14381 break; 14382 } 14383 } 14384 14385 14386 UNINITIALIZED_TEST(SetJitCodeEventHandler) { 14387 i::FLAG_stress_compaction = true; 14388 i::FLAG_incremental_marking = false; 14389 if (i::FLAG_never_compact) return; 14390 const char* script = 14391 "function bar() {" 14392 " var sum = 0;" 14393 " for (i = 0; i < 100; ++i)" 14394 " sum = foo(i);" 14395 " return sum;" 14396 "}" 14397 "function foo(i) { return i * i; };" 14398 "bar();"; 14399 14400 // Run this test in a new isolate to make sure we don't 14401 // have remnants of state from other code. 14402 v8::Isolate* isolate = v8::Isolate::New(); 14403 isolate->Enter(); 14404 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 14405 i::Heap* heap = i_isolate->heap(); 14406 14407 { 14408 v8::HandleScope scope(isolate); 14409 i::HashMap code(MatchPointers); 14410 code_map = &code; 14411 14412 i::HashMap lineinfo(MatchPointers); 14413 jitcode_line_info = &lineinfo; 14414 14415 saw_bar = 0; 14416 move_events = 0; 14417 14418 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 14419 14420 // Generate new code objects sparsely distributed across several 14421 // different fragmented code-space pages. 14422 const int kIterations = 10; 14423 for (int i = 0; i < kIterations; ++i) { 14424 LocalContext env(isolate); 14425 i::AlwaysAllocateScope always_allocate(i_isolate); 14426 SimulateFullSpace(heap->code_space()); 14427 CompileRun(script); 14428 14429 // Keep a strong reference to the code object in the handle scope. 14430 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast( 14431 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code()); 14432 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast( 14433 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code()); 14434 14435 // Clear the compilation cache to get more wastage. 14436 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear(); 14437 } 14438 14439 // Force code movement. 14440 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler"); 14441 14442 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14443 14444 CHECK_LE(kIterations, saw_bar); 14445 CHECK_LT(0, move_events); 14446 14447 code_map = NULL; 14448 jitcode_line_info = NULL; 14449 } 14450 14451 isolate->Exit(); 14452 isolate->Dispose(); 14453 14454 // Do this in a new isolate. 14455 isolate = v8::Isolate::New(); 14456 isolate->Enter(); 14457 14458 // Verify that we get callbacks for existing code objects when we 14459 // request enumeration of existing code. 14460 { 14461 v8::HandleScope scope(isolate); 14462 LocalContext env(isolate); 14463 CompileRun(script); 14464 14465 // Now get code through initial iteration. 14466 i::HashMap code(MatchPointers); 14467 code_map = &code; 14468 14469 i::HashMap lineinfo(MatchPointers); 14470 jitcode_line_info = &lineinfo; 14471 14472 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, 14473 event_handler); 14474 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 14475 14476 jitcode_line_info = NULL; 14477 // We expect that we got some events. Note that if we could get code removal 14478 // notifications, we could compare two collections, one created by listening 14479 // from the time of creation of an isolate, and the other by subscribing 14480 // with EnumExisting. 14481 CHECK_LT(0, code.occupancy()); 14482 14483 code_map = NULL; 14484 } 14485 14486 isolate->Exit(); 14487 isolate->Dispose(); 14488 } 14489 14490 14491 THREADED_TEST(ExternalAllocatedMemory) { 14492 v8::Isolate* isolate = CcTest::isolate(); 14493 v8::HandleScope outer(isolate); 14494 v8::Local<Context> env(Context::New(isolate)); 14495 CHECK(!env.IsEmpty()); 14496 const int64_t kSize = 1024*1024; 14497 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0); 14498 CHECK_EQ(baseline + kSize, 14499 isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); 14500 CHECK_EQ(baseline, 14501 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); 14502 } 14503 14504 14505 // Regression test for issue 54, object templates with internal fields 14506 // but no accessors or interceptors did not get their internal field 14507 // count set on instances. 14508 THREADED_TEST(Regress54) { 14509 LocalContext context; 14510 v8::Isolate* isolate = context->GetIsolate(); 14511 v8::HandleScope outer(isolate); 14512 static v8::Persistent<v8::ObjectTemplate> templ; 14513 if (templ.IsEmpty()) { 14514 v8::EscapableHandleScope inner(isolate); 14515 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate); 14516 local->SetInternalFieldCount(1); 14517 templ.Reset(isolate, inner.Escape(local)); 14518 } 14519 v8::Handle<v8::Object> result = 14520 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance(); 14521 CHECK_EQ(1, result->InternalFieldCount()); 14522 } 14523 14524 14525 // If part of the threaded tests, this test makes ThreadingTest fail 14526 // on mac. 14527 TEST(CatchStackOverflow) { 14528 LocalContext context; 14529 v8::HandleScope scope(context->GetIsolate()); 14530 v8::TryCatch try_catch; 14531 v8::Handle<v8::Value> result = CompileRun( 14532 "function f() {" 14533 " return f();" 14534 "}" 14535 "" 14536 "f();"); 14537 CHECK(result.IsEmpty()); 14538 } 14539 14540 14541 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, 14542 const char* resource_name, 14543 int line_offset) { 14544 v8::HandleScope scope(CcTest::isolate()); 14545 v8::TryCatch try_catch; 14546 v8::Handle<v8::Value> result = script->Run(); 14547 CHECK(result.IsEmpty()); 14548 CHECK(try_catch.HasCaught()); 14549 v8::Handle<v8::Message> message = try_catch.Message(); 14550 CHECK(!message.IsEmpty()); 14551 CHECK_EQ(10 + line_offset, message->GetLineNumber()); 14552 CHECK_EQ(91, message->GetStartPosition()); 14553 CHECK_EQ(92, message->GetEndPosition()); 14554 CHECK_EQ(2, message->GetStartColumn()); 14555 CHECK_EQ(3, message->GetEndColumn()); 14556 v8::String::Utf8Value line(message->GetSourceLine()); 14557 CHECK_EQ(" throw 'nirk';", *line); 14558 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName()); 14559 CHECK_EQ(resource_name, *name); 14560 } 14561 14562 14563 THREADED_TEST(TryCatchSourceInfo) { 14564 LocalContext context; 14565 v8::HandleScope scope(context->GetIsolate()); 14566 v8::Local<v8::String> source = v8_str( 14567 "function Foo() {\n" 14568 " return Bar();\n" 14569 "}\n" 14570 "\n" 14571 "function Bar() {\n" 14572 " return Baz();\n" 14573 "}\n" 14574 "\n" 14575 "function Baz() {\n" 14576 " throw 'nirk';\n" 14577 "}\n" 14578 "\n" 14579 "Foo();\n"); 14580 14581 const char* resource_name; 14582 v8::Handle<v8::Script> script; 14583 resource_name = "test.js"; 14584 script = CompileWithOrigin(source, resource_name); 14585 CheckTryCatchSourceInfo(script, resource_name, 0); 14586 14587 resource_name = "test1.js"; 14588 v8::ScriptOrigin origin1( 14589 v8::String::NewFromUtf8(context->GetIsolate(), resource_name)); 14590 script = v8::Script::Compile(source, &origin1); 14591 CheckTryCatchSourceInfo(script, resource_name, 0); 14592 14593 resource_name = "test2.js"; 14594 v8::ScriptOrigin origin2( 14595 v8::String::NewFromUtf8(context->GetIsolate(), resource_name), 14596 v8::Integer::New(context->GetIsolate(), 7)); 14597 script = v8::Script::Compile(source, &origin2); 14598 CheckTryCatchSourceInfo(script, resource_name, 7); 14599 } 14600 14601 14602 THREADED_TEST(CompilationCache) { 14603 LocalContext context; 14604 v8::HandleScope scope(context->GetIsolate()); 14605 v8::Handle<v8::String> source0 = 14606 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14607 v8::Handle<v8::String> source1 = 14608 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14609 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js"); 14610 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js"); 14611 v8::Handle<v8::Script> script2 = 14612 v8::Script::Compile(source0); // different origin 14613 CHECK_EQ(1234, script0->Run()->Int32Value()); 14614 CHECK_EQ(1234, script1->Run()->Int32Value()); 14615 CHECK_EQ(1234, script2->Run()->Int32Value()); 14616 } 14617 14618 14619 static void FunctionNameCallback( 14620 const v8::FunctionCallbackInfo<v8::Value>& args) { 14621 ApiTestFuzzer::Fuzz(); 14622 args.GetReturnValue().Set(v8_num(42)); 14623 } 14624 14625 14626 THREADED_TEST(CallbackFunctionName) { 14627 LocalContext context; 14628 v8::Isolate* isolate = context->GetIsolate(); 14629 v8::HandleScope scope(isolate); 14630 Local<ObjectTemplate> t = ObjectTemplate::New(isolate); 14631 t->Set(v8_str("asdf"), 14632 v8::FunctionTemplate::New(isolate, FunctionNameCallback)); 14633 context->Global()->Set(v8_str("obj"), t->NewInstance()); 14634 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name"); 14635 CHECK(value->IsString()); 14636 v8::String::Utf8Value name(value); 14637 CHECK_EQ("asdf", *name); 14638 } 14639 14640 14641 THREADED_TEST(DateAccess) { 14642 LocalContext context; 14643 v8::HandleScope scope(context->GetIsolate()); 14644 v8::Handle<v8::Value> date = 14645 v8::Date::New(context->GetIsolate(), 1224744689038.0); 14646 CHECK(date->IsDate()); 14647 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 14648 } 14649 14650 14651 void CheckProperties(v8::Isolate* isolate, 14652 v8::Handle<v8::Value> val, 14653 int elmc, 14654 const char* elmv[]) { 14655 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14656 v8::Handle<v8::Array> props = obj->GetPropertyNames(); 14657 CHECK_EQ(elmc, props->Length()); 14658 for (int i = 0; i < elmc; i++) { 14659 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i))); 14660 CHECK_EQ(elmv[i], *elm); 14661 } 14662 } 14663 14664 14665 void CheckOwnProperties(v8::Isolate* isolate, 14666 v8::Handle<v8::Value> val, 14667 int elmc, 14668 const char* elmv[]) { 14669 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14670 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames(); 14671 CHECK_EQ(elmc, props->Length()); 14672 for (int i = 0; i < elmc; i++) { 14673 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i))); 14674 CHECK_EQ(elmv[i], *elm); 14675 } 14676 } 14677 14678 14679 THREADED_TEST(PropertyEnumeration) { 14680 LocalContext context; 14681 v8::Isolate* isolate = context->GetIsolate(); 14682 v8::HandleScope scope(isolate); 14683 v8::Handle<v8::Value> obj = CompileRun( 14684 "var result = [];" 14685 "result[0] = {};" 14686 "result[1] = {a: 1, b: 2};" 14687 "result[2] = [1, 2, 3];" 14688 "var proto = {x: 1, y: 2, z: 3};" 14689 "var x = { __proto__: proto, w: 0, z: 1 };" 14690 "result[3] = x;" 14691 "result;"); 14692 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14693 CHECK_EQ(4, elms->Length()); 14694 int elmc0 = 0; 14695 const char** elmv0 = NULL; 14696 CheckProperties( 14697 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14698 CheckOwnProperties( 14699 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14700 int elmc1 = 2; 14701 const char* elmv1[] = {"a", "b"}; 14702 CheckProperties( 14703 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1); 14704 CheckOwnProperties( 14705 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1); 14706 int elmc2 = 3; 14707 const char* elmv2[] = {"0", "1", "2"}; 14708 CheckProperties( 14709 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2); 14710 CheckOwnProperties( 14711 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2); 14712 int elmc3 = 4; 14713 const char* elmv3[] = {"w", "z", "x", "y"}; 14714 CheckProperties( 14715 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3); 14716 int elmc4 = 2; 14717 const char* elmv4[] = {"w", "z"}; 14718 CheckOwnProperties( 14719 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4); 14720 } 14721 14722 14723 THREADED_TEST(PropertyEnumeration2) { 14724 LocalContext context; 14725 v8::Isolate* isolate = context->GetIsolate(); 14726 v8::HandleScope scope(isolate); 14727 v8::Handle<v8::Value> obj = CompileRun( 14728 "var result = [];" 14729 "result[0] = {};" 14730 "result[1] = {a: 1, b: 2};" 14731 "result[2] = [1, 2, 3];" 14732 "var proto = {x: 1, y: 2, z: 3};" 14733 "var x = { __proto__: proto, w: 0, z: 1 };" 14734 "result[3] = x;" 14735 "result;"); 14736 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14737 CHECK_EQ(4, elms->Length()); 14738 int elmc0 = 0; 14739 const char** elmv0 = NULL; 14740 CheckProperties(isolate, 14741 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0); 14742 14743 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0)); 14744 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames(); 14745 CHECK_EQ(0, props->Length()); 14746 for (uint32_t i = 0; i < props->Length(); i++) { 14747 printf("p[%d]\n", i); 14748 } 14749 } 14750 14751 static bool NamedSetAccessBlocker(Local<v8::Object> obj, 14752 Local<Value> name, 14753 v8::AccessType type, 14754 Local<Value> data) { 14755 return type != v8::ACCESS_SET; 14756 } 14757 14758 14759 static bool IndexedSetAccessBlocker(Local<v8::Object> obj, 14760 uint32_t key, 14761 v8::AccessType type, 14762 Local<Value> data) { 14763 return type != v8::ACCESS_SET; 14764 } 14765 14766 14767 THREADED_TEST(DisableAccessChecksWhileConfiguring) { 14768 LocalContext context; 14769 v8::Isolate* isolate = context->GetIsolate(); 14770 v8::HandleScope scope(isolate); 14771 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 14772 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14773 IndexedSetAccessBlocker); 14774 templ->Set(v8_str("x"), v8::True(isolate)); 14775 Local<v8::Object> instance = templ->NewInstance(); 14776 context->Global()->Set(v8_str("obj"), instance); 14777 Local<Value> value = CompileRun("obj.x"); 14778 CHECK(value->BooleanValue()); 14779 } 14780 14781 14782 static bool NamedGetAccessBlocker(Local<v8::Object> obj, 14783 Local<Value> name, 14784 v8::AccessType type, 14785 Local<Value> data) { 14786 return false; 14787 } 14788 14789 14790 static bool IndexedGetAccessBlocker(Local<v8::Object> obj, 14791 uint32_t key, 14792 v8::AccessType type, 14793 Local<Value> data) { 14794 return false; 14795 } 14796 14797 14798 14799 THREADED_TEST(AccessChecksReenabledCorrectly) { 14800 LocalContext context; 14801 v8::Isolate* isolate = context->GetIsolate(); 14802 v8::HandleScope scope(isolate); 14803 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 14804 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14805 IndexedGetAccessBlocker); 14806 templ->Set(v8_str("a"), v8_str("a")); 14807 // Add more than 8 (see kMaxFastProperties) properties 14808 // so that the constructor will force copying map. 14809 // Cannot sprintf, gcc complains unsafety. 14810 char buf[4]; 14811 for (char i = '0'; i <= '9' ; i++) { 14812 buf[0] = i; 14813 for (char j = '0'; j <= '9'; j++) { 14814 buf[1] = j; 14815 for (char k = '0'; k <= '9'; k++) { 14816 buf[2] = k; 14817 buf[3] = 0; 14818 templ->Set(v8_str(buf), v8::Number::New(isolate, k)); 14819 } 14820 } 14821 } 14822 14823 Local<v8::Object> instance_1 = templ->NewInstance(); 14824 context->Global()->Set(v8_str("obj_1"), instance_1); 14825 14826 Local<Value> value_1 = CompileRun("obj_1.a"); 14827 CHECK(value_1.IsEmpty()); 14828 14829 Local<v8::Object> instance_2 = templ->NewInstance(); 14830 context->Global()->Set(v8_str("obj_2"), instance_2); 14831 14832 Local<Value> value_2 = CompileRun("obj_2.a"); 14833 CHECK(value_2.IsEmpty()); 14834 } 14835 14836 14837 // This tests that access check information remains on the global 14838 // object template when creating contexts. 14839 THREADED_TEST(AccessControlRepeatedContextCreation) { 14840 v8::Isolate* isolate = CcTest::isolate(); 14841 v8::HandleScope handle_scope(isolate); 14842 v8::Handle<v8::ObjectTemplate> global_template = 14843 v8::ObjectTemplate::New(isolate); 14844 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14845 IndexedSetAccessBlocker); 14846 i::Handle<i::ObjectTemplateInfo> internal_template = 14847 v8::Utils::OpenHandle(*global_template); 14848 CHECK(!internal_template->constructor()->IsUndefined()); 14849 i::Handle<i::FunctionTemplateInfo> constructor( 14850 i::FunctionTemplateInfo::cast(internal_template->constructor())); 14851 CHECK(!constructor->access_check_info()->IsUndefined()); 14852 v8::Local<Context> context0(Context::New(isolate, NULL, global_template)); 14853 CHECK(!context0.IsEmpty()); 14854 CHECK(!constructor->access_check_info()->IsUndefined()); 14855 } 14856 14857 14858 THREADED_TEST(TurnOnAccessCheck) { 14859 v8::Isolate* isolate = CcTest::isolate(); 14860 v8::HandleScope handle_scope(isolate); 14861 14862 // Create an environment with access check to the global object disabled by 14863 // default. 14864 v8::Handle<v8::ObjectTemplate> global_template = 14865 v8::ObjectTemplate::New(isolate); 14866 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14867 IndexedGetAccessBlocker, 14868 v8::Handle<v8::Value>(), 14869 false); 14870 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14871 Context::Scope context_scope(context); 14872 14873 // Set up a property and a number of functions. 14874 context->Global()->Set(v8_str("a"), v8_num(1)); 14875 CompileRun("function f1() {return a;}" 14876 "function f2() {return a;}" 14877 "function g1() {return h();}" 14878 "function g2() {return h();}" 14879 "function h() {return 1;}"); 14880 Local<Function> f1 = 14881 Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14882 Local<Function> f2 = 14883 Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14884 Local<Function> g1 = 14885 Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14886 Local<Function> g2 = 14887 Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14888 Local<Function> h = 14889 Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14890 14891 // Get the global object. 14892 v8::Handle<v8::Object> global = context->Global(); 14893 14894 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14895 // uses the runtime system to retreive property a whereas f2 uses global load 14896 // inline cache. 14897 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14898 for (int i = 0; i < 4; i++) { 14899 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14900 } 14901 14902 // Same for g1 and g2. 14903 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14904 for (int i = 0; i < 4; i++) { 14905 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14906 } 14907 14908 // Detach the global and turn on access check. 14909 Local<Object> hidden_global = Local<Object>::Cast( 14910 context->Global()->GetPrototype()); 14911 context->DetachGlobal(); 14912 hidden_global->TurnOnAccessCheck(); 14913 14914 // Failing access check results in exception. 14915 CHECK(f1->Call(global, 0, NULL).IsEmpty()); 14916 CHECK(f2->Call(global, 0, NULL).IsEmpty()); 14917 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14918 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14919 14920 // No failing access check when just returning a constant. 14921 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 14922 } 14923 14924 14925 static const char* kPropertyA = "a"; 14926 static const char* kPropertyH = "h"; 14927 14928 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, 14929 Local<Value> name, 14930 v8::AccessType type, 14931 Local<Value> data) { 14932 if (!name->IsString()) return false; 14933 i::Handle<i::String> name_handle = 14934 v8::Utils::OpenHandle(String::Cast(*name)); 14935 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA)) 14936 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH)); 14937 } 14938 14939 14940 THREADED_TEST(TurnOnAccessCheckAndRecompile) { 14941 v8::Isolate* isolate = CcTest::isolate(); 14942 v8::HandleScope handle_scope(isolate); 14943 14944 // Create an environment with access check to the global object disabled by 14945 // default. When the registered access checker will block access to properties 14946 // a and h. 14947 v8::Handle<v8::ObjectTemplate> global_template = 14948 v8::ObjectTemplate::New(isolate); 14949 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, 14950 IndexedGetAccessBlocker, 14951 v8::Handle<v8::Value>(), 14952 false); 14953 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14954 Context::Scope context_scope(context); 14955 14956 // Set up a property and a number of functions. 14957 context->Global()->Set(v8_str("a"), v8_num(1)); 14958 static const char* source = "function f1() {return a;}" 14959 "function f2() {return a;}" 14960 "function g1() {return h();}" 14961 "function g2() {return h();}" 14962 "function h() {return 1;}"; 14963 14964 CompileRun(source); 14965 Local<Function> f1; 14966 Local<Function> f2; 14967 Local<Function> g1; 14968 Local<Function> g2; 14969 Local<Function> h; 14970 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14971 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14972 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14973 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14974 h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14975 14976 // Get the global object. 14977 v8::Handle<v8::Object> global = context->Global(); 14978 14979 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14980 // uses the runtime system to retreive property a whereas f2 uses global load 14981 // inline cache. 14982 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14983 for (int i = 0; i < 4; i++) { 14984 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14985 } 14986 14987 // Same for g1 and g2. 14988 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14989 for (int i = 0; i < 4; i++) { 14990 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14991 } 14992 14993 // Detach the global and turn on access check now blocking access to property 14994 // a and function h. 14995 Local<Object> hidden_global = Local<Object>::Cast( 14996 context->Global()->GetPrototype()); 14997 context->DetachGlobal(); 14998 hidden_global->TurnOnAccessCheck(); 14999 15000 // Failing access check results in exception. 15001 CHECK(f1->Call(global, 0, NULL).IsEmpty()); 15002 CHECK(f2->Call(global, 0, NULL).IsEmpty()); 15003 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 15004 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 15005 15006 // No failing access check when just returning a constant. 15007 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 15008 15009 // Now compile the source again. And get the newly compiled functions, except 15010 // for h for which access is blocked. 15011 CompileRun(source); 15012 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1"))); 15013 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2"))); 15014 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1"))); 15015 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2"))); 15016 CHECK(hidden_global->Get(v8_str("h")).IsEmpty()); 15017 15018 // Failing access check results in exception. 15019 v8::Local<v8::Value> result = f1->Call(global, 0, NULL); 15020 CHECK(result.IsEmpty()); 15021 CHECK(f1->Call(global, 0, NULL).IsEmpty()); 15022 CHECK(f2->Call(global, 0, NULL).IsEmpty()); 15023 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 15024 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 15025 } 15026 15027 15028 // Tests that ScriptData can be serialized and deserialized. 15029 TEST(PreCompileSerialization) { 15030 v8::V8::Initialize(); 15031 LocalContext env; 15032 v8::Isolate* isolate = env->GetIsolate(); 15033 HandleScope handle_scope(isolate); 15034 15035 i::FLAG_min_preparse_length = 0; 15036 const char* script = "function foo(a) { return a+1; }"; 15037 v8::ScriptCompiler::Source source(v8_str(script)); 15038 v8::ScriptCompiler::Compile(isolate, &source, 15039 v8::ScriptCompiler::kProduceParserCache); 15040 // Serialize. 15041 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData(); 15042 i::byte* serialized_data = i::NewArray<i::byte>(cd->length); 15043 i::MemCopy(serialized_data, cd->data, cd->length); 15044 15045 // Deserialize. 15046 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length); 15047 15048 // Verify that the original is the same as the deserialized. 15049 CHECK_EQ(cd->length, deserialized->length()); 15050 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length)); 15051 15052 delete deserialized; 15053 i::DeleteArray(serialized_data); 15054 } 15055 15056 15057 // This tests that we do not allow dictionary load/call inline caches 15058 // to use functions that have not yet been compiled. The potential 15059 // problem of loading a function that has not yet been compiled can 15060 // arise because we share code between contexts via the compilation 15061 // cache. 15062 THREADED_TEST(DictionaryICLoadedFunction) { 15063 v8::HandleScope scope(CcTest::isolate()); 15064 // Test LoadIC. 15065 for (int i = 0; i < 2; i++) { 15066 LocalContext context; 15067 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 15068 context->Global()->Delete(v8_str("tmp")); 15069 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 15070 } 15071 // Test CallIC. 15072 for (int i = 0; i < 2; i++) { 15073 LocalContext context; 15074 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 15075 context->Global()->Delete(v8_str("tmp")); 15076 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 15077 } 15078 } 15079 15080 15081 // Test that cross-context new calls use the context of the callee to 15082 // create the new JavaScript object. 15083 THREADED_TEST(CrossContextNew) { 15084 v8::Isolate* isolate = CcTest::isolate(); 15085 v8::HandleScope scope(isolate); 15086 v8::Local<Context> context0 = Context::New(isolate); 15087 v8::Local<Context> context1 = Context::New(isolate); 15088 15089 // Allow cross-domain access. 15090 Local<String> token = v8_str("<security token>"); 15091 context0->SetSecurityToken(token); 15092 context1->SetSecurityToken(token); 15093 15094 // Set an 'x' property on the Object prototype and define a 15095 // constructor function in context0. 15096 context0->Enter(); 15097 CompileRun("Object.prototype.x = 42; function C() {};"); 15098 context0->Exit(); 15099 15100 // Call the constructor function from context0 and check that the 15101 // result has the 'x' property. 15102 context1->Enter(); 15103 context1->Global()->Set(v8_str("other"), context0->Global()); 15104 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 15105 CHECK(value->IsInt32()); 15106 CHECK_EQ(42, value->Int32Value()); 15107 context1->Exit(); 15108 } 15109 15110 15111 // Verify that we can clone an object 15112 TEST(ObjectClone) { 15113 LocalContext env; 15114 v8::Isolate* isolate = env->GetIsolate(); 15115 v8::HandleScope scope(isolate); 15116 15117 const char* sample = 15118 "var rv = {};" \ 15119 "rv.alpha = 'hello';" \ 15120 "rv.beta = 123;" \ 15121 "rv;"; 15122 15123 // Create an object, verify basics. 15124 Local<Value> val = CompileRun(sample); 15125 CHECK(val->IsObject()); 15126 Local<v8::Object> obj = val.As<v8::Object>(); 15127 obj->Set(v8_str("gamma"), v8_str("cloneme")); 15128 15129 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); 15130 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta"))); 15131 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma"))); 15132 15133 // Clone it. 15134 Local<v8::Object> clone = obj->Clone(); 15135 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 15136 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta"))); 15137 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 15138 15139 // Set a property on the clone, verify each object. 15140 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456)); 15141 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta"))); 15142 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta"))); 15143 } 15144 15145 15146 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource { 15147 public: 15148 explicit OneByteVectorResource(i::Vector<const char> vector) 15149 : data_(vector) {} 15150 virtual ~OneByteVectorResource() {} 15151 virtual size_t length() const { return data_.length(); } 15152 virtual const char* data() const { return data_.start(); } 15153 private: 15154 i::Vector<const char> data_; 15155 }; 15156 15157 15158 class UC16VectorResource : public v8::String::ExternalStringResource { 15159 public: 15160 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 15161 : data_(vector) {} 15162 virtual ~UC16VectorResource() {} 15163 virtual size_t length() const { return data_.length(); } 15164 virtual const i::uc16* data() const { return data_.start(); } 15165 private: 15166 i::Vector<const i::uc16> data_; 15167 }; 15168 15169 15170 static void MorphAString(i::String* string, 15171 OneByteVectorResource* one_byte_resource, 15172 UC16VectorResource* uc16_resource) { 15173 CHECK(i::StringShape(string).IsExternal()); 15174 if (string->IsOneByteRepresentation()) { 15175 // Check old map is not internalized or long. 15176 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map()); 15177 // Morph external string to be TwoByte string. 15178 string->set_map(CcTest::heap()->external_string_map()); 15179 i::ExternalTwoByteString* morphed = 15180 i::ExternalTwoByteString::cast(string); 15181 morphed->set_resource(uc16_resource); 15182 } else { 15183 // Check old map is not internalized or long. 15184 CHECK(string->map() == CcTest::heap()->external_string_map()); 15185 // Morph external string to be one-byte string. 15186 string->set_map(CcTest::heap()->external_one_byte_string_map()); 15187 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string); 15188 morphed->set_resource(one_byte_resource); 15189 } 15190 } 15191 15192 15193 // Test that we can still flatten a string if the components it is built up 15194 // from have been turned into 16 bit strings in the mean time. 15195 THREADED_TEST(MorphCompositeStringTest) { 15196 char utf_buffer[129]; 15197 const char* c_string = "Now is the time for all good men" 15198 " to come to the aid of the party"; 15199 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 15200 { 15201 LocalContext env; 15202 i::Factory* factory = CcTest::i_isolate()->factory(); 15203 v8::HandleScope scope(env->GetIsolate()); 15204 OneByteVectorResource one_byte_resource( 15205 i::Vector<const char>(c_string, i::StrLength(c_string))); 15206 UC16VectorResource uc16_resource( 15207 i::Vector<const uint16_t>(two_byte_string, 15208 i::StrLength(c_string))); 15209 15210 Local<String> lhs( 15211 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 15212 &one_byte_resource).ToHandleChecked())); 15213 Local<String> rhs( 15214 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte( 15215 &one_byte_resource).ToHandleChecked())); 15216 15217 env->Global()->Set(v8_str("lhs"), lhs); 15218 env->Global()->Set(v8_str("rhs"), rhs); 15219 15220 CompileRun( 15221 "var cons = lhs + rhs;" 15222 "var slice = lhs.substring(1, lhs.length - 1);" 15223 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 15224 15225 CHECK(lhs->IsOneByte()); 15226 CHECK(rhs->IsOneByte()); 15227 15228 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource, 15229 &uc16_resource); 15230 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource, 15231 &uc16_resource); 15232 15233 // This should UTF-8 without flattening, since everything is ASCII. 15234 Handle<String> cons = v8_compile("cons")->Run().As<String>(); 15235 CHECK_EQ(128, cons->Utf8Length()); 15236 int nchars = -1; 15237 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 15238 CHECK_EQ(128, nchars); 15239 CHECK_EQ(0, strcmp( 15240 utf_buffer, 15241 "Now is the time for all good men to come to the aid of the party" 15242 "Now is the time for all good men to come to the aid of the party")); 15243 15244 // Now do some stuff to make sure the strings are flattened, etc. 15245 CompileRun( 15246 "/[^a-z]/.test(cons);" 15247 "/[^a-z]/.test(slice);" 15248 "/[^a-z]/.test(slice_on_cons);"); 15249 const char* expected_cons = 15250 "Now is the time for all good men to come to the aid of the party" 15251 "Now is the time for all good men to come to the aid of the party"; 15252 const char* expected_slice = 15253 "ow is the time for all good men to come to the aid of the part"; 15254 const char* expected_slice_on_cons = 15255 "ow is the time for all good men to come to the aid of the party" 15256 "Now is the time for all good men to come to the aid of the part"; 15257 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons), 15258 env->Global()->Get(v8_str("cons"))); 15259 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice), 15260 env->Global()->Get(v8_str("slice"))); 15261 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons), 15262 env->Global()->Get(v8_str("slice_on_cons"))); 15263 } 15264 i::DeleteArray(two_byte_string); 15265 } 15266 15267 15268 TEST(CompileExternalTwoByteSource) { 15269 LocalContext context; 15270 v8::HandleScope scope(context->GetIsolate()); 15271 15272 // This is a very short list of sources, which currently is to check for a 15273 // regression caused by r2703. 15274 const char* one_byte_sources[] = { 15275 "0.5", 15276 "-0.5", // This mainly testes PushBack in the Scanner. 15277 "--0.5", // This mainly testes PushBack in the Scanner. 15278 NULL}; 15279 15280 // Compile the sources as external two byte strings. 15281 for (int i = 0; one_byte_sources[i] != NULL; i++) { 15282 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]); 15283 TestResource* uc16_resource = new TestResource(two_byte_string); 15284 v8::Local<v8::String> source = 15285 v8::String::NewExternal(context->GetIsolate(), uc16_resource); 15286 v8::Script::Compile(source); 15287 } 15288 } 15289 15290 15291 #ifndef V8_INTERPRETED_REGEXP 15292 15293 struct RegExpInterruptionData { 15294 int loop_count; 15295 UC16VectorResource* string_resource; 15296 v8::Persistent<v8::String> string; 15297 } regexp_interruption_data; 15298 15299 15300 class RegExpInterruptionThread : public v8::base::Thread { 15301 public: 15302 explicit RegExpInterruptionThread(v8::Isolate* isolate) 15303 : Thread(Options("TimeoutThread")), isolate_(isolate) {} 15304 15305 virtual void Run() { 15306 for (regexp_interruption_data.loop_count = 0; 15307 regexp_interruption_data.loop_count < 7; 15308 regexp_interruption_data.loop_count++) { 15309 v8::base::OS::Sleep(50); // Wait a bit before requesting GC. 15310 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); 15311 } 15312 v8::base::OS::Sleep(50); // Wait a bit before terminating. 15313 v8::V8::TerminateExecution(isolate_); 15314 } 15315 15316 private: 15317 v8::Isolate* isolate_; 15318 }; 15319 15320 15321 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) { 15322 if (regexp_interruption_data.loop_count != 2) return; 15323 v8::HandleScope scope(CcTest::isolate()); 15324 v8::Local<v8::String> string = v8::Local<v8::String>::New( 15325 CcTest::isolate(), regexp_interruption_data.string); 15326 string->MakeExternal(regexp_interruption_data.string_resource); 15327 } 15328 15329 15330 // Test that RegExp execution can be interrupted. Specifically, we test 15331 // * interrupting with GC 15332 // * turn the subject string from one-byte internal to two-byte external string 15333 // * force termination 15334 TEST(RegExpInterruption) { 15335 v8::HandleScope scope(CcTest::isolate()); 15336 LocalContext env; 15337 15338 RegExpInterruptionThread timeout_thread(CcTest::isolate()); 15339 15340 v8::V8::AddGCPrologueCallback(RunBeforeGC); 15341 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 15342 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content); 15343 v8::Local<v8::String> string = v8_str(one_byte_content); 15344 15345 CcTest::global()->Set(v8_str("a"), string); 15346 regexp_interruption_data.string.Reset(CcTest::isolate(), string); 15347 regexp_interruption_data.string_resource = new UC16VectorResource( 15348 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content))); 15349 15350 v8::TryCatch try_catch; 15351 timeout_thread.Start(); 15352 15353 CompileRun("/((a*)*)*b/.exec(a)"); 15354 CHECK(try_catch.HasTerminated()); 15355 15356 timeout_thread.Join(); 15357 15358 regexp_interruption_data.string.Reset(); 15359 i::DeleteArray(uc16_content); 15360 } 15361 15362 #endif // V8_INTERPRETED_REGEXP 15363 15364 15365 // Test that we cannot set a property on the global object if there 15366 // is a read-only property in the prototype chain. 15367 TEST(ReadOnlyPropertyInGlobalProto) { 15368 v8::Isolate* isolate = CcTest::isolate(); 15369 v8::HandleScope scope(isolate); 15370 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15371 LocalContext context(0, templ); 15372 v8::Handle<v8::Object> global = context->Global(); 15373 v8::Handle<v8::Object> global_proto = 15374 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); 15375 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0), 15376 v8::ReadOnly); 15377 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0), 15378 v8::ReadOnly); 15379 // Check without 'eval' or 'with'. 15380 v8::Handle<v8::Value> res = 15381 CompileRun("function f() { x = 42; return x; }; f()"); 15382 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15383 // Check with 'eval'. 15384 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 15385 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15386 // Check with 'with'. 15387 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 15388 CHECK_EQ(v8::Integer::New(isolate, 0), res); 15389 } 15390 15391 static int force_set_set_count = 0; 15392 static int force_set_get_count = 0; 15393 bool pass_on_get = false; 15394 15395 static void ForceSetGetter(v8::Local<v8::String> name, 15396 const v8::PropertyCallbackInfo<v8::Value>& info) { 15397 force_set_get_count++; 15398 if (pass_on_get) { 15399 return; 15400 } 15401 info.GetReturnValue().Set(3); 15402 } 15403 15404 static void ForceSetSetter(v8::Local<v8::String> name, 15405 v8::Local<v8::Value> value, 15406 const v8::PropertyCallbackInfo<void>& info) { 15407 force_set_set_count++; 15408 } 15409 15410 static void ForceSetInterceptSetter( 15411 v8::Local<v8::String> name, 15412 v8::Local<v8::Value> value, 15413 const v8::PropertyCallbackInfo<v8::Value>& info) { 15414 force_set_set_count++; 15415 info.GetReturnValue().SetUndefined(); 15416 } 15417 15418 15419 TEST(ForceSet) { 15420 force_set_get_count = 0; 15421 force_set_set_count = 0; 15422 pass_on_get = false; 15423 15424 v8::Isolate* isolate = CcTest::isolate(); 15425 v8::HandleScope scope(isolate); 15426 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15427 v8::Handle<v8::String> access_property = 15428 v8::String::NewFromUtf8(isolate, "a"); 15429 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); 15430 LocalContext context(NULL, templ); 15431 v8::Handle<v8::Object> global = context->Global(); 15432 15433 // Ordinary properties 15434 v8::Handle<v8::String> simple_property = 15435 v8::String::NewFromUtf8(isolate, "p"); 15436 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly); 15437 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15438 // This should fail because the property is read-only 15439 global->Set(simple_property, v8::Int32::New(isolate, 5)); 15440 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15441 // This should succeed even though the property is read-only 15442 global->ForceSet(simple_property, v8::Int32::New(isolate, 6)); 15443 CHECK_EQ(6, global->Get(simple_property)->Int32Value()); 15444 15445 // Accessors 15446 CHECK_EQ(0, force_set_set_count); 15447 CHECK_EQ(0, force_set_get_count); 15448 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 15449 // CHECK_EQ the property shouldn't override it, just call the setter 15450 // which in this case does nothing. 15451 global->Set(access_property, v8::Int32::New(isolate, 7)); 15452 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 15453 CHECK_EQ(1, force_set_set_count); 15454 CHECK_EQ(2, force_set_get_count); 15455 // Forcing the property to be set should override the accessor without 15456 // calling it 15457 global->ForceSet(access_property, v8::Int32::New(isolate, 8)); 15458 CHECK_EQ(8, global->Get(access_property)->Int32Value()); 15459 CHECK_EQ(1, force_set_set_count); 15460 CHECK_EQ(2, force_set_get_count); 15461 } 15462 15463 15464 TEST(ForceSetWithInterceptor) { 15465 force_set_get_count = 0; 15466 force_set_set_count = 0; 15467 pass_on_get = false; 15468 15469 v8::Isolate* isolate = CcTest::isolate(); 15470 v8::HandleScope scope(isolate); 15471 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15472 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); 15473 LocalContext context(NULL, templ); 15474 v8::Handle<v8::Object> global = context->Global(); 15475 15476 v8::Handle<v8::String> some_property = 15477 v8::String::NewFromUtf8(isolate, "a"); 15478 CHECK_EQ(0, force_set_set_count); 15479 CHECK_EQ(0, force_set_get_count); 15480 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15481 // Setting the property shouldn't override it, just call the setter 15482 // which in this case does nothing. 15483 global->Set(some_property, v8::Int32::New(isolate, 7)); 15484 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15485 CHECK_EQ(1, force_set_set_count); 15486 CHECK_EQ(2, force_set_get_count); 15487 // Getting the property when the interceptor returns an empty handle 15488 // should yield undefined, since the property isn't present on the 15489 // object itself yet. 15490 pass_on_get = true; 15491 CHECK(global->Get(some_property)->IsUndefined()); 15492 CHECK_EQ(1, force_set_set_count); 15493 CHECK_EQ(3, force_set_get_count); 15494 // Forcing the property to be set should cause the value to be 15495 // set locally without calling the interceptor. 15496 global->ForceSet(some_property, v8::Int32::New(isolate, 8)); 15497 CHECK_EQ(8, global->Get(some_property)->Int32Value()); 15498 CHECK_EQ(1, force_set_set_count); 15499 CHECK_EQ(4, force_set_get_count); 15500 // Reenabling the interceptor should cause it to take precedence over 15501 // the property 15502 pass_on_get = false; 15503 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15504 CHECK_EQ(1, force_set_set_count); 15505 CHECK_EQ(5, force_set_get_count); 15506 // The interceptor should also work for other properties 15507 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b")) 15508 ->Int32Value()); 15509 CHECK_EQ(1, force_set_set_count); 15510 CHECK_EQ(6, force_set_get_count); 15511 } 15512 15513 15514 THREADED_TEST(ForceDelete) { 15515 v8::Isolate* isolate = CcTest::isolate(); 15516 v8::HandleScope scope(isolate); 15517 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15518 LocalContext context(NULL, templ); 15519 v8::Handle<v8::Object> global = context->Global(); 15520 15521 // Ordinary properties 15522 v8::Handle<v8::String> simple_property = 15523 v8::String::NewFromUtf8(isolate, "p"); 15524 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete); 15525 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15526 // This should fail because the property is dont-delete. 15527 CHECK(!global->Delete(simple_property)); 15528 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15529 // This should succeed even though the property is dont-delete. 15530 CHECK(global->ForceDelete(simple_property)); 15531 CHECK(global->Get(simple_property)->IsUndefined()); 15532 } 15533 15534 15535 static int force_delete_interceptor_count = 0; 15536 static bool pass_on_delete = false; 15537 15538 15539 static void ForceDeleteDeleter( 15540 v8::Local<v8::String> name, 15541 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 15542 force_delete_interceptor_count++; 15543 if (pass_on_delete) return; 15544 info.GetReturnValue().Set(true); 15545 } 15546 15547 15548 THREADED_TEST(ForceDeleteWithInterceptor) { 15549 force_delete_interceptor_count = 0; 15550 pass_on_delete = false; 15551 15552 v8::Isolate* isolate = CcTest::isolate(); 15553 v8::HandleScope scope(isolate); 15554 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 15555 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter); 15556 LocalContext context(NULL, templ); 15557 v8::Handle<v8::Object> global = context->Global(); 15558 15559 v8::Handle<v8::String> some_property = 15560 v8::String::NewFromUtf8(isolate, "a"); 15561 global->ForceSet(some_property, v8::Integer::New(isolate, 42), 15562 v8::DontDelete); 15563 15564 // Deleting a property should get intercepted and nothing should 15565 // happen. 15566 CHECK_EQ(0, force_delete_interceptor_count); 15567 CHECK(global->Delete(some_property)); 15568 CHECK_EQ(1, force_delete_interceptor_count); 15569 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15570 // Deleting the property when the interceptor returns an empty 15571 // handle should not delete the property since it is DontDelete. 15572 pass_on_delete = true; 15573 CHECK(!global->Delete(some_property)); 15574 CHECK_EQ(2, force_delete_interceptor_count); 15575 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15576 // Forcing the property to be deleted should delete the value 15577 // without calling the interceptor. 15578 CHECK(global->ForceDelete(some_property)); 15579 CHECK(global->Get(some_property)->IsUndefined()); 15580 CHECK_EQ(2, force_delete_interceptor_count); 15581 } 15582 15583 15584 // Make sure that forcing a delete invalidates any IC stubs, so we 15585 // don't read the hole value. 15586 THREADED_TEST(ForceDeleteIC) { 15587 LocalContext context; 15588 v8::HandleScope scope(context->GetIsolate()); 15589 // Create a DontDelete variable on the global object. 15590 CompileRun("this.__proto__ = { foo: 'horse' };" 15591 "var foo = 'fish';" 15592 "function f() { return foo.length; }"); 15593 // Initialize the IC for foo in f. 15594 CompileRun("for (var i = 0; i < 4; i++) f();"); 15595 // Make sure the value of foo is correct before the deletion. 15596 CHECK_EQ(4, CompileRun("f()")->Int32Value()); 15597 // Force the deletion of foo. 15598 CHECK(context->Global()->ForceDelete(v8_str("foo"))); 15599 // Make sure the value for foo is read from the prototype, and that 15600 // we don't get in trouble with reading the deleted cell value 15601 // sentinel. 15602 CHECK_EQ(5, CompileRun("f()")->Int32Value()); 15603 } 15604 15605 15606 TEST(InlinedFunctionAcrossContexts) { 15607 i::FLAG_allow_natives_syntax = true; 15608 v8::Isolate* isolate = CcTest::isolate(); 15609 v8::HandleScope outer_scope(isolate); 15610 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate); 15611 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate); 15612 ctx1->Enter(); 15613 15614 { 15615 v8::HandleScope inner_scope(CcTest::isolate()); 15616 CompileRun("var G = 42; function foo() { return G; }"); 15617 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo")); 15618 ctx2->Enter(); 15619 ctx2->Global()->Set(v8_str("o"), foo); 15620 v8::Local<v8::Value> res = CompileRun( 15621 "function f() { return o(); }" 15622 "for (var i = 0; i < 10; ++i) f();" 15623 "%OptimizeFunctionOnNextCall(f);" 15624 "f();"); 15625 CHECK_EQ(42, res->Int32Value()); 15626 ctx2->Exit(); 15627 v8::Handle<v8::String> G_property = 15628 v8::String::NewFromUtf8(CcTest::isolate(), "G"); 15629 CHECK(ctx1->Global()->ForceDelete(G_property)); 15630 ctx2->Enter(); 15631 ExpectString( 15632 "(function() {" 15633 " try {" 15634 " return f();" 15635 " } catch(e) {" 15636 " return e.toString();" 15637 " }" 15638 " })()", 15639 "ReferenceError: G is not defined"); 15640 ctx2->Exit(); 15641 ctx1->Exit(); 15642 } 15643 } 15644 15645 15646 static v8::Local<Context> calling_context0; 15647 static v8::Local<Context> calling_context1; 15648 static v8::Local<Context> calling_context2; 15649 15650 15651 // Check that the call to the callback is initiated in 15652 // calling_context2, the directly calling context is calling_context1 15653 // and the callback itself is in calling_context0. 15654 static void GetCallingContextCallback( 15655 const v8::FunctionCallbackInfo<v8::Value>& args) { 15656 ApiTestFuzzer::Fuzz(); 15657 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0); 15658 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1); 15659 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2); 15660 args.GetReturnValue().Set(42); 15661 } 15662 15663 15664 THREADED_TEST(GetCurrentContextWhenNotInContext) { 15665 i::Isolate* isolate = CcTest::i_isolate(); 15666 CHECK(isolate != NULL); 15667 CHECK(isolate->context() == NULL); 15668 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 15669 v8::HandleScope scope(v8_isolate); 15670 // The following should not crash, but return an empty handle. 15671 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 15672 CHECK(current.IsEmpty()); 15673 } 15674 15675 15676 THREADED_TEST(GetCallingContext) { 15677 v8::Isolate* isolate = CcTest::isolate(); 15678 v8::HandleScope scope(isolate); 15679 15680 Local<Context> calling_context0(Context::New(isolate)); 15681 Local<Context> calling_context1(Context::New(isolate)); 15682 Local<Context> calling_context2(Context::New(isolate)); 15683 ::calling_context0 = calling_context0; 15684 ::calling_context1 = calling_context1; 15685 ::calling_context2 = calling_context2; 15686 15687 // Allow cross-domain access. 15688 Local<String> token = v8_str("<security token>"); 15689 calling_context0->SetSecurityToken(token); 15690 calling_context1->SetSecurityToken(token); 15691 calling_context2->SetSecurityToken(token); 15692 15693 // Create an object with a C++ callback in context0. 15694 calling_context0->Enter(); 15695 Local<v8::FunctionTemplate> callback_templ = 15696 v8::FunctionTemplate::New(isolate, GetCallingContextCallback); 15697 calling_context0->Global()->Set(v8_str("callback"), 15698 callback_templ->GetFunction()); 15699 calling_context0->Exit(); 15700 15701 // Expose context0 in context1 and set up a function that calls the 15702 // callback function. 15703 calling_context1->Enter(); 15704 calling_context1->Global()->Set(v8_str("context0"), 15705 calling_context0->Global()); 15706 CompileRun("function f() { context0.callback() }"); 15707 calling_context1->Exit(); 15708 15709 // Expose context1 in context2 and call the callback function in 15710 // context0 indirectly through f in context1. 15711 calling_context2->Enter(); 15712 calling_context2->Global()->Set(v8_str("context1"), 15713 calling_context1->Global()); 15714 CompileRun("context1.f()"); 15715 calling_context2->Exit(); 15716 ::calling_context0.Clear(); 15717 ::calling_context1.Clear(); 15718 ::calling_context2.Clear(); 15719 } 15720 15721 15722 // Check that a variable declaration with no explicit initialization 15723 // value does shadow an existing property in the prototype chain. 15724 THREADED_TEST(InitGlobalVarInProtoChain) { 15725 LocalContext context; 15726 v8::HandleScope scope(context->GetIsolate()); 15727 // Introduce a variable in the prototype chain. 15728 CompileRun("__proto__.x = 42"); 15729 v8::Handle<v8::Value> result = CompileRun("var x = 43; x"); 15730 CHECK(!result->IsUndefined()); 15731 CHECK_EQ(43, result->Int32Value()); 15732 } 15733 15734 15735 // Regression test for issue 398. 15736 // If a function is added to an object, creating a constant function 15737 // field, and the result is cloned, replacing the constant function on the 15738 // original should not affect the clone. 15739 // See http://code.google.com/p/v8/issues/detail?id=398 15740 THREADED_TEST(ReplaceConstantFunction) { 15741 LocalContext context; 15742 v8::Isolate* isolate = context->GetIsolate(); 15743 v8::HandleScope scope(isolate); 15744 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 15745 v8::Handle<v8::FunctionTemplate> func_templ = 15746 v8::FunctionTemplate::New(isolate); 15747 v8::Handle<v8::String> foo_string = 15748 v8::String::NewFromUtf8(isolate, "foo"); 15749 obj->Set(foo_string, func_templ->GetFunction()); 15750 v8::Handle<v8::Object> obj_clone = obj->Clone(); 15751 obj_clone->Set(foo_string, 15752 v8::String::NewFromUtf8(isolate, "Hello")); 15753 CHECK(!obj->Get(foo_string)->IsUndefined()); 15754 } 15755 15756 15757 static void CheckElementValue(i::Isolate* isolate, 15758 int expected, 15759 i::Handle<i::Object> obj, 15760 int offset) { 15761 i::Object* element = 15762 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked(); 15763 CHECK_EQ(expected, i::Smi::cast(element)->value()); 15764 } 15765 15766 15767 THREADED_TEST(PixelArray) { 15768 LocalContext context; 15769 i::Isolate* isolate = CcTest::i_isolate(); 15770 i::Factory* factory = isolate->factory(); 15771 v8::HandleScope scope(context->GetIsolate()); 15772 const int kElementCount = 260; 15773 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 15774 i::Handle<i::ExternalUint8ClampedArray> pixels = 15775 i::Handle<i::ExternalUint8ClampedArray>::cast( 15776 factory->NewExternalArray(kElementCount, 15777 v8::kExternalUint8ClampedArray, 15778 pixel_data)); 15779 // Force GC to trigger verification. 15780 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15781 for (int i = 0; i < kElementCount; i++) { 15782 pixels->set(i, i % 256); 15783 } 15784 // Force GC to trigger verification. 15785 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15786 for (int i = 0; i < kElementCount; i++) { 15787 CHECK_EQ(i % 256, pixels->get_scalar(i)); 15788 CHECK_EQ(i % 256, pixel_data[i]); 15789 } 15790 15791 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 15792 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15793 // Set the elements to be the pixels. 15794 // jsobj->set_elements(*pixels); 15795 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 15796 CheckElementValue(isolate, 1, jsobj, 1); 15797 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503)); 15798 context->Global()->Set(v8_str("pixels"), obj); 15799 v8::Handle<v8::Value> result = CompileRun("pixels.field"); 15800 CHECK_EQ(1503, result->Int32Value()); 15801 result = CompileRun("pixels[1]"); 15802 CHECK_EQ(1, result->Int32Value()); 15803 15804 result = CompileRun("var sum = 0;" 15805 "for (var i = 0; i < 8; i++) {" 15806 " sum += pixels[i] = pixels[i] = -i;" 15807 "}" 15808 "sum;"); 15809 CHECK_EQ(-28, result->Int32Value()); 15810 15811 result = CompileRun("var sum = 0;" 15812 "for (var i = 0; i < 8; i++) {" 15813 " sum += pixels[i] = pixels[i] = 0;" 15814 "}" 15815 "sum;"); 15816 CHECK_EQ(0, result->Int32Value()); 15817 15818 result = CompileRun("var sum = 0;" 15819 "for (var i = 0; i < 8; i++) {" 15820 " sum += pixels[i] = pixels[i] = 255;" 15821 "}" 15822 "sum;"); 15823 CHECK_EQ(8 * 255, result->Int32Value()); 15824 15825 result = CompileRun("var sum = 0;" 15826 "for (var i = 0; i < 8; i++) {" 15827 " sum += pixels[i] = pixels[i] = 256 + i;" 15828 "}" 15829 "sum;"); 15830 CHECK_EQ(2076, result->Int32Value()); 15831 15832 result = CompileRun("var sum = 0;" 15833 "for (var i = 0; i < 8; i++) {" 15834 " sum += pixels[i] = pixels[i] = i;" 15835 "}" 15836 "sum;"); 15837 CHECK_EQ(28, result->Int32Value()); 15838 15839 result = CompileRun("var sum = 0;" 15840 "for (var i = 0; i < 8; i++) {" 15841 " sum += pixels[i];" 15842 "}" 15843 "sum;"); 15844 CHECK_EQ(28, result->Int32Value()); 15845 15846 i::Handle<i::Smi> value(i::Smi::FromInt(2), 15847 reinterpret_cast<i::Isolate*>(context->GetIsolate())); 15848 i::Handle<i::Object> no_failure; 15849 no_failure = i::JSObject::SetElement( 15850 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15851 DCHECK(!no_failure.is_null()); 15852 USE(no_failure); 15853 CheckElementValue(isolate, 2, jsobj, 1); 15854 *value.location() = i::Smi::FromInt(256); 15855 no_failure = i::JSObject::SetElement( 15856 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15857 DCHECK(!no_failure.is_null()); 15858 USE(no_failure); 15859 CheckElementValue(isolate, 255, jsobj, 1); 15860 *value.location() = i::Smi::FromInt(-1); 15861 no_failure = i::JSObject::SetElement( 15862 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked(); 15863 DCHECK(!no_failure.is_null()); 15864 USE(no_failure); 15865 CheckElementValue(isolate, 0, jsobj, 1); 15866 15867 result = CompileRun("for (var i = 0; i < 8; i++) {" 15868 " pixels[i] = (i * 65) - 109;" 15869 "}" 15870 "pixels[1] + pixels[6];"); 15871 CHECK_EQ(255, result->Int32Value()); 15872 CheckElementValue(isolate, 0, jsobj, 0); 15873 CheckElementValue(isolate, 0, jsobj, 1); 15874 CheckElementValue(isolate, 21, jsobj, 2); 15875 CheckElementValue(isolate, 86, jsobj, 3); 15876 CheckElementValue(isolate, 151, jsobj, 4); 15877 CheckElementValue(isolate, 216, jsobj, 5); 15878 CheckElementValue(isolate, 255, jsobj, 6); 15879 CheckElementValue(isolate, 255, jsobj, 7); 15880 result = CompileRun("var sum = 0;" 15881 "for (var i = 0; i < 8; i++) {" 15882 " sum += pixels[i];" 15883 "}" 15884 "sum;"); 15885 CHECK_EQ(984, result->Int32Value()); 15886 15887 result = CompileRun("for (var i = 0; i < 8; i++) {" 15888 " pixels[i] = (i * 1.1);" 15889 "}" 15890 "pixels[1] + pixels[6];"); 15891 CHECK_EQ(8, result->Int32Value()); 15892 CheckElementValue(isolate, 0, jsobj, 0); 15893 CheckElementValue(isolate, 1, jsobj, 1); 15894 CheckElementValue(isolate, 2, jsobj, 2); 15895 CheckElementValue(isolate, 3, jsobj, 3); 15896 CheckElementValue(isolate, 4, jsobj, 4); 15897 CheckElementValue(isolate, 6, jsobj, 5); 15898 CheckElementValue(isolate, 7, jsobj, 6); 15899 CheckElementValue(isolate, 8, jsobj, 7); 15900 15901 result = CompileRun("for (var i = 0; i < 8; i++) {" 15902 " pixels[7] = undefined;" 15903 "}" 15904 "pixels[7];"); 15905 CHECK_EQ(0, result->Int32Value()); 15906 CheckElementValue(isolate, 0, jsobj, 7); 15907 15908 result = CompileRun("for (var i = 0; i < 8; i++) {" 15909 " pixels[6] = '2.3';" 15910 "}" 15911 "pixels[6];"); 15912 CHECK_EQ(2, result->Int32Value()); 15913 CheckElementValue(isolate, 2, jsobj, 6); 15914 15915 result = CompileRun("for (var i = 0; i < 8; i++) {" 15916 " pixels[5] = NaN;" 15917 "}" 15918 "pixels[5];"); 15919 CHECK_EQ(0, result->Int32Value()); 15920 CheckElementValue(isolate, 0, jsobj, 5); 15921 15922 result = CompileRun("for (var i = 0; i < 8; i++) {" 15923 " pixels[8] = Infinity;" 15924 "}" 15925 "pixels[8];"); 15926 CHECK_EQ(255, result->Int32Value()); 15927 CheckElementValue(isolate, 255, jsobj, 8); 15928 15929 result = CompileRun("for (var i = 0; i < 8; i++) {" 15930 " pixels[9] = -Infinity;" 15931 "}" 15932 "pixels[9];"); 15933 CHECK_EQ(0, result->Int32Value()); 15934 CheckElementValue(isolate, 0, jsobj, 9); 15935 15936 result = CompileRun("pixels[3] = 33;" 15937 "delete pixels[3];" 15938 "pixels[3];"); 15939 CHECK_EQ(33, result->Int32Value()); 15940 15941 result = CompileRun("pixels[0] = 10; pixels[1] = 11;" 15942 "pixels[2] = 12; pixels[3] = 13;" 15943 "pixels.__defineGetter__('2'," 15944 "function() { return 120; });" 15945 "pixels[2];"); 15946 CHECK_EQ(12, result->Int32Value()); 15947 15948 result = CompileRun("var js_array = new Array(40);" 15949 "js_array[0] = 77;" 15950 "js_array;"); 15951 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15952 15953 result = CompileRun("pixels[1] = 23;" 15954 "pixels.__proto__ = [];" 15955 "js_array.__proto__ = pixels;" 15956 "js_array.concat(pixels);"); 15957 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15958 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 15959 15960 result = CompileRun("pixels[1] = 23;"); 15961 CHECK_EQ(23, result->Int32Value()); 15962 15963 // Test for index greater than 255. Regression test for: 15964 // http://code.google.com/p/chromium/issues/detail?id=26337. 15965 result = CompileRun("pixels[256] = 255;"); 15966 CHECK_EQ(255, result->Int32Value()); 15967 result = CompileRun("var i = 0;" 15968 "for (var j = 0; j < 8; j++) { i = pixels[256]; }" 15969 "i"); 15970 CHECK_EQ(255, result->Int32Value()); 15971 15972 // Make sure that pixel array ICs recognize when a non-pixel array 15973 // is passed to it. 15974 result = CompileRun("function pa_load(p) {" 15975 " var sum = 0;" 15976 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15977 " return sum;" 15978 "}" 15979 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15980 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15981 "just_ints = new Object();" 15982 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15983 "for (var i = 0; i < 10; ++i) {" 15984 " result = pa_load(just_ints);" 15985 "}" 15986 "result"); 15987 CHECK_EQ(32640, result->Int32Value()); 15988 15989 // Make sure that pixel array ICs recognize out-of-bound accesses. 15990 result = CompileRun("function pa_load(p, start) {" 15991 " var sum = 0;" 15992 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15993 " return sum;" 15994 "}" 15995 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15996 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15997 "for (var i = 0; i < 10; ++i) {" 15998 " result = pa_load(pixels,-10);" 15999 "}" 16000 "result"); 16001 CHECK_EQ(0, result->Int32Value()); 16002 16003 // Make sure that generic ICs properly handles a pixel array. 16004 result = CompileRun("function pa_load(p) {" 16005 " var sum = 0;" 16006 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 16007 " return sum;" 16008 "}" 16009 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16010 "just_ints = new Object();" 16011 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16012 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 16013 "for (var i = 0; i < 10; ++i) {" 16014 " result = pa_load(pixels);" 16015 "}" 16016 "result"); 16017 CHECK_EQ(32640, result->Int32Value()); 16018 16019 // Make sure that generic load ICs recognize out-of-bound accesses in 16020 // pixel arrays. 16021 result = CompileRun("function pa_load(p, start) {" 16022 " var sum = 0;" 16023 " for (var j = start; j < 256; j++) { sum += p[j]; }" 16024 " return sum;" 16025 "}" 16026 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16027 "just_ints = new Object();" 16028 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16029 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }" 16030 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 16031 "for (var i = 0; i < 10; ++i) {" 16032 " result = pa_load(pixels,-10);" 16033 "}" 16034 "result"); 16035 CHECK_EQ(0, result->Int32Value()); 16036 16037 // Make sure that generic ICs properly handles other types than pixel 16038 // arrays (that the inlined fast pixel array test leaves the right information 16039 // in the right registers). 16040 result = CompileRun("function pa_load(p) {" 16041 " var sum = 0;" 16042 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 16043 " return sum;" 16044 "}" 16045 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16046 "just_ints = new Object();" 16047 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16048 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 16049 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 16050 "sparse_array = new Object();" 16051 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }" 16052 "sparse_array[1000000] = 3;" 16053 "for (var i = 0; i < 10; ++i) {" 16054 " result = pa_load(sparse_array);" 16055 "}" 16056 "result"); 16057 CHECK_EQ(32640, result->Int32Value()); 16058 16059 // Make sure that pixel array store ICs clamp values correctly. 16060 result = CompileRun("function pa_store(p) {" 16061 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 16062 "}" 16063 "pa_store(pixels);" 16064 "var sum = 0;" 16065 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16066 "sum"); 16067 CHECK_EQ(48896, result->Int32Value()); 16068 16069 // Make sure that pixel array stores correctly handle accesses outside 16070 // of the pixel array.. 16071 result = CompileRun("function pa_store(p,start) {" 16072 " for (var j = 0; j < 256; j++) {" 16073 " p[j+start] = j * 2;" 16074 " }" 16075 "}" 16076 "pa_store(pixels,0);" 16077 "pa_store(pixels,-128);" 16078 "var sum = 0;" 16079 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16080 "sum"); 16081 CHECK_EQ(65280, result->Int32Value()); 16082 16083 // Make sure that the generic store stub correctly handle accesses outside 16084 // of the pixel array.. 16085 result = CompileRun("function pa_store(p,start) {" 16086 " for (var j = 0; j < 256; j++) {" 16087 " p[j+start] = j * 2;" 16088 " }" 16089 "}" 16090 "pa_store(pixels,0);" 16091 "just_ints = new Object();" 16092 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 16093 "pa_store(just_ints, 0);" 16094 "pa_store(pixels,-128);" 16095 "var sum = 0;" 16096 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16097 "sum"); 16098 CHECK_EQ(65280, result->Int32Value()); 16099 16100 // Make sure that the generic keyed store stub clamps pixel array values 16101 // correctly. 16102 result = CompileRun("function pa_store(p) {" 16103 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 16104 "}" 16105 "pa_store(pixels);" 16106 "just_ints = new Object();" 16107 "pa_store(just_ints);" 16108 "pa_store(pixels);" 16109 "var sum = 0;" 16110 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 16111 "sum"); 16112 CHECK_EQ(48896, result->Int32Value()); 16113 16114 // Make sure that pixel array loads are optimized by crankshaft. 16115 result = CompileRun("function pa_load(p) {" 16116 " var sum = 0;" 16117 " for (var i=0; i<256; ++i) {" 16118 " sum += p[i];" 16119 " }" 16120 " return sum; " 16121 "}" 16122 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 16123 "for (var i = 0; i < 5000; ++i) {" 16124 " result = pa_load(pixels);" 16125 "}" 16126 "result"); 16127 CHECK_EQ(32640, result->Int32Value()); 16128 16129 // Make sure that pixel array stores are optimized by crankshaft. 16130 result = CompileRun("function pa_init(p) {" 16131 "for (var i = 0; i < 256; ++i) { p[i] = i; }" 16132 "}" 16133 "function pa_load(p) {" 16134 " var sum = 0;" 16135 " for (var i=0; i<256; ++i) {" 16136 " sum += p[i];" 16137 " }" 16138 " return sum; " 16139 "}" 16140 "for (var i = 0; i < 5000; ++i) {" 16141 " pa_init(pixels);" 16142 "}" 16143 "result = pa_load(pixels);" 16144 "result"); 16145 CHECK_EQ(32640, result->Int32Value()); 16146 16147 free(pixel_data); 16148 } 16149 16150 16151 THREADED_TEST(PixelArrayInfo) { 16152 LocalContext context; 16153 v8::HandleScope scope(context->GetIsolate()); 16154 for (int size = 0; size < 100; size += 10) { 16155 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size)); 16156 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16157 obj->SetIndexedPropertiesToPixelData(pixel_data, size); 16158 CHECK(obj->HasIndexedPropertiesInPixelData()); 16159 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData()); 16160 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength()); 16161 free(pixel_data); 16162 } 16163 } 16164 16165 16166 static void NotHandledIndexedPropertyGetter( 16167 uint32_t index, 16168 const v8::PropertyCallbackInfo<v8::Value>& info) { 16169 ApiTestFuzzer::Fuzz(); 16170 } 16171 16172 16173 static void NotHandledIndexedPropertySetter( 16174 uint32_t index, 16175 Local<Value> value, 16176 const v8::PropertyCallbackInfo<v8::Value>& info) { 16177 ApiTestFuzzer::Fuzz(); 16178 } 16179 16180 16181 THREADED_TEST(PixelArrayWithInterceptor) { 16182 LocalContext context; 16183 i::Factory* factory = CcTest::i_isolate()->factory(); 16184 v8::Isolate* isolate = context->GetIsolate(); 16185 v8::HandleScope scope(isolate); 16186 const int kElementCount = 260; 16187 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 16188 i::Handle<i::ExternalUint8ClampedArray> pixels = 16189 i::Handle<i::ExternalUint8ClampedArray>::cast( 16190 factory->NewExternalArray(kElementCount, 16191 v8::kExternalUint8ClampedArray, 16192 pixel_data)); 16193 for (int i = 0; i < kElementCount; i++) { 16194 pixels->set(i, i % 256); 16195 } 16196 v8::Handle<v8::ObjectTemplate> templ = 16197 v8::ObjectTemplate::New(context->GetIsolate()); 16198 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter, 16199 NotHandledIndexedPropertySetter); 16200 v8::Handle<v8::Object> obj = templ->NewInstance(); 16201 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 16202 context->Global()->Set(v8_str("pixels"), obj); 16203 v8::Handle<v8::Value> result = CompileRun("pixels[1]"); 16204 CHECK_EQ(1, result->Int32Value()); 16205 result = CompileRun("var sum = 0;" 16206 "for (var i = 0; i < 8; i++) {" 16207 " sum += pixels[i] = pixels[i] = -i;" 16208 "}" 16209 "sum;"); 16210 CHECK_EQ(-28, result->Int32Value()); 16211 result = CompileRun("pixels.hasOwnProperty('1')"); 16212 CHECK(result->BooleanValue()); 16213 free(pixel_data); 16214 } 16215 16216 16217 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) { 16218 switch (array_type) { 16219 case v8::kExternalInt8Array: 16220 case v8::kExternalUint8Array: 16221 case v8::kExternalUint8ClampedArray: 16222 return 1; 16223 break; 16224 case v8::kExternalInt16Array: 16225 case v8::kExternalUint16Array: 16226 return 2; 16227 break; 16228 case v8::kExternalInt32Array: 16229 case v8::kExternalUint32Array: 16230 case v8::kExternalFloat32Array: 16231 return 4; 16232 break; 16233 case v8::kExternalFloat64Array: 16234 return 8; 16235 break; 16236 default: 16237 UNREACHABLE(); 16238 return -1; 16239 } 16240 UNREACHABLE(); 16241 return -1; 16242 } 16243 16244 16245 template <class ExternalArrayClass, class ElementType> 16246 static void ObjectWithExternalArrayTestHelper( 16247 Handle<Context> context, 16248 v8::Handle<Object> obj, 16249 int element_count, 16250 v8::ExternalArrayType array_type, 16251 int64_t low, int64_t high) { 16252 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16253 i::Isolate* isolate = jsobj->GetIsolate(); 16254 obj->Set(v8_str("field"), 16255 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503)); 16256 context->Global()->Set(v8_str("ext_array"), obj); 16257 v8::Handle<v8::Value> result = CompileRun("ext_array.field"); 16258 CHECK_EQ(1503, result->Int32Value()); 16259 result = CompileRun("ext_array[1]"); 16260 CHECK_EQ(1, result->Int32Value()); 16261 16262 // Check assigned smis 16263 result = CompileRun("for (var i = 0; i < 8; i++) {" 16264 " ext_array[i] = i;" 16265 "}" 16266 "var sum = 0;" 16267 "for (var i = 0; i < 8; i++) {" 16268 " sum += ext_array[i];" 16269 "}" 16270 "sum;"); 16271 16272 CHECK_EQ(28, result->Int32Value()); 16273 // Check pass through of assigned smis 16274 result = CompileRun("var sum = 0;" 16275 "for (var i = 0; i < 8; i++) {" 16276 " sum += ext_array[i] = ext_array[i] = -i;" 16277 "}" 16278 "sum;"); 16279 CHECK_EQ(-28, result->Int32Value()); 16280 16281 16282 // Check assigned smis in reverse order 16283 result = CompileRun("for (var i = 8; --i >= 0; ) {" 16284 " ext_array[i] = i;" 16285 "}" 16286 "var sum = 0;" 16287 "for (var i = 0; i < 8; i++) {" 16288 " sum += ext_array[i];" 16289 "}" 16290 "sum;"); 16291 CHECK_EQ(28, result->Int32Value()); 16292 16293 // Check pass through of assigned HeapNumbers 16294 result = CompileRun("var sum = 0;" 16295 "for (var i = 0; i < 16; i+=2) {" 16296 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 16297 "}" 16298 "sum;"); 16299 CHECK_EQ(-28, result->Int32Value()); 16300 16301 // Check assigned HeapNumbers 16302 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 16303 " ext_array[i] = (i * 0.5);" 16304 "}" 16305 "var sum = 0;" 16306 "for (var i = 0; i < 16; i+=2) {" 16307 " sum += ext_array[i];" 16308 "}" 16309 "sum;"); 16310 CHECK_EQ(28, result->Int32Value()); 16311 16312 // Check assigned HeapNumbers in reverse order 16313 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 16314 " ext_array[i] = (i * 0.5);" 16315 "}" 16316 "var sum = 0;" 16317 "for (var i = 0; i < 16; i+=2) {" 16318 " sum += ext_array[i];" 16319 "}" 16320 "sum;"); 16321 CHECK_EQ(28, result->Int32Value()); 16322 16323 i::ScopedVector<char> test_buf(1024); 16324 16325 // Check legal boundary conditions. 16326 // The repeated loads and stores ensure the ICs are exercised. 16327 const char* boundary_program = 16328 "var res = 0;" 16329 "for (var i = 0; i < 16; i++) {" 16330 " ext_array[i] = %lld;" 16331 " if (i > 8) {" 16332 " res = ext_array[i];" 16333 " }" 16334 "}" 16335 "res;"; 16336 i::SNPrintF(test_buf, 16337 boundary_program, 16338 low); 16339 result = CompileRun(test_buf.start()); 16340 CHECK_EQ(low, result->IntegerValue()); 16341 16342 i::SNPrintF(test_buf, 16343 boundary_program, 16344 high); 16345 result = CompileRun(test_buf.start()); 16346 CHECK_EQ(high, result->IntegerValue()); 16347 16348 // Check misprediction of type in IC. 16349 result = CompileRun("var tmp_array = ext_array;" 16350 "var sum = 0;" 16351 "for (var i = 0; i < 8; i++) {" 16352 " tmp_array[i] = i;" 16353 " sum += tmp_array[i];" 16354 " if (i == 4) {" 16355 " tmp_array = {};" 16356 " }" 16357 "}" 16358 "sum;"); 16359 // Force GC to trigger verification. 16360 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16361 CHECK_EQ(28, result->Int32Value()); 16362 16363 // Make sure out-of-range loads do not throw. 16364 i::SNPrintF(test_buf, 16365 "var caught_exception = false;" 16366 "try {" 16367 " ext_array[%d];" 16368 "} catch (e) {" 16369 " caught_exception = true;" 16370 "}" 16371 "caught_exception;", 16372 element_count); 16373 result = CompileRun(test_buf.start()); 16374 CHECK_EQ(false, result->BooleanValue()); 16375 16376 // Make sure out-of-range stores do not throw. 16377 i::SNPrintF(test_buf, 16378 "var caught_exception = false;" 16379 "try {" 16380 " ext_array[%d] = 1;" 16381 "} catch (e) {" 16382 " caught_exception = true;" 16383 "}" 16384 "caught_exception;", 16385 element_count); 16386 result = CompileRun(test_buf.start()); 16387 CHECK_EQ(false, result->BooleanValue()); 16388 16389 // Check other boundary conditions, values and operations. 16390 result = CompileRun("for (var i = 0; i < 8; i++) {" 16391 " ext_array[7] = undefined;" 16392 "}" 16393 "ext_array[7];"); 16394 CHECK_EQ(0, result->Int32Value()); 16395 if (array_type == v8::kExternalFloat64Array || 16396 array_type == v8::kExternalFloat32Array) { 16397 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()), 16398 static_cast<int>( 16399 i::Object::GetElement( 16400 isolate, jsobj, 7).ToHandleChecked()->Number())); 16401 } else { 16402 CheckElementValue(isolate, 0, jsobj, 7); 16403 } 16404 16405 result = CompileRun("for (var i = 0; i < 8; i++) {" 16406 " ext_array[6] = '2.3';" 16407 "}" 16408 "ext_array[6];"); 16409 CHECK_EQ(2, result->Int32Value()); 16410 CHECK_EQ(2, 16411 static_cast<int>( 16412 i::Object::GetElement( 16413 isolate, jsobj, 6).ToHandleChecked()->Number())); 16414 16415 if (array_type != v8::kExternalFloat32Array && 16416 array_type != v8::kExternalFloat64Array) { 16417 // Though the specification doesn't state it, be explicit about 16418 // converting NaNs and +/-Infinity to zero. 16419 result = CompileRun("for (var i = 0; i < 8; i++) {" 16420 " ext_array[i] = 5;" 16421 "}" 16422 "for (var i = 0; i < 8; i++) {" 16423 " ext_array[i] = NaN;" 16424 "}" 16425 "ext_array[5];"); 16426 CHECK_EQ(0, result->Int32Value()); 16427 CheckElementValue(isolate, 0, jsobj, 5); 16428 16429 result = CompileRun("for (var i = 0; i < 8; i++) {" 16430 " ext_array[i] = 5;" 16431 "}" 16432 "for (var i = 0; i < 8; i++) {" 16433 " ext_array[i] = Infinity;" 16434 "}" 16435 "ext_array[5];"); 16436 int expected_value = 16437 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0; 16438 CHECK_EQ(expected_value, result->Int32Value()); 16439 CheckElementValue(isolate, expected_value, jsobj, 5); 16440 16441 result = CompileRun("for (var i = 0; i < 8; i++) {" 16442 " ext_array[i] = 5;" 16443 "}" 16444 "for (var i = 0; i < 8; i++) {" 16445 " ext_array[i] = -Infinity;" 16446 "}" 16447 "ext_array[5];"); 16448 CHECK_EQ(0, result->Int32Value()); 16449 CheckElementValue(isolate, 0, jsobj, 5); 16450 16451 // Check truncation behavior of integral arrays. 16452 const char* unsigned_data = 16453 "var source_data = [0.6, 10.6];" 16454 "var expected_results = [0, 10];"; 16455 const char* signed_data = 16456 "var source_data = [0.6, 10.6, -0.6, -10.6];" 16457 "var expected_results = [0, 10, 0, -10];"; 16458 const char* pixel_data = 16459 "var source_data = [0.6, 10.6];" 16460 "var expected_results = [1, 11];"; 16461 bool is_unsigned = 16462 (array_type == v8::kExternalUint8Array || 16463 array_type == v8::kExternalUint16Array || 16464 array_type == v8::kExternalUint32Array); 16465 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray; 16466 16467 i::SNPrintF(test_buf, 16468 "%s" 16469 "var all_passed = true;" 16470 "for (var i = 0; i < source_data.length; i++) {" 16471 " for (var j = 0; j < 8; j++) {" 16472 " ext_array[j] = source_data[i];" 16473 " }" 16474 " all_passed = all_passed &&" 16475 " (ext_array[5] == expected_results[i]);" 16476 "}" 16477 "all_passed;", 16478 (is_unsigned ? 16479 unsigned_data : 16480 (is_pixel_data ? pixel_data : signed_data))); 16481 result = CompileRun(test_buf.start()); 16482 CHECK_EQ(true, result->BooleanValue()); 16483 } 16484 16485 i::Handle<ExternalArrayClass> array( 16486 ExternalArrayClass::cast(jsobj->elements())); 16487 for (int i = 0; i < element_count; i++) { 16488 array->set(i, static_cast<ElementType>(i)); 16489 } 16490 16491 // Test complex assignments 16492 result = CompileRun("function ee_op_test_complex_func(sum) {" 16493 " for (var i = 0; i < 40; ++i) {" 16494 " sum += (ext_array[i] += 1);" 16495 " sum += (ext_array[i] -= 1);" 16496 " } " 16497 " return sum;" 16498 "}" 16499 "sum=0;" 16500 "for (var i=0;i<10000;++i) {" 16501 " sum=ee_op_test_complex_func(sum);" 16502 "}" 16503 "sum;"); 16504 CHECK_EQ(16000000, result->Int32Value()); 16505 16506 // Test count operations 16507 result = CompileRun("function ee_op_test_count_func(sum) {" 16508 " for (var i = 0; i < 40; ++i) {" 16509 " sum += (++ext_array[i]);" 16510 " sum += (--ext_array[i]);" 16511 " } " 16512 " return sum;" 16513 "}" 16514 "sum=0;" 16515 "for (var i=0;i<10000;++i) {" 16516 " sum=ee_op_test_count_func(sum);" 16517 "}" 16518 "sum;"); 16519 CHECK_EQ(16000000, result->Int32Value()); 16520 16521 result = CompileRun("ext_array[3] = 33;" 16522 "delete ext_array[3];" 16523 "ext_array[3];"); 16524 CHECK_EQ(33, result->Int32Value()); 16525 16526 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 16527 "ext_array[2] = 12; ext_array[3] = 13;" 16528 "ext_array.__defineGetter__('2'," 16529 "function() { return 120; });" 16530 "ext_array[2];"); 16531 CHECK_EQ(12, result->Int32Value()); 16532 16533 result = CompileRun("var js_array = new Array(40);" 16534 "js_array[0] = 77;" 16535 "js_array;"); 16536 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16537 16538 result = CompileRun("ext_array[1] = 23;" 16539 "ext_array.__proto__ = [];" 16540 "js_array.__proto__ = ext_array;" 16541 "js_array.concat(ext_array);"); 16542 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16543 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 16544 16545 result = CompileRun("ext_array[1] = 23;"); 16546 CHECK_EQ(23, result->Int32Value()); 16547 } 16548 16549 16550 template <class FixedTypedArrayClass, 16551 i::ElementsKind elements_kind, 16552 class ElementType> 16553 static void FixedTypedArrayTestHelper( 16554 v8::ExternalArrayType array_type, 16555 ElementType low, 16556 ElementType high) { 16557 i::FLAG_allow_natives_syntax = true; 16558 LocalContext context; 16559 i::Isolate* isolate = CcTest::i_isolate(); 16560 i::Factory* factory = isolate->factory(); 16561 v8::HandleScope scope(context->GetIsolate()); 16562 const int kElementCount = 260; 16563 i::Handle<FixedTypedArrayClass> fixed_array = 16564 i::Handle<FixedTypedArrayClass>::cast( 16565 factory->NewFixedTypedArray(kElementCount, array_type)); 16566 CHECK_EQ(FixedTypedArrayClass::kInstanceType, 16567 fixed_array->map()->instance_type()); 16568 CHECK_EQ(kElementCount, fixed_array->length()); 16569 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16570 for (int i = 0; i < kElementCount; i++) { 16571 fixed_array->set(i, static_cast<ElementType>(i)); 16572 } 16573 // Force GC to trigger verification. 16574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16575 for (int i = 0; i < kElementCount; i++) { 16576 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)), 16577 static_cast<int64_t>(fixed_array->get_scalar(i))); 16578 } 16579 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate()); 16580 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16581 i::Handle<i::Map> fixed_array_map = 16582 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind); 16583 jsobj->set_map(*fixed_array_map); 16584 jsobj->set_elements(*fixed_array); 16585 16586 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>( 16587 context.local(), obj, kElementCount, array_type, 16588 static_cast<int64_t>(low), 16589 static_cast<int64_t>(high)); 16590 } 16591 16592 16593 THREADED_TEST(FixedUint8Array) { 16594 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>( 16595 v8::kExternalUint8Array, 16596 0x0, 0xFF); 16597 } 16598 16599 16600 THREADED_TEST(FixedUint8ClampedArray) { 16601 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray, 16602 i::UINT8_CLAMPED_ELEMENTS, uint8_t>( 16603 v8::kExternalUint8ClampedArray, 16604 0x0, 0xFF); 16605 } 16606 16607 16608 THREADED_TEST(FixedInt8Array) { 16609 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>( 16610 v8::kExternalInt8Array, 16611 -0x80, 0x7F); 16612 } 16613 16614 16615 THREADED_TEST(FixedUint16Array) { 16616 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>( 16617 v8::kExternalUint16Array, 16618 0x0, 0xFFFF); 16619 } 16620 16621 16622 THREADED_TEST(FixedInt16Array) { 16623 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>( 16624 v8::kExternalInt16Array, 16625 -0x8000, 0x7FFF); 16626 } 16627 16628 16629 THREADED_TEST(FixedUint32Array) { 16630 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>( 16631 v8::kExternalUint32Array, 16632 0x0, UINT_MAX); 16633 } 16634 16635 16636 THREADED_TEST(FixedInt32Array) { 16637 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>( 16638 v8::kExternalInt32Array, 16639 INT_MIN, INT_MAX); 16640 } 16641 16642 16643 THREADED_TEST(FixedFloat32Array) { 16644 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>( 16645 v8::kExternalFloat32Array, 16646 -500, 500); 16647 } 16648 16649 16650 THREADED_TEST(FixedFloat64Array) { 16651 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>( 16652 v8::kExternalFloat64Array, 16653 -500, 500); 16654 } 16655 16656 16657 template <class ExternalArrayClass, class ElementType> 16658 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, 16659 int64_t low, 16660 int64_t high) { 16661 LocalContext context; 16662 i::Isolate* isolate = CcTest::i_isolate(); 16663 i::Factory* factory = isolate->factory(); 16664 v8::HandleScope scope(context->GetIsolate()); 16665 const int kElementCount = 40; 16666 int element_size = ExternalArrayElementSize(array_type); 16667 ElementType* array_data = 16668 static_cast<ElementType*>(malloc(kElementCount * element_size)); 16669 i::Handle<ExternalArrayClass> array = 16670 i::Handle<ExternalArrayClass>::cast( 16671 factory->NewExternalArray(kElementCount, array_type, array_data)); 16672 // Force GC to trigger verification. 16673 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16674 for (int i = 0; i < kElementCount; i++) { 16675 array->set(i, static_cast<ElementType>(i)); 16676 } 16677 // Force GC to trigger verification. 16678 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16679 for (int i = 0; i < kElementCount; i++) { 16680 CHECK_EQ(static_cast<int64_t>(i), 16681 static_cast<int64_t>(array->get_scalar(i))); 16682 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); 16683 } 16684 16685 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16686 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16687 // Set the elements to be the external array. 16688 obj->SetIndexedPropertiesToExternalArrayData(array_data, 16689 array_type, 16690 kElementCount); 16691 CHECK_EQ(1, 16692 static_cast<int>( 16693 i::Object::GetElement( 16694 isolate, jsobj, 1).ToHandleChecked()->Number())); 16695 16696 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16697 context.local(), obj, kElementCount, array_type, low, high); 16698 16699 v8::Handle<v8::Value> result; 16700 16701 // Test more complex manipulations which cause eax to contain values 16702 // that won't be completely overwritten by loads from the arrays. 16703 // This catches bugs in the instructions used for the KeyedLoadIC 16704 // for byte and word types. 16705 { 16706 const int kXSize = 300; 16707 const int kYSize = 300; 16708 const int kLargeElementCount = kXSize * kYSize * 4; 16709 ElementType* large_array_data = 16710 static_cast<ElementType*>(malloc(kLargeElementCount * element_size)); 16711 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate()); 16712 // Set the elements to be the external array. 16713 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data, 16714 array_type, 16715 kLargeElementCount); 16716 context->Global()->Set(v8_str("large_array"), large_obj); 16717 // Initialize contents of a few rows. 16718 for (int x = 0; x < 300; x++) { 16719 int row = 0; 16720 int offset = row * 300 * 4; 16721 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16722 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16723 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16724 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16725 row = 150; 16726 offset = row * 300 * 4; 16727 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16728 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16729 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16730 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16731 row = 298; 16732 offset = row * 300 * 4; 16733 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16734 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16735 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16736 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16737 } 16738 // The goal of the code below is to make "offset" large enough 16739 // that the computation of the index (which goes into eax) has 16740 // high bits set which will not be overwritten by a byte or short 16741 // load. 16742 result = CompileRun("var failed = false;" 16743 "var offset = 0;" 16744 "for (var i = 0; i < 300; i++) {" 16745 " if (large_array[4 * i] != 127 ||" 16746 " large_array[4 * i + 1] != 0 ||" 16747 " large_array[4 * i + 2] != 0 ||" 16748 " large_array[4 * i + 3] != 127) {" 16749 " failed = true;" 16750 " }" 16751 "}" 16752 "offset = 150 * 300 * 4;" 16753 "for (var i = 0; i < 300; i++) {" 16754 " if (large_array[offset + 4 * i] != 127 ||" 16755 " large_array[offset + 4 * i + 1] != 0 ||" 16756 " large_array[offset + 4 * i + 2] != 0 ||" 16757 " large_array[offset + 4 * i + 3] != 127) {" 16758 " failed = true;" 16759 " }" 16760 "}" 16761 "offset = 298 * 300 * 4;" 16762 "for (var i = 0; i < 300; i++) {" 16763 " if (large_array[offset + 4 * i] != 127 ||" 16764 " large_array[offset + 4 * i + 1] != 0 ||" 16765 " large_array[offset + 4 * i + 2] != 0 ||" 16766 " large_array[offset + 4 * i + 3] != 127) {" 16767 " failed = true;" 16768 " }" 16769 "}" 16770 "!failed;"); 16771 CHECK_EQ(true, result->BooleanValue()); 16772 free(large_array_data); 16773 } 16774 16775 // The "" property descriptor is overloaded to store information about 16776 // the external array. Ensure that setting and accessing the "" property 16777 // works (it should overwrite the information cached about the external 16778 // array in the DescriptorArray) in various situations. 16779 result = CompileRun("ext_array[''] = 23; ext_array['']"); 16780 CHECK_EQ(23, result->Int32Value()); 16781 16782 // Property "" set after the external array is associated with the object. 16783 { 16784 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16785 obj2->Set(v8_str("ee_test_field"), 16786 v8::Int32::New(context->GetIsolate(), 256)); 16787 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503)); 16788 // Set the elements to be the external array. 16789 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16790 array_type, 16791 kElementCount); 16792 context->Global()->Set(v8_str("ext_array"), obj2); 16793 result = CompileRun("ext_array['']"); 16794 CHECK_EQ(1503, result->Int32Value()); 16795 } 16796 16797 // Property "" set after the external array is associated with the object. 16798 { 16799 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16800 obj2->Set(v8_str("ee_test_field_2"), 16801 v8::Int32::New(context->GetIsolate(), 256)); 16802 // Set the elements to be the external array. 16803 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16804 array_type, 16805 kElementCount); 16806 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503)); 16807 context->Global()->Set(v8_str("ext_array"), obj2); 16808 result = CompileRun("ext_array['']"); 16809 CHECK_EQ(1503, result->Int32Value()); 16810 } 16811 16812 // Should reuse the map from previous test. 16813 { 16814 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16815 obj2->Set(v8_str("ee_test_field_2"), 16816 v8::Int32::New(context->GetIsolate(), 256)); 16817 // Set the elements to be the external array. Should re-use the map 16818 // from previous test. 16819 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16820 array_type, 16821 kElementCount); 16822 context->Global()->Set(v8_str("ext_array"), obj2); 16823 result = CompileRun("ext_array['']"); 16824 } 16825 16826 // Property "" is a constant function that shouldn't not be interfered with 16827 // when an external array is set. 16828 { 16829 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16830 // Start 16831 obj2->Set(v8_str("ee_test_field3"), 16832 v8::Int32::New(context->GetIsolate(), 256)); 16833 16834 // Add a constant function to an object. 16835 context->Global()->Set(v8_str("ext_array"), obj2); 16836 result = CompileRun("ext_array[''] = function() {return 1503;};" 16837 "ext_array['']();"); 16838 16839 // Add an external array transition to the same map that 16840 // has the constant transition. 16841 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate()); 16842 obj3->Set(v8_str("ee_test_field3"), 16843 v8::Int32::New(context->GetIsolate(), 256)); 16844 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16845 array_type, 16846 kElementCount); 16847 context->Global()->Set(v8_str("ext_array"), obj3); 16848 } 16849 16850 // If a external array transition is in the map, it should get clobbered 16851 // by a constant function. 16852 { 16853 // Add an external array transition. 16854 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate()); 16855 obj3->Set(v8_str("ee_test_field4"), 16856 v8::Int32::New(context->GetIsolate(), 256)); 16857 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16858 array_type, 16859 kElementCount); 16860 16861 // Add a constant function to the same map that just got an external array 16862 // transition. 16863 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate()); 16864 obj2->Set(v8_str("ee_test_field4"), 16865 v8::Int32::New(context->GetIsolate(), 256)); 16866 context->Global()->Set(v8_str("ext_array"), obj2); 16867 result = CompileRun("ext_array[''] = function() {return 1503;};" 16868 "ext_array['']();"); 16869 } 16870 16871 free(array_data); 16872 } 16873 16874 16875 THREADED_TEST(ExternalInt8Array) { 16876 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>( 16877 v8::kExternalInt8Array, 16878 -128, 16879 127); 16880 } 16881 16882 16883 THREADED_TEST(ExternalUint8Array) { 16884 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>( 16885 v8::kExternalUint8Array, 16886 0, 16887 255); 16888 } 16889 16890 16891 THREADED_TEST(ExternalUint8ClampedArray) { 16892 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>( 16893 v8::kExternalUint8ClampedArray, 16894 0, 16895 255); 16896 } 16897 16898 16899 THREADED_TEST(ExternalInt16Array) { 16900 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>( 16901 v8::kExternalInt16Array, 16902 -32768, 16903 32767); 16904 } 16905 16906 16907 THREADED_TEST(ExternalUint16Array) { 16908 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>( 16909 v8::kExternalUint16Array, 16910 0, 16911 65535); 16912 } 16913 16914 16915 THREADED_TEST(ExternalInt32Array) { 16916 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>( 16917 v8::kExternalInt32Array, 16918 INT_MIN, // -2147483648 16919 INT_MAX); // 2147483647 16920 } 16921 16922 16923 THREADED_TEST(ExternalUint32Array) { 16924 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>( 16925 v8::kExternalUint32Array, 16926 0, 16927 UINT_MAX); // 4294967295 16928 } 16929 16930 16931 THREADED_TEST(ExternalFloat32Array) { 16932 ExternalArrayTestHelper<i::ExternalFloat32Array, float>( 16933 v8::kExternalFloat32Array, 16934 -500, 16935 500); 16936 } 16937 16938 16939 THREADED_TEST(ExternalFloat64Array) { 16940 ExternalArrayTestHelper<i::ExternalFloat64Array, double>( 16941 v8::kExternalFloat64Array, 16942 -500, 16943 500); 16944 } 16945 16946 16947 THREADED_TEST(ExternalArrays) { 16948 TestExternalInt8Array(); 16949 TestExternalUint8Array(); 16950 TestExternalInt16Array(); 16951 TestExternalUint16Array(); 16952 TestExternalInt32Array(); 16953 TestExternalUint32Array(); 16954 TestExternalFloat32Array(); 16955 } 16956 16957 16958 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) { 16959 LocalContext context; 16960 v8::HandleScope scope(context->GetIsolate()); 16961 for (int size = 0; size < 100; size += 10) { 16962 int element_size = ExternalArrayElementSize(array_type); 16963 void* external_data = malloc(size * element_size); 16964 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate()); 16965 obj->SetIndexedPropertiesToExternalArrayData( 16966 external_data, array_type, size); 16967 CHECK(obj->HasIndexedPropertiesInExternalArrayData()); 16968 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData()); 16969 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType()); 16970 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength()); 16971 free(external_data); 16972 } 16973 } 16974 16975 16976 THREADED_TEST(ExternalArrayInfo) { 16977 ExternalArrayInfoTestHelper(v8::kExternalInt8Array); 16978 ExternalArrayInfoTestHelper(v8::kExternalUint8Array); 16979 ExternalArrayInfoTestHelper(v8::kExternalInt16Array); 16980 ExternalArrayInfoTestHelper(v8::kExternalUint16Array); 16981 ExternalArrayInfoTestHelper(v8::kExternalInt32Array); 16982 ExternalArrayInfoTestHelper(v8::kExternalUint32Array); 16983 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array); 16984 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array); 16985 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray); 16986 } 16987 16988 16989 void ExtArrayLimitsHelper(v8::Isolate* isolate, 16990 v8::ExternalArrayType array_type, 16991 int size) { 16992 v8::Handle<v8::Object> obj = v8::Object::New(isolate); 16993 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 16994 last_location = last_message = NULL; 16995 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size); 16996 CHECK(!obj->HasIndexedPropertiesInExternalArrayData()); 16997 CHECK_NE(NULL, last_location); 16998 CHECK_NE(NULL, last_message); 16999 } 17000 17001 17002 TEST(ExternalArrayLimits) { 17003 LocalContext context; 17004 v8::Isolate* isolate = context->GetIsolate(); 17005 v8::HandleScope scope(isolate); 17006 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000); 17007 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff); 17008 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000); 17009 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff); 17010 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000); 17011 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff); 17012 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000); 17013 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff); 17014 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000); 17015 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff); 17016 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000); 17017 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff); 17018 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000); 17019 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff); 17020 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000); 17021 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff); 17022 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000); 17023 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff); 17024 } 17025 17026 17027 template <typename ElementType, typename TypedArray, 17028 class ExternalArrayClass> 17029 void TypedArrayTestHelper(v8::ExternalArrayType array_type, 17030 int64_t low, int64_t high) { 17031 const int kElementCount = 50; 17032 17033 i::ScopedVector<ElementType> backing_store(kElementCount+2); 17034 17035 LocalContext env; 17036 v8::Isolate* isolate = env->GetIsolate(); 17037 v8::HandleScope handle_scope(isolate); 17038 17039 Local<v8::ArrayBuffer> ab = 17040 v8::ArrayBuffer::New(isolate, backing_store.start(), 17041 (kElementCount + 2) * sizeof(ElementType)); 17042 Local<TypedArray> ta = 17043 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 17044 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 17045 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 17046 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset())); 17047 CHECK_EQ(kElementCount*sizeof(ElementType), 17048 static_cast<int>(ta->ByteLength())); 17049 CHECK_EQ(ab, ta->Buffer()); 17050 17051 ElementType* data = backing_store.start() + 2; 17052 for (int i = 0; i < kElementCount; i++) { 17053 data[i] = static_cast<ElementType>(i); 17054 } 17055 17056 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 17057 env.local(), ta, kElementCount, array_type, low, high); 17058 } 17059 17060 17061 THREADED_TEST(Uint8Array) { 17062 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>( 17063 v8::kExternalUint8Array, 0, 0xFF); 17064 } 17065 17066 17067 THREADED_TEST(Int8Array) { 17068 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>( 17069 v8::kExternalInt8Array, -0x80, 0x7F); 17070 } 17071 17072 17073 THREADED_TEST(Uint16Array) { 17074 TypedArrayTestHelper<uint16_t, 17075 v8::Uint16Array, 17076 i::ExternalUint16Array>( 17077 v8::kExternalUint16Array, 0, 0xFFFF); 17078 } 17079 17080 17081 THREADED_TEST(Int16Array) { 17082 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>( 17083 v8::kExternalInt16Array, -0x8000, 0x7FFF); 17084 } 17085 17086 17087 THREADED_TEST(Uint32Array) { 17088 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>( 17089 v8::kExternalUint32Array, 0, UINT_MAX); 17090 } 17091 17092 17093 THREADED_TEST(Int32Array) { 17094 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>( 17095 v8::kExternalInt32Array, INT_MIN, INT_MAX); 17096 } 17097 17098 17099 THREADED_TEST(Float32Array) { 17100 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>( 17101 v8::kExternalFloat32Array, -500, 500); 17102 } 17103 17104 17105 THREADED_TEST(Float64Array) { 17106 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>( 17107 v8::kExternalFloat64Array, -500, 500); 17108 } 17109 17110 17111 THREADED_TEST(Uint8ClampedArray) { 17112 TypedArrayTestHelper<uint8_t, 17113 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>( 17114 v8::kExternalUint8ClampedArray, 0, 0xFF); 17115 } 17116 17117 17118 THREADED_TEST(DataView) { 17119 const int kSize = 50; 17120 17121 i::ScopedVector<uint8_t> backing_store(kSize+2); 17122 17123 LocalContext env; 17124 v8::Isolate* isolate = env->GetIsolate(); 17125 v8::HandleScope handle_scope(isolate); 17126 17127 Local<v8::ArrayBuffer> ab = 17128 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 17129 Local<v8::DataView> dv = 17130 v8::DataView::New(ab, 2, kSize); 17131 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 17132 CHECK_EQ(2, static_cast<int>(dv->ByteOffset())); 17133 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 17134 CHECK_EQ(ab, dv->Buffer()); 17135 } 17136 17137 17138 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 17139 THREADED_TEST(Is##View) { \ 17140 LocalContext env; \ 17141 v8::Isolate* isolate = env->GetIsolate(); \ 17142 v8::HandleScope handle_scope(isolate); \ 17143 \ 17144 Handle<Value> result = CompileRun( \ 17145 "var ab = new ArrayBuffer(128);" \ 17146 "new " #View "(ab)"); \ 17147 CHECK(result->IsArrayBufferView()); \ 17148 CHECK(result->Is##View()); \ 17149 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 17150 } 17151 17152 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 17153 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 17154 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 17155 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 17156 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 17157 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 17158 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 17159 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 17160 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 17161 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 17162 17163 #undef IS_ARRAY_BUFFER_VIEW_TEST 17164 17165 17166 17167 THREADED_TEST(ScriptContextDependence) { 17168 LocalContext c1; 17169 v8::HandleScope scope(c1->GetIsolate()); 17170 const char *source = "foo"; 17171 v8::Handle<v8::Script> dep = v8_compile(source); 17172 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8( 17173 c1->GetIsolate(), source)); 17174 v8::Handle<v8::UnboundScript> indep = 17175 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source); 17176 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"), 17177 v8::Integer::New(c1->GetIsolate(), 100)); 17178 CHECK_EQ(dep->Run()->Int32Value(), 100); 17179 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100); 17180 LocalContext c2; 17181 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"), 17182 v8::Integer::New(c2->GetIsolate(), 101)); 17183 CHECK_EQ(dep->Run()->Int32Value(), 100); 17184 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101); 17185 } 17186 17187 17188 THREADED_TEST(StackTrace) { 17189 LocalContext context; 17190 v8::HandleScope scope(context->GetIsolate()); 17191 v8::TryCatch try_catch; 17192 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 17193 v8::Handle<v8::String> src = 17194 v8::String::NewFromUtf8(context->GetIsolate(), source); 17195 v8::Handle<v8::String> origin = 17196 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test"); 17197 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin)); 17198 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source) 17199 ->BindToCurrentContext() 17200 ->Run(); 17201 CHECK(try_catch.HasCaught()); 17202 v8::String::Utf8Value stack(try_catch.StackTrace()); 17203 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 17204 } 17205 17206 17207 // Checks that a StackFrame has certain expected values. 17208 void checkStackFrame(const char* expected_script_name, 17209 const char* expected_func_name, int expected_line_number, 17210 int expected_column, bool is_eval, bool is_constructor, 17211 v8::Handle<v8::StackFrame> frame) { 17212 v8::HandleScope scope(CcTest::isolate()); 17213 v8::String::Utf8Value func_name(frame->GetFunctionName()); 17214 v8::String::Utf8Value script_name(frame->GetScriptName()); 17215 if (*script_name == NULL) { 17216 // The situation where there is no associated script, like for evals. 17217 CHECK(expected_script_name == NULL); 17218 } else { 17219 CHECK(strstr(*script_name, expected_script_name) != NULL); 17220 } 17221 CHECK(strstr(*func_name, expected_func_name) != NULL); 17222 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 17223 CHECK_EQ(expected_column, frame->GetColumn()); 17224 CHECK_EQ(is_eval, frame->IsEval()); 17225 CHECK_EQ(is_constructor, frame->IsConstructor()); 17226 } 17227 17228 17229 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 17230 v8::HandleScope scope(args.GetIsolate()); 17231 const char* origin = "capture-stack-trace-test"; 17232 const int kOverviewTest = 1; 17233 const int kDetailedTest = 2; 17234 17235 DCHECK(args.Length() == 1); 17236 17237 int testGroup = args[0]->Int32Value(); 17238 if (testGroup == kOverviewTest) { 17239 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17240 args.GetIsolate(), 10, v8::StackTrace::kOverview); 17241 CHECK_EQ(4, stackTrace->GetFrameCount()); 17242 checkStackFrame(origin, "bar", 2, 10, false, false, 17243 stackTrace->GetFrame(0)); 17244 checkStackFrame(origin, "foo", 6, 3, false, false, 17245 stackTrace->GetFrame(1)); 17246 // This is the source string inside the eval which has the call to foo. 17247 checkStackFrame(NULL, "", 1, 5, false, false, 17248 stackTrace->GetFrame(2)); 17249 // The last frame is an anonymous function which has the initial eval call. 17250 checkStackFrame(origin, "", 8, 7, false, false, 17251 stackTrace->GetFrame(3)); 17252 17253 CHECK(stackTrace->AsArray()->IsArray()); 17254 } else if (testGroup == kDetailedTest) { 17255 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17256 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17257 CHECK_EQ(4, stackTrace->GetFrameCount()); 17258 checkStackFrame(origin, "bat", 4, 22, false, false, 17259 stackTrace->GetFrame(0)); 17260 checkStackFrame(origin, "baz", 8, 3, false, true, 17261 stackTrace->GetFrame(1)); 17262 bool is_eval = true; 17263 // This is the source string inside the eval which has the call to baz. 17264 checkStackFrame(NULL, "", 1, 5, is_eval, false, 17265 stackTrace->GetFrame(2)); 17266 // The last frame is an anonymous function which has the initial eval call. 17267 checkStackFrame(origin, "", 10, 1, false, false, 17268 stackTrace->GetFrame(3)); 17269 17270 CHECK(stackTrace->AsArray()->IsArray()); 17271 } 17272 } 17273 17274 17275 // Tests the C++ StackTrace API. 17276 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 17277 // THREADED_TEST(CaptureStackTrace) { 17278 TEST(CaptureStackTrace) { 17279 v8::Isolate* isolate = CcTest::isolate(); 17280 v8::HandleScope scope(isolate); 17281 v8::Handle<v8::String> origin = 17282 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test"); 17283 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17284 templ->Set(v8_str("AnalyzeStackInNativeCode"), 17285 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode)); 17286 LocalContext context(0, templ); 17287 17288 // Test getting OVERVIEW information. Should ignore information that is not 17289 // script name, function name, line number, and column offset. 17290 const char *overview_source = 17291 "function bar() {\n" 17292 " var y; AnalyzeStackInNativeCode(1);\n" 17293 "}\n" 17294 "function foo() {\n" 17295 "\n" 17296 " bar();\n" 17297 "}\n" 17298 "var x;eval('new foo();');"; 17299 v8::Handle<v8::String> overview_src = 17300 v8::String::NewFromUtf8(isolate, overview_source); 17301 v8::ScriptCompiler::Source script_source(overview_src, 17302 v8::ScriptOrigin(origin)); 17303 v8::Handle<Value> overview_result( 17304 v8::ScriptCompiler::CompileUnbound(isolate, &script_source) 17305 ->BindToCurrentContext() 17306 ->Run()); 17307 CHECK(!overview_result.IsEmpty()); 17308 CHECK(overview_result->IsObject()); 17309 17310 // Test getting DETAILED information. 17311 const char *detailed_source = 17312 "function bat() {AnalyzeStackInNativeCode(2);\n" 17313 "}\n" 17314 "\n" 17315 "function baz() {\n" 17316 " bat();\n" 17317 "}\n" 17318 "eval('new baz();');"; 17319 v8::Handle<v8::String> detailed_src = 17320 v8::String::NewFromUtf8(isolate, detailed_source); 17321 // Make the script using a non-zero line and column offset. 17322 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3); 17323 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5); 17324 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 17325 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin); 17326 v8::Handle<v8::UnboundScript> detailed_script( 17327 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2)); 17328 v8::Handle<Value> detailed_result( 17329 detailed_script->BindToCurrentContext()->Run()); 17330 CHECK(!detailed_result.IsEmpty()); 17331 CHECK(detailed_result->IsObject()); 17332 } 17333 17334 17335 static void StackTraceForUncaughtExceptionListener( 17336 v8::Handle<v8::Message> message, 17337 v8::Handle<Value>) { 17338 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17339 CHECK_EQ(2, stack_trace->GetFrameCount()); 17340 checkStackFrame("origin", "foo", 2, 3, false, false, 17341 stack_trace->GetFrame(0)); 17342 checkStackFrame("origin", "bar", 5, 3, false, false, 17343 stack_trace->GetFrame(1)); 17344 } 17345 17346 17347 TEST(CaptureStackTraceForUncaughtException) { 17348 report_count = 0; 17349 LocalContext env; 17350 v8::HandleScope scope(env->GetIsolate()); 17351 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener); 17352 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17353 17354 CompileRunWithOrigin( 17355 "function foo() {\n" 17356 " throw 1;\n" 17357 "};\n" 17358 "function bar() {\n" 17359 " foo();\n" 17360 "};", 17361 "origin"); 17362 v8::Local<v8::Object> global = env->Global(); 17363 Local<Value> trouble = global->Get(v8_str("bar")); 17364 CHECK(trouble->IsFunction()); 17365 Function::Cast(*trouble)->Call(global, 0, NULL); 17366 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17367 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 17368 } 17369 17370 17371 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 17372 LocalContext env; 17373 v8::HandleScope scope(env->GetIsolate()); 17374 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, 17375 1024, 17376 v8::StackTrace::kDetailed); 17377 17378 CompileRun( 17379 "var setters = ['column', 'lineNumber', 'scriptName',\n" 17380 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 17381 " 'isConstructor'];\n" 17382 "for (var i = 0; i < setters.length; i++) {\n" 17383 " var prop = setters[i];\n" 17384 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 17385 "}\n"); 17386 CompileRun("throw 'exception';"); 17387 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17388 } 17389 17390 17391 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message, 17392 v8::Handle<v8::Value> data) { 17393 // Use the frame where JavaScript is called from. 17394 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17395 CHECK(!stack_trace.IsEmpty()); 17396 int frame_count = stack_trace->GetFrameCount(); 17397 CHECK_EQ(3, frame_count); 17398 int line_number[] = {1, 2, 5}; 17399 for (int i = 0; i < frame_count; i++) { 17400 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17401 } 17402 } 17403 17404 17405 // Test that we only return the stack trace at the site where the exception 17406 // is first thrown (not where it is rethrown). 17407 TEST(RethrowStackTrace) { 17408 LocalContext env; 17409 v8::HandleScope scope(env->GetIsolate()); 17410 // We make sure that 17411 // - the stack trace of the ReferenceError in g() is reported. 17412 // - the stack trace is not overwritten when e1 is rethrown by t(). 17413 // - the stack trace of e2 does not overwrite that of e1. 17414 const char* source = 17415 "function g() { error; } \n" 17416 "function f() { g(); } \n" 17417 "function t(e) { throw e; } \n" 17418 "try { \n" 17419 " f(); \n" 17420 "} catch (e1) { \n" 17421 " try { \n" 17422 " error; \n" 17423 " } catch (e2) { \n" 17424 " t(e1); \n" 17425 " } \n" 17426 "} \n"; 17427 v8::V8::AddMessageListener(RethrowStackTraceHandler); 17428 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17429 CompileRun(source); 17430 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17431 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler); 17432 } 17433 17434 17435 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message, 17436 v8::Handle<v8::Value> data) { 17437 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17438 CHECK(!stack_trace.IsEmpty()); 17439 int frame_count = stack_trace->GetFrameCount(); 17440 CHECK_EQ(2, frame_count); 17441 int line_number[] = {3, 7}; 17442 for (int i = 0; i < frame_count; i++) { 17443 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 17444 } 17445 } 17446 17447 17448 // Test that we do not recognize identity for primitive exceptions. 17449 TEST(RethrowPrimitiveStackTrace) { 17450 LocalContext env; 17451 v8::HandleScope scope(env->GetIsolate()); 17452 // We do not capture stack trace for non Error objects on creation time. 17453 // Instead, we capture the stack trace on last throw. 17454 const char* source = 17455 "function g() { throw 404; } \n" 17456 "function f() { g(); } \n" 17457 "function t(e) { throw e; } \n" 17458 "try { \n" 17459 " f(); \n" 17460 "} catch (e1) { \n" 17461 " t(e1) \n" 17462 "} \n"; 17463 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler); 17464 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17465 CompileRun(source); 17466 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17467 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 17468 } 17469 17470 17471 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message, 17472 v8::Handle<v8::Value> data) { 17473 // Use the frame where JavaScript is called from. 17474 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17475 CHECK(!stack_trace.IsEmpty()); 17476 CHECK_EQ(1, stack_trace->GetFrameCount()); 17477 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 17478 } 17479 17480 17481 // Test that the stack trace is captured when the error object is created and 17482 // not where it is thrown. 17483 TEST(RethrowExistingStackTrace) { 17484 LocalContext env; 17485 v8::HandleScope scope(env->GetIsolate()); 17486 const char* source = 17487 "var e = new Error(); \n" 17488 "throw e; \n"; 17489 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler); 17490 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17491 CompileRun(source); 17492 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17493 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler); 17494 } 17495 17496 17497 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message, 17498 v8::Handle<v8::Value> data) { 17499 // Use the frame where JavaScript is called from. 17500 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 17501 CHECK(!stack_trace.IsEmpty()); 17502 CHECK_EQ(1, stack_trace->GetFrameCount()); 17503 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 17504 } 17505 17506 17507 // Test that the stack trace is captured where the bogus Error object is thrown. 17508 TEST(RethrowBogusErrorStackTrace) { 17509 LocalContext env; 17510 v8::HandleScope scope(env->GetIsolate()); 17511 const char* source = 17512 "var e = {__proto__: new Error()} \n" 17513 "throw e; \n"; 17514 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler); 17515 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 17516 CompileRun(source); 17517 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 17518 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 17519 } 17520 17521 17522 void AnalyzeStackOfEvalWithSourceURL( 17523 const v8::FunctionCallbackInfo<v8::Value>& args) { 17524 v8::HandleScope scope(args.GetIsolate()); 17525 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17526 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17527 CHECK_EQ(5, stackTrace->GetFrameCount()); 17528 v8::Handle<v8::String> url = v8_str("eval_url"); 17529 for (int i = 0; i < 3; i++) { 17530 v8::Handle<v8::String> name = 17531 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17532 CHECK(!name.IsEmpty()); 17533 CHECK_EQ(url, name); 17534 } 17535 } 17536 17537 17538 TEST(SourceURLInStackTrace) { 17539 v8::Isolate* isolate = CcTest::isolate(); 17540 v8::HandleScope scope(isolate); 17541 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17542 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 17543 v8::FunctionTemplate::New(isolate, 17544 AnalyzeStackOfEvalWithSourceURL)); 17545 LocalContext context(0, templ); 17546 17547 const char *source = 17548 "function outer() {\n" 17549 "function bar() {\n" 17550 " AnalyzeStackOfEvalWithSourceURL();\n" 17551 "}\n" 17552 "function foo() {\n" 17553 "\n" 17554 " bar();\n" 17555 "}\n" 17556 "foo();\n" 17557 "}\n" 17558 "eval('(' + outer +')()%s');"; 17559 17560 i::ScopedVector<char> code(1024); 17561 i::SNPrintF(code, source, "//# sourceURL=eval_url"); 17562 CHECK(CompileRun(code.start())->IsUndefined()); 17563 i::SNPrintF(code, source, "//@ sourceURL=eval_url"); 17564 CHECK(CompileRun(code.start())->IsUndefined()); 17565 } 17566 17567 17568 static int scriptIdInStack[2]; 17569 17570 void AnalyzeScriptIdInStack( 17571 const v8::FunctionCallbackInfo<v8::Value>& args) { 17572 v8::HandleScope scope(args.GetIsolate()); 17573 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17574 args.GetIsolate(), 10, v8::StackTrace::kScriptId); 17575 CHECK_EQ(2, stackTrace->GetFrameCount()); 17576 for (int i = 0; i < 2; i++) { 17577 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId(); 17578 } 17579 } 17580 17581 17582 TEST(ScriptIdInStackTrace) { 17583 v8::Isolate* isolate = CcTest::isolate(); 17584 v8::HandleScope scope(isolate); 17585 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17586 templ->Set(v8_str("AnalyzeScriptIdInStack"), 17587 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack)); 17588 LocalContext context(0, templ); 17589 17590 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 17591 isolate, 17592 "function foo() {\n" 17593 " AnalyzeScriptIdInStack();" 17594 "}\n" 17595 "foo();\n"); 17596 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test"); 17597 script->Run(); 17598 for (int i = 0; i < 2; i++) { 17599 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); 17600 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId()); 17601 } 17602 } 17603 17604 17605 void AnalyzeStackOfInlineScriptWithSourceURL( 17606 const v8::FunctionCallbackInfo<v8::Value>& args) { 17607 v8::HandleScope scope(args.GetIsolate()); 17608 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17609 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17610 CHECK_EQ(4, stackTrace->GetFrameCount()); 17611 v8::Handle<v8::String> url = v8_str("url"); 17612 for (int i = 0; i < 3; i++) { 17613 v8::Handle<v8::String> name = 17614 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17615 CHECK(!name.IsEmpty()); 17616 CHECK_EQ(url, name); 17617 } 17618 } 17619 17620 17621 TEST(InlineScriptWithSourceURLInStackTrace) { 17622 v8::Isolate* isolate = CcTest::isolate(); 17623 v8::HandleScope scope(isolate); 17624 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17625 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 17626 v8::FunctionTemplate::New( 17627 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL)); 17628 LocalContext context(0, templ); 17629 17630 const char *source = 17631 "function outer() {\n" 17632 "function bar() {\n" 17633 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 17634 "}\n" 17635 "function foo() {\n" 17636 "\n" 17637 " bar();\n" 17638 "}\n" 17639 "foo();\n" 17640 "}\n" 17641 "outer()\n%s"; 17642 17643 i::ScopedVector<char> code(1024); 17644 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17645 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17646 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17647 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17648 } 17649 17650 17651 void AnalyzeStackOfDynamicScriptWithSourceURL( 17652 const v8::FunctionCallbackInfo<v8::Value>& args) { 17653 v8::HandleScope scope(args.GetIsolate()); 17654 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17655 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17656 CHECK_EQ(4, stackTrace->GetFrameCount()); 17657 v8::Handle<v8::String> url = v8_str("source_url"); 17658 for (int i = 0; i < 3; i++) { 17659 v8::Handle<v8::String> name = 17660 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17661 CHECK(!name.IsEmpty()); 17662 CHECK_EQ(url, name); 17663 } 17664 } 17665 17666 17667 TEST(DynamicWithSourceURLInStackTrace) { 17668 v8::Isolate* isolate = CcTest::isolate(); 17669 v8::HandleScope scope(isolate); 17670 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 17671 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 17672 v8::FunctionTemplate::New( 17673 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL)); 17674 LocalContext context(0, templ); 17675 17676 const char *source = 17677 "function outer() {\n" 17678 "function bar() {\n" 17679 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 17680 "}\n" 17681 "function foo() {\n" 17682 "\n" 17683 " bar();\n" 17684 "}\n" 17685 "foo();\n" 17686 "}\n" 17687 "outer()\n%s"; 17688 17689 i::ScopedVector<char> code(1024); 17690 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17691 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17692 i::SNPrintF(code, source, "//@ sourceURL=source_url"); 17693 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17694 } 17695 17696 17697 TEST(DynamicWithSourceURLInStackTraceString) { 17698 LocalContext context; 17699 v8::HandleScope scope(context->GetIsolate()); 17700 17701 const char *source = 17702 "function outer() {\n" 17703 " function foo() {\n" 17704 " FAIL.FAIL;\n" 17705 " }\n" 17706 " foo();\n" 17707 "}\n" 17708 "outer()\n%s"; 17709 17710 i::ScopedVector<char> code(1024); 17711 i::SNPrintF(code, source, "//# sourceURL=source_url"); 17712 v8::TryCatch try_catch; 17713 CompileRunWithOrigin(code.start(), "", 0, 0); 17714 CHECK(try_catch.HasCaught()); 17715 v8::String::Utf8Value stack(try_catch.StackTrace()); 17716 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL); 17717 } 17718 17719 17720 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17721 LocalContext context; 17722 v8::HandleScope scope(context->GetIsolate()); 17723 17724 const char *source = 17725 "function outer() {\n" 17726 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n" 17727 " //# sourceURL=source_url\";\n" 17728 " eval(scriptContents);\n" 17729 " foo(); }\n" 17730 "outer();\n" 17731 "//# sourceURL=outer_url"; 17732 17733 v8::TryCatch try_catch; 17734 CompileRun(source); 17735 CHECK(try_catch.HasCaught()); 17736 17737 Local<v8::Message> message = try_catch.Message(); 17738 Handle<Value> sourceURL = 17739 message->GetScriptOrigin().ResourceName(); 17740 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url"); 17741 } 17742 17743 17744 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) { 17745 LocalContext context; 17746 v8::HandleScope scope(context->GetIsolate()); 17747 17748 const char *source = 17749 "function outer() {\n" 17750 " var scriptContents = \"function boo(){ boo(); }\\\n" 17751 " //# sourceURL=source_url\";\n" 17752 " eval(scriptContents);\n" 17753 " boo(); }\n" 17754 "outer();\n" 17755 "//# sourceURL=outer_url"; 17756 17757 v8::TryCatch try_catch; 17758 CompileRun(source); 17759 CHECK(try_catch.HasCaught()); 17760 17761 Local<v8::Message> message = try_catch.Message(); 17762 Handle<Value> sourceURL = 17763 message->GetScriptOrigin().ResourceName(); 17764 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url"); 17765 } 17766 17767 17768 static void CreateGarbageInOldSpace() { 17769 i::Factory* factory = CcTest::i_isolate()->factory(); 17770 v8::HandleScope scope(CcTest::isolate()); 17771 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate()); 17772 for (int i = 0; i < 1000; i++) { 17773 factory->NewFixedArray(1000, i::TENURED); 17774 } 17775 } 17776 17777 17778 // Test that idle notification can be handled and eventually returns true. 17779 TEST(IdleNotification) { 17780 const intptr_t MB = 1024 * 1024; 17781 const int IdlePauseInMs = 1000; 17782 LocalContext env; 17783 v8::HandleScope scope(env->GetIsolate()); 17784 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17785 CreateGarbageInOldSpace(); 17786 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17787 CHECK_GT(size_with_garbage, initial_size + MB); 17788 bool finished = false; 17789 for (int i = 0; i < 200 && !finished; i++) { 17790 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); 17791 } 17792 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17793 CHECK(finished); 17794 CHECK_LT(final_size, initial_size + 1); 17795 } 17796 17797 17798 // Test that idle notification can be handled and eventually collects garbage. 17799 TEST(IdleNotificationWithSmallHint) { 17800 const intptr_t MB = 1024 * 1024; 17801 const int IdlePauseInMs = 900; 17802 LocalContext env; 17803 v8::HandleScope scope(env->GetIsolate()); 17804 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17805 CreateGarbageInOldSpace(); 17806 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17807 CHECK_GT(size_with_garbage, initial_size + MB); 17808 bool finished = false; 17809 for (int i = 0; i < 200 && !finished; i++) { 17810 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); 17811 } 17812 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17813 CHECK(finished); 17814 CHECK_LT(final_size, initial_size + 1); 17815 } 17816 17817 17818 // Test that idle notification can be handled and eventually collects garbage. 17819 TEST(IdleNotificationWithLargeHint) { 17820 const intptr_t MB = 1024 * 1024; 17821 const int IdlePauseInMs = 900; 17822 LocalContext env; 17823 v8::HandleScope scope(env->GetIsolate()); 17824 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17825 CreateGarbageInOldSpace(); 17826 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17827 CHECK_GT(size_with_garbage, initial_size + MB); 17828 bool finished = false; 17829 for (int i = 0; i < 200 && !finished; i++) { 17830 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); 17831 } 17832 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17833 CHECK(finished); 17834 CHECK_LT(final_size, initial_size + 1); 17835 } 17836 17837 17838 TEST(Regress2107) { 17839 const intptr_t MB = 1024 * 1024; 17840 const int kIdlePauseInMs = 1000; 17841 LocalContext env; 17842 v8::Isolate* isolate = env->GetIsolate(); 17843 v8::HandleScope scope(env->GetIsolate()); 17844 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17845 // Send idle notification to start a round of incremental GCs. 17846 env->GetIsolate()->IdleNotification(kIdlePauseInMs); 17847 // Emulate 7 page reloads. 17848 for (int i = 0; i < 7; i++) { 17849 { 17850 v8::HandleScope inner_scope(env->GetIsolate()); 17851 v8::Local<v8::Context> ctx = v8::Context::New(isolate); 17852 ctx->Enter(); 17853 CreateGarbageInOldSpace(); 17854 ctx->Exit(); 17855 } 17856 env->GetIsolate()->ContextDisposedNotification(); 17857 env->GetIsolate()->IdleNotification(kIdlePauseInMs); 17858 } 17859 // Create garbage and check that idle notification still collects it. 17860 CreateGarbageInOldSpace(); 17861 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17862 CHECK_GT(size_with_garbage, initial_size + MB); 17863 bool finished = false; 17864 for (int i = 0; i < 200 && !finished; i++) { 17865 finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs); 17866 } 17867 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17868 CHECK_LT(final_size, initial_size + 1); 17869 } 17870 17871 17872 TEST(Regress2333) { 17873 LocalContext env; 17874 for (int i = 0; i < 3; i++) { 17875 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 17876 } 17877 } 17878 17879 static uint32_t* stack_limit; 17880 17881 static void GetStackLimitCallback( 17882 const v8::FunctionCallbackInfo<v8::Value>& args) { 17883 stack_limit = reinterpret_cast<uint32_t*>( 17884 CcTest::i_isolate()->stack_guard()->real_climit()); 17885 } 17886 17887 17888 // Uses the address of a local variable to determine the stack top now. 17889 // Given a size, returns an address that is that far from the current 17890 // top of stack. 17891 static uint32_t* ComputeStackLimit(uint32_t size) { 17892 uint32_t* answer = &size - (size / sizeof(size)); 17893 // If the size is very large and the stack is very near the bottom of 17894 // memory then the calculation above may wrap around and give an address 17895 // that is above the (downwards-growing) stack. In that case we return 17896 // a very low address. 17897 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 17898 return answer; 17899 } 17900 17901 17902 // We need at least 165kB for an x64 debug build with clang and ASAN. 17903 static const int stack_breathing_room = 256 * i::KB; 17904 17905 17906 TEST(SetStackLimit) { 17907 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 17908 17909 // Set stack limit. 17910 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17911 17912 // Execute a script. 17913 LocalContext env; 17914 v8::HandleScope scope(env->GetIsolate()); 17915 Local<v8::FunctionTemplate> fun_templ = 17916 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback); 17917 Local<Function> fun = fun_templ->GetFunction(); 17918 env->Global()->Set(v8_str("get_stack_limit"), fun); 17919 CompileRun("get_stack_limit();"); 17920 17921 CHECK(stack_limit == set_limit); 17922 } 17923 17924 17925 TEST(SetStackLimitInThread) { 17926 uint32_t* set_limit; 17927 { 17928 v8::Locker locker(CcTest::isolate()); 17929 set_limit = ComputeStackLimit(stack_breathing_room); 17930 17931 // Set stack limit. 17932 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit)); 17933 17934 // Execute a script. 17935 v8::HandleScope scope(CcTest::isolate()); 17936 LocalContext env; 17937 Local<v8::FunctionTemplate> fun_templ = 17938 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback); 17939 Local<Function> fun = fun_templ->GetFunction(); 17940 env->Global()->Set(v8_str("get_stack_limit"), fun); 17941 CompileRun("get_stack_limit();"); 17942 17943 CHECK(stack_limit == set_limit); 17944 } 17945 { 17946 v8::Locker locker(CcTest::isolate()); 17947 CHECK(stack_limit == set_limit); 17948 } 17949 } 17950 17951 17952 THREADED_TEST(GetHeapStatistics) { 17953 LocalContext c1; 17954 v8::HandleScope scope(c1->GetIsolate()); 17955 v8::HeapStatistics heap_statistics; 17956 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0); 17957 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0); 17958 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 17959 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 17960 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 17961 } 17962 17963 17964 class VisitorImpl : public v8::ExternalResourceVisitor { 17965 public: 17966 explicit VisitorImpl(TestResource** resource) { 17967 for (int i = 0; i < 4; i++) { 17968 resource_[i] = resource[i]; 17969 found_resource_[i] = false; 17970 } 17971 } 17972 virtual ~VisitorImpl() {} 17973 virtual void VisitExternalString(v8::Handle<v8::String> string) { 17974 if (!string->IsExternal()) { 17975 CHECK(string->IsExternalOneByte()); 17976 return; 17977 } 17978 v8::String::ExternalStringResource* resource = 17979 string->GetExternalStringResource(); 17980 CHECK(resource); 17981 for (int i = 0; i < 4; i++) { 17982 if (resource_[i] == resource) { 17983 CHECK(!found_resource_[i]); 17984 found_resource_[i] = true; 17985 } 17986 } 17987 } 17988 void CheckVisitedResources() { 17989 for (int i = 0; i < 4; i++) { 17990 CHECK(found_resource_[i]); 17991 } 17992 } 17993 17994 private: 17995 v8::String::ExternalStringResource* resource_[4]; 17996 bool found_resource_[4]; 17997 }; 17998 17999 18000 TEST(ExternalizeOldSpaceTwoByteCons) { 18001 LocalContext env; 18002 v8::HandleScope scope(env->GetIsolate()); 18003 v8::Local<v8::String> cons = 18004 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(); 18005 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 18006 CcTest::heap()->CollectAllAvailableGarbage(); 18007 CHECK(CcTest::heap()->old_pointer_space()->Contains( 18008 *v8::Utils::OpenHandle(*cons))); 18009 18010 TestResource* resource = new TestResource( 18011 AsciiToTwoByteString("Romeo Montague Juliet Capulet")); 18012 cons->MakeExternal(resource); 18013 18014 CHECK(cons->IsExternal()); 18015 CHECK_EQ(resource, cons->GetExternalStringResource()); 18016 String::Encoding encoding; 18017 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 18018 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 18019 } 18020 18021 18022 TEST(ExternalizeOldSpaceOneByteCons) { 18023 LocalContext env; 18024 v8::HandleScope scope(env->GetIsolate()); 18025 v8::Local<v8::String> cons = 18026 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(); 18027 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); 18028 CcTest::heap()->CollectAllAvailableGarbage(); 18029 CHECK(CcTest::heap()->old_pointer_space()->Contains( 18030 *v8::Utils::OpenHandle(*cons))); 18031 18032 TestOneByteResource* resource = 18033 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet")); 18034 cons->MakeExternal(resource); 18035 18036 CHECK(cons->IsExternalOneByte()); 18037 CHECK_EQ(resource, cons->GetExternalOneByteStringResource()); 18038 String::Encoding encoding; 18039 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding)); 18040 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding); 18041 } 18042 18043 18044 TEST(VisitExternalStrings) { 18045 LocalContext env; 18046 v8::HandleScope scope(env->GetIsolate()); 18047 const char* string = "Some string"; 18048 uint16_t* two_byte_string = AsciiToTwoByteString(string); 18049 TestResource* resource[4]; 18050 resource[0] = new TestResource(two_byte_string); 18051 v8::Local<v8::String> string0 = 18052 v8::String::NewExternal(env->GetIsolate(), resource[0]); 18053 resource[1] = new TestResource(two_byte_string, NULL, false); 18054 v8::Local<v8::String> string1 = 18055 v8::String::NewExternal(env->GetIsolate(), resource[1]); 18056 18057 // Externalized symbol. 18058 resource[2] = new TestResource(two_byte_string, NULL, false); 18059 v8::Local<v8::String> string2 = v8::String::NewFromUtf8( 18060 env->GetIsolate(), string, v8::String::kInternalizedString); 18061 CHECK(string2->MakeExternal(resource[2])); 18062 18063 // Symbolized External. 18064 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 18065 v8::Local<v8::String> string3 = 18066 v8::String::NewExternal(env->GetIsolate(), resource[3]); 18067 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. 18068 // Turn into a symbol. 18069 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 18070 CHECK(!CcTest::i_isolate()->factory()->InternalizeString( 18071 string3_i).is_null()); 18072 CHECK(string3_i->IsInternalizedString()); 18073 18074 // We need to add usages for string* to avoid warnings in GCC 4.7 18075 CHECK(string0->IsExternal()); 18076 CHECK(string1->IsExternal()); 18077 CHECK(string2->IsExternal()); 18078 CHECK(string3->IsExternal()); 18079 18080 VisitorImpl visitor(resource); 18081 v8::V8::VisitExternalResources(&visitor); 18082 visitor.CheckVisitedResources(); 18083 } 18084 18085 18086 TEST(ExternalStringCollectedAtTearDown) { 18087 int destroyed = 0; 18088 v8::Isolate* isolate = v8::Isolate::New(); 18089 { v8::Isolate::Scope isolate_scope(isolate); 18090 v8::HandleScope handle_scope(isolate); 18091 const char* s = "One string to test them all, one string to find them."; 18092 TestOneByteResource* inscription = 18093 new TestOneByteResource(i::StrDup(s), &destroyed); 18094 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription); 18095 // Ring is still alive. Orcs are roaming freely across our lands. 18096 CHECK_EQ(0, destroyed); 18097 USE(ring); 18098 } 18099 18100 isolate->Dispose(); 18101 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18102 CHECK_EQ(1, destroyed); 18103 } 18104 18105 18106 TEST(ExternalInternalizedStringCollectedAtTearDown) { 18107 int destroyed = 0; 18108 v8::Isolate* isolate = v8::Isolate::New(); 18109 { v8::Isolate::Scope isolate_scope(isolate); 18110 LocalContext env(isolate); 18111 v8::HandleScope handle_scope(isolate); 18112 CompileRun("var ring = 'One string to test them all';"); 18113 const char* s = "One string to test them all"; 18114 TestOneByteResource* inscription = 18115 new TestOneByteResource(i::StrDup(s), &destroyed); 18116 v8::Local<v8::String> ring = CompileRun("ring")->ToString(); 18117 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18118 ring->MakeExternal(inscription); 18119 // Ring is still alive. Orcs are roaming freely across our lands. 18120 CHECK_EQ(0, destroyed); 18121 USE(ring); 18122 } 18123 18124 isolate->Dispose(); 18125 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18126 CHECK_EQ(1, destroyed); 18127 } 18128 18129 18130 TEST(ExternalInternalizedStringCollectedAtGC) { 18131 int destroyed = 0; 18132 { LocalContext env; 18133 v8::HandleScope handle_scope(env->GetIsolate()); 18134 CompileRun("var ring = 'One string to test them all';"); 18135 const char* s = "One string to test them all"; 18136 TestOneByteResource* inscription = 18137 new TestOneByteResource(i::StrDup(s), &destroyed); 18138 v8::Local<v8::String> ring = CompileRun("ring")->ToString(); 18139 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString()); 18140 ring->MakeExternal(inscription); 18141 // Ring is still alive. Orcs are roaming freely across our lands. 18142 CHECK_EQ(0, destroyed); 18143 USE(ring); 18144 } 18145 18146 // Garbage collector deals swift blows to evil. 18147 CcTest::i_isolate()->compilation_cache()->Clear(); 18148 CcTest::heap()->CollectAllAvailableGarbage(); 18149 18150 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 18151 CHECK_EQ(1, destroyed); 18152 } 18153 18154 18155 static double DoubleFromBits(uint64_t value) { 18156 double target; 18157 i::MemCopy(&target, &value, sizeof(target)); 18158 return target; 18159 } 18160 18161 18162 static uint64_t DoubleToBits(double value) { 18163 uint64_t target; 18164 i::MemCopy(&target, &value, sizeof(target)); 18165 return target; 18166 } 18167 18168 18169 static double DoubleToDateTime(double input) { 18170 double date_limit = 864e13; 18171 if (std::isnan(input) || input < -date_limit || input > date_limit) { 18172 return v8::base::OS::nan_value(); 18173 } 18174 return (input < 0) ? -(std::floor(-input)) : std::floor(input); 18175 } 18176 18177 18178 // We don't have a consistent way to write 64-bit constants syntactically, so we 18179 // split them into two 32-bit constants and combine them programmatically. 18180 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 18181 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 18182 } 18183 18184 18185 THREADED_TEST(QuietSignalingNaNs) { 18186 LocalContext context; 18187 v8::Isolate* isolate = context->GetIsolate(); 18188 v8::HandleScope scope(isolate); 18189 v8::TryCatch try_catch; 18190 18191 // Special double values. 18192 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 18193 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 18194 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 18195 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 18196 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 18197 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 18198 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 18199 18200 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 18201 // on either side of the epoch. 18202 double date_limit = 864e13; 18203 18204 double test_values[] = { 18205 snan, 18206 qnan, 18207 infinity, 18208 max_normal, 18209 date_limit + 1, 18210 date_limit, 18211 min_normal, 18212 max_denormal, 18213 min_denormal, 18214 0, 18215 -0, 18216 -min_denormal, 18217 -max_denormal, 18218 -min_normal, 18219 -date_limit, 18220 -date_limit - 1, 18221 -max_normal, 18222 -infinity, 18223 -qnan, 18224 -snan 18225 }; 18226 int num_test_values = 20; 18227 18228 for (int i = 0; i < num_test_values; i++) { 18229 double test_value = test_values[i]; 18230 18231 // Check that Number::New preserves non-NaNs and quiets SNaNs. 18232 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value); 18233 double stored_number = number->NumberValue(); 18234 if (!std::isnan(test_value)) { 18235 CHECK_EQ(test_value, stored_number); 18236 } else { 18237 uint64_t stored_bits = DoubleToBits(stored_number); 18238 // Check if quiet nan (bits 51..62 all set). 18239 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 18240 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR) 18241 // Most significant fraction bit for quiet nan is set to 0 18242 // on MIPS architecture. Allowed by IEEE-754. 18243 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18244 #else 18245 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18246 #endif 18247 } 18248 18249 // Check that Date::New preserves non-NaNs in the date range and 18250 // quiets SNaNs. 18251 v8::Handle<v8::Value> date = 18252 v8::Date::New(isolate, test_value); 18253 double expected_stored_date = DoubleToDateTime(test_value); 18254 double stored_date = date->NumberValue(); 18255 if (!std::isnan(expected_stored_date)) { 18256 CHECK_EQ(expected_stored_date, stored_date); 18257 } else { 18258 uint64_t stored_bits = DoubleToBits(stored_date); 18259 // Check if quiet nan (bits 51..62 all set). 18260 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \ 18261 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR) 18262 // Most significant fraction bit for quiet nan is set to 0 18263 // on MIPS architecture. Allowed by IEEE-754. 18264 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 18265 #else 18266 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 18267 #endif 18268 } 18269 } 18270 } 18271 18272 18273 static void SpaghettiIncident( 18274 const v8::FunctionCallbackInfo<v8::Value>& args) { 18275 v8::HandleScope scope(args.GetIsolate()); 18276 v8::TryCatch tc; 18277 v8::Handle<v8::String> str(args[0]->ToString()); 18278 USE(str); 18279 if (tc.HasCaught()) 18280 tc.ReThrow(); 18281 } 18282 18283 18284 // Test that an exception can be propagated down through a spaghetti 18285 // stack using ReThrow. 18286 THREADED_TEST(SpaghettiStackReThrow) { 18287 v8::Isolate* isolate = CcTest::isolate(); 18288 v8::HandleScope scope(isolate); 18289 LocalContext context; 18290 context->Global()->Set( 18291 v8::String::NewFromUtf8(isolate, "s"), 18292 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction()); 18293 v8::TryCatch try_catch; 18294 CompileRun( 18295 "var i = 0;" 18296 "var o = {" 18297 " toString: function () {" 18298 " if (i == 10) {" 18299 " throw 'Hey!';" 18300 " } else {" 18301 " i++;" 18302 " return s(o);" 18303 " }" 18304 " }" 18305 "};" 18306 "s(o);"); 18307 CHECK(try_catch.HasCaught()); 18308 v8::String::Utf8Value value(try_catch.Exception()); 18309 CHECK_EQ(0, strcmp(*value, "Hey!")); 18310 } 18311 18312 18313 TEST(Regress528) { 18314 v8::V8::Initialize(); 18315 v8::Isolate* isolate = CcTest::isolate(); 18316 v8::HandleScope scope(isolate); 18317 v8::Local<Context> other_context; 18318 int gc_count; 18319 18320 // Create a context used to keep the code from aging in the compilation 18321 // cache. 18322 other_context = Context::New(isolate); 18323 18324 // Context-dependent context data creates reference from the compilation 18325 // cache to the global object. 18326 const char* source_simple = "1"; 18327 { 18328 v8::HandleScope scope(isolate); 18329 v8::Local<Context> context = Context::New(isolate); 18330 18331 context->Enter(); 18332 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, ""); 18333 context->SetEmbedderData(0, obj); 18334 CompileRun(source_simple); 18335 context->Exit(); 18336 } 18337 isolate->ContextDisposedNotification(); 18338 for (gc_count = 1; gc_count < 10; gc_count++) { 18339 other_context->Enter(); 18340 CompileRun(source_simple); 18341 other_context->Exit(); 18342 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18343 if (GetGlobalObjectsCount() == 1) break; 18344 } 18345 CHECK_GE(2, gc_count); 18346 CHECK_EQ(1, GetGlobalObjectsCount()); 18347 18348 // Eval in a function creates reference from the compilation cache to the 18349 // global object. 18350 const char* source_eval = "function f(){eval('1')}; f()"; 18351 { 18352 v8::HandleScope scope(isolate); 18353 v8::Local<Context> context = Context::New(isolate); 18354 18355 context->Enter(); 18356 CompileRun(source_eval); 18357 context->Exit(); 18358 } 18359 isolate->ContextDisposedNotification(); 18360 for (gc_count = 1; gc_count < 10; gc_count++) { 18361 other_context->Enter(); 18362 CompileRun(source_eval); 18363 other_context->Exit(); 18364 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18365 if (GetGlobalObjectsCount() == 1) break; 18366 } 18367 CHECK_GE(2, gc_count); 18368 CHECK_EQ(1, GetGlobalObjectsCount()); 18369 18370 // Looking up the line number for an exception creates reference from the 18371 // compilation cache to the global object. 18372 const char* source_exception = "function f(){throw 1;} f()"; 18373 { 18374 v8::HandleScope scope(isolate); 18375 v8::Local<Context> context = Context::New(isolate); 18376 18377 context->Enter(); 18378 v8::TryCatch try_catch; 18379 CompileRun(source_exception); 18380 CHECK(try_catch.HasCaught()); 18381 v8::Handle<v8::Message> message = try_catch.Message(); 18382 CHECK(!message.IsEmpty()); 18383 CHECK_EQ(1, message->GetLineNumber()); 18384 context->Exit(); 18385 } 18386 isolate->ContextDisposedNotification(); 18387 for (gc_count = 1; gc_count < 10; gc_count++) { 18388 other_context->Enter(); 18389 CompileRun(source_exception); 18390 other_context->Exit(); 18391 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18392 if (GetGlobalObjectsCount() == 1) break; 18393 } 18394 CHECK_GE(2, gc_count); 18395 CHECK_EQ(1, GetGlobalObjectsCount()); 18396 18397 isolate->ContextDisposedNotification(); 18398 } 18399 18400 18401 THREADED_TEST(ScriptOrigin) { 18402 LocalContext env; 18403 v8::HandleScope scope(env->GetIsolate()); 18404 v8::ScriptOrigin origin = 18405 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18406 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18407 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 18408 v8::Script::Compile(script, &origin)->Run(); 18409 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18410 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18411 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18412 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18413 18414 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 18415 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName())); 18416 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value()); 18417 18418 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 18419 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName())); 18420 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value()); 18421 } 18422 18423 18424 THREADED_TEST(FunctionGetInferredName) { 18425 LocalContext env; 18426 v8::HandleScope scope(env->GetIsolate()); 18427 v8::ScriptOrigin origin = 18428 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18429 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18430 env->GetIsolate(), 18431 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 18432 v8::Script::Compile(script, &origin)->Run(); 18433 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18434 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18435 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); 18436 } 18437 18438 18439 THREADED_TEST(FunctionGetDisplayName) { 18440 LocalContext env; 18441 v8::HandleScope scope(env->GetIsolate()); 18442 const char* code = "var error = false;" 18443 "function a() { this.x = 1; };" 18444 "a.displayName = 'display_a';" 18445 "var b = (function() {" 18446 " var f = function() { this.x = 2; };" 18447 " f.displayName = 'display_b';" 18448 " return f;" 18449 "})();" 18450 "var c = function() {};" 18451 "c.__defineGetter__('displayName', function() {" 18452 " error = true;" 18453 " throw new Error();" 18454 "});" 18455 "function d() {};" 18456 "d.__defineGetter__('displayName', function() {" 18457 " error = true;" 18458 " return 'wrong_display_name';" 18459 "});" 18460 "function e() {};" 18461 "e.displayName = 'wrong_display_name';" 18462 "e.__defineSetter__('displayName', function() {" 18463 " error = true;" 18464 " throw new Error();" 18465 "});" 18466 "function f() {};" 18467 "f.displayName = { 'foo': 6, toString: function() {" 18468 " error = true;" 18469 " return 'wrong_display_name';" 18470 "}};" 18471 "var g = function() {" 18472 " arguments.callee.displayName = 'set_in_runtime';" 18473 "}; g();" 18474 ; 18475 v8::ScriptOrigin origin = 18476 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18477 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin) 18478 ->Run(); 18479 v8::Local<v8::Value> error = 18480 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error")); 18481 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( 18482 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a"))); 18483 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( 18484 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b"))); 18485 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( 18486 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"))); 18487 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( 18488 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d"))); 18489 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( 18490 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e"))); 18491 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18492 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18493 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18494 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18495 CHECK_EQ(false, error->BooleanValue()); 18496 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName())); 18497 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName())); 18498 CHECK(c->GetDisplayName()->IsUndefined()); 18499 CHECK(d->GetDisplayName()->IsUndefined()); 18500 CHECK(e->GetDisplayName()->IsUndefined()); 18501 CHECK(f->GetDisplayName()->IsUndefined()); 18502 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())); 18503 } 18504 18505 18506 THREADED_TEST(ScriptLineNumber) { 18507 LocalContext env; 18508 v8::HandleScope scope(env->GetIsolate()); 18509 v8::ScriptOrigin origin = 18510 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 18511 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18512 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 18513 v8::Script::Compile(script, &origin)->Run(); 18514 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18515 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18516 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18517 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18518 CHECK_EQ(0, f->GetScriptLineNumber()); 18519 CHECK_EQ(2, g->GetScriptLineNumber()); 18520 } 18521 18522 18523 THREADED_TEST(ScriptColumnNumber) { 18524 LocalContext env; 18525 v8::Isolate* isolate = env->GetIsolate(); 18526 v8::HandleScope scope(isolate); 18527 v8::ScriptOrigin origin = 18528 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"), 18529 v8::Integer::New(isolate, 3), 18530 v8::Integer::New(isolate, 2)); 18531 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18532 isolate, "function foo() {}\n\n function bar() {}"); 18533 v8::Script::Compile(script, &origin)->Run(); 18534 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18535 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"))); 18536 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18537 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar"))); 18538 CHECK_EQ(14, foo->GetScriptColumnNumber()); 18539 CHECK_EQ(17, bar->GetScriptColumnNumber()); 18540 } 18541 18542 18543 THREADED_TEST(FunctionIsBuiltin) { 18544 LocalContext env; 18545 v8::Isolate* isolate = env->GetIsolate(); 18546 v8::HandleScope scope(isolate); 18547 v8::Local<v8::Function> f; 18548 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); 18549 CHECK(f->IsBuiltin()); 18550 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); 18551 CHECK(f->IsBuiltin()); 18552 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); 18553 CHECK(f->IsBuiltin()); 18554 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); 18555 CHECK(f->IsBuiltin()); 18556 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); 18557 CHECK(!f->IsBuiltin()); 18558 } 18559 18560 18561 THREADED_TEST(FunctionGetScriptId) { 18562 LocalContext env; 18563 v8::Isolate* isolate = env->GetIsolate(); 18564 v8::HandleScope scope(isolate); 18565 v8::ScriptOrigin origin = 18566 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"), 18567 v8::Integer::New(isolate, 3), 18568 v8::Integer::New(isolate, 2)); 18569 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 18570 isolate, "function foo() {}\n\n function bar() {}"); 18571 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); 18572 script->Run(); 18573 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 18574 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo"))); 18575 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 18576 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar"))); 18577 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId()); 18578 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId()); 18579 } 18580 18581 18582 THREADED_TEST(FunctionGetBoundFunction) { 18583 LocalContext env; 18584 v8::HandleScope scope(env->GetIsolate()); 18585 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8( 18586 env->GetIsolate(), "test")); 18587 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 18588 env->GetIsolate(), 18589 "var a = new Object();\n" 18590 "a.x = 1;\n" 18591 "function f () { return this.x };\n" 18592 "var g = f.bind(a);\n" 18593 "var b = g();"); 18594 v8::Script::Compile(script, &origin)->Run(); 18595 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 18596 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 18597 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 18598 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 18599 CHECK(g->GetBoundFunction()->IsFunction()); 18600 Local<v8::Function> original_function = Local<v8::Function>::Cast( 18601 g->GetBoundFunction()); 18602 CHECK_EQ(f->GetName(), original_function->GetName()); 18603 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber()); 18604 CHECK_EQ(f->GetScriptColumnNumber(), 18605 original_function->GetScriptColumnNumber()); 18606 } 18607 18608 18609 static void GetterWhichReturns42( 18610 Local<String> name, 18611 const v8::PropertyCallbackInfo<v8::Value>& info) { 18612 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18613 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18614 info.GetReturnValue().Set(v8_num(42)); 18615 } 18616 18617 18618 static void SetterWhichSetsYOnThisTo23( 18619 Local<String> name, 18620 Local<Value> value, 18621 const v8::PropertyCallbackInfo<void>& info) { 18622 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18623 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18624 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18625 } 18626 18627 18628 void FooGetInterceptor(Local<String> name, 18629 const v8::PropertyCallbackInfo<v8::Value>& info) { 18630 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18631 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18632 if (!name->Equals(v8_str("foo"))) return; 18633 info.GetReturnValue().Set(v8_num(42)); 18634 } 18635 18636 18637 void FooSetInterceptor(Local<String> name, 18638 Local<Value> value, 18639 const v8::PropertyCallbackInfo<v8::Value>& info) { 18640 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 18641 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 18642 if (!name->Equals(v8_str("foo"))) return; 18643 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18644 info.GetReturnValue().Set(v8_num(23)); 18645 } 18646 18647 18648 TEST(SetterOnConstructorPrototype) { 18649 v8::Isolate* isolate = CcTest::isolate(); 18650 v8::HandleScope scope(isolate); 18651 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18652 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 18653 SetterWhichSetsYOnThisTo23); 18654 LocalContext context; 18655 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18656 CompileRun("function C1() {" 18657 " this.x = 23;" 18658 "};" 18659 "C1.prototype = P;" 18660 "function C2() {" 18661 " this.x = 23" 18662 "};" 18663 "C2.prototype = { };" 18664 "C2.prototype.__proto__ = P;"); 18665 18666 v8::Local<v8::Script> script; 18667 script = v8_compile("new C1();"); 18668 for (int i = 0; i < 10; i++) { 18669 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18670 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 18671 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 18672 } 18673 18674 script = v8_compile("new C2();"); 18675 for (int i = 0; i < 10; i++) { 18676 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 18677 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value()); 18678 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value()); 18679 } 18680 } 18681 18682 18683 static void NamedPropertyGetterWhichReturns42( 18684 Local<String> name, 18685 const v8::PropertyCallbackInfo<v8::Value>& info) { 18686 info.GetReturnValue().Set(v8_num(42)); 18687 } 18688 18689 18690 static void NamedPropertySetterWhichSetsYOnThisTo23( 18691 Local<String> name, 18692 Local<Value> value, 18693 const v8::PropertyCallbackInfo<v8::Value>& info) { 18694 if (name->Equals(v8_str("x"))) { 18695 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23)); 18696 } 18697 } 18698 18699 18700 THREADED_TEST(InterceptorOnConstructorPrototype) { 18701 v8::Isolate* isolate = CcTest::isolate(); 18702 v8::HandleScope scope(isolate); 18703 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18704 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42, 18705 NamedPropertySetterWhichSetsYOnThisTo23); 18706 LocalContext context; 18707 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18708 CompileRun("function C1() {" 18709 " this.x = 23;" 18710 "};" 18711 "C1.prototype = P;" 18712 "function C2() {" 18713 " this.x = 23" 18714 "};" 18715 "C2.prototype = { };" 18716 "C2.prototype.__proto__ = P;"); 18717 18718 v8::Local<v8::Script> script; 18719 script = v8_compile("new C1();"); 18720 for (int i = 0; i < 10; i++) { 18721 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18722 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 18723 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 18724 } 18725 18726 script = v8_compile("new C2();"); 18727 for (int i = 0; i < 10; i++) { 18728 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 18729 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value()); 18730 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value()); 18731 } 18732 } 18733 18734 18735 TEST(Regress618) { 18736 const char* source = "function C1() {" 18737 " this.x = 23;" 18738 "};" 18739 "C1.prototype = P;"; 18740 18741 LocalContext context; 18742 v8::Isolate* isolate = context->GetIsolate(); 18743 v8::HandleScope scope(isolate); 18744 v8::Local<v8::Script> script; 18745 18746 // Use a simple object as prototype. 18747 v8::Local<v8::Object> prototype = v8::Object::New(isolate); 18748 prototype->Set(v8_str("y"), v8_num(42)); 18749 context->Global()->Set(v8_str("P"), prototype); 18750 18751 // This compile will add the code to the compilation cache. 18752 CompileRun(source); 18753 18754 script = v8_compile("new C1();"); 18755 // Allow enough iterations for the inobject slack tracking logic 18756 // to finalize instance size and install the fast construct stub. 18757 for (int i = 0; i < 256; i++) { 18758 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18759 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 18760 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 18761 } 18762 18763 // Use an API object with accessors as prototype. 18764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 18765 templ->SetAccessor(v8_str("x"), GetterWhichReturns42, 18766 SetterWhichSetsYOnThisTo23); 18767 context->Global()->Set(v8_str("P"), templ->NewInstance()); 18768 18769 // This compile will get the code from the compilation cache. 18770 CompileRun(source); 18771 18772 script = v8_compile("new C1();"); 18773 for (int i = 0; i < 10; i++) { 18774 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 18775 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 18776 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 18777 } 18778 } 18779 18780 v8::Isolate* gc_callbacks_isolate = NULL; 18781 int prologue_call_count = 0; 18782 int epilogue_call_count = 0; 18783 int prologue_call_count_second = 0; 18784 int epilogue_call_count_second = 0; 18785 int prologue_call_count_alloc = 0; 18786 int epilogue_call_count_alloc = 0; 18787 18788 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) { 18789 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18790 ++prologue_call_count; 18791 } 18792 18793 18794 void PrologueCallback(v8::Isolate* isolate, 18795 v8::GCType, 18796 v8::GCCallbackFlags flags) { 18797 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18798 CHECK_EQ(gc_callbacks_isolate, isolate); 18799 ++prologue_call_count; 18800 } 18801 18802 18803 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) { 18804 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18805 ++epilogue_call_count; 18806 } 18807 18808 18809 void EpilogueCallback(v8::Isolate* isolate, 18810 v8::GCType, 18811 v8::GCCallbackFlags flags) { 18812 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18813 CHECK_EQ(gc_callbacks_isolate, isolate); 18814 ++epilogue_call_count; 18815 } 18816 18817 18818 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18819 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18820 ++prologue_call_count_second; 18821 } 18822 18823 18824 void PrologueCallbackSecond(v8::Isolate* isolate, 18825 v8::GCType, 18826 v8::GCCallbackFlags flags) { 18827 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18828 CHECK_EQ(gc_callbacks_isolate, isolate); 18829 ++prologue_call_count_second; 18830 } 18831 18832 18833 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18834 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18835 ++epilogue_call_count_second; 18836 } 18837 18838 18839 void EpilogueCallbackSecond(v8::Isolate* isolate, 18840 v8::GCType, 18841 v8::GCCallbackFlags flags) { 18842 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18843 CHECK_EQ(gc_callbacks_isolate, isolate); 18844 ++epilogue_call_count_second; 18845 } 18846 18847 18848 void PrologueCallbackAlloc(v8::Isolate* isolate, 18849 v8::GCType, 18850 v8::GCCallbackFlags flags) { 18851 v8::HandleScope scope(isolate); 18852 18853 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18854 CHECK_EQ(gc_callbacks_isolate, isolate); 18855 ++prologue_call_count_alloc; 18856 18857 // Simulate full heap to see if we will reenter this callback 18858 SimulateFullSpace(CcTest::heap()->new_space()); 18859 18860 Local<Object> obj = Object::New(isolate); 18861 CHECK(!obj.IsEmpty()); 18862 18863 CcTest::heap()->CollectAllGarbage( 18864 i::Heap::kAbortIncrementalMarkingMask); 18865 } 18866 18867 18868 void EpilogueCallbackAlloc(v8::Isolate* isolate, 18869 v8::GCType, 18870 v8::GCCallbackFlags flags) { 18871 v8::HandleScope scope(isolate); 18872 18873 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18874 CHECK_EQ(gc_callbacks_isolate, isolate); 18875 ++epilogue_call_count_alloc; 18876 18877 // Simulate full heap to see if we will reenter this callback 18878 SimulateFullSpace(CcTest::heap()->new_space()); 18879 18880 Local<Object> obj = Object::New(isolate); 18881 CHECK(!obj.IsEmpty()); 18882 18883 CcTest::heap()->CollectAllGarbage( 18884 i::Heap::kAbortIncrementalMarkingMask); 18885 } 18886 18887 18888 TEST(GCCallbacksOld) { 18889 LocalContext context; 18890 18891 v8::V8::AddGCPrologueCallback(PrologueCallback); 18892 v8::V8::AddGCEpilogueCallback(EpilogueCallback); 18893 CHECK_EQ(0, prologue_call_count); 18894 CHECK_EQ(0, epilogue_call_count); 18895 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18896 CHECK_EQ(1, prologue_call_count); 18897 CHECK_EQ(1, epilogue_call_count); 18898 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); 18899 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); 18900 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18901 CHECK_EQ(2, prologue_call_count); 18902 CHECK_EQ(2, epilogue_call_count); 18903 CHECK_EQ(1, prologue_call_count_second); 18904 CHECK_EQ(1, epilogue_call_count_second); 18905 v8::V8::RemoveGCPrologueCallback(PrologueCallback); 18906 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); 18907 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18908 CHECK_EQ(2, prologue_call_count); 18909 CHECK_EQ(2, epilogue_call_count); 18910 CHECK_EQ(2, prologue_call_count_second); 18911 CHECK_EQ(2, epilogue_call_count_second); 18912 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); 18913 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18914 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18915 CHECK_EQ(2, prologue_call_count); 18916 CHECK_EQ(2, epilogue_call_count); 18917 CHECK_EQ(2, prologue_call_count_second); 18918 CHECK_EQ(2, epilogue_call_count_second); 18919 } 18920 18921 18922 TEST(GCCallbacks) { 18923 LocalContext context; 18924 v8::Isolate* isolate = context->GetIsolate(); 18925 gc_callbacks_isolate = isolate; 18926 isolate->AddGCPrologueCallback(PrologueCallback); 18927 isolate->AddGCEpilogueCallback(EpilogueCallback); 18928 CHECK_EQ(0, prologue_call_count); 18929 CHECK_EQ(0, epilogue_call_count); 18930 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18931 CHECK_EQ(1, prologue_call_count); 18932 CHECK_EQ(1, epilogue_call_count); 18933 isolate->AddGCPrologueCallback(PrologueCallbackSecond); 18934 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); 18935 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18936 CHECK_EQ(2, prologue_call_count); 18937 CHECK_EQ(2, epilogue_call_count); 18938 CHECK_EQ(1, prologue_call_count_second); 18939 CHECK_EQ(1, epilogue_call_count_second); 18940 isolate->RemoveGCPrologueCallback(PrologueCallback); 18941 isolate->RemoveGCEpilogueCallback(EpilogueCallback); 18942 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18943 CHECK_EQ(2, prologue_call_count); 18944 CHECK_EQ(2, epilogue_call_count); 18945 CHECK_EQ(2, prologue_call_count_second); 18946 CHECK_EQ(2, epilogue_call_count_second); 18947 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); 18948 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18949 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18950 CHECK_EQ(2, prologue_call_count); 18951 CHECK_EQ(2, epilogue_call_count); 18952 CHECK_EQ(2, prologue_call_count_second); 18953 CHECK_EQ(2, epilogue_call_count_second); 18954 18955 CHECK_EQ(0, prologue_call_count_alloc); 18956 CHECK_EQ(0, epilogue_call_count_alloc); 18957 isolate->AddGCPrologueCallback(PrologueCallbackAlloc); 18958 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc); 18959 CcTest::heap()->CollectAllGarbage( 18960 i::Heap::kAbortIncrementalMarkingMask); 18961 CHECK_EQ(1, prologue_call_count_alloc); 18962 CHECK_EQ(1, epilogue_call_count_alloc); 18963 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc); 18964 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc); 18965 } 18966 18967 18968 THREADED_TEST(AddToJSFunctionResultCache) { 18969 i::FLAG_stress_compaction = false; 18970 i::FLAG_allow_natives_syntax = true; 18971 v8::HandleScope scope(CcTest::isolate()); 18972 18973 LocalContext context; 18974 18975 const char* code = 18976 "(function() {" 18977 " var key0 = 'a';" 18978 " var key1 = 'b';" 18979 " var r0 = %_GetFromCache(0, key0);" 18980 " var r1 = %_GetFromCache(0, key1);" 18981 " var r0_ = %_GetFromCache(0, key0);" 18982 " if (r0 !== r0_)" 18983 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;" 18984 " var r1_ = %_GetFromCache(0, key1);" 18985 " if (r1 !== r1_)" 18986 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" 18987 " return 'PASSED';" 18988 "})()"; 18989 CcTest::heap()->ClearJSFunctionResultCaches(); 18990 ExpectString(code, "PASSED"); 18991 } 18992 18993 18994 THREADED_TEST(FillJSFunctionResultCache) { 18995 i::FLAG_allow_natives_syntax = true; 18996 LocalContext context; 18997 v8::HandleScope scope(context->GetIsolate()); 18998 18999 const char* code = 19000 "(function() {" 19001 " var k = 'a';" 19002 " var r = %_GetFromCache(0, k);" 19003 " for (var i = 0; i < 16; i++) {" 19004 " %_GetFromCache(0, 'a' + i);" 19005 " };" 19006 " if (r === %_GetFromCache(0, k))" 19007 " return 'FAILED: k0CacheSize is too small';" 19008 " return 'PASSED';" 19009 "})()"; 19010 CcTest::heap()->ClearJSFunctionResultCaches(); 19011 ExpectString(code, "PASSED"); 19012 } 19013 19014 19015 THREADED_TEST(RoundRobinGetFromCache) { 19016 i::FLAG_allow_natives_syntax = true; 19017 LocalContext context; 19018 v8::HandleScope scope(context->GetIsolate()); 19019 19020 const char* code = 19021 "(function() {" 19022 " var keys = [];" 19023 " for (var i = 0; i < 16; i++) keys.push(i);" 19024 " var values = [];" 19025 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 19026 " for (var i = 0; i < 16; i++) {" 19027 " var v = %_GetFromCache(0, keys[i]);" 19028 " if (v.toString() !== values[i].toString())" 19029 " return 'Wrong value for ' + " 19030 " keys[i] + ': ' + v + ' vs. ' + values[i];" 19031 " };" 19032 " return 'PASSED';" 19033 "})()"; 19034 CcTest::heap()->ClearJSFunctionResultCaches(); 19035 ExpectString(code, "PASSED"); 19036 } 19037 19038 19039 THREADED_TEST(ReverseGetFromCache) { 19040 i::FLAG_allow_natives_syntax = true; 19041 LocalContext context; 19042 v8::HandleScope scope(context->GetIsolate()); 19043 19044 const char* code = 19045 "(function() {" 19046 " var keys = [];" 19047 " for (var i = 0; i < 16; i++) keys.push(i);" 19048 " var values = [];" 19049 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 19050 " for (var i = 15; i >= 16; i--) {" 19051 " var v = %_GetFromCache(0, keys[i]);" 19052 " if (v !== values[i])" 19053 " return 'Wrong value for ' + " 19054 " keys[i] + ': ' + v + ' vs. ' + values[i];" 19055 " };" 19056 " return 'PASSED';" 19057 "})()"; 19058 CcTest::heap()->ClearJSFunctionResultCaches(); 19059 ExpectString(code, "PASSED"); 19060 } 19061 19062 19063 THREADED_TEST(TestEviction) { 19064 i::FLAG_allow_natives_syntax = true; 19065 LocalContext context; 19066 v8::HandleScope scope(context->GetIsolate()); 19067 19068 const char* code = 19069 "(function() {" 19070 " for (var i = 0; i < 2*16; i++) {" 19071 " %_GetFromCache(0, 'a' + i);" 19072 " };" 19073 " return 'PASSED';" 19074 "})()"; 19075 CcTest::heap()->ClearJSFunctionResultCaches(); 19076 ExpectString(code, "PASSED"); 19077 } 19078 19079 19080 THREADED_TEST(TwoByteStringInOneByteCons) { 19081 // See Chromium issue 47824. 19082 LocalContext context; 19083 v8::HandleScope scope(context->GetIsolate()); 19084 19085 const char* init_code = 19086 "var str1 = 'abelspendabel';" 19087 "var str2 = str1 + str1 + str1;" 19088 "str2;"; 19089 Local<Value> result = CompileRun(init_code); 19090 19091 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 19092 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 19093 19094 CHECK(result->IsString()); 19095 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 19096 int length = string->length(); 19097 CHECK(string->IsOneByteRepresentation()); 19098 19099 i::Handle<i::String> flat_string = i::String::Flatten(string); 19100 19101 CHECK(string->IsOneByteRepresentation()); 19102 CHECK(flat_string->IsOneByteRepresentation()); 19103 19104 // Create external resource. 19105 uint16_t* uc16_buffer = new uint16_t[length + 1]; 19106 19107 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 19108 uc16_buffer[length] = 0; 19109 19110 TestResource resource(uc16_buffer); 19111 19112 flat_string->MakeExternal(&resource); 19113 19114 CHECK(flat_string->IsTwoByteRepresentation()); 19115 19116 // If the cons string has been short-circuited, skip the following checks. 19117 if (!string.is_identical_to(flat_string)) { 19118 // At this point, we should have a Cons string which is flat and one-byte, 19119 // with a first half that is a two-byte string (although it only contains 19120 // one-byte characters). This is a valid sequence of steps, and it can 19121 // happen in real pages. 19122 CHECK(string->IsOneByteRepresentation()); 19123 i::ConsString* cons = i::ConsString::cast(*string); 19124 CHECK_EQ(0, cons->second()->length()); 19125 CHECK(cons->first()->IsTwoByteRepresentation()); 19126 } 19127 19128 // Check that some string operations work. 19129 19130 // Atom RegExp. 19131 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 19132 CHECK_EQ(6, reresult->Int32Value()); 19133 19134 // Nonatom RegExp. 19135 reresult = CompileRun("str2.match(/abe./g).length;"); 19136 CHECK_EQ(6, reresult->Int32Value()); 19137 19138 reresult = CompileRun("str2.search(/bel/g);"); 19139 CHECK_EQ(1, reresult->Int32Value()); 19140 19141 reresult = CompileRun("str2.search(/be./g);"); 19142 CHECK_EQ(1, reresult->Int32Value()); 19143 19144 ExpectTrue("/bel/g.test(str2);"); 19145 19146 ExpectTrue("/be./g.test(str2);"); 19147 19148 reresult = CompileRun("/bel/g.exec(str2);"); 19149 CHECK(!reresult->IsNull()); 19150 19151 reresult = CompileRun("/be./g.exec(str2);"); 19152 CHECK(!reresult->IsNull()); 19153 19154 ExpectString("str2.substring(2, 10);", "elspenda"); 19155 19156 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 19157 19158 ExpectString("str2.charAt(2);", "e"); 19159 19160 ExpectObject("str2.indexOf('els');", indexof); 19161 19162 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 19163 19164 reresult = CompileRun("str2.charCodeAt(2);"); 19165 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 19166 } 19167 19168 19169 TEST(ContainsOnlyOneByte) { 19170 v8::V8::Initialize(); 19171 v8::Isolate* isolate = CcTest::isolate(); 19172 v8::HandleScope scope(isolate); 19173 // Make a buffer long enough that it won't automatically be converted. 19174 const int length = 512; 19175 // Ensure word aligned assignment. 19176 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 19177 i::SmartArrayPointer<uintptr_t> 19178 aligned_contents(new uintptr_t[aligned_length]); 19179 uint16_t* string_contents = 19180 reinterpret_cast<uint16_t*>(aligned_contents.get()); 19181 // Set to contain only one byte. 19182 for (int i = 0; i < length-1; i++) { 19183 string_contents[i] = 0x41; 19184 } 19185 string_contents[length-1] = 0; 19186 // Simple case. 19187 Handle<String> string = 19188 String::NewExternal(isolate, 19189 new TestResource(string_contents, NULL, false)); 19190 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19191 // Counter example. 19192 string = String::NewFromTwoByte(isolate, string_contents); 19193 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19194 // Test left right and balanced cons strings. 19195 Handle<String> base = String::NewFromUtf8(isolate, "a"); 19196 Handle<String> left = base; 19197 Handle<String> right = base; 19198 for (int i = 0; i < 1000; i++) { 19199 left = String::Concat(base, left); 19200 right = String::Concat(right, base); 19201 } 19202 Handle<String> balanced = String::Concat(left, base); 19203 balanced = String::Concat(balanced, right); 19204 Handle<String> cons_strings[] = {left, balanced, right}; 19205 Handle<String> two_byte = 19206 String::NewExternal(isolate, 19207 new TestResource(string_contents, NULL, false)); 19208 USE(two_byte); USE(cons_strings); 19209 for (size_t i = 0; i < arraysize(cons_strings); i++) { 19210 // Base assumptions. 19211 string = cons_strings[i]; 19212 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 19213 // Test left and right concatentation. 19214 string = String::Concat(two_byte, cons_strings[i]); 19215 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19216 string = String::Concat(cons_strings[i], two_byte); 19217 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 19218 } 19219 // Set bits in different positions 19220 // for strings of different lengths and alignments. 19221 for (int alignment = 0; alignment < 7; alignment++) { 19222 for (int size = 2; alignment + size < length; size *= 2) { 19223 int zero_offset = size + alignment; 19224 string_contents[zero_offset] = 0; 19225 for (int i = 0; i < size; i++) { 19226 int shift = 8 + (i % 7); 19227 string_contents[alignment + i] = 1 << shift; 19228 string = String::NewExternal( 19229 isolate, 19230 new TestResource(string_contents + alignment, NULL, false)); 19231 CHECK_EQ(size, string->Length()); 19232 CHECK(!string->ContainsOnlyOneByte()); 19233 string_contents[alignment + i] = 0x41; 19234 } 19235 string_contents[zero_offset] = 0x41; 19236 } 19237 } 19238 } 19239 19240 19241 // Failed access check callback that performs a GC on each invocation. 19242 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 19243 v8::AccessType type, 19244 Local<v8::Value> data) { 19245 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19246 } 19247 19248 19249 TEST(GCInFailedAccessCheckCallback) { 19250 // Install a failed access check callback that performs a GC on each 19251 // invocation. Then force the callback to be called from va 19252 19253 v8::V8::Initialize(); 19254 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 19255 19256 v8::Isolate* isolate = CcTest::isolate(); 19257 v8::HandleScope scope(isolate); 19258 19259 // Create an ObjectTemplate for global objects and install access 19260 // check callbacks that will block access. 19261 v8::Handle<v8::ObjectTemplate> global_template = 19262 v8::ObjectTemplate::New(isolate); 19263 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 19264 IndexedGetAccessBlocker, 19265 v8::Handle<v8::Value>(), 19266 false); 19267 19268 // Create a context and set an x property on it's global object. 19269 LocalContext context0(NULL, global_template); 19270 context0->Global()->Set(v8_str("x"), v8_num(42)); 19271 v8::Handle<v8::Object> global0 = context0->Global(); 19272 19273 // Create a context with a different security token so that the 19274 // failed access check callback will be called on each access. 19275 LocalContext context1(NULL, global_template); 19276 context1->Global()->Set(v8_str("other"), global0); 19277 19278 // Get property with failed access check. 19279 ExpectUndefined("other.x"); 19280 19281 // Get element with failed access check. 19282 ExpectUndefined("other[0]"); 19283 19284 // Set property with failed access check. 19285 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); 19286 CHECK(result->IsObject()); 19287 19288 // Set element with failed access check. 19289 result = CompileRun("other[0] = new Object()"); 19290 CHECK(result->IsObject()); 19291 19292 // Get property attribute with failed access check. 19293 ExpectFalse("\'x\' in other"); 19294 19295 // Get property attribute for element with failed access check. 19296 ExpectFalse("0 in other"); 19297 19298 // Delete property. 19299 ExpectFalse("delete other.x"); 19300 19301 // Delete element. 19302 CHECK_EQ(false, global0->Delete(0)); 19303 19304 // DefineAccessor. 19305 CHECK_EQ(false, 19306 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); 19307 19308 // Define JavaScript accessor. 19309 ExpectUndefined("Object.prototype.__defineGetter__.call(" 19310 " other, \'x\', function() { return 42; })"); 19311 19312 // LookupAccessor. 19313 ExpectUndefined("Object.prototype.__lookupGetter__.call(" 19314 " other, \'x\')"); 19315 19316 // HasOwnElement. 19317 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); 19318 19319 CHECK_EQ(false, global0->HasRealIndexedProperty(0)); 19320 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); 19321 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); 19322 19323 // Reset the failed access check callback so it does not influence 19324 // the other tests. 19325 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 19326 } 19327 19328 19329 TEST(IsolateNewDispose) { 19330 v8::Isolate* current_isolate = CcTest::isolate(); 19331 v8::Isolate* isolate = v8::Isolate::New(); 19332 CHECK(isolate != NULL); 19333 CHECK(current_isolate != isolate); 19334 CHECK(current_isolate == CcTest::isolate()); 19335 19336 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19337 last_location = last_message = NULL; 19338 isolate->Dispose(); 19339 CHECK_EQ(last_location, NULL); 19340 CHECK_EQ(last_message, NULL); 19341 } 19342 19343 19344 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) { 19345 v8::Isolate* isolate = v8::Isolate::New(); 19346 { 19347 v8::Isolate::Scope i_scope(isolate); 19348 v8::HandleScope scope(isolate); 19349 LocalContext context(isolate); 19350 // Run something in this isolate. 19351 ExpectTrue("true"); 19352 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19353 last_location = last_message = NULL; 19354 // Still entered, should fail. 19355 isolate->Dispose(); 19356 CHECK_NE(last_location, NULL); 19357 CHECK_NE(last_message, NULL); 19358 } 19359 isolate->Dispose(); 19360 } 19361 19362 19363 TEST(RunTwoIsolatesOnSingleThread) { 19364 // Run isolate 1. 19365 v8::Isolate* isolate1 = v8::Isolate::New(); 19366 isolate1->Enter(); 19367 v8::Persistent<v8::Context> context1; 19368 { 19369 v8::HandleScope scope(isolate1); 19370 context1.Reset(isolate1, Context::New(isolate1)); 19371 } 19372 19373 { 19374 v8::HandleScope scope(isolate1); 19375 v8::Local<v8::Context> context = 19376 v8::Local<v8::Context>::New(isolate1, context1); 19377 v8::Context::Scope context_scope(context); 19378 // Run something in new isolate. 19379 CompileRun("var foo = 'isolate 1';"); 19380 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19381 } 19382 19383 // Run isolate 2. 19384 v8::Isolate* isolate2 = v8::Isolate::New(); 19385 v8::Persistent<v8::Context> context2; 19386 19387 { 19388 v8::Isolate::Scope iscope(isolate2); 19389 v8::HandleScope scope(isolate2); 19390 context2.Reset(isolate2, Context::New(isolate2)); 19391 v8::Local<v8::Context> context = 19392 v8::Local<v8::Context>::New(isolate2, context2); 19393 v8::Context::Scope context_scope(context); 19394 19395 // Run something in new isolate. 19396 CompileRun("var foo = 'isolate 2';"); 19397 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19398 } 19399 19400 { 19401 v8::HandleScope scope(isolate1); 19402 v8::Local<v8::Context> context = 19403 v8::Local<v8::Context>::New(isolate1, context1); 19404 v8::Context::Scope context_scope(context); 19405 // Now again in isolate 1 19406 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19407 } 19408 19409 isolate1->Exit(); 19410 19411 // Run some stuff in default isolate. 19412 v8::Persistent<v8::Context> context_default; 19413 { 19414 v8::Isolate* isolate = CcTest::isolate(); 19415 v8::Isolate::Scope iscope(isolate); 19416 v8::HandleScope scope(isolate); 19417 context_default.Reset(isolate, Context::New(isolate)); 19418 } 19419 19420 { 19421 v8::HandleScope scope(CcTest::isolate()); 19422 v8::Local<v8::Context> context = 19423 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19424 v8::Context::Scope context_scope(context); 19425 // Variables in other isolates should be not available, verify there 19426 // is an exception. 19427 ExpectTrue("function f() {" 19428 " try {" 19429 " foo;" 19430 " return false;" 19431 " } catch(e) {" 19432 " return true;" 19433 " }" 19434 "};" 19435 "var isDefaultIsolate = true;" 19436 "f()"); 19437 } 19438 19439 isolate1->Enter(); 19440 19441 { 19442 v8::Isolate::Scope iscope(isolate2); 19443 v8::HandleScope scope(isolate2); 19444 v8::Local<v8::Context> context = 19445 v8::Local<v8::Context>::New(isolate2, context2); 19446 v8::Context::Scope context_scope(context); 19447 ExpectString("function f() { return foo; }; f()", "isolate 2"); 19448 } 19449 19450 { 19451 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19452 v8::Local<v8::Context> context = 19453 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 19454 v8::Context::Scope context_scope(context); 19455 ExpectString("function f() { return foo; }; f()", "isolate 1"); 19456 } 19457 19458 { 19459 v8::Isolate::Scope iscope(isolate2); 19460 context2.Reset(); 19461 } 19462 19463 context1.Reset(); 19464 isolate1->Exit(); 19465 19466 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 19467 last_location = last_message = NULL; 19468 19469 isolate1->Dispose(); 19470 CHECK_EQ(last_location, NULL); 19471 CHECK_EQ(last_message, NULL); 19472 19473 isolate2->Dispose(); 19474 CHECK_EQ(last_location, NULL); 19475 CHECK_EQ(last_message, NULL); 19476 19477 // Check that default isolate still runs. 19478 { 19479 v8::HandleScope scope(CcTest::isolate()); 19480 v8::Local<v8::Context> context = 19481 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 19482 v8::Context::Scope context_scope(context); 19483 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 19484 } 19485 } 19486 19487 19488 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 19489 v8::Isolate::Scope isolate_scope(isolate); 19490 v8::HandleScope scope(isolate); 19491 LocalContext context(isolate); 19492 i::ScopedVector<char> code(1024); 19493 i::SNPrintF(code, "function fib(n) {" 19494 " if (n <= 2) return 1;" 19495 " return fib(n-1) + fib(n-2);" 19496 "}" 19497 "fib(%d)", limit); 19498 Local<Value> value = CompileRun(code.start()); 19499 CHECK(value->IsNumber()); 19500 return static_cast<int>(value->NumberValue()); 19501 } 19502 19503 class IsolateThread : public v8::base::Thread { 19504 public: 19505 explicit IsolateThread(int fib_limit) 19506 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {} 19507 19508 void Run() { 19509 v8::Isolate* isolate = v8::Isolate::New(); 19510 result_ = CalcFibonacci(isolate, fib_limit_); 19511 isolate->Dispose(); 19512 } 19513 19514 int result() { return result_; } 19515 19516 private: 19517 int fib_limit_; 19518 int result_; 19519 }; 19520 19521 19522 TEST(MultipleIsolatesOnIndividualThreads) { 19523 IsolateThread thread1(21); 19524 IsolateThread thread2(12); 19525 19526 // Compute some fibonacci numbers on 3 threads in 3 isolates. 19527 thread1.Start(); 19528 thread2.Start(); 19529 19530 int result1 = CalcFibonacci(CcTest::isolate(), 21); 19531 int result2 = CalcFibonacci(CcTest::isolate(), 12); 19532 19533 thread1.Join(); 19534 thread2.Join(); 19535 19536 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 19537 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 19538 CHECK_EQ(result1, 10946); 19539 CHECK_EQ(result2, 144); 19540 CHECK_EQ(result1, thread1.result()); 19541 CHECK_EQ(result2, thread2.result()); 19542 } 19543 19544 19545 TEST(IsolateDifferentContexts) { 19546 v8::Isolate* isolate = v8::Isolate::New(); 19547 Local<v8::Context> context; 19548 { 19549 v8::Isolate::Scope isolate_scope(isolate); 19550 v8::HandleScope handle_scope(isolate); 19551 context = v8::Context::New(isolate); 19552 v8::Context::Scope context_scope(context); 19553 Local<Value> v = CompileRun("2"); 19554 CHECK(v->IsNumber()); 19555 CHECK_EQ(2, static_cast<int>(v->NumberValue())); 19556 } 19557 { 19558 v8::Isolate::Scope isolate_scope(isolate); 19559 v8::HandleScope handle_scope(isolate); 19560 context = v8::Context::New(isolate); 19561 v8::Context::Scope context_scope(context); 19562 Local<Value> v = CompileRun("22"); 19563 CHECK(v->IsNumber()); 19564 CHECK_EQ(22, static_cast<int>(v->NumberValue())); 19565 } 19566 isolate->Dispose(); 19567 } 19568 19569 class InitDefaultIsolateThread : public v8::base::Thread { 19570 public: 19571 enum TestCase { 19572 SetResourceConstraints, 19573 SetFatalHandler, 19574 SetCounterFunction, 19575 SetCreateHistogramFunction, 19576 SetAddHistogramSampleFunction 19577 }; 19578 19579 explicit InitDefaultIsolateThread(TestCase testCase) 19580 : Thread(Options("InitDefaultIsolateThread")), 19581 testCase_(testCase), 19582 result_(false) {} 19583 19584 void Run() { 19585 v8::Isolate::CreateParams create_params; 19586 switch (testCase_) { 19587 case SetResourceConstraints: { 19588 create_params.constraints.set_max_semi_space_size(1); 19589 create_params.constraints.set_max_old_space_size(4); 19590 break; 19591 } 19592 default: 19593 break; 19594 } 19595 v8::Isolate* isolate = v8::Isolate::New(create_params); 19596 isolate->Enter(); 19597 switch (testCase_) { 19598 case SetResourceConstraints: 19599 // Already handled in pre-Isolate-creation block. 19600 break; 19601 19602 case SetFatalHandler: 19603 v8::V8::SetFatalErrorHandler(NULL); 19604 break; 19605 19606 case SetCounterFunction: 19607 CcTest::isolate()->SetCounterFunction(NULL); 19608 break; 19609 19610 case SetCreateHistogramFunction: 19611 CcTest::isolate()->SetCreateHistogramFunction(NULL); 19612 break; 19613 19614 case SetAddHistogramSampleFunction: 19615 CcTest::isolate()->SetAddHistogramSampleFunction(NULL); 19616 break; 19617 } 19618 isolate->Exit(); 19619 isolate->Dispose(); 19620 result_ = true; 19621 } 19622 19623 bool result() { return result_; } 19624 19625 private: 19626 TestCase testCase_; 19627 bool result_; 19628 }; 19629 19630 19631 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 19632 InitDefaultIsolateThread thread(testCase); 19633 thread.Start(); 19634 thread.Join(); 19635 CHECK_EQ(thread.result(), true); 19636 } 19637 19638 19639 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 19640 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 19641 } 19642 19643 19644 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 19645 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 19646 } 19647 19648 19649 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 19650 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 19651 } 19652 19653 19654 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 19655 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 19656 } 19657 19658 19659 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 19660 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 19661 } 19662 19663 19664 TEST(StringCheckMultipleContexts) { 19665 const char* code = 19666 "(function() { return \"a\".charAt(0); })()"; 19667 19668 { 19669 // Run the code twice in the first context to initialize the call IC. 19670 LocalContext context1; 19671 v8::HandleScope scope(context1->GetIsolate()); 19672 ExpectString(code, "a"); 19673 ExpectString(code, "a"); 19674 } 19675 19676 { 19677 // Change the String.prototype in the second context and check 19678 // that the right function gets called. 19679 LocalContext context2; 19680 v8::HandleScope scope(context2->GetIsolate()); 19681 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 19682 ExpectString(code, "not a"); 19683 } 19684 } 19685 19686 19687 TEST(NumberCheckMultipleContexts) { 19688 const char* code = 19689 "(function() { return (42).toString(); })()"; 19690 19691 { 19692 // Run the code twice in the first context to initialize the call IC. 19693 LocalContext context1; 19694 v8::HandleScope scope(context1->GetIsolate()); 19695 ExpectString(code, "42"); 19696 ExpectString(code, "42"); 19697 } 19698 19699 { 19700 // Change the Number.prototype in the second context and check 19701 // that the right function gets called. 19702 LocalContext context2; 19703 v8::HandleScope scope(context2->GetIsolate()); 19704 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 19705 ExpectString(code, "not 42"); 19706 } 19707 } 19708 19709 19710 TEST(BooleanCheckMultipleContexts) { 19711 const char* code = 19712 "(function() { return true.toString(); })()"; 19713 19714 { 19715 // Run the code twice in the first context to initialize the call IC. 19716 LocalContext context1; 19717 v8::HandleScope scope(context1->GetIsolate()); 19718 ExpectString(code, "true"); 19719 ExpectString(code, "true"); 19720 } 19721 19722 { 19723 // Change the Boolean.prototype in the second context and check 19724 // that the right function gets called. 19725 LocalContext context2; 19726 v8::HandleScope scope(context2->GetIsolate()); 19727 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 19728 ExpectString(code, ""); 19729 } 19730 } 19731 19732 19733 TEST(DontDeleteCellLoadIC) { 19734 const char* function_code = 19735 "function readCell() { while (true) { return cell; } }"; 19736 19737 { 19738 // Run the code twice in the first context to initialize the load 19739 // IC for a don't delete cell. 19740 LocalContext context1; 19741 v8::HandleScope scope(context1->GetIsolate()); 19742 CompileRun("var cell = \"first\";"); 19743 ExpectBoolean("delete cell", false); 19744 CompileRun(function_code); 19745 ExpectString("readCell()", "first"); 19746 ExpectString("readCell()", "first"); 19747 } 19748 19749 { 19750 // Use a deletable cell in the second context. 19751 LocalContext context2; 19752 v8::HandleScope scope(context2->GetIsolate()); 19753 CompileRun("cell = \"second\";"); 19754 CompileRun(function_code); 19755 ExpectString("readCell()", "second"); 19756 ExpectBoolean("delete cell", true); 19757 ExpectString("(function() {" 19758 " try {" 19759 " return readCell();" 19760 " } catch(e) {" 19761 " return e.toString();" 19762 " }" 19763 "})()", 19764 "ReferenceError: cell is not defined"); 19765 CompileRun("cell = \"new_second\";"); 19766 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19767 ExpectString("readCell()", "new_second"); 19768 ExpectString("readCell()", "new_second"); 19769 } 19770 } 19771 19772 19773 TEST(DontDeleteCellLoadICForceDelete) { 19774 const char* function_code = 19775 "function readCell() { while (true) { return cell; } }"; 19776 19777 // Run the code twice to initialize the load IC for a don't delete 19778 // cell. 19779 LocalContext context; 19780 v8::HandleScope scope(context->GetIsolate()); 19781 CompileRun("var cell = \"value\";"); 19782 ExpectBoolean("delete cell", false); 19783 CompileRun(function_code); 19784 ExpectString("readCell()", "value"); 19785 ExpectString("readCell()", "value"); 19786 19787 // Delete the cell using the API and check the inlined code works 19788 // correctly. 19789 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 19790 ExpectString("(function() {" 19791 " try {" 19792 " return readCell();" 19793 " } catch(e) {" 19794 " return e.toString();" 19795 " }" 19796 "})()", 19797 "ReferenceError: cell is not defined"); 19798 } 19799 19800 19801 TEST(DontDeleteCellLoadICAPI) { 19802 const char* function_code = 19803 "function readCell() { while (true) { return cell; } }"; 19804 19805 // Run the code twice to initialize the load IC for a don't delete 19806 // cell created using the API. 19807 LocalContext context; 19808 v8::HandleScope scope(context->GetIsolate()); 19809 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete); 19810 ExpectBoolean("delete cell", false); 19811 CompileRun(function_code); 19812 ExpectString("readCell()", "value"); 19813 ExpectString("readCell()", "value"); 19814 19815 // Delete the cell using the API and check the inlined code works 19816 // correctly. 19817 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 19818 ExpectString("(function() {" 19819 " try {" 19820 " return readCell();" 19821 " } catch(e) {" 19822 " return e.toString();" 19823 " }" 19824 "})()", 19825 "ReferenceError: cell is not defined"); 19826 } 19827 19828 19829 class Visitor42 : public v8::PersistentHandleVisitor { 19830 public: 19831 explicit Visitor42(v8::Persistent<v8::Object>* object) 19832 : counter_(0), object_(object) { } 19833 19834 virtual void VisitPersistentHandle(Persistent<Value>* value, 19835 uint16_t class_id) { 19836 if (class_id != 42) return; 19837 CHECK_EQ(42, value->WrapperClassId()); 19838 v8::Isolate* isolate = CcTest::isolate(); 19839 v8::HandleScope handle_scope(isolate); 19840 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 19841 v8::Handle<v8::Value> object = 19842 v8::Local<v8::Object>::New(isolate, *object_); 19843 CHECK(handle->IsObject()); 19844 CHECK_EQ(Handle<Object>::Cast(handle), object); 19845 ++counter_; 19846 } 19847 19848 int counter_; 19849 v8::Persistent<v8::Object>* object_; 19850 }; 19851 19852 19853 TEST(PersistentHandleVisitor) { 19854 LocalContext context; 19855 v8::Isolate* isolate = context->GetIsolate(); 19856 v8::HandleScope scope(isolate); 19857 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19858 CHECK_EQ(0, object.WrapperClassId()); 19859 object.SetWrapperClassId(42); 19860 CHECK_EQ(42, object.WrapperClassId()); 19861 19862 Visitor42 visitor(&object); 19863 v8::V8::VisitHandlesWithClassIds(&visitor); 19864 CHECK_EQ(1, visitor.counter_); 19865 19866 object.Reset(); 19867 } 19868 19869 19870 TEST(WrapperClassId) { 19871 LocalContext context; 19872 v8::Isolate* isolate = context->GetIsolate(); 19873 v8::HandleScope scope(isolate); 19874 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate)); 19875 CHECK_EQ(0, object.WrapperClassId()); 19876 object.SetWrapperClassId(65535); 19877 CHECK_EQ(65535, object.WrapperClassId()); 19878 object.Reset(); 19879 } 19880 19881 19882 TEST(PersistentHandleInNewSpaceVisitor) { 19883 LocalContext context; 19884 v8::Isolate* isolate = context->GetIsolate(); 19885 v8::HandleScope scope(isolate); 19886 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate)); 19887 CHECK_EQ(0, object1.WrapperClassId()); 19888 object1.SetWrapperClassId(42); 19889 CHECK_EQ(42, object1.WrapperClassId()); 19890 19891 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19892 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19893 19894 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate)); 19895 CHECK_EQ(0, object2.WrapperClassId()); 19896 object2.SetWrapperClassId(42); 19897 CHECK_EQ(42, object2.WrapperClassId()); 19898 19899 Visitor42 visitor(&object2); 19900 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); 19901 CHECK_EQ(1, visitor.counter_); 19902 19903 object1.Reset(); 19904 object2.Reset(); 19905 } 19906 19907 19908 TEST(RegExp) { 19909 LocalContext context; 19910 v8::HandleScope scope(context->GetIsolate()); 19911 19912 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone); 19913 CHECK(re->IsRegExp()); 19914 CHECK(re->GetSource()->Equals(v8_str("foo"))); 19915 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19916 19917 re = v8::RegExp::New(v8_str("bar"), 19918 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19919 v8::RegExp::kGlobal)); 19920 CHECK(re->IsRegExp()); 19921 CHECK(re->GetSource()->Equals(v8_str("bar"))); 19922 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 19923 static_cast<int>(re->GetFlags())); 19924 19925 re = v8::RegExp::New(v8_str("baz"), 19926 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19927 v8::RegExp::kMultiline)); 19928 CHECK(re->IsRegExp()); 19929 CHECK(re->GetSource()->Equals(v8_str("baz"))); 19930 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19931 static_cast<int>(re->GetFlags())); 19932 19933 re = CompileRun("/quux/").As<v8::RegExp>(); 19934 CHECK(re->IsRegExp()); 19935 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19936 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19937 19938 re = CompileRun("/quux/gm").As<v8::RegExp>(); 19939 CHECK(re->IsRegExp()); 19940 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19941 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 19942 static_cast<int>(re->GetFlags())); 19943 19944 // Override the RegExp constructor and check the API constructor 19945 // still works. 19946 CompileRun("RegExp = function() {}"); 19947 19948 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone); 19949 CHECK(re->IsRegExp()); 19950 CHECK(re->GetSource()->Equals(v8_str("foobar"))); 19951 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19952 19953 re = v8::RegExp::New(v8_str("foobarbaz"), 19954 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19955 v8::RegExp::kMultiline)); 19956 CHECK(re->IsRegExp()); 19957 CHECK(re->GetSource()->Equals(v8_str("foobarbaz"))); 19958 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19959 static_cast<int>(re->GetFlags())); 19960 19961 context->Global()->Set(v8_str("re"), re); 19962 ExpectTrue("re.test('FoobarbaZ')"); 19963 19964 // RegExps are objects on which you can set properties. 19965 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32)); 19966 v8::Handle<v8::Value> value(CompileRun("re.property")); 19967 CHECK_EQ(32, value->Int32Value()); 19968 19969 v8::TryCatch try_catch; 19970 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); 19971 CHECK(re.IsEmpty()); 19972 CHECK(try_catch.HasCaught()); 19973 context->Global()->Set(v8_str("ex"), try_catch.Exception()); 19974 ExpectTrue("ex instanceof SyntaxError"); 19975 } 19976 19977 19978 THREADED_TEST(Equals) { 19979 LocalContext localContext; 19980 v8::HandleScope handleScope(localContext->GetIsolate()); 19981 19982 v8::Handle<v8::Object> globalProxy = localContext->Global(); 19983 v8::Handle<Value> global = globalProxy->GetPrototype(); 19984 19985 CHECK(global->StrictEquals(global)); 19986 CHECK(!global->StrictEquals(globalProxy)); 19987 CHECK(!globalProxy->StrictEquals(global)); 19988 CHECK(globalProxy->StrictEquals(globalProxy)); 19989 19990 CHECK(global->Equals(global)); 19991 CHECK(!global->Equals(globalProxy)); 19992 CHECK(!globalProxy->Equals(global)); 19993 CHECK(globalProxy->Equals(globalProxy)); 19994 } 19995 19996 19997 static void Getter(v8::Local<v8::String> property, 19998 const v8::PropertyCallbackInfo<v8::Value>& info ) { 19999 info.GetReturnValue().Set(v8_str("42!")); 20000 } 20001 20002 20003 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 20004 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate()); 20005 result->Set(0, v8_str("universalAnswer")); 20006 info.GetReturnValue().Set(result); 20007 } 20008 20009 20010 TEST(NamedEnumeratorAndForIn) { 20011 LocalContext context; 20012 v8::Isolate* isolate = context->GetIsolate(); 20013 v8::HandleScope handle_scope(isolate); 20014 v8::Context::Scope context_scope(context.local()); 20015 20016 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate); 20017 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); 20018 context->Global()->Set(v8_str("o"), tmpl->NewInstance()); 20019 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 20020 "var result = []; for (var k in o) result.push(k); result")); 20021 CHECK_EQ(1, result->Length()); 20022 CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); 20023 } 20024 20025 20026 TEST(DefinePropertyPostDetach) { 20027 LocalContext context; 20028 v8::HandleScope scope(context->GetIsolate()); 20029 v8::Handle<v8::Object> proxy = context->Global(); 20030 v8::Handle<v8::Function> define_property = 20031 CompileRun("(function() {" 20032 " Object.defineProperty(" 20033 " this," 20034 " 1," 20035 " { configurable: true, enumerable: true, value: 3 });" 20036 "})").As<Function>(); 20037 context->DetachGlobal(); 20038 define_property->Call(proxy, 0, NULL); 20039 } 20040 20041 20042 static void InstallContextId(v8::Handle<Context> context, int id) { 20043 Context::Scope scope(context); 20044 CompileRun("Object.prototype").As<Object>()-> 20045 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id)); 20046 } 20047 20048 20049 static void CheckContextId(v8::Handle<Object> object, int expected) { 20050 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value()); 20051 } 20052 20053 20054 THREADED_TEST(CreationContext) { 20055 v8::Isolate* isolate = CcTest::isolate(); 20056 HandleScope handle_scope(isolate); 20057 Handle<Context> context1 = Context::New(isolate); 20058 InstallContextId(context1, 1); 20059 Handle<Context> context2 = Context::New(isolate); 20060 InstallContextId(context2, 2); 20061 Handle<Context> context3 = Context::New(isolate); 20062 InstallContextId(context3, 3); 20063 20064 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate); 20065 20066 Local<Object> object1; 20067 Local<Function> func1; 20068 { 20069 Context::Scope scope(context1); 20070 object1 = Object::New(isolate); 20071 func1 = tmpl->GetFunction(); 20072 } 20073 20074 Local<Object> object2; 20075 Local<Function> func2; 20076 { 20077 Context::Scope scope(context2); 20078 object2 = Object::New(isolate); 20079 func2 = tmpl->GetFunction(); 20080 } 20081 20082 Local<Object> instance1; 20083 Local<Object> instance2; 20084 20085 { 20086 Context::Scope scope(context3); 20087 instance1 = func1->NewInstance(); 20088 instance2 = func2->NewInstance(); 20089 } 20090 20091 CHECK(object1->CreationContext() == context1); 20092 CheckContextId(object1, 1); 20093 CHECK(func1->CreationContext() == context1); 20094 CheckContextId(func1, 1); 20095 CHECK(instance1->CreationContext() == context1); 20096 CheckContextId(instance1, 1); 20097 CHECK(object2->CreationContext() == context2); 20098 CheckContextId(object2, 2); 20099 CHECK(func2->CreationContext() == context2); 20100 CheckContextId(func2, 2); 20101 CHECK(instance2->CreationContext() == context2); 20102 CheckContextId(instance2, 2); 20103 20104 { 20105 Context::Scope scope(context1); 20106 CHECK(object1->CreationContext() == context1); 20107 CheckContextId(object1, 1); 20108 CHECK(func1->CreationContext() == context1); 20109 CheckContextId(func1, 1); 20110 CHECK(instance1->CreationContext() == context1); 20111 CheckContextId(instance1, 1); 20112 CHECK(object2->CreationContext() == context2); 20113 CheckContextId(object2, 2); 20114 CHECK(func2->CreationContext() == context2); 20115 CheckContextId(func2, 2); 20116 CHECK(instance2->CreationContext() == context2); 20117 CheckContextId(instance2, 2); 20118 } 20119 20120 { 20121 Context::Scope scope(context2); 20122 CHECK(object1->CreationContext() == context1); 20123 CheckContextId(object1, 1); 20124 CHECK(func1->CreationContext() == context1); 20125 CheckContextId(func1, 1); 20126 CHECK(instance1->CreationContext() == context1); 20127 CheckContextId(instance1, 1); 20128 CHECK(object2->CreationContext() == context2); 20129 CheckContextId(object2, 2); 20130 CHECK(func2->CreationContext() == context2); 20131 CheckContextId(func2, 2); 20132 CHECK(instance2->CreationContext() == context2); 20133 CheckContextId(instance2, 2); 20134 } 20135 } 20136 20137 20138 THREADED_TEST(CreationContextOfJsFunction) { 20139 HandleScope handle_scope(CcTest::isolate()); 20140 Handle<Context> context = Context::New(CcTest::isolate()); 20141 InstallContextId(context, 1); 20142 20143 Local<Object> function; 20144 { 20145 Context::Scope scope(context); 20146 function = CompileRun("function foo() {}; foo").As<Object>(); 20147 } 20148 20149 CHECK(function->CreationContext() == context); 20150 CheckContextId(function, 1); 20151 } 20152 20153 20154 void HasOwnPropertyIndexedPropertyGetter( 20155 uint32_t index, 20156 const v8::PropertyCallbackInfo<v8::Value>& info) { 20157 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 20158 } 20159 20160 20161 void HasOwnPropertyNamedPropertyGetter( 20162 Local<String> property, 20163 const v8::PropertyCallbackInfo<v8::Value>& info) { 20164 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes")); 20165 } 20166 20167 20168 void HasOwnPropertyIndexedPropertyQuery( 20169 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 20170 if (index == 42) info.GetReturnValue().Set(1); 20171 } 20172 20173 20174 void HasOwnPropertyNamedPropertyQuery( 20175 Local<String> property, 20176 const v8::PropertyCallbackInfo<v8::Integer>& info) { 20177 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1); 20178 } 20179 20180 20181 void HasOwnPropertyNamedPropertyQuery2( 20182 Local<String> property, 20183 const v8::PropertyCallbackInfo<v8::Integer>& info) { 20184 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1); 20185 } 20186 20187 20188 void HasOwnPropertyAccessorGetter( 20189 Local<String> property, 20190 const v8::PropertyCallbackInfo<v8::Value>& info) { 20191 info.GetReturnValue().Set(v8_str("yes")); 20192 } 20193 20194 20195 TEST(HasOwnProperty) { 20196 LocalContext env; 20197 v8::Isolate* isolate = env->GetIsolate(); 20198 v8::HandleScope scope(isolate); 20199 { // Check normal properties and defined getters. 20200 Handle<Value> value = CompileRun( 20201 "function Foo() {" 20202 " this.foo = 11;" 20203 " this.__defineGetter__('baz', function() { return 1; });" 20204 "};" 20205 "function Bar() { " 20206 " this.bar = 13;" 20207 " this.__defineGetter__('bla', function() { return 2; });" 20208 "};" 20209 "Bar.prototype = new Foo();" 20210 "new Bar();"); 20211 CHECK(value->IsObject()); 20212 Handle<Object> object = value->ToObject(); 20213 CHECK(object->Has(v8_str("foo"))); 20214 CHECK(!object->HasOwnProperty(v8_str("foo"))); 20215 CHECK(object->HasOwnProperty(v8_str("bar"))); 20216 CHECK(object->Has(v8_str("baz"))); 20217 CHECK(!object->HasOwnProperty(v8_str("baz"))); 20218 CHECK(object->HasOwnProperty(v8_str("bla"))); 20219 } 20220 { // Check named getter interceptors. 20221 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20222 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter); 20223 Handle<Object> instance = templ->NewInstance(); 20224 CHECK(!instance->HasOwnProperty(v8_str("42"))); 20225 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20226 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20227 } 20228 { // Check indexed getter interceptors. 20229 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20230 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter); 20231 Handle<Object> instance = templ->NewInstance(); 20232 CHECK(instance->HasOwnProperty(v8_str("42"))); 20233 CHECK(!instance->HasOwnProperty(v8_str("43"))); 20234 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 20235 } 20236 { // Check named query interceptors. 20237 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20238 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery); 20239 Handle<Object> instance = templ->NewInstance(); 20240 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20241 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20242 } 20243 { // Check indexed query interceptors. 20244 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20245 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery); 20246 Handle<Object> instance = templ->NewInstance(); 20247 CHECK(instance->HasOwnProperty(v8_str("42"))); 20248 CHECK(!instance->HasOwnProperty(v8_str("41"))); 20249 } 20250 { // Check callbacks. 20251 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20252 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 20253 Handle<Object> instance = templ->NewInstance(); 20254 CHECK(instance->HasOwnProperty(v8_str("foo"))); 20255 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 20256 } 20257 { // Check that query wins on disagreement. 20258 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20259 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter, 20260 0, 20261 HasOwnPropertyNamedPropertyQuery2); 20262 Handle<Object> instance = templ->NewInstance(); 20263 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 20264 CHECK(instance->HasOwnProperty(v8_str("bar"))); 20265 } 20266 } 20267 20268 20269 TEST(IndexedInterceptorWithStringProto) { 20270 v8::Isolate* isolate = CcTest::isolate(); 20271 v8::HandleScope scope(isolate); 20272 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20273 templ->SetIndexedPropertyHandler(NULL, 20274 NULL, 20275 HasOwnPropertyIndexedPropertyQuery); 20276 LocalContext context; 20277 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 20278 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 20279 // These should be intercepted. 20280 CHECK(CompileRun("42 in obj")->BooleanValue()); 20281 CHECK(CompileRun("'42' in obj")->BooleanValue()); 20282 // These should fall through to the String prototype. 20283 CHECK(CompileRun("0 in obj")->BooleanValue()); 20284 CHECK(CompileRun("'0' in obj")->BooleanValue()); 20285 // And these should both fail. 20286 CHECK(!CompileRun("32 in obj")->BooleanValue()); 20287 CHECK(!CompileRun("'32' in obj")->BooleanValue()); 20288 } 20289 20290 20291 void CheckCodeGenerationAllowed() { 20292 Handle<Value> result = CompileRun("eval('42')"); 20293 CHECK_EQ(42, result->Int32Value()); 20294 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20295 CHECK_EQ(42, result->Int32Value()); 20296 result = CompileRun("var f = new Function('return 42'); f()"); 20297 CHECK_EQ(42, result->Int32Value()); 20298 } 20299 20300 20301 void CheckCodeGenerationDisallowed() { 20302 TryCatch try_catch; 20303 20304 Handle<Value> result = CompileRun("eval('42')"); 20305 CHECK(result.IsEmpty()); 20306 CHECK(try_catch.HasCaught()); 20307 try_catch.Reset(); 20308 20309 result = CompileRun("(function(e) { return e('42'); })(eval)"); 20310 CHECK(result.IsEmpty()); 20311 CHECK(try_catch.HasCaught()); 20312 try_catch.Reset(); 20313 20314 result = CompileRun("var f = new Function('return 42'); f()"); 20315 CHECK(result.IsEmpty()); 20316 CHECK(try_catch.HasCaught()); 20317 } 20318 20319 20320 bool CodeGenerationAllowed(Local<Context> context) { 20321 ApiTestFuzzer::Fuzz(); 20322 return true; 20323 } 20324 20325 20326 bool CodeGenerationDisallowed(Local<Context> context) { 20327 ApiTestFuzzer::Fuzz(); 20328 return false; 20329 } 20330 20331 20332 THREADED_TEST(AllowCodeGenFromStrings) { 20333 LocalContext context; 20334 v8::HandleScope scope(context->GetIsolate()); 20335 20336 // eval and the Function constructor allowed by default. 20337 CHECK(context->IsCodeGenerationFromStringsAllowed()); 20338 CheckCodeGenerationAllowed(); 20339 20340 // Disallow eval and the Function constructor. 20341 context->AllowCodeGenerationFromStrings(false); 20342 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20343 CheckCodeGenerationDisallowed(); 20344 20345 // Allow again. 20346 context->AllowCodeGenerationFromStrings(true); 20347 CheckCodeGenerationAllowed(); 20348 20349 // Disallow but setting a global callback that will allow the calls. 20350 context->AllowCodeGenerationFromStrings(false); 20351 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed); 20352 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20353 CheckCodeGenerationAllowed(); 20354 20355 // Set a callback that disallows the code generation. 20356 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 20357 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 20358 CheckCodeGenerationDisallowed(); 20359 } 20360 20361 20362 TEST(SetErrorMessageForCodeGenFromStrings) { 20363 LocalContext context; 20364 v8::HandleScope scope(context->GetIsolate()); 20365 TryCatch try_catch; 20366 20367 Handle<String> message = v8_str("Message") ; 20368 Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); 20369 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 20370 context->AllowCodeGenerationFromStrings(false); 20371 context->SetErrorMessageForCodeGenerationFromStrings(message); 20372 Handle<Value> result = CompileRun("eval('42')"); 20373 CHECK(result.IsEmpty()); 20374 CHECK(try_catch.HasCaught()); 20375 Handle<String> actual_message = try_catch.Message()->Get(); 20376 CHECK(expected_message->Equals(actual_message)); 20377 } 20378 20379 20380 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 20381 } 20382 20383 20384 THREADED_TEST(CallAPIFunctionOnNonObject) { 20385 LocalContext context; 20386 v8::Isolate* isolate = context->GetIsolate(); 20387 v8::HandleScope scope(isolate); 20388 Handle<FunctionTemplate> templ = 20389 v8::FunctionTemplate::New(isolate, NonObjectThis); 20390 Handle<Function> function = templ->GetFunction(); 20391 context->Global()->Set(v8_str("f"), function); 20392 TryCatch try_catch; 20393 CompileRun("f.call(2)"); 20394 } 20395 20396 20397 // Regression test for issue 1470. 20398 THREADED_TEST(ReadOnlyIndexedProperties) { 20399 v8::Isolate* isolate = CcTest::isolate(); 20400 v8::HandleScope scope(isolate); 20401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 20402 20403 LocalContext context; 20404 Local<v8::Object> obj = templ->NewInstance(); 20405 context->Global()->Set(v8_str("obj"), obj); 20406 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); 20407 obj->Set(v8_str("1"), v8_str("foobar")); 20408 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); 20409 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); 20410 obj->Set(v8_num(2), v8_str("foobar")); 20411 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); 20412 20413 // Test non-smi case. 20414 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); 20415 obj->Set(v8_str("2000000000"), v8_str("foobar")); 20416 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); 20417 } 20418 20419 20420 THREADED_TEST(Regress1516) { 20421 LocalContext context; 20422 v8::HandleScope scope(context->GetIsolate()); 20423 20424 { v8::HandleScope temp_scope(context->GetIsolate()); 20425 CompileRun("({'a': 0})"); 20426 } 20427 20428 int elements; 20429 { i::MapCache* map_cache = 20430 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache()); 20431 elements = map_cache->NumberOfElements(); 20432 CHECK_LE(1, elements); 20433 } 20434 20435 CcTest::heap()->CollectAllGarbage( 20436 i::Heap::kAbortIncrementalMarkingMask); 20437 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache(); 20438 if (raw_map_cache != CcTest::heap()->undefined_value()) { 20439 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache); 20440 CHECK_GT(elements, map_cache->NumberOfElements()); 20441 } 20442 } 20443 } 20444 20445 20446 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, 20447 Local<Value> name, 20448 v8::AccessType type, 20449 Local<Value> data) { 20450 // Only block read access to __proto__. 20451 if (type == v8::ACCESS_GET && 20452 name->IsString() && 20453 name->ToString()->Length() == 9 && 20454 name->ToString()->Utf8Length() == 9) { 20455 char buffer[10]; 20456 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); 20457 return strncmp(buffer, "__proto__", 9) != 0; 20458 } 20459 20460 return true; 20461 } 20462 20463 20464 THREADED_TEST(Regress93759) { 20465 v8::Isolate* isolate = CcTest::isolate(); 20466 HandleScope scope(isolate); 20467 20468 // Template for object with security check. 20469 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate); 20470 // We don't do indexing, so any callback can be used for that. 20471 no_proto_template->SetAccessCheckCallbacks( 20472 BlockProtoNamedSecurityTestCallback, 20473 IndexedSecurityTestCallback); 20474 20475 // Templates for objects with hidden prototypes and possibly security check. 20476 Local<FunctionTemplate> hidden_proto_template = 20477 v8::FunctionTemplate::New(isolate); 20478 hidden_proto_template->SetHiddenPrototype(true); 20479 20480 Local<FunctionTemplate> protected_hidden_proto_template = 20481 v8::FunctionTemplate::New(isolate); 20482 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( 20483 BlockProtoNamedSecurityTestCallback, 20484 IndexedSecurityTestCallback); 20485 protected_hidden_proto_template->SetHiddenPrototype(true); 20486 20487 // Context for "foreign" objects used in test. 20488 Local<Context> context = v8::Context::New(isolate); 20489 context->Enter(); 20490 20491 // Plain object, no security check. 20492 Local<Object> simple_object = Object::New(isolate); 20493 20494 // Object with explicit security check. 20495 Local<Object> protected_object = 20496 no_proto_template->NewInstance(); 20497 20498 // JSGlobalProxy object, always have security check. 20499 Local<Object> proxy_object = 20500 context->Global(); 20501 20502 // Global object, the prototype of proxy_object. No security checks. 20503 Local<Object> global_object = 20504 proxy_object->GetPrototype()->ToObject(); 20505 20506 // Hidden prototype without security check. 20507 Local<Object> hidden_prototype = 20508 hidden_proto_template->GetFunction()->NewInstance(); 20509 Local<Object> object_with_hidden = 20510 Object::New(isolate); 20511 object_with_hidden->SetPrototype(hidden_prototype); 20512 20513 // Hidden prototype with security check on the hidden prototype. 20514 Local<Object> protected_hidden_prototype = 20515 protected_hidden_proto_template->GetFunction()->NewInstance(); 20516 Local<Object> object_with_protected_hidden = 20517 Object::New(isolate); 20518 object_with_protected_hidden->SetPrototype(protected_hidden_prototype); 20519 20520 context->Exit(); 20521 20522 // Template for object for second context. Values to test are put on it as 20523 // properties. 20524 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); 20525 global_template->Set(v8_str("simple"), simple_object); 20526 global_template->Set(v8_str("protected"), protected_object); 20527 global_template->Set(v8_str("global"), global_object); 20528 global_template->Set(v8_str("proxy"), proxy_object); 20529 global_template->Set(v8_str("hidden"), object_with_hidden); 20530 global_template->Set(v8_str("phidden"), object_with_protected_hidden); 20531 20532 LocalContext context2(NULL, global_template); 20533 20534 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 20535 CHECK(result1->Equals(simple_object->GetPrototype())); 20536 20537 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 20538 CHECK(result2.IsEmpty()); 20539 20540 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 20541 CHECK(result3->Equals(global_object->GetPrototype())); 20542 20543 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 20544 CHECK(result4.IsEmpty()); 20545 20546 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 20547 CHECK(result5->Equals( 20548 object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); 20549 20550 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); 20551 CHECK(result6.IsEmpty()); 20552 } 20553 20554 20555 THREADED_TEST(Regress125988) { 20556 v8::HandleScope scope(CcTest::isolate()); 20557 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate()); 20558 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter); 20559 LocalContext env; 20560 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction()); 20561 CompileRun("var a = new Object();" 20562 "var b = new Intercept();" 20563 "var c = new Object();" 20564 "c.__proto__ = b;" 20565 "b.__proto__ = a;" 20566 "a.x = 23;" 20567 "for (var i = 0; i < 3; i++) c.x;"); 20568 ExpectBoolean("c.hasOwnProperty('x')", false); 20569 ExpectInt32("c.x", 23); 20570 CompileRun("a.y = 42;" 20571 "for (var i = 0; i < 3; i++) c.x;"); 20572 ExpectBoolean("c.hasOwnProperty('x')", false); 20573 ExpectInt32("c.x", 23); 20574 ExpectBoolean("c.hasOwnProperty('y')", false); 20575 ExpectInt32("c.y", 42); 20576 } 20577 20578 20579 static void TestReceiver(Local<Value> expected_result, 20580 Local<Value> expected_receiver, 20581 const char* code) { 20582 Local<Value> result = CompileRun(code); 20583 CHECK(result->IsObject()); 20584 CHECK(expected_receiver->Equals(result->ToObject()->Get(1))); 20585 CHECK(expected_result->Equals(result->ToObject()->Get(0))); 20586 } 20587 20588 20589 THREADED_TEST(ForeignFunctionReceiver) { 20590 v8::Isolate* isolate = CcTest::isolate(); 20591 HandleScope scope(isolate); 20592 20593 // Create two contexts with different "id" properties ('i' and 'o'). 20594 // Call a function both from its own context and from a the foreign 20595 // context, and see what "this" is bound to (returning both "this" 20596 // and "this.id" for comparison). 20597 20598 Local<Context> foreign_context = v8::Context::New(isolate); 20599 foreign_context->Enter(); 20600 Local<Value> foreign_function = 20601 CompileRun("function func() { return { 0: this.id, " 20602 " 1: this, " 20603 " toString: function() { " 20604 " return this[0];" 20605 " }" 20606 " };" 20607 "}" 20608 "var id = 'i';" 20609 "func;"); 20610 CHECK(foreign_function->IsFunction()); 20611 foreign_context->Exit(); 20612 20613 LocalContext context; 20614 20615 Local<String> password = v8_str("Password"); 20616 // Don't get hit by security checks when accessing foreign_context's 20617 // global receiver (aka. global proxy). 20618 context->SetSecurityToken(password); 20619 foreign_context->SetSecurityToken(password); 20620 20621 Local<String> i = v8_str("i"); 20622 Local<String> o = v8_str("o"); 20623 Local<String> id = v8_str("id"); 20624 20625 CompileRun("function ownfunc() { return { 0: this.id, " 20626 " 1: this, " 20627 " toString: function() { " 20628 " return this[0];" 20629 " }" 20630 " };" 20631 "}" 20632 "var id = 'o';" 20633 "ownfunc"); 20634 context->Global()->Set(v8_str("func"), foreign_function); 20635 20636 // Sanity check the contexts. 20637 CHECK(i->Equals(foreign_context->Global()->Get(id))); 20638 CHECK(o->Equals(context->Global()->Get(id))); 20639 20640 // Checking local function's receiver. 20641 // Calling function using its call/apply methods. 20642 TestReceiver(o, context->Global(), "ownfunc.call()"); 20643 TestReceiver(o, context->Global(), "ownfunc.apply()"); 20644 // Making calls through built-in functions. 20645 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 20646 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))); 20647 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))); 20648 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))); 20649 // Calling with environment record as base. 20650 TestReceiver(o, context->Global(), "ownfunc()"); 20651 // Calling with no base. 20652 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 20653 20654 // Checking foreign function return value. 20655 // Calling function using its call/apply methods. 20656 TestReceiver(i, foreign_context->Global(), "func.call()"); 20657 TestReceiver(i, foreign_context->Global(), "func.apply()"); 20658 // Calling function using another context's call/apply methods. 20659 TestReceiver(i, foreign_context->Global(), 20660 "Function.prototype.call.call(func)"); 20661 TestReceiver(i, foreign_context->Global(), 20662 "Function.prototype.call.apply(func)"); 20663 TestReceiver(i, foreign_context->Global(), 20664 "Function.prototype.apply.call(func)"); 20665 TestReceiver(i, foreign_context->Global(), 20666 "Function.prototype.apply.apply(func)"); 20667 // Making calls through built-in functions. 20668 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 20669 // ToString(func()) is func()[0], i.e., the returned this.id. 20670 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]"))); 20671 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]"))); 20672 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]"))); 20673 20674 // Calling with environment record as base. 20675 TestReceiver(i, foreign_context->Global(), "func()"); 20676 // Calling with no base. 20677 TestReceiver(i, foreign_context->Global(), "(1,func)()"); 20678 } 20679 20680 20681 uint8_t callback_fired = 0; 20682 20683 20684 void CallCompletedCallback1() { 20685 v8::base::OS::Print("Firing callback 1.\n"); 20686 callback_fired ^= 1; // Toggle first bit. 20687 } 20688 20689 20690 void CallCompletedCallback2() { 20691 v8::base::OS::Print("Firing callback 2.\n"); 20692 callback_fired ^= 2; // Toggle second bit. 20693 } 20694 20695 20696 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 20697 int32_t level = args[0]->Int32Value(); 20698 if (level < 3) { 20699 level++; 20700 v8::base::OS::Print("Entering recursion level %d.\n", level); 20701 char script[64]; 20702 i::Vector<char> script_vector(script, sizeof(script)); 20703 i::SNPrintF(script_vector, "recursion(%d)", level); 20704 CompileRun(script_vector.start()); 20705 v8::base::OS::Print("Leaving recursion level %d.\n", level); 20706 CHECK_EQ(0, callback_fired); 20707 } else { 20708 v8::base::OS::Print("Recursion ends.\n"); 20709 CHECK_EQ(0, callback_fired); 20710 } 20711 } 20712 20713 20714 TEST(CallCompletedCallback) { 20715 LocalContext env; 20716 v8::HandleScope scope(env->GetIsolate()); 20717 v8::Handle<v8::FunctionTemplate> recursive_runtime = 20718 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall); 20719 env->Global()->Set(v8_str("recursion"), 20720 recursive_runtime->GetFunction()); 20721 // Adding the same callback a second time has no effect. 20722 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20723 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); 20724 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); 20725 v8::base::OS::Print("--- Script (1) ---\n"); 20726 Local<Script> script = v8::Script::Compile( 20727 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)")); 20728 script->Run(); 20729 CHECK_EQ(3, callback_fired); 20730 20731 v8::base::OS::Print("\n--- Script (2) ---\n"); 20732 callback_fired = 0; 20733 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); 20734 script->Run(); 20735 CHECK_EQ(2, callback_fired); 20736 20737 v8::base::OS::Print("\n--- Function ---\n"); 20738 callback_fired = 0; 20739 Local<Function> recursive_function = 20740 Local<Function>::Cast(env->Global()->Get(v8_str("recursion"))); 20741 v8::Handle<Value> args[] = { v8_num(0) }; 20742 recursive_function->Call(env->Global(), 1, args); 20743 CHECK_EQ(2, callback_fired); 20744 } 20745 20746 20747 void CallCompletedCallbackNoException() { 20748 v8::HandleScope scope(CcTest::isolate()); 20749 CompileRun("1+1;"); 20750 } 20751 20752 20753 void CallCompletedCallbackException() { 20754 v8::HandleScope scope(CcTest::isolate()); 20755 CompileRun("throw 'second exception';"); 20756 } 20757 20758 20759 TEST(CallCompletedCallbackOneException) { 20760 LocalContext env; 20761 v8::HandleScope scope(env->GetIsolate()); 20762 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException); 20763 CompileRun("throw 'exception';"); 20764 } 20765 20766 20767 TEST(CallCompletedCallbackTwoExceptions) { 20768 LocalContext env; 20769 v8::HandleScope scope(env->GetIsolate()); 20770 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException); 20771 CompileRun("throw 'first exception';"); 20772 } 20773 20774 20775 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) { 20776 v8::HandleScope scope(info.GetIsolate()); 20777 CompileRun("ext1Calls++;"); 20778 } 20779 20780 20781 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) { 20782 v8::HandleScope scope(info.GetIsolate()); 20783 CompileRun("ext2Calls++;"); 20784 } 20785 20786 20787 void* g_passed_to_three = NULL; 20788 20789 20790 static void MicrotaskThree(void* data) { 20791 g_passed_to_three = data; 20792 } 20793 20794 20795 TEST(EnqueueMicrotask) { 20796 LocalContext env; 20797 v8::HandleScope scope(env->GetIsolate()); 20798 CompileRun( 20799 "var ext1Calls = 0;" 20800 "var ext2Calls = 0;"); 20801 CompileRun("1+1;"); 20802 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); 20803 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20804 20805 env->GetIsolate()->EnqueueMicrotask( 20806 Function::New(env->GetIsolate(), MicrotaskOne)); 20807 CompileRun("1+1;"); 20808 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20809 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20810 20811 env->GetIsolate()->EnqueueMicrotask( 20812 Function::New(env->GetIsolate(), MicrotaskOne)); 20813 env->GetIsolate()->EnqueueMicrotask( 20814 Function::New(env->GetIsolate(), MicrotaskTwo)); 20815 CompileRun("1+1;"); 20816 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20817 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20818 20819 env->GetIsolate()->EnqueueMicrotask( 20820 Function::New(env->GetIsolate(), MicrotaskTwo)); 20821 CompileRun("1+1;"); 20822 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20823 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20824 20825 CompileRun("1+1;"); 20826 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20827 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20828 20829 g_passed_to_three = NULL; 20830 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree); 20831 CompileRun("1+1;"); 20832 CHECK_EQ(NULL, g_passed_to_three); 20833 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20834 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20835 20836 int dummy; 20837 env->GetIsolate()->EnqueueMicrotask( 20838 Function::New(env->GetIsolate(), MicrotaskOne)); 20839 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy); 20840 env->GetIsolate()->EnqueueMicrotask( 20841 Function::New(env->GetIsolate(), MicrotaskTwo)); 20842 CompileRun("1+1;"); 20843 CHECK_EQ(&dummy, g_passed_to_three); 20844 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value()); 20845 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20846 g_passed_to_three = NULL; 20847 } 20848 20849 20850 static void MicrotaskExceptionOne( 20851 const v8::FunctionCallbackInfo<Value>& info) { 20852 v8::HandleScope scope(info.GetIsolate()); 20853 CompileRun("exception1Calls++;"); 20854 info.GetIsolate()->ThrowException( 20855 v8::Exception::Error(v8_str("first"))); 20856 } 20857 20858 20859 static void MicrotaskExceptionTwo( 20860 const v8::FunctionCallbackInfo<Value>& info) { 20861 v8::HandleScope scope(info.GetIsolate()); 20862 CompileRun("exception2Calls++;"); 20863 info.GetIsolate()->ThrowException( 20864 v8::Exception::Error(v8_str("second"))); 20865 } 20866 20867 20868 TEST(RunMicrotasksIgnoresThrownExceptions) { 20869 LocalContext env; 20870 v8::Isolate* isolate = env->GetIsolate(); 20871 v8::HandleScope scope(isolate); 20872 CompileRun( 20873 "var exception1Calls = 0;" 20874 "var exception2Calls = 0;"); 20875 isolate->EnqueueMicrotask( 20876 Function::New(isolate, MicrotaskExceptionOne)); 20877 isolate->EnqueueMicrotask( 20878 Function::New(isolate, MicrotaskExceptionTwo)); 20879 TryCatch try_catch; 20880 CompileRun("1+1;"); 20881 CHECK(!try_catch.HasCaught()); 20882 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value()); 20883 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value()); 20884 } 20885 20886 20887 TEST(SetAutorunMicrotasks) { 20888 LocalContext env; 20889 v8::HandleScope scope(env->GetIsolate()); 20890 CompileRun( 20891 "var ext1Calls = 0;" 20892 "var ext2Calls = 0;"); 20893 CompileRun("1+1;"); 20894 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); 20895 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20896 20897 env->GetIsolate()->EnqueueMicrotask( 20898 Function::New(env->GetIsolate(), MicrotaskOne)); 20899 CompileRun("1+1;"); 20900 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20901 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20902 20903 env->GetIsolate()->SetAutorunMicrotasks(false); 20904 env->GetIsolate()->EnqueueMicrotask( 20905 Function::New(env->GetIsolate(), MicrotaskOne)); 20906 env->GetIsolate()->EnqueueMicrotask( 20907 Function::New(env->GetIsolate(), MicrotaskTwo)); 20908 CompileRun("1+1;"); 20909 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20910 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); 20911 20912 env->GetIsolate()->RunMicrotasks(); 20913 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20914 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20915 20916 env->GetIsolate()->EnqueueMicrotask( 20917 Function::New(env->GetIsolate(), MicrotaskTwo)); 20918 CompileRun("1+1;"); 20919 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20920 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); 20921 20922 env->GetIsolate()->RunMicrotasks(); 20923 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20924 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); 20925 20926 env->GetIsolate()->SetAutorunMicrotasks(true); 20927 env->GetIsolate()->EnqueueMicrotask( 20928 Function::New(env->GetIsolate(), MicrotaskTwo)); 20929 CompileRun("1+1;"); 20930 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20931 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20932 20933 env->GetIsolate()->EnqueueMicrotask( 20934 Function::New(env->GetIsolate(), MicrotaskTwo)); 20935 { 20936 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate()); 20937 CompileRun("1+1;"); 20938 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20939 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); 20940 } 20941 20942 CompileRun("1+1;"); 20943 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); 20944 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value()); 20945 } 20946 20947 20948 TEST(RunMicrotasksWithoutEnteringContext) { 20949 v8::Isolate* isolate = CcTest::isolate(); 20950 HandleScope handle_scope(isolate); 20951 isolate->SetAutorunMicrotasks(false); 20952 Handle<Context> context = Context::New(isolate); 20953 { 20954 Context::Scope context_scope(context); 20955 CompileRun("var ext1Calls = 0;"); 20956 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne)); 20957 } 20958 isolate->RunMicrotasks(); 20959 { 20960 Context::Scope context_scope(context); 20961 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); 20962 } 20963 isolate->SetAutorunMicrotasks(true); 20964 } 20965 20966 20967 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) { 20968 v8::DebugEvent event = event_details.GetEvent(); 20969 if (event != v8::Break) return; 20970 Handle<Object> exec_state = event_details.GetExecutionState(); 20971 Handle<Value> break_id = exec_state->Get(v8_str("break_id")); 20972 CompileRun("function f(id) { new FrameDetails(id, 0); }"); 20973 Handle<Function> fun = Handle<Function>::Cast( 20974 CcTest::global()->Get(v8_str("f"))->ToObject()); 20975 fun->Call(CcTest::global(), 1, &break_id); 20976 } 20977 20978 20979 TEST(Regress385349) { 20980 i::FLAG_allow_natives_syntax = true; 20981 v8::Isolate* isolate = CcTest::isolate(); 20982 HandleScope handle_scope(isolate); 20983 isolate->SetAutorunMicrotasks(false); 20984 Handle<Context> context = Context::New(isolate); 20985 v8::Debug::SetDebugEventListener(DebugEventInObserver); 20986 { 20987 Context::Scope context_scope(context); 20988 CompileRun("var obj = {};" 20989 "Object.observe(obj, function(changes) { debugger; });" 20990 "obj.a = 0;"); 20991 } 20992 isolate->RunMicrotasks(); 20993 isolate->SetAutorunMicrotasks(true); 20994 v8::Debug::SetDebugEventListener(NULL); 20995 } 20996 20997 20998 #ifdef DEBUG 20999 static int probes_counter = 0; 21000 static int misses_counter = 0; 21001 static int updates_counter = 0; 21002 21003 21004 static int* LookupCounter(const char* name) { 21005 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 21006 return &probes_counter; 21007 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 21008 return &misses_counter; 21009 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 21010 return &updates_counter; 21011 } 21012 return NULL; 21013 } 21014 21015 21016 static const char* kMegamorphicTestProgram = 21017 "function ClassA() { };" 21018 "function ClassB() { };" 21019 "ClassA.prototype.foo = function() { };" 21020 "ClassB.prototype.foo = function() { };" 21021 "function fooify(obj) { obj.foo(); };" 21022 "var a = new ClassA();" 21023 "var b = new ClassB();" 21024 "for (var i = 0; i < 10000; i++) {" 21025 " fooify(a);" 21026 " fooify(b);" 21027 "}"; 21028 #endif 21029 21030 21031 static void StubCacheHelper(bool primary) { 21032 #ifdef DEBUG 21033 i::FLAG_native_code_counters = true; 21034 if (primary) { 21035 i::FLAG_test_primary_stub_cache = true; 21036 } else { 21037 i::FLAG_test_secondary_stub_cache = true; 21038 } 21039 i::FLAG_crankshaft = false; 21040 LocalContext env; 21041 env->GetIsolate()->SetCounterFunction(LookupCounter); 21042 v8::HandleScope scope(env->GetIsolate()); 21043 int initial_probes = probes_counter; 21044 int initial_misses = misses_counter; 21045 int initial_updates = updates_counter; 21046 CompileRun(kMegamorphicTestProgram); 21047 int probes = probes_counter - initial_probes; 21048 int misses = misses_counter - initial_misses; 21049 int updates = updates_counter - initial_updates; 21050 CHECK_LT(updates, 10); 21051 CHECK_LT(misses, 10); 21052 // TODO(verwaest): Update this test to overflow the degree of polymorphism 21053 // before megamorphism. The number of probes will only work once we teach the 21054 // serializer to embed references to counters in the stubs, given that the 21055 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub. 21056 CHECK_GE(probes, 0); 21057 #endif 21058 } 21059 21060 21061 TEST(SecondaryStubCache) { 21062 StubCacheHelper(true); 21063 } 21064 21065 21066 TEST(PrimaryStubCache) { 21067 StubCacheHelper(false); 21068 } 21069 21070 21071 #ifdef DEBUG 21072 static int cow_arrays_created_runtime = 0; 21073 21074 21075 static int* LookupCounterCOWArrays(const char* name) { 21076 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) { 21077 return &cow_arrays_created_runtime; 21078 } 21079 return NULL; 21080 } 21081 #endif 21082 21083 21084 TEST(CheckCOWArraysCreatedRuntimeCounter) { 21085 #ifdef DEBUG 21086 i::FLAG_native_code_counters = true; 21087 LocalContext env; 21088 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays); 21089 v8::HandleScope scope(env->GetIsolate()); 21090 int initial_cow_arrays = cow_arrays_created_runtime; 21091 CompileRun("var o = [1, 2, 3];"); 21092 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays); 21093 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};"); 21094 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays); 21095 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};"); 21096 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays); 21097 #endif 21098 } 21099 21100 21101 TEST(StaticGetters) { 21102 LocalContext context; 21103 i::Factory* factory = CcTest::i_isolate()->factory(); 21104 v8::Isolate* isolate = CcTest::isolate(); 21105 v8::HandleScope scope(isolate); 21106 i::Handle<i::Object> undefined_value = factory->undefined_value(); 21107 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 21108 i::Handle<i::Object> null_value = factory->null_value(); 21109 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 21110 i::Handle<i::Object> true_value = factory->true_value(); 21111 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 21112 i::Handle<i::Object> false_value = factory->false_value(); 21113 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 21114 } 21115 21116 21117 UNINITIALIZED_TEST(IsolateEmbedderData) { 21118 CcTest::DisableAutomaticDispose(); 21119 v8::Isolate* isolate = v8::Isolate::New(); 21120 isolate->Enter(); 21121 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 21122 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21123 CHECK_EQ(NULL, isolate->GetData(slot)); 21124 CHECK_EQ(NULL, i_isolate->GetData(slot)); 21125 } 21126 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21127 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21128 isolate->SetData(slot, data); 21129 } 21130 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21131 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 21132 CHECK_EQ(data, isolate->GetData(slot)); 21133 CHECK_EQ(data, i_isolate->GetData(slot)); 21134 } 21135 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21136 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21137 isolate->SetData(slot, data); 21138 } 21139 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 21140 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 21141 CHECK_EQ(data, isolate->GetData(slot)); 21142 CHECK_EQ(data, i_isolate->GetData(slot)); 21143 } 21144 isolate->Exit(); 21145 isolate->Dispose(); 21146 } 21147 21148 21149 TEST(StringEmpty) { 21150 LocalContext context; 21151 i::Factory* factory = CcTest::i_isolate()->factory(); 21152 v8::Isolate* isolate = CcTest::isolate(); 21153 v8::HandleScope scope(isolate); 21154 i::Handle<i::Object> empty_string = factory->empty_string(); 21155 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 21156 } 21157 21158 21159 static int instance_checked_getter_count = 0; 21160 static void InstanceCheckedGetter( 21161 Local<String> name, 21162 const v8::PropertyCallbackInfo<v8::Value>& info) { 21163 CHECK_EQ(name, v8_str("foo")); 21164 instance_checked_getter_count++; 21165 info.GetReturnValue().Set(v8_num(11)); 21166 } 21167 21168 21169 static int instance_checked_setter_count = 0; 21170 static void InstanceCheckedSetter(Local<String> name, 21171 Local<Value> value, 21172 const v8::PropertyCallbackInfo<void>& info) { 21173 CHECK_EQ(name, v8_str("foo")); 21174 CHECK_EQ(value, v8_num(23)); 21175 instance_checked_setter_count++; 21176 } 21177 21178 21179 static void CheckInstanceCheckedResult(int getters, int setters, 21180 bool expects_callbacks, 21181 TryCatch* try_catch) { 21182 if (expects_callbacks) { 21183 CHECK(!try_catch->HasCaught()); 21184 CHECK_EQ(getters, instance_checked_getter_count); 21185 CHECK_EQ(setters, instance_checked_setter_count); 21186 } else { 21187 CHECK(try_catch->HasCaught()); 21188 CHECK_EQ(0, instance_checked_getter_count); 21189 CHECK_EQ(0, instance_checked_setter_count); 21190 } 21191 try_catch->Reset(); 21192 } 21193 21194 21195 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 21196 instance_checked_getter_count = 0; 21197 instance_checked_setter_count = 0; 21198 TryCatch try_catch; 21199 21200 // Test path through generic runtime code. 21201 CompileRun("obj.foo"); 21202 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 21203 CompileRun("obj.foo = 23"); 21204 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 21205 21206 // Test path through generated LoadIC and StoredIC. 21207 CompileRun("function test_get(o) { o.foo; }" 21208 "test_get(obj);"); 21209 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 21210 CompileRun("test_get(obj);"); 21211 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 21212 CompileRun("test_get(obj);"); 21213 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 21214 CompileRun("function test_set(o) { o.foo = 23; }" 21215 "test_set(obj);"); 21216 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 21217 CompileRun("test_set(obj);"); 21218 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 21219 CompileRun("test_set(obj);"); 21220 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 21221 21222 // Test path through optimized code. 21223 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 21224 "test_get(obj);"); 21225 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 21226 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 21227 "test_set(obj);"); 21228 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 21229 21230 // Cleanup so that closures start out fresh in next check. 21231 CompileRun("%DeoptimizeFunction(test_get);" 21232 "%ClearFunctionTypeFeedback(test_get);" 21233 "%DeoptimizeFunction(test_set);" 21234 "%ClearFunctionTypeFeedback(test_set);"); 21235 } 21236 21237 21238 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 21239 v8::internal::FLAG_allow_natives_syntax = true; 21240 LocalContext context; 21241 v8::HandleScope scope(context->GetIsolate()); 21242 21243 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21244 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21245 inst->SetAccessor(v8_str("foo"), 21246 InstanceCheckedGetter, InstanceCheckedSetter, 21247 Handle<Value>(), 21248 v8::DEFAULT, 21249 v8::None, 21250 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21251 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21252 21253 printf("Testing positive ...\n"); 21254 CompileRun("var obj = new f();"); 21255 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21256 CheckInstanceCheckedAccessors(true); 21257 21258 printf("Testing negative ...\n"); 21259 CompileRun("var obj = {};" 21260 "obj.__proto__ = new f();"); 21261 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21262 CheckInstanceCheckedAccessors(false); 21263 } 21264 21265 21266 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 21267 v8::internal::FLAG_allow_natives_syntax = true; 21268 LocalContext context; 21269 v8::HandleScope scope(context->GetIsolate()); 21270 21271 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21272 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 21273 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21274 inst->SetAccessor(v8_str("foo"), 21275 InstanceCheckedGetter, InstanceCheckedSetter, 21276 Handle<Value>(), 21277 v8::DEFAULT, 21278 v8::None, 21279 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21280 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21281 21282 printf("Testing positive ...\n"); 21283 CompileRun("var obj = new f();"); 21284 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21285 CheckInstanceCheckedAccessors(true); 21286 21287 printf("Testing negative ...\n"); 21288 CompileRun("var obj = {};" 21289 "obj.__proto__ = new f();"); 21290 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21291 CheckInstanceCheckedAccessors(false); 21292 } 21293 21294 21295 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 21296 v8::internal::FLAG_allow_natives_syntax = true; 21297 LocalContext context; 21298 v8::HandleScope scope(context->GetIsolate()); 21299 21300 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21301 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 21302 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter, 21303 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT, 21304 v8::None, 21305 v8::AccessorSignature::New(context->GetIsolate(), templ)); 21306 context->Global()->Set(v8_str("f"), templ->GetFunction()); 21307 21308 printf("Testing positive ...\n"); 21309 CompileRun("var obj = new f();"); 21310 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21311 CheckInstanceCheckedAccessors(true); 21312 21313 printf("Testing negative ...\n"); 21314 CompileRun("var obj = {};" 21315 "obj.__proto__ = new f();"); 21316 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21317 CheckInstanceCheckedAccessors(false); 21318 21319 printf("Testing positive with modified prototype chain ...\n"); 21320 CompileRun("var obj = new f();" 21321 "var pro = {};" 21322 "pro.__proto__ = obj.__proto__;" 21323 "obj.__proto__ = pro;"); 21324 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 21325 CheckInstanceCheckedAccessors(true); 21326 } 21327 21328 21329 TEST(TryFinallyMessage) { 21330 LocalContext context; 21331 v8::HandleScope scope(context->GetIsolate()); 21332 { 21333 // Test that the original error message is not lost if there is a 21334 // recursive call into Javascript is done in the finally block, e.g. to 21335 // initialize an IC. (crbug.com/129171) 21336 TryCatch try_catch; 21337 const char* trigger_ic = 21338 "try { \n" 21339 " throw new Error('test'); \n" 21340 "} finally { \n" 21341 " var x = 0; \n" 21342 " x++; \n" // Trigger an IC initialization here. 21343 "} \n"; 21344 CompileRun(trigger_ic); 21345 CHECK(try_catch.HasCaught()); 21346 Local<Message> message = try_catch.Message(); 21347 CHECK(!message.IsEmpty()); 21348 CHECK_EQ(2, message->GetLineNumber()); 21349 } 21350 21351 { 21352 // Test that the original exception message is indeed overwritten if 21353 // a new error is thrown in the finally block. 21354 TryCatch try_catch; 21355 const char* throw_again = 21356 "try { \n" 21357 " throw new Error('test'); \n" 21358 "} finally { \n" 21359 " var x = 0; \n" 21360 " x++; \n" 21361 " throw new Error('again'); \n" // This is the new uncaught error. 21362 "} \n"; 21363 CompileRun(throw_again); 21364 CHECK(try_catch.HasCaught()); 21365 Local<Message> message = try_catch.Message(); 21366 CHECK(!message.IsEmpty()); 21367 CHECK_EQ(6, message->GetLineNumber()); 21368 } 21369 } 21370 21371 21372 static void Helper137002(bool do_store, 21373 bool polymorphic, 21374 bool remove_accessor, 21375 bool interceptor) { 21376 LocalContext context; 21377 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate()); 21378 if (interceptor) { 21379 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor); 21380 } else { 21381 templ->SetAccessor(v8_str("foo"), 21382 GetterWhichReturns42, 21383 SetterWhichSetsYOnThisTo23); 21384 } 21385 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21386 21387 // Turn monomorphic on slow object with native accessor, then turn 21388 // polymorphic, finally optimize to create negative lookup and fail. 21389 CompileRun(do_store ? 21390 "function f(x) { x.foo = void 0; }" : 21391 "function f(x) { return x.foo; }"); 21392 CompileRun("obj.y = void 0;"); 21393 if (!interceptor) { 21394 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 21395 } 21396 CompileRun("obj.__proto__ = null;" 21397 "f(obj); f(obj); f(obj);"); 21398 if (polymorphic) { 21399 CompileRun("f({});"); 21400 } 21401 CompileRun("obj.y = void 0;" 21402 "%OptimizeFunctionOnNextCall(f);"); 21403 if (remove_accessor) { 21404 CompileRun("delete obj.foo;"); 21405 } 21406 CompileRun("var result = f(obj);"); 21407 if (do_store) { 21408 CompileRun("result = obj.y;"); 21409 } 21410 if (remove_accessor && !interceptor) { 21411 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); 21412 } else { 21413 CHECK_EQ(do_store ? 23 : 42, 21414 context->Global()->Get(v8_str("result"))->Int32Value()); 21415 } 21416 } 21417 21418 21419 THREADED_TEST(Regress137002a) { 21420 i::FLAG_allow_natives_syntax = true; 21421 i::FLAG_compilation_cache = false; 21422 v8::HandleScope scope(CcTest::isolate()); 21423 for (int i = 0; i < 16; i++) { 21424 Helper137002(i & 8, i & 4, i & 2, i & 1); 21425 } 21426 } 21427 21428 21429 THREADED_TEST(Regress137002b) { 21430 i::FLAG_allow_natives_syntax = true; 21431 LocalContext context; 21432 v8::Isolate* isolate = context->GetIsolate(); 21433 v8::HandleScope scope(isolate); 21434 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21435 templ->SetAccessor(v8_str("foo"), 21436 GetterWhichReturns42, 21437 SetterWhichSetsYOnThisTo23); 21438 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21439 21440 // Turn monomorphic on slow object with native accessor, then just 21441 // delete the property and fail. 21442 CompileRun("function load(x) { return x.foo; }" 21443 "function store(x) { x.foo = void 0; }" 21444 "function keyed_load(x, key) { return x[key]; }" 21445 // Second version of function has a different source (add void 0) 21446 // so that it does not share code with the first version. This 21447 // ensures that the ICs are monomorphic. 21448 "function load2(x) { void 0; return x.foo; }" 21449 "function store2(x) { void 0; x.foo = void 0; }" 21450 "function keyed_load2(x, key) { void 0; return x[key]; }" 21451 21452 "obj.y = void 0;" 21453 "obj.__proto__ = null;" 21454 "var subobj = {};" 21455 "subobj.y = void 0;" 21456 "subobj.__proto__ = obj;" 21457 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21458 21459 // Make the ICs monomorphic. 21460 "load(obj); load(obj);" 21461 "load2(subobj); load2(subobj);" 21462 "store(obj); store(obj);" 21463 "store2(subobj); store2(subobj);" 21464 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 21465 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 21466 21467 // Actually test the shiny new ICs and better not crash. This 21468 // serves as a regression test for issue 142088 as well. 21469 "load(obj);" 21470 "load2(subobj);" 21471 "store(obj);" 21472 "store2(subobj);" 21473 "keyed_load(obj, 'foo');" 21474 "keyed_load2(subobj, 'foo');" 21475 21476 // Delete the accessor. It better not be called any more now. 21477 "delete obj.foo;" 21478 "obj.y = void 0;" 21479 "subobj.y = void 0;" 21480 21481 "var load_result = load(obj);" 21482 "var load_result2 = load2(subobj);" 21483 "var keyed_load_result = keyed_load(obj, 'foo');" 21484 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 21485 "store(obj);" 21486 "store2(subobj);" 21487 "var y_from_obj = obj.y;" 21488 "var y_from_subobj = subobj.y;"); 21489 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); 21490 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); 21491 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); 21492 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); 21493 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); 21494 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); 21495 } 21496 21497 21498 THREADED_TEST(Regress142088) { 21499 i::FLAG_allow_natives_syntax = true; 21500 LocalContext context; 21501 v8::Isolate* isolate = context->GetIsolate(); 21502 v8::HandleScope scope(isolate); 21503 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21504 templ->SetAccessor(v8_str("foo"), 21505 GetterWhichReturns42, 21506 SetterWhichSetsYOnThisTo23); 21507 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 21508 21509 CompileRun("function load(x) { return x.foo; }" 21510 "var o = Object.create(obj);" 21511 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 21512 "load(o); load(o); load(o); load(o);"); 21513 } 21514 21515 21516 THREADED_TEST(Regress3337) { 21517 LocalContext context; 21518 v8::Isolate* isolate = context->GetIsolate(); 21519 v8::HandleScope scope(isolate); 21520 Local<v8::Object> o1 = Object::New(isolate); 21521 Local<v8::Object> o2 = Object::New(isolate); 21522 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1); 21523 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2); 21524 CHECK(io1->map() == io2->map()); 21525 o1->SetIndexedPropertiesToExternalArrayData( 21526 NULL, v8::kExternalUint32Array, 0); 21527 o2->SetIndexedPropertiesToExternalArrayData( 21528 NULL, v8::kExternalUint32Array, 0); 21529 CHECK(io1->map() == io2->map()); 21530 } 21531 21532 21533 THREADED_TEST(Regress137496) { 21534 i::FLAG_expose_gc = true; 21535 LocalContext context; 21536 v8::HandleScope scope(context->GetIsolate()); 21537 21538 // Compile a try-finally clause where the finally block causes a GC 21539 // while there still is a message pending for external reporting. 21540 TryCatch try_catch; 21541 try_catch.SetVerbose(true); 21542 CompileRun("try { throw new Error(); } finally { gc(); }"); 21543 CHECK(try_catch.HasCaught()); 21544 } 21545 21546 21547 THREADED_TEST(Regress149912) { 21548 LocalContext context; 21549 v8::HandleScope scope(context->GetIsolate()); 21550 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21551 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21552 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 21553 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();"); 21554 } 21555 21556 21557 THREADED_TEST(Regress157124) { 21558 LocalContext context; 21559 v8::Isolate* isolate = context->GetIsolate(); 21560 v8::HandleScope scope(isolate); 21561 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 21562 Local<Object> obj = templ->NewInstance(); 21563 obj->GetIdentityHash(); 21564 obj->DeleteHiddenValue(v8_str("Bug")); 21565 } 21566 21567 21568 THREADED_TEST(Regress2535) { 21569 LocalContext context; 21570 v8::HandleScope scope(context->GetIsolate()); 21571 Local<Value> set_value = CompileRun("new Set();"); 21572 Local<Object> set_object(Local<Object>::Cast(set_value)); 21573 CHECK_EQ(0, set_object->InternalFieldCount()); 21574 Local<Value> map_value = CompileRun("new Map();"); 21575 Local<Object> map_object(Local<Object>::Cast(map_value)); 21576 CHECK_EQ(0, map_object->InternalFieldCount()); 21577 } 21578 21579 21580 THREADED_TEST(Regress2746) { 21581 LocalContext context; 21582 v8::Isolate* isolate = context->GetIsolate(); 21583 v8::HandleScope scope(isolate); 21584 Local<Object> obj = Object::New(isolate); 21585 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key"); 21586 obj->SetHiddenValue(key, v8::Undefined(isolate)); 21587 Local<Value> value = obj->GetHiddenValue(key); 21588 CHECK(!value.IsEmpty()); 21589 CHECK(value->IsUndefined()); 21590 } 21591 21592 21593 THREADED_TEST(Regress260106) { 21594 LocalContext context; 21595 v8::Isolate* isolate = context->GetIsolate(); 21596 v8::HandleScope scope(isolate); 21597 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate, 21598 DummyCallHandler); 21599 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 21600 Local<Function> function = templ->GetFunction(); 21601 CHECK(!function.IsEmpty()); 21602 CHECK(function->IsFunction()); 21603 } 21604 21605 21606 THREADED_TEST(JSONParseObject) { 21607 LocalContext context; 21608 HandleScope scope(context->GetIsolate()); 21609 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}")); 21610 Handle<Object> global = context->Global(); 21611 global->Set(v8_str("obj"), obj); 21612 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 21613 } 21614 21615 21616 THREADED_TEST(JSONParseNumber) { 21617 LocalContext context; 21618 HandleScope scope(context->GetIsolate()); 21619 Local<Value> obj = v8::JSON::Parse(v8_str("42")); 21620 Handle<Object> global = context->Global(); 21621 global->Set(v8_str("obj"), obj); 21622 ExpectString("JSON.stringify(obj)", "42"); 21623 } 21624 21625 21626 #if V8_OS_POSIX && !V8_OS_NACL 21627 class ThreadInterruptTest { 21628 public: 21629 ThreadInterruptTest() : sem_(0), sem_value_(0) { } 21630 ~ThreadInterruptTest() {} 21631 21632 void RunTest() { 21633 InterruptThread i_thread(this); 21634 i_thread.Start(); 21635 21636 sem_.Wait(); 21637 CHECK_EQ(kExpectedValue, sem_value_); 21638 } 21639 21640 private: 21641 static const int kExpectedValue = 1; 21642 21643 class InterruptThread : public v8::base::Thread { 21644 public: 21645 explicit InterruptThread(ThreadInterruptTest* test) 21646 : Thread(Options("InterruptThread")), test_(test) {} 21647 21648 virtual void Run() { 21649 struct sigaction action; 21650 21651 // Ensure that we'll enter waiting condition 21652 v8::base::OS::Sleep(100); 21653 21654 // Setup signal handler 21655 memset(&action, 0, sizeof(action)); 21656 action.sa_handler = SignalHandler; 21657 sigaction(SIGCHLD, &action, NULL); 21658 21659 // Send signal 21660 kill(getpid(), SIGCHLD); 21661 21662 // Ensure that if wait has returned because of error 21663 v8::base::OS::Sleep(100); 21664 21665 // Set value and signal semaphore 21666 test_->sem_value_ = 1; 21667 test_->sem_.Signal(); 21668 } 21669 21670 static void SignalHandler(int signal) { 21671 } 21672 21673 private: 21674 ThreadInterruptTest* test_; 21675 }; 21676 21677 v8::base::Semaphore sem_; 21678 volatile int sem_value_; 21679 }; 21680 21681 21682 THREADED_TEST(SemaphoreInterruption) { 21683 ThreadInterruptTest().RunTest(); 21684 } 21685 21686 21687 #endif // V8_OS_POSIX 21688 21689 21690 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global, 21691 Local<Value> name, 21692 v8::AccessType type, 21693 Local<Value> data) { 21694 i::PrintF("Named access blocked.\n"); 21695 return false; 21696 } 21697 21698 21699 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global, 21700 uint32_t key, 21701 v8::AccessType type, 21702 Local<Value> data) { 21703 i::PrintF("Indexed access blocked.\n"); 21704 return false; 21705 } 21706 21707 21708 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21709 CHECK(false); 21710 } 21711 21712 21713 TEST(JSONStringifyAccessCheck) { 21714 v8::V8::Initialize(); 21715 v8::Isolate* isolate = CcTest::isolate(); 21716 v8::HandleScope scope(isolate); 21717 21718 // Create an ObjectTemplate for global objects and install access 21719 // check callbacks that will block access. 21720 v8::Handle<v8::ObjectTemplate> global_template = 21721 v8::ObjectTemplate::New(isolate); 21722 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 21723 IndexAccessAlwaysBlocked); 21724 21725 // Create a context and set an x property on it's global object. 21726 LocalContext context0(NULL, global_template); 21727 v8::Handle<v8::Object> global0 = context0->Global(); 21728 global0->Set(v8_str("x"), v8_num(42)); 21729 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 21730 21731 for (int i = 0; i < 2; i++) { 21732 if (i == 1) { 21733 // Install a toJSON function on the second run. 21734 v8::Handle<v8::FunctionTemplate> toJSON = 21735 v8::FunctionTemplate::New(isolate, UnreachableCallback); 21736 21737 global0->Set(v8_str("toJSON"), toJSON->GetFunction()); 21738 } 21739 // Create a context with a different security token so that the 21740 // failed access check callback will be called on each access. 21741 LocalContext context1(NULL, global_template); 21742 context1->Global()->Set(v8_str("other"), global0); 21743 21744 CHECK(CompileRun("JSON.stringify(other)").IsEmpty()); 21745 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty()); 21746 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty()); 21747 21748 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2); 21749 array->Set(0, v8_str("a")); 21750 array->Set(1, v8_str("b")); 21751 context1->Global()->Set(v8_str("array"), array); 21752 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); 21753 array->TurnOnAccessCheck(); 21754 CHECK(CompileRun("JSON.stringify(array)").IsEmpty()); 21755 CHECK(CompileRun("JSON.stringify([array])").IsEmpty()); 21756 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty()); 21757 } 21758 } 21759 21760 21761 bool access_check_fail_thrown = false; 21762 bool catch_callback_called = false; 21763 21764 21765 // Failed access check callback that performs a GC on each invocation. 21766 void FailedAccessCheckThrows(Local<v8::Object> target, 21767 v8::AccessType type, 21768 Local<v8::Value> data) { 21769 access_check_fail_thrown = true; 21770 i::PrintF("Access check failed. Error thrown.\n"); 21771 CcTest::isolate()->ThrowException( 21772 v8::Exception::Error(v8_str("cross context"))); 21773 } 21774 21775 21776 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21777 for (int i = 0; i < args.Length(); i++) { 21778 i::PrintF("%s\n", *String::Utf8Value(args[i])); 21779 } 21780 catch_callback_called = true; 21781 } 21782 21783 21784 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 21785 args[0]->ToObject()->HasOwnProperty(args[1]->ToString()); 21786 } 21787 21788 21789 void CheckCorrectThrow(const char* script) { 21790 // Test that the script, when wrapped into a try-catch, triggers the catch 21791 // clause due to failed access check throwing an exception. 21792 // The subsequent try-catch should run without any exception. 21793 access_check_fail_thrown = false; 21794 catch_callback_called = false; 21795 i::ScopedVector<char> source(1024); 21796 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 21797 CompileRun(source.start()); 21798 CHECK(access_check_fail_thrown); 21799 CHECK(catch_callback_called); 21800 21801 access_check_fail_thrown = false; 21802 catch_callback_called = false; 21803 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 21804 CHECK(!access_check_fail_thrown); 21805 CHECK(!catch_callback_called); 21806 } 21807 21808 21809 TEST(AccessCheckThrows) { 21810 i::FLAG_allow_natives_syntax = true; 21811 v8::V8::Initialize(); 21812 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 21813 v8::Isolate* isolate = CcTest::isolate(); 21814 v8::HandleScope scope(isolate); 21815 21816 // Create an ObjectTemplate for global objects and install access 21817 // check callbacks that will block access. 21818 v8::Handle<v8::ObjectTemplate> global_template = 21819 v8::ObjectTemplate::New(isolate); 21820 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 21821 IndexAccessAlwaysBlocked); 21822 21823 // Create a context and set an x property on it's global object. 21824 LocalContext context0(NULL, global_template); 21825 v8::Handle<v8::Object> global0 = context0->Global(); 21826 21827 // Create a context with a different security token so that the 21828 // failed access check callback will be called on each access. 21829 LocalContext context1(NULL, global_template); 21830 context1->Global()->Set(v8_str("other"), global0); 21831 21832 v8::Handle<v8::FunctionTemplate> catcher_fun = 21833 v8::FunctionTemplate::New(isolate, CatcherCallback); 21834 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction()); 21835 21836 v8::Handle<v8::FunctionTemplate> has_own_property_fun = 21837 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback); 21838 context1->Global()->Set(v8_str("has_own_property"), 21839 has_own_property_fun->GetFunction()); 21840 21841 { v8::TryCatch try_catch; 21842 access_check_fail_thrown = false; 21843 CompileRun("other.x;"); 21844 CHECK(access_check_fail_thrown); 21845 CHECK(try_catch.HasCaught()); 21846 } 21847 21848 CheckCorrectThrow("other.x"); 21849 CheckCorrectThrow("other[1]"); 21850 CheckCorrectThrow("JSON.stringify(other)"); 21851 CheckCorrectThrow("has_own_property(other, 'x')"); 21852 CheckCorrectThrow("%GetProperty(other, 'x')"); 21853 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)"); 21854 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)"); 21855 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); 21856 CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); 21857 CheckCorrectThrow("%HasOwnProperty(other, 'x')"); 21858 CheckCorrectThrow("%HasProperty(other, 'x')"); 21859 CheckCorrectThrow("%HasElement(other, 1)"); 21860 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); 21861 CheckCorrectThrow("%GetPropertyNames(other)"); 21862 // PROPERTY_ATTRIBUTES_NONE = 0 21863 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)"); 21864 CheckCorrectThrow("%DefineAccessorPropertyUnchecked(" 21865 "other, 'x', null, null, 1)"); 21866 21867 // Reset the failed access check callback so it does not influence 21868 // the other tests. 21869 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 21870 } 21871 21872 21873 THREADED_TEST(Regress256330) { 21874 i::FLAG_allow_natives_syntax = true; 21875 LocalContext context; 21876 v8::HandleScope scope(context->GetIsolate()); 21877 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate()); 21878 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 21879 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 21880 CompileRun("\"use strict\"; var o = new Bug;" 21881 "function f(o) { o.x = 10; };" 21882 "f(o); f(o); f(o);" 21883 "%OptimizeFunctionOnNextCall(f);" 21884 "f(o);"); 21885 ExpectBoolean("%GetOptimizationStatus(f) != 2", true); 21886 } 21887 21888 21889 THREADED_TEST(CrankshaftInterceptorSetter) { 21890 i::FLAG_allow_natives_syntax = true; 21891 v8::HandleScope scope(CcTest::isolate()); 21892 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21893 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21894 LocalContext env; 21895 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21896 CompileRun("var obj = new Obj;" 21897 // Initialize fields to avoid transitions later. 21898 "obj.age = 0;" 21899 "obj.accessor_age = 42;" 21900 "function setter(i) { this.accessor_age = i; };" 21901 "function getter() { return this.accessor_age; };" 21902 "function setAge(i) { obj.age = i; };" 21903 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 21904 "setAge(1);" 21905 "setAge(2);" 21906 "setAge(3);" 21907 "%OptimizeFunctionOnNextCall(setAge);" 21908 "setAge(4);"); 21909 // All stores went through the interceptor. 21910 ExpectInt32("obj.interceptor_age", 4); 21911 ExpectInt32("obj.accessor_age", 42); 21912 } 21913 21914 21915 THREADED_TEST(CrankshaftInterceptorGetter) { 21916 i::FLAG_allow_natives_syntax = true; 21917 v8::HandleScope scope(CcTest::isolate()); 21918 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21919 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21920 LocalContext env; 21921 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21922 CompileRun("var obj = new Obj;" 21923 // Initialize fields to avoid transitions later. 21924 "obj.age = 1;" 21925 "obj.accessor_age = 42;" 21926 "function getter() { return this.accessor_age; };" 21927 "function getAge() { return obj.interceptor_age; };" 21928 "Object.defineProperty(obj, 'interceptor_age', { get:getter });" 21929 "getAge();" 21930 "getAge();" 21931 "getAge();" 21932 "%OptimizeFunctionOnNextCall(getAge);"); 21933 // Access through interceptor. 21934 ExpectInt32("getAge()", 1); 21935 } 21936 21937 21938 THREADED_TEST(CrankshaftInterceptorFieldRead) { 21939 i::FLAG_allow_natives_syntax = true; 21940 v8::HandleScope scope(CcTest::isolate()); 21941 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21942 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21943 LocalContext env; 21944 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21945 CompileRun("var obj = new Obj;" 21946 "obj.__proto__.interceptor_age = 42;" 21947 "obj.age = 100;" 21948 "function getAge() { return obj.interceptor_age; };"); 21949 ExpectInt32("getAge();", 100); 21950 ExpectInt32("getAge();", 100); 21951 ExpectInt32("getAge();", 100); 21952 CompileRun("%OptimizeFunctionOnNextCall(getAge);"); 21953 // Access through interceptor. 21954 ExpectInt32("getAge();", 100); 21955 } 21956 21957 21958 THREADED_TEST(CrankshaftInterceptorFieldWrite) { 21959 i::FLAG_allow_natives_syntax = true; 21960 v8::HandleScope scope(CcTest::isolate()); 21961 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate()); 21962 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 21963 LocalContext env; 21964 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 21965 CompileRun("var obj = new Obj;" 21966 "obj.age = 100000;" 21967 "function setAge(i) { obj.age = i };" 21968 "setAge(100);" 21969 "setAge(101);" 21970 "setAge(102);" 21971 "%OptimizeFunctionOnNextCall(setAge);" 21972 "setAge(103);"); 21973 ExpectInt32("obj.age", 100000); 21974 ExpectInt32("obj.interceptor_age", 103); 21975 } 21976 21977 21978 class RequestInterruptTestBase { 21979 public: 21980 RequestInterruptTestBase() 21981 : env_(), 21982 isolate_(env_->GetIsolate()), 21983 sem_(0), 21984 warmup_(20000), 21985 should_continue_(true) { 21986 } 21987 21988 virtual ~RequestInterruptTestBase() { } 21989 21990 virtual void StartInterruptThread() = 0; 21991 21992 virtual void TestBody() = 0; 21993 21994 void RunTest() { 21995 StartInterruptThread(); 21996 21997 v8::HandleScope handle_scope(isolate_); 21998 21999 TestBody(); 22000 22001 isolate_->ClearInterrupt(); 22002 22003 // Verify we arrived here because interruptor was called 22004 // not due to a bug causing us to exit the loop too early. 22005 CHECK(!should_continue()); 22006 } 22007 22008 void WakeUpInterruptor() { 22009 sem_.Signal(); 22010 } 22011 22012 bool should_continue() const { return should_continue_; } 22013 22014 bool ShouldContinue() { 22015 if (warmup_ > 0) { 22016 if (--warmup_ == 0) { 22017 WakeUpInterruptor(); 22018 } 22019 } 22020 22021 return should_continue_; 22022 } 22023 22024 static void ShouldContinueCallback( 22025 const v8::FunctionCallbackInfo<Value>& info) { 22026 RequestInterruptTestBase* test = 22027 reinterpret_cast<RequestInterruptTestBase*>( 22028 info.Data().As<v8::External>()->Value()); 22029 info.GetReturnValue().Set(test->ShouldContinue()); 22030 } 22031 22032 LocalContext env_; 22033 v8::Isolate* isolate_; 22034 v8::base::Semaphore sem_; 22035 int warmup_; 22036 bool should_continue_; 22037 }; 22038 22039 22040 class RequestInterruptTestBaseWithSimpleInterrupt 22041 : public RequestInterruptTestBase { 22042 public: 22043 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { } 22044 22045 virtual void StartInterruptThread() { 22046 i_thread.Start(); 22047 } 22048 22049 private: 22050 class InterruptThread : public v8::base::Thread { 22051 public: 22052 explicit InterruptThread(RequestInterruptTestBase* test) 22053 : Thread(Options("RequestInterruptTest")), test_(test) {} 22054 22055 virtual void Run() { 22056 test_->sem_.Wait(); 22057 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 22058 } 22059 22060 static void OnInterrupt(v8::Isolate* isolate, void* data) { 22061 reinterpret_cast<RequestInterruptTestBase*>(data)-> 22062 should_continue_ = false; 22063 } 22064 22065 private: 22066 RequestInterruptTestBase* test_; 22067 }; 22068 22069 InterruptThread i_thread; 22070 }; 22071 22072 22073 class RequestInterruptTestWithFunctionCall 22074 : public RequestInterruptTestBaseWithSimpleInterrupt { 22075 public: 22076 virtual void TestBody() { 22077 Local<Function> func = Function::New( 22078 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); 22079 env_->Global()->Set(v8_str("ShouldContinue"), func); 22080 22081 CompileRun("while (ShouldContinue()) { }"); 22082 } 22083 }; 22084 22085 22086 class RequestInterruptTestWithMethodCall 22087 : public RequestInterruptTestBaseWithSimpleInterrupt { 22088 public: 22089 virtual void TestBody() { 22090 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22091 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22092 proto->Set(v8_str("shouldContinue"), Function::New( 22093 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22094 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22095 22096 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22097 } 22098 }; 22099 22100 22101 class RequestInterruptTestWithAccessor 22102 : public RequestInterruptTestBaseWithSimpleInterrupt { 22103 public: 22104 virtual void TestBody() { 22105 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22106 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22107 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New( 22108 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22109 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22110 22111 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22112 } 22113 }; 22114 22115 22116 class RequestInterruptTestWithNativeAccessor 22117 : public RequestInterruptTestBaseWithSimpleInterrupt { 22118 public: 22119 virtual void TestBody() { 22120 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22121 t->InstanceTemplate()->SetNativeDataProperty( 22122 v8_str("shouldContinue"), 22123 &ShouldContinueNativeGetter, 22124 NULL, 22125 v8::External::New(isolate_, this)); 22126 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22127 22128 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); 22129 } 22130 22131 private: 22132 static void ShouldContinueNativeGetter( 22133 Local<String> property, 22134 const v8::PropertyCallbackInfo<v8::Value>& info) { 22135 RequestInterruptTestBase* test = 22136 reinterpret_cast<RequestInterruptTestBase*>( 22137 info.Data().As<v8::External>()->Value()); 22138 info.GetReturnValue().Set(test->ShouldContinue()); 22139 } 22140 }; 22141 22142 22143 class RequestInterruptTestWithMethodCallAndInterceptor 22144 : public RequestInterruptTestBaseWithSimpleInterrupt { 22145 public: 22146 virtual void TestBody() { 22147 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); 22148 v8::Local<v8::Template> proto = t->PrototypeTemplate(); 22149 proto->Set(v8_str("shouldContinue"), Function::New( 22150 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); 22151 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate(); 22152 instance_template->SetNamedPropertyHandler(EmptyInterceptor); 22153 22154 env_->Global()->Set(v8_str("Klass"), t->GetFunction()); 22155 22156 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); 22157 } 22158 22159 private: 22160 static void EmptyInterceptor( 22161 Local<String> property, 22162 const v8::PropertyCallbackInfo<v8::Value>& info) { 22163 } 22164 }; 22165 22166 22167 class RequestInterruptTestWithMathAbs 22168 : public RequestInterruptTestBaseWithSimpleInterrupt { 22169 public: 22170 virtual void TestBody() { 22171 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New( 22172 isolate_, 22173 WakeUpInterruptorCallback, 22174 v8::External::New(isolate_, this))); 22175 22176 env_->Global()->Set(v8_str("ShouldContinue"), Function::New( 22177 isolate_, 22178 ShouldContinueCallback, 22179 v8::External::New(isolate_, this))); 22180 22181 i::FLAG_allow_natives_syntax = true; 22182 CompileRun("function loopish(o) {" 22183 " var pre = 10;" 22184 " while (o.abs(1) > 0) {" 22185 " if (o.abs(1) >= 0 && !ShouldContinue()) break;" 22186 " if (pre > 0) {" 22187 " if (--pre === 0) WakeUpInterruptor(o === Math);" 22188 " }" 22189 " }" 22190 "}" 22191 "var i = 50;" 22192 "var obj = {abs: function () { return i-- }, x: null};" 22193 "delete obj.x;" 22194 "loopish(obj);" 22195 "%OptimizeFunctionOnNextCall(loopish);" 22196 "loopish(Math);"); 22197 22198 i::FLAG_allow_natives_syntax = false; 22199 } 22200 22201 private: 22202 static void WakeUpInterruptorCallback( 22203 const v8::FunctionCallbackInfo<Value>& info) { 22204 if (!info[0]->BooleanValue()) return; 22205 22206 RequestInterruptTestBase* test = 22207 reinterpret_cast<RequestInterruptTestBase*>( 22208 info.Data().As<v8::External>()->Value()); 22209 test->WakeUpInterruptor(); 22210 } 22211 22212 static void ShouldContinueCallback( 22213 const v8::FunctionCallbackInfo<Value>& info) { 22214 RequestInterruptTestBase* test = 22215 reinterpret_cast<RequestInterruptTestBase*>( 22216 info.Data().As<v8::External>()->Value()); 22217 info.GetReturnValue().Set(test->should_continue()); 22218 } 22219 }; 22220 22221 22222 TEST(RequestInterruptTestWithFunctionCall) { 22223 RequestInterruptTestWithFunctionCall().RunTest(); 22224 } 22225 22226 22227 TEST(RequestInterruptTestWithMethodCall) { 22228 RequestInterruptTestWithMethodCall().RunTest(); 22229 } 22230 22231 22232 TEST(RequestInterruptTestWithAccessor) { 22233 RequestInterruptTestWithAccessor().RunTest(); 22234 } 22235 22236 22237 TEST(RequestInterruptTestWithNativeAccessor) { 22238 RequestInterruptTestWithNativeAccessor().RunTest(); 22239 } 22240 22241 22242 TEST(RequestInterruptTestWithMethodCallAndInterceptor) { 22243 RequestInterruptTestWithMethodCallAndInterceptor().RunTest(); 22244 } 22245 22246 22247 TEST(RequestInterruptTestWithMathAbs) { 22248 RequestInterruptTestWithMathAbs().RunTest(); 22249 } 22250 22251 22252 class ClearInterruptFromAnotherThread 22253 : public RequestInterruptTestBase { 22254 public: 22255 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { } 22256 22257 virtual void StartInterruptThread() { 22258 i_thread.Start(); 22259 } 22260 22261 virtual void TestBody() { 22262 Local<Function> func = Function::New( 22263 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); 22264 env_->Global()->Set(v8_str("ShouldContinue"), func); 22265 22266 CompileRun("while (ShouldContinue()) { }"); 22267 } 22268 22269 private: 22270 class InterruptThread : public v8::base::Thread { 22271 public: 22272 explicit InterruptThread(ClearInterruptFromAnotherThread* test) 22273 : Thread(Options("RequestInterruptTest")), test_(test) {} 22274 22275 virtual void Run() { 22276 test_->sem_.Wait(); 22277 test_->isolate_->RequestInterrupt(&OnInterrupt, test_); 22278 test_->sem_.Wait(); 22279 test_->isolate_->ClearInterrupt(); 22280 test_->sem2_.Signal(); 22281 } 22282 22283 static void OnInterrupt(v8::Isolate* isolate, void* data) { 22284 ClearInterruptFromAnotherThread* test = 22285 reinterpret_cast<ClearInterruptFromAnotherThread*>(data); 22286 test->sem_.Signal(); 22287 bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2)); 22288 // Crash instead of timeout to make this failure more prominent. 22289 CHECK(success); 22290 test->should_continue_ = false; 22291 } 22292 22293 private: 22294 ClearInterruptFromAnotherThread* test_; 22295 }; 22296 22297 InterruptThread i_thread; 22298 v8::base::Semaphore sem2_; 22299 }; 22300 22301 22302 TEST(ClearInterruptFromAnotherThread) { 22303 ClearInterruptFromAnotherThread().RunTest(); 22304 } 22305 22306 22307 static Local<Value> function_new_expected_env; 22308 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { 22309 CHECK_EQ(function_new_expected_env, info.Data()); 22310 info.GetReturnValue().Set(17); 22311 } 22312 22313 22314 THREADED_TEST(FunctionNew) { 22315 LocalContext env; 22316 v8::Isolate* isolate = env->GetIsolate(); 22317 v8::HandleScope scope(isolate); 22318 Local<Object> data = v8::Object::New(isolate); 22319 function_new_expected_env = data; 22320 Local<Function> func = Function::New(isolate, FunctionNewCallback, data); 22321 env->Global()->Set(v8_str("func"), func); 22322 Local<Value> result = CompileRun("func();"); 22323 CHECK_EQ(v8::Integer::New(isolate, 17), result); 22324 // Verify function not cached 22325 int serial_number = 22326 i::Smi::cast(v8::Utils::OpenHandle(*func) 22327 ->shared()->get_api_func_data()->serial_number())->value(); 22328 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 22329 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache()); 22330 i::Handle<i::Object> elm = 22331 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked(); 22332 CHECK(elm->IsUndefined()); 22333 // Verify that each Function::New creates a new function instance 22334 Local<Object> data2 = v8::Object::New(isolate); 22335 function_new_expected_env = data2; 22336 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2); 22337 CHECK(!func2->IsNull()); 22338 CHECK_NE(func, func2); 22339 env->Global()->Set(v8_str("func2"), func2); 22340 Local<Value> result2 = CompileRun("func2();"); 22341 CHECK_EQ(v8::Integer::New(isolate, 17), result2); 22342 } 22343 22344 22345 TEST(EscapeableHandleScope) { 22346 HandleScope outer_scope(CcTest::isolate()); 22347 LocalContext context; 22348 const int runs = 10; 22349 Local<String> values[runs]; 22350 for (int i = 0; i < runs; i++) { 22351 v8::EscapableHandleScope inner_scope(CcTest::isolate()); 22352 Local<String> value; 22353 if (i != 0) value = v8_str("escape value"); 22354 values[i] = inner_scope.Escape(value); 22355 } 22356 for (int i = 0; i < runs; i++) { 22357 Local<String> expected; 22358 if (i != 0) { 22359 CHECK_EQ(v8_str("escape value"), values[i]); 22360 } else { 22361 CHECK(values[i].IsEmpty()); 22362 } 22363 } 22364 } 22365 22366 22367 static void SetterWhichExpectsThisAndHolderToDiffer( 22368 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) { 22369 CHECK(info.Holder() != info.This()); 22370 } 22371 22372 22373 TEST(Regress239669) { 22374 LocalContext context; 22375 v8::Isolate* isolate = context->GetIsolate(); 22376 v8::HandleScope scope(isolate); 22377 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); 22378 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer); 22379 context->Global()->Set(v8_str("P"), templ->NewInstance()); 22380 CompileRun( 22381 "function C1() {" 22382 " this.x = 23;" 22383 "};" 22384 "C1.prototype = P;" 22385 "for (var i = 0; i < 4; i++ ) {" 22386 " new C1();" 22387 "}"); 22388 } 22389 22390 22391 class ApiCallOptimizationChecker { 22392 private: 22393 static Local<Object> data; 22394 static Local<Object> receiver; 22395 static Local<Object> holder; 22396 static Local<Object> callee; 22397 static int count; 22398 22399 static void OptimizationCallback( 22400 const v8::FunctionCallbackInfo<v8::Value>& info) { 22401 CHECK(callee == info.Callee()); 22402 CHECK(data == info.Data()); 22403 CHECK(receiver == info.This()); 22404 if (info.Length() == 1) { 22405 CHECK_EQ(v8_num(1), info[0]); 22406 } 22407 CHECK(holder == info.Holder()); 22408 count++; 22409 info.GetReturnValue().Set(v8_str("returned")); 22410 } 22411 22412 public: 22413 enum SignatureType { 22414 kNoSignature, 22415 kSignatureOnReceiver, 22416 kSignatureOnPrototype 22417 }; 22418 22419 void RunAll() { 22420 SignatureType signature_types[] = 22421 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype}; 22422 for (unsigned i = 0; i < arraysize(signature_types); i++) { 22423 SignatureType signature_type = signature_types[i]; 22424 for (int j = 0; j < 2; j++) { 22425 bool global = j == 0; 22426 int key = signature_type + 22427 arraysize(signature_types) * (global ? 1 : 0); 22428 Run(signature_type, global, key); 22429 } 22430 } 22431 } 22432 22433 void Run(SignatureType signature_type, bool global, int key) { 22434 v8::Isolate* isolate = CcTest::isolate(); 22435 v8::HandleScope scope(isolate); 22436 // Build a template for signature checks. 22437 Local<v8::ObjectTemplate> signature_template; 22438 Local<v8::Signature> signature; 22439 { 22440 Local<v8::FunctionTemplate> parent_template = 22441 FunctionTemplate::New(isolate); 22442 parent_template->SetHiddenPrototype(true); 22443 Local<v8::FunctionTemplate> function_template 22444 = FunctionTemplate::New(isolate); 22445 function_template->Inherit(parent_template); 22446 switch (signature_type) { 22447 case kNoSignature: 22448 break; 22449 case kSignatureOnReceiver: 22450 signature = v8::Signature::New(isolate, function_template); 22451 break; 22452 case kSignatureOnPrototype: 22453 signature = v8::Signature::New(isolate, parent_template); 22454 break; 22455 } 22456 signature_template = function_template->InstanceTemplate(); 22457 } 22458 // Global object must pass checks. 22459 Local<v8::Context> context = 22460 v8::Context::New(isolate, NULL, signature_template); 22461 v8::Context::Scope context_scope(context); 22462 // Install regular object that can pass signature checks. 22463 Local<Object> function_receiver = signature_template->NewInstance(); 22464 context->Global()->Set(v8_str("function_receiver"), function_receiver); 22465 // Get the holder objects. 22466 Local<Object> inner_global = 22467 Local<Object>::Cast(context->Global()->GetPrototype()); 22468 // Install functions on hidden prototype object if there is one. 22469 data = Object::New(isolate); 22470 Local<FunctionTemplate> function_template = FunctionTemplate::New( 22471 isolate, OptimizationCallback, data, signature); 22472 Local<Function> function = function_template->GetFunction(); 22473 Local<Object> global_holder = inner_global; 22474 Local<Object> function_holder = function_receiver; 22475 if (signature_type == kSignatureOnPrototype) { 22476 function_holder = Local<Object>::Cast(function_holder->GetPrototype()); 22477 global_holder = Local<Object>::Cast(global_holder->GetPrototype()); 22478 } 22479 global_holder->Set(v8_str("g_f"), function); 22480 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function); 22481 function_holder->Set(v8_str("f"), function); 22482 function_holder->SetAccessorProperty(v8_str("acc"), function, function); 22483 // Initialize expected values. 22484 callee = function; 22485 count = 0; 22486 if (global) { 22487 receiver = context->Global(); 22488 holder = inner_global; 22489 } else { 22490 holder = function_receiver; 22491 // If not using a signature, add something else to the prototype chain 22492 // to test the case that holder != receiver 22493 if (signature_type == kNoSignature) { 22494 receiver = Local<Object>::Cast(CompileRun( 22495 "var receiver_subclass = {};\n" 22496 "receiver_subclass.__proto__ = function_receiver;\n" 22497 "receiver_subclass")); 22498 } else { 22499 receiver = Local<Object>::Cast(CompileRun( 22500 "var receiver_subclass = function_receiver;\n" 22501 "receiver_subclass")); 22502 } 22503 } 22504 // With no signature, the holder is not set. 22505 if (signature_type == kNoSignature) holder = receiver; 22506 // build wrap_function 22507 i::ScopedVector<char> wrap_function(200); 22508 if (global) { 22509 i::SNPrintF( 22510 wrap_function, 22511 "function wrap_f_%d() { var f = g_f; return f(); }\n" 22512 "function wrap_get_%d() { return this.g_acc; }\n" 22513 "function wrap_set_%d() { return this.g_acc = 1; }\n", 22514 key, key, key); 22515 } else { 22516 i::SNPrintF( 22517 wrap_function, 22518 "function wrap_f_%d() { return receiver_subclass.f(); }\n" 22519 "function wrap_get_%d() { return receiver_subclass.acc; }\n" 22520 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", 22521 key, key, key); 22522 } 22523 // build source string 22524 i::ScopedVector<char> source(1000); 22525 i::SNPrintF( 22526 source, 22527 "%s\n" // wrap functions 22528 "function wrap_f() { return wrap_f_%d(); }\n" 22529 "function wrap_get() { return wrap_get_%d(); }\n" 22530 "function wrap_set() { return wrap_set_%d(); }\n" 22531 "check = function(returned) {\n" 22532 " if (returned !== 'returned') { throw returned; }\n" 22533 "}\n" 22534 "\n" 22535 "check(wrap_f());\n" 22536 "check(wrap_f());\n" 22537 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n" 22538 "check(wrap_f());\n" 22539 "\n" 22540 "check(wrap_get());\n" 22541 "check(wrap_get());\n" 22542 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n" 22543 "check(wrap_get());\n" 22544 "\n" 22545 "check = function(returned) {\n" 22546 " if (returned !== 1) { throw returned; }\n" 22547 "}\n" 22548 "check(wrap_set());\n" 22549 "check(wrap_set());\n" 22550 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" 22551 "check(wrap_set());\n", 22552 wrap_function.start(), key, key, key, key, key, key); 22553 v8::TryCatch try_catch; 22554 CompileRun(source.start()); 22555 DCHECK(!try_catch.HasCaught()); 22556 CHECK_EQ(9, count); 22557 } 22558 }; 22559 22560 22561 Local<Object> ApiCallOptimizationChecker::data; 22562 Local<Object> ApiCallOptimizationChecker::receiver; 22563 Local<Object> ApiCallOptimizationChecker::holder; 22564 Local<Object> ApiCallOptimizationChecker::callee; 22565 int ApiCallOptimizationChecker::count = 0; 22566 22567 22568 TEST(TestFunctionCallOptimization) { 22569 i::FLAG_allow_natives_syntax = true; 22570 ApiCallOptimizationChecker checker; 22571 checker.RunAll(); 22572 } 22573 22574 22575 static const char* last_event_message; 22576 static int last_event_status; 22577 void StoringEventLoggerCallback(const char* message, int status) { 22578 last_event_message = message; 22579 last_event_status = status; 22580 } 22581 22582 22583 TEST(EventLogging) { 22584 v8::Isolate* isolate = CcTest::isolate(); 22585 isolate->SetEventLogger(StoringEventLoggerCallback); 22586 v8::internal::HistogramTimer histogramTimer( 22587 "V8.Test", 0, 10000, 50, 22588 reinterpret_cast<v8::internal::Isolate*>(isolate)); 22589 histogramTimer.Start(); 22590 CHECK_EQ("V8.Test", last_event_message); 22591 CHECK_EQ(0, last_event_status); 22592 histogramTimer.Stop(); 22593 CHECK_EQ("V8.Test", last_event_message); 22594 CHECK_EQ(1, last_event_status); 22595 } 22596 22597 22598 TEST(Promises) { 22599 LocalContext context; 22600 v8::Isolate* isolate = context->GetIsolate(); 22601 v8::HandleScope scope(isolate); 22602 Handle<Object> global = context->Global(); 22603 22604 // Creation. 22605 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate); 22606 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate); 22607 Handle<v8::Promise> p = pr->GetPromise(); 22608 Handle<v8::Promise> r = rr->GetPromise(); 22609 22610 // IsPromise predicate. 22611 CHECK(p->IsPromise()); 22612 CHECK(r->IsPromise()); 22613 Handle<Value> o = v8::Object::New(isolate); 22614 CHECK(!o->IsPromise()); 22615 22616 // Resolution and rejection. 22617 pr->Resolve(v8::Integer::New(isolate, 1)); 22618 CHECK(p->IsPromise()); 22619 rr->Reject(v8::Integer::New(isolate, 2)); 22620 CHECK(r->IsPromise()); 22621 22622 // Chaining non-pending promises. 22623 CompileRun( 22624 "var x1 = 0;\n" 22625 "var x2 = 0;\n" 22626 "function f1(x) { x1 = x; return x+1 };\n" 22627 "function f2(x) { x2 = x; return x+1 };\n"); 22628 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1"))); 22629 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2"))); 22630 22631 p->Chain(f1); 22632 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22633 isolate->RunMicrotasks(); 22634 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22635 22636 p->Catch(f2); 22637 isolate->RunMicrotasks(); 22638 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22639 22640 r->Catch(f2); 22641 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22642 isolate->RunMicrotasks(); 22643 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); 22644 22645 r->Chain(f1); 22646 isolate->RunMicrotasks(); 22647 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22648 22649 // Chaining pending promises. 22650 CompileRun("x1 = x2 = 0;"); 22651 pr = v8::Promise::Resolver::New(isolate); 22652 rr = v8::Promise::Resolver::New(isolate); 22653 22654 pr->GetPromise()->Chain(f1); 22655 rr->GetPromise()->Catch(f2); 22656 isolate->RunMicrotasks(); 22657 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22658 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22659 22660 pr->Resolve(v8::Integer::New(isolate, 1)); 22661 rr->Reject(v8::Integer::New(isolate, 2)); 22662 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22663 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22664 22665 isolate->RunMicrotasks(); 22666 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22667 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); 22668 22669 // Multi-chaining. 22670 CompileRun("x1 = x2 = 0;"); 22671 pr = v8::Promise::Resolver::New(isolate); 22672 pr->GetPromise()->Chain(f1)->Chain(f2); 22673 pr->Resolve(v8::Integer::New(isolate, 3)); 22674 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22675 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22676 isolate->RunMicrotasks(); 22677 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22678 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22679 22680 CompileRun("x1 = x2 = 0;"); 22681 rr = v8::Promise::Resolver::New(isolate); 22682 rr->GetPromise()->Catch(f1)->Chain(f2); 22683 rr->Reject(v8::Integer::New(isolate, 3)); 22684 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22685 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22686 isolate->RunMicrotasks(); 22687 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22688 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22689 } 22690 22691 22692 TEST(PromiseThen) { 22693 LocalContext context; 22694 v8::Isolate* isolate = context->GetIsolate(); 22695 v8::HandleScope scope(isolate); 22696 Handle<Object> global = context->Global(); 22697 22698 // Creation. 22699 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate); 22700 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate); 22701 Handle<v8::Promise> p = pr->GetPromise(); 22702 Handle<v8::Promise> q = qr->GetPromise(); 22703 22704 CHECK(p->IsPromise()); 22705 CHECK(q->IsPromise()); 22706 22707 pr->Resolve(v8::Integer::New(isolate, 1)); 22708 qr->Resolve(p); 22709 22710 // Chaining non-pending promises. 22711 CompileRun( 22712 "var x1 = 0;\n" 22713 "var x2 = 0;\n" 22714 "function f1(x) { x1 = x; return x+1 };\n" 22715 "function f2(x) { x2 = x; return x+1 };\n"); 22716 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1"))); 22717 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2"))); 22718 22719 // Chain 22720 q->Chain(f1); 22721 CHECK(global->Get(v8_str("x1"))->IsNumber()); 22722 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22723 isolate->RunMicrotasks(); 22724 CHECK(!global->Get(v8_str("x1"))->IsNumber()); 22725 CHECK_EQ(p, global->Get(v8_str("x1"))); 22726 22727 // Then 22728 CompileRun("x1 = x2 = 0;"); 22729 q->Then(f1); 22730 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22731 isolate->RunMicrotasks(); 22732 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); 22733 22734 // Then 22735 CompileRun("x1 = x2 = 0;"); 22736 pr = v8::Promise::Resolver::New(isolate); 22737 qr = v8::Promise::Resolver::New(isolate); 22738 22739 qr->Resolve(pr); 22740 qr->GetPromise()->Then(f1)->Then(f2); 22741 22742 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22743 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22744 isolate->RunMicrotasks(); 22745 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22746 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22747 22748 pr->Resolve(v8::Integer::New(isolate, 3)); 22749 22750 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); 22751 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); 22752 isolate->RunMicrotasks(); 22753 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); 22754 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); 22755 } 22756 22757 22758 TEST(DisallowJavascriptExecutionScope) { 22759 LocalContext context; 22760 v8::Isolate* isolate = context->GetIsolate(); 22761 v8::HandleScope scope(isolate); 22762 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22763 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22764 CompileRun("2+2"); 22765 } 22766 22767 22768 TEST(AllowJavascriptExecutionScope) { 22769 LocalContext context; 22770 v8::Isolate* isolate = context->GetIsolate(); 22771 v8::HandleScope scope(isolate); 22772 v8::Isolate::DisallowJavascriptExecutionScope no_js( 22773 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); 22774 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22775 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22776 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate); 22777 CompileRun("1+1"); 22778 } 22779 } 22780 22781 22782 TEST(ThrowOnJavascriptExecution) { 22783 LocalContext context; 22784 v8::Isolate* isolate = context->GetIsolate(); 22785 v8::HandleScope scope(isolate); 22786 v8::TryCatch try_catch; 22787 v8::Isolate::DisallowJavascriptExecutionScope throw_js( 22788 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); 22789 CompileRun("1+1"); 22790 CHECK(try_catch.HasCaught()); 22791 } 22792 22793 22794 TEST(Regress354123) { 22795 LocalContext current; 22796 v8::Isolate* isolate = current->GetIsolate(); 22797 v8::HandleScope scope(isolate); 22798 22799 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); 22800 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter); 22801 current->Global()->Set(v8_str("friend"), templ->NewInstance()); 22802 22803 // Test access using __proto__ from the prototype chain. 22804 named_access_count = 0; 22805 CompileRun("friend.__proto__ = {};"); 22806 CHECK_EQ(2, named_access_count); 22807 CompileRun("friend.__proto__;"); 22808 CHECK_EQ(4, named_access_count); 22809 22810 // Test access using __proto__ as a hijacked function (A). 22811 named_access_count = 0; 22812 CompileRun("var p = Object.prototype;" 22813 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;" 22814 "f.call(friend, {});"); 22815 CHECK_EQ(1, named_access_count); 22816 CompileRun("var p = Object.prototype;" 22817 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;" 22818 "f.call(friend);"); 22819 CHECK_EQ(2, named_access_count); 22820 22821 // Test access using __proto__ as a hijacked function (B). 22822 named_access_count = 0; 22823 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');" 22824 "f.call(friend, {});"); 22825 CHECK_EQ(1, named_access_count); 22826 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');" 22827 "f.call(friend);"); 22828 CHECK_EQ(2, named_access_count); 22829 22830 // Test access using Object.setPrototypeOf reflective method. 22831 named_access_count = 0; 22832 CompileRun("Object.setPrototypeOf(friend, {});"); 22833 CHECK_EQ(1, named_access_count); 22834 CompileRun("Object.getPrototypeOf(friend);"); 22835 CHECK_EQ(2, named_access_count); 22836 } 22837 22838 22839 TEST(CaptureStackTraceForStackOverflow) { 22840 v8::internal::FLAG_stack_size = 150; 22841 LocalContext current; 22842 v8::Isolate* isolate = current->GetIsolate(); 22843 v8::HandleScope scope(isolate); 22844 V8::SetCaptureStackTraceForUncaughtExceptions( 22845 true, 10, v8::StackTrace::kDetailed); 22846 v8::TryCatch try_catch; 22847 CompileRun("(function f(x) { f(x+1); })(0)"); 22848 CHECK(try_catch.HasCaught()); 22849 } 22850 22851 22852 TEST(ScriptNameAndLineNumber) { 22853 LocalContext env; 22854 v8::Isolate* isolate = env->GetIsolate(); 22855 v8::HandleScope scope(isolate); 22856 const char* url = "http://www.foo.com/foo.js"; 22857 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13)); 22858 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin); 22859 Local<Script> script = v8::ScriptCompiler::Compile( 22860 isolate, &script_source); 22861 Local<Value> script_name = script->GetUnboundScript()->GetScriptName(); 22862 CHECK(!script_name.IsEmpty()); 22863 CHECK(script_name->IsString()); 22864 String::Utf8Value utf8_name(script_name); 22865 CHECK_EQ(url, *utf8_name); 22866 int line_number = script->GetUnboundScript()->GetLineNumber(0); 22867 CHECK_EQ(13, line_number); 22868 } 22869 22870 22871 void SourceURLHelper(const char* source, const char* expected_source_url, 22872 const char* expected_source_mapping_url) { 22873 Local<Script> script = v8_compile(source); 22874 if (expected_source_url != NULL) { 22875 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL()); 22876 CHECK_EQ(expected_source_url, *url); 22877 } else { 22878 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined()); 22879 } 22880 if (expected_source_mapping_url != NULL) { 22881 v8::String::Utf8Value url( 22882 script->GetUnboundScript()->GetSourceMappingURL()); 22883 CHECK_EQ(expected_source_mapping_url, *url); 22884 } else { 22885 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined()); 22886 } 22887 } 22888 22889 22890 TEST(ScriptSourceURLAndSourceMappingURL) { 22891 LocalContext env; 22892 v8::Isolate* isolate = env->GetIsolate(); 22893 v8::HandleScope scope(isolate); 22894 SourceURLHelper("function foo() {}\n" 22895 "//# sourceURL=bar1.js\n", "bar1.js", NULL); 22896 SourceURLHelper("function foo() {}\n" 22897 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js"); 22898 22899 // Both sourceURL and sourceMappingURL. 22900 SourceURLHelper("function foo() {}\n" 22901 "//# sourceURL=bar3.js\n" 22902 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js"); 22903 22904 // Two source URLs; the first one is ignored. 22905 SourceURLHelper("function foo() {}\n" 22906 "//# sourceURL=ignoreme.js\n" 22907 "//# sourceURL=bar5.js\n", "bar5.js", NULL); 22908 SourceURLHelper("function foo() {}\n" 22909 "//# sourceMappingURL=ignoreme.js\n" 22910 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js"); 22911 22912 // SourceURL or sourceMappingURL in the middle of the script. 22913 SourceURLHelper("function foo() {}\n" 22914 "//# sourceURL=bar7.js\n" 22915 "function baz() {}\n", "bar7.js", NULL); 22916 SourceURLHelper("function foo() {}\n" 22917 "//# sourceMappingURL=bar8.js\n" 22918 "function baz() {}\n", NULL, "bar8.js"); 22919 22920 // Too much whitespace. 22921 SourceURLHelper("function foo() {}\n" 22922 "//# sourceURL=bar9.js\n" 22923 "//# sourceMappingURL=bar10.js\n", NULL, NULL); 22924 SourceURLHelper("function foo() {}\n" 22925 "//# sourceURL =bar11.js\n" 22926 "//# sourceMappingURL =bar12.js\n", NULL, NULL); 22927 22928 // Disallowed characters in value. 22929 SourceURLHelper("function foo() {}\n" 22930 "//# sourceURL=bar13 .js \n" 22931 "//# sourceMappingURL=bar14 .js \n", 22932 NULL, NULL); 22933 SourceURLHelper("function foo() {}\n" 22934 "//# sourceURL=bar15\t.js \n" 22935 "//# sourceMappingURL=bar16\t.js \n", 22936 NULL, NULL); 22937 SourceURLHelper("function foo() {}\n" 22938 "//# sourceURL=bar17'.js \n" 22939 "//# sourceMappingURL=bar18'.js \n", 22940 NULL, NULL); 22941 SourceURLHelper("function foo() {}\n" 22942 "//# sourceURL=bar19\".js \n" 22943 "//# sourceMappingURL=bar20\".js \n", 22944 NULL, NULL); 22945 22946 // Not too much whitespace. 22947 SourceURLHelper("function foo() {}\n" 22948 "//# sourceURL= bar21.js \n" 22949 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js"); 22950 } 22951 22952 22953 TEST(GetOwnPropertyDescriptor) { 22954 LocalContext env; 22955 v8::Isolate* isolate = env->GetIsolate(); 22956 v8::HandleScope scope(isolate); 22957 CompileRun( 22958 "var x = { value : 13};" 22959 "Object.defineProperty(x, 'p0', {value : 12});" 22960 "Object.defineProperty(x, 'p1', {" 22961 " set : function(value) { this.value = value; }," 22962 " get : function() { return this.value; }," 22963 "});"); 22964 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x"))); 22965 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop")); 22966 CHECK(desc->IsUndefined()); 22967 desc = x->GetOwnPropertyDescriptor(v8_str("p0")); 22968 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value"))); 22969 desc = x->GetOwnPropertyDescriptor(v8_str("p1")); 22970 Local<Function> set = 22971 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set"))); 22972 Local<Function> get = 22973 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get"))); 22974 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL)); 22975 Handle<Value> args[] = { v8_num(14) }; 22976 set->Call(x, 1, args); 22977 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL)); 22978 } 22979 22980 22981 TEST(Regress411877) { 22982 v8::Isolate* isolate = CcTest::isolate(); 22983 v8::HandleScope handle_scope(isolate); 22984 v8::Handle<v8::ObjectTemplate> object_template = 22985 v8::ObjectTemplate::New(isolate); 22986 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 22987 IndexedAccessCounter); 22988 22989 v8::Handle<Context> context = Context::New(isolate); 22990 v8::Context::Scope context_scope(context); 22991 22992 context->Global()->Set(v8_str("o"), object_template->NewInstance()); 22993 CompileRun("Object.getOwnPropertyNames(o)"); 22994 } 22995 22996 22997 TEST(GetHiddenPropertyTableAfterAccessCheck) { 22998 v8::Isolate* isolate = CcTest::isolate(); 22999 v8::HandleScope handle_scope(isolate); 23000 v8::Handle<v8::ObjectTemplate> object_template = 23001 v8::ObjectTemplate::New(isolate); 23002 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 23003 IndexedAccessCounter); 23004 23005 v8::Handle<Context> context = Context::New(isolate); 23006 v8::Context::Scope context_scope(context); 23007 23008 v8::Handle<v8::Object> obj = object_template->NewInstance(); 23009 obj->Set(v8_str("key"), v8_str("value")); 23010 obj->Delete(v8_str("key")); 23011 23012 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2")); 23013 } 23014 23015 23016 TEST(Regress411793) { 23017 v8::Isolate* isolate = CcTest::isolate(); 23018 v8::HandleScope handle_scope(isolate); 23019 v8::Handle<v8::ObjectTemplate> object_template = 23020 v8::ObjectTemplate::New(isolate); 23021 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 23022 IndexedAccessCounter); 23023 23024 v8::Handle<Context> context = Context::New(isolate); 23025 v8::Context::Scope context_scope(context); 23026 23027 context->Global()->Set(v8_str("o"), object_template->NewInstance()); 23028 CompileRun( 23029 "Object.defineProperty(o, 'key', " 23030 " { get: function() {}, set: function() {} });"); 23031 } 23032 23033 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream { 23034 public: 23035 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {} 23036 23037 virtual size_t GetMoreData(const uint8_t** src) { 23038 // Unlike in real use cases, this function will never block. 23039 if (chunks_[index_] == NULL) { 23040 return 0; 23041 } 23042 // Copy the data, since the caller takes ownership of it. 23043 size_t len = strlen(chunks_[index_]); 23044 // We don't need to zero-terminate since we return the length. 23045 uint8_t* copy = new uint8_t[len]; 23046 memcpy(copy, chunks_[index_], len); 23047 *src = copy; 23048 ++index_; 23049 return len; 23050 } 23051 23052 // Helper for constructing a string from chunks (the compilation needs it 23053 // too). 23054 static char* FullSourceString(const char** chunks) { 23055 size_t total_len = 0; 23056 for (size_t i = 0; chunks[i] != NULL; ++i) { 23057 total_len += strlen(chunks[i]); 23058 } 23059 char* full_string = new char[total_len + 1]; 23060 size_t offset = 0; 23061 for (size_t i = 0; chunks[i] != NULL; ++i) { 23062 size_t len = strlen(chunks[i]); 23063 memcpy(full_string + offset, chunks[i], len); 23064 offset += len; 23065 } 23066 full_string[total_len] = 0; 23067 return full_string; 23068 } 23069 23070 private: 23071 const char** chunks_; 23072 unsigned index_; 23073 }; 23074 23075 23076 // Helper function for running streaming tests. 23077 void RunStreamingTest(const char** chunks, 23078 v8::ScriptCompiler::StreamedSource::Encoding encoding = 23079 v8::ScriptCompiler::StreamedSource::ONE_BYTE, 23080 bool expected_success = true) { 23081 LocalContext env; 23082 v8::Isolate* isolate = env->GetIsolate(); 23083 v8::HandleScope scope(isolate); 23084 v8::TryCatch try_catch; 23085 23086 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks), 23087 encoding); 23088 v8::ScriptCompiler::ScriptStreamingTask* task = 23089 v8::ScriptCompiler::StartStreamingScript(isolate, &source); 23090 23091 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 23092 // task here in the main thread. 23093 task->Run(); 23094 delete task; 23095 23096 v8::ScriptOrigin origin(v8_str("http://foo.com")); 23097 char* full_source = TestSourceStream::FullSourceString(chunks); 23098 23099 // The possible errors are only produced while compiling. 23100 CHECK_EQ(false, try_catch.HasCaught()); 23101 23102 v8::Handle<Script> script = v8::ScriptCompiler::Compile( 23103 isolate, &source, v8_str(full_source), origin); 23104 if (expected_success) { 23105 CHECK(!script.IsEmpty()); 23106 v8::Handle<Value> result(script->Run()); 23107 // All scripts are supposed to return the fixed value 13 when ran. 23108 CHECK_EQ(13, result->Int32Value()); 23109 } else { 23110 CHECK(script.IsEmpty()); 23111 CHECK(try_catch.HasCaught()); 23112 } 23113 delete[] full_source; 23114 } 23115 23116 23117 TEST(StreamingSimpleScript) { 23118 // This script is unrealistically small, since no one chunk is enough to fill 23119 // the backing buffer of Scanner, let alone overflow it. 23120 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 23121 NULL}; 23122 RunStreamingTest(chunks); 23123 } 23124 23125 23126 TEST(StreamingBiggerScript) { 23127 const char* chunk1 = 23128 "function foo() {\n" 23129 " // Make this chunk sufficiently long so that it will overflow the\n" 23130 " // backing buffer of the Scanner.\n" 23131 " var i = 0;\n" 23132 " var result = 0;\n" 23133 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23134 " result = 0;\n" 23135 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23136 " result = 0;\n" 23137 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23138 " result = 0;\n" 23139 " for (i = 0; i < 13; ++i) { result = result + 1; }\n" 23140 " return result;\n" 23141 "}\n"; 23142 const char* chunks[] = {chunk1, "foo(); ", NULL}; 23143 RunStreamingTest(chunks); 23144 } 23145 23146 23147 TEST(StreamingScriptWithParseError) { 23148 // Test that parse errors from streamed scripts are propagated correctly. 23149 { 23150 char chunk1[] = 23151 " // This will result in a parse error.\n" 23152 " var if else then foo"; 23153 char chunk2[] = " 13\n"; 23154 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23155 23156 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE, 23157 false); 23158 } 23159 // Test that the next script succeeds normally. 23160 { 23161 char chunk1[] = 23162 " // This will be parsed successfully.\n" 23163 " function foo() { return "; 23164 char chunk2[] = " 13; }\n"; 23165 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23166 23167 RunStreamingTest(chunks); 23168 } 23169 } 23170 23171 23172 TEST(StreamingUtf8Script) { 23173 // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers 23174 // don't like it. 23175 const char* chunk1 = 23176 "function foo() {\n" 23177 " // This function will contain an UTF-8 character which is not in\n" 23178 " // ASCII.\n" 23179 " var foob\xeb\x91\x80r = 13;\n" 23180 " return foob\xeb\x91\x80r;\n" 23181 "}\n"; 23182 const char* chunks[] = {chunk1, "foo(); ", NULL}; 23183 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23184 } 23185 23186 23187 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) { 23188 // A sanity check to prove that the approach of splitting UTF-8 23189 // characters is correct. Here is an UTF-8 character which will take three 23190 // bytes. 23191 const char* reference = "\xeb\x91\x80"; 23192 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned. 23193 23194 char chunk1[] = 23195 "function foo() {\n" 23196 " // This function will contain an UTF-8 character which is not in\n" 23197 " // ASCII.\n" 23198 " var foob"; 23199 char chunk2[] = 23200 "XXXr = 13;\n" 23201 " return foob\xeb\x91\x80r;\n" 23202 "}\n"; 23203 for (int i = 0; i < 3; ++i) { 23204 chunk2[i] = reference[i]; 23205 } 23206 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23207 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23208 } 23209 23210 23211 TEST(StreamingUtf8ScriptWithSplitCharacters) { 23212 // Stream data where a multi-byte UTF-8 character is split between two data 23213 // chunks. 23214 const char* reference = "\xeb\x91\x80"; 23215 char chunk1[] = 23216 "function foo() {\n" 23217 " // This function will contain an UTF-8 character which is not in\n" 23218 " // ASCII.\n" 23219 " var foobX"; 23220 char chunk2[] = 23221 "XXr = 13;\n" 23222 " return foob\xeb\x91\x80r;\n" 23223 "}\n"; 23224 chunk1[strlen(chunk1) - 1] = reference[0]; 23225 chunk2[0] = reference[1]; 23226 chunk2[1] = reference[2]; 23227 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23228 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23229 } 23230 23231 23232 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) { 23233 // Tests edge cases which should still be decoded correctly. 23234 23235 // Case 1: a chunk contains only bytes for a split character (and no other 23236 // data). This kind of a chunk would be exceptionally small, but we should 23237 // still decode it correctly. 23238 const char* reference = "\xeb\x91\x80"; 23239 // The small chunk is at the beginning of the split character 23240 { 23241 char chunk1[] = 23242 "function foo() {\n" 23243 " // This function will contain an UTF-8 character which is not in\n" 23244 " // ASCII.\n" 23245 " var foob"; 23246 char chunk2[] = "XX"; 23247 char chunk3[] = 23248 "Xr = 13;\n" 23249 " return foob\xeb\x91\x80r;\n" 23250 "}\n"; 23251 chunk2[0] = reference[0]; 23252 chunk2[1] = reference[1]; 23253 chunk3[0] = reference[2]; 23254 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23255 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23256 } 23257 // The small chunk is at the end of a character 23258 { 23259 char chunk1[] = 23260 "function foo() {\n" 23261 " // This function will contain an UTF-8 character which is not in\n" 23262 " // ASCII.\n" 23263 " var foobX"; 23264 char chunk2[] = "XX"; 23265 char chunk3[] = 23266 "r = 13;\n" 23267 " return foob\xeb\x91\x80r;\n" 23268 "}\n"; 23269 chunk1[strlen(chunk1) - 1] = reference[0]; 23270 chunk2[0] = reference[1]; 23271 chunk2[1] = reference[2]; 23272 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23273 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23274 } 23275 // Case 2: the script ends with a multi-byte character. Make sure that it's 23276 // decoded correctly and not just ignored. 23277 { 23278 char chunk1[] = 23279 "var foob\xeb\x91\x80 = 13;\n" 23280 "foob\xeb\x91\x80"; 23281 const char* chunks[] = {chunk1, NULL}; 23282 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); 23283 } 23284 } 23285 23286 23287 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { 23288 // Test cases where a UTF-8 character is split over several chunks. Those 23289 // cases are not supported (the embedder should give the data in big enough 23290 // chunks), but we shouldn't crash, just produce a parse error. 23291 const char* reference = "\xeb\x91\x80"; 23292 char chunk1[] = 23293 "function foo() {\n" 23294 " // This function will contain an UTF-8 character which is not in\n" 23295 " // ASCII.\n" 23296 " var foobX"; 23297 char chunk2[] = "X"; 23298 char chunk3[] = 23299 "Xr = 13;\n" 23300 " return foob\xeb\x91\x80r;\n" 23301 "}\n"; 23302 chunk1[strlen(chunk1) - 1] = reference[0]; 23303 chunk2[0] = reference[1]; 23304 chunk3[0] = reference[2]; 23305 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; 23306 23307 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 23308 } 23309 23310 23311 TEST(StreamingProducesParserCache) { 23312 i::FLAG_min_preparse_length = 0; 23313 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", 23314 NULL}; 23315 23316 LocalContext env; 23317 v8::Isolate* isolate = env->GetIsolate(); 23318 v8::HandleScope scope(isolate); 23319 23320 v8::ScriptCompiler::StreamedSource source( 23321 new TestSourceStream(chunks), 23322 v8::ScriptCompiler::StreamedSource::ONE_BYTE); 23323 v8::ScriptCompiler::ScriptStreamingTask* task = 23324 v8::ScriptCompiler::StartStreamingScript( 23325 isolate, &source, v8::ScriptCompiler::kProduceParserCache); 23326 23327 // TestSourceStream::GetMoreData won't block, so it's OK to just run the 23328 // task here in the main thread. 23329 task->Run(); 23330 delete task; 23331 23332 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData(); 23333 CHECK(cached_data != NULL); 23334 CHECK(cached_data->data != NULL); 23335 CHECK_GT(cached_data->length, 0); 23336 } 23337 23338 23339 TEST(StreamingScriptWithInvalidUtf8) { 23340 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a 23341 // chunk don't produce a crash. 23342 const char* reference = "\xeb\x91\x80\x80\x80"; 23343 char chunk1[] = 23344 "function foo() {\n" 23345 " // This function will contain an UTF-8 character which is not in\n" 23346 " // ASCII.\n" 23347 " var foobXXXXX"; // Too many bytes which look like incomplete chars! 23348 char chunk2[] = 23349 "r = 13;\n" 23350 " return foob\xeb\x91\x80\x80\x80r;\n" 23351 "}\n"; 23352 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i]; 23353 23354 const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; 23355 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); 23356 } 23357