1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <climits> 29 #include <csignal> 30 #include <string> 31 #include <map> 32 33 #include "v8.h" 34 35 #if V8_OS_POSIX 36 #include <unistd.h> // NOLINT 37 #endif 38 39 #include "api.h" 40 #include "arguments.h" 41 #include "cctest.h" 42 #include "compilation-cache.h" 43 #include "cpu-profiler.h" 44 #include "execution.h" 45 #include "isolate.h" 46 #include "objects.h" 47 #include "parser.h" 48 #include "platform.h" 49 #include "snapshot.h" 50 #include "unicode-inl.h" 51 #include "utils.h" 52 #include "vm-state.h" 53 54 static const bool kLogThreading = false; 55 56 using ::v8::Boolean; 57 using ::v8::BooleanObject; 58 using ::v8::Context; 59 using ::v8::Extension; 60 using ::v8::Function; 61 using ::v8::FunctionTemplate; 62 using ::v8::Handle; 63 using ::v8::HandleScope; 64 using ::v8::Local; 65 using ::v8::Message; 66 using ::v8::MessageCallback; 67 using ::v8::Object; 68 using ::v8::ObjectTemplate; 69 using ::v8::Persistent; 70 using ::v8::Script; 71 using ::v8::StackTrace; 72 using ::v8::String; 73 using ::v8::TryCatch; 74 using ::v8::Undefined; 75 using ::v8::UniqueId; 76 using ::v8::V8; 77 using ::v8::Value; 78 79 80 #define THREADED_PROFILED_TEST(Name) \ 81 static void Test##Name(); \ 82 TEST(Name##WithProfiler) { \ 83 RunWithProfiler(&Test##Name); \ 84 } \ 85 THREADED_TEST(Name) 86 87 88 void RunWithProfiler(void (*test)()) { 89 LocalContext env; 90 v8::HandleScope scope(env->GetIsolate()); 91 v8::Local<v8::String> profile_name = 92 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1"); 93 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 94 95 cpu_profiler->StartCpuProfiling(profile_name); 96 (*test)(); 97 cpu_profiler->DeleteAllCpuProfiles(); 98 } 99 100 101 static void ExpectString(const char* code, const char* expected) { 102 Local<Value> result = CompileRun(code); 103 CHECK(result->IsString()); 104 String::Utf8Value utf8(result); 105 CHECK_EQ(expected, *utf8); 106 } 107 108 109 static void ExpectInt32(const char* code, int expected) { 110 Local<Value> result = CompileRun(code); 111 CHECK(result->IsInt32()); 112 CHECK_EQ(expected, result->Int32Value()); 113 } 114 115 116 static void ExpectBoolean(const char* code, bool expected) { 117 Local<Value> result = CompileRun(code); 118 CHECK(result->IsBoolean()); 119 CHECK_EQ(expected, result->BooleanValue()); 120 } 121 122 123 static void ExpectTrue(const char* code) { 124 ExpectBoolean(code, true); 125 } 126 127 128 static void ExpectFalse(const char* code) { 129 ExpectBoolean(code, false); 130 } 131 132 133 static void ExpectObject(const char* code, Local<Value> expected) { 134 Local<Value> result = CompileRun(code); 135 CHECK(result->Equals(expected)); 136 } 137 138 139 static void ExpectUndefined(const char* code) { 140 Local<Value> result = CompileRun(code); 141 CHECK(result->IsUndefined()); 142 } 143 144 145 static int signature_callback_count; 146 static Local<Value> signature_expected_receiver; 147 static void IncrementingSignatureCallback( 148 const v8::FunctionCallbackInfo<v8::Value>& args) { 149 ApiTestFuzzer::Fuzz(); 150 signature_callback_count++; 151 CHECK_EQ(signature_expected_receiver, args.Holder()); 152 CHECK_EQ(signature_expected_receiver, args.This()); 153 v8::Handle<v8::Array> result = 154 v8::Array::New(args.GetIsolate(), args.Length()); 155 for (int i = 0; i < args.Length(); i++) 156 result->Set(v8::Integer::New(i), args[i]); 157 args.GetReturnValue().Set(result); 158 } 159 160 161 static void SignatureCallback( 162 const v8::FunctionCallbackInfo<v8::Value>& args) { 163 ApiTestFuzzer::Fuzz(); 164 v8::Handle<v8::Array> result = 165 v8::Array::New(args.GetIsolate(), args.Length()); 166 for (int i = 0; i < args.Length(); i++) { 167 result->Set(v8::Integer::New(i), args[i]); 168 } 169 args.GetReturnValue().Set(result); 170 } 171 172 173 // Tests that call v8::V8::Dispose() cannot be threaded. 174 TEST(InitializeAndDisposeOnce) { 175 CHECK(v8::V8::Initialize()); 176 CHECK(v8::V8::Dispose()); 177 } 178 179 180 // Tests that call v8::V8::Dispose() cannot be threaded. 181 TEST(InitializeAndDisposeMultiple) { 182 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 183 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 184 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 185 // TODO(mstarzinger): This should fail gracefully instead of asserting. 186 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize()); 187 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose()); 188 } 189 190 191 THREADED_TEST(Handles) { 192 v8::HandleScope scope(CcTest::isolate()); 193 Local<Context> local_env; 194 { 195 LocalContext env; 196 local_env = env.local(); 197 } 198 199 // Local context should still be live. 200 CHECK(!local_env.IsEmpty()); 201 local_env->Enter(); 202 203 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate()); 204 CHECK(!undef.IsEmpty()); 205 CHECK(undef->IsUndefined()); 206 207 const char* c_source = "1 + 2 + 3"; 208 Local<String> source = String::NewFromUtf8(CcTest::isolate(), c_source); 209 Local<Script> script = Script::Compile(source); 210 CHECK_EQ(6, script->Run()->Int32Value()); 211 212 local_env->Exit(); 213 } 214 215 216 THREADED_TEST(IsolateOfContext) { 217 v8::HandleScope scope(CcTest::isolate()); 218 v8::Handle<Context> env = Context::New(CcTest::isolate()); 219 220 CHECK(!env->GetIsolate()->InContext()); 221 CHECK(env->GetIsolate() == CcTest::isolate()); 222 env->Enter(); 223 CHECK(env->GetIsolate()->InContext()); 224 CHECK(env->GetIsolate() == CcTest::isolate()); 225 env->Exit(); 226 CHECK(!env->GetIsolate()->InContext()); 227 CHECK(env->GetIsolate() == CcTest::isolate()); 228 } 229 230 231 static void TestSignature(const char* loop_js, Local<Value> receiver) { 232 i::ScopedVector<char> source(200); 233 i::OS::SNPrintF(source, 234 "for (var i = 0; i < 10; i++) {" 235 " %s" 236 "}", 237 loop_js); 238 signature_callback_count = 0; 239 signature_expected_receiver = receiver; 240 bool expected_to_throw = receiver.IsEmpty(); 241 v8::TryCatch try_catch; 242 CompileRun(source.start()); 243 CHECK_EQ(expected_to_throw, try_catch.HasCaught()); 244 if (!expected_to_throw) { 245 CHECK_EQ(10, signature_callback_count); 246 } else { 247 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 248 try_catch.Exception()->ToString()); 249 } 250 } 251 252 253 THREADED_TEST(ReceiverSignature) { 254 LocalContext env; 255 v8::HandleScope scope(env->GetIsolate()); 256 // Setup templates. 257 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 258 v8::Handle<v8::Signature> sig = v8::Signature::New(env->GetIsolate(), fun); 259 v8::Handle<v8::FunctionTemplate> callback_sig = 260 v8::FunctionTemplate::New( 261 IncrementingSignatureCallback, Local<Value>(), sig); 262 v8::Handle<v8::FunctionTemplate> callback = 263 v8::FunctionTemplate::New(IncrementingSignatureCallback); 264 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(); 265 sub_fun->Inherit(fun); 266 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New(); 267 // Install properties. 268 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate(); 269 fun_proto->Set(v8_str("prop_sig"), callback_sig); 270 fun_proto->Set(v8_str("prop"), callback); 271 fun_proto->SetAccessorProperty( 272 v8_str("accessor_sig"), callback_sig, callback_sig); 273 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback); 274 // Instantiate templates. 275 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance(); 276 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance(); 277 // Setup global variables. 278 env->Global()->Set(v8_str("Fun"), fun->GetFunction()); 279 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); 280 env->Global()->Set(v8_str("fun_instance"), fun_instance); 281 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance); 282 CompileRun( 283 "var accessor_sig_key = 'accessor_sig';" 284 "var accessor_key = 'accessor';" 285 "var prop_sig_key = 'prop_sig';" 286 "var prop_key = 'prop';" 287 "" 288 "function copy_props(obj) {" 289 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];" 290 " var source = Fun.prototype;" 291 " for (var i in keys) {" 292 " var key = keys[i];" 293 " var desc = Object.getOwnPropertyDescriptor(source, key);" 294 " Object.defineProperty(obj, key, desc);" 295 " }" 296 "}" 297 "" 298 "var obj = {};" 299 "copy_props(obj);" 300 "var unrel = new UnrelFun();" 301 "copy_props(unrel);"); 302 // Test with and without ICs 303 const char* test_objects[] = { 304 "fun_instance", "sub_fun_instance", "obj", "unrel" }; 305 unsigned bad_signature_start_offset = 2; 306 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) { 307 i::ScopedVector<char> source(200); 308 i::OS::SNPrintF( 309 source, "var test_object = %s; test_object", test_objects[i]); 310 Local<Value> test_object = CompileRun(source.start()); 311 TestSignature("test_object.prop();", test_object); 312 TestSignature("test_object.accessor;", test_object); 313 TestSignature("test_object[accessor_key];", test_object); 314 TestSignature("test_object.accessor = 1;", test_object); 315 TestSignature("test_object[accessor_key] = 1;", test_object); 316 if (i >= bad_signature_start_offset) test_object = Local<Value>(); 317 TestSignature("test_object.prop_sig();", test_object); 318 TestSignature("test_object.accessor_sig;", test_object); 319 TestSignature("test_object[accessor_sig_key];", test_object); 320 TestSignature("test_object.accessor_sig = 1;", test_object); 321 TestSignature("test_object[accessor_sig_key] = 1;", test_object); 322 } 323 } 324 325 326 THREADED_TEST(ArgumentSignature) { 327 LocalContext env; 328 v8::HandleScope scope(env->GetIsolate()); 329 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(); 330 cons->SetClassName(v8_str("Cons")); 331 v8::Handle<v8::Signature> sig = v8::Signature::New( 332 env->GetIsolate(), v8::Handle<v8::FunctionTemplate>(), 1, &cons); 333 v8::Handle<v8::FunctionTemplate> fun = 334 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig); 335 env->Global()->Set(v8_str("Cons"), cons->GetFunction()); 336 env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); 337 338 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); 339 CHECK(value1->IsTrue()); 340 341 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); 342 CHECK(value2->IsTrue()); 343 344 v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); 345 CHECK(value3->IsTrue()); 346 347 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(); 348 cons1->SetClassName(v8_str("Cons1")); 349 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(); 350 cons2->SetClassName(v8_str("Cons2")); 351 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(); 352 cons3->SetClassName(v8_str("Cons3")); 353 354 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; 355 v8::Handle<v8::Signature> wsig = v8::Signature::New( 356 env->GetIsolate(), v8::Handle<v8::FunctionTemplate>(), 3, args); 357 v8::Handle<v8::FunctionTemplate> fun2 = 358 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig); 359 360 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); 361 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); 362 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); 363 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); 364 v8::Handle<Value> value4 = CompileRun( 365 "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" 366 "'[object Cons1],[object Cons2],[object Cons3]'"); 367 CHECK(value4->IsTrue()); 368 369 v8::Handle<Value> value5 = CompileRun( 370 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); 371 CHECK(value5->IsTrue()); 372 373 v8::Handle<Value> value6 = CompileRun( 374 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); 375 CHECK(value6->IsTrue()); 376 377 v8::Handle<Value> value7 = CompileRun( 378 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " 379 "'[object Cons1],[object Cons2],[object Cons3],d';"); 380 CHECK(value7->IsTrue()); 381 382 v8::Handle<Value> value8 = CompileRun( 383 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); 384 CHECK(value8->IsTrue()); 385 } 386 387 388 THREADED_TEST(HulIgennem) { 389 LocalContext env; 390 v8::Isolate* isolate = env->GetIsolate(); 391 v8::HandleScope scope(isolate); 392 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate); 393 Local<String> undef_str = undef->ToString(); 394 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 395 undef_str->WriteUtf8(value); 396 CHECK_EQ(0, strcmp(value, "undefined")); 397 i::DeleteArray(value); 398 } 399 400 401 THREADED_TEST(Access) { 402 LocalContext env; 403 v8::Isolate* isolate = env->GetIsolate(); 404 v8::HandleScope scope(isolate); 405 Local<v8::Object> obj = v8::Object::New(); 406 Local<Value> foo_before = obj->Get(v8_str("foo")); 407 CHECK(foo_before->IsUndefined()); 408 Local<String> bar_str = v8_str("bar"); 409 obj->Set(v8_str("foo"), bar_str); 410 Local<Value> foo_after = obj->Get(v8_str("foo")); 411 CHECK(!foo_after->IsUndefined()); 412 CHECK(foo_after->IsString()); 413 CHECK_EQ(bar_str, foo_after); 414 } 415 416 417 THREADED_TEST(AccessElement) { 418 LocalContext env; 419 v8::HandleScope scope(env->GetIsolate()); 420 Local<v8::Object> obj = v8::Object::New(); 421 Local<Value> before = obj->Get(1); 422 CHECK(before->IsUndefined()); 423 Local<String> bar_str = v8_str("bar"); 424 obj->Set(1, bar_str); 425 Local<Value> after = obj->Get(1); 426 CHECK(!after->IsUndefined()); 427 CHECK(after->IsString()); 428 CHECK_EQ(bar_str, after); 429 430 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 431 CHECK_EQ(v8_str("a"), value->Get(0)); 432 CHECK_EQ(v8_str("b"), value->Get(1)); 433 } 434 435 436 THREADED_TEST(Script) { 437 LocalContext env; 438 v8::HandleScope scope(env->GetIsolate()); 439 const char* c_source = "1 + 2 + 3"; 440 Local<String> source = String::NewFromUtf8(env->GetIsolate(), c_source); 441 Local<Script> script = Script::Compile(source); 442 CHECK_EQ(6, script->Run()->Int32Value()); 443 } 444 445 446 static uint16_t* AsciiToTwoByteString(const char* source) { 447 int array_length = i::StrLength(source) + 1; 448 uint16_t* converted = i::NewArray<uint16_t>(array_length); 449 for (int i = 0; i < array_length; i++) converted[i] = source[i]; 450 return converted; 451 } 452 453 454 class TestResource: public String::ExternalStringResource { 455 public: 456 explicit TestResource(uint16_t* data, int* counter = NULL) 457 : data_(data), length_(0), counter_(counter) { 458 while (data[length_]) ++length_; 459 } 460 461 ~TestResource() { 462 i::DeleteArray(data_); 463 if (counter_ != NULL) ++*counter_; 464 } 465 466 const uint16_t* data() const { 467 return data_; 468 } 469 470 size_t length() const { 471 return length_; 472 } 473 private: 474 uint16_t* data_; 475 size_t length_; 476 int* counter_; 477 }; 478 479 480 class TestAsciiResource: public String::ExternalAsciiStringResource { 481 public: 482 explicit TestAsciiResource(const char* data, int* counter = NULL) 483 : data_(data), length_(strlen(data)), counter_(counter) { } 484 485 ~TestAsciiResource() { 486 i::DeleteArray(data_); 487 if (counter_ != NULL) ++*counter_; 488 } 489 490 const char* data() const { 491 return data_; 492 } 493 494 size_t length() const { 495 return length_; 496 } 497 private: 498 const char* data_; 499 size_t length_; 500 int* counter_; 501 }; 502 503 504 THREADED_TEST(ScriptUsingStringResource) { 505 int dispose_count = 0; 506 const char* c_source = "1 + 2 * 3"; 507 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 508 { 509 LocalContext env; 510 v8::HandleScope scope(env->GetIsolate()); 511 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 512 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 513 Local<Script> script = Script::Compile(source); 514 Local<Value> value = script->Run(); 515 CHECK(value->IsNumber()); 516 CHECK_EQ(7, value->Int32Value()); 517 CHECK(source->IsExternal()); 518 CHECK_EQ(resource, 519 static_cast<TestResource*>(source->GetExternalStringResource())); 520 String::Encoding encoding = String::UNKNOWN_ENCODING; 521 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 522 source->GetExternalStringResourceBase(&encoding)); 523 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 524 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 525 CHECK_EQ(0, dispose_count); 526 } 527 CcTest::i_isolate()->compilation_cache()->Clear(); 528 CcTest::heap()->CollectAllAvailableGarbage(); 529 CHECK_EQ(1, dispose_count); 530 } 531 532 533 THREADED_TEST(ScriptUsingAsciiStringResource) { 534 int dispose_count = 0; 535 const char* c_source = "1 + 2 * 3"; 536 { 537 LocalContext env; 538 v8::HandleScope scope(env->GetIsolate()); 539 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source), 540 &dispose_count); 541 Local<String> source = String::NewExternal(env->GetIsolate(), resource); 542 CHECK(source->IsExternalAscii()); 543 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 544 source->GetExternalAsciiStringResource()); 545 String::Encoding encoding = String::UNKNOWN_ENCODING; 546 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 547 source->GetExternalStringResourceBase(&encoding)); 548 CHECK_EQ(String::ASCII_ENCODING, encoding); 549 Local<Script> script = Script::Compile(source); 550 Local<Value> value = script->Run(); 551 CHECK(value->IsNumber()); 552 CHECK_EQ(7, value->Int32Value()); 553 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 554 CHECK_EQ(0, dispose_count); 555 } 556 CcTest::i_isolate()->compilation_cache()->Clear(); 557 CcTest::heap()->CollectAllAvailableGarbage(); 558 CHECK_EQ(1, dispose_count); 559 } 560 561 562 THREADED_TEST(ScriptMakingExternalString) { 563 int dispose_count = 0; 564 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 565 { 566 LocalContext env; 567 v8::HandleScope scope(env->GetIsolate()); 568 Local<String> source = 569 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 570 // Trigger GCs so that the newly allocated string moves to old gen. 571 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 572 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 573 CHECK_EQ(source->IsExternal(), false); 574 CHECK_EQ(source->IsExternalAscii(), false); 575 String::Encoding encoding = String::UNKNOWN_ENCODING; 576 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); 577 CHECK_EQ(String::ASCII_ENCODING, encoding); 578 bool success = source->MakeExternal(new TestResource(two_byte_source, 579 &dispose_count)); 580 CHECK(success); 581 Local<Script> script = Script::Compile(source); 582 Local<Value> value = script->Run(); 583 CHECK(value->IsNumber()); 584 CHECK_EQ(7, value->Int32Value()); 585 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 586 CHECK_EQ(0, dispose_count); 587 } 588 CcTest::i_isolate()->compilation_cache()->Clear(); 589 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 590 CHECK_EQ(1, dispose_count); 591 } 592 593 594 THREADED_TEST(ScriptMakingExternalAsciiString) { 595 int dispose_count = 0; 596 const char* c_source = "1 + 2 * 3"; 597 { 598 LocalContext env; 599 v8::HandleScope scope(env->GetIsolate()); 600 Local<String> source = v8_str(c_source); 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 bool success = source->MakeExternal( 605 new TestAsciiResource(i::StrDup(c_source), &dispose_count)); 606 CHECK(success); 607 Local<Script> script = Script::Compile(source); 608 Local<Value> value = script->Run(); 609 CHECK(value->IsNumber()); 610 CHECK_EQ(7, value->Int32Value()); 611 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 612 CHECK_EQ(0, dispose_count); 613 } 614 CcTest::i_isolate()->compilation_cache()->Clear(); 615 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 616 CHECK_EQ(1, dispose_count); 617 } 618 619 620 TEST(MakingExternalStringConditions) { 621 LocalContext env; 622 v8::HandleScope scope(env->GetIsolate()); 623 624 // Free some space in the new space so that we can check freshness. 625 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 626 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 627 628 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 629 Local<String> small_string = 630 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 631 i::DeleteArray(two_byte_string); 632 633 // We should refuse to externalize newly created small string. 634 CHECK(!small_string->CanMakeExternal()); 635 // Trigger GCs so that the newly allocated string moves to old gen. 636 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 637 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 638 // Old space strings should be accepted. 639 CHECK(small_string->CanMakeExternal()); 640 641 two_byte_string = AsciiToTwoByteString("small string 2"); 642 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 643 i::DeleteArray(two_byte_string); 644 645 // We should refuse externalizing newly created small string. 646 CHECK(!small_string->CanMakeExternal()); 647 for (int i = 0; i < 100; i++) { 648 String::Value value(small_string); 649 } 650 // Frequently used strings should be accepted. 651 CHECK(small_string->CanMakeExternal()); 652 653 const int buf_size = 10 * 1024; 654 char* buf = i::NewArray<char>(buf_size); 655 memset(buf, 'a', buf_size); 656 buf[buf_size - 1] = '\0'; 657 658 two_byte_string = AsciiToTwoByteString(buf); 659 Local<String> large_string = 660 String::NewFromTwoByte(env->GetIsolate(), two_byte_string); 661 i::DeleteArray(buf); 662 i::DeleteArray(two_byte_string); 663 // Large strings should be immediately accepted. 664 CHECK(large_string->CanMakeExternal()); 665 } 666 667 668 TEST(MakingExternalAsciiStringConditions) { 669 LocalContext env; 670 v8::HandleScope scope(env->GetIsolate()); 671 672 // Free some space in the new space so that we can check freshness. 673 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 674 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 675 676 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1"); 677 // We should refuse to externalize newly created small string. 678 CHECK(!small_string->CanMakeExternal()); 679 // Trigger GCs so that the newly allocated string moves to old gen. 680 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 681 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 682 // Old space strings should be accepted. 683 CHECK(small_string->CanMakeExternal()); 684 685 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2"); 686 // We should refuse externalizing newly created small string. 687 CHECK(!small_string->CanMakeExternal()); 688 for (int i = 0; i < 100; i++) { 689 String::Value value(small_string); 690 } 691 // Frequently used strings should be accepted. 692 CHECK(small_string->CanMakeExternal()); 693 694 const int buf_size = 10 * 1024; 695 char* buf = i::NewArray<char>(buf_size); 696 memset(buf, 'a', buf_size); 697 buf[buf_size - 1] = '\0'; 698 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf); 699 i::DeleteArray(buf); 700 // Large strings should be immediately accepted. 701 CHECK(large_string->CanMakeExternal()); 702 } 703 704 705 TEST(MakingExternalUnalignedAsciiString) { 706 LocalContext env; 707 v8::HandleScope scope(env->GetIsolate()); 708 709 CompileRun("function cons(a, b) { return a + b; }" 710 "function slice(a) { return a.substring(1); }"); 711 // Create a cons string that will land in old pointer space. 712 Local<String> cons = Local<String>::Cast(CompileRun( 713 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 714 // Create a sliced string that will land in old pointer space. 715 Local<String> slice = Local<String>::Cast(CompileRun( 716 "slice('abcdefghijklmnopqrstuvwxyz');")); 717 718 // Trigger GCs so that the newly allocated string moves to old gen. 719 SimulateFullSpace(CcTest::heap()->old_pointer_space()); 720 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 721 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 722 723 // Turn into external string with unaligned resource data. 724 int dispose_count = 0; 725 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 726 bool success = cons->MakeExternal( 727 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count)); 728 CHECK(success); 729 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 730 success = slice->MakeExternal( 731 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count)); 732 CHECK(success); 733 734 // Trigger GCs and force evacuation. 735 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 736 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 737 } 738 739 740 THREADED_TEST(UsingExternalString) { 741 i::Factory* factory = CcTest::i_isolate()->factory(); 742 { 743 v8::HandleScope scope(CcTest::isolate()); 744 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 745 Local<String> string = String::NewExternal( 746 CcTest::isolate(), new TestResource(two_byte_string)); 747 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 748 // Trigger GCs so that the newly allocated string moves to old gen. 749 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 750 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 751 i::Handle<i::String> isymbol = 752 factory->InternalizedStringFromString(istring); 753 CHECK(isymbol->IsInternalizedString()); 754 } 755 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 756 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 757 } 758 759 760 THREADED_TEST(UsingExternalAsciiString) { 761 i::Factory* factory = CcTest::i_isolate()->factory(); 762 { 763 v8::HandleScope scope(CcTest::isolate()); 764 const char* one_byte_string = "test string"; 765 Local<String> string = String::NewExternal( 766 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string))); 767 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 768 // Trigger GCs so that the newly allocated string moves to old gen. 769 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 770 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 771 i::Handle<i::String> isymbol = 772 factory->InternalizedStringFromString(istring); 773 CHECK(isymbol->IsInternalizedString()); 774 } 775 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 776 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 777 } 778 779 780 THREADED_TEST(ScavengeExternalString) { 781 i::FLAG_stress_compaction = false; 782 i::FLAG_gc_global = false; 783 int dispose_count = 0; 784 bool in_new_space = false; 785 { 786 v8::HandleScope scope(CcTest::isolate()); 787 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 788 Local<String> string = String::NewExternal( 789 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count)); 790 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 791 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 792 in_new_space = CcTest::heap()->InNewSpace(*istring); 793 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 794 CHECK_EQ(0, dispose_count); 795 } 796 CcTest::heap()->CollectGarbage( 797 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 798 CHECK_EQ(1, dispose_count); 799 } 800 801 802 THREADED_TEST(ScavengeExternalAsciiString) { 803 i::FLAG_stress_compaction = false; 804 i::FLAG_gc_global = false; 805 int dispose_count = 0; 806 bool in_new_space = false; 807 { 808 v8::HandleScope scope(CcTest::isolate()); 809 const char* one_byte_string = "test string"; 810 Local<String> string = String::NewExternal( 811 CcTest::isolate(), 812 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count)); 813 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 814 CcTest::heap()->CollectGarbage(i::NEW_SPACE); 815 in_new_space = CcTest::heap()->InNewSpace(*istring); 816 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); 817 CHECK_EQ(0, dispose_count); 818 } 819 CcTest::heap()->CollectGarbage( 820 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 821 CHECK_EQ(1, dispose_count); 822 } 823 824 825 class TestAsciiResourceWithDisposeControl: public TestAsciiResource { 826 public: 827 // Only used by non-threaded tests, so it can use static fields. 828 static int dispose_calls; 829 static int dispose_count; 830 831 TestAsciiResourceWithDisposeControl(const char* data, bool dispose) 832 : TestAsciiResource(data, &dispose_count), 833 dispose_(dispose) { } 834 835 void Dispose() { 836 ++dispose_calls; 837 if (dispose_) delete this; 838 } 839 private: 840 bool dispose_; 841 }; 842 843 844 int TestAsciiResourceWithDisposeControl::dispose_count = 0; 845 int TestAsciiResourceWithDisposeControl::dispose_calls = 0; 846 847 848 TEST(ExternalStringWithDisposeHandling) { 849 const char* c_source = "1 + 2 * 3"; 850 851 // Use a stack allocated external string resource allocated object. 852 TestAsciiResourceWithDisposeControl::dispose_count = 0; 853 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 854 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 855 { 856 LocalContext env; 857 v8::HandleScope scope(env->GetIsolate()); 858 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack); 859 Local<Script> script = Script::Compile(source); 860 Local<Value> value = script->Run(); 861 CHECK(value->IsNumber()); 862 CHECK_EQ(7, value->Int32Value()); 863 CcTest::heap()->CollectAllAvailableGarbage(); 864 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 865 } 866 CcTest::i_isolate()->compilation_cache()->Clear(); 867 CcTest::heap()->CollectAllAvailableGarbage(); 868 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 869 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 870 871 // Use a heap allocated external string resource allocated object. 872 TestAsciiResourceWithDisposeControl::dispose_count = 0; 873 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 874 TestAsciiResource* res_heap = 875 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true); 876 { 877 LocalContext env; 878 v8::HandleScope scope(env->GetIsolate()); 879 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap); 880 Local<Script> script = Script::Compile(source); 881 Local<Value> value = script->Run(); 882 CHECK(value->IsNumber()); 883 CHECK_EQ(7, value->Int32Value()); 884 CcTest::heap()->CollectAllAvailableGarbage(); 885 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 886 } 887 CcTest::i_isolate()->compilation_cache()->Clear(); 888 CcTest::heap()->CollectAllAvailableGarbage(); 889 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 890 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count); 891 } 892 893 894 THREADED_TEST(StringConcat) { 895 { 896 LocalContext env; 897 v8::HandleScope scope(env->GetIsolate()); 898 const char* one_byte_string_1 = "function a_times_t"; 899 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 900 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 901 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 902 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 903 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 904 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 905 Local<String> left = v8_str(one_byte_string_1); 906 907 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 908 Local<String> right = 909 String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 910 i::DeleteArray(two_byte_source); 911 912 Local<String> source = String::Concat(left, right); 913 right = String::NewExternal( 914 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1))); 915 source = String::Concat(source, right); 916 right = String::NewExternal( 917 env->GetIsolate(), 918 new TestResource(AsciiToTwoByteString(two_byte_extern_1))); 919 source = String::Concat(source, right); 920 right = v8_str(one_byte_string_2); 921 source = String::Concat(source, right); 922 923 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 924 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source); 925 i::DeleteArray(two_byte_source); 926 927 source = String::Concat(source, right); 928 right = String::NewExternal( 929 env->GetIsolate(), 930 new TestResource(AsciiToTwoByteString(two_byte_extern_2))); 931 source = String::Concat(source, right); 932 Local<Script> script = Script::Compile(source); 933 Local<Value> value = script->Run(); 934 CHECK(value->IsNumber()); 935 CHECK_EQ(68, value->Int32Value()); 936 } 937 CcTest::i_isolate()->compilation_cache()->Clear(); 938 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 939 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 940 } 941 942 943 THREADED_TEST(GlobalProperties) { 944 LocalContext env; 945 v8::HandleScope scope(env->GetIsolate()); 946 v8::Handle<v8::Object> global = env->Global(); 947 global->Set(v8_str("pi"), v8_num(3.1415926)); 948 Local<Value> pi = global->Get(v8_str("pi")); 949 CHECK_EQ(3.1415926, pi->NumberValue()); 950 } 951 952 953 template<typename T> 954 static void CheckReturnValue(const T& t, i::Address callback) { 955 v8::ReturnValue<v8::Value> rv = t.GetReturnValue(); 956 i::Object** o = *reinterpret_cast<i::Object***>(&rv); 957 CHECK_EQ(CcTest::isolate(), t.GetIsolate()); 958 CHECK_EQ(t.GetIsolate(), rv.GetIsolate()); 959 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 960 // Verify reset 961 bool is_runtime = (*o)->IsTheHole(); 962 rv.Set(true); 963 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined()); 964 rv.Set(v8::Handle<v8::Object>()); 965 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 966 CHECK_EQ(is_runtime, (*o)->IsTheHole()); 967 968 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate()); 969 // If CPU profiler is active check that when API callback is invoked 970 // VMState is set to EXTERNAL. 971 if (isolate->cpu_profiler()->is_profiling()) { 972 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state()); 973 CHECK(isolate->external_callback_scope()); 974 CHECK_EQ(callback, isolate->external_callback_scope()->callback()); 975 } 976 } 977 978 979 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 980 i::Address callback) { 981 ApiTestFuzzer::Fuzz(); 982 CheckReturnValue(info, callback); 983 info.GetReturnValue().Set(v8_str("bad value")); 984 info.GetReturnValue().Set(v8_num(102)); 985 } 986 987 988 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 989 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 990 } 991 992 993 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 994 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 995 } 996 997 static void construct_callback( 998 const v8::FunctionCallbackInfo<Value>& info) { 999 ApiTestFuzzer::Fuzz(); 1000 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 1001 info.This()->Set(v8_str("x"), v8_num(1)); 1002 info.This()->Set(v8_str("y"), v8_num(2)); 1003 info.GetReturnValue().Set(v8_str("bad value")); 1004 info.GetReturnValue().Set(info.This()); 1005 } 1006 1007 1008 static void Return239Callback( 1009 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 1010 ApiTestFuzzer::Fuzz(); 1011 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 1012 info.GetReturnValue().Set(v8_str("bad value")); 1013 info.GetReturnValue().Set(v8_num(239)); 1014 } 1015 1016 1017 template<typename Handler> 1018 static void TestFunctionTemplateInitializer(Handler handler, 1019 Handler handler_2) { 1020 // Test constructor calls. 1021 { 1022 LocalContext env; 1023 v8::HandleScope scope(env->GetIsolate()); 1024 1025 Local<v8::FunctionTemplate> fun_templ = 1026 v8::FunctionTemplate::New(handler); 1027 Local<Function> fun = fun_templ->GetFunction(); 1028 env->Global()->Set(v8_str("obj"), fun); 1029 Local<Script> script = v8_compile("obj()"); 1030 for (int i = 0; i < 30; i++) { 1031 CHECK_EQ(102, script->Run()->Int32Value()); 1032 } 1033 } 1034 // Use SetCallHandler to initialize a function template, should work like 1035 // the previous one. 1036 { 1037 LocalContext env; 1038 v8::HandleScope scope(env->GetIsolate()); 1039 1040 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 1041 fun_templ->SetCallHandler(handler_2); 1042 Local<Function> fun = fun_templ->GetFunction(); 1043 env->Global()->Set(v8_str("obj"), fun); 1044 Local<Script> script = v8_compile("obj()"); 1045 for (int i = 0; i < 30; i++) { 1046 CHECK_EQ(102, script->Run()->Int32Value()); 1047 } 1048 } 1049 } 1050 1051 1052 template<typename Constructor, typename Accessor> 1053 static void TestFunctionTemplateAccessor(Constructor constructor, 1054 Accessor accessor) { 1055 LocalContext env; 1056 v8::HandleScope scope(env->GetIsolate()); 1057 1058 Local<v8::FunctionTemplate> fun_templ = 1059 v8::FunctionTemplate::New(constructor); 1060 fun_templ->SetClassName(v8_str("funky")); 1061 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 1062 Local<Function> fun = fun_templ->GetFunction(); 1063 env->Global()->Set(v8_str("obj"), fun); 1064 Local<Value> result = v8_compile("(new obj()).toString()")->Run(); 1065 CHECK_EQ(v8_str("[object funky]"), result); 1066 CompileRun("var obj_instance = new obj();"); 1067 Local<Script> script; 1068 script = v8_compile("obj_instance.x"); 1069 for (int i = 0; i < 30; i++) { 1070 CHECK_EQ(1, script->Run()->Int32Value()); 1071 } 1072 script = v8_compile("obj_instance.m"); 1073 for (int i = 0; i < 30; i++) { 1074 CHECK_EQ(239, script->Run()->Int32Value()); 1075 } 1076 } 1077 1078 1079 THREADED_PROFILED_TEST(FunctionTemplate) { 1080 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 1081 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 1082 } 1083 1084 1085 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1086 ApiTestFuzzer::Fuzz(); 1087 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1088 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1089 } 1090 1091 1092 template<typename Callback> 1093 static void TestSimpleCallback(Callback callback) { 1094 LocalContext env; 1095 v8::HandleScope scope(env->GetIsolate()); 1096 1097 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 1098 object_template->Set(env->GetIsolate(), "callback", 1099 v8::FunctionTemplate::New(callback)); 1100 v8::Local<v8::Object> object = object_template->NewInstance(); 1101 (*env)->Global()->Set(v8_str("callback_object"), object); 1102 v8::Handle<v8::Script> script; 1103 script = v8_compile("callback_object.callback(17)"); 1104 for (int i = 0; i < 30; i++) { 1105 CHECK_EQ(51424, script->Run()->Int32Value()); 1106 } 1107 script = v8_compile("callback_object.callback(17, 24)"); 1108 for (int i = 0; i < 30; i++) { 1109 CHECK_EQ(51425, script->Run()->Int32Value()); 1110 } 1111 } 1112 1113 1114 THREADED_PROFILED_TEST(SimpleCallback) { 1115 TestSimpleCallback(SimpleCallback); 1116 } 1117 1118 1119 template<typename T> 1120 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1121 1122 // constant return values 1123 static int32_t fast_return_value_int32 = 471; 1124 static uint32_t fast_return_value_uint32 = 571; 1125 static const double kFastReturnValueDouble = 2.7; 1126 // variable return values 1127 static bool fast_return_value_bool = false; 1128 enum ReturnValueOddball { 1129 kNullReturnValue, 1130 kUndefinedReturnValue, 1131 kEmptyStringReturnValue 1132 }; 1133 static ReturnValueOddball fast_return_value_void; 1134 static bool fast_return_value_object_is_empty = false; 1135 1136 // Helper function to avoid compiler error: insufficient contextual information 1137 // to determine type when applying FUNCTION_ADDR to a template function. 1138 static i::Address address_of(v8::FunctionCallback callback) { 1139 return FUNCTION_ADDR(callback); 1140 } 1141 1142 template<> 1143 void FastReturnValueCallback<int32_t>( 1144 const v8::FunctionCallbackInfo<v8::Value>& info) { 1145 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1146 info.GetReturnValue().Set(fast_return_value_int32); 1147 } 1148 1149 template<> 1150 void FastReturnValueCallback<uint32_t>( 1151 const v8::FunctionCallbackInfo<v8::Value>& info) { 1152 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1153 info.GetReturnValue().Set(fast_return_value_uint32); 1154 } 1155 1156 template<> 1157 void FastReturnValueCallback<double>( 1158 const v8::FunctionCallbackInfo<v8::Value>& info) { 1159 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1160 info.GetReturnValue().Set(kFastReturnValueDouble); 1161 } 1162 1163 template<> 1164 void FastReturnValueCallback<bool>( 1165 const v8::FunctionCallbackInfo<v8::Value>& info) { 1166 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1167 info.GetReturnValue().Set(fast_return_value_bool); 1168 } 1169 1170 template<> 1171 void FastReturnValueCallback<void>( 1172 const v8::FunctionCallbackInfo<v8::Value>& info) { 1173 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1174 switch (fast_return_value_void) { 1175 case kNullReturnValue: 1176 info.GetReturnValue().SetNull(); 1177 break; 1178 case kUndefinedReturnValue: 1179 info.GetReturnValue().SetUndefined(); 1180 break; 1181 case kEmptyStringReturnValue: 1182 info.GetReturnValue().SetEmptyString(); 1183 break; 1184 } 1185 } 1186 1187 template<> 1188 void FastReturnValueCallback<Object>( 1189 const v8::FunctionCallbackInfo<v8::Value>& info) { 1190 v8::Handle<v8::Object> object; 1191 if (!fast_return_value_object_is_empty) object = Object::New(); 1192 info.GetReturnValue().Set(object); 1193 } 1194 1195 template<typename T> 1196 Handle<Value> TestFastReturnValues() { 1197 LocalContext env; 1198 v8::HandleScope scope(env->GetIsolate()); 1199 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 1200 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1201 object_template->Set(env->GetIsolate(), "callback", 1202 v8::FunctionTemplate::New(callback)); 1203 v8::Local<v8::Object> object = object_template->NewInstance(); 1204 (*env)->Global()->Set(v8_str("callback_object"), object); 1205 return scope.Close(CompileRun("callback_object.callback()")); 1206 } 1207 1208 1209 THREADED_PROFILED_TEST(FastReturnValues) { 1210 LocalContext env; 1211 v8::HandleScope scope(CcTest::isolate()); 1212 v8::Handle<v8::Value> value; 1213 // check int32_t and uint32_t 1214 int32_t int_values[] = { 1215 0, 234, -723, 1216 i::Smi::kMinValue, i::Smi::kMaxValue 1217 }; 1218 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) { 1219 for (int modifier = -1; modifier <= 1; modifier++) { 1220 int int_value = int_values[i] + modifier; 1221 // check int32_t 1222 fast_return_value_int32 = int_value; 1223 value = TestFastReturnValues<int32_t>(); 1224 CHECK(value->IsInt32()); 1225 CHECK(fast_return_value_int32 == value->Int32Value()); 1226 // check uint32_t 1227 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1228 value = TestFastReturnValues<uint32_t>(); 1229 CHECK(value->IsUint32()); 1230 CHECK(fast_return_value_uint32 == value->Uint32Value()); 1231 } 1232 } 1233 // check double 1234 value = TestFastReturnValues<double>(); 1235 CHECK(value->IsNumber()); 1236 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value()); 1237 // check bool values 1238 for (int i = 0; i < 2; i++) { 1239 fast_return_value_bool = i == 0; 1240 value = TestFastReturnValues<bool>(); 1241 CHECK(value->IsBoolean()); 1242 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value()); 1243 } 1244 // check oddballs 1245 ReturnValueOddball oddballs[] = { 1246 kNullReturnValue, 1247 kUndefinedReturnValue, 1248 kEmptyStringReturnValue 1249 }; 1250 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) { 1251 fast_return_value_void = oddballs[i]; 1252 value = TestFastReturnValues<void>(); 1253 switch (fast_return_value_void) { 1254 case kNullReturnValue: 1255 CHECK(value->IsNull()); 1256 break; 1257 case kUndefinedReturnValue: 1258 CHECK(value->IsUndefined()); 1259 break; 1260 case kEmptyStringReturnValue: 1261 CHECK(value->IsString()); 1262 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1263 break; 1264 } 1265 } 1266 // check handles 1267 fast_return_value_object_is_empty = false; 1268 value = TestFastReturnValues<Object>(); 1269 CHECK(value->IsObject()); 1270 fast_return_value_object_is_empty = true; 1271 value = TestFastReturnValues<Object>(); 1272 CHECK(value->IsUndefined()); 1273 } 1274 1275 1276 THREADED_TEST(FunctionTemplateSetLength) { 1277 LocalContext env; 1278 v8::HandleScope scope(env->GetIsolate()); 1279 { 1280 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New( 1281 handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23); 1282 Local<Function> fun = fun_templ->GetFunction(); 1283 env->Global()->Set(v8_str("obj"), fun); 1284 Local<Script> script = v8_compile("obj.length"); 1285 CHECK_EQ(23, script->Run()->Int32Value()); 1286 } 1287 { 1288 Local<v8::FunctionTemplate> fun_templ = 1289 v8::FunctionTemplate::New(handle_callback); 1290 fun_templ->SetLength(22); 1291 Local<Function> fun = fun_templ->GetFunction(); 1292 env->Global()->Set(v8_str("obj"), fun); 1293 Local<Script> script = v8_compile("obj.length"); 1294 CHECK_EQ(22, script->Run()->Int32Value()); 1295 } 1296 { 1297 // Without setting length it defaults to 0. 1298 Local<v8::FunctionTemplate> fun_templ = 1299 v8::FunctionTemplate::New(handle_callback); 1300 Local<Function> fun = fun_templ->GetFunction(); 1301 env->Global()->Set(v8_str("obj"), fun); 1302 Local<Script> script = v8_compile("obj.length"); 1303 CHECK_EQ(0, script->Run()->Int32Value()); 1304 } 1305 } 1306 1307 1308 static void* expected_ptr; 1309 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1310 void* ptr = v8::External::Cast(*args.Data())->Value(); 1311 CHECK_EQ(expected_ptr, ptr); 1312 args.GetReturnValue().Set(true); 1313 } 1314 1315 1316 static void TestExternalPointerWrapping() { 1317 LocalContext env; 1318 v8::HandleScope scope(env->GetIsolate()); 1319 1320 v8::Handle<v8::Value> data = 1321 v8::External::New(env->GetIsolate(), expected_ptr); 1322 1323 v8::Handle<v8::Object> obj = v8::Object::New(); 1324 obj->Set(v8_str("func"), 1325 v8::FunctionTemplate::New(callback, data)->GetFunction()); 1326 env->Global()->Set(v8_str("obj"), obj); 1327 1328 CHECK(CompileRun( 1329 "function foo() {\n" 1330 " for (var i = 0; i < 13; i++) obj.func();\n" 1331 "}\n" 1332 "foo(), true")->BooleanValue()); 1333 } 1334 1335 1336 THREADED_TEST(ExternalWrap) { 1337 // Check heap allocated object. 1338 int* ptr = new int; 1339 expected_ptr = ptr; 1340 TestExternalPointerWrapping(); 1341 delete ptr; 1342 1343 // Check stack allocated object. 1344 int foo; 1345 expected_ptr = &foo; 1346 TestExternalPointerWrapping(); 1347 1348 // Check not aligned addresses. 1349 const int n = 100; 1350 char* s = new char[n]; 1351 for (int i = 0; i < n; i++) { 1352 expected_ptr = s + i; 1353 TestExternalPointerWrapping(); 1354 } 1355 1356 delete[] s; 1357 1358 // Check several invalid addresses. 1359 expected_ptr = reinterpret_cast<void*>(1); 1360 TestExternalPointerWrapping(); 1361 1362 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1363 TestExternalPointerWrapping(); 1364 1365 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1366 TestExternalPointerWrapping(); 1367 1368 #if defined(V8_HOST_ARCH_X64) 1369 // Check a value with a leading 1 bit in x64 Smi encoding. 1370 expected_ptr = reinterpret_cast<void*>(0x400000000); 1371 TestExternalPointerWrapping(); 1372 1373 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1374 TestExternalPointerWrapping(); 1375 1376 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1377 TestExternalPointerWrapping(); 1378 #endif 1379 } 1380 1381 1382 THREADED_TEST(FindInstanceInPrototypeChain) { 1383 LocalContext env; 1384 v8::HandleScope scope(env->GetIsolate()); 1385 1386 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(); 1387 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(); 1388 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(); 1389 derived->Inherit(base); 1390 1391 Local<v8::Function> base_function = base->GetFunction(); 1392 Local<v8::Function> derived_function = derived->GetFunction(); 1393 Local<v8::Function> other_function = other->GetFunction(); 1394 1395 Local<v8::Object> base_instance = base_function->NewInstance(); 1396 Local<v8::Object> derived_instance = derived_function->NewInstance(); 1397 Local<v8::Object> derived_instance2 = derived_function->NewInstance(); 1398 Local<v8::Object> other_instance = other_function->NewInstance(); 1399 derived_instance2->Set(v8_str("__proto__"), derived_instance); 1400 other_instance->Set(v8_str("__proto__"), derived_instance2); 1401 1402 // base_instance is only an instance of base. 1403 CHECK_EQ(base_instance, 1404 base_instance->FindInstanceInPrototypeChain(base)); 1405 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1406 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1407 1408 // derived_instance is an instance of base and derived. 1409 CHECK_EQ(derived_instance, 1410 derived_instance->FindInstanceInPrototypeChain(base)); 1411 CHECK_EQ(derived_instance, 1412 derived_instance->FindInstanceInPrototypeChain(derived)); 1413 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1414 1415 // other_instance is an instance of other and its immediate 1416 // prototype derived_instance2 is an instance of base and derived. 1417 // Note, derived_instance is an instance of base and derived too, 1418 // but it comes after derived_instance2 in the prototype chain of 1419 // other_instance. 1420 CHECK_EQ(derived_instance2, 1421 other_instance->FindInstanceInPrototypeChain(base)); 1422 CHECK_EQ(derived_instance2, 1423 other_instance->FindInstanceInPrototypeChain(derived)); 1424 CHECK_EQ(other_instance, 1425 other_instance->FindInstanceInPrototypeChain(other)); 1426 } 1427 1428 1429 THREADED_TEST(TinyInteger) { 1430 LocalContext env; 1431 v8::HandleScope scope(env->GetIsolate()); 1432 v8::Isolate* isolate = CcTest::isolate(); 1433 1434 int32_t value = 239; 1435 Local<v8::Integer> value_obj = v8::Integer::New(value); 1436 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1437 1438 value_obj = v8::Integer::New(value, isolate); 1439 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1440 } 1441 1442 1443 THREADED_TEST(BigSmiInteger) { 1444 LocalContext env; 1445 v8::HandleScope scope(env->GetIsolate()); 1446 v8::Isolate* isolate = CcTest::isolate(); 1447 1448 int32_t value = i::Smi::kMaxValue; 1449 // We cannot add one to a Smi::kMaxValue without wrapping. 1450 if (i::SmiValuesAre31Bits()) { 1451 CHECK(i::Smi::IsValid(value)); 1452 CHECK(!i::Smi::IsValid(value + 1)); 1453 1454 Local<v8::Integer> value_obj = v8::Integer::New(value); 1455 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1456 1457 value_obj = v8::Integer::New(value, isolate); 1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1459 } 1460 } 1461 1462 1463 THREADED_TEST(BigInteger) { 1464 LocalContext env; 1465 v8::HandleScope scope(env->GetIsolate()); 1466 v8::Isolate* isolate = CcTest::isolate(); 1467 1468 // We cannot add one to a Smi::kMaxValue without wrapping. 1469 if (i::SmiValuesAre31Bits()) { 1470 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1471 // The code will not be run in that case, due to the "if" guard. 1472 int32_t value = 1473 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1474 CHECK(value > i::Smi::kMaxValue); 1475 CHECK(!i::Smi::IsValid(value)); 1476 1477 Local<v8::Integer> value_obj = v8::Integer::New(value); 1478 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1479 1480 value_obj = v8::Integer::New(value, isolate); 1481 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1482 } 1483 } 1484 1485 1486 THREADED_TEST(TinyUnsignedInteger) { 1487 LocalContext env; 1488 v8::HandleScope scope(env->GetIsolate()); 1489 v8::Isolate* isolate = CcTest::isolate(); 1490 1491 uint32_t value = 239; 1492 1493 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1494 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1495 1496 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1497 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1498 } 1499 1500 1501 THREADED_TEST(BigUnsignedSmiInteger) { 1502 LocalContext env; 1503 v8::HandleScope scope(env->GetIsolate()); 1504 v8::Isolate* isolate = CcTest::isolate(); 1505 1506 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1507 CHECK(i::Smi::IsValid(value)); 1508 CHECK(!i::Smi::IsValid(value + 1)); 1509 1510 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1512 1513 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1514 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1515 } 1516 1517 1518 THREADED_TEST(BigUnsignedInteger) { 1519 LocalContext env; 1520 v8::HandleScope scope(env->GetIsolate()); 1521 v8::Isolate* isolate = CcTest::isolate(); 1522 1523 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1524 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1525 CHECK(!i::Smi::IsValid(value)); 1526 1527 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1529 1530 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1532 } 1533 1534 1535 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1536 LocalContext env; 1537 v8::HandleScope scope(env->GetIsolate()); 1538 v8::Isolate* isolate = CcTest::isolate(); 1539 1540 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1541 uint32_t value = INT32_MAX_AS_UINT + 1; 1542 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1543 1544 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1545 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1546 1547 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1548 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1549 } 1550 1551 1552 THREADED_TEST(IsNativeError) { 1553 LocalContext env; 1554 v8::HandleScope scope(env->GetIsolate()); 1555 v8::Handle<Value> syntax_error = CompileRun( 1556 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1557 CHECK(syntax_error->IsNativeError()); 1558 v8::Handle<Value> not_error = CompileRun("{a:42}"); 1559 CHECK(!not_error->IsNativeError()); 1560 v8::Handle<Value> not_object = CompileRun("42"); 1561 CHECK(!not_object->IsNativeError()); 1562 } 1563 1564 1565 THREADED_TEST(StringObject) { 1566 LocalContext env; 1567 v8::HandleScope scope(env->GetIsolate()); 1568 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); 1569 CHECK(boxed_string->IsStringObject()); 1570 v8::Handle<Value> unboxed_string = CompileRun("\"test\""); 1571 CHECK(!unboxed_string->IsStringObject()); 1572 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); 1573 CHECK(!boxed_not_string->IsStringObject()); 1574 v8::Handle<Value> not_object = CompileRun("0"); 1575 CHECK(!not_object->IsStringObject()); 1576 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1577 CHECK(!as_boxed.IsEmpty()); 1578 Local<v8::String> the_string = as_boxed->ValueOf(); 1579 CHECK(!the_string.IsEmpty()); 1580 ExpectObject("\"test\"", the_string); 1581 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1582 CHECK(new_boxed_string->IsStringObject()); 1583 as_boxed = new_boxed_string.As<v8::StringObject>(); 1584 the_string = as_boxed->ValueOf(); 1585 CHECK(!the_string.IsEmpty()); 1586 ExpectObject("\"test\"", the_string); 1587 } 1588 1589 1590 THREADED_TEST(NumberObject) { 1591 LocalContext env; 1592 v8::HandleScope scope(env->GetIsolate()); 1593 v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); 1594 CHECK(boxed_number->IsNumberObject()); 1595 v8::Handle<Value> unboxed_number = CompileRun("42"); 1596 CHECK(!unboxed_number->IsNumberObject()); 1597 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1598 CHECK(!boxed_not_number->IsNumberObject()); 1599 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1600 CHECK(!as_boxed.IsEmpty()); 1601 double the_number = as_boxed->ValueOf(); 1602 CHECK_EQ(42.0, the_number); 1603 v8::Handle<v8::Value> new_boxed_number = 1604 v8::NumberObject::New(env->GetIsolate(), 43); 1605 CHECK(new_boxed_number->IsNumberObject()); 1606 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1607 the_number = as_boxed->ValueOf(); 1608 CHECK_EQ(43.0, the_number); 1609 } 1610 1611 1612 THREADED_TEST(BooleanObject) { 1613 LocalContext env; 1614 v8::HandleScope scope(env->GetIsolate()); 1615 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1616 CHECK(boxed_boolean->IsBooleanObject()); 1617 v8::Handle<Value> unboxed_boolean = CompileRun("true"); 1618 CHECK(!unboxed_boolean->IsBooleanObject()); 1619 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1620 CHECK(!boxed_not_boolean->IsBooleanObject()); 1621 v8::Handle<v8::BooleanObject> as_boxed = 1622 boxed_boolean.As<v8::BooleanObject>(); 1623 CHECK(!as_boxed.IsEmpty()); 1624 bool the_boolean = as_boxed->ValueOf(); 1625 CHECK_EQ(true, the_boolean); 1626 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); 1627 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); 1628 CHECK(boxed_true->IsBooleanObject()); 1629 CHECK(boxed_false->IsBooleanObject()); 1630 as_boxed = boxed_true.As<v8::BooleanObject>(); 1631 CHECK_EQ(true, as_boxed->ValueOf()); 1632 as_boxed = boxed_false.As<v8::BooleanObject>(); 1633 CHECK_EQ(false, as_boxed->ValueOf()); 1634 } 1635 1636 1637 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1638 LocalContext env; 1639 v8::HandleScope scope(env->GetIsolate()); 1640 1641 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false); 1642 CHECK(primitive_false->IsBoolean()); 1643 CHECK(!primitive_false->IsBooleanObject()); 1644 CHECK(!primitive_false->BooleanValue()); 1645 CHECK(!primitive_false->IsTrue()); 1646 CHECK(primitive_false->IsFalse()); 1647 1648 Local<Value> false_value = BooleanObject::New(false); 1649 CHECK(!false_value->IsBoolean()); 1650 CHECK(false_value->IsBooleanObject()); 1651 CHECK(false_value->BooleanValue()); 1652 CHECK(!false_value->IsTrue()); 1653 CHECK(!false_value->IsFalse()); 1654 1655 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1656 CHECK(!false_boolean_object->IsBoolean()); 1657 CHECK(false_boolean_object->IsBooleanObject()); 1658 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1659 // CHECK(false_boolean_object->BooleanValue()); 1660 CHECK(!false_boolean_object->ValueOf()); 1661 CHECK(!false_boolean_object->IsTrue()); 1662 CHECK(!false_boolean_object->IsFalse()); 1663 1664 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true); 1665 CHECK(primitive_true->IsBoolean()); 1666 CHECK(!primitive_true->IsBooleanObject()); 1667 CHECK(primitive_true->BooleanValue()); 1668 CHECK(primitive_true->IsTrue()); 1669 CHECK(!primitive_true->IsFalse()); 1670 1671 Local<Value> true_value = BooleanObject::New(true); 1672 CHECK(!true_value->IsBoolean()); 1673 CHECK(true_value->IsBooleanObject()); 1674 CHECK(true_value->BooleanValue()); 1675 CHECK(!true_value->IsTrue()); 1676 CHECK(!true_value->IsFalse()); 1677 1678 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1679 CHECK(!true_boolean_object->IsBoolean()); 1680 CHECK(true_boolean_object->IsBooleanObject()); 1681 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1682 // CHECK(true_boolean_object->BooleanValue()); 1683 CHECK(true_boolean_object->ValueOf()); 1684 CHECK(!true_boolean_object->IsTrue()); 1685 CHECK(!true_boolean_object->IsFalse()); 1686 } 1687 1688 1689 THREADED_TEST(Number) { 1690 LocalContext env; 1691 v8::HandleScope scope(env->GetIsolate()); 1692 double PI = 3.1415926; 1693 Local<v8::Number> pi_obj = v8::Number::New(PI); 1694 CHECK_EQ(PI, pi_obj->NumberValue()); 1695 } 1696 1697 1698 THREADED_TEST(ToNumber) { 1699 LocalContext env; 1700 v8::Isolate* isolate = CcTest::isolate(); 1701 v8::HandleScope scope(isolate); 1702 Local<String> str = v8_str("3.1415926"); 1703 CHECK_EQ(3.1415926, str->NumberValue()); 1704 v8::Handle<v8::Boolean> t = v8::True(isolate); 1705 CHECK_EQ(1.0, t->NumberValue()); 1706 v8::Handle<v8::Boolean> f = v8::False(isolate); 1707 CHECK_EQ(0.0, f->NumberValue()); 1708 } 1709 1710 1711 THREADED_TEST(Date) { 1712 LocalContext env; 1713 v8::HandleScope scope(env->GetIsolate()); 1714 double PI = 3.1415926; 1715 Local<Value> date = v8::Date::New(env->GetIsolate(), PI); 1716 CHECK_EQ(3.0, date->NumberValue()); 1717 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42)); 1718 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value()); 1719 } 1720 1721 1722 THREADED_TEST(Boolean) { 1723 LocalContext env; 1724 v8::HandleScope scope(env->GetIsolate()); 1725 v8::Handle<v8::Boolean> t = v8::True(CcTest::isolate()); 1726 CHECK(t->Value()); 1727 v8::Handle<v8::Boolean> f = v8::False(CcTest::isolate()); 1728 CHECK(!f->Value()); 1729 v8::Handle<v8::Primitive> u = v8::Undefined(CcTest::isolate()); 1730 CHECK(!u->BooleanValue()); 1731 v8::Handle<v8::Primitive> n = v8::Null(CcTest::isolate()); 1732 CHECK(!n->BooleanValue()); 1733 v8::Handle<String> str1 = v8_str(""); 1734 CHECK(!str1->BooleanValue()); 1735 v8::Handle<String> str2 = v8_str("x"); 1736 CHECK(str2->BooleanValue()); 1737 CHECK(!v8::Number::New(0)->BooleanValue()); 1738 CHECK(v8::Number::New(-1)->BooleanValue()); 1739 CHECK(v8::Number::New(1)->BooleanValue()); 1740 CHECK(v8::Number::New(42)->BooleanValue()); 1741 CHECK(!v8_compile("NaN")->Run()->BooleanValue()); 1742 } 1743 1744 1745 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1746 ApiTestFuzzer::Fuzz(); 1747 args.GetReturnValue().Set(v8_num(13.4)); 1748 } 1749 1750 1751 static void GetM(Local<String> name, 1752 const v8::PropertyCallbackInfo<v8::Value>& info) { 1753 ApiTestFuzzer::Fuzz(); 1754 info.GetReturnValue().Set(v8_num(876)); 1755 } 1756 1757 1758 THREADED_TEST(GlobalPrototype) { 1759 v8::HandleScope scope(CcTest::isolate()); 1760 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 1761 func_templ->PrototypeTemplate()->Set( 1762 CcTest::isolate(), "dummy", v8::FunctionTemplate::New(DummyCallHandler)); 1763 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1764 templ->Set(CcTest::isolate(), "x", v8_num(200)); 1765 templ->SetAccessor(v8_str("m"), GetM); 1766 LocalContext env(0, templ); 1767 v8::Handle<Script> script(v8_compile("dummy()")); 1768 v8::Handle<Value> result(script->Run()); 1769 CHECK_EQ(13.4, result->NumberValue()); 1770 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); 1771 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value()); 1772 } 1773 1774 1775 THREADED_TEST(ObjectTemplate) { 1776 v8::HandleScope scope(CcTest::isolate()); 1777 Local<ObjectTemplate> templ1 = ObjectTemplate::New(); 1778 templ1->Set(CcTest::isolate(), "x", v8_num(10)); 1779 templ1->Set(CcTest::isolate(), "y", v8_num(13)); 1780 LocalContext env; 1781 Local<v8::Object> instance1 = templ1->NewInstance(); 1782 env->Global()->Set(v8_str("p"), instance1); 1783 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); 1784 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); 1785 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 1786 fun->PrototypeTemplate()->Set(CcTest::isolate(), "nirk", v8_num(123)); 1787 Local<ObjectTemplate> templ2 = fun->InstanceTemplate(); 1788 templ2->Set(CcTest::isolate(), "a", v8_num(12)); 1789 templ2->Set(CcTest::isolate(), "b", templ1); 1790 Local<v8::Object> instance2 = templ2->NewInstance(); 1791 env->Global()->Set(v8_str("q"), instance2); 1792 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); 1793 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); 1794 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); 1795 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue()); 1796 } 1797 1798 1799 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 1800 ApiTestFuzzer::Fuzz(); 1801 args.GetReturnValue().Set(v8_num(17.2)); 1802 } 1803 1804 1805 static void GetKnurd(Local<String> property, 1806 const v8::PropertyCallbackInfo<v8::Value>& info) { 1807 ApiTestFuzzer::Fuzz(); 1808 info.GetReturnValue().Set(v8_num(15.2)); 1809 } 1810 1811 1812 THREADED_TEST(DescriptorInheritance) { 1813 v8::HandleScope scope(CcTest::isolate()); 1814 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(); 1815 super->PrototypeTemplate()->Set(CcTest::isolate(), "flabby", 1816 v8::FunctionTemplate::New(GetFlabby)); 1817 super->PrototypeTemplate()->Set(CcTest::isolate(), "PI", v8_num(3.14)); 1818 1819 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1820 1821 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(); 1822 base1->Inherit(super); 1823 base1->PrototypeTemplate()->Set(CcTest::isolate(), "v1", v8_num(20.1)); 1824 1825 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(); 1826 base2->Inherit(super); 1827 base2->PrototypeTemplate()->Set(CcTest::isolate(), "v2", v8_num(10.1)); 1828 1829 LocalContext env; 1830 1831 env->Global()->Set(v8_str("s"), super->GetFunction()); 1832 env->Global()->Set(v8_str("base1"), base1->GetFunction()); 1833 env->Global()->Set(v8_str("base2"), base2->GetFunction()); 1834 1835 // Checks right __proto__ chain. 1836 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); 1837 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); 1838 1839 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); 1840 1841 // Instance accessor should not be visible on function object or its prototype 1842 CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); 1843 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); 1844 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); 1845 1846 env->Global()->Set(v8_str("obj"), 1847 base1->GetFunction()->NewInstance()); 1848 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); 1849 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); 1850 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); 1851 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); 1852 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); 1853 1854 env->Global()->Set(v8_str("obj2"), 1855 base2->GetFunction()->NewInstance()); 1856 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); 1857 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); 1858 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); 1859 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); 1860 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); 1861 1862 // base1 and base2 cannot cross reference to each's prototype 1863 CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); 1864 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined()); 1865 } 1866 1867 1868 int echo_named_call_count; 1869 1870 1871 static void EchoNamedProperty(Local<String> name, 1872 const v8::PropertyCallbackInfo<v8::Value>& info) { 1873 ApiTestFuzzer::Fuzz(); 1874 CHECK_EQ(v8_str("data"), info.Data()); 1875 echo_named_call_count++; 1876 info.GetReturnValue().Set(name); 1877 } 1878 1879 1880 // Helper functions for Interceptor/Accessor interaction tests 1881 1882 void SimpleAccessorGetter(Local<String> name, 1883 const v8::PropertyCallbackInfo<v8::Value>& info) { 1884 Handle<Object> self = info.This(); 1885 info.GetReturnValue().Set( 1886 self->Get(String::Concat(v8_str("accessor_"), name))); 1887 } 1888 1889 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 1890 const v8::PropertyCallbackInfo<void>& info) { 1891 Handle<Object> self = info.This(); 1892 self->Set(String::Concat(v8_str("accessor_"), name), value); 1893 } 1894 1895 void EmptyInterceptorGetter(Local<String> name, 1896 const v8::PropertyCallbackInfo<v8::Value>& info) { 1897 } 1898 1899 void EmptyInterceptorSetter(Local<String> name, 1900 Local<Value> value, 1901 const v8::PropertyCallbackInfo<v8::Value>& info) { 1902 } 1903 1904 void InterceptorGetter(Local<String> name, 1905 const v8::PropertyCallbackInfo<v8::Value>& info) { 1906 // Intercept names that start with 'interceptor_'. 1907 String::Utf8Value utf8(name); 1908 char* name_str = *utf8; 1909 char prefix[] = "interceptor_"; 1910 int i; 1911 for (i = 0; name_str[i] && prefix[i]; ++i) { 1912 if (name_str[i] != prefix[i]) return; 1913 } 1914 Handle<Object> self = info.This(); 1915 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i))); 1916 } 1917 1918 void InterceptorSetter(Local<String> name, 1919 Local<Value> value, 1920 const v8::PropertyCallbackInfo<v8::Value>& info) { 1921 // Intercept accesses that set certain integer values, for which the name does 1922 // not start with 'accessor_'. 1923 String::Utf8Value utf8(name); 1924 char* name_str = *utf8; 1925 char prefix[] = "accessor_"; 1926 int i; 1927 for (i = 0; name_str[i] && prefix[i]; ++i) { 1928 if (name_str[i] != prefix[i]) break; 1929 } 1930 if (!prefix[i]) return; 1931 1932 if (value->IsInt32() && value->Int32Value() < 10000) { 1933 Handle<Object> self = info.This(); 1934 self->SetHiddenValue(name, value); 1935 info.GetReturnValue().Set(value); 1936 } 1937 } 1938 1939 void AddAccessor(Handle<FunctionTemplate> templ, 1940 Handle<String> name, 1941 v8::AccessorGetterCallback getter, 1942 v8::AccessorSetterCallback setter) { 1943 templ->PrototypeTemplate()->SetAccessor(name, getter, setter); 1944 } 1945 1946 void AddInterceptor(Handle<FunctionTemplate> templ, 1947 v8::NamedPropertyGetterCallback getter, 1948 v8::NamedPropertySetterCallback setter) { 1949 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter); 1950 } 1951 1952 1953 THREADED_TEST(EmptyInterceptorBreakTransitions) { 1954 v8::HandleScope scope(CcTest::isolate()); 1955 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 1956 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 1957 LocalContext env; 1958 env->Global()->Set(v8_str("Constructor"), templ->GetFunction()); 1959 CompileRun("var o1 = new Constructor;" 1960 "o1.a = 1;" // Ensure a and x share the descriptor array. 1961 "Object.defineProperty(o1, 'x', {value: 10});"); 1962 CompileRun("var o2 = new Constructor;" 1963 "o2.a = 1;" 1964 "Object.defineProperty(o2, 'x', {value: 10});"); 1965 } 1966 1967 1968 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { 1969 v8::HandleScope scope(CcTest::isolate()); 1970 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1971 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1972 child->Inherit(parent); 1973 AddAccessor(parent, v8_str("age"), 1974 SimpleAccessorGetter, SimpleAccessorSetter); 1975 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1976 LocalContext env; 1977 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1978 CompileRun("var child = new Child;" 1979 "child.age = 10;"); 1980 ExpectBoolean("child.hasOwnProperty('age')", false); 1981 ExpectInt32("child.age", 10); 1982 ExpectInt32("child.accessor_age", 10); 1983 } 1984 1985 1986 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) { 1987 v8::HandleScope scope(CcTest::isolate()); 1988 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1989 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1990 child->Inherit(parent); 1991 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1992 LocalContext env; 1993 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1994 CompileRun("var child = new Child;" 1995 "var parent = child.__proto__;" 1996 "Object.defineProperty(parent, 'age', " 1997 " {get: function(){ return this.accessor_age; }, " 1998 " set: function(v){ this.accessor_age = v; }, " 1999 " enumerable: true, configurable: true});" 2000 "child.age = 10;"); 2001 ExpectBoolean("child.hasOwnProperty('age')", false); 2002 ExpectInt32("child.age", 10); 2003 ExpectInt32("child.accessor_age", 10); 2004 } 2005 2006 2007 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) { 2008 v8::HandleScope scope(CcTest::isolate()); 2009 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2010 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2011 child->Inherit(parent); 2012 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 2013 LocalContext env; 2014 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2015 CompileRun("var child = new Child;" 2016 "var parent = child.__proto__;" 2017 "parent.name = 'Alice';"); 2018 ExpectBoolean("child.hasOwnProperty('name')", false); 2019 ExpectString("child.name", "Alice"); 2020 CompileRun("child.name = 'Bob';"); 2021 ExpectString("child.name", "Bob"); 2022 ExpectBoolean("child.hasOwnProperty('name')", true); 2023 ExpectString("parent.name", "Alice"); 2024 } 2025 2026 2027 THREADED_TEST(SwitchFromInterceptorToAccessor) { 2028 v8::HandleScope scope(CcTest::isolate()); 2029 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 2030 AddAccessor(templ, v8_str("age"), 2031 SimpleAccessorGetter, SimpleAccessorSetter); 2032 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2033 LocalContext env; 2034 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2035 CompileRun("var obj = new Obj;" 2036 "function setAge(i){ obj.age = i; };" 2037 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2038 // All i < 10000 go to the interceptor. 2039 ExpectInt32("obj.interceptor_age", 9999); 2040 // The last i goes to the accessor. 2041 ExpectInt32("obj.accessor_age", 10000); 2042 } 2043 2044 2045 THREADED_TEST(SwitchFromAccessorToInterceptor) { 2046 v8::HandleScope scope(CcTest::isolate()); 2047 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 2048 AddAccessor(templ, v8_str("age"), 2049 SimpleAccessorGetter, SimpleAccessorSetter); 2050 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2051 LocalContext env; 2052 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2053 CompileRun("var obj = new Obj;" 2054 "function setAge(i){ obj.age = i; };" 2055 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2056 // All i >= 10000 go to the accessor. 2057 ExpectInt32("obj.accessor_age", 10000); 2058 // The last i goes to the interceptor. 2059 ExpectInt32("obj.interceptor_age", 9999); 2060 } 2061 2062 2063 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) { 2064 v8::HandleScope scope(CcTest::isolate()); 2065 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2066 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2067 child->Inherit(parent); 2068 AddAccessor(parent, v8_str("age"), 2069 SimpleAccessorGetter, SimpleAccessorSetter); 2070 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2071 LocalContext env; 2072 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2073 CompileRun("var child = new Child;" 2074 "function setAge(i){ child.age = i; };" 2075 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2076 // All i < 10000 go to the interceptor. 2077 ExpectInt32("child.interceptor_age", 9999); 2078 // The last i goes to the accessor. 2079 ExpectInt32("child.accessor_age", 10000); 2080 } 2081 2082 2083 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) { 2084 v8::HandleScope scope(CcTest::isolate()); 2085 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2086 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2087 child->Inherit(parent); 2088 AddAccessor(parent, v8_str("age"), 2089 SimpleAccessorGetter, SimpleAccessorSetter); 2090 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2091 LocalContext env; 2092 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2093 CompileRun("var child = new Child;" 2094 "function setAge(i){ child.age = i; };" 2095 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2096 // All i >= 10000 go to the accessor. 2097 ExpectInt32("child.accessor_age", 10000); 2098 // The last i goes to the interceptor. 2099 ExpectInt32("child.interceptor_age", 9999); 2100 } 2101 2102 2103 THREADED_TEST(SwitchFromInterceptorToJSAccessor) { 2104 v8::HandleScope scope(CcTest::isolate()); 2105 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 2106 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2107 LocalContext env; 2108 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2109 CompileRun("var obj = new Obj;" 2110 "function setter(i) { this.accessor_age = i; };" 2111 "function getter() { return this.accessor_age; };" 2112 "function setAge(i) { obj.age = i; };" 2113 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2114 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2115 // All i < 10000 go to the interceptor. 2116 ExpectInt32("obj.interceptor_age", 9999); 2117 // The last i goes to the JavaScript accessor. 2118 ExpectInt32("obj.accessor_age", 10000); 2119 // The installed JavaScript getter is still intact. 2120 // This last part is a regression test for issue 1651 and relies on the fact 2121 // that both interceptor and accessor are being installed on the same object. 2122 ExpectInt32("obj.age", 10000); 2123 ExpectBoolean("obj.hasOwnProperty('age')", true); 2124 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2125 } 2126 2127 2128 THREADED_TEST(SwitchFromJSAccessorToInterceptor) { 2129 v8::HandleScope scope(CcTest::isolate()); 2130 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 2131 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2132 LocalContext env; 2133 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2134 CompileRun("var obj = new Obj;" 2135 "function setter(i) { this.accessor_age = i; };" 2136 "function getter() { return this.accessor_age; };" 2137 "function setAge(i) { obj.age = i; };" 2138 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 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 // The installed JavaScript getter is still intact. 2145 // This last part is a regression test for issue 1651 and relies on the fact 2146 // that both interceptor and accessor are being installed on the same object. 2147 ExpectInt32("obj.age", 10000); 2148 ExpectBoolean("obj.hasOwnProperty('age')", true); 2149 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2150 } 2151 2152 2153 THREADED_TEST(SwitchFromInterceptorToProperty) { 2154 v8::HandleScope scope(CcTest::isolate()); 2155 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2156 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2157 child->Inherit(parent); 2158 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2159 LocalContext env; 2160 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2161 CompileRun("var child = new Child;" 2162 "function setAge(i){ child.age = i; };" 2163 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2164 // All i < 10000 go to the interceptor. 2165 ExpectInt32("child.interceptor_age", 9999); 2166 // The last i goes to child's own property. 2167 ExpectInt32("child.age", 10000); 2168 } 2169 2170 2171 THREADED_TEST(SwitchFromPropertyToInterceptor) { 2172 v8::HandleScope scope(CcTest::isolate()); 2173 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2174 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2175 child->Inherit(parent); 2176 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2177 LocalContext env; 2178 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2179 CompileRun("var child = new Child;" 2180 "function setAge(i){ child.age = i; };" 2181 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2182 // All i >= 10000 go to child's own property. 2183 ExpectInt32("child.age", 10000); 2184 // The last i goes to the interceptor. 2185 ExpectInt32("child.interceptor_age", 9999); 2186 } 2187 2188 2189 THREADED_TEST(NamedPropertyHandlerGetter) { 2190 echo_named_call_count = 0; 2191 v8::HandleScope scope(CcTest::isolate()); 2192 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2193 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty, 2194 0, 0, 0, 0, 2195 v8_str("data")); 2196 LocalContext env; 2197 env->Global()->Set(v8_str("obj"), 2198 templ->GetFunction()->NewInstance()); 2199 CHECK_EQ(echo_named_call_count, 0); 2200 v8_compile("obj.x")->Run(); 2201 CHECK_EQ(echo_named_call_count, 1); 2202 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;"; 2203 v8::Handle<Value> str = CompileRun(code); 2204 String::Utf8Value value(str); 2205 CHECK_EQ(*value, "oddlepoddle"); 2206 // Check default behavior 2207 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10); 2208 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue()); 2209 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); 2210 } 2211 2212 2213 int echo_indexed_call_count = 0; 2214 2215 2216 static void EchoIndexedProperty( 2217 uint32_t index, 2218 const v8::PropertyCallbackInfo<v8::Value>& info) { 2219 ApiTestFuzzer::Fuzz(); 2220 CHECK_EQ(v8_num(637), info.Data()); 2221 echo_indexed_call_count++; 2222 info.GetReturnValue().Set(v8_num(index)); 2223 } 2224 2225 2226 THREADED_TEST(IndexedPropertyHandlerGetter) { 2227 v8::HandleScope scope(CcTest::isolate()); 2228 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2229 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty, 2230 0, 0, 0, 0, 2231 v8_num(637)); 2232 LocalContext env; 2233 env->Global()->Set(v8_str("obj"), 2234 templ->GetFunction()->NewInstance()); 2235 Local<Script> script = v8_compile("obj[900]"); 2236 CHECK_EQ(script->Run()->Int32Value(), 900); 2237 } 2238 2239 2240 v8::Handle<v8::Object> bottom; 2241 2242 static void CheckThisIndexedPropertyHandler( 2243 uint32_t index, 2244 const v8::PropertyCallbackInfo<v8::Value>& info) { 2245 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler)); 2246 ApiTestFuzzer::Fuzz(); 2247 CHECK(info.This()->Equals(bottom)); 2248 } 2249 2250 static void CheckThisNamedPropertyHandler( 2251 Local<String> name, 2252 const v8::PropertyCallbackInfo<v8::Value>& info) { 2253 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler)); 2254 ApiTestFuzzer::Fuzz(); 2255 CHECK(info.This()->Equals(bottom)); 2256 } 2257 2258 void CheckThisIndexedPropertySetter( 2259 uint32_t index, 2260 Local<Value> value, 2261 const v8::PropertyCallbackInfo<v8::Value>& info) { 2262 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter)); 2263 ApiTestFuzzer::Fuzz(); 2264 CHECK(info.This()->Equals(bottom)); 2265 } 2266 2267 2268 void CheckThisNamedPropertySetter( 2269 Local<String> property, 2270 Local<Value> value, 2271 const v8::PropertyCallbackInfo<v8::Value>& info) { 2272 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter)); 2273 ApiTestFuzzer::Fuzz(); 2274 CHECK(info.This()->Equals(bottom)); 2275 } 2276 2277 void CheckThisIndexedPropertyQuery( 2278 uint32_t index, 2279 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2280 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery)); 2281 ApiTestFuzzer::Fuzz(); 2282 CHECK(info.This()->Equals(bottom)); 2283 } 2284 2285 2286 void CheckThisNamedPropertyQuery( 2287 Local<String> property, 2288 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2289 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery)); 2290 ApiTestFuzzer::Fuzz(); 2291 CHECK(info.This()->Equals(bottom)); 2292 } 2293 2294 2295 void CheckThisIndexedPropertyDeleter( 2296 uint32_t index, 2297 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2298 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter)); 2299 ApiTestFuzzer::Fuzz(); 2300 CHECK(info.This()->Equals(bottom)); 2301 } 2302 2303 2304 void CheckThisNamedPropertyDeleter( 2305 Local<String> property, 2306 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2307 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter)); 2308 ApiTestFuzzer::Fuzz(); 2309 CHECK(info.This()->Equals(bottom)); 2310 } 2311 2312 2313 void CheckThisIndexedPropertyEnumerator( 2314 const v8::PropertyCallbackInfo<v8::Array>& info) { 2315 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator)); 2316 ApiTestFuzzer::Fuzz(); 2317 CHECK(info.This()->Equals(bottom)); 2318 } 2319 2320 2321 void CheckThisNamedPropertyEnumerator( 2322 const v8::PropertyCallbackInfo<v8::Array>& info) { 2323 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator)); 2324 ApiTestFuzzer::Fuzz(); 2325 CHECK(info.This()->Equals(bottom)); 2326 } 2327 2328 2329 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) { 2330 LocalContext env; 2331 v8::HandleScope scope(env->GetIsolate()); 2332 2333 // Set up a prototype chain with three interceptors. 2334 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2335 templ->InstanceTemplate()->SetIndexedPropertyHandler( 2336 CheckThisIndexedPropertyHandler, 2337 CheckThisIndexedPropertySetter, 2338 CheckThisIndexedPropertyQuery, 2339 CheckThisIndexedPropertyDeleter, 2340 CheckThisIndexedPropertyEnumerator); 2341 2342 templ->InstanceTemplate()->SetNamedPropertyHandler( 2343 CheckThisNamedPropertyHandler, 2344 CheckThisNamedPropertySetter, 2345 CheckThisNamedPropertyQuery, 2346 CheckThisNamedPropertyDeleter, 2347 CheckThisNamedPropertyEnumerator); 2348 2349 bottom = templ->GetFunction()->NewInstance(); 2350 Local<v8::Object> top = templ->GetFunction()->NewInstance(); 2351 Local<v8::Object> middle = templ->GetFunction()->NewInstance(); 2352 2353 bottom->SetPrototype(middle); 2354 middle->SetPrototype(top); 2355 env->Global()->Set(v8_str("obj"), bottom); 2356 2357 // Indexed and named get. 2358 Script::Compile(v8_str("obj[0]"))->Run(); 2359 Script::Compile(v8_str("obj.x"))->Run(); 2360 2361 // Indexed and named set. 2362 Script::Compile(v8_str("obj[1] = 42"))->Run(); 2363 Script::Compile(v8_str("obj.y = 42"))->Run(); 2364 2365 // Indexed and named query. 2366 Script::Compile(v8_str("0 in obj"))->Run(); 2367 Script::Compile(v8_str("'x' in obj"))->Run(); 2368 2369 // Indexed and named deleter. 2370 Script::Compile(v8_str("delete obj[0]"))->Run(); 2371 Script::Compile(v8_str("delete obj.x"))->Run(); 2372 2373 // Enumerators. 2374 Script::Compile(v8_str("for (var p in obj) ;"))->Run(); 2375 } 2376 2377 2378 static void PrePropertyHandlerGet( 2379 Local<String> key, 2380 const v8::PropertyCallbackInfo<v8::Value>& info) { 2381 ApiTestFuzzer::Fuzz(); 2382 if (v8_str("pre")->Equals(key)) { 2383 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre")); 2384 } 2385 } 2386 2387 2388 static void PrePropertyHandlerQuery( 2389 Local<String> key, 2390 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2391 if (v8_str("pre")->Equals(key)) { 2392 info.GetReturnValue().Set(static_cast<int32_t>(v8::None)); 2393 } 2394 } 2395 2396 2397 THREADED_TEST(PrePropertyHandler) { 2398 v8::HandleScope scope(CcTest::isolate()); 2399 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 2400 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet, 2401 0, 2402 PrePropertyHandlerQuery); 2403 LocalContext env(NULL, desc->InstanceTemplate()); 2404 Script::Compile(v8_str( 2405 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run(); 2406 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run(); 2407 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre); 2408 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run(); 2409 CHECK_EQ(v8_str("Object: on"), result_on); 2410 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run(); 2411 CHECK(result_post.IsEmpty()); 2412 } 2413 2414 2415 THREADED_TEST(UndefinedIsNotEnumerable) { 2416 LocalContext env; 2417 v8::HandleScope scope(env->GetIsolate()); 2418 v8::Handle<Value> result = Script::Compile(v8_str( 2419 "this.propertyIsEnumerable(undefined)"))->Run(); 2420 CHECK(result->IsFalse()); 2421 } 2422 2423 2424 v8::Handle<Script> call_recursively_script; 2425 static const int kTargetRecursionDepth = 200; // near maximum 2426 2427 2428 static void CallScriptRecursivelyCall( 2429 const v8::FunctionCallbackInfo<v8::Value>& args) { 2430 ApiTestFuzzer::Fuzz(); 2431 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2432 if (depth == kTargetRecursionDepth) return; 2433 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 2434 args.GetReturnValue().Set(call_recursively_script->Run()); 2435 } 2436 2437 2438 static void CallFunctionRecursivelyCall( 2439 const v8::FunctionCallbackInfo<v8::Value>& args) { 2440 ApiTestFuzzer::Fuzz(); 2441 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2442 if (depth == kTargetRecursionDepth) { 2443 printf("[depth = %d]\n", depth); 2444 return; 2445 } 2446 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 2447 v8::Handle<Value> function = 2448 args.This()->Get(v8_str("callFunctionRecursively")); 2449 args.GetReturnValue().Set( 2450 function.As<Function>()->Call(args.This(), 0, NULL)); 2451 } 2452 2453 2454 THREADED_TEST(DeepCrossLanguageRecursion) { 2455 v8::HandleScope scope(CcTest::isolate()); 2456 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 2457 global->Set(v8_str("callScriptRecursively"), 2458 v8::FunctionTemplate::New(CallScriptRecursivelyCall)); 2459 global->Set(v8_str("callFunctionRecursively"), 2460 v8::FunctionTemplate::New(CallFunctionRecursivelyCall)); 2461 LocalContext env(NULL, global); 2462 2463 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 2464 call_recursively_script = v8_compile("callScriptRecursively()"); 2465 call_recursively_script->Run(); 2466 call_recursively_script = v8::Handle<Script>(); 2467 2468 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 2469 Script::Compile(v8_str("callFunctionRecursively()"))->Run(); 2470 } 2471 2472 2473 static void ThrowingPropertyHandlerGet( 2474 Local<String> key, 2475 const v8::PropertyCallbackInfo<v8::Value>& info) { 2476 ApiTestFuzzer::Fuzz(); 2477 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key)); 2478 } 2479 2480 2481 static void ThrowingPropertyHandlerSet( 2482 Local<String> key, 2483 Local<Value>, 2484 const v8::PropertyCallbackInfo<v8::Value>& info) { 2485 info.GetIsolate()->ThrowException(key); 2486 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2487 } 2488 2489 2490 THREADED_TEST(CallbackExceptionRegression) { 2491 v8::HandleScope scope(CcTest::isolate()); 2492 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 2493 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet, 2494 ThrowingPropertyHandlerSet); 2495 LocalContext env; 2496 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 2497 v8::Handle<Value> otto = Script::Compile(v8_str( 2498 "try { with (obj) { otto; } } catch (e) { e; }"))->Run(); 2499 CHECK_EQ(v8_str("otto"), otto); 2500 v8::Handle<Value> netto = Script::Compile(v8_str( 2501 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run(); 2502 CHECK_EQ(v8_str("netto"), netto); 2503 } 2504 2505 2506 THREADED_TEST(FunctionPrototype) { 2507 v8::HandleScope scope(CcTest::isolate()); 2508 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(); 2509 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2510 LocalContext env; 2511 env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); 2512 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak")); 2513 CHECK_EQ(script->Run()->Int32Value(), 321); 2514 } 2515 2516 2517 THREADED_TEST(InternalFields) { 2518 LocalContext env; 2519 v8::HandleScope scope(env->GetIsolate()); 2520 2521 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2522 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2523 instance_templ->SetInternalFieldCount(1); 2524 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2525 CHECK_EQ(1, obj->InternalFieldCount()); 2526 CHECK(obj->GetInternalField(0)->IsUndefined()); 2527 obj->SetInternalField(0, v8_num(17)); 2528 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value()); 2529 } 2530 2531 2532 THREADED_TEST(GlobalObjectInternalFields) { 2533 v8::HandleScope scope(CcTest::isolate()); 2534 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 2535 global_template->SetInternalFieldCount(1); 2536 LocalContext env(NULL, global_template); 2537 v8::Handle<v8::Object> global_proxy = env->Global(); 2538 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2539 CHECK_EQ(1, global->InternalFieldCount()); 2540 CHECK(global->GetInternalField(0)->IsUndefined()); 2541 global->SetInternalField(0, v8_num(17)); 2542 CHECK_EQ(17, global->GetInternalField(0)->Int32Value()); 2543 } 2544 2545 2546 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2547 LocalContext env; 2548 v8::HandleScope scope(CcTest::isolate()); 2549 2550 v8::Local<v8::Object> global = env->Global(); 2551 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value")); 2552 CHECK(global->HasRealIndexedProperty(0)); 2553 } 2554 2555 2556 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, 2557 void* value) { 2558 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2559 obj->SetAlignedPointerInInternalField(0, value); 2560 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2561 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2562 } 2563 2564 2565 THREADED_TEST(InternalFieldsAlignedPointers) { 2566 LocalContext env; 2567 v8::HandleScope scope(env->GetIsolate()); 2568 2569 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2570 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2571 instance_templ->SetInternalFieldCount(1); 2572 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2573 CHECK_EQ(1, obj->InternalFieldCount()); 2574 2575 CheckAlignedPointerInInternalField(obj, NULL); 2576 2577 int* heap_allocated = new int[100]; 2578 CheckAlignedPointerInInternalField(obj, heap_allocated); 2579 delete[] heap_allocated; 2580 2581 int stack_allocated[100]; 2582 CheckAlignedPointerInInternalField(obj, stack_allocated); 2583 2584 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2585 CheckAlignedPointerInInternalField(obj, huge); 2586 } 2587 2588 2589 static void CheckAlignedPointerInEmbedderData(LocalContext* env, 2590 int index, 2591 void* value) { 2592 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2593 (*env)->SetAlignedPointerInEmbedderData(index, value); 2594 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2595 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2596 } 2597 2598 2599 static void* AlignedTestPointer(int i) { 2600 return reinterpret_cast<void*>(i * 1234); 2601 } 2602 2603 2604 THREADED_TEST(EmbedderDataAlignedPointers) { 2605 LocalContext env; 2606 v8::HandleScope scope(env->GetIsolate()); 2607 2608 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2609 2610 int* heap_allocated = new int[100]; 2611 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2612 delete[] heap_allocated; 2613 2614 int stack_allocated[100]; 2615 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2616 2617 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2618 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2619 2620 // Test growing of the embedder data's backing store. 2621 for (int i = 0; i < 100; i++) { 2622 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2623 } 2624 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2625 for (int i = 0; i < 100; i++) { 2626 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2627 } 2628 } 2629 2630 2631 static void CheckEmbedderData(LocalContext* env, 2632 int index, 2633 v8::Handle<Value> data) { 2634 (*env)->SetEmbedderData(index, data); 2635 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2636 } 2637 2638 2639 THREADED_TEST(EmbedderData) { 2640 LocalContext env; 2641 v8::HandleScope scope(env->GetIsolate()); 2642 2643 CheckEmbedderData( 2644 &env, 3, 2645 v8::String::NewFromUtf8(env->GetIsolate(), "The quick brown fox jumps")); 2646 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(env->GetIsolate(), 2647 "over the lazy dog.")); 2648 CheckEmbedderData(&env, 1, v8::Number::New(1.2345)); 2649 CheckEmbedderData(&env, 0, v8::Boolean::New(env->GetIsolate(), true)); 2650 } 2651 2652 2653 THREADED_TEST(IdentityHash) { 2654 LocalContext env; 2655 v8::HandleScope scope(env->GetIsolate()); 2656 2657 // Ensure that the test starts with an fresh heap to test whether the hash 2658 // code is based on the address. 2659 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2660 Local<v8::Object> obj = v8::Object::New(); 2661 int hash = obj->GetIdentityHash(); 2662 int hash1 = obj->GetIdentityHash(); 2663 CHECK_EQ(hash, hash1); 2664 int hash2 = v8::Object::New()->GetIdentityHash(); 2665 // Since the identity hash is essentially a random number two consecutive 2666 // objects should not be assigned the same hash code. If the test below fails 2667 // the random number generator should be evaluated. 2668 CHECK_NE(hash, hash2); 2669 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2670 int hash3 = v8::Object::New()->GetIdentityHash(); 2671 // Make sure that the identity hash is not based on the initial address of 2672 // the object alone. If the test below fails the random number generator 2673 // should be evaluated. 2674 CHECK_NE(hash, hash3); 2675 int hash4 = obj->GetIdentityHash(); 2676 CHECK_EQ(hash, hash4); 2677 2678 // Check identity hashes behaviour in the presence of JS accessors. 2679 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2680 { 2681 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2682 Local<v8::Object> o1 = v8::Object::New(); 2683 Local<v8::Object> o2 = v8::Object::New(); 2684 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2685 } 2686 { 2687 CompileRun( 2688 "function cnst() { return 42; };\n" 2689 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2690 Local<v8::Object> o1 = v8::Object::New(); 2691 Local<v8::Object> o2 = v8::Object::New(); 2692 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2693 } 2694 } 2695 2696 2697 THREADED_TEST(SymbolProperties) { 2698 i::FLAG_harmony_symbols = true; 2699 2700 LocalContext env; 2701 v8::Isolate* isolate = env->GetIsolate(); 2702 v8::HandleScope scope(isolate); 2703 2704 v8::Local<v8::Object> obj = v8::Object::New(); 2705 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2706 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol"); 2707 2708 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2709 2710 // Check basic symbol functionality. 2711 CHECK(sym1->IsSymbol()); 2712 CHECK(sym2->IsSymbol()); 2713 CHECK(!obj->IsSymbol()); 2714 2715 CHECK(sym1->Equals(sym1)); 2716 CHECK(sym2->Equals(sym2)); 2717 CHECK(!sym1->Equals(sym2)); 2718 CHECK(!sym2->Equals(sym1)); 2719 CHECK(sym1->StrictEquals(sym1)); 2720 CHECK(sym2->StrictEquals(sym2)); 2721 CHECK(!sym1->StrictEquals(sym2)); 2722 CHECK(!sym2->StrictEquals(sym1)); 2723 2724 CHECK(sym2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-symbol"))); 2725 2726 v8::Local<v8::Value> sym_val = sym2; 2727 CHECK(sym_val->IsSymbol()); 2728 CHECK(sym_val->Equals(sym2)); 2729 CHECK(sym_val->StrictEquals(sym2)); 2730 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2)); 2731 2732 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2733 CHECK(sym_obj->IsSymbolObject()); 2734 CHECK(!sym2->IsSymbolObject()); 2735 CHECK(!obj->IsSymbolObject()); 2736 CHECK(sym_obj->Equals(sym2)); 2737 CHECK(!sym_obj->StrictEquals(sym2)); 2738 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj)); 2739 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2)); 2740 2741 // Make sure delete of a non-existent symbol property works. 2742 CHECK(obj->Delete(sym1)); 2743 CHECK(!obj->Has(sym1)); 2744 2745 CHECK(obj->Set(sym1, v8::Integer::New(1503))); 2746 CHECK(obj->Has(sym1)); 2747 CHECK_EQ(1503, obj->Get(sym1)->Int32Value()); 2748 CHECK(obj->Set(sym1, v8::Integer::New(2002))); 2749 CHECK(obj->Has(sym1)); 2750 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2751 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1)); 2752 2753 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2754 int num_props = obj->GetPropertyNames()->Length(); 2755 CHECK( 2756 obj->Set(v8::String::NewFromUtf8(isolate, "bla"), v8::Integer::New(20))); 2757 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2758 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2759 2760 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2761 2762 // Add another property and delete it afterwards to force the object in 2763 // slow case. 2764 CHECK(obj->Set(sym2, v8::Integer::New(2008))); 2765 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2766 CHECK_EQ(2008, obj->Get(sym2)->Int32Value()); 2767 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2768 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2769 2770 CHECK(obj->Has(sym1)); 2771 CHECK(obj->Has(sym2)); 2772 CHECK(obj->Delete(sym2)); 2773 CHECK(obj->Has(sym1)); 2774 CHECK(!obj->Has(sym2)); 2775 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2776 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2777 2778 // Symbol properties are inherited. 2779 v8::Local<v8::Object> child = v8::Object::New(); 2780 child->SetPrototype(obj); 2781 CHECK(child->Has(sym1)); 2782 CHECK_EQ(2002, child->Get(sym1)->Int32Value()); 2783 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2784 } 2785 2786 2787 THREADED_TEST(PrivateProperties) { 2788 LocalContext env; 2789 v8::Isolate* isolate = env->GetIsolate(); 2790 v8::HandleScope scope(isolate); 2791 2792 v8::Local<v8::Object> obj = v8::Object::New(); 2793 v8::Local<v8::Private> priv1 = v8::Private::New(isolate); 2794 v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private"); 2795 2796 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2797 2798 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private"))); 2799 2800 // Make sure delete of a non-existent private symbol property works. 2801 CHECK(obj->DeletePrivate(priv1)); 2802 CHECK(!obj->HasPrivate(priv1)); 2803 2804 CHECK(obj->SetPrivate(priv1, v8::Integer::New(1503))); 2805 CHECK(obj->HasPrivate(priv1)); 2806 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value()); 2807 CHECK(obj->SetPrivate(priv1, v8::Integer::New(2002))); 2808 CHECK(obj->HasPrivate(priv1)); 2809 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2810 2811 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2812 int num_props = obj->GetPropertyNames()->Length(); 2813 CHECK( 2814 obj->Set(v8::String::NewFromUtf8(isolate, "bla"), v8::Integer::New(20))); 2815 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2816 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2817 2818 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2819 2820 // Add another property and delete it afterwards to force the object in 2821 // slow case. 2822 CHECK(obj->SetPrivate(priv2, v8::Integer::New(2008))); 2823 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2824 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value()); 2825 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2826 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2827 2828 CHECK(obj->HasPrivate(priv1)); 2829 CHECK(obj->HasPrivate(priv2)); 2830 CHECK(obj->DeletePrivate(priv2)); 2831 CHECK(obj->HasPrivate(priv1)); 2832 CHECK(!obj->HasPrivate(priv2)); 2833 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value()); 2834 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2835 2836 // Private properties are inherited (for the time being). 2837 v8::Local<v8::Object> child = v8::Object::New(); 2838 child->SetPrototype(obj); 2839 CHECK(child->HasPrivate(priv1)); 2840 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value()); 2841 CHECK_EQ(0, child->GetOwnPropertyNames()->Length()); 2842 } 2843 2844 2845 class ScopedArrayBufferContents { 2846 public: 2847 explicit ScopedArrayBufferContents( 2848 const v8::ArrayBuffer::Contents& contents) 2849 : contents_(contents) {} 2850 ~ScopedArrayBufferContents() { free(contents_.Data()); } 2851 void* Data() const { return contents_.Data(); } 2852 size_t ByteLength() const { return contents_.ByteLength(); } 2853 private: 2854 const v8::ArrayBuffer::Contents contents_; 2855 }; 2856 2857 template <typename T> 2858 static void CheckInternalFieldsAreZero(v8::Handle<T> value) { 2859 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 2860 for (int i = 0; i < value->InternalFieldCount(); i++) { 2861 CHECK_EQ(0, value->GetInternalField(i)->Int32Value()); 2862 } 2863 } 2864 2865 2866 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 2867 LocalContext env; 2868 v8::Isolate* isolate = env->GetIsolate(); 2869 v8::HandleScope handle_scope(isolate); 2870 2871 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024); 2872 CheckInternalFieldsAreZero(ab); 2873 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 2874 CHECK(!ab->IsExternal()); 2875 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 2876 2877 ScopedArrayBufferContents ab_contents(ab->Externalize()); 2878 CHECK(ab->IsExternal()); 2879 2880 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 2881 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 2882 ASSERT(data != NULL); 2883 env->Global()->Set(v8_str("ab"), ab); 2884 2885 v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); 2886 CHECK_EQ(1024, result->Int32Value()); 2887 2888 result = CompileRun("var u8 = new Uint8Array(ab);" 2889 "u8[0] = 0xFF;" 2890 "u8[1] = 0xAA;" 2891 "u8.length"); 2892 CHECK_EQ(1024, result->Int32Value()); 2893 CHECK_EQ(0xFF, data[0]); 2894 CHECK_EQ(0xAA, data[1]); 2895 data[0] = 0xCC; 2896 data[1] = 0x11; 2897 result = CompileRun("u8[0] + u8[1]"); 2898 CHECK_EQ(0xDD, result->Int32Value()); 2899 } 2900 2901 2902 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 2903 LocalContext env; 2904 v8::Isolate* isolate = env->GetIsolate(); 2905 v8::HandleScope handle_scope(isolate); 2906 2907 2908 v8::Local<v8::Value> result = 2909 CompileRun("var ab1 = new ArrayBuffer(2);" 2910 "var u8_a = new Uint8Array(ab1);" 2911 "u8_a[0] = 0xAA;" 2912 "u8_a[1] = 0xFF; u8_a.buffer"); 2913 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 2914 CheckInternalFieldsAreZero(ab1); 2915 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 2916 CHECK(!ab1->IsExternal()); 2917 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 2918 CHECK(ab1->IsExternal()); 2919 2920 result = CompileRun("ab1.byteLength"); 2921 CHECK_EQ(2, result->Int32Value()); 2922 result = CompileRun("u8_a[0]"); 2923 CHECK_EQ(0xAA, result->Int32Value()); 2924 result = CompileRun("u8_a[1]"); 2925 CHECK_EQ(0xFF, result->Int32Value()); 2926 result = CompileRun("var u8_b = new Uint8Array(ab1);" 2927 "u8_b[0] = 0xBB;" 2928 "u8_a[0]"); 2929 CHECK_EQ(0xBB, result->Int32Value()); 2930 result = CompileRun("u8_b[1]"); 2931 CHECK_EQ(0xFF, result->Int32Value()); 2932 2933 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 2934 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 2935 CHECK_EQ(0xBB, ab1_data[0]); 2936 CHECK_EQ(0xFF, ab1_data[1]); 2937 ab1_data[0] = 0xCC; 2938 ab1_data[1] = 0x11; 2939 result = CompileRun("u8_a[0] + u8_a[1]"); 2940 CHECK_EQ(0xDD, result->Int32Value()); 2941 } 2942 2943 2944 THREADED_TEST(ArrayBuffer_External) { 2945 LocalContext env; 2946 v8::Isolate* isolate = env->GetIsolate(); 2947 v8::HandleScope handle_scope(isolate); 2948 2949 i::ScopedVector<uint8_t> my_data(100); 2950 memset(my_data.start(), 0, 100); 2951 Local<v8::ArrayBuffer> ab3 = 2952 v8::ArrayBuffer::New(isolate, my_data.start(), 100); 2953 CheckInternalFieldsAreZero(ab3); 2954 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 2955 CHECK(ab3->IsExternal()); 2956 2957 env->Global()->Set(v8_str("ab3"), ab3); 2958 2959 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength"); 2960 CHECK_EQ(100, result->Int32Value()); 2961 2962 result = CompileRun("var u8_b = new Uint8Array(ab3);" 2963 "u8_b[0] = 0xBB;" 2964 "u8_b[1] = 0xCC;" 2965 "u8_b.length"); 2966 CHECK_EQ(100, result->Int32Value()); 2967 CHECK_EQ(0xBB, my_data[0]); 2968 CHECK_EQ(0xCC, my_data[1]); 2969 my_data[0] = 0xCC; 2970 my_data[1] = 0x11; 2971 result = CompileRun("u8_b[0] + u8_b[1]"); 2972 CHECK_EQ(0xDD, result->Int32Value()); 2973 } 2974 2975 2976 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) { 2977 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 2978 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 2979 } 2980 2981 2982 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) { 2983 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 2984 CHECK_EQ(0, static_cast<int>(ta->Length())); 2985 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 2986 } 2987 2988 2989 static void CheckIsTypedArrayVarNeutered(const char* name) { 2990 i::ScopedVector<char> source(1024); 2991 i::OS::SNPrintF(source, 2992 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 2993 name, name, name); 2994 CHECK(CompileRun(source.start())->IsTrue()); 2995 v8::Handle<v8::TypedArray> ta = 2996 v8::Handle<v8::TypedArray>::Cast(CompileRun(name)); 2997 CheckIsNeutered(ta); 2998 } 2999 3000 3001 template <typename TypedArray, int kElementSize> 3002 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab, 3003 int byteOffset, 3004 int length) { 3005 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 3006 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 3007 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 3008 CHECK_EQ(length, static_cast<int>(ta->Length())); 3009 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 3010 return ta; 3011 } 3012 3013 3014 THREADED_TEST(ArrayBuffer_NeuteringApi) { 3015 LocalContext env; 3016 v8::Isolate* isolate = env->GetIsolate(); 3017 v8::HandleScope handle_scope(isolate); 3018 3019 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024); 3020 3021 v8::Handle<v8::Uint8Array> u8a = 3022 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 3023 v8::Handle<v8::Uint8ClampedArray> u8c = 3024 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 3025 v8::Handle<v8::Int8Array> i8a = 3026 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 3027 3028 v8::Handle<v8::Uint16Array> u16a = 3029 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 3030 v8::Handle<v8::Int16Array> i16a = 3031 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 3032 3033 v8::Handle<v8::Uint32Array> u32a = 3034 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 3035 v8::Handle<v8::Int32Array> i32a = 3036 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 3037 3038 v8::Handle<v8::Float32Array> f32a = 3039 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 3040 v8::Handle<v8::Float64Array> f64a = 3041 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 3042 3043 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 3044 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 3045 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 3046 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 3047 3048 ScopedArrayBufferContents contents(buffer->Externalize()); 3049 buffer->Neuter(); 3050 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 3051 CheckIsNeutered(u8a); 3052 CheckIsNeutered(u8c); 3053 CheckIsNeutered(i8a); 3054 CheckIsNeutered(u16a); 3055 CheckIsNeutered(i16a); 3056 CheckIsNeutered(u32a); 3057 CheckIsNeutered(i32a); 3058 CheckIsNeutered(f32a); 3059 CheckIsNeutered(f64a); 3060 CheckDataViewIsNeutered(dv); 3061 } 3062 3063 3064 THREADED_TEST(ArrayBuffer_NeuteringScript) { 3065 LocalContext env; 3066 v8::Isolate* isolate = env->GetIsolate(); 3067 v8::HandleScope handle_scope(isolate); 3068 3069 CompileRun( 3070 "var ab = new ArrayBuffer(1024);" 3071 "var u8a = new Uint8Array(ab, 1, 1023);" 3072 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 3073 "var i8a = new Int8Array(ab, 1, 1023);" 3074 "var u16a = new Uint16Array(ab, 2, 511);" 3075 "var i16a = new Int16Array(ab, 2, 511);" 3076 "var u32a = new Uint32Array(ab, 4, 255);" 3077 "var i32a = new Int32Array(ab, 4, 255);" 3078 "var f32a = new Float32Array(ab, 4, 255);" 3079 "var f64a = new Float64Array(ab, 8, 127);" 3080 "var dv = new DataView(ab, 1, 1023);"); 3081 3082 v8::Handle<v8::ArrayBuffer> ab = 3083 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 3084 3085 v8::Handle<v8::DataView> dv = 3086 v8::Handle<v8::DataView>::Cast(CompileRun("dv")); 3087 3088 ScopedArrayBufferContents contents(ab->Externalize()); 3089 ab->Neuter(); 3090 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 3091 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value()); 3092 3093 CheckIsTypedArrayVarNeutered("u8a"); 3094 CheckIsTypedArrayVarNeutered("u8c"); 3095 CheckIsTypedArrayVarNeutered("i8a"); 3096 CheckIsTypedArrayVarNeutered("u16a"); 3097 CheckIsTypedArrayVarNeutered("i16a"); 3098 CheckIsTypedArrayVarNeutered("u32a"); 3099 CheckIsTypedArrayVarNeutered("i32a"); 3100 CheckIsTypedArrayVarNeutered("f32a"); 3101 CheckIsTypedArrayVarNeutered("f64a"); 3102 3103 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 3104 CheckDataViewIsNeutered(dv); 3105 } 3106 3107 3108 3109 THREADED_TEST(HiddenProperties) { 3110 LocalContext env; 3111 v8::HandleScope scope(env->GetIsolate()); 3112 3113 v8::Local<v8::Object> obj = v8::Object::New(); 3114 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3115 v8::Local<v8::String> empty = v8_str(""); 3116 v8::Local<v8::String> prop_name = v8_str("prop_name"); 3117 3118 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3119 3120 // Make sure delete of a non-existent hidden value works 3121 CHECK(obj->DeleteHiddenValue(key)); 3122 3123 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503))); 3124 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value()); 3125 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); 3126 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3127 3128 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3129 3130 // Make sure we do not find the hidden property. 3131 CHECK(!obj->Has(empty)); 3132 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3133 CHECK(obj->Get(empty)->IsUndefined()); 3134 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3135 CHECK(obj->Set(empty, v8::Integer::New(2003))); 3136 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3137 CHECK_EQ(2003, obj->Get(empty)->Int32Value()); 3138 3139 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3140 3141 // Add another property and delete it afterwards to force the object in 3142 // slow case. 3143 CHECK(obj->Set(prop_name, v8::Integer::New(2008))); 3144 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3145 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value()); 3146 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3147 CHECK(obj->Delete(prop_name)); 3148 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 3149 3150 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 3151 3152 CHECK(obj->SetHiddenValue(key, Handle<Value>())); 3153 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3154 3155 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); 3156 CHECK(obj->DeleteHiddenValue(key)); 3157 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3158 } 3159 3160 3161 THREADED_TEST(Regress97784) { 3162 // Regression test for crbug.com/97784 3163 // Messing with the Object.prototype should not have effect on 3164 // hidden properties. 3165 LocalContext env; 3166 v8::HandleScope scope(env->GetIsolate()); 3167 3168 v8::Local<v8::Object> obj = v8::Object::New(); 3169 v8::Local<v8::String> key = v8_str("hidden"); 3170 3171 CompileRun( 3172 "set_called = false;" 3173 "Object.defineProperty(" 3174 " Object.prototype," 3175 " 'hidden'," 3176 " {get: function() { return 45; }," 3177 " set: function() { set_called = true; }})"); 3178 3179 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3180 // Make sure that the getter and setter from Object.prototype is not invoked. 3181 // If it did we would have full access to the hidden properties in 3182 // the accessor. 3183 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42))); 3184 ExpectFalse("set_called"); 3185 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value()); 3186 } 3187 3188 3189 static bool interceptor_for_hidden_properties_called; 3190 static void InterceptorForHiddenProperties( 3191 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 3192 interceptor_for_hidden_properties_called = true; 3193 } 3194 3195 3196 THREADED_TEST(HiddenPropertiesWithInterceptors) { 3197 LocalContext context; 3198 v8::HandleScope scope(context->GetIsolate()); 3199 3200 interceptor_for_hidden_properties_called = false; 3201 3202 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3203 3204 // Associate an interceptor with an object and start setting hidden values. 3205 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 3206 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 3207 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties); 3208 Local<v8::Function> function = fun_templ->GetFunction(); 3209 Local<v8::Object> obj = function->NewInstance(); 3210 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302))); 3211 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value()); 3212 CHECK(!interceptor_for_hidden_properties_called); 3213 } 3214 3215 3216 THREADED_TEST(External) { 3217 v8::HandleScope scope(CcTest::isolate()); 3218 int x = 3; 3219 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x); 3220 LocalContext env; 3221 env->Global()->Set(v8_str("ext"), ext); 3222 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run(); 3223 v8::Handle<v8::External> reext = reext_obj.As<v8::External>(); 3224 int* ptr = static_cast<int*>(reext->Value()); 3225 CHECK_EQ(x, 3); 3226 *ptr = 10; 3227 CHECK_EQ(x, 10); 3228 3229 // Make sure unaligned pointers are wrapped properly. 3230 char* data = i::StrDup("0123456789"); 3231 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]); 3232 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]); 3233 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]); 3234 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]); 3235 3236 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3237 CHECK_EQ('0', *char_ptr); 3238 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3239 CHECK_EQ('1', *char_ptr); 3240 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3241 CHECK_EQ('2', *char_ptr); 3242 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3243 CHECK_EQ('3', *char_ptr); 3244 i::DeleteArray(data); 3245 } 3246 3247 3248 THREADED_TEST(GlobalHandle) { 3249 v8::Isolate* isolate = CcTest::isolate(); 3250 v8::Persistent<String> global; 3251 { 3252 v8::HandleScope scope(isolate); 3253 global.Reset(isolate, v8_str("str")); 3254 } 3255 { 3256 v8::HandleScope scope(isolate); 3257 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3258 } 3259 global.Reset(); 3260 { 3261 v8::HandleScope scope(isolate); 3262 global.Reset(isolate, v8_str("str")); 3263 } 3264 { 3265 v8::HandleScope scope(isolate); 3266 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3267 } 3268 global.Reset(); 3269 } 3270 3271 3272 THREADED_TEST(ResettingGlobalHandle) { 3273 v8::Isolate* isolate = CcTest::isolate(); 3274 v8::Persistent<String> global; 3275 { 3276 v8::HandleScope scope(isolate); 3277 global.Reset(isolate, v8_str("str")); 3278 } 3279 v8::internal::GlobalHandles* global_handles = 3280 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3281 int initial_handle_count = global_handles->global_handles_count(); 3282 { 3283 v8::HandleScope scope(isolate); 3284 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3285 } 3286 { 3287 v8::HandleScope scope(isolate); 3288 global.Reset(isolate, v8_str("longer")); 3289 } 3290 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3291 { 3292 v8::HandleScope scope(isolate); 3293 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3294 } 3295 global.Reset(); 3296 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3297 } 3298 3299 3300 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3301 v8::Isolate* isolate = CcTest::isolate(); 3302 v8::Persistent<String> global; 3303 { 3304 v8::HandleScope scope(isolate); 3305 global.Reset(isolate, v8_str("str")); 3306 } 3307 v8::internal::GlobalHandles* global_handles = 3308 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3309 int initial_handle_count = global_handles->global_handles_count(); 3310 { 3311 v8::HandleScope scope(isolate); 3312 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3313 } 3314 { 3315 v8::HandleScope scope(isolate); 3316 Local<String> empty; 3317 global.Reset(isolate, empty); 3318 } 3319 CHECK(global.IsEmpty()); 3320 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3321 } 3322 3323 3324 template<class T> 3325 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) { 3326 return unique.Pass(); 3327 } 3328 3329 3330 template<class T> 3331 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate, 3332 const v8::Persistent<T> & global) { 3333 v8::UniquePersistent<String> unique(isolate, global); 3334 return unique.Pass(); 3335 } 3336 3337 3338 THREADED_TEST(UniquePersistent) { 3339 v8::Isolate* isolate = CcTest::isolate(); 3340 v8::Persistent<String> global; 3341 { 3342 v8::HandleScope scope(isolate); 3343 global.Reset(isolate, v8_str("str")); 3344 } 3345 v8::internal::GlobalHandles* global_handles = 3346 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3347 int initial_handle_count = global_handles->global_handles_count(); 3348 { 3349 v8::UniquePersistent<String> unique(isolate, global); 3350 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3351 // Test assignment via Pass 3352 { 3353 v8::UniquePersistent<String> copy = unique.Pass(); 3354 CHECK(unique.IsEmpty()); 3355 CHECK(copy == global); 3356 CHECK_EQ(initial_handle_count + 1, 3357 global_handles->global_handles_count()); 3358 unique = copy.Pass(); 3359 } 3360 // Test ctor via Pass 3361 { 3362 v8::UniquePersistent<String> copy(unique.Pass()); 3363 CHECK(unique.IsEmpty()); 3364 CHECK(copy == global); 3365 CHECK_EQ(initial_handle_count + 1, 3366 global_handles->global_handles_count()); 3367 unique = copy.Pass(); 3368 } 3369 // Test pass through function call 3370 { 3371 v8::UniquePersistent<String> copy = PassUnique(unique.Pass()); 3372 CHECK(unique.IsEmpty()); 3373 CHECK(copy == global); 3374 CHECK_EQ(initial_handle_count + 1, 3375 global_handles->global_handles_count()); 3376 unique = copy.Pass(); 3377 } 3378 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3379 } 3380 // Test pass from function call 3381 { 3382 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global); 3383 CHECK(unique == global); 3384 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); 3385 } 3386 CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); 3387 global.Reset(); 3388 } 3389 3390 3391 THREADED_TEST(GlobalHandleUpcast) { 3392 v8::Isolate* isolate = CcTest::isolate(); 3393 v8::HandleScope scope(isolate); 3394 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str")); 3395 v8::Persistent<String> global_string(isolate, local); 3396 v8::Persistent<Value>& global_value = 3397 v8::Persistent<Value>::Cast(global_string); 3398 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 3399 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 3400 global_string.Reset(); 3401 } 3402 3403 3404 THREADED_TEST(HandleEquality) { 3405 v8::Isolate* isolate = CcTest::isolate(); 3406 v8::Persistent<String> global1; 3407 v8::Persistent<String> global2; 3408 { 3409 v8::HandleScope scope(isolate); 3410 global1.Reset(isolate, v8_str("str")); 3411 global2.Reset(isolate, v8_str("str2")); 3412 } 3413 CHECK_EQ(global1 == global1, true); 3414 CHECK_EQ(global1 != global1, false); 3415 { 3416 v8::HandleScope scope(isolate); 3417 Local<String> local1 = Local<String>::New(isolate, global1); 3418 Local<String> local2 = Local<String>::New(isolate, global2); 3419 3420 CHECK_EQ(global1 == local1, true); 3421 CHECK_EQ(global1 != local1, false); 3422 CHECK_EQ(local1 == global1, true); 3423 CHECK_EQ(local1 != global1, false); 3424 3425 CHECK_EQ(global1 == local2, false); 3426 CHECK_EQ(global1 != local2, true); 3427 CHECK_EQ(local2 == global1, false); 3428 CHECK_EQ(local2 != global1, true); 3429 3430 CHECK_EQ(local1 == local2, false); 3431 CHECK_EQ(local1 != local2, true); 3432 3433 Local<String> anotherLocal1 = Local<String>::New(isolate, global1); 3434 CHECK_EQ(local1 == anotherLocal1, true); 3435 CHECK_EQ(local1 != anotherLocal1, false); 3436 } 3437 global1.Reset(); 3438 global2.Reset(); 3439 } 3440 3441 3442 THREADED_TEST(LocalHandle) { 3443 v8::HandleScope scope(CcTest::isolate()); 3444 v8::Local<String> local = 3445 v8::Local<String>::New(CcTest::isolate(), v8_str("str")); 3446 CHECK_EQ(local->Length(), 3); 3447 } 3448 3449 3450 class WeakCallCounter { 3451 public: 3452 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } 3453 int id() { return id_; } 3454 void increment() { number_of_weak_calls_++; } 3455 int NumberOfWeakCalls() { return number_of_weak_calls_; } 3456 private: 3457 int id_; 3458 int number_of_weak_calls_; 3459 }; 3460 3461 3462 template<typename T> 3463 struct WeakCallCounterAndPersistent { 3464 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) 3465 : counter(counter) {} 3466 WeakCallCounter* counter; 3467 v8::Persistent<T> handle; 3468 }; 3469 3470 3471 template <typename T> 3472 static void WeakPointerCallback( 3473 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) { 3474 CHECK_EQ(1234, data.GetParameter()->counter->id()); 3475 data.GetParameter()->counter->increment(); 3476 data.GetParameter()->handle.Reset(); 3477 } 3478 3479 3480 template<typename T> 3481 static UniqueId MakeUniqueId(const Persistent<T>& p) { 3482 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 3483 } 3484 3485 3486 THREADED_TEST(ApiObjectGroups) { 3487 LocalContext env; 3488 v8::Isolate* iso = env->GetIsolate(); 3489 HandleScope scope(iso); 3490 3491 WeakCallCounter counter(1234); 3492 3493 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3494 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3495 WeakCallCounterAndPersistent<Value> g1c1(&counter); 3496 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3497 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3498 WeakCallCounterAndPersistent<Value> g2c1(&counter); 3499 3500 { 3501 HandleScope scope(iso); 3502 g1s1.handle.Reset(iso, Object::New()); 3503 g1s2.handle.Reset(iso, Object::New()); 3504 g1c1.handle.Reset(iso, Object::New()); 3505 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3506 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3507 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3508 3509 g2s1.handle.Reset(iso, Object::New()); 3510 g2s2.handle.Reset(iso, Object::New()); 3511 g2c1.handle.Reset(iso, Object::New()); 3512 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3513 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3514 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3515 } 3516 3517 WeakCallCounterAndPersistent<Value> root(&counter); 3518 root.handle.Reset(iso, g1s1.handle); // make a root. 3519 3520 // Connect group 1 and 2, make a cycle. 3521 { 3522 HandleScope scope(iso); 3523 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())-> 3524 Set(0, Local<Value>::New(iso, g2s2.handle))); 3525 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())-> 3526 Set(0, Local<Value>::New(iso, g1s1.handle))); 3527 } 3528 3529 { 3530 UniqueId id1 = MakeUniqueId(g1s1.handle); 3531 UniqueId id2 = MakeUniqueId(g2s2.handle); 3532 iso->SetObjectGroupId(g1s1.handle, id1); 3533 iso->SetObjectGroupId(g1s2.handle, id1); 3534 iso->SetReferenceFromGroup(id1, g1c1.handle); 3535 iso->SetObjectGroupId(g2s1.handle, id2); 3536 iso->SetObjectGroupId(g2s2.handle, id2); 3537 iso->SetReferenceFromGroup(id2, g2c1.handle); 3538 } 3539 // Do a single full GC, ensure incremental marking is stopped. 3540 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3541 iso)->heap(); 3542 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3543 3544 // All object should be alive. 3545 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3546 3547 // Weaken the root. 3548 root.handle.SetWeak(&root, &WeakPointerCallback); 3549 // But make children strong roots---all the objects (except for children) 3550 // should be collectable now. 3551 g1c1.handle.ClearWeak(); 3552 g2c1.handle.ClearWeak(); 3553 3554 // Groups are deleted, rebuild groups. 3555 { 3556 UniqueId id1 = MakeUniqueId(g1s1.handle); 3557 UniqueId id2 = MakeUniqueId(g2s2.handle); 3558 iso->SetObjectGroupId(g1s1.handle, id1); 3559 iso->SetObjectGroupId(g1s2.handle, id1); 3560 iso->SetReferenceFromGroup(id1, g1c1.handle); 3561 iso->SetObjectGroupId(g2s1.handle, id2); 3562 iso->SetObjectGroupId(g2s2.handle, id2); 3563 iso->SetReferenceFromGroup(id2, g2c1.handle); 3564 } 3565 3566 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3567 3568 // All objects should be gone. 5 global handles in total. 3569 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3570 3571 // And now make children weak again and collect them. 3572 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3573 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3574 3575 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3576 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3577 } 3578 3579 3580 THREADED_TEST(ApiObjectGroupsForSubtypes) { 3581 LocalContext env; 3582 v8::Isolate* iso = env->GetIsolate(); 3583 HandleScope scope(iso); 3584 3585 WeakCallCounter counter(1234); 3586 3587 WeakCallCounterAndPersistent<Object> g1s1(&counter); 3588 WeakCallCounterAndPersistent<String> g1s2(&counter); 3589 WeakCallCounterAndPersistent<String> g1c1(&counter); 3590 WeakCallCounterAndPersistent<Object> g2s1(&counter); 3591 WeakCallCounterAndPersistent<String> g2s2(&counter); 3592 WeakCallCounterAndPersistent<String> g2c1(&counter); 3593 3594 { 3595 HandleScope scope(iso); 3596 g1s1.handle.Reset(iso, Object::New()); 3597 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1")); 3598 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2")); 3599 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3600 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3601 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3602 3603 g2s1.handle.Reset(iso, Object::New()); 3604 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3")); 3605 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4")); 3606 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3607 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3608 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3609 } 3610 3611 WeakCallCounterAndPersistent<Value> root(&counter); 3612 root.handle.Reset(iso, g1s1.handle); // make a root. 3613 3614 // Connect group 1 and 2, make a cycle. 3615 { 3616 HandleScope scope(iso); 3617 CHECK(Local<Object>::New(iso, g1s1.handle) 3618 ->Set(0, Local<Object>::New(iso, g2s1.handle))); 3619 CHECK(Local<Object>::New(iso, g2s1.handle) 3620 ->Set(0, Local<Object>::New(iso, g1s1.handle))); 3621 } 3622 3623 { 3624 UniqueId id1 = MakeUniqueId(g1s1.handle); 3625 UniqueId id2 = MakeUniqueId(g2s2.handle); 3626 iso->SetObjectGroupId(g1s1.handle, id1); 3627 iso->SetObjectGroupId(g1s2.handle, id1); 3628 iso->SetReference(g1s1.handle, g1c1.handle); 3629 iso->SetObjectGroupId(g2s1.handle, id2); 3630 iso->SetObjectGroupId(g2s2.handle, id2); 3631 iso->SetReferenceFromGroup(id2, g2c1.handle); 3632 } 3633 // Do a single full GC, ensure incremental marking is stopped. 3634 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3635 iso)->heap(); 3636 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3637 3638 // All object should be alive. 3639 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3640 3641 // Weaken the root. 3642 root.handle.SetWeak(&root, &WeakPointerCallback); 3643 // But make children strong roots---all the objects (except for children) 3644 // should be collectable now. 3645 g1c1.handle.ClearWeak(); 3646 g2c1.handle.ClearWeak(); 3647 3648 // Groups are deleted, rebuild groups. 3649 { 3650 UniqueId id1 = MakeUniqueId(g1s1.handle); 3651 UniqueId id2 = MakeUniqueId(g2s2.handle); 3652 iso->SetObjectGroupId(g1s1.handle, id1); 3653 iso->SetObjectGroupId(g1s2.handle, id1); 3654 iso->SetReference(g1s1.handle, g1c1.handle); 3655 iso->SetObjectGroupId(g2s1.handle, id2); 3656 iso->SetObjectGroupId(g2s2.handle, id2); 3657 iso->SetReferenceFromGroup(id2, g2c1.handle); 3658 } 3659 3660 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3661 3662 // All objects should be gone. 5 global handles in total. 3663 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3664 3665 // And now make children weak again and collect them. 3666 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); 3667 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); 3668 3669 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3670 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3671 } 3672 3673 3674 THREADED_TEST(ApiObjectGroupsCycle) { 3675 LocalContext env; 3676 v8::Isolate* iso = env->GetIsolate(); 3677 HandleScope scope(iso); 3678 3679 WeakCallCounter counter(1234); 3680 3681 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3682 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3683 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3684 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3685 WeakCallCounterAndPersistent<Value> g3s1(&counter); 3686 WeakCallCounterAndPersistent<Value> g3s2(&counter); 3687 WeakCallCounterAndPersistent<Value> g4s1(&counter); 3688 WeakCallCounterAndPersistent<Value> g4s2(&counter); 3689 3690 { 3691 HandleScope scope(iso); 3692 g1s1.handle.Reset(iso, Object::New()); 3693 g1s2.handle.Reset(iso, Object::New()); 3694 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3695 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3696 CHECK(g1s1.handle.IsWeak()); 3697 CHECK(g1s2.handle.IsWeak()); 3698 3699 g2s1.handle.Reset(iso, Object::New()); 3700 g2s2.handle.Reset(iso, Object::New()); 3701 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3702 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3703 CHECK(g2s1.handle.IsWeak()); 3704 CHECK(g2s2.handle.IsWeak()); 3705 3706 g3s1.handle.Reset(iso, Object::New()); 3707 g3s2.handle.Reset(iso, Object::New()); 3708 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 3709 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 3710 CHECK(g3s1.handle.IsWeak()); 3711 CHECK(g3s2.handle.IsWeak()); 3712 3713 g4s1.handle.Reset(iso, Object::New()); 3714 g4s2.handle.Reset(iso, Object::New()); 3715 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback); 3716 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback); 3717 CHECK(g4s1.handle.IsWeak()); 3718 CHECK(g4s2.handle.IsWeak()); 3719 } 3720 3721 WeakCallCounterAndPersistent<Value> root(&counter); 3722 root.handle.Reset(iso, g1s1.handle); // make a root. 3723 3724 // Connect groups. We're building the following cycle: 3725 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 3726 // groups. 3727 { 3728 UniqueId id1 = MakeUniqueId(g1s1.handle); 3729 UniqueId id2 = MakeUniqueId(g2s1.handle); 3730 UniqueId id3 = MakeUniqueId(g3s1.handle); 3731 UniqueId id4 = MakeUniqueId(g4s1.handle); 3732 iso->SetObjectGroupId(g1s1.handle, id1); 3733 iso->SetObjectGroupId(g1s2.handle, id1); 3734 iso->SetReferenceFromGroup(id1, g2s1.handle); 3735 iso->SetObjectGroupId(g2s1.handle, id2); 3736 iso->SetObjectGroupId(g2s2.handle, id2); 3737 iso->SetReferenceFromGroup(id2, g3s1.handle); 3738 iso->SetObjectGroupId(g3s1.handle, id3); 3739 iso->SetObjectGroupId(g3s2.handle, id3); 3740 iso->SetReferenceFromGroup(id3, g4s1.handle); 3741 iso->SetObjectGroupId(g4s1.handle, id4); 3742 iso->SetObjectGroupId(g4s2.handle, id4); 3743 iso->SetReferenceFromGroup(id4, g1s1.handle); 3744 } 3745 // Do a single full GC 3746 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3747 iso)->heap(); 3748 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3749 3750 // All object should be alive. 3751 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3752 3753 // Weaken the root. 3754 root.handle.SetWeak(&root, &WeakPointerCallback); 3755 3756 // Groups are deleted, rebuild groups. 3757 { 3758 UniqueId id1 = MakeUniqueId(g1s1.handle); 3759 UniqueId id2 = MakeUniqueId(g2s1.handle); 3760 UniqueId id3 = MakeUniqueId(g3s1.handle); 3761 UniqueId id4 = MakeUniqueId(g4s1.handle); 3762 iso->SetObjectGroupId(g1s1.handle, id1); 3763 iso->SetObjectGroupId(g1s2.handle, id1); 3764 iso->SetReferenceFromGroup(id1, g2s1.handle); 3765 iso->SetObjectGroupId(g2s1.handle, id2); 3766 iso->SetObjectGroupId(g2s2.handle, id2); 3767 iso->SetReferenceFromGroup(id2, g3s1.handle); 3768 iso->SetObjectGroupId(g3s1.handle, id3); 3769 iso->SetObjectGroupId(g3s2.handle, id3); 3770 iso->SetReferenceFromGroup(id3, g4s1.handle); 3771 iso->SetObjectGroupId(g4s1.handle, id4); 3772 iso->SetObjectGroupId(g4s2.handle, id4); 3773 iso->SetReferenceFromGroup(id4, g1s1.handle); 3774 } 3775 3776 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3777 3778 // All objects should be gone. 9 global handles in total. 3779 CHECK_EQ(9, counter.NumberOfWeakCalls()); 3780 } 3781 3782 3783 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures 3784 // on the buildbots, so was made non-threaded for the time being. 3785 TEST(ApiObjectGroupsCycleForScavenger) { 3786 i::FLAG_stress_compaction = false; 3787 i::FLAG_gc_global = false; 3788 LocalContext env; 3789 v8::Isolate* iso = env->GetIsolate(); 3790 HandleScope scope(iso); 3791 3792 WeakCallCounter counter(1234); 3793 3794 WeakCallCounterAndPersistent<Value> g1s1(&counter); 3795 WeakCallCounterAndPersistent<Value> g1s2(&counter); 3796 WeakCallCounterAndPersistent<Value> g2s1(&counter); 3797 WeakCallCounterAndPersistent<Value> g2s2(&counter); 3798 WeakCallCounterAndPersistent<Value> g3s1(&counter); 3799 WeakCallCounterAndPersistent<Value> g3s2(&counter); 3800 3801 { 3802 HandleScope scope(iso); 3803 g1s1.handle.Reset(iso, Object::New()); 3804 g1s2.handle.Reset(iso, Object::New()); 3805 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); 3806 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); 3807 3808 g2s1.handle.Reset(iso, Object::New()); 3809 g2s2.handle.Reset(iso, Object::New()); 3810 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); 3811 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); 3812 3813 g3s1.handle.Reset(iso, Object::New()); 3814 g3s2.handle.Reset(iso, Object::New()); 3815 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); 3816 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); 3817 } 3818 3819 // Make a root. 3820 WeakCallCounterAndPersistent<Value> root(&counter); 3821 root.handle.Reset(iso, g1s1.handle); 3822 root.handle.MarkPartiallyDependent(); 3823 3824 // Connect groups. We're building the following cycle: 3825 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 3826 // groups. 3827 { 3828 HandleScope handle_scope(iso); 3829 g1s1.handle.MarkPartiallyDependent(); 3830 g1s2.handle.MarkPartiallyDependent(); 3831 g2s1.handle.MarkPartiallyDependent(); 3832 g2s2.handle.MarkPartiallyDependent(); 3833 g3s1.handle.MarkPartiallyDependent(); 3834 g3s2.handle.MarkPartiallyDependent(); 3835 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 3836 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 3837 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 3838 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 3839 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 3840 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 3841 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 3842 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 3843 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 3844 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 3845 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 3846 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 3847 } 3848 3849 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3850 iso)->heap(); 3851 heap->CollectGarbage(i::NEW_SPACE); 3852 3853 // All objects should be alive. 3854 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3855 3856 // Weaken the root. 3857 root.handle.SetWeak(&root, &WeakPointerCallback); 3858 root.handle.MarkPartiallyDependent(); 3859 3860 // Groups are deleted, rebuild groups. 3861 { 3862 HandleScope handle_scope(iso); 3863 g1s1.handle.MarkPartiallyDependent(); 3864 g1s2.handle.MarkPartiallyDependent(); 3865 g2s1.handle.MarkPartiallyDependent(); 3866 g2s2.handle.MarkPartiallyDependent(); 3867 g3s1.handle.MarkPartiallyDependent(); 3868 g3s2.handle.MarkPartiallyDependent(); 3869 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); 3870 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); 3871 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( 3872 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); 3873 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); 3874 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); 3875 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( 3876 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); 3877 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); 3878 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); 3879 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( 3880 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); 3881 } 3882 3883 heap->CollectGarbage(i::NEW_SPACE); 3884 3885 // All objects should be gone. 7 global handles in total. 3886 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3887 } 3888 3889 3890 THREADED_TEST(ScriptException) { 3891 LocalContext env; 3892 v8::HandleScope scope(env->GetIsolate()); 3893 Local<Script> script = Script::Compile(v8_str("throw 'panama!';")); 3894 v8::TryCatch try_catch; 3895 Local<Value> result = script->Run(); 3896 CHECK(result.IsEmpty()); 3897 CHECK(try_catch.HasCaught()); 3898 String::Utf8Value exception_value(try_catch.Exception()); 3899 CHECK_EQ(*exception_value, "panama!"); 3900 } 3901 3902 3903 TEST(TryCatchCustomException) { 3904 LocalContext env; 3905 v8::HandleScope scope(env->GetIsolate()); 3906 v8::TryCatch try_catch; 3907 CompileRun("function CustomError() { this.a = 'b'; }" 3908 "(function f() { throw new CustomError(); })();"); 3909 CHECK(try_catch.HasCaught()); 3910 CHECK(try_catch.Exception()->ToObject()-> 3911 Get(v8_str("a"))->Equals(v8_str("b"))); 3912 } 3913 3914 3915 bool message_received; 3916 3917 3918 static void check_message_0(v8::Handle<v8::Message> message, 3919 v8::Handle<Value> data) { 3920 CHECK_EQ(5.76, data->NumberValue()); 3921 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3922 CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); 3923 CHECK(!message->IsSharedCrossOrigin()); 3924 message_received = true; 3925 } 3926 3927 3928 THREADED_TEST(MessageHandler0) { 3929 message_received = false; 3930 v8::HandleScope scope(CcTest::isolate()); 3931 CHECK(!message_received); 3932 v8::V8::AddMessageListener(check_message_0, v8_num(5.76)); 3933 LocalContext context; 3934 v8::ScriptOrigin origin = 3935 v8::ScriptOrigin(v8_str("6.75")); 3936 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 3937 &origin); 3938 script->SetData(v8_str("7.56")); 3939 script->Run(); 3940 CHECK(message_received); 3941 // clear out the message listener 3942 v8::V8::RemoveMessageListeners(check_message_0); 3943 } 3944 3945 3946 static void check_message_1(v8::Handle<v8::Message> message, 3947 v8::Handle<Value> data) { 3948 CHECK(data->IsNumber()); 3949 CHECK_EQ(1337, data->Int32Value()); 3950 CHECK(!message->IsSharedCrossOrigin()); 3951 message_received = true; 3952 } 3953 3954 3955 TEST(MessageHandler1) { 3956 message_received = false; 3957 v8::HandleScope scope(CcTest::isolate()); 3958 CHECK(!message_received); 3959 v8::V8::AddMessageListener(check_message_1); 3960 LocalContext context; 3961 CompileRun("throw 1337;"); 3962 CHECK(message_received); 3963 // clear out the message listener 3964 v8::V8::RemoveMessageListeners(check_message_1); 3965 } 3966 3967 3968 static void check_message_2(v8::Handle<v8::Message> message, 3969 v8::Handle<Value> data) { 3970 LocalContext context; 3971 CHECK(data->IsObject()); 3972 v8::Local<v8::Value> hidden_property = 3973 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); 3974 CHECK(v8_str("hidden value")->Equals(hidden_property)); 3975 CHECK(!message->IsSharedCrossOrigin()); 3976 message_received = true; 3977 } 3978 3979 3980 TEST(MessageHandler2) { 3981 message_received = false; 3982 v8::HandleScope scope(CcTest::isolate()); 3983 CHECK(!message_received); 3984 v8::V8::AddMessageListener(check_message_2); 3985 LocalContext context; 3986 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 3987 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), 3988 v8_str("hidden value")); 3989 context->Global()->Set(v8_str("error"), error); 3990 CompileRun("throw error;"); 3991 CHECK(message_received); 3992 // clear out the message listener 3993 v8::V8::RemoveMessageListeners(check_message_2); 3994 } 3995 3996 3997 static void check_message_3(v8::Handle<v8::Message> message, 3998 v8::Handle<Value> data) { 3999 CHECK(message->IsSharedCrossOrigin()); 4000 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4001 message_received = true; 4002 } 4003 4004 4005 TEST(MessageHandler3) { 4006 message_received = false; 4007 v8::Isolate* isolate = CcTest::isolate(); 4008 v8::HandleScope scope(isolate); 4009 CHECK(!message_received); 4010 v8::V8::AddMessageListener(check_message_3); 4011 LocalContext context; 4012 v8::ScriptOrigin origin = 4013 v8::ScriptOrigin(v8_str("6.75"), 4014 v8::Integer::New(1, isolate), 4015 v8::Integer::New(2, isolate), 4016 v8::True(isolate)); 4017 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4018 &origin); 4019 script->Run(); 4020 CHECK(message_received); 4021 // clear out the message listener 4022 v8::V8::RemoveMessageListeners(check_message_3); 4023 } 4024 4025 4026 static void check_message_4(v8::Handle<v8::Message> message, 4027 v8::Handle<Value> data) { 4028 CHECK(!message->IsSharedCrossOrigin()); 4029 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4030 message_received = true; 4031 } 4032 4033 4034 TEST(MessageHandler4) { 4035 message_received = false; 4036 v8::Isolate* isolate = CcTest::isolate(); 4037 v8::HandleScope scope(isolate); 4038 CHECK(!message_received); 4039 v8::V8::AddMessageListener(check_message_4); 4040 LocalContext context; 4041 v8::ScriptOrigin origin = 4042 v8::ScriptOrigin(v8_str("6.75"), 4043 v8::Integer::New(1, isolate), 4044 v8::Integer::New(2, isolate), 4045 v8::False(isolate)); 4046 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4047 &origin); 4048 script->Run(); 4049 CHECK(message_received); 4050 // clear out the message listener 4051 v8::V8::RemoveMessageListeners(check_message_4); 4052 } 4053 4054 4055 static void check_message_5a(v8::Handle<v8::Message> message, 4056 v8::Handle<Value> data) { 4057 CHECK(message->IsSharedCrossOrigin()); 4058 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4059 message_received = true; 4060 } 4061 4062 4063 static void check_message_5b(v8::Handle<v8::Message> message, 4064 v8::Handle<Value> data) { 4065 CHECK(!message->IsSharedCrossOrigin()); 4066 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 4067 message_received = true; 4068 } 4069 4070 4071 TEST(MessageHandler5) { 4072 message_received = false; 4073 v8::Isolate* isolate = CcTest::isolate(); 4074 v8::HandleScope scope(isolate); 4075 CHECK(!message_received); 4076 v8::V8::AddMessageListener(check_message_5a); 4077 LocalContext context; 4078 v8::ScriptOrigin origin = 4079 v8::ScriptOrigin(v8_str("6.75"), 4080 v8::Integer::New(1, isolate), 4081 v8::Integer::New(2, isolate), 4082 v8::True(isolate)); 4083 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 4084 &origin); 4085 script->Run(); 4086 CHECK(message_received); 4087 // clear out the message listener 4088 v8::V8::RemoveMessageListeners(check_message_5a); 4089 4090 message_received = false; 4091 v8::V8::AddMessageListener(check_message_5b); 4092 origin = 4093 v8::ScriptOrigin(v8_str("6.75"), 4094 v8::Integer::New(1, isolate), 4095 v8::Integer::New(2, isolate), 4096 v8::False(isolate)); 4097 script = Script::Compile(v8_str("throw 'error'"), 4098 &origin); 4099 script->Run(); 4100 CHECK(message_received); 4101 // clear out the message listener 4102 v8::V8::RemoveMessageListeners(check_message_5b); 4103 } 4104 4105 4106 THREADED_TEST(GetSetProperty) { 4107 LocalContext context; 4108 v8::HandleScope scope(context->GetIsolate()); 4109 context->Global()->Set(v8_str("foo"), v8_num(14)); 4110 context->Global()->Set(v8_str("12"), v8_num(92)); 4111 context->Global()->Set(v8::Integer::New(16), v8_num(32)); 4112 context->Global()->Set(v8_num(13), v8_num(56)); 4113 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run(); 4114 CHECK_EQ(14, foo->Int32Value()); 4115 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run(); 4116 CHECK_EQ(92, twelve->Int32Value()); 4117 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run(); 4118 CHECK_EQ(32, sixteen->Int32Value()); 4119 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run(); 4120 CHECK_EQ(56, thirteen->Int32Value()); 4121 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value()); 4122 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value()); 4123 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value()); 4124 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value()); 4125 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value()); 4126 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value()); 4127 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value()); 4128 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value()); 4129 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value()); 4130 } 4131 4132 4133 THREADED_TEST(PropertyAttributes) { 4134 LocalContext context; 4135 v8::HandleScope scope(context->GetIsolate()); 4136 // none 4137 Local<String> prop = v8_str("none"); 4138 context->Global()->Set(prop, v8_num(7)); 4139 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4140 // read-only 4141 prop = v8_str("read_only"); 4142 context->Global()->Set(prop, v8_num(7), v8::ReadOnly); 4143 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4144 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); 4145 Script::Compile(v8_str("read_only = 9"))->Run(); 4146 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4147 context->Global()->Set(prop, v8_num(10)); 4148 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 4149 // dont-delete 4150 prop = v8_str("dont_delete"); 4151 context->Global()->Set(prop, v8_num(13), v8::DontDelete); 4152 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4153 Script::Compile(v8_str("delete dont_delete"))->Run(); 4154 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 4155 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); 4156 // dont-enum 4157 prop = v8_str("dont_enum"); 4158 context->Global()->Set(prop, v8_num(28), v8::DontEnum); 4159 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); 4160 // absent 4161 prop = v8_str("absent"); 4162 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 4163 Local<Value> fake_prop = v8_num(1); 4164 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); 4165 // exception 4166 TryCatch try_catch; 4167 Local<Value> exception = 4168 CompileRun("({ toString: function() { throw 'exception';} })"); 4169 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); 4170 CHECK(try_catch.HasCaught()); 4171 String::Utf8Value exception_value(try_catch.Exception()); 4172 CHECK_EQ("exception", *exception_value); 4173 try_catch.Reset(); 4174 } 4175 4176 4177 THREADED_TEST(Array) { 4178 LocalContext context; 4179 v8::HandleScope scope(context->GetIsolate()); 4180 Local<v8::Array> array = v8::Array::New(context->GetIsolate()); 4181 CHECK_EQ(0, array->Length()); 4182 CHECK(array->Get(0)->IsUndefined()); 4183 CHECK(!array->Has(0)); 4184 CHECK(array->Get(100)->IsUndefined()); 4185 CHECK(!array->Has(100)); 4186 array->Set(2, v8_num(7)); 4187 CHECK_EQ(3, array->Length()); 4188 CHECK(!array->Has(0)); 4189 CHECK(!array->Has(1)); 4190 CHECK(array->Has(2)); 4191 CHECK_EQ(7, array->Get(2)->Int32Value()); 4192 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run(); 4193 Local<v8::Array> arr = obj.As<v8::Array>(); 4194 CHECK_EQ(3, arr->Length()); 4195 CHECK_EQ(1, arr->Get(0)->Int32Value()); 4196 CHECK_EQ(2, arr->Get(1)->Int32Value()); 4197 CHECK_EQ(3, arr->Get(2)->Int32Value()); 4198 array = v8::Array::New(context->GetIsolate(), 27); 4199 CHECK_EQ(27, array->Length()); 4200 array = v8::Array::New(context->GetIsolate(), -27); 4201 CHECK_EQ(0, array->Length()); 4202 } 4203 4204 4205 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 4206 v8::HandleScope scope(args.GetIsolate()); 4207 ApiTestFuzzer::Fuzz(); 4208 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length()); 4209 for (int i = 0; i < args.Length(); i++) 4210 result->Set(i, args[i]); 4211 args.GetReturnValue().Set(scope.Close(result)); 4212 } 4213 4214 4215 THREADED_TEST(Vector) { 4216 v8::HandleScope scope(CcTest::isolate()); 4217 Local<ObjectTemplate> global = ObjectTemplate::New(); 4218 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF)); 4219 LocalContext context(0, global); 4220 4221 const char* fun = "f()"; 4222 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 4223 CHECK_EQ(0, a0->Length()); 4224 4225 const char* fun2 = "f(11)"; 4226 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 4227 CHECK_EQ(1, a1->Length()); 4228 CHECK_EQ(11, a1->Get(0)->Int32Value()); 4229 4230 const char* fun3 = "f(12, 13)"; 4231 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 4232 CHECK_EQ(2, a2->Length()); 4233 CHECK_EQ(12, a2->Get(0)->Int32Value()); 4234 CHECK_EQ(13, a2->Get(1)->Int32Value()); 4235 4236 const char* fun4 = "f(14, 15, 16)"; 4237 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 4238 CHECK_EQ(3, a3->Length()); 4239 CHECK_EQ(14, a3->Get(0)->Int32Value()); 4240 CHECK_EQ(15, a3->Get(1)->Int32Value()); 4241 CHECK_EQ(16, a3->Get(2)->Int32Value()); 4242 4243 const char* fun5 = "f(17, 18, 19, 20)"; 4244 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 4245 CHECK_EQ(4, a4->Length()); 4246 CHECK_EQ(17, a4->Get(0)->Int32Value()); 4247 CHECK_EQ(18, a4->Get(1)->Int32Value()); 4248 CHECK_EQ(19, a4->Get(2)->Int32Value()); 4249 CHECK_EQ(20, a4->Get(3)->Int32Value()); 4250 } 4251 4252 4253 THREADED_TEST(FunctionCall) { 4254 LocalContext context; 4255 v8::Isolate* isolate = context->GetIsolate(); 4256 v8::HandleScope scope(isolate); 4257 CompileRun( 4258 "function Foo() {" 4259 " var result = [];" 4260 " for (var i = 0; i < arguments.length; i++) {" 4261 " result.push(arguments[i]);" 4262 " }" 4263 " return result;" 4264 "}" 4265 "function ReturnThisSloppy() {" 4266 " return this;" 4267 "}" 4268 "function ReturnThisStrict() {" 4269 " 'use strict';" 4270 " return this;" 4271 "}"); 4272 Local<Function> Foo = 4273 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4274 Local<Function> ReturnThisSloppy = 4275 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy"))); 4276 Local<Function> ReturnThisStrict = 4277 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict"))); 4278 4279 v8::Handle<Value>* args0 = NULL; 4280 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0)); 4281 CHECK_EQ(0, a0->Length()); 4282 4283 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4284 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1)); 4285 CHECK_EQ(1, a1->Length()); 4286 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 4287 4288 v8::Handle<Value> args2[] = { v8_num(2.2), 4289 v8_num(3.3) }; 4290 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2)); 4291 CHECK_EQ(2, a2->Length()); 4292 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 4293 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 4294 4295 v8::Handle<Value> args3[] = { v8_num(4.4), 4296 v8_num(5.5), 4297 v8_num(6.6) }; 4298 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3)); 4299 CHECK_EQ(3, a3->Length()); 4300 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 4301 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 4302 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 4303 4304 v8::Handle<Value> args4[] = { v8_num(7.7), 4305 v8_num(8.8), 4306 v8_num(9.9), 4307 v8_num(10.11) }; 4308 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4)); 4309 CHECK_EQ(4, a4->Length()); 4310 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 4311 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 4312 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 4313 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 4314 4315 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL); 4316 CHECK(r1->StrictEquals(context->Global())); 4317 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL); 4318 CHECK(r2->StrictEquals(context->Global())); 4319 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL); 4320 CHECK(r3->IsNumberObject()); 4321 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf()); 4322 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL); 4323 CHECK(r4->IsStringObject()); 4324 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 4325 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL); 4326 CHECK(r5->IsBooleanObject()); 4327 CHECK(r5.As<v8::BooleanObject>()->ValueOf()); 4328 4329 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL); 4330 CHECK(r6->IsUndefined()); 4331 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL); 4332 CHECK(r7->IsNull()); 4333 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL); 4334 CHECK(r8->StrictEquals(v8_num(42))); 4335 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL); 4336 CHECK(r9->StrictEquals(v8_str("hello"))); 4337 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL); 4338 CHECK(r10->StrictEquals(v8::True(isolate))); 4339 } 4340 4341 4342 static const char* js_code_causing_out_of_memory = 4343 "var a = new Array(); while(true) a.push(a);"; 4344 4345 4346 // These tests run for a long time and prevent us from running tests 4347 // that come after them so they cannot run in parallel. 4348 TEST(OutOfMemory) { 4349 // It's not possible to read a snapshot into a heap with different dimensions. 4350 if (i::Snapshot::IsEnabled()) return; 4351 // Set heap limits. 4352 static const int K = 1024; 4353 v8::ResourceConstraints constraints; 4354 constraints.set_max_young_space_size(256 * K); 4355 constraints.set_max_old_space_size(5 * K * K); 4356 v8::SetResourceConstraints(CcTest::isolate(), &constraints); 4357 4358 // Execute a script that causes out of memory. 4359 LocalContext context; 4360 v8::HandleScope scope(context->GetIsolate()); 4361 v8::V8::IgnoreOutOfMemoryException(); 4362 Local<Script> script = Script::Compile(String::NewFromUtf8( 4363 context->GetIsolate(), js_code_causing_out_of_memory)); 4364 Local<Value> result = script->Run(); 4365 4366 // Check for out of memory state. 4367 CHECK(result.IsEmpty()); 4368 CHECK(context->HasOutOfMemoryException()); 4369 } 4370 4371 4372 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { 4373 ApiTestFuzzer::Fuzz(); 4374 4375 LocalContext context; 4376 v8::HandleScope scope(context->GetIsolate()); 4377 Local<Script> script = Script::Compile(String::NewFromUtf8( 4378 context->GetIsolate(), js_code_causing_out_of_memory)); 4379 Local<Value> result = script->Run(); 4380 4381 // Check for out of memory state. 4382 CHECK(result.IsEmpty()); 4383 CHECK(context->HasOutOfMemoryException()); 4384 4385 args.GetReturnValue().Set(result); 4386 } 4387 4388 4389 TEST(OutOfMemoryNested) { 4390 // It's not possible to read a snapshot into a heap with different dimensions. 4391 if (i::Snapshot::IsEnabled()) return; 4392 // Set heap limits. 4393 static const int K = 1024; 4394 v8::ResourceConstraints constraints; 4395 constraints.set_max_young_space_size(256 * K); 4396 constraints.set_max_old_space_size(5 * K * K); 4397 v8::SetResourceConstraints(CcTest::isolate(), &constraints); 4398 4399 v8::HandleScope scope(CcTest::isolate()); 4400 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4401 templ->Set(v8_str("ProvokeOutOfMemory"), 4402 v8::FunctionTemplate::New(ProvokeOutOfMemory)); 4403 LocalContext context(0, templ); 4404 v8::V8::IgnoreOutOfMemoryException(); 4405 Local<Value> result = CompileRun( 4406 "var thrown = false;" 4407 "try {" 4408 " ProvokeOutOfMemory();" 4409 "} catch (e) {" 4410 " thrown = true;" 4411 "}"); 4412 // Check for out of memory state. 4413 CHECK(result.IsEmpty()); 4414 CHECK(context->HasOutOfMemoryException()); 4415 } 4416 4417 4418 TEST(HugeConsStringOutOfMemory) { 4419 // It's not possible to read a snapshot into a heap with different dimensions. 4420 if (i::Snapshot::IsEnabled()) return; 4421 // Set heap limits. 4422 static const int K = 1024; 4423 v8::ResourceConstraints constraints; 4424 constraints.set_max_young_space_size(256 * K); 4425 constraints.set_max_old_space_size(4 * K * K); 4426 v8::SetResourceConstraints(CcTest::isolate(), &constraints); 4427 4428 // Execute a script that causes out of memory. 4429 v8::V8::IgnoreOutOfMemoryException(); 4430 4431 LocalContext context; 4432 v8::HandleScope scope(context->GetIsolate()); 4433 4434 // Build huge string. This should fail with out of memory exception. 4435 Local<Value> result = CompileRun( 4436 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();" 4437 "for (var i = 0; i < 22; i++) { str = str + str; }"); 4438 4439 // Check for out of memory state. 4440 CHECK(result.IsEmpty()); 4441 CHECK(context->HasOutOfMemoryException()); 4442 } 4443 4444 4445 THREADED_TEST(ConstructCall) { 4446 LocalContext context; 4447 v8::HandleScope scope(context->GetIsolate()); 4448 CompileRun( 4449 "function Foo() {" 4450 " var result = [];" 4451 " for (var i = 0; i < arguments.length; i++) {" 4452 " result.push(arguments[i]);" 4453 " }" 4454 " return result;" 4455 "}"); 4456 Local<Function> Foo = 4457 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4458 4459 v8::Handle<Value>* args0 = NULL; 4460 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0)); 4461 CHECK_EQ(0, a0->Length()); 4462 4463 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4464 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1)); 4465 CHECK_EQ(1, a1->Length()); 4466 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 4467 4468 v8::Handle<Value> args2[] = { v8_num(2.2), 4469 v8_num(3.3) }; 4470 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2)); 4471 CHECK_EQ(2, a2->Length()); 4472 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 4473 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 4474 4475 v8::Handle<Value> args3[] = { v8_num(4.4), 4476 v8_num(5.5), 4477 v8_num(6.6) }; 4478 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3)); 4479 CHECK_EQ(3, a3->Length()); 4480 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 4481 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 4482 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 4483 4484 v8::Handle<Value> args4[] = { v8_num(7.7), 4485 v8_num(8.8), 4486 v8_num(9.9), 4487 v8_num(10.11) }; 4488 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4)); 4489 CHECK_EQ(4, a4->Length()); 4490 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 4491 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 4492 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 4493 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 4494 } 4495 4496 4497 static void CheckUncle(v8::TryCatch* try_catch) { 4498 CHECK(try_catch->HasCaught()); 4499 String::Utf8Value str_value(try_catch->Exception()); 4500 CHECK_EQ(*str_value, "uncle?"); 4501 try_catch->Reset(); 4502 } 4503 4504 4505 THREADED_TEST(ConversionNumber) { 4506 LocalContext env; 4507 v8::HandleScope scope(env->GetIsolate()); 4508 // Very large number. 4509 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4510 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4511 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value()); 4512 CHECK_EQ(0, obj->ToInt32()->Value()); 4513 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned. 4514 // Large number. 4515 CompileRun("var obj = -1234567890123;"); 4516 obj = env->Global()->Get(v8_str("obj")); 4517 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value()); 4518 CHECK_EQ(-1912276171, obj->ToInt32()->Value()); 4519 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT 4520 // Small positive integer. 4521 CompileRun("var obj = 42;"); 4522 obj = env->Global()->Get(v8_str("obj")); 4523 CHECK_EQ(42.0, obj->ToNumber()->Value()); 4524 CHECK_EQ(42, obj->ToInt32()->Value()); 4525 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4526 // Negative integer. 4527 CompileRun("var obj = -37;"); 4528 obj = env->Global()->Get(v8_str("obj")); 4529 CHECK_EQ(-37.0, obj->ToNumber()->Value()); 4530 CHECK_EQ(-37, obj->ToInt32()->Value()); 4531 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT 4532 // Positive non-int32 integer. 4533 CompileRun("var obj = 0x81234567;"); 4534 obj = env->Global()->Get(v8_str("obj")); 4535 CHECK_EQ(2166572391.0, obj->ToNumber()->Value()); 4536 CHECK_EQ(-2128394905, obj->ToInt32()->Value()); 4537 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT 4538 // Fraction. 4539 CompileRun("var obj = 42.3;"); 4540 obj = env->Global()->Get(v8_str("obj")); 4541 CHECK_EQ(42.3, obj->ToNumber()->Value()); 4542 CHECK_EQ(42, obj->ToInt32()->Value()); 4543 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4544 // Large negative fraction. 4545 CompileRun("var obj = -5726623061.75;"); 4546 obj = env->Global()->Get(v8_str("obj")); 4547 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value()); 4548 CHECK_EQ(-1431655765, obj->ToInt32()->Value()); 4549 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT 4550 } 4551 4552 4553 THREADED_TEST(isNumberType) { 4554 LocalContext env; 4555 v8::HandleScope scope(env->GetIsolate()); 4556 // Very large number. 4557 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4558 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4559 CHECK(!obj->IsInt32()); 4560 CHECK(!obj->IsUint32()); 4561 // Large negative number. 4562 CompileRun("var obj = -1234567890123;"); 4563 obj = env->Global()->Get(v8_str("obj")); 4564 CHECK(!obj->IsInt32()); 4565 CHECK(!obj->IsUint32()); 4566 // Small positive integer. 4567 CompileRun("var obj = 42;"); 4568 obj = env->Global()->Get(v8_str("obj")); 4569 CHECK(obj->IsInt32()); 4570 CHECK(obj->IsUint32()); 4571 // Negative integer. 4572 CompileRun("var obj = -37;"); 4573 obj = env->Global()->Get(v8_str("obj")); 4574 CHECK(obj->IsInt32()); 4575 CHECK(!obj->IsUint32()); 4576 // Positive non-int32 integer. 4577 CompileRun("var obj = 0x81234567;"); 4578 obj = env->Global()->Get(v8_str("obj")); 4579 CHECK(!obj->IsInt32()); 4580 CHECK(obj->IsUint32()); 4581 // Fraction. 4582 CompileRun("var obj = 42.3;"); 4583 obj = env->Global()->Get(v8_str("obj")); 4584 CHECK(!obj->IsInt32()); 4585 CHECK(!obj->IsUint32()); 4586 // Large negative fraction. 4587 CompileRun("var obj = -5726623061.75;"); 4588 obj = env->Global()->Get(v8_str("obj")); 4589 CHECK(!obj->IsInt32()); 4590 CHECK(!obj->IsUint32()); 4591 // Positive zero 4592 CompileRun("var obj = 0.0;"); 4593 obj = env->Global()->Get(v8_str("obj")); 4594 CHECK(obj->IsInt32()); 4595 CHECK(obj->IsUint32()); 4596 // Positive zero 4597 CompileRun("var obj = -0.0;"); 4598 obj = env->Global()->Get(v8_str("obj")); 4599 CHECK(!obj->IsInt32()); 4600 CHECK(!obj->IsUint32()); 4601 } 4602 4603 4604 THREADED_TEST(ConversionException) { 4605 LocalContext env; 4606 v8::Isolate* isolate = env->GetIsolate(); 4607 v8::HandleScope scope(isolate); 4608 CompileRun( 4609 "function TestClass() { };" 4610 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 4611 "var obj = new TestClass();"); 4612 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4613 4614 v8::TryCatch try_catch; 4615 4616 Local<Value> to_string_result = obj->ToString(); 4617 CHECK(to_string_result.IsEmpty()); 4618 CheckUncle(&try_catch); 4619 4620 Local<Value> to_number_result = obj->ToNumber(); 4621 CHECK(to_number_result.IsEmpty()); 4622 CheckUncle(&try_catch); 4623 4624 Local<Value> to_integer_result = obj->ToInteger(); 4625 CHECK(to_integer_result.IsEmpty()); 4626 CheckUncle(&try_catch); 4627 4628 Local<Value> to_uint32_result = obj->ToUint32(); 4629 CHECK(to_uint32_result.IsEmpty()); 4630 CheckUncle(&try_catch); 4631 4632 Local<Value> to_int32_result = obj->ToInt32(); 4633 CHECK(to_int32_result.IsEmpty()); 4634 CheckUncle(&try_catch); 4635 4636 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(); 4637 CHECK(to_object_result.IsEmpty()); 4638 CHECK(try_catch.HasCaught()); 4639 try_catch.Reset(); 4640 4641 int32_t int32_value = obj->Int32Value(); 4642 CHECK_EQ(0, int32_value); 4643 CheckUncle(&try_catch); 4644 4645 uint32_t uint32_value = obj->Uint32Value(); 4646 CHECK_EQ(0, uint32_value); 4647 CheckUncle(&try_catch); 4648 4649 double number_value = obj->NumberValue(); 4650 CHECK_NE(0, std::isnan(number_value)); 4651 CheckUncle(&try_catch); 4652 4653 int64_t integer_value = obj->IntegerValue(); 4654 CHECK_EQ(0.0, static_cast<double>(integer_value)); 4655 CheckUncle(&try_catch); 4656 } 4657 4658 4659 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 4660 ApiTestFuzzer::Fuzz(); 4661 args.GetIsolate()->ThrowException(v8_str("konto")); 4662 } 4663 4664 4665 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 4666 if (args.Length() < 1) { 4667 args.GetReturnValue().Set(false); 4668 return; 4669 } 4670 v8::HandleScope scope(args.GetIsolate()); 4671 v8::TryCatch try_catch; 4672 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run(); 4673 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 4674 args.GetReturnValue().Set(try_catch.HasCaught()); 4675 } 4676 4677 4678 THREADED_TEST(APICatch) { 4679 v8::HandleScope scope(CcTest::isolate()); 4680 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4681 templ->Set(v8_str("ThrowFromC"), 4682 v8::FunctionTemplate::New(ThrowFromC)); 4683 LocalContext context(0, templ); 4684 CompileRun( 4685 "var thrown = false;" 4686 "try {" 4687 " ThrowFromC();" 4688 "} catch (e) {" 4689 " thrown = true;" 4690 "}"); 4691 Local<Value> thrown = context->Global()->Get(v8_str("thrown")); 4692 CHECK(thrown->BooleanValue()); 4693 } 4694 4695 4696 THREADED_TEST(APIThrowTryCatch) { 4697 v8::HandleScope scope(CcTest::isolate()); 4698 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4699 templ->Set(v8_str("ThrowFromC"), 4700 v8::FunctionTemplate::New(ThrowFromC)); 4701 LocalContext context(0, templ); 4702 v8::TryCatch try_catch; 4703 CompileRun("ThrowFromC();"); 4704 CHECK(try_catch.HasCaught()); 4705 } 4706 4707 4708 // Test that a try-finally block doesn't shadow a try-catch block 4709 // when setting up an external handler. 4710 // 4711 // BUG(271): Some of the exception propagation does not work on the 4712 // ARM simulator because the simulator separates the C++ stack and the 4713 // JS stack. This test therefore fails on the simulator. The test is 4714 // not threaded to allow the threading tests to run on the simulator. 4715 TEST(TryCatchInTryFinally) { 4716 v8::HandleScope scope(CcTest::isolate()); 4717 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4718 templ->Set(v8_str("CCatcher"), 4719 v8::FunctionTemplate::New(CCatcher)); 4720 LocalContext context(0, templ); 4721 Local<Value> result = CompileRun("try {" 4722 " try {" 4723 " CCatcher('throw 7;');" 4724 " } finally {" 4725 " }" 4726 "} catch (e) {" 4727 "}"); 4728 CHECK(result->IsTrue()); 4729 } 4730 4731 4732 static void check_reference_error_message( 4733 v8::Handle<v8::Message> message, 4734 v8::Handle<v8::Value> data) { 4735 const char* reference_error = "Uncaught ReferenceError: asdf is not defined"; 4736 CHECK(message->Get()->Equals(v8_str(reference_error))); 4737 } 4738 4739 4740 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) { 4741 ApiTestFuzzer::Fuzz(); 4742 CHECK(false); 4743 } 4744 4745 4746 // Test that overwritten methods are not invoked on uncaught exception 4747 // formatting. However, they are invoked when performing normal error 4748 // string conversions. 4749 TEST(APIThrowMessageOverwrittenToString) { 4750 v8::HandleScope scope(CcTest::isolate()); 4751 v8::V8::AddMessageListener(check_reference_error_message); 4752 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4753 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail)); 4754 LocalContext context(NULL, templ); 4755 CompileRun("asdf;"); 4756 CompileRun("var limit = {};" 4757 "limit.valueOf = fail;" 4758 "Error.stackTraceLimit = limit;"); 4759 CompileRun("asdf"); 4760 CompileRun("Array.prototype.pop = fail;"); 4761 CompileRun("Object.prototype.hasOwnProperty = fail;"); 4762 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); 4763 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); 4764 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); 4765 CompileRun("ReferenceError.prototype.toString =" 4766 " function() { return 'Whoops' }"); 4767 CompileRun("asdf;"); 4768 CompileRun("ReferenceError.prototype.constructor.name = void 0;"); 4769 CompileRun("asdf;"); 4770 CompileRun("ReferenceError.prototype.constructor = void 0;"); 4771 CompileRun("asdf;"); 4772 CompileRun("ReferenceError.prototype.__proto__ = new Object();"); 4773 CompileRun("asdf;"); 4774 CompileRun("ReferenceError.prototype = new Object();"); 4775 CompileRun("asdf;"); 4776 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }"); 4777 CHECK(string->Equals(v8_str("Whoops"))); 4778 CompileRun("ReferenceError.prototype.constructor = new Object();" 4779 "ReferenceError.prototype.constructor.name = 1;" 4780 "Number.prototype.toString = function() { return 'Whoops'; };" 4781 "ReferenceError.prototype.toString = Object.prototype.toString;"); 4782 CompileRun("asdf;"); 4783 v8::V8::RemoveMessageListeners(check_reference_error_message); 4784 } 4785 4786 4787 static void check_custom_error_tostring( 4788 v8::Handle<v8::Message> message, 4789 v8::Handle<v8::Value> data) { 4790 const char* uncaught_error = "Uncaught MyError toString"; 4791 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4792 } 4793 4794 4795 TEST(CustomErrorToString) { 4796 LocalContext context; 4797 v8::HandleScope scope(context->GetIsolate()); 4798 v8::V8::AddMessageListener(check_custom_error_tostring); 4799 CompileRun( 4800 "function MyError(name, message) { " 4801 " this.name = name; " 4802 " this.message = message; " 4803 "} " 4804 "MyError.prototype = Object.create(Error.prototype); " 4805 "MyError.prototype.toString = function() { " 4806 " return 'MyError toString'; " 4807 "}; " 4808 "throw new MyError('my name', 'my message'); "); 4809 v8::V8::RemoveMessageListeners(check_custom_error_tostring); 4810 } 4811 4812 4813 static void check_custom_error_message( 4814 v8::Handle<v8::Message> message, 4815 v8::Handle<v8::Value> data) { 4816 const char* uncaught_error = "Uncaught MyError: my message"; 4817 printf("%s\n", *v8::String::Utf8Value(message->Get())); 4818 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4819 } 4820 4821 4822 TEST(CustomErrorMessage) { 4823 LocalContext context; 4824 v8::HandleScope scope(context->GetIsolate()); 4825 v8::V8::AddMessageListener(check_custom_error_message); 4826 4827 // Handlebars. 4828 CompileRun( 4829 "function MyError(msg) { " 4830 " this.name = 'MyError'; " 4831 " this.message = msg; " 4832 "} " 4833 "MyError.prototype = new Error(); " 4834 "throw new MyError('my message'); "); 4835 4836 // Closure. 4837 CompileRun( 4838 "function MyError(msg) { " 4839 " this.name = 'MyError'; " 4840 " this.message = msg; " 4841 "} " 4842 "inherits = function(childCtor, parentCtor) { " 4843 " function tempCtor() {}; " 4844 " tempCtor.prototype = parentCtor.prototype; " 4845 " childCtor.superClass_ = parentCtor.prototype; " 4846 " childCtor.prototype = new tempCtor(); " 4847 " childCtor.prototype.constructor = childCtor; " 4848 "}; " 4849 "inherits(MyError, Error); " 4850 "throw new MyError('my message'); "); 4851 4852 // Object.create. 4853 CompileRun( 4854 "function MyError(msg) { " 4855 " this.name = 'MyError'; " 4856 " this.message = msg; " 4857 "} " 4858 "MyError.prototype = Object.create(Error.prototype); " 4859 "throw new MyError('my message'); "); 4860 4861 v8::V8::RemoveMessageListeners(check_custom_error_message); 4862 } 4863 4864 4865 static void receive_message(v8::Handle<v8::Message> message, 4866 v8::Handle<v8::Value> data) { 4867 message->Get(); 4868 message_received = true; 4869 } 4870 4871 4872 TEST(APIThrowMessage) { 4873 message_received = false; 4874 v8::HandleScope scope(CcTest::isolate()); 4875 v8::V8::AddMessageListener(receive_message); 4876 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4877 templ->Set(v8_str("ThrowFromC"), 4878 v8::FunctionTemplate::New(ThrowFromC)); 4879 LocalContext context(0, templ); 4880 CompileRun("ThrowFromC();"); 4881 CHECK(message_received); 4882 v8::V8::RemoveMessageListeners(receive_message); 4883 } 4884 4885 4886 TEST(APIThrowMessageAndVerboseTryCatch) { 4887 message_received = false; 4888 v8::HandleScope scope(CcTest::isolate()); 4889 v8::V8::AddMessageListener(receive_message); 4890 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4891 templ->Set(v8_str("ThrowFromC"), 4892 v8::FunctionTemplate::New(ThrowFromC)); 4893 LocalContext context(0, templ); 4894 v8::TryCatch try_catch; 4895 try_catch.SetVerbose(true); 4896 Local<Value> result = CompileRun("ThrowFromC();"); 4897 CHECK(try_catch.HasCaught()); 4898 CHECK(result.IsEmpty()); 4899 CHECK(message_received); 4900 v8::V8::RemoveMessageListeners(receive_message); 4901 } 4902 4903 4904 TEST(APIStackOverflowAndVerboseTryCatch) { 4905 message_received = false; 4906 LocalContext context; 4907 v8::HandleScope scope(context->GetIsolate()); 4908 v8::V8::AddMessageListener(receive_message); 4909 v8::TryCatch try_catch; 4910 try_catch.SetVerbose(true); 4911 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 4912 CHECK(try_catch.HasCaught()); 4913 CHECK(result.IsEmpty()); 4914 CHECK(message_received); 4915 v8::V8::RemoveMessageListeners(receive_message); 4916 } 4917 4918 4919 THREADED_TEST(ExternalScriptException) { 4920 v8::HandleScope scope(CcTest::isolate()); 4921 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4922 templ->Set(v8_str("ThrowFromC"), 4923 v8::FunctionTemplate::New(ThrowFromC)); 4924 LocalContext context(0, templ); 4925 4926 v8::TryCatch try_catch; 4927 Local<Script> script 4928 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';")); 4929 Local<Value> result = script->Run(); 4930 CHECK(result.IsEmpty()); 4931 CHECK(try_catch.HasCaught()); 4932 String::Utf8Value exception_value(try_catch.Exception()); 4933 CHECK_EQ("konto", *exception_value); 4934 } 4935 4936 4937 4938 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 4939 ApiTestFuzzer::Fuzz(); 4940 CHECK_EQ(4, args.Length()); 4941 int count = args[0]->Int32Value(); 4942 int cInterval = args[2]->Int32Value(); 4943 if (count == 0) { 4944 args.GetIsolate()->ThrowException(v8_str("FromC")); 4945 return; 4946 } else { 4947 Local<v8::Object> global = 4948 args.GetIsolate()->GetCurrentContext()->Global(); 4949 Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); 4950 v8::Handle<Value> argv[] = { v8_num(count - 1), 4951 args[1], 4952 args[2], 4953 args[3] }; 4954 if (count % cInterval == 0) { 4955 v8::TryCatch try_catch; 4956 Local<Value> result = fun.As<Function>()->Call(global, 4, argv); 4957 int expected = args[3]->Int32Value(); 4958 if (try_catch.HasCaught()) { 4959 CHECK_EQ(expected, count); 4960 CHECK(result.IsEmpty()); 4961 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 4962 } else { 4963 CHECK_NE(expected, count); 4964 } 4965 args.GetReturnValue().Set(result); 4966 return; 4967 } else { 4968 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv)); 4969 return; 4970 } 4971 } 4972 } 4973 4974 4975 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 4976 ApiTestFuzzer::Fuzz(); 4977 CHECK_EQ(3, args.Length()); 4978 bool equality = args[0]->BooleanValue(); 4979 int count = args[1]->Int32Value(); 4980 int expected = args[2]->Int32Value(); 4981 if (equality) { 4982 CHECK_EQ(count, expected); 4983 } else { 4984 CHECK_NE(count, expected); 4985 } 4986 } 4987 4988 4989 THREADED_TEST(EvalInTryFinally) { 4990 LocalContext context; 4991 v8::HandleScope scope(context->GetIsolate()); 4992 v8::TryCatch try_catch; 4993 CompileRun("(function() {" 4994 " try {" 4995 " eval('asldkf (*&^&*^');" 4996 " } finally {" 4997 " return;" 4998 " }" 4999 "})()"); 5000 CHECK(!try_catch.HasCaught()); 5001 } 5002 5003 5004 // This test works by making a stack of alternating JavaScript and C 5005 // activations. These activations set up exception handlers with regular 5006 // intervals, one interval for C activations and another for JavaScript 5007 // activations. When enough activations have been created an exception is 5008 // thrown and we check that the right activation catches the exception and that 5009 // no other activations do. The right activation is always the topmost one with 5010 // a handler, regardless of whether it is in JavaScript or C. 5011 // 5012 // The notation used to describe a test case looks like this: 5013 // 5014 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5015 // 5016 // Each entry is an activation, either JS or C. The index is the count at that 5017 // level. Stars identify activations with exception handlers, the @ identifies 5018 // the exception handler that should catch the exception. 5019 // 5020 // BUG(271): Some of the exception propagation does not work on the 5021 // ARM simulator because the simulator separates the C++ stack and the 5022 // JS stack. This test therefore fails on the simulator. The test is 5023 // not threaded to allow the threading tests to run on the simulator. 5024 TEST(ExceptionOrder) { 5025 v8::HandleScope scope(CcTest::isolate()); 5026 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5027 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck)); 5028 templ->Set(v8_str("CThrowCountDown"), 5029 v8::FunctionTemplate::New(CThrowCountDown)); 5030 LocalContext context(0, templ); 5031 CompileRun( 5032 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 5033 " if (count == 0) throw 'FromJS';" 5034 " if (count % jsInterval == 0) {" 5035 " try {" 5036 " var value = CThrowCountDown(count - 1," 5037 " jsInterval," 5038 " cInterval," 5039 " expected);" 5040 " check(false, count, expected);" 5041 " return value;" 5042 " } catch (e) {" 5043 " check(true, count, expected);" 5044 " }" 5045 " } else {" 5046 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 5047 " }" 5048 "}"); 5049 Local<Function> fun = 5050 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown"))); 5051 5052 const int argc = 4; 5053 // count jsInterval cInterval expected 5054 5055 // *JS[4] *C[3] @JS[2] C[1] JS[0] 5056 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) }; 5057 fun->Call(fun, argc, a0); 5058 5059 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 5060 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) }; 5061 fun->Call(fun, argc, a1); 5062 5063 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 5064 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) }; 5065 fun->Call(fun, argc, a2); 5066 5067 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 5068 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) }; 5069 fun->Call(fun, argc, a3); 5070 5071 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 5072 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) }; 5073 fun->Call(fun, argc, a4); 5074 5075 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 5076 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) }; 5077 fun->Call(fun, argc, a5); 5078 } 5079 5080 5081 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 5082 ApiTestFuzzer::Fuzz(); 5083 CHECK_EQ(1, args.Length()); 5084 args.GetIsolate()->ThrowException(args[0]); 5085 } 5086 5087 5088 THREADED_TEST(ThrowValues) { 5089 v8::HandleScope scope(CcTest::isolate()); 5090 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5091 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue)); 5092 LocalContext context(0, templ); 5093 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 5094 "function Run(obj) {" 5095 " try {" 5096 " Throw(obj);" 5097 " } catch (e) {" 5098 " return e;" 5099 " }" 5100 " return 'no exception';" 5101 "}" 5102 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 5103 CHECK_EQ(5, result->Length()); 5104 CHECK(result->Get(v8::Integer::New(0))->IsString()); 5105 CHECK(result->Get(v8::Integer::New(1))->IsNumber()); 5106 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value()); 5107 CHECK(result->Get(v8::Integer::New(2))->IsNumber()); 5108 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value()); 5109 CHECK(result->Get(v8::Integer::New(3))->IsNull()); 5110 CHECK(result->Get(v8::Integer::New(4))->IsUndefined()); 5111 } 5112 5113 5114 THREADED_TEST(CatchZero) { 5115 LocalContext context; 5116 v8::HandleScope scope(context->GetIsolate()); 5117 v8::TryCatch try_catch; 5118 CHECK(!try_catch.HasCaught()); 5119 Script::Compile(v8_str("throw 10"))->Run(); 5120 CHECK(try_catch.HasCaught()); 5121 CHECK_EQ(10, try_catch.Exception()->Int32Value()); 5122 try_catch.Reset(); 5123 CHECK(!try_catch.HasCaught()); 5124 Script::Compile(v8_str("throw 0"))->Run(); 5125 CHECK(try_catch.HasCaught()); 5126 CHECK_EQ(0, try_catch.Exception()->Int32Value()); 5127 } 5128 5129 5130 THREADED_TEST(CatchExceptionFromWith) { 5131 LocalContext context; 5132 v8::HandleScope scope(context->GetIsolate()); 5133 v8::TryCatch try_catch; 5134 CHECK(!try_catch.HasCaught()); 5135 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run(); 5136 CHECK(try_catch.HasCaught()); 5137 } 5138 5139 5140 THREADED_TEST(TryCatchAndFinallyHidingException) { 5141 LocalContext context; 5142 v8::HandleScope scope(context->GetIsolate()); 5143 v8::TryCatch try_catch; 5144 CHECK(!try_catch.HasCaught()); 5145 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 5146 CompileRun("f({toString: function() { throw 42; }});"); 5147 CHECK(!try_catch.HasCaught()); 5148 } 5149 5150 5151 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 5152 v8::TryCatch try_catch; 5153 } 5154 5155 5156 THREADED_TEST(TryCatchAndFinally) { 5157 LocalContext context; 5158 v8::HandleScope scope(context->GetIsolate()); 5159 context->Global()->Set( 5160 v8_str("native_with_try_catch"), 5161 v8::FunctionTemplate::New(WithTryCatch)->GetFunction()); 5162 v8::TryCatch try_catch; 5163 CHECK(!try_catch.HasCaught()); 5164 CompileRun( 5165 "try {\n" 5166 " throw new Error('a');\n" 5167 "} finally {\n" 5168 " native_with_try_catch();\n" 5169 "}\n"); 5170 CHECK(try_catch.HasCaught()); 5171 } 5172 5173 5174 static void TryCatchNestedHelper(int depth) { 5175 if (depth > 0) { 5176 v8::TryCatch try_catch; 5177 try_catch.SetVerbose(true); 5178 TryCatchNestedHelper(depth - 1); 5179 CHECK(try_catch.HasCaught()); 5180 try_catch.ReThrow(); 5181 } else { 5182 CcTest::isolate()->ThrowException(v8_str("back")); 5183 } 5184 } 5185 5186 5187 TEST(TryCatchNested) { 5188 v8::V8::Initialize(); 5189 LocalContext context; 5190 v8::HandleScope scope(context->GetIsolate()); 5191 v8::TryCatch try_catch; 5192 TryCatchNestedHelper(5); 5193 CHECK(try_catch.HasCaught()); 5194 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); 5195 } 5196 5197 5198 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 5199 CHECK(try_catch->HasCaught()); 5200 Handle<Message> message = try_catch->Message(); 5201 Handle<Value> resource = message->GetScriptResourceName(); 5202 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 5203 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()), 5204 "Uncaught Error: a")); 5205 CHECK_EQ(1, message->GetLineNumber()); 5206 CHECK_EQ(6, message->GetStartColumn()); 5207 } 5208 5209 5210 void TryCatchMixedNestingHelper( 5211 const v8::FunctionCallbackInfo<v8::Value>& args) { 5212 ApiTestFuzzer::Fuzz(); 5213 v8::TryCatch try_catch; 5214 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 5215 CHECK(try_catch.HasCaught()); 5216 TryCatchMixedNestingCheck(&try_catch); 5217 try_catch.ReThrow(); 5218 } 5219 5220 5221 // This test ensures that an outer TryCatch in the following situation: 5222 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 5223 // does not clobber the Message object generated for the inner TryCatch. 5224 // This exercises the ability of TryCatch.ReThrow() to restore the 5225 // inner pending Message before throwing the exception again. 5226 TEST(TryCatchMixedNesting) { 5227 v8::HandleScope scope(CcTest::isolate()); 5228 v8::V8::Initialize(); 5229 v8::TryCatch try_catch; 5230 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5231 templ->Set(v8_str("TryCatchMixedNestingHelper"), 5232 v8::FunctionTemplate::New(TryCatchMixedNestingHelper)); 5233 LocalContext context(0, templ); 5234 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 5235 TryCatchMixedNestingCheck(&try_catch); 5236 } 5237 5238 5239 THREADED_TEST(Equality) { 5240 LocalContext context; 5241 v8::Isolate* isolate = context->GetIsolate(); 5242 v8::HandleScope scope(context->GetIsolate()); 5243 // Check that equality works at all before relying on CHECK_EQ 5244 CHECK(v8_str("a")->Equals(v8_str("a"))); 5245 CHECK(!v8_str("a")->Equals(v8_str("b"))); 5246 5247 CHECK_EQ(v8_str("a"), v8_str("a")); 5248 CHECK_NE(v8_str("a"), v8_str("b")); 5249 CHECK_EQ(v8_num(1), v8_num(1)); 5250 CHECK_EQ(v8_num(1.00), v8_num(1)); 5251 CHECK_NE(v8_num(1), v8_num(2)); 5252 5253 // Assume String is not internalized. 5254 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 5255 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 5256 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 5257 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 5258 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 5259 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0))); 5260 Local<Value> not_a_number = v8_num(i::OS::nan_value()); 5261 CHECK(!not_a_number->StrictEquals(not_a_number)); 5262 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate))); 5263 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate))); 5264 5265 v8::Handle<v8::Object> obj = v8::Object::New(); 5266 v8::Persistent<v8::Object> alias(isolate, obj); 5267 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 5268 alias.Reset(); 5269 5270 CHECK(v8_str("a")->SameValue(v8_str("a"))); 5271 CHECK(!v8_str("a")->SameValue(v8_str("b"))); 5272 CHECK(!v8_str("5")->SameValue(v8_num(5))); 5273 CHECK(v8_num(1)->SameValue(v8_num(1))); 5274 CHECK(!v8_num(1)->SameValue(v8_num(2))); 5275 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0))); 5276 CHECK(not_a_number->SameValue(not_a_number)); 5277 CHECK(v8::False(isolate)->SameValue(v8::False(isolate))); 5278 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate))); 5279 } 5280 5281 5282 THREADED_TEST(MultiRun) { 5283 LocalContext context; 5284 v8::HandleScope scope(context->GetIsolate()); 5285 Local<Script> script = Script::Compile(v8_str("x")); 5286 for (int i = 0; i < 10; i++) 5287 script->Run(); 5288 } 5289 5290 5291 static void GetXValue(Local<String> name, 5292 const v8::PropertyCallbackInfo<v8::Value>& info) { 5293 ApiTestFuzzer::Fuzz(); 5294 CHECK_EQ(info.Data(), v8_str("donut")); 5295 CHECK_EQ(name, v8_str("x")); 5296 info.GetReturnValue().Set(name); 5297 } 5298 5299 5300 THREADED_TEST(SimplePropertyRead) { 5301 LocalContext context; 5302 v8::HandleScope scope(context->GetIsolate()); 5303 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5304 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5305 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5306 Local<Script> script = Script::Compile(v8_str("obj.x")); 5307 for (int i = 0; i < 10; i++) { 5308 Local<Value> result = script->Run(); 5309 CHECK_EQ(result, v8_str("x")); 5310 } 5311 } 5312 5313 5314 THREADED_TEST(DefinePropertyOnAPIAccessor) { 5315 LocalContext context; 5316 v8::HandleScope scope(context->GetIsolate()); 5317 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5318 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5319 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5320 5321 // Uses getOwnPropertyDescriptor to check the configurable status 5322 Local<Script> script_desc 5323 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( " 5324 "obj, 'x');" 5325 "prop.configurable;")); 5326 Local<Value> result = script_desc->Run(); 5327 CHECK_EQ(result->BooleanValue(), true); 5328 5329 // Redefine get - but still configurable 5330 Local<Script> script_define 5331 = Script::Compile(v8_str("var desc = { get: function(){return 42; }," 5332 " configurable: true };" 5333 "Object.defineProperty(obj, 'x', desc);" 5334 "obj.x")); 5335 result = script_define->Run(); 5336 CHECK_EQ(result, v8_num(42)); 5337 5338 // Check that the accessor is still configurable 5339 result = script_desc->Run(); 5340 CHECK_EQ(result->BooleanValue(), true); 5341 5342 // Redefine to a non-configurable 5343 script_define 5344 = Script::Compile(v8_str("var desc = { get: function(){return 43; }," 5345 " configurable: false };" 5346 "Object.defineProperty(obj, 'x', desc);" 5347 "obj.x")); 5348 result = script_define->Run(); 5349 CHECK_EQ(result, v8_num(43)); 5350 result = script_desc->Run(); 5351 CHECK_EQ(result->BooleanValue(), false); 5352 5353 // Make sure that it is not possible to redefine again 5354 v8::TryCatch try_catch; 5355 result = script_define->Run(); 5356 CHECK(try_catch.HasCaught()); 5357 String::Utf8Value exception_value(try_catch.Exception()); 5358 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5359 } 5360 5361 5362 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 5363 v8::HandleScope scope(CcTest::isolate()); 5364 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5365 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 5366 LocalContext context; 5367 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5368 5369 Local<Script> script_desc = Script::Compile(v8_str("var prop =" 5370 "Object.getOwnPropertyDescriptor( " 5371 "obj, 'x');" 5372 "prop.configurable;")); 5373 Local<Value> result = script_desc->Run(); 5374 CHECK_EQ(result->BooleanValue(), true); 5375 5376 Local<Script> script_define = 5377 Script::Compile(v8_str("var desc = {get: function(){return 42; }," 5378 " configurable: true };" 5379 "Object.defineProperty(obj, 'x', desc);" 5380 "obj.x")); 5381 result = script_define->Run(); 5382 CHECK_EQ(result, v8_num(42)); 5383 5384 5385 result = script_desc->Run(); 5386 CHECK_EQ(result->BooleanValue(), true); 5387 5388 5389 script_define = 5390 Script::Compile(v8_str("var desc = {get: function(){return 43; }," 5391 " configurable: false };" 5392 "Object.defineProperty(obj, 'x', desc);" 5393 "obj.x")); 5394 result = script_define->Run(); 5395 CHECK_EQ(result, v8_num(43)); 5396 result = script_desc->Run(); 5397 5398 CHECK_EQ(result->BooleanValue(), false); 5399 5400 v8::TryCatch try_catch; 5401 result = script_define->Run(); 5402 CHECK(try_catch.HasCaught()); 5403 String::Utf8Value exception_value(try_catch.Exception()); 5404 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5405 } 5406 5407 5408 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context, 5409 char const* name) { 5410 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name))); 5411 } 5412 5413 5414 THREADED_TEST(DefineAPIAccessorOnObject) { 5415 v8::HandleScope scope(CcTest::isolate()); 5416 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5417 LocalContext context; 5418 5419 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5420 CompileRun("var obj2 = {};"); 5421 5422 CHECK(CompileRun("obj1.x")->IsUndefined()); 5423 CHECK(CompileRun("obj2.x")->IsUndefined()); 5424 5425 CHECK(GetGlobalProperty(&context, "obj1")-> 5426 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5427 5428 ExpectString("obj1.x", "x"); 5429 CHECK(CompileRun("obj2.x")->IsUndefined()); 5430 5431 CHECK(GetGlobalProperty(&context, "obj2")-> 5432 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5433 5434 ExpectString("obj1.x", "x"); 5435 ExpectString("obj2.x", "x"); 5436 5437 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5438 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5439 5440 CompileRun("Object.defineProperty(obj1, 'x'," 5441 "{ get: function() { return 'y'; }, configurable: true })"); 5442 5443 ExpectString("obj1.x", "y"); 5444 ExpectString("obj2.x", "x"); 5445 5446 CompileRun("Object.defineProperty(obj2, 'x'," 5447 "{ get: function() { return 'y'; }, configurable: true })"); 5448 5449 ExpectString("obj1.x", "y"); 5450 ExpectString("obj2.x", "y"); 5451 5452 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5453 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5454 5455 CHECK(GetGlobalProperty(&context, "obj1")-> 5456 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5457 CHECK(GetGlobalProperty(&context, "obj2")-> 5458 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5459 5460 ExpectString("obj1.x", "x"); 5461 ExpectString("obj2.x", "x"); 5462 5463 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5464 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5465 5466 // Define getters/setters, but now make them not configurable. 5467 CompileRun("Object.defineProperty(obj1, 'x'," 5468 "{ get: function() { return 'z'; }, configurable: false })"); 5469 CompileRun("Object.defineProperty(obj2, 'x'," 5470 "{ get: function() { return 'z'; }, configurable: false })"); 5471 5472 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5473 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5474 5475 ExpectString("obj1.x", "z"); 5476 ExpectString("obj2.x", "z"); 5477 5478 CHECK(!GetGlobalProperty(&context, "obj1")-> 5479 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5480 CHECK(!GetGlobalProperty(&context, "obj2")-> 5481 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5482 5483 ExpectString("obj1.x", "z"); 5484 ExpectString("obj2.x", "z"); 5485 } 5486 5487 5488 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 5489 v8::HandleScope scope(CcTest::isolate()); 5490 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5491 LocalContext context; 5492 5493 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5494 CompileRun("var obj2 = {};"); 5495 5496 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5497 v8_str("x"), 5498 GetXValue, NULL, 5499 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5500 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5501 v8_str("x"), 5502 GetXValue, NULL, 5503 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5504 5505 ExpectString("obj1.x", "x"); 5506 ExpectString("obj2.x", "x"); 5507 5508 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5509 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5510 5511 CHECK(!GetGlobalProperty(&context, "obj1")-> 5512 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5513 CHECK(!GetGlobalProperty(&context, "obj2")-> 5514 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5515 5516 { 5517 v8::TryCatch try_catch; 5518 CompileRun("Object.defineProperty(obj1, 'x'," 5519 "{get: function() { return 'func'; }})"); 5520 CHECK(try_catch.HasCaught()); 5521 String::Utf8Value exception_value(try_catch.Exception()); 5522 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5523 } 5524 { 5525 v8::TryCatch try_catch; 5526 CompileRun("Object.defineProperty(obj2, 'x'," 5527 "{get: function() { return 'func'; }})"); 5528 CHECK(try_catch.HasCaught()); 5529 String::Utf8Value exception_value(try_catch.Exception()); 5530 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5531 } 5532 } 5533 5534 5535 static void Get239Value(Local<String> name, 5536 const v8::PropertyCallbackInfo<v8::Value>& info) { 5537 ApiTestFuzzer::Fuzz(); 5538 CHECK_EQ(info.Data(), v8_str("donut")); 5539 CHECK_EQ(name, v8_str("239")); 5540 info.GetReturnValue().Set(name); 5541 } 5542 5543 5544 THREADED_TEST(ElementAPIAccessor) { 5545 v8::HandleScope scope(CcTest::isolate()); 5546 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5547 LocalContext context; 5548 5549 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5550 CompileRun("var obj2 = {};"); 5551 5552 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5553 v8_str("239"), 5554 Get239Value, NULL, 5555 v8_str("donut"))); 5556 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5557 v8_str("239"), 5558 Get239Value, NULL, 5559 v8_str("donut"))); 5560 5561 ExpectString("obj1[239]", "239"); 5562 ExpectString("obj2[239]", "239"); 5563 ExpectString("obj1['239']", "239"); 5564 ExpectString("obj2['239']", "239"); 5565 } 5566 5567 5568 v8::Persistent<Value> xValue; 5569 5570 5571 static void SetXValue(Local<String> name, 5572 Local<Value> value, 5573 const v8::PropertyCallbackInfo<void>& info) { 5574 CHECK_EQ(value, v8_num(4)); 5575 CHECK_EQ(info.Data(), v8_str("donut")); 5576 CHECK_EQ(name, v8_str("x")); 5577 CHECK(xValue.IsEmpty()); 5578 xValue.Reset(info.GetIsolate(), value); 5579 } 5580 5581 5582 THREADED_TEST(SimplePropertyWrite) { 5583 v8::HandleScope scope(CcTest::isolate()); 5584 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5585 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 5586 LocalContext context; 5587 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5588 Local<Script> script = Script::Compile(v8_str("obj.x = 4")); 5589 for (int i = 0; i < 10; i++) { 5590 CHECK(xValue.IsEmpty()); 5591 script->Run(); 5592 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5593 xValue.Reset(); 5594 } 5595 } 5596 5597 5598 THREADED_TEST(SetterOnly) { 5599 v8::HandleScope scope(CcTest::isolate()); 5600 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5601 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 5602 LocalContext context; 5603 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5604 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x")); 5605 for (int i = 0; i < 10; i++) { 5606 CHECK(xValue.IsEmpty()); 5607 script->Run(); 5608 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue)); 5609 xValue.Reset(); 5610 } 5611 } 5612 5613 5614 THREADED_TEST(NoAccessors) { 5615 v8::HandleScope scope(CcTest::isolate()); 5616 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5617 templ->SetAccessor(v8_str("x"), 5618 static_cast<v8::AccessorGetterCallback>(NULL), 5619 NULL, 5620 v8_str("donut")); 5621 LocalContext context; 5622 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5623 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x")); 5624 for (int i = 0; i < 10; i++) { 5625 script->Run(); 5626 } 5627 } 5628 5629 5630 static void XPropertyGetter(Local<String> property, 5631 const v8::PropertyCallbackInfo<v8::Value>& info) { 5632 ApiTestFuzzer::Fuzz(); 5633 CHECK(info.Data()->IsUndefined()); 5634 info.GetReturnValue().Set(property); 5635 } 5636 5637 5638 THREADED_TEST(NamedInterceptorPropertyRead) { 5639 v8::HandleScope scope(CcTest::isolate()); 5640 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5641 templ->SetNamedPropertyHandler(XPropertyGetter); 5642 LocalContext context; 5643 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5644 Local<Script> script = Script::Compile(v8_str("obj.x")); 5645 for (int i = 0; i < 10; i++) { 5646 Local<Value> result = script->Run(); 5647 CHECK_EQ(result, v8_str("x")); 5648 } 5649 } 5650 5651 5652 THREADED_TEST(NamedInterceptorDictionaryIC) { 5653 v8::HandleScope scope(CcTest::isolate()); 5654 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5655 templ->SetNamedPropertyHandler(XPropertyGetter); 5656 LocalContext context; 5657 // Create an object with a named interceptor. 5658 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance()); 5659 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x")); 5660 for (int i = 0; i < 10; i++) { 5661 Local<Value> result = script->Run(); 5662 CHECK_EQ(result, v8_str("x")); 5663 } 5664 // Create a slow case object and a function accessing a property in 5665 // that slow case object (with dictionary probing in generated 5666 // code). Then force object with a named interceptor into slow-case, 5667 // pass it to the function, and check that the interceptor is called 5668 // instead of accessing the local property. 5669 Local<Value> result = 5670 CompileRun("function get_x(o) { return o.x; };" 5671 "var obj = { x : 42, y : 0 };" 5672 "delete obj.y;" 5673 "for (var i = 0; i < 10; i++) get_x(obj);" 5674 "interceptor_obj.x = 42;" 5675 "interceptor_obj.y = 10;" 5676 "delete interceptor_obj.y;" 5677 "get_x(interceptor_obj)"); 5678 CHECK_EQ(result, v8_str("x")); 5679 } 5680 5681 5682 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) { 5683 v8::Isolate* isolate = CcTest::isolate(); 5684 v8::HandleScope scope(isolate); 5685 v8::Local<Context> context1 = Context::New(isolate); 5686 5687 context1->Enter(); 5688 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5689 templ->SetNamedPropertyHandler(XPropertyGetter); 5690 // Create an object with a named interceptor. 5691 v8::Local<v8::Object> object = templ->NewInstance(); 5692 context1->Global()->Set(v8_str("interceptor_obj"), object); 5693 5694 // Force the object into the slow case. 5695 CompileRun("interceptor_obj.y = 0;" 5696 "delete interceptor_obj.y;"); 5697 context1->Exit(); 5698 5699 { 5700 // Introduce the object into a different context. 5701 // Repeat named loads to exercise ICs. 5702 LocalContext context2; 5703 context2->Global()->Set(v8_str("interceptor_obj"), object); 5704 Local<Value> result = 5705 CompileRun("function get_x(o) { return o.x; }" 5706 "interceptor_obj.x = 42;" 5707 "for (var i=0; i != 10; i++) {" 5708 " get_x(interceptor_obj);" 5709 "}" 5710 "get_x(interceptor_obj)"); 5711 // Check that the interceptor was actually invoked. 5712 CHECK_EQ(result, v8_str("x")); 5713 } 5714 5715 // Return to the original context and force some object to the slow case 5716 // to cause the NormalizedMapCache to verify. 5717 context1->Enter(); 5718 CompileRun("var obj = { x : 0 }; delete obj.x;"); 5719 context1->Exit(); 5720 } 5721 5722 5723 static void SetXOnPrototypeGetter( 5724 Local<String> property, 5725 const v8::PropertyCallbackInfo<v8::Value>& info) { 5726 // Set x on the prototype object and do not handle the get request. 5727 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype(); 5728 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23)); 5729 } 5730 5731 5732 // This is a regression test for http://crbug.com/20104. Map 5733 // transitions should not interfere with post interceptor lookup. 5734 THREADED_TEST(NamedInterceptorMapTransitionRead) { 5735 v8::HandleScope scope(CcTest::isolate()); 5736 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(); 5737 Local<v8::ObjectTemplate> instance_template 5738 = function_template->InstanceTemplate(); 5739 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter); 5740 LocalContext context; 5741 context->Global()->Set(v8_str("F"), function_template->GetFunction()); 5742 // Create an instance of F and introduce a map transition for x. 5743 CompileRun("var o = new F(); o.x = 23;"); 5744 // Create an instance of F and invoke the getter. The result should be 23. 5745 Local<Value> result = CompileRun("o = new F(); o.x"); 5746 CHECK_EQ(result->Int32Value(), 23); 5747 } 5748 5749 5750 static void IndexedPropertyGetter( 5751 uint32_t index, 5752 const v8::PropertyCallbackInfo<v8::Value>& info) { 5753 ApiTestFuzzer::Fuzz(); 5754 if (index == 37) { 5755 info.GetReturnValue().Set(v8_num(625)); 5756 } 5757 } 5758 5759 5760 static void IndexedPropertySetter( 5761 uint32_t index, 5762 Local<Value> value, 5763 const v8::PropertyCallbackInfo<v8::Value>& info) { 5764 ApiTestFuzzer::Fuzz(); 5765 if (index == 39) { 5766 info.GetReturnValue().Set(value); 5767 } 5768 } 5769 5770 5771 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { 5772 v8::HandleScope scope(CcTest::isolate()); 5773 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5774 templ->SetIndexedPropertyHandler(IndexedPropertyGetter, 5775 IndexedPropertySetter); 5776 LocalContext context; 5777 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5778 Local<Script> getter_script = Script::Compile(v8_str( 5779 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];")); 5780 Local<Script> setter_script = Script::Compile(v8_str( 5781 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" 5782 "obj[17] = 23;" 5783 "obj.foo;")); 5784 Local<Script> interceptor_setter_script = Script::Compile(v8_str( 5785 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" 5786 "obj[39] = 47;" 5787 "obj.foo;")); // This setter should not run, due to the interceptor. 5788 Local<Script> interceptor_getter_script = Script::Compile(v8_str( 5789 "obj[37];")); 5790 Local<Value> result = getter_script->Run(); 5791 CHECK_EQ(v8_num(5), result); 5792 result = setter_script->Run(); 5793 CHECK_EQ(v8_num(23), result); 5794 result = interceptor_setter_script->Run(); 5795 CHECK_EQ(v8_num(23), result); 5796 result = interceptor_getter_script->Run(); 5797 CHECK_EQ(v8_num(625), result); 5798 } 5799 5800 5801 static void UnboxedDoubleIndexedPropertyGetter( 5802 uint32_t index, 5803 const v8::PropertyCallbackInfo<v8::Value>& info) { 5804 ApiTestFuzzer::Fuzz(); 5805 if (index < 25) { 5806 info.GetReturnValue().Set(v8_num(index)); 5807 } 5808 } 5809 5810 5811 static void UnboxedDoubleIndexedPropertySetter( 5812 uint32_t index, 5813 Local<Value> value, 5814 const v8::PropertyCallbackInfo<v8::Value>& info) { 5815 ApiTestFuzzer::Fuzz(); 5816 if (index < 25) { 5817 info.GetReturnValue().Set(v8_num(index)); 5818 } 5819 } 5820 5821 5822 void UnboxedDoubleIndexedPropertyEnumerator( 5823 const v8::PropertyCallbackInfo<v8::Array>& info) { 5824 // Force the list of returned keys to be stored in a FastDoubleArray. 5825 Local<Script> indexed_property_names_script = Script::Compile(v8_str( 5826 "keys = new Array(); keys[125000] = 1;" 5827 "for(i = 0; i < 80000; i++) { keys[i] = i; };" 5828 "keys.length = 25; keys;")); 5829 Local<Value> result = indexed_property_names_script->Run(); 5830 info.GetReturnValue().Set(Local<v8::Array>::Cast(result)); 5831 } 5832 5833 5834 // Make sure that the the interceptor code in the runtime properly handles 5835 // merging property name lists for double-array-backed arrays. 5836 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { 5837 v8::HandleScope scope(CcTest::isolate()); 5838 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5839 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter, 5840 UnboxedDoubleIndexedPropertySetter, 5841 0, 5842 0, 5843 UnboxedDoubleIndexedPropertyEnumerator); 5844 LocalContext context; 5845 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5846 // When obj is created, force it to be Stored in a FastDoubleArray. 5847 Local<Script> create_unboxed_double_script = Script::Compile(v8_str( 5848 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } " 5849 "key_count = 0; " 5850 "for (x in obj) {key_count++;};" 5851 "obj;")); 5852 Local<Value> result = create_unboxed_double_script->Run(); 5853 CHECK(result->ToObject()->HasRealIndexedProperty(2000)); 5854 Local<Script> key_count_check = Script::Compile(v8_str( 5855 "key_count;")); 5856 result = key_count_check->Run(); 5857 CHECK_EQ(v8_num(40013), result); 5858 } 5859 5860 5861 void NonStrictArgsIndexedPropertyEnumerator( 5862 const v8::PropertyCallbackInfo<v8::Array>& info) { 5863 // Force the list of returned keys to be stored in a Arguments object. 5864 Local<Script> indexed_property_names_script = Script::Compile(v8_str( 5865 "function f(w,x) {" 5866 " return arguments;" 5867 "}" 5868 "keys = f(0, 1, 2, 3);" 5869 "keys;")); 5870 Local<Object> result = 5871 Local<Object>::Cast(indexed_property_names_script->Run()); 5872 // Have to populate the handle manually, as it's not Cast-able. 5873 i::Handle<i::JSObject> o = 5874 v8::Utils::OpenHandle<Object, i::JSObject>(result); 5875 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o)); 5876 info.GetReturnValue().Set(v8::Utils::ToLocal(array)); 5877 } 5878 5879 5880 static void NonStrictIndexedPropertyGetter( 5881 uint32_t index, 5882 const v8::PropertyCallbackInfo<v8::Value>& info) { 5883 ApiTestFuzzer::Fuzz(); 5884 if (index < 4) { 5885 info.GetReturnValue().Set(v8_num(index)); 5886 } 5887 } 5888 5889 5890 // Make sure that the the interceptor code in the runtime properly handles 5891 // merging property name lists for non-string arguments arrays. 5892 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) { 5893 v8::HandleScope scope(CcTest::isolate()); 5894 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5895 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter, 5896 0, 5897 0, 5898 0, 5899 NonStrictArgsIndexedPropertyEnumerator); 5900 LocalContext context; 5901 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5902 Local<Script> create_args_script = 5903 Script::Compile(v8_str( 5904 "var key_count = 0;" 5905 "for (x in obj) {key_count++;} key_count;")); 5906 Local<Value> result = create_args_script->Run(); 5907 CHECK_EQ(v8_num(4), result); 5908 } 5909 5910 5911 static void IdentityIndexedPropertyGetter( 5912 uint32_t index, 5913 const v8::PropertyCallbackInfo<v8::Value>& info) { 5914 info.GetReturnValue().Set(index); 5915 } 5916 5917 5918 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) { 5919 v8::HandleScope scope(CcTest::isolate()); 5920 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5921 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5922 5923 LocalContext context; 5924 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5925 5926 // Check fast object case. 5927 const char* fast_case_code = 5928 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()"; 5929 ExpectString(fast_case_code, "0"); 5930 5931 // Check slow case. 5932 const char* slow_case_code = 5933 "obj.x = 1; delete obj.x;" 5934 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()"; 5935 ExpectString(slow_case_code, "1"); 5936 } 5937 5938 5939 THREADED_TEST(IndexedInterceptorWithNoSetter) { 5940 v8::HandleScope scope(CcTest::isolate()); 5941 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5942 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5943 5944 LocalContext context; 5945 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5946 5947 const char* code = 5948 "try {" 5949 " obj[0] = 239;" 5950 " for (var i = 0; i < 100; i++) {" 5951 " var v = obj[0];" 5952 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;" 5953 " }" 5954 " 'PASSED'" 5955 "} catch(e) {" 5956 " e" 5957 "}"; 5958 ExpectString(code, "PASSED"); 5959 } 5960 5961 5962 THREADED_TEST(IndexedInterceptorWithAccessorCheck) { 5963 v8::HandleScope scope(CcTest::isolate()); 5964 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5965 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5966 5967 LocalContext context; 5968 Local<v8::Object> obj = templ->NewInstance(); 5969 obj->TurnOnAccessCheck(); 5970 context->Global()->Set(v8_str("obj"), obj); 5971 5972 const char* code = 5973 "try {" 5974 " for (var i = 0; i < 100; i++) {" 5975 " var v = obj[0];" 5976 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;" 5977 " }" 5978 " 'PASSED'" 5979 "} catch(e) {" 5980 " e" 5981 "}"; 5982 ExpectString(code, "PASSED"); 5983 } 5984 5985 5986 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { 5987 i::FLAG_allow_natives_syntax = true; 5988 v8::HandleScope scope(CcTest::isolate()); 5989 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5990 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5991 5992 LocalContext context; 5993 Local<v8::Object> obj = templ->NewInstance(); 5994 context->Global()->Set(v8_str("obj"), obj); 5995 5996 const char* code = 5997 "try {" 5998 " for (var i = 0; i < 100; i++) {" 5999 " var expected = i;" 6000 " if (i == 5) {" 6001 " %EnableAccessChecks(obj);" 6002 " expected = undefined;" 6003 " }" 6004 " var v = obj[i];" 6005 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6006 " if (i == 5) %DisableAccessChecks(obj);" 6007 " }" 6008 " 'PASSED'" 6009 "} catch(e) {" 6010 " e" 6011 "}"; 6012 ExpectString(code, "PASSED"); 6013 } 6014 6015 6016 THREADED_TEST(IndexedInterceptorWithDifferentIndices) { 6017 v8::HandleScope scope(CcTest::isolate()); 6018 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6019 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6020 6021 LocalContext context; 6022 Local<v8::Object> obj = templ->NewInstance(); 6023 context->Global()->Set(v8_str("obj"), obj); 6024 6025 const char* code = 6026 "try {" 6027 " for (var i = 0; i < 100; i++) {" 6028 " var v = obj[i];" 6029 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6030 " }" 6031 " 'PASSED'" 6032 "} catch(e) {" 6033 " e" 6034 "}"; 6035 ExpectString(code, "PASSED"); 6036 } 6037 6038 6039 THREADED_TEST(IndexedInterceptorWithNegativeIndices) { 6040 v8::HandleScope scope(CcTest::isolate()); 6041 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6042 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6043 6044 LocalContext context; 6045 Local<v8::Object> obj = templ->NewInstance(); 6046 context->Global()->Set(v8_str("obj"), obj); 6047 6048 const char* code = 6049 "try {" 6050 " for (var i = 0; i < 100; i++) {" 6051 " var expected = i;" 6052 " var key = i;" 6053 " if (i == 25) {" 6054 " key = -1;" 6055 " expected = undefined;" 6056 " }" 6057 " if (i == 50) {" 6058 " /* probe minimal Smi number on 32-bit platforms */" 6059 " key = -(1 << 30);" 6060 " expected = undefined;" 6061 " }" 6062 " if (i == 75) {" 6063 " /* probe minimal Smi number on 64-bit platforms */" 6064 " key = 1 << 31;" 6065 " expected = undefined;" 6066 " }" 6067 " var v = obj[key];" 6068 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6069 " }" 6070 " 'PASSED'" 6071 "} catch(e) {" 6072 " e" 6073 "}"; 6074 ExpectString(code, "PASSED"); 6075 } 6076 6077 6078 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) { 6079 v8::HandleScope scope(CcTest::isolate()); 6080 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6081 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6082 6083 LocalContext context; 6084 Local<v8::Object> obj = templ->NewInstance(); 6085 context->Global()->Set(v8_str("obj"), obj); 6086 6087 const char* code = 6088 "try {" 6089 " for (var i = 0; i < 100; i++) {" 6090 " var expected = i;" 6091 " var key = i;" 6092 " if (i == 50) {" 6093 " key = 'foobar';" 6094 " expected = undefined;" 6095 " }" 6096 " var v = obj[key];" 6097 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6098 " }" 6099 " 'PASSED'" 6100 "} catch(e) {" 6101 " e" 6102 "}"; 6103 ExpectString(code, "PASSED"); 6104 } 6105 6106 6107 THREADED_TEST(IndexedInterceptorGoingMegamorphic) { 6108 v8::HandleScope scope(CcTest::isolate()); 6109 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6110 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6111 6112 LocalContext context; 6113 Local<v8::Object> obj = templ->NewInstance(); 6114 context->Global()->Set(v8_str("obj"), obj); 6115 6116 const char* code = 6117 "var original = obj;" 6118 "try {" 6119 " for (var i = 0; i < 100; i++) {" 6120 " var expected = i;" 6121 " if (i == 50) {" 6122 " obj = {50: 'foobar'};" 6123 " expected = 'foobar';" 6124 " }" 6125 " var v = obj[i];" 6126 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6127 " if (i == 50) obj = original;" 6128 " }" 6129 " 'PASSED'" 6130 "} catch(e) {" 6131 " e" 6132 "}"; 6133 ExpectString(code, "PASSED"); 6134 } 6135 6136 6137 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) { 6138 v8::HandleScope scope(CcTest::isolate()); 6139 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6140 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6141 6142 LocalContext context; 6143 Local<v8::Object> obj = templ->NewInstance(); 6144 context->Global()->Set(v8_str("obj"), obj); 6145 6146 const char* code = 6147 "var original = obj;" 6148 "try {" 6149 " for (var i = 0; i < 100; i++) {" 6150 " var expected = i;" 6151 " if (i == 5) {" 6152 " obj = 239;" 6153 " expected = undefined;" 6154 " }" 6155 " var v = obj[i];" 6156 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 6157 " if (i == 5) obj = original;" 6158 " }" 6159 " 'PASSED'" 6160 "} catch(e) {" 6161 " e" 6162 "}"; 6163 ExpectString(code, "PASSED"); 6164 } 6165 6166 6167 THREADED_TEST(IndexedInterceptorOnProto) { 6168 v8::HandleScope scope(CcTest::isolate()); 6169 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6170 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 6171 6172 LocalContext context; 6173 Local<v8::Object> obj = templ->NewInstance(); 6174 context->Global()->Set(v8_str("obj"), obj); 6175 6176 const char* code = 6177 "var o = {__proto__: obj};" 6178 "try {" 6179 " for (var i = 0; i < 100; i++) {" 6180 " var v = o[i];" 6181 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 6182 " }" 6183 " 'PASSED'" 6184 "} catch(e) {" 6185 " e" 6186 "}"; 6187 ExpectString(code, "PASSED"); 6188 } 6189 6190 6191 THREADED_TEST(MultiContexts) { 6192 v8::HandleScope scope(CcTest::isolate()); 6193 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(); 6194 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler)); 6195 6196 Local<String> password = v8_str("Password"); 6197 6198 // Create an environment 6199 LocalContext context0(0, templ); 6200 context0->SetSecurityToken(password); 6201 v8::Handle<v8::Object> global0 = context0->Global(); 6202 global0->Set(v8_str("custom"), v8_num(1234)); 6203 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6204 6205 // Create an independent environment 6206 LocalContext context1(0, templ); 6207 context1->SetSecurityToken(password); 6208 v8::Handle<v8::Object> global1 = context1->Global(); 6209 global1->Set(v8_str("custom"), v8_num(1234)); 6210 CHECK_NE(global0, global1); 6211 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 6212 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value()); 6213 6214 // Now create a new context with the old global 6215 LocalContext context2(0, templ, global1); 6216 context2->SetSecurityToken(password); 6217 v8::Handle<v8::Object> global2 = context2->Global(); 6218 CHECK_EQ(global1, global2); 6219 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value()); 6220 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value()); 6221 } 6222 6223 6224 THREADED_TEST(FunctionPrototypeAcrossContexts) { 6225 // Make sure that functions created by cloning boilerplates cannot 6226 // communicate through their __proto__ field. 6227 6228 v8::HandleScope scope(CcTest::isolate()); 6229 6230 LocalContext env0; 6231 v8::Handle<v8::Object> global0 = 6232 env0->Global(); 6233 v8::Handle<v8::Object> object0 = 6234 global0->Get(v8_str("Object")).As<v8::Object>(); 6235 v8::Handle<v8::Object> tostring0 = 6236 object0->Get(v8_str("toString")).As<v8::Object>(); 6237 v8::Handle<v8::Object> proto0 = 6238 tostring0->Get(v8_str("__proto__")).As<v8::Object>(); 6239 proto0->Set(v8_str("custom"), v8_num(1234)); 6240 6241 LocalContext env1; 6242 v8::Handle<v8::Object> global1 = 6243 env1->Global(); 6244 v8::Handle<v8::Object> object1 = 6245 global1->Get(v8_str("Object")).As<v8::Object>(); 6246 v8::Handle<v8::Object> tostring1 = 6247 object1->Get(v8_str("toString")).As<v8::Object>(); 6248 v8::Handle<v8::Object> proto1 = 6249 tostring1->Get(v8_str("__proto__")).As<v8::Object>(); 6250 CHECK(!proto1->Has(v8_str("custom"))); 6251 } 6252 6253 6254 THREADED_TEST(Regress892105) { 6255 // Make sure that object and array literals created by cloning 6256 // boilerplates cannot communicate through their __proto__ 6257 // field. This is rather difficult to check, but we try to add stuff 6258 // to Object.prototype and Array.prototype and create a new 6259 // environment. This should succeed. 6260 6261 v8::HandleScope scope(CcTest::isolate()); 6262 6263 Local<String> source = v8_str("Object.prototype.obj = 1234;" 6264 "Array.prototype.arr = 4567;" 6265 "8901"); 6266 6267 LocalContext env0; 6268 Local<Script> script0 = Script::Compile(source); 6269 CHECK_EQ(8901.0, script0->Run()->NumberValue()); 6270 6271 LocalContext env1; 6272 Local<Script> script1 = Script::Compile(source); 6273 CHECK_EQ(8901.0, script1->Run()->NumberValue()); 6274 } 6275 6276 6277 THREADED_TEST(UndetectableObject) { 6278 LocalContext env; 6279 v8::HandleScope scope(env->GetIsolate()); 6280 6281 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 6282 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6283 6284 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6285 env->Global()->Set(v8_str("undetectable"), obj); 6286 6287 ExpectString("undetectable.toString()", "[object Object]"); 6288 ExpectString("typeof undetectable", "undefined"); 6289 ExpectString("typeof(undetectable)", "undefined"); 6290 ExpectBoolean("typeof undetectable == 'undefined'", true); 6291 ExpectBoolean("typeof undetectable == 'object'", false); 6292 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6293 ExpectBoolean("!undetectable", true); 6294 6295 ExpectObject("true&&undetectable", obj); 6296 ExpectBoolean("false&&undetectable", false); 6297 ExpectBoolean("true||undetectable", true); 6298 ExpectObject("false||undetectable", obj); 6299 6300 ExpectObject("undetectable&&true", obj); 6301 ExpectObject("undetectable&&false", obj); 6302 ExpectBoolean("undetectable||true", true); 6303 ExpectBoolean("undetectable||false", false); 6304 6305 ExpectBoolean("undetectable==null", true); 6306 ExpectBoolean("null==undetectable", true); 6307 ExpectBoolean("undetectable==undefined", true); 6308 ExpectBoolean("undefined==undetectable", true); 6309 ExpectBoolean("undetectable==undetectable", true); 6310 6311 6312 ExpectBoolean("undetectable===null", false); 6313 ExpectBoolean("null===undetectable", false); 6314 ExpectBoolean("undetectable===undefined", false); 6315 ExpectBoolean("undefined===undetectable", false); 6316 ExpectBoolean("undetectable===undetectable", true); 6317 } 6318 6319 6320 THREADED_TEST(VoidLiteral) { 6321 LocalContext env; 6322 v8::HandleScope scope(env->GetIsolate()); 6323 6324 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 6325 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6326 6327 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6328 env->Global()->Set(v8_str("undetectable"), obj); 6329 6330 ExpectBoolean("undefined == void 0", true); 6331 ExpectBoolean("undetectable == void 0", true); 6332 ExpectBoolean("null == void 0", true); 6333 ExpectBoolean("undefined === void 0", true); 6334 ExpectBoolean("undetectable === void 0", false); 6335 ExpectBoolean("null === void 0", false); 6336 6337 ExpectBoolean("void 0 == undefined", true); 6338 ExpectBoolean("void 0 == undetectable", true); 6339 ExpectBoolean("void 0 == null", true); 6340 ExpectBoolean("void 0 === undefined", true); 6341 ExpectBoolean("void 0 === undetectable", false); 6342 ExpectBoolean("void 0 === null", false); 6343 6344 ExpectString("(function() {" 6345 " try {" 6346 " return x === void 0;" 6347 " } catch(e) {" 6348 " return e.toString();" 6349 " }" 6350 "})()", 6351 "ReferenceError: x is not defined"); 6352 ExpectString("(function() {" 6353 " try {" 6354 " return void 0 === x;" 6355 " } catch(e) {" 6356 " return e.toString();" 6357 " }" 6358 "})()", 6359 "ReferenceError: x is not defined"); 6360 } 6361 6362 6363 THREADED_TEST(ExtensibleOnUndetectable) { 6364 LocalContext env; 6365 v8::HandleScope scope(env->GetIsolate()); 6366 6367 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 6368 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 6369 6370 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 6371 env->Global()->Set(v8_str("undetectable"), obj); 6372 6373 Local<String> source = v8_str("undetectable.x = 42;" 6374 "undetectable.x"); 6375 6376 Local<Script> script = Script::Compile(source); 6377 6378 CHECK_EQ(v8::Integer::New(42), script->Run()); 6379 6380 ExpectBoolean("Object.isExtensible(undetectable)", true); 6381 6382 source = v8_str("Object.preventExtensions(undetectable);"); 6383 script = Script::Compile(source); 6384 script->Run(); 6385 ExpectBoolean("Object.isExtensible(undetectable)", false); 6386 6387 source = v8_str("undetectable.y = 2000;"); 6388 script = Script::Compile(source); 6389 script->Run(); 6390 ExpectBoolean("undetectable.y == undefined", true); 6391 } 6392 6393 6394 6395 THREADED_TEST(UndetectableString) { 6396 LocalContext env; 6397 v8::HandleScope scope(env->GetIsolate()); 6398 6399 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6400 String::kUndetectableString); 6401 env->Global()->Set(v8_str("undetectable"), obj); 6402 6403 ExpectString("undetectable", "foo"); 6404 ExpectString("typeof undetectable", "undefined"); 6405 ExpectString("typeof(undetectable)", "undefined"); 6406 ExpectBoolean("typeof undetectable == 'undefined'", true); 6407 ExpectBoolean("typeof undetectable == 'string'", false); 6408 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6409 ExpectBoolean("!undetectable", true); 6410 6411 ExpectObject("true&&undetectable", obj); 6412 ExpectBoolean("false&&undetectable", false); 6413 ExpectBoolean("true||undetectable", true); 6414 ExpectObject("false||undetectable", obj); 6415 6416 ExpectObject("undetectable&&true", obj); 6417 ExpectObject("undetectable&&false", obj); 6418 ExpectBoolean("undetectable||true", true); 6419 ExpectBoolean("undetectable||false", false); 6420 6421 ExpectBoolean("undetectable==null", true); 6422 ExpectBoolean("null==undetectable", true); 6423 ExpectBoolean("undetectable==undefined", true); 6424 ExpectBoolean("undefined==undetectable", true); 6425 ExpectBoolean("undetectable==undetectable", true); 6426 6427 6428 ExpectBoolean("undetectable===null", false); 6429 ExpectBoolean("null===undetectable", false); 6430 ExpectBoolean("undetectable===undefined", false); 6431 ExpectBoolean("undefined===undetectable", false); 6432 ExpectBoolean("undetectable===undetectable", true); 6433 } 6434 6435 6436 TEST(UndetectableOptimized) { 6437 i::FLAG_allow_natives_syntax = true; 6438 LocalContext env; 6439 v8::HandleScope scope(env->GetIsolate()); 6440 6441 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo", 6442 String::kUndetectableString); 6443 env->Global()->Set(v8_str("undetectable"), obj); 6444 env->Global()->Set(v8_str("detectable"), v8_str("bar")); 6445 6446 ExpectString( 6447 "function testBranch() {" 6448 " if (!%_IsUndetectableObject(undetectable)) throw 1;" 6449 " if (%_IsUndetectableObject(detectable)) throw 2;" 6450 "}\n" 6451 "function testBool() {" 6452 " var b1 = !%_IsUndetectableObject(undetectable);" 6453 " var b2 = %_IsUndetectableObject(detectable);" 6454 " if (b1) throw 3;" 6455 " if (b2) throw 4;" 6456 " return b1 == b2;" 6457 "}\n" 6458 "%OptimizeFunctionOnNextCall(testBranch);" 6459 "%OptimizeFunctionOnNextCall(testBool);" 6460 "for (var i = 0; i < 10; i++) {" 6461 " testBranch();" 6462 " testBool();" 6463 "}\n" 6464 "\"PASS\"", 6465 "PASS"); 6466 } 6467 6468 6469 template <typename T> static void USE(T) { } 6470 6471 6472 // This test is not intended to be run, just type checked. 6473 static inline void PersistentHandles(v8::Isolate* isolate) { 6474 USE(PersistentHandles); 6475 Local<String> str = v8_str("foo"); 6476 v8::Persistent<String> p_str(isolate, str); 6477 p_str.Reset(); 6478 Local<Script> scr = Script::Compile(v8_str("")); 6479 v8::Persistent<Script> p_scr(isolate, scr); 6480 p_scr.Reset(); 6481 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6482 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 6483 p_templ.Reset(); 6484 } 6485 6486 6487 static void HandleLogDelegator( 6488 const v8::FunctionCallbackInfo<v8::Value>& args) { 6489 ApiTestFuzzer::Fuzz(); 6490 } 6491 6492 6493 THREADED_TEST(GlobalObjectTemplate) { 6494 v8::Isolate* isolate = CcTest::isolate(); 6495 v8::HandleScope handle_scope(isolate); 6496 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 6497 global_template->Set(v8_str("JSNI_Log"), 6498 v8::FunctionTemplate::New(HandleLogDelegator)); 6499 v8::Local<Context> context = Context::New(isolate, 0, global_template); 6500 Context::Scope context_scope(context); 6501 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run(); 6502 } 6503 6504 6505 static const char* kSimpleExtensionSource = 6506 "function Foo() {" 6507 " return 4;" 6508 "}"; 6509 6510 6511 THREADED_TEST(SimpleExtensions) { 6512 v8::HandleScope handle_scope(CcTest::isolate()); 6513 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 6514 const char* extension_names[] = { "simpletest" }; 6515 v8::ExtensionConfiguration extensions(1, extension_names); 6516 v8::Handle<Context> context = 6517 Context::New(CcTest::isolate(), &extensions); 6518 Context::Scope lock(context); 6519 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 6520 CHECK_EQ(result, v8::Integer::New(4)); 6521 } 6522 6523 6524 THREADED_TEST(NullExtensions) { 6525 v8::HandleScope handle_scope(CcTest::isolate()); 6526 v8::RegisterExtension(new Extension("nulltest", NULL)); 6527 const char* extension_names[] = { "nulltest" }; 6528 v8::ExtensionConfiguration extensions(1, extension_names); 6529 v8::Handle<Context> context = 6530 Context::New(CcTest::isolate(), &extensions); 6531 Context::Scope lock(context); 6532 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run(); 6533 CHECK_EQ(result, v8::Integer::New(4)); 6534 } 6535 6536 6537 static const char* kEmbeddedExtensionSource = 6538 "function Ret54321(){return 54321;}~~@@$" 6539 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 6540 static const int kEmbeddedExtensionSourceValidLen = 34; 6541 6542 6543 THREADED_TEST(ExtensionMissingSourceLength) { 6544 v8::HandleScope handle_scope(CcTest::isolate()); 6545 v8::RegisterExtension(new Extension("srclentest_fail", 6546 kEmbeddedExtensionSource)); 6547 const char* extension_names[] = { "srclentest_fail" }; 6548 v8::ExtensionConfiguration extensions(1, extension_names); 6549 v8::Handle<Context> context = 6550 Context::New(CcTest::isolate(), &extensions); 6551 CHECK_EQ(0, *context); 6552 } 6553 6554 6555 THREADED_TEST(ExtensionWithSourceLength) { 6556 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 6557 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 6558 v8::HandleScope handle_scope(CcTest::isolate()); 6559 i::ScopedVector<char> extension_name(32); 6560 i::OS::SNPrintF(extension_name, "ext #%d", source_len); 6561 v8::RegisterExtension(new Extension(extension_name.start(), 6562 kEmbeddedExtensionSource, 0, 0, 6563 source_len)); 6564 const char* extension_names[1] = { extension_name.start() }; 6565 v8::ExtensionConfiguration extensions(1, extension_names); 6566 v8::Handle<Context> context = 6567 Context::New(CcTest::isolate(), &extensions); 6568 if (source_len == kEmbeddedExtensionSourceValidLen) { 6569 Context::Scope lock(context); 6570 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run(); 6571 CHECK_EQ(v8::Integer::New(54321), result); 6572 } else { 6573 // Anything but exactly the right length should fail to compile. 6574 CHECK_EQ(0, *context); 6575 } 6576 } 6577 } 6578 6579 6580 static const char* kEvalExtensionSource1 = 6581 "function UseEval1() {" 6582 " var x = 42;" 6583 " return eval('x');" 6584 "}"; 6585 6586 6587 static const char* kEvalExtensionSource2 = 6588 "(function() {" 6589 " var x = 42;" 6590 " function e() {" 6591 " return eval('x');" 6592 " }" 6593 " this.UseEval2 = e;" 6594 "})()"; 6595 6596 6597 THREADED_TEST(UseEvalFromExtension) { 6598 v8::HandleScope handle_scope(CcTest::isolate()); 6599 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 6600 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 6601 const char* extension_names[] = { "evaltest1", "evaltest2" }; 6602 v8::ExtensionConfiguration extensions(2, extension_names); 6603 v8::Handle<Context> context = 6604 Context::New(CcTest::isolate(), &extensions); 6605 Context::Scope lock(context); 6606 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run(); 6607 CHECK_EQ(result, v8::Integer::New(42)); 6608 result = Script::Compile(v8_str("UseEval2()"))->Run(); 6609 CHECK_EQ(result, v8::Integer::New(42)); 6610 } 6611 6612 6613 static const char* kWithExtensionSource1 = 6614 "function UseWith1() {" 6615 " var x = 42;" 6616 " with({x:87}) { return x; }" 6617 "}"; 6618 6619 6620 6621 static const char* kWithExtensionSource2 = 6622 "(function() {" 6623 " var x = 42;" 6624 " function e() {" 6625 " with ({x:87}) { return x; }" 6626 " }" 6627 " this.UseWith2 = e;" 6628 "})()"; 6629 6630 6631 THREADED_TEST(UseWithFromExtension) { 6632 v8::HandleScope handle_scope(CcTest::isolate()); 6633 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 6634 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 6635 const char* extension_names[] = { "withtest1", "withtest2" }; 6636 v8::ExtensionConfiguration extensions(2, extension_names); 6637 v8::Handle<Context> context = 6638 Context::New(CcTest::isolate(), &extensions); 6639 Context::Scope lock(context); 6640 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run(); 6641 CHECK_EQ(result, v8::Integer::New(87)); 6642 result = Script::Compile(v8_str("UseWith2()"))->Run(); 6643 CHECK_EQ(result, v8::Integer::New(87)); 6644 } 6645 6646 6647 THREADED_TEST(AutoExtensions) { 6648 v8::HandleScope handle_scope(CcTest::isolate()); 6649 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 6650 extension->set_auto_enable(true); 6651 v8::RegisterExtension(extension); 6652 v8::Handle<Context> context = 6653 Context::New(CcTest::isolate()); 6654 Context::Scope lock(context); 6655 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 6656 CHECK_EQ(result, v8::Integer::New(4)); 6657 } 6658 6659 6660 static const char* kSyntaxErrorInExtensionSource = 6661 "["; 6662 6663 6664 // Test that a syntax error in an extension does not cause a fatal 6665 // error but results in an empty context. 6666 THREADED_TEST(SyntaxErrorExtensions) { 6667 v8::HandleScope handle_scope(CcTest::isolate()); 6668 v8::RegisterExtension(new Extension("syntaxerror", 6669 kSyntaxErrorInExtensionSource)); 6670 const char* extension_names[] = { "syntaxerror" }; 6671 v8::ExtensionConfiguration extensions(1, extension_names); 6672 v8::Handle<Context> context = 6673 Context::New(CcTest::isolate(), &extensions); 6674 CHECK(context.IsEmpty()); 6675 } 6676 6677 6678 static const char* kExceptionInExtensionSource = 6679 "throw 42"; 6680 6681 6682 // Test that an exception when installing an extension does not cause 6683 // a fatal error but results in an empty context. 6684 THREADED_TEST(ExceptionExtensions) { 6685 v8::HandleScope handle_scope(CcTest::isolate()); 6686 v8::RegisterExtension(new Extension("exception", 6687 kExceptionInExtensionSource)); 6688 const char* extension_names[] = { "exception" }; 6689 v8::ExtensionConfiguration extensions(1, extension_names); 6690 v8::Handle<Context> context = 6691 Context::New(CcTest::isolate(), &extensions); 6692 CHECK(context.IsEmpty()); 6693 } 6694 6695 6696 static const char* kNativeCallInExtensionSource = 6697 "function call_runtime_last_index_of(x) {" 6698 " return %StringLastIndexOf(x, 'bob', 10);" 6699 "}"; 6700 6701 6702 static const char* kNativeCallTest = 6703 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 6704 6705 // Test that a native runtime calls are supported in extensions. 6706 THREADED_TEST(NativeCallInExtensions) { 6707 v8::HandleScope handle_scope(CcTest::isolate()); 6708 v8::RegisterExtension(new Extension("nativecall", 6709 kNativeCallInExtensionSource)); 6710 const char* extension_names[] = { "nativecall" }; 6711 v8::ExtensionConfiguration extensions(1, extension_names); 6712 v8::Handle<Context> context = 6713 Context::New(CcTest::isolate(), &extensions); 6714 Context::Scope lock(context); 6715 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run(); 6716 CHECK_EQ(result, v8::Integer::New(3)); 6717 } 6718 6719 6720 class NativeFunctionExtension : public Extension { 6721 public: 6722 NativeFunctionExtension(const char* name, 6723 const char* source, 6724 v8::FunctionCallback fun = &Echo) 6725 : Extension(name, source), 6726 function_(fun) { } 6727 6728 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 6729 v8::Isolate* isolate, 6730 v8::Handle<v8::String> name) { 6731 return v8::FunctionTemplate::New(function_); 6732 } 6733 6734 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 6735 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 6736 } 6737 private: 6738 v8::FunctionCallback function_; 6739 }; 6740 6741 6742 THREADED_TEST(NativeFunctionDeclaration) { 6743 v8::HandleScope handle_scope(CcTest::isolate()); 6744 const char* name = "nativedecl"; 6745 v8::RegisterExtension(new NativeFunctionExtension(name, 6746 "native function foo();")); 6747 const char* extension_names[] = { name }; 6748 v8::ExtensionConfiguration extensions(1, extension_names); 6749 v8::Handle<Context> context = 6750 Context::New(CcTest::isolate(), &extensions); 6751 Context::Scope lock(context); 6752 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run(); 6753 CHECK_EQ(result, v8::Integer::New(42)); 6754 } 6755 6756 6757 THREADED_TEST(NativeFunctionDeclarationError) { 6758 v8::HandleScope handle_scope(CcTest::isolate()); 6759 const char* name = "nativedeclerr"; 6760 // Syntax error in extension code. 6761 v8::RegisterExtension(new NativeFunctionExtension(name, 6762 "native\nfunction foo();")); 6763 const char* extension_names[] = { name }; 6764 v8::ExtensionConfiguration extensions(1, extension_names); 6765 v8::Handle<Context> context = 6766 Context::New(CcTest::isolate(), &extensions); 6767 CHECK(context.IsEmpty()); 6768 } 6769 6770 6771 THREADED_TEST(NativeFunctionDeclarationErrorEscape) { 6772 v8::HandleScope handle_scope(CcTest::isolate()); 6773 const char* name = "nativedeclerresc"; 6774 // Syntax error in extension code - escape code in "native" means that 6775 // it's not treated as a keyword. 6776 v8::RegisterExtension(new NativeFunctionExtension( 6777 name, 6778 "nativ\\u0065 function foo();")); 6779 const char* extension_names[] = { name }; 6780 v8::ExtensionConfiguration extensions(1, extension_names); 6781 v8::Handle<Context> context = 6782 Context::New(CcTest::isolate(), &extensions); 6783 CHECK(context.IsEmpty()); 6784 } 6785 6786 6787 static void CheckDependencies(const char* name, const char* expected) { 6788 v8::HandleScope handle_scope(CcTest::isolate()); 6789 v8::ExtensionConfiguration config(1, &name); 6790 LocalContext context(&config); 6791 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected), 6792 context->Global()->Get(v8_str("loaded"))); 6793 } 6794 6795 6796 /* 6797 * Configuration: 6798 * 6799 * /-- B <--\ 6800 * A <- -- D <-- E 6801 * \-- C <--/ 6802 */ 6803 THREADED_TEST(ExtensionDependency) { 6804 static const char* kEDeps[] = { "D" }; 6805 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 6806 static const char* kDDeps[] = { "B", "C" }; 6807 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 6808 static const char* kBCDeps[] = { "A" }; 6809 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 6810 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 6811 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 6812 CheckDependencies("A", "undefinedA"); 6813 CheckDependencies("B", "undefinedAB"); 6814 CheckDependencies("C", "undefinedAC"); 6815 CheckDependencies("D", "undefinedABCD"); 6816 CheckDependencies("E", "undefinedABCDE"); 6817 v8::HandleScope handle_scope(CcTest::isolate()); 6818 static const char* exts[2] = { "C", "E" }; 6819 v8::ExtensionConfiguration config(2, exts); 6820 LocalContext context(&config); 6821 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded"))); 6822 } 6823 6824 6825 static const char* kExtensionTestScript = 6826 "native function A();" 6827 "native function B();" 6828 "native function C();" 6829 "function Foo(i) {" 6830 " if (i == 0) return A();" 6831 " if (i == 1) return B();" 6832 " if (i == 2) return C();" 6833 "}"; 6834 6835 6836 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 6837 ApiTestFuzzer::Fuzz(); 6838 if (args.IsConstructCall()) { 6839 args.This()->Set(v8_str("data"), args.Data()); 6840 args.GetReturnValue().SetNull(); 6841 return; 6842 } 6843 args.GetReturnValue().Set(args.Data()); 6844 } 6845 6846 6847 class FunctionExtension : public Extension { 6848 public: 6849 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { } 6850 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 6851 v8::Isolate* isolate, 6852 v8::Handle<String> name); 6853 }; 6854 6855 6856 static int lookup_count = 0; 6857 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate( 6858 v8::Isolate* isolate, v8::Handle<String> name) { 6859 lookup_count++; 6860 if (name->Equals(v8_str("A"))) { 6861 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8)); 6862 } else if (name->Equals(v8_str("B"))) { 6863 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7)); 6864 } else if (name->Equals(v8_str("C"))) { 6865 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6)); 6866 } else { 6867 return v8::Handle<v8::FunctionTemplate>(); 6868 } 6869 } 6870 6871 6872 THREADED_TEST(FunctionLookup) { 6873 v8::RegisterExtension(new FunctionExtension()); 6874 v8::HandleScope handle_scope(CcTest::isolate()); 6875 static const char* exts[1] = { "functiontest" }; 6876 v8::ExtensionConfiguration config(1, exts); 6877 LocalContext context(&config); 6878 CHECK_EQ(3, lookup_count); 6879 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run()); 6880 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run()); 6881 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run()); 6882 } 6883 6884 6885 THREADED_TEST(NativeFunctionConstructCall) { 6886 v8::RegisterExtension(new FunctionExtension()); 6887 v8::HandleScope handle_scope(CcTest::isolate()); 6888 static const char* exts[1] = { "functiontest" }; 6889 v8::ExtensionConfiguration config(1, exts); 6890 LocalContext context(&config); 6891 for (int i = 0; i < 10; i++) { 6892 // Run a few times to ensure that allocation of objects doesn't 6893 // change behavior of a constructor function. 6894 CHECK_EQ(v8::Integer::New(8), 6895 Script::Compile(v8_str("(new A()).data"))->Run()); 6896 CHECK_EQ(v8::Integer::New(7), 6897 Script::Compile(v8_str("(new B()).data"))->Run()); 6898 CHECK_EQ(v8::Integer::New(6), 6899 Script::Compile(v8_str("(new C()).data"))->Run()); 6900 } 6901 } 6902 6903 6904 static const char* last_location; 6905 static const char* last_message; 6906 void StoringErrorCallback(const char* location, const char* message) { 6907 if (last_location == NULL) { 6908 last_location = location; 6909 last_message = message; 6910 } 6911 } 6912 6913 6914 // ErrorReporting creates a circular extensions configuration and 6915 // tests that the fatal error handler gets called. This renders V8 6916 // unusable and therefore this test cannot be run in parallel. 6917 TEST(ErrorReporting) { 6918 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 6919 static const char* aDeps[] = { "B" }; 6920 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 6921 static const char* bDeps[] = { "A" }; 6922 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 6923 last_location = NULL; 6924 v8::ExtensionConfiguration config(1, bDeps); 6925 v8::Handle<Context> context = 6926 Context::New(CcTest::isolate(), &config); 6927 CHECK(context.IsEmpty()); 6928 CHECK_NE(last_location, NULL); 6929 } 6930 6931 6932 static const char* js_code_causing_huge_string_flattening = 6933 "var str = 'X';" 6934 "for (var i = 0; i < 30; i++) {" 6935 " str = str + str;" 6936 "}" 6937 "str.match(/X/);"; 6938 6939 6940 void OOMCallback(const char* location, const char* message) { 6941 exit(0); 6942 } 6943 6944 6945 TEST(RegexpOutOfMemory) { 6946 // Execute a script that causes out of memory when flattening a string. 6947 v8::HandleScope scope(CcTest::isolate()); 6948 v8::V8::SetFatalErrorHandler(OOMCallback); 6949 LocalContext context; 6950 Local<Script> script = Script::Compile(String::NewFromUtf8( 6951 CcTest::isolate(), js_code_causing_huge_string_flattening)); 6952 last_location = NULL; 6953 script->Run(); 6954 6955 CHECK(false); // Should not return. 6956 } 6957 6958 6959 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, 6960 v8::Handle<Value> data) { 6961 CHECK(message->GetScriptResourceName()->IsUndefined()); 6962 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName()); 6963 message->GetLineNumber(); 6964 message->GetSourceLine(); 6965 } 6966 6967 6968 THREADED_TEST(ErrorWithMissingScriptInfo) { 6969 LocalContext context; 6970 v8::HandleScope scope(context->GetIsolate()); 6971 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); 6972 Script::Compile(v8_str("throw Error()"))->Run(); 6973 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); 6974 } 6975 6976 6977 int global_index = 0; 6978 6979 template<typename T> 6980 class Snorkel { 6981 public: 6982 explicit Snorkel(v8::Persistent<T>* handle) : handle_(handle) { 6983 index_ = global_index++; 6984 } 6985 v8::Persistent<T>* handle_; 6986 int index_; 6987 }; 6988 6989 class Whammy { 6990 public: 6991 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { } 6992 ~Whammy() { script_.Reset(); } 6993 v8::Handle<Script> getScript() { 6994 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo")); 6995 return Local<Script>::New(isolate_, script_); 6996 } 6997 6998 public: 6999 static const int kObjectCount = 256; 7000 int cursor_; 7001 v8::Isolate* isolate_; 7002 v8::Persistent<v8::Object> objects_[kObjectCount]; 7003 v8::Persistent<Script> script_; 7004 }; 7005 7006 static void HandleWeakReference( 7007 const v8::WeakCallbackData<v8::Value, Snorkel<v8::Value> >& data) { 7008 data.GetParameter()->handle_->ClearWeak(); 7009 delete data.GetParameter(); 7010 } 7011 7012 void WhammyPropertyGetter(Local<String> name, 7013 const v8::PropertyCallbackInfo<v8::Value>& info) { 7014 Whammy* whammy = 7015 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); 7016 7017 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_]; 7018 7019 v8::Handle<v8::Object> obj = v8::Object::New(); 7020 if (!prev.IsEmpty()) { 7021 v8::Local<v8::Object>::New(info.GetIsolate(), prev) 7022 ->Set(v8_str("next"), obj); 7023 prev.SetWeak<Value, Snorkel<Value> >(new Snorkel<Value>(&prev.As<Value>()), 7024 &HandleWeakReference); 7025 } 7026 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj); 7027 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount; 7028 info.GetReturnValue().Set(whammy->getScript()->Run()); 7029 } 7030 7031 7032 THREADED_TEST(WeakReference) { 7033 v8::HandleScope handle_scope(CcTest::isolate()); 7034 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(); 7035 Whammy* whammy = new Whammy(CcTest::isolate()); 7036 templ->SetNamedPropertyHandler(WhammyPropertyGetter, 7037 0, 0, 0, 0, 7038 v8::External::New(CcTest::isolate(), whammy)); 7039 const char* extension_list[] = { "v8/gc" }; 7040 v8::ExtensionConfiguration extensions(1, extension_list); 7041 v8::Handle<Context> context = 7042 Context::New(CcTest::isolate(), &extensions); 7043 Context::Scope context_scope(context); 7044 7045 v8::Handle<v8::Object> interceptor = templ->NewInstance(); 7046 context->Global()->Set(v8_str("whammy"), interceptor); 7047 const char* code = 7048 "var last;" 7049 "for (var i = 0; i < 10000; i++) {" 7050 " var obj = whammy.length;" 7051 " if (last) last.next = obj;" 7052 " last = obj;" 7053 "}" 7054 "gc();" 7055 "4"; 7056 v8::Handle<Value> result = CompileRun(code); 7057 CHECK_EQ(4.0, result->NumberValue()); 7058 delete whammy; 7059 } 7060 7061 7062 struct FlagAndPersistent { 7063 bool flag; 7064 v8::Persistent<v8::Object> handle; 7065 }; 7066 7067 7068 static void DisposeAndSetFlag( 7069 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7070 data.GetParameter()->handle.Reset(); 7071 data.GetParameter()->flag = true; 7072 } 7073 7074 7075 THREADED_TEST(IndependentWeakHandle) { 7076 v8::Isolate* iso = CcTest::isolate(); 7077 v8::HandleScope scope(iso); 7078 v8::Handle<Context> context = Context::New(iso); 7079 Context::Scope context_scope(context); 7080 7081 FlagAndPersistent object_a, object_b; 7082 7083 { 7084 v8::HandleScope handle_scope(iso); 7085 object_a.handle.Reset(iso, v8::Object::New()); 7086 object_b.handle.Reset(iso, v8::Object::New()); 7087 } 7088 7089 object_a.flag = false; 7090 object_b.flag = false; 7091 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag); 7092 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag); 7093 CHECK(!object_b.handle.IsIndependent()); 7094 object_a.handle.MarkIndependent(); 7095 object_b.handle.MarkIndependent(); 7096 CHECK(object_b.handle.IsIndependent()); 7097 CcTest::heap()->PerformScavenge(); 7098 CHECK(object_a.flag); 7099 CHECK(object_b.flag); 7100 } 7101 7102 7103 static void InvokeScavenge() { 7104 CcTest::heap()->PerformScavenge(); 7105 } 7106 7107 7108 static void InvokeMarkSweep() { 7109 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7110 } 7111 7112 7113 static void ForceScavenge( 7114 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7115 data.GetParameter()->handle.Reset(); 7116 data.GetParameter()->flag = true; 7117 InvokeScavenge(); 7118 } 7119 7120 7121 static void ForceMarkSweep( 7122 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7123 data.GetParameter()->handle.Reset(); 7124 data.GetParameter()->flag = true; 7125 InvokeMarkSweep(); 7126 } 7127 7128 7129 THREADED_TEST(GCFromWeakCallbacks) { 7130 v8::Isolate* isolate = CcTest::isolate(); 7131 v8::HandleScope scope(isolate); 7132 v8::Handle<Context> context = Context::New(isolate); 7133 Context::Scope context_scope(context); 7134 7135 static const int kNumberOfGCTypes = 2; 7136 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback 7137 Callback; 7138 Callback gc_forcing_callback[kNumberOfGCTypes] = 7139 {&ForceScavenge, &ForceMarkSweep}; 7140 7141 typedef void (*GCInvoker)(); 7142 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 7143 7144 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 7145 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 7146 FlagAndPersistent object; 7147 { 7148 v8::HandleScope handle_scope(isolate); 7149 object.handle.Reset(isolate, v8::Object::New()); 7150 } 7151 object.flag = false; 7152 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]); 7153 object.handle.MarkIndependent(); 7154 invoke_gc[outer_gc](); 7155 CHECK(object.flag); 7156 } 7157 } 7158 } 7159 7160 7161 static void RevivingCallback( 7162 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { 7163 data.GetParameter()->handle.ClearWeak(); 7164 data.GetParameter()->flag = true; 7165 } 7166 7167 7168 THREADED_TEST(IndependentHandleRevival) { 7169 v8::Isolate* isolate = CcTest::isolate(); 7170 v8::HandleScope scope(isolate); 7171 v8::Handle<Context> context = Context::New(isolate); 7172 Context::Scope context_scope(context); 7173 7174 FlagAndPersistent object; 7175 { 7176 v8::HandleScope handle_scope(isolate); 7177 v8::Local<v8::Object> o = v8::Object::New(); 7178 object.handle.Reset(isolate, o); 7179 o->Set(v8_str("x"), v8::Integer::New(1)); 7180 v8::Local<String> y_str = v8_str("y"); 7181 o->Set(y_str, y_str); 7182 } 7183 object.flag = false; 7184 object.handle.SetWeak(&object, &RevivingCallback); 7185 object.handle.MarkIndependent(); 7186 CcTest::heap()->PerformScavenge(); 7187 CHECK(object.flag); 7188 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 7189 { 7190 v8::HandleScope handle_scope(isolate); 7191 v8::Local<v8::Object> o = 7192 v8::Local<v8::Object>::New(isolate, object.handle); 7193 v8::Local<String> y_str = v8_str("y"); 7194 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x"))); 7195 CHECK(o->Get(y_str)->Equals(y_str)); 7196 } 7197 } 7198 7199 7200 v8::Handle<Function> args_fun; 7201 7202 7203 static void ArgumentsTestCallback( 7204 const v8::FunctionCallbackInfo<v8::Value>& args) { 7205 ApiTestFuzzer::Fuzz(); 7206 v8::Isolate* isolate = args.GetIsolate(); 7207 CHECK_EQ(args_fun, args.Callee()); 7208 CHECK_EQ(3, args.Length()); 7209 CHECK_EQ(v8::Integer::New(1, isolate), args[0]); 7210 CHECK_EQ(v8::Integer::New(2, isolate), args[1]); 7211 CHECK_EQ(v8::Integer::New(3, isolate), args[2]); 7212 CHECK_EQ(v8::Undefined(isolate), args[3]); 7213 v8::HandleScope scope(args.GetIsolate()); 7214 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 7215 } 7216 7217 7218 THREADED_TEST(Arguments) { 7219 v8::HandleScope scope(CcTest::isolate()); 7220 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 7221 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback)); 7222 LocalContext context(NULL, global); 7223 args_fun = context->Global()->Get(v8_str("f")).As<Function>(); 7224 v8_compile("f(1, 2, 3)")->Run(); 7225 } 7226 7227 7228 static void NoBlockGetterX(Local<String> name, 7229 const v8::PropertyCallbackInfo<v8::Value>&) { 7230 } 7231 7232 7233 static void NoBlockGetterI(uint32_t index, 7234 const v8::PropertyCallbackInfo<v8::Value>&) { 7235 } 7236 7237 7238 static void PDeleter(Local<String> name, 7239 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7240 if (!name->Equals(v8_str("foo"))) { 7241 return; // not intercepted 7242 } 7243 7244 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7245 } 7246 7247 7248 static void IDeleter(uint32_t index, 7249 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 7250 if (index != 2) { 7251 return; // not intercepted 7252 } 7253 7254 info.GetReturnValue().Set(false); // intercepted, don't delete the property 7255 } 7256 7257 7258 THREADED_TEST(Deleter) { 7259 v8::HandleScope scope(CcTest::isolate()); 7260 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7261 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL); 7262 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL); 7263 LocalContext context; 7264 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7265 CompileRun( 7266 "k.foo = 'foo';" 7267 "k.bar = 'bar';" 7268 "k[2] = 2;" 7269 "k[4] = 4;"); 7270 CHECK(v8_compile("delete k.foo")->Run()->IsFalse()); 7271 CHECK(v8_compile("delete k.bar")->Run()->IsTrue()); 7272 7273 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo")); 7274 CHECK(v8_compile("k.bar")->Run()->IsUndefined()); 7275 7276 CHECK(v8_compile("delete k[2]")->Run()->IsFalse()); 7277 CHECK(v8_compile("delete k[4]")->Run()->IsTrue()); 7278 7279 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2)); 7280 CHECK(v8_compile("k[4]")->Run()->IsUndefined()); 7281 } 7282 7283 7284 static void GetK(Local<String> name, 7285 const v8::PropertyCallbackInfo<v8::Value>& info) { 7286 ApiTestFuzzer::Fuzz(); 7287 if (name->Equals(v8_str("foo")) || 7288 name->Equals(v8_str("bar")) || 7289 name->Equals(v8_str("baz"))) { 7290 info.GetReturnValue().SetUndefined(); 7291 } 7292 } 7293 7294 7295 static void IndexedGetK(uint32_t index, 7296 const v8::PropertyCallbackInfo<v8::Value>& info) { 7297 ApiTestFuzzer::Fuzz(); 7298 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined(); 7299 } 7300 7301 7302 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7303 ApiTestFuzzer::Fuzz(); 7304 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3); 7305 result->Set(v8::Integer::New(0), v8_str("foo")); 7306 result->Set(v8::Integer::New(1), v8_str("bar")); 7307 result->Set(v8::Integer::New(2), v8_str("baz")); 7308 info.GetReturnValue().Set(result); 7309 } 7310 7311 7312 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 7313 ApiTestFuzzer::Fuzz(); 7314 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 7315 result->Set(v8::Integer::New(0), v8_str("0")); 7316 result->Set(v8::Integer::New(1), v8_str("1")); 7317 info.GetReturnValue().Set(result); 7318 } 7319 7320 7321 THREADED_TEST(Enumerators) { 7322 v8::HandleScope scope(CcTest::isolate()); 7323 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7324 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); 7325 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); 7326 LocalContext context; 7327 context->Global()->Set(v8_str("k"), obj->NewInstance()); 7328 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 7329 "k[10] = 0;" 7330 "k.a = 0;" 7331 "k[5] = 0;" 7332 "k.b = 0;" 7333 "k[4294967295] = 0;" 7334 "k.c = 0;" 7335 "k[4294967296] = 0;" 7336 "k.d = 0;" 7337 "k[140000] = 0;" 7338 "k.e = 0;" 7339 "k[30000000000] = 0;" 7340 "k.f = 0;" 7341 "var result = [];" 7342 "for (var prop in k) {" 7343 " result.push(prop);" 7344 "}" 7345 "result")); 7346 // Check that we get all the property names returned including the 7347 // ones from the enumerators in the right order: indexed properties 7348 // in numerical order, indexed interceptor properties, named 7349 // properties in insertion order, named interceptor properties. 7350 // This order is not mandated by the spec, so this test is just 7351 // documenting our behavior. 7352 CHECK_EQ(17, result->Length()); 7353 // Indexed properties in numerical order. 7354 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0))); 7355 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1))); 7356 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2))); 7357 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3))); 7358 // Indexed interceptor properties in the order they are returned 7359 // from the enumerator interceptor. 7360 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4))); 7361 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5))); 7362 // Named properties in insertion order. 7363 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6))); 7364 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7))); 7365 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8))); 7366 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9))); 7367 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10))); 7368 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11))); 7369 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12))); 7370 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13))); 7371 // Named interceptor properties. 7372 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14))); 7373 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15))); 7374 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16))); 7375 } 7376 7377 7378 int p_getter_count; 7379 int p_getter_count2; 7380 7381 7382 static void PGetter(Local<String> name, 7383 const v8::PropertyCallbackInfo<v8::Value>& info) { 7384 ApiTestFuzzer::Fuzz(); 7385 p_getter_count++; 7386 v8::Handle<v8::Object> global = 7387 info.GetIsolate()->GetCurrentContext()->Global(); 7388 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7389 if (name->Equals(v8_str("p1"))) { 7390 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7391 } else if (name->Equals(v8_str("p2"))) { 7392 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7393 } else if (name->Equals(v8_str("p3"))) { 7394 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7395 } else if (name->Equals(v8_str("p4"))) { 7396 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7397 } 7398 } 7399 7400 7401 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) { 7402 ApiTestFuzzer::Fuzz(); 7403 LocalContext context; 7404 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 7405 CompileRun( 7406 "o1.__proto__ = { };" 7407 "var o2 = { __proto__: o1 };" 7408 "var o3 = { __proto__: o2 };" 7409 "var o4 = { __proto__: o3 };" 7410 "for (var i = 0; i < 10; i++) o4.p4;" 7411 "for (var i = 0; i < 10; i++) o3.p3;" 7412 "for (var i = 0; i < 10; i++) o2.p2;" 7413 "for (var i = 0; i < 10; i++) o1.p1;"); 7414 } 7415 7416 7417 static void PGetter2(Local<String> name, 7418 const v8::PropertyCallbackInfo<v8::Value>& info) { 7419 ApiTestFuzzer::Fuzz(); 7420 p_getter_count2++; 7421 v8::Handle<v8::Object> global = 7422 info.GetIsolate()->GetCurrentContext()->Global(); 7423 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7424 if (name->Equals(v8_str("p1"))) { 7425 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7426 } else if (name->Equals(v8_str("p2"))) { 7427 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7428 } else if (name->Equals(v8_str("p3"))) { 7429 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7430 } else if (name->Equals(v8_str("p4"))) { 7431 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7432 } 7433 } 7434 7435 7436 THREADED_TEST(GetterHolders) { 7437 v8::HandleScope scope(CcTest::isolate()); 7438 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7439 obj->SetAccessor(v8_str("p1"), PGetter); 7440 obj->SetAccessor(v8_str("p2"), PGetter); 7441 obj->SetAccessor(v8_str("p3"), PGetter); 7442 obj->SetAccessor(v8_str("p4"), PGetter); 7443 p_getter_count = 0; 7444 RunHolderTest(obj); 7445 CHECK_EQ(40, p_getter_count); 7446 } 7447 7448 7449 THREADED_TEST(PreInterceptorHolders) { 7450 v8::HandleScope scope(CcTest::isolate()); 7451 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7452 obj->SetNamedPropertyHandler(PGetter2); 7453 p_getter_count2 = 0; 7454 RunHolderTest(obj); 7455 CHECK_EQ(40, p_getter_count2); 7456 } 7457 7458 7459 THREADED_TEST(ObjectInstantiation) { 7460 v8::Isolate* isolate = CcTest::isolate(); 7461 v8::HandleScope scope(isolate); 7462 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 7463 templ->SetAccessor(v8_str("t"), PGetter2); 7464 LocalContext context; 7465 context->Global()->Set(v8_str("o"), templ->NewInstance()); 7466 for (int i = 0; i < 100; i++) { 7467 v8::HandleScope inner_scope(CcTest::isolate()); 7468 v8::Handle<v8::Object> obj = templ->NewInstance(); 7469 CHECK_NE(obj, context->Global()->Get(v8_str("o"))); 7470 context->Global()->Set(v8_str("o2"), obj); 7471 v8::Handle<Value> value = 7472 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run(); 7473 CHECK_EQ(v8::True(isolate), value); 7474 context->Global()->Set(v8_str("o"), obj); 7475 } 7476 } 7477 7478 7479 static int StrCmp16(uint16_t* a, uint16_t* b) { 7480 while (true) { 7481 if (*a == 0 && *b == 0) return 0; 7482 if (*a != *b) return 0 + *a - *b; 7483 a++; 7484 b++; 7485 } 7486 } 7487 7488 7489 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 7490 while (true) { 7491 if (n-- == 0) return 0; 7492 if (*a == 0 && *b == 0) return 0; 7493 if (*a != *b) return 0 + *a - *b; 7494 a++; 7495 b++; 7496 } 7497 } 7498 7499 7500 int GetUtf8Length(Handle<String> str) { 7501 int len = str->Utf8Length(); 7502 if (len < 0) { 7503 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 7504 i::FlattenString(istr); 7505 len = str->Utf8Length(); 7506 } 7507 return len; 7508 } 7509 7510 7511 THREADED_TEST(StringWrite) { 7512 LocalContext context; 7513 v8::HandleScope scope(context->GetIsolate()); 7514 v8::Handle<String> str = v8_str("abcde"); 7515 // abc<Icelandic eth><Unicode snowman>. 7516 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203"); 7517 v8::Handle<String> str3 = v8::String::NewFromUtf8( 7518 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7); 7519 const int kStride = 4; // Must match stride in for loops in JS below. 7520 CompileRun( 7521 "var left = '';" 7522 "for (var i = 0; i < 0xd800; i += 4) {" 7523 " left = left + String.fromCharCode(i);" 7524 "}"); 7525 CompileRun( 7526 "var right = '';" 7527 "for (var i = 0; i < 0xd800; i += 4) {" 7528 " right = String.fromCharCode(i) + right;" 7529 "}"); 7530 v8::Handle<v8::Object> global = context->Global(); 7531 Handle<String> left_tree = global->Get(v8_str("left")).As<String>(); 7532 Handle<String> right_tree = global->Get(v8_str("right")).As<String>(); 7533 7534 CHECK_EQ(5, str2->Length()); 7535 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 7536 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 7537 7538 char buf[100]; 7539 char utf8buf[0xd800 * 3]; 7540 uint16_t wbuf[100]; 7541 int len; 7542 int charlen; 7543 7544 memset(utf8buf, 0x1, 1000); 7545 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7546 CHECK_EQ(9, len); 7547 CHECK_EQ(5, charlen); 7548 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7549 7550 memset(utf8buf, 0x1, 1000); 7551 len = str2->WriteUtf8(utf8buf, 8, &charlen); 7552 CHECK_EQ(8, len); 7553 CHECK_EQ(5, charlen); 7554 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 7555 7556 memset(utf8buf, 0x1, 1000); 7557 len = str2->WriteUtf8(utf8buf, 7, &charlen); 7558 CHECK_EQ(5, len); 7559 CHECK_EQ(4, charlen); 7560 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7561 7562 memset(utf8buf, 0x1, 1000); 7563 len = str2->WriteUtf8(utf8buf, 6, &charlen); 7564 CHECK_EQ(5, len); 7565 CHECK_EQ(4, charlen); 7566 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7567 7568 memset(utf8buf, 0x1, 1000); 7569 len = str2->WriteUtf8(utf8buf, 5, &charlen); 7570 CHECK_EQ(5, len); 7571 CHECK_EQ(4, charlen); 7572 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7573 7574 memset(utf8buf, 0x1, 1000); 7575 len = str2->WriteUtf8(utf8buf, 4, &charlen); 7576 CHECK_EQ(3, len); 7577 CHECK_EQ(3, charlen); 7578 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7579 7580 memset(utf8buf, 0x1, 1000); 7581 len = str2->WriteUtf8(utf8buf, 3, &charlen); 7582 CHECK_EQ(3, len); 7583 CHECK_EQ(3, charlen); 7584 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7585 7586 memset(utf8buf, 0x1, 1000); 7587 len = str2->WriteUtf8(utf8buf, 2, &charlen); 7588 CHECK_EQ(2, len); 7589 CHECK_EQ(2, charlen); 7590 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 7591 7592 memset(utf8buf, 0x1, sizeof(utf8buf)); 7593 len = GetUtf8Length(left_tree); 7594 int utf8_expected = 7595 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 7596 CHECK_EQ(utf8_expected, len); 7597 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7598 CHECK_EQ(utf8_expected, len); 7599 CHECK_EQ(0xd800 / kStride, charlen); 7600 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 7601 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 7602 CHECK_EQ(0xc0 - kStride, 7603 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 7604 CHECK_EQ(1, utf8buf[utf8_expected]); 7605 7606 memset(utf8buf, 0x1, sizeof(utf8buf)); 7607 len = GetUtf8Length(right_tree); 7608 CHECK_EQ(utf8_expected, len); 7609 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7610 CHECK_EQ(utf8_expected, len); 7611 CHECK_EQ(0xd800 / kStride, charlen); 7612 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 7613 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 7614 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 7615 CHECK_EQ(1, utf8buf[utf8_expected]); 7616 7617 memset(buf, 0x1, sizeof(buf)); 7618 memset(wbuf, 0x1, sizeof(wbuf)); 7619 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7620 CHECK_EQ(5, len); 7621 len = str->Write(wbuf); 7622 CHECK_EQ(5, len); 7623 CHECK_EQ(0, strcmp("abcde", buf)); 7624 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7625 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 7626 7627 memset(buf, 0x1, sizeof(buf)); 7628 memset(wbuf, 0x1, sizeof(wbuf)); 7629 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 7630 CHECK_EQ(4, len); 7631 len = str->Write(wbuf, 0, 4); 7632 CHECK_EQ(4, len); 7633 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 7634 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 7635 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 7636 7637 memset(buf, 0x1, sizeof(buf)); 7638 memset(wbuf, 0x1, sizeof(wbuf)); 7639 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 7640 CHECK_EQ(5, len); 7641 len = str->Write(wbuf, 0, 5); 7642 CHECK_EQ(5, len); 7643 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 7644 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 7645 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 7646 7647 memset(buf, 0x1, sizeof(buf)); 7648 memset(wbuf, 0x1, sizeof(wbuf)); 7649 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 7650 CHECK_EQ(5, len); 7651 len = str->Write(wbuf, 0, 6); 7652 CHECK_EQ(5, len); 7653 CHECK_EQ(0, strcmp("abcde", buf)); 7654 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7655 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 7656 7657 memset(buf, 0x1, sizeof(buf)); 7658 memset(wbuf, 0x1, sizeof(wbuf)); 7659 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 7660 CHECK_EQ(1, len); 7661 len = str->Write(wbuf, 4, -1); 7662 CHECK_EQ(1, len); 7663 CHECK_EQ(0, strcmp("e", buf)); 7664 uint16_t answer5[] = {'e', '\0'}; 7665 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7666 7667 memset(buf, 0x1, sizeof(buf)); 7668 memset(wbuf, 0x1, sizeof(wbuf)); 7669 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 7670 CHECK_EQ(1, len); 7671 len = str->Write(wbuf, 4, 6); 7672 CHECK_EQ(1, len); 7673 CHECK_EQ(0, strcmp("e", buf)); 7674 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7675 7676 memset(buf, 0x1, sizeof(buf)); 7677 memset(wbuf, 0x1, sizeof(wbuf)); 7678 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 7679 CHECK_EQ(1, len); 7680 len = str->Write(wbuf, 4, 1); 7681 CHECK_EQ(1, len); 7682 CHECK_EQ(0, strncmp("e\1", buf, 2)); 7683 uint16_t answer6[] = {'e', 0x101}; 7684 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 7685 7686 memset(buf, 0x1, sizeof(buf)); 7687 memset(wbuf, 0x1, sizeof(wbuf)); 7688 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 7689 CHECK_EQ(1, len); 7690 len = str->Write(wbuf, 3, 1); 7691 CHECK_EQ(1, len); 7692 CHECK_EQ(0, strncmp("d\1", buf, 2)); 7693 uint16_t answer7[] = {'d', 0x101}; 7694 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 7695 7696 memset(wbuf, 0x1, sizeof(wbuf)); 7697 wbuf[5] = 'X'; 7698 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 7699 CHECK_EQ(5, len); 7700 CHECK_EQ('X', wbuf[5]); 7701 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 7702 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7703 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 7704 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 7705 wbuf[5] = '\0'; 7706 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 7707 7708 memset(buf, 0x1, sizeof(buf)); 7709 buf[5] = 'X'; 7710 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 7711 0, 7712 6, 7713 String::NO_NULL_TERMINATION); 7714 CHECK_EQ(5, len); 7715 CHECK_EQ('X', buf[5]); 7716 CHECK_EQ(0, strncmp("abcde", buf, 5)); 7717 CHECK_NE(0, strcmp("abcde", buf)); 7718 buf[5] = '\0'; 7719 CHECK_EQ(0, strcmp("abcde", buf)); 7720 7721 memset(utf8buf, 0x1, sizeof(utf8buf)); 7722 utf8buf[8] = 'X'; 7723 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7724 String::NO_NULL_TERMINATION); 7725 CHECK_EQ(8, len); 7726 CHECK_EQ('X', utf8buf[8]); 7727 CHECK_EQ(5, charlen); 7728 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 7729 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7730 utf8buf[8] = '\0'; 7731 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7732 7733 memset(utf8buf, 0x1, sizeof(utf8buf)); 7734 utf8buf[5] = 'X'; 7735 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7736 String::NO_NULL_TERMINATION); 7737 CHECK_EQ(5, len); 7738 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 7739 CHECK_EQ(5, charlen); 7740 utf8buf[5] = '\0'; 7741 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 7742 7743 memset(buf, 0x1, sizeof(buf)); 7744 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7745 CHECK_EQ(7, len); 7746 CHECK_EQ(0, strcmp("abc", buf)); 7747 CHECK_EQ(0, buf[3]); 7748 CHECK_EQ(0, strcmp("def", buf + 4)); 7749 7750 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7751 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7752 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7753 } 7754 7755 7756 static void Utf16Helper( 7757 LocalContext& context, 7758 const char* name, 7759 const char* lengths_name, 7760 int len) { 7761 Local<v8::Array> a = 7762 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7763 Local<v8::Array> alens = 7764 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7765 for (int i = 0; i < len; i++) { 7766 Local<v8::String> string = 7767 Local<v8::String>::Cast(a->Get(i)); 7768 Local<v8::Number> expected_len = 7769 Local<v8::Number>::Cast(alens->Get(i)); 7770 int length = GetUtf8Length(string); 7771 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 7772 } 7773 } 7774 7775 7776 static uint16_t StringGet(Handle<String> str, int index) { 7777 i::Handle<i::String> istring = 7778 v8::Utils::OpenHandle(String::Cast(*str)); 7779 return istring->Get(index); 7780 } 7781 7782 7783 static void WriteUtf8Helper( 7784 LocalContext& context, 7785 const char* name, 7786 const char* lengths_name, 7787 int len) { 7788 Local<v8::Array> b = 7789 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7790 Local<v8::Array> alens = 7791 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7792 char buffer[1000]; 7793 char buffer2[1000]; 7794 for (int i = 0; i < len; i++) { 7795 Local<v8::String> string = 7796 Local<v8::String>::Cast(b->Get(i)); 7797 Local<v8::Number> expected_len = 7798 Local<v8::Number>::Cast(alens->Get(i)); 7799 int utf8_length = static_cast<int>(expected_len->Value()); 7800 for (int j = utf8_length + 1; j >= 0; j--) { 7801 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer)); 7802 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2)); 7803 int nchars; 7804 int utf8_written = 7805 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS); 7806 int utf8_written2 = 7807 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION); 7808 CHECK_GE(utf8_length + 1, utf8_written); 7809 CHECK_GE(utf8_length, utf8_written2); 7810 for (int k = 0; k < utf8_written2; k++) { 7811 CHECK_EQ(buffer[k], buffer2[k]); 7812 } 7813 CHECK(nchars * 3 >= utf8_written - 1); 7814 CHECK(nchars <= utf8_written); 7815 if (j == utf8_length + 1) { 7816 CHECK_EQ(utf8_written2, utf8_length); 7817 CHECK_EQ(utf8_written2 + 1, utf8_written); 7818 } 7819 CHECK_EQ(buffer[utf8_written], 42); 7820 if (j > utf8_length) { 7821 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0); 7822 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42); 7823 Handle<String> roundtrip = v8_str(buffer); 7824 CHECK(roundtrip->Equals(string)); 7825 } else { 7826 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7827 } 7828 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7829 if (nchars >= 2) { 7830 uint16_t trail = StringGet(string, nchars - 1); 7831 uint16_t lead = StringGet(string, nchars - 2); 7832 if (((lead & 0xfc00) == 0xd800) && 7833 ((trail & 0xfc00) == 0xdc00)) { 7834 unsigned char u1 = buffer2[utf8_written2 - 4]; 7835 unsigned char u2 = buffer2[utf8_written2 - 3]; 7836 unsigned char u3 = buffer2[utf8_written2 - 2]; 7837 unsigned char u4 = buffer2[utf8_written2 - 1]; 7838 CHECK_EQ((u1 & 0xf8), 0xf0); 7839 CHECK_EQ((u2 & 0xc0), 0x80); 7840 CHECK_EQ((u3 & 0xc0), 0x80); 7841 CHECK_EQ((u4 & 0xc0), 0x80); 7842 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff); 7843 CHECK_EQ((u4 & 0x3f), (c & 0x3f)); 7844 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f)); 7845 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f)); 7846 CHECK_EQ((u1 & 0x3), c >> 18); 7847 } 7848 } 7849 } 7850 } 7851 } 7852 7853 7854 THREADED_TEST(Utf16) { 7855 LocalContext context; 7856 v8::HandleScope scope(context->GetIsolate()); 7857 CompileRun( 7858 "var pad = '01234567890123456789';" 7859 "var p = [];" 7860 "var plens = [20, 3, 3];" 7861 "p.push('01234567890123456789');" 7862 "var lead = 0xd800;" 7863 "var trail = 0xdc00;" 7864 "p.push(String.fromCharCode(0xd800));" 7865 "p.push(String.fromCharCode(0xdc00));" 7866 "var a = [];" 7867 "var b = [];" 7868 "var c = [];" 7869 "var alens = [];" 7870 "for (var i = 0; i < 3; i++) {" 7871 " p[1] = String.fromCharCode(lead++);" 7872 " for (var j = 0; j < 3; j++) {" 7873 " p[2] = String.fromCharCode(trail++);" 7874 " a.push(p[i] + p[j]);" 7875 " b.push(p[i] + p[j]);" 7876 " c.push(p[i] + p[j]);" 7877 " alens.push(plens[i] + plens[j]);" 7878 " }" 7879 "}" 7880 "alens[5] -= 2;" // Here the surrogate pairs match up. 7881 "var a2 = [];" 7882 "var b2 = [];" 7883 "var c2 = [];" 7884 "var a2lens = [];" 7885 "for (var m = 0; m < 9; m++) {" 7886 " for (var n = 0; n < 9; n++) {" 7887 " a2.push(a[m] + a[n]);" 7888 " b2.push(b[m] + b[n]);" 7889 " var newc = 'x' + c[m] + c[n] + 'y';" 7890 " c2.push(newc.substring(1, newc.length - 1));" 7891 " var utf = alens[m] + alens[n];" // And here. 7892 // The 'n's that start with 0xdc.. are 6-8 7893 // The 'm's that end with 0xd8.. are 1, 4 and 7 7894 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 7895 " a2lens.push(utf);" 7896 " }" 7897 "}"); 7898 Utf16Helper(context, "a", "alens", 9); 7899 Utf16Helper(context, "a2", "a2lens", 81); 7900 WriteUtf8Helper(context, "b", "alens", 9); 7901 WriteUtf8Helper(context, "b2", "a2lens", 81); 7902 WriteUtf8Helper(context, "c2", "a2lens", 81); 7903 } 7904 7905 7906 static bool SameSymbol(Handle<String> s1, Handle<String> s2) { 7907 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 7908 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 7909 return *is1 == *is2; 7910 } 7911 7912 static void SameSymbolHelper(v8::Isolate* isolate, const char* a, 7913 const char* b) { 7914 Handle<String> symbol1 = 7915 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString); 7916 Handle<String> symbol2 = 7917 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString); 7918 CHECK(SameSymbol(symbol1, symbol2)); 7919 } 7920 7921 7922 THREADED_TEST(Utf16Symbol) { 7923 LocalContext context; 7924 v8::HandleScope scope(context->GetIsolate()); 7925 7926 Handle<String> symbol1 = v8::String::NewFromUtf8( 7927 context->GetIsolate(), "abc", v8::String::kInternalizedString); 7928 Handle<String> symbol2 = v8::String::NewFromUtf8( 7929 context->GetIsolate(), "abc", v8::String::kInternalizedString); 7930 CHECK(SameSymbol(symbol1, symbol2)); 7931 7932 SameSymbolHelper(context->GetIsolate(), 7933 "\360\220\220\205", // 4 byte encoding. 7934 "\355\240\201\355\260\205"); // 2 3-byte surrogates. 7935 SameSymbolHelper(context->GetIsolate(), 7936 "\355\240\201\355\260\206", // 2 3-byte surrogates. 7937 "\360\220\220\206"); // 4 byte encoding. 7938 SameSymbolHelper(context->GetIsolate(), 7939 "x\360\220\220\205", // 4 byte encoding. 7940 "x\355\240\201\355\260\205"); // 2 3-byte surrogates. 7941 SameSymbolHelper(context->GetIsolate(), 7942 "x\355\240\201\355\260\206", // 2 3-byte surrogates. 7943 "x\360\220\220\206"); // 4 byte encoding. 7944 CompileRun( 7945 "var sym0 = 'benedictus';" 7946 "var sym0b = 'S\303\270ren';" 7947 "var sym1 = '\355\240\201\355\260\207';" 7948 "var sym2 = '\360\220\220\210';" 7949 "var sym3 = 'x\355\240\201\355\260\207';" 7950 "var sym4 = 'x\360\220\220\210';" 7951 "if (sym1.length != 2) throw sym1;" 7952 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 7953 "if (sym2.length != 2) throw sym2;" 7954 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 7955 "if (sym3.length != 3) throw sym3;" 7956 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 7957 "if (sym4.length != 3) throw sym4;" 7958 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 7959 Handle<String> sym0 = v8::String::NewFromUtf8( 7960 context->GetIsolate(), "benedictus", v8::String::kInternalizedString); 7961 Handle<String> sym0b = v8::String::NewFromUtf8( 7962 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString); 7963 Handle<String> sym1 = 7964 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207", 7965 v8::String::kInternalizedString); 7966 Handle<String> sym2 = 7967 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210", 7968 v8::String::kInternalizedString); 7969 Handle<String> sym3 = v8::String::NewFromUtf8( 7970 context->GetIsolate(), "x\355\240\201\355\260\207", 7971 v8::String::kInternalizedString); 7972 Handle<String> sym4 = 7973 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210", 7974 v8::String::kInternalizedString); 7975 v8::Local<v8::Object> global = context->Global(); 7976 Local<Value> s0 = global->Get(v8_str("sym0")); 7977 Local<Value> s0b = global->Get(v8_str("sym0b")); 7978 Local<Value> s1 = global->Get(v8_str("sym1")); 7979 Local<Value> s2 = global->Get(v8_str("sym2")); 7980 Local<Value> s3 = global->Get(v8_str("sym3")); 7981 Local<Value> s4 = global->Get(v8_str("sym4")); 7982 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0))); 7983 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b))); 7984 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1))); 7985 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2))); 7986 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3))); 7987 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4))); 7988 } 7989 7990 7991 THREADED_TEST(ToArrayIndex) { 7992 LocalContext context; 7993 v8::HandleScope scope(context->GetIsolate()); 7994 7995 v8::Handle<String> str = v8_str("42"); 7996 v8::Handle<v8::Uint32> index = str->ToArrayIndex(); 7997 CHECK(!index.IsEmpty()); 7998 CHECK_EQ(42.0, index->Uint32Value()); 7999 str = v8_str("42asdf"); 8000 index = str->ToArrayIndex(); 8001 CHECK(index.IsEmpty()); 8002 str = v8_str("-42"); 8003 index = str->ToArrayIndex(); 8004 CHECK(index.IsEmpty()); 8005 str = v8_str("4294967295"); 8006 index = str->ToArrayIndex(); 8007 CHECK(!index.IsEmpty()); 8008 CHECK_EQ(4294967295.0, index->Uint32Value()); 8009 v8::Handle<v8::Number> num = v8::Number::New(1); 8010 index = num->ToArrayIndex(); 8011 CHECK(!index.IsEmpty()); 8012 CHECK_EQ(1.0, index->Uint32Value()); 8013 num = v8::Number::New(-1); 8014 index = num->ToArrayIndex(); 8015 CHECK(index.IsEmpty()); 8016 v8::Handle<v8::Object> obj = v8::Object::New(); 8017 index = obj->ToArrayIndex(); 8018 CHECK(index.IsEmpty()); 8019 } 8020 8021 8022 THREADED_TEST(ErrorConstruction) { 8023 LocalContext context; 8024 v8::HandleScope scope(context->GetIsolate()); 8025 8026 v8::Handle<String> foo = v8_str("foo"); 8027 v8::Handle<String> message = v8_str("message"); 8028 v8::Handle<Value> range_error = v8::Exception::RangeError(foo); 8029 CHECK(range_error->IsObject()); 8030 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo)); 8031 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo); 8032 CHECK(reference_error->IsObject()); 8033 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo)); 8034 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo); 8035 CHECK(syntax_error->IsObject()); 8036 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo)); 8037 v8::Handle<Value> type_error = v8::Exception::TypeError(foo); 8038 CHECK(type_error->IsObject()); 8039 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo)); 8040 v8::Handle<Value> error = v8::Exception::Error(foo); 8041 CHECK(error->IsObject()); 8042 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo)); 8043 } 8044 8045 8046 static void YGetter(Local<String> name, 8047 const v8::PropertyCallbackInfo<v8::Value>& info) { 8048 ApiTestFuzzer::Fuzz(); 8049 info.GetReturnValue().Set(v8_num(10)); 8050 } 8051 8052 8053 static void YSetter(Local<String> name, 8054 Local<Value> value, 8055 const v8::PropertyCallbackInfo<void>& info) { 8056 if (info.This()->Has(name)) { 8057 info.This()->Delete(name); 8058 } 8059 info.This()->Set(name, value); 8060 } 8061 8062 8063 THREADED_TEST(DeleteAccessor) { 8064 v8::HandleScope scope(CcTest::isolate()); 8065 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 8066 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 8067 LocalContext context; 8068 v8::Handle<v8::Object> holder = obj->NewInstance(); 8069 context->Global()->Set(v8_str("holder"), holder); 8070 v8::Handle<Value> result = CompileRun( 8071 "holder.y = 11; holder.y = 12; holder.y"); 8072 CHECK_EQ(12, result->Uint32Value()); 8073 } 8074 8075 8076 THREADED_TEST(TypeSwitch) { 8077 v8::HandleScope scope(CcTest::isolate()); 8078 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(); 8079 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(); 8080 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(); 8081 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 }; 8082 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs); 8083 LocalContext context; 8084 v8::Handle<v8::Object> obj0 = v8::Object::New(); 8085 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance(); 8086 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance(); 8087 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance(); 8088 for (int i = 0; i < 10; i++) { 8089 CHECK_EQ(0, type_switch->match(obj0)); 8090 CHECK_EQ(1, type_switch->match(obj1)); 8091 CHECK_EQ(2, type_switch->match(obj2)); 8092 CHECK_EQ(3, type_switch->match(obj3)); 8093 CHECK_EQ(3, type_switch->match(obj3)); 8094 CHECK_EQ(2, type_switch->match(obj2)); 8095 CHECK_EQ(1, type_switch->match(obj1)); 8096 CHECK_EQ(0, type_switch->match(obj0)); 8097 } 8098 } 8099 8100 8101 // For use within the TestSecurityHandler() test. 8102 static bool g_security_callback_result = false; 8103 static bool NamedSecurityTestCallback(Local<v8::Object> global, 8104 Local<Value> name, 8105 v8::AccessType type, 8106 Local<Value> data) { 8107 // Always allow read access. 8108 if (type == v8::ACCESS_GET) 8109 return true; 8110 8111 // Sometimes allow other access. 8112 return g_security_callback_result; 8113 } 8114 8115 8116 static bool IndexedSecurityTestCallback(Local<v8::Object> global, 8117 uint32_t key, 8118 v8::AccessType type, 8119 Local<Value> data) { 8120 // Always allow read access. 8121 if (type == v8::ACCESS_GET) 8122 return true; 8123 8124 // Sometimes allow other access. 8125 return g_security_callback_result; 8126 } 8127 8128 8129 static int trouble_nesting = 0; 8130 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 8131 ApiTestFuzzer::Fuzz(); 8132 trouble_nesting++; 8133 8134 // Call a JS function that throws an uncaught exception. 8135 Local<v8::Object> arg_this = 8136 args.GetIsolate()->GetCurrentContext()->Global(); 8137 Local<Value> trouble_callee = (trouble_nesting == 3) ? 8138 arg_this->Get(v8_str("trouble_callee")) : 8139 arg_this->Get(v8_str("trouble_caller")); 8140 CHECK(trouble_callee->IsFunction()); 8141 args.GetReturnValue().Set( 8142 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL)); 8143 } 8144 8145 8146 static int report_count = 0; 8147 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>, 8148 v8::Handle<Value>) { 8149 report_count++; 8150 } 8151 8152 8153 // Counts uncaught exceptions, but other tests running in parallel 8154 // also have uncaught exceptions. 8155 TEST(ApiUncaughtException) { 8156 report_count = 0; 8157 LocalContext env; 8158 v8::HandleScope scope(env->GetIsolate()); 8159 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener); 8160 8161 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 8162 v8::Local<v8::Object> global = env->Global(); 8163 global->Set(v8_str("trouble"), fun->GetFunction()); 8164 8165 Script::Compile(v8_str("function trouble_callee() {" 8166 " var x = null;" 8167 " return x.foo;" 8168 "};" 8169 "function trouble_caller() {" 8170 " trouble();" 8171 "};"))->Run(); 8172 Local<Value> trouble = global->Get(v8_str("trouble")); 8173 CHECK(trouble->IsFunction()); 8174 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee")); 8175 CHECK(trouble_callee->IsFunction()); 8176 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller")); 8177 CHECK(trouble_caller->IsFunction()); 8178 Function::Cast(*trouble_caller)->Call(global, 0, NULL); 8179 CHECK_EQ(1, report_count); 8180 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener); 8181 } 8182 8183 static const char* script_resource_name = "ExceptionInNativeScript.js"; 8184 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, 8185 v8::Handle<Value>) { 8186 v8::Handle<v8::Value> name_val = message->GetScriptResourceName(); 8187 CHECK(!name_val.IsEmpty() && name_val->IsString()); 8188 v8::String::Utf8Value name(message->GetScriptResourceName()); 8189 CHECK_EQ(script_resource_name, *name); 8190 CHECK_EQ(3, message->GetLineNumber()); 8191 v8::String::Utf8Value source_line(message->GetSourceLine()); 8192 CHECK_EQ(" new o.foo();", *source_line); 8193 } 8194 8195 8196 TEST(ExceptionInNativeScript) { 8197 LocalContext env; 8198 v8::HandleScope scope(env->GetIsolate()); 8199 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener); 8200 8201 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 8202 v8::Local<v8::Object> global = env->Global(); 8203 global->Set(v8_str("trouble"), fun->GetFunction()); 8204 8205 Script::Compile( 8206 v8_str( 8207 "function trouble() {\n" 8208 " var o = {};\n" 8209 " new o.foo();\n" 8210 "};"), 8211 v8::String::NewFromUtf8(env->GetIsolate(), script_resource_name))->Run(); 8212 Local<Value> trouble = global->Get(v8_str("trouble")); 8213 CHECK(trouble->IsFunction()); 8214 Function::Cast(*trouble)->Call(global, 0, NULL); 8215 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener); 8216 } 8217 8218 8219 TEST(CompilationErrorUsingTryCatchHandler) { 8220 LocalContext env; 8221 v8::HandleScope scope(env->GetIsolate()); 8222 v8::TryCatch try_catch; 8223 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile.")); 8224 CHECK_NE(NULL, *try_catch.Exception()); 8225 CHECK(try_catch.HasCaught()); 8226 } 8227 8228 8229 TEST(TryCatchFinallyUsingTryCatchHandler) { 8230 LocalContext env; 8231 v8::HandleScope scope(env->GetIsolate()); 8232 v8::TryCatch try_catch; 8233 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run(); 8234 CHECK(!try_catch.HasCaught()); 8235 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run(); 8236 CHECK(try_catch.HasCaught()); 8237 try_catch.Reset(); 8238 Script::Compile(v8_str("(function() {" 8239 "try { throw ''; } finally { return; }" 8240 "})()"))->Run(); 8241 CHECK(!try_catch.HasCaught()); 8242 Script::Compile(v8_str("(function()" 8243 " { try { throw ''; } finally { throw 0; }" 8244 "})()"))->Run(); 8245 CHECK(try_catch.HasCaught()); 8246 } 8247 8248 8249 // SecurityHandler can't be run twice 8250 TEST(SecurityHandler) { 8251 v8::HandleScope scope0(CcTest::isolate()); 8252 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 8253 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, 8254 IndexedSecurityTestCallback); 8255 // Create an environment 8256 v8::Handle<Context> context0 = 8257 Context::New(CcTest::isolate(), NULL, global_template); 8258 context0->Enter(); 8259 8260 v8::Handle<v8::Object> global0 = context0->Global(); 8261 v8::Handle<Script> script0 = v8_compile("foo = 111"); 8262 script0->Run(); 8263 global0->Set(v8_str("0"), v8_num(999)); 8264 v8::Handle<Value> foo0 = global0->Get(v8_str("foo")); 8265 CHECK_EQ(111, foo0->Int32Value()); 8266 v8::Handle<Value> z0 = global0->Get(v8_str("0")); 8267 CHECK_EQ(999, z0->Int32Value()); 8268 8269 // Create another environment, should fail security checks. 8270 v8::HandleScope scope1(CcTest::isolate()); 8271 8272 v8::Handle<Context> context1 = 8273 Context::New(CcTest::isolate(), NULL, global_template); 8274 context1->Enter(); 8275 8276 v8::Handle<v8::Object> global1 = context1->Global(); 8277 global1->Set(v8_str("othercontext"), global0); 8278 // This set will fail the security check. 8279 v8::Handle<Script> script1 = 8280 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 8281 script1->Run(); 8282 // This read will pass the security check. 8283 v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); 8284 CHECK_EQ(111, foo1->Int32Value()); 8285 // This read will pass the security check. 8286 v8::Handle<Value> z1 = global0->Get(v8_str("0")); 8287 CHECK_EQ(999, z1->Int32Value()); 8288 8289 // Create another environment, should pass security checks. 8290 { g_security_callback_result = true; // allow security handler to pass. 8291 v8::HandleScope scope2(CcTest::isolate()); 8292 LocalContext context2; 8293 v8::Handle<v8::Object> global2 = context2->Global(); 8294 global2->Set(v8_str("othercontext"), global0); 8295 v8::Handle<Script> script2 = 8296 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 8297 script2->Run(); 8298 v8::Handle<Value> foo2 = global0->Get(v8_str("foo")); 8299 CHECK_EQ(333, foo2->Int32Value()); 8300 v8::Handle<Value> z2 = global0->Get(v8_str("0")); 8301 CHECK_EQ(888, z2->Int32Value()); 8302 } 8303 8304 context1->Exit(); 8305 context0->Exit(); 8306 } 8307 8308 8309 THREADED_TEST(SecurityChecks) { 8310 LocalContext env1; 8311 v8::HandleScope handle_scope(env1->GetIsolate()); 8312 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8313 8314 Local<Value> foo = v8_str("foo"); 8315 Local<Value> bar = v8_str("bar"); 8316 8317 // Set to the same domain. 8318 env1->SetSecurityToken(foo); 8319 8320 // Create a function in env1. 8321 Script::Compile(v8_str("spy=function(){return spy;}"))->Run(); 8322 Local<Value> spy = env1->Global()->Get(v8_str("spy")); 8323 CHECK(spy->IsFunction()); 8324 8325 // Create another function accessing global objects. 8326 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run(); 8327 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2")); 8328 CHECK(spy2->IsFunction()); 8329 8330 // Switch to env2 in the same domain and invoke spy on env2. 8331 { 8332 env2->SetSecurityToken(foo); 8333 // Enter env2 8334 Context::Scope scope_env2(env2); 8335 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL); 8336 CHECK(result->IsFunction()); 8337 } 8338 8339 { 8340 env2->SetSecurityToken(bar); 8341 Context::Scope scope_env2(env2); 8342 8343 // Call cross_domain_call, it should throw an exception 8344 v8::TryCatch try_catch; 8345 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); 8346 CHECK(try_catch.HasCaught()); 8347 } 8348 } 8349 8350 8351 // Regression test case for issue 1183439. 8352 THREADED_TEST(SecurityChecksForPrototypeChain) { 8353 LocalContext current; 8354 v8::HandleScope scope(current->GetIsolate()); 8355 v8::Handle<Context> other = Context::New(current->GetIsolate()); 8356 8357 // Change context to be able to get to the Object function in the 8358 // other context without hitting the security checks. 8359 v8::Local<Value> other_object; 8360 { Context::Scope scope(other); 8361 other_object = other->Global()->Get(v8_str("Object")); 8362 other->Global()->Set(v8_num(42), v8_num(87)); 8363 } 8364 8365 current->Global()->Set(v8_str("other"), other->Global()); 8366 CHECK(v8_compile("other")->Run()->Equals(other->Global())); 8367 8368 // Make sure the security check fails here and we get an undefined 8369 // result instead of getting the Object function. Repeat in a loop 8370 // to make sure to exercise the IC code. 8371 v8::Local<Script> access_other0 = v8_compile("other.Object"); 8372 v8::Local<Script> access_other1 = v8_compile("other[42]"); 8373 for (int i = 0; i < 5; i++) { 8374 CHECK(!access_other0->Run()->Equals(other_object)); 8375 CHECK(access_other0->Run()->IsUndefined()); 8376 CHECK(!access_other1->Run()->Equals(v8_num(87))); 8377 CHECK(access_other1->Run()->IsUndefined()); 8378 } 8379 8380 // Create an object that has 'other' in its prototype chain and make 8381 // sure we cannot access the Object function indirectly through 8382 // that. Repeat in a loop to make sure to exercise the IC code. 8383 v8_compile("function F() { };" 8384 "F.prototype = other;" 8385 "var f = new F();")->Run(); 8386 v8::Local<Script> access_f0 = v8_compile("f.Object"); 8387 v8::Local<Script> access_f1 = v8_compile("f[42]"); 8388 for (int j = 0; j < 5; j++) { 8389 CHECK(!access_f0->Run()->Equals(other_object)); 8390 CHECK(access_f0->Run()->IsUndefined()); 8391 CHECK(!access_f1->Run()->Equals(v8_num(87))); 8392 CHECK(access_f1->Run()->IsUndefined()); 8393 } 8394 8395 // Now it gets hairy: Set the prototype for the other global object 8396 // to be the current global object. The prototype chain for 'f' now 8397 // goes through 'other' but ends up in the current global object. 8398 { Context::Scope scope(other); 8399 other->Global()->Set(v8_str("__proto__"), current->Global()); 8400 } 8401 // Set a named and an index property on the current global 8402 // object. To force the lookup to go through the other global object, 8403 // the properties must not exist in the other global object. 8404 current->Global()->Set(v8_str("foo"), v8_num(100)); 8405 current->Global()->Set(v8_num(99), v8_num(101)); 8406 // Try to read the properties from f and make sure that the access 8407 // gets stopped by the security checks on the other global object. 8408 Local<Script> access_f2 = v8_compile("f.foo"); 8409 Local<Script> access_f3 = v8_compile("f[99]"); 8410 for (int k = 0; k < 5; k++) { 8411 CHECK(!access_f2->Run()->Equals(v8_num(100))); 8412 CHECK(access_f2->Run()->IsUndefined()); 8413 CHECK(!access_f3->Run()->Equals(v8_num(101))); 8414 CHECK(access_f3->Run()->IsUndefined()); 8415 } 8416 } 8417 8418 8419 THREADED_TEST(CrossDomainDelete) { 8420 LocalContext env1; 8421 v8::HandleScope handle_scope(env1->GetIsolate()); 8422 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8423 8424 Local<Value> foo = v8_str("foo"); 8425 Local<Value> bar = v8_str("bar"); 8426 8427 // Set to the same domain. 8428 env1->SetSecurityToken(foo); 8429 env2->SetSecurityToken(foo); 8430 8431 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8432 env2->Global()->Set(v8_str("env1"), env1->Global()); 8433 8434 // Change env2 to a different domain and delete env1.prop. 8435 env2->SetSecurityToken(bar); 8436 { 8437 Context::Scope scope_env2(env2); 8438 Local<Value> result = 8439 Script::Compile(v8_str("delete env1.prop"))->Run(); 8440 CHECK(result->IsFalse()); 8441 } 8442 8443 // Check that env1.prop still exists. 8444 Local<Value> v = env1->Global()->Get(v8_str("prop")); 8445 CHECK(v->IsNumber()); 8446 CHECK_EQ(3, v->Int32Value()); 8447 } 8448 8449 8450 THREADED_TEST(CrossDomainIsPropertyEnumerable) { 8451 LocalContext env1; 8452 v8::HandleScope handle_scope(env1->GetIsolate()); 8453 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8454 8455 Local<Value> foo = v8_str("foo"); 8456 Local<Value> bar = v8_str("bar"); 8457 8458 // Set to the same domain. 8459 env1->SetSecurityToken(foo); 8460 env2->SetSecurityToken(foo); 8461 8462 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8463 env2->Global()->Set(v8_str("env1"), env1->Global()); 8464 8465 // env1.prop is enumerable in env2. 8466 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 8467 { 8468 Context::Scope scope_env2(env2); 8469 Local<Value> result = Script::Compile(test)->Run(); 8470 CHECK(result->IsTrue()); 8471 } 8472 8473 // Change env2 to a different domain and test again. 8474 env2->SetSecurityToken(bar); 8475 { 8476 Context::Scope scope_env2(env2); 8477 Local<Value> result = Script::Compile(test)->Run(); 8478 CHECK(result->IsFalse()); 8479 } 8480 } 8481 8482 8483 THREADED_TEST(CrossDomainForIn) { 8484 LocalContext env1; 8485 v8::HandleScope handle_scope(env1->GetIsolate()); 8486 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8487 8488 Local<Value> foo = v8_str("foo"); 8489 Local<Value> bar = v8_str("bar"); 8490 8491 // Set to the same domain. 8492 env1->SetSecurityToken(foo); 8493 env2->SetSecurityToken(foo); 8494 8495 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8496 env2->Global()->Set(v8_str("env1"), env1->Global()); 8497 8498 // Change env2 to a different domain and set env1's global object 8499 // as the __proto__ of an object in env2 and enumerate properties 8500 // in for-in. It shouldn't enumerate properties on env1's global 8501 // object. 8502 env2->SetSecurityToken(bar); 8503 { 8504 Context::Scope scope_env2(env2); 8505 Local<Value> result = 8506 CompileRun("(function(){var obj = {'__proto__':env1};" 8507 "for (var p in obj)" 8508 " if (p == 'prop') return false;" 8509 "return true;})()"); 8510 CHECK(result->IsTrue()); 8511 } 8512 } 8513 8514 8515 TEST(ContextDetachGlobal) { 8516 LocalContext env1; 8517 v8::HandleScope handle_scope(env1->GetIsolate()); 8518 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8519 8520 Local<v8::Object> global1 = env1->Global(); 8521 8522 Local<Value> foo = v8_str("foo"); 8523 8524 // Set to the same domain. 8525 env1->SetSecurityToken(foo); 8526 env2->SetSecurityToken(foo); 8527 8528 // Enter env2 8529 env2->Enter(); 8530 8531 // Create a function in env2 and add a reference to it in env1. 8532 Local<v8::Object> global2 = env2->Global(); 8533 global2->Set(v8_str("prop"), v8::Integer::New(1)); 8534 CompileRun("function getProp() {return prop;}"); 8535 8536 env1->Global()->Set(v8_str("getProp"), 8537 global2->Get(v8_str("getProp"))); 8538 8539 // Detach env2's global, and reuse the global object of env2 8540 env2->Exit(); 8541 env2->DetachGlobal(); 8542 8543 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8544 0, 8545 v8::Handle<v8::ObjectTemplate>(), 8546 global2); 8547 env3->SetSecurityToken(v8_str("bar")); 8548 env3->Enter(); 8549 8550 Local<v8::Object> global3 = env3->Global(); 8551 CHECK_EQ(global2, global3); 8552 CHECK(global3->Get(v8_str("prop"))->IsUndefined()); 8553 CHECK(global3->Get(v8_str("getProp"))->IsUndefined()); 8554 global3->Set(v8_str("prop"), v8::Integer::New(-1)); 8555 global3->Set(v8_str("prop2"), v8::Integer::New(2)); 8556 env3->Exit(); 8557 8558 // Call getProp in env1, and it should return the value 1 8559 { 8560 Local<Value> get_prop = global1->Get(v8_str("getProp")); 8561 CHECK(get_prop->IsFunction()); 8562 v8::TryCatch try_catch; 8563 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); 8564 CHECK(!try_catch.HasCaught()); 8565 CHECK_EQ(1, r->Int32Value()); 8566 } 8567 8568 // Check that env3 is not accessible from env1 8569 { 8570 Local<Value> r = global3->Get(v8_str("prop2")); 8571 CHECK(r->IsUndefined()); 8572 } 8573 } 8574 8575 8576 TEST(DetachGlobal) { 8577 LocalContext env1; 8578 v8::HandleScope scope(env1->GetIsolate()); 8579 8580 // Create second environment. 8581 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8582 8583 Local<Value> foo = v8_str("foo"); 8584 8585 // Set same security token for env1 and env2. 8586 env1->SetSecurityToken(foo); 8587 env2->SetSecurityToken(foo); 8588 8589 // Create a property on the global object in env2. 8590 { 8591 v8::Context::Scope scope(env2); 8592 env2->Global()->Set(v8_str("p"), v8::Integer::New(42)); 8593 } 8594 8595 // Create a reference to env2 global from env1 global. 8596 env1->Global()->Set(v8_str("other"), env2->Global()); 8597 8598 // Check that we have access to other.p in env2 from env1. 8599 Local<Value> result = CompileRun("other.p"); 8600 CHECK(result->IsInt32()); 8601 CHECK_EQ(42, result->Int32Value()); 8602 8603 // Hold on to global from env2 and detach global from env2. 8604 Local<v8::Object> global2 = env2->Global(); 8605 env2->DetachGlobal(); 8606 8607 // Check that the global has been detached. No other.p property can 8608 // be found. 8609 result = CompileRun("other.p"); 8610 CHECK(result->IsUndefined()); 8611 8612 // Reuse global2 for env3. 8613 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8614 0, 8615 v8::Handle<v8::ObjectTemplate>(), 8616 global2); 8617 CHECK_EQ(global2, env3->Global()); 8618 8619 // Start by using the same security token for env3 as for env1 and env2. 8620 env3->SetSecurityToken(foo); 8621 8622 // Create a property on the global object in env3. 8623 { 8624 v8::Context::Scope scope(env3); 8625 env3->Global()->Set(v8_str("p"), v8::Integer::New(24)); 8626 } 8627 8628 // Check that other.p is now the property in env3 and that we have access. 8629 result = CompileRun("other.p"); 8630 CHECK(result->IsInt32()); 8631 CHECK_EQ(24, result->Int32Value()); 8632 8633 // Change security token for env3 to something different from env1 and env2. 8634 env3->SetSecurityToken(v8_str("bar")); 8635 8636 // Check that we do not have access to other.p in env1. |other| is now 8637 // the global object for env3 which has a different security token, 8638 // so access should be blocked. 8639 result = CompileRun("other.p"); 8640 CHECK(result->IsUndefined()); 8641 } 8642 8643 8644 TEST(DetachedAccesses) { 8645 LocalContext env1; 8646 v8::HandleScope scope(env1->GetIsolate()); 8647 8648 // Create second environment. 8649 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8650 8651 Local<Value> foo = v8_str("foo"); 8652 8653 // Set same security token for env1 and env2. 8654 env1->SetSecurityToken(foo); 8655 env2->SetSecurityToken(foo); 8656 8657 { 8658 v8::Context::Scope scope(env2); 8659 CompileRun( 8660 "var x = 'x';" 8661 "function get_x() { return this.x; }" 8662 "function get_x_w() { return get_x(); }" 8663 ""); 8664 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x")); 8665 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w")); 8666 } 8667 8668 Local<Object> env2_global = env2->Global(); 8669 env2_global->TurnOnAccessCheck(); 8670 env2->DetachGlobal(); 8671 8672 Local<Value> result; 8673 result = CompileRun("get_x()"); 8674 CHECK(result->IsUndefined()); 8675 result = CompileRun("get_x_w()"); 8676 CHECK(result->IsUndefined()); 8677 8678 // Reattach env2's proxy 8679 env2 = Context::New(env1->GetIsolate(), 8680 0, 8681 v8::Handle<v8::ObjectTemplate>(), 8682 env2_global); 8683 env2->SetSecurityToken(foo); 8684 { 8685 v8::Context::Scope scope(env2); 8686 CompileRun("var x = 'x2';"); 8687 } 8688 8689 result = CompileRun("get_x()"); 8690 CHECK(result->IsUndefined()); 8691 result = CompileRun("get_x_w()"); 8692 CHECK_EQ(v8_str("x2"), result); 8693 } 8694 8695 8696 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; 8697 static bool NamedAccessBlocker(Local<v8::Object> global, 8698 Local<Value> name, 8699 v8::AccessType type, 8700 Local<Value> data) { 8701 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 8702 allowed_access_type[type]; 8703 } 8704 8705 8706 static bool IndexedAccessBlocker(Local<v8::Object> global, 8707 uint32_t key, 8708 v8::AccessType type, 8709 Local<Value> data) { 8710 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || 8711 allowed_access_type[type]; 8712 } 8713 8714 8715 static int g_echo_value_1 = -1; 8716 static int g_echo_value_2 = -1; 8717 8718 8719 static void EchoGetter( 8720 Local<String> name, 8721 const v8::PropertyCallbackInfo<v8::Value>& info) { 8722 info.GetReturnValue().Set(v8_num(g_echo_value_1)); 8723 } 8724 8725 8726 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 8727 info.GetReturnValue().Set(v8_num(g_echo_value_2)); 8728 } 8729 8730 8731 static void EchoSetter(Local<String> name, 8732 Local<Value> value, 8733 const v8::PropertyCallbackInfo<void>&) { 8734 if (value->IsNumber()) 8735 g_echo_value_1 = value->Int32Value(); 8736 } 8737 8738 8739 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 8740 v8::Handle<v8::Value> value = info[0]; 8741 if (value->IsNumber()) 8742 g_echo_value_2 = value->Int32Value(); 8743 } 8744 8745 8746 static void UnreachableGetter( 8747 Local<String> name, 8748 const v8::PropertyCallbackInfo<v8::Value>& info) { 8749 CHECK(false); // This function should not be called.. 8750 } 8751 8752 8753 static void UnreachableSetter(Local<String>, 8754 Local<Value>, 8755 const v8::PropertyCallbackInfo<void>&) { 8756 CHECK(false); // This function should nto be called. 8757 } 8758 8759 8760 static void UnreachableFunction( 8761 const v8::FunctionCallbackInfo<v8::Value>& info) { 8762 CHECK(false); // This function should not be called.. 8763 } 8764 8765 8766 TEST(AccessControl) { 8767 v8::Isolate* isolate = CcTest::isolate(); 8768 v8::HandleScope handle_scope(isolate); 8769 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 8770 8771 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 8772 IndexedAccessBlocker); 8773 8774 // Add an accessor accessible by cross-domain JS code. 8775 global_template->SetAccessor( 8776 v8_str("accessible_prop"), 8777 EchoGetter, EchoSetter, 8778 v8::Handle<Value>(), 8779 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 8780 8781 8782 global_template->SetAccessorProperty( 8783 v8_str("accessible_js_prop"), 8784 v8::FunctionTemplate::New(EchoGetter), 8785 v8::FunctionTemplate::New(EchoSetter), 8786 v8::None, 8787 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 8788 8789 // Add an accessor that is not accessible by cross-domain JS code. 8790 global_template->SetAccessor(v8_str("blocked_prop"), 8791 UnreachableGetter, UnreachableSetter, 8792 v8::Handle<Value>(), 8793 v8::DEFAULT); 8794 8795 global_template->SetAccessorProperty( 8796 v8_str("blocked_js_prop"), 8797 v8::FunctionTemplate::New(UnreachableFunction), 8798 v8::FunctionTemplate::New(UnreachableFunction), 8799 v8::None, 8800 v8::DEFAULT); 8801 8802 // Create an environment 8803 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 8804 context0->Enter(); 8805 8806 v8::Handle<v8::Object> global0 = context0->Global(); 8807 8808 // Define a property with JS getter and setter. 8809 CompileRun( 8810 "function getter() { return 'getter'; };\n" 8811 "function setter() { return 'setter'; }\n" 8812 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 8813 8814 Local<Value> getter = global0->Get(v8_str("getter")); 8815 Local<Value> setter = global0->Get(v8_str("setter")); 8816 8817 // And define normal element. 8818 global0->Set(239, v8_str("239")); 8819 8820 // Define an element with JS getter and setter. 8821 CompileRun( 8822 "function el_getter() { return 'el_getter'; };\n" 8823 "function el_setter() { return 'el_setter'; };\n" 8824 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 8825 8826 Local<Value> el_getter = global0->Get(v8_str("el_getter")); 8827 Local<Value> el_setter = global0->Get(v8_str("el_setter")); 8828 8829 v8::HandleScope scope1(isolate); 8830 8831 v8::Local<Context> context1 = Context::New(isolate); 8832 context1->Enter(); 8833 8834 v8::Handle<v8::Object> global1 = context1->Global(); 8835 global1->Set(v8_str("other"), global0); 8836 8837 // Access blocked property. 8838 CompileRun("other.blocked_prop = 1"); 8839 8840 ExpectUndefined("other.blocked_prop"); 8841 ExpectUndefined( 8842 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 8843 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')"); 8844 8845 // Enable ACCESS_HAS 8846 allowed_access_type[v8::ACCESS_HAS] = true; 8847 ExpectUndefined("other.blocked_prop"); 8848 // ... and now we can get the descriptor... 8849 ExpectUndefined( 8850 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value"); 8851 // ... and enumerate the property. 8852 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')"); 8853 allowed_access_type[v8::ACCESS_HAS] = false; 8854 8855 // Access blocked element. 8856 CompileRun("other[239] = 1"); 8857 8858 ExpectUndefined("other[239]"); 8859 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')"); 8860 ExpectFalse("propertyIsEnumerable.call(other, '239')"); 8861 8862 // Enable ACCESS_HAS 8863 allowed_access_type[v8::ACCESS_HAS] = true; 8864 ExpectUndefined("other[239]"); 8865 // ... and now we can get the descriptor... 8866 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value"); 8867 // ... and enumerate the property. 8868 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 8869 allowed_access_type[v8::ACCESS_HAS] = false; 8870 8871 // Access a property with JS accessor. 8872 CompileRun("other.js_accessor_p = 2"); 8873 8874 ExpectUndefined("other.js_accessor_p"); 8875 ExpectUndefined( 8876 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')"); 8877 8878 // Enable ACCESS_HAS. 8879 allowed_access_type[v8::ACCESS_HAS] = true; 8880 ExpectUndefined("other.js_accessor_p"); 8881 ExpectUndefined( 8882 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 8883 ExpectUndefined( 8884 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 8885 ExpectUndefined( 8886 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8887 allowed_access_type[v8::ACCESS_HAS] = false; 8888 8889 // Enable both ACCESS_HAS and ACCESS_GET. 8890 allowed_access_type[v8::ACCESS_HAS] = true; 8891 allowed_access_type[v8::ACCESS_GET] = true; 8892 8893 ExpectString("other.js_accessor_p", "getter"); 8894 ExpectObject( 8895 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 8896 ExpectUndefined( 8897 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 8898 ExpectUndefined( 8899 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8900 8901 allowed_access_type[v8::ACCESS_GET] = false; 8902 allowed_access_type[v8::ACCESS_HAS] = false; 8903 8904 // Enable both ACCESS_HAS and ACCESS_SET. 8905 allowed_access_type[v8::ACCESS_HAS] = true; 8906 allowed_access_type[v8::ACCESS_SET] = true; 8907 8908 ExpectUndefined("other.js_accessor_p"); 8909 ExpectUndefined( 8910 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 8911 ExpectObject( 8912 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 8913 ExpectUndefined( 8914 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8915 8916 allowed_access_type[v8::ACCESS_SET] = false; 8917 allowed_access_type[v8::ACCESS_HAS] = false; 8918 8919 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 8920 allowed_access_type[v8::ACCESS_HAS] = true; 8921 allowed_access_type[v8::ACCESS_GET] = true; 8922 allowed_access_type[v8::ACCESS_SET] = true; 8923 8924 ExpectString("other.js_accessor_p", "getter"); 8925 ExpectObject( 8926 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 8927 ExpectObject( 8928 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 8929 ExpectUndefined( 8930 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8931 8932 allowed_access_type[v8::ACCESS_SET] = false; 8933 allowed_access_type[v8::ACCESS_GET] = false; 8934 allowed_access_type[v8::ACCESS_HAS] = false; 8935 8936 // Access an element with JS accessor. 8937 CompileRun("other[42] = 2"); 8938 8939 ExpectUndefined("other[42]"); 8940 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')"); 8941 8942 // Enable ACCESS_HAS. 8943 allowed_access_type[v8::ACCESS_HAS] = true; 8944 ExpectUndefined("other[42]"); 8945 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 8946 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 8947 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8948 allowed_access_type[v8::ACCESS_HAS] = false; 8949 8950 // Enable both ACCESS_HAS and ACCESS_GET. 8951 allowed_access_type[v8::ACCESS_HAS] = true; 8952 allowed_access_type[v8::ACCESS_GET] = true; 8953 8954 ExpectString("other[42]", "el_getter"); 8955 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 8956 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 8957 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8958 8959 allowed_access_type[v8::ACCESS_GET] = false; 8960 allowed_access_type[v8::ACCESS_HAS] = false; 8961 8962 // Enable both ACCESS_HAS and ACCESS_SET. 8963 allowed_access_type[v8::ACCESS_HAS] = true; 8964 allowed_access_type[v8::ACCESS_SET] = true; 8965 8966 ExpectUndefined("other[42]"); 8967 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 8968 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 8969 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8970 8971 allowed_access_type[v8::ACCESS_SET] = false; 8972 allowed_access_type[v8::ACCESS_HAS] = false; 8973 8974 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 8975 allowed_access_type[v8::ACCESS_HAS] = true; 8976 allowed_access_type[v8::ACCESS_GET] = true; 8977 allowed_access_type[v8::ACCESS_SET] = true; 8978 8979 ExpectString("other[42]", "el_getter"); 8980 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 8981 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 8982 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8983 8984 allowed_access_type[v8::ACCESS_SET] = false; 8985 allowed_access_type[v8::ACCESS_GET] = false; 8986 allowed_access_type[v8::ACCESS_HAS] = false; 8987 8988 v8::Handle<Value> value; 8989 8990 // Access accessible property 8991 value = CompileRun("other.accessible_prop = 3"); 8992 CHECK(value->IsNumber()); 8993 CHECK_EQ(3, value->Int32Value()); 8994 CHECK_EQ(3, g_echo_value_1); 8995 8996 // Access accessible js property 8997 value = CompileRun("other.accessible_js_prop = 3"); 8998 CHECK(value->IsNumber()); 8999 CHECK_EQ(3, value->Int32Value()); 9000 CHECK_EQ(3, g_echo_value_2); 9001 9002 value = CompileRun("other.accessible_prop"); 9003 CHECK(value->IsNumber()); 9004 CHECK_EQ(3, value->Int32Value()); 9005 9006 value = CompileRun("other.accessible_js_prop"); 9007 CHECK(value->IsNumber()); 9008 CHECK_EQ(3, value->Int32Value()); 9009 9010 value = CompileRun( 9011 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 9012 CHECK(value->IsNumber()); 9013 CHECK_EQ(3, value->Int32Value()); 9014 9015 value = CompileRun( 9016 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()"); 9017 CHECK(value->IsNumber()); 9018 CHECK_EQ(3, value->Int32Value()); 9019 9020 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 9021 CHECK(value->IsTrue()); 9022 9023 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')"); 9024 CHECK(value->IsTrue()); 9025 9026 // Enumeration doesn't enumerate accessors from inaccessible objects in 9027 // the prototype chain even if the accessors are in themselves accessible. 9028 value = 9029 CompileRun("(function(){var obj = {'__proto__':other};" 9030 "for (var p in obj)" 9031 " if (p == 'accessible_prop' ||" 9032 " p == 'accessible_js_prop' ||" 9033 " p == 'blocked_js_prop' ||" 9034 " p == 'blocked_js_prop') {" 9035 " return false;" 9036 " }" 9037 "return true;})()"); 9038 CHECK(value->IsTrue()); 9039 9040 context1->Exit(); 9041 context0->Exit(); 9042 } 9043 9044 9045 TEST(AccessControlES5) { 9046 v8::Isolate* isolate = CcTest::isolate(); 9047 v8::HandleScope handle_scope(isolate); 9048 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 9049 9050 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 9051 IndexedAccessBlocker); 9052 9053 // Add accessible accessor. 9054 global_template->SetAccessor( 9055 v8_str("accessible_prop"), 9056 EchoGetter, EchoSetter, 9057 v8::Handle<Value>(), 9058 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 9059 9060 9061 // Add an accessor that is not accessible by cross-domain JS code. 9062 global_template->SetAccessor(v8_str("blocked_prop"), 9063 UnreachableGetter, UnreachableSetter, 9064 v8::Handle<Value>(), 9065 v8::DEFAULT); 9066 9067 // Create an environment 9068 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9069 context0->Enter(); 9070 9071 v8::Handle<v8::Object> global0 = context0->Global(); 9072 9073 v8::Local<Context> context1 = Context::New(isolate); 9074 context1->Enter(); 9075 v8::Handle<v8::Object> global1 = context1->Global(); 9076 global1->Set(v8_str("other"), global0); 9077 9078 // Regression test for issue 1154. 9079 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1"); 9080 9081 ExpectUndefined("other.blocked_prop"); 9082 9083 // Regression test for issue 1027. 9084 CompileRun("Object.defineProperty(\n" 9085 " other, 'blocked_prop', {configurable: false})"); 9086 ExpectUndefined("other.blocked_prop"); 9087 ExpectUndefined( 9088 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 9089 9090 // Regression test for issue 1171. 9091 ExpectTrue("Object.isExtensible(other)"); 9092 CompileRun("Object.preventExtensions(other)"); 9093 ExpectTrue("Object.isExtensible(other)"); 9094 9095 // Object.seal and Object.freeze. 9096 CompileRun("Object.freeze(other)"); 9097 ExpectTrue("Object.isExtensible(other)"); 9098 9099 CompileRun("Object.seal(other)"); 9100 ExpectTrue("Object.isExtensible(other)"); 9101 9102 // Regression test for issue 1250. 9103 // Make sure that we can set the accessible accessors value using normal 9104 // assignment. 9105 CompileRun("other.accessible_prop = 42"); 9106 CHECK_EQ(42, g_echo_value_1); 9107 9108 v8::Handle<Value> value; 9109 // We follow Safari in ignoring assignments to host object accessors. 9110 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); 9111 value = CompileRun("other.accessible_prop == 42"); 9112 CHECK(value->IsTrue()); 9113 } 9114 9115 9116 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global, 9117 Local<Value> name, 9118 v8::AccessType type, 9119 Local<Value> data) { 9120 return false; 9121 } 9122 9123 9124 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global, 9125 uint32_t key, 9126 v8::AccessType type, 9127 Local<Value> data) { 9128 return false; 9129 } 9130 9131 9132 THREADED_TEST(AccessControlGetOwnPropertyNames) { 9133 v8::Isolate* isolate = CcTest::isolate(); 9134 v8::HandleScope handle_scope(isolate); 9135 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 9136 9137 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 9138 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker, 9139 GetOwnPropertyNamesIndexedBlocker); 9140 9141 // Create an environment 9142 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 9143 context0->Enter(); 9144 9145 v8::Handle<v8::Object> global0 = context0->Global(); 9146 9147 v8::HandleScope scope1(CcTest::isolate()); 9148 9149 v8::Local<Context> context1 = Context::New(isolate); 9150 context1->Enter(); 9151 9152 v8::Handle<v8::Object> global1 = context1->Global(); 9153 global1->Set(v8_str("other"), global0); 9154 global1->Set(v8_str("object"), obj_template->NewInstance()); 9155 9156 v8::Handle<Value> value; 9157 9158 // Attempt to get the property names of the other global object and 9159 // of an object that requires access checks. Accessing the other 9160 // global object should be blocked by access checks on the global 9161 // proxy object. Accessing the object that requires access checks 9162 // is blocked by the access checks on the object itself. 9163 value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); 9164 CHECK(value->IsTrue()); 9165 9166 value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); 9167 CHECK(value->IsTrue()); 9168 9169 context1->Exit(); 9170 context0->Exit(); 9171 } 9172 9173 9174 static void IndexedPropertyEnumerator( 9175 const v8::PropertyCallbackInfo<v8::Array>& info) { 9176 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9177 result->Set(0, v8::Integer::New(7)); 9178 result->Set(1, v8::Object::New()); 9179 info.GetReturnValue().Set(result); 9180 } 9181 9182 9183 static void NamedPropertyEnumerator( 9184 const v8::PropertyCallbackInfo<v8::Array>& info) { 9185 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2); 9186 result->Set(0, v8_str("x")); 9187 result->Set(1, v8::Object::New()); 9188 info.GetReturnValue().Set(result); 9189 } 9190 9191 9192 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { 9193 v8::HandleScope handle_scope(CcTest::isolate()); 9194 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 9195 9196 obj_template->Set(v8_str("7"), v8::Integer::New(7)); 9197 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 9198 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, 9199 IndexedPropertyEnumerator); 9200 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL, 9201 NamedPropertyEnumerator); 9202 9203 LocalContext context; 9204 v8::Handle<v8::Object> global = context->Global(); 9205 global->Set(v8_str("object"), obj_template->NewInstance()); 9206 9207 v8::Handle<v8::Value> result = 9208 CompileRun("Object.getOwnPropertyNames(object)"); 9209 CHECK(result->IsArray()); 9210 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result); 9211 CHECK_EQ(3, result_array->Length()); 9212 CHECK(result_array->Get(0)->IsString()); 9213 CHECK(result_array->Get(1)->IsString()); 9214 CHECK(result_array->Get(2)->IsString()); 9215 CHECK_EQ(v8_str("7"), result_array->Get(0)); 9216 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1)); 9217 CHECK_EQ(v8_str("x"), result_array->Get(2)); 9218 } 9219 9220 9221 static void ConstTenGetter(Local<String> name, 9222 const v8::PropertyCallbackInfo<v8::Value>& info) { 9223 info.GetReturnValue().Set(v8_num(10)); 9224 } 9225 9226 9227 THREADED_TEST(CrossDomainAccessors) { 9228 v8::Isolate* isolate = CcTest::isolate(); 9229 v8::HandleScope handle_scope(isolate); 9230 9231 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(); 9232 9233 v8::Handle<v8::ObjectTemplate> global_template = 9234 func_template->InstanceTemplate(); 9235 9236 v8::Handle<v8::ObjectTemplate> proto_template = 9237 func_template->PrototypeTemplate(); 9238 9239 // Add an accessor to proto that's accessible by cross-domain JS code. 9240 proto_template->SetAccessor(v8_str("accessible"), 9241 ConstTenGetter, 0, 9242 v8::Handle<Value>(), 9243 v8::ALL_CAN_READ); 9244 9245 // Add an accessor that is not accessible by cross-domain JS code. 9246 global_template->SetAccessor(v8_str("unreachable"), 9247 UnreachableGetter, 0, 9248 v8::Handle<Value>(), 9249 v8::DEFAULT); 9250 9251 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 9252 context0->Enter(); 9253 9254 Local<v8::Object> global = context0->Global(); 9255 // Add a normal property that shadows 'accessible' 9256 global->Set(v8_str("accessible"), v8_num(11)); 9257 9258 // Enter a new context. 9259 v8::HandleScope scope1(CcTest::isolate()); 9260 v8::Local<Context> context1 = Context::New(isolate); 9261 context1->Enter(); 9262 9263 v8::Handle<v8::Object> global1 = context1->Global(); 9264 global1->Set(v8_str("other"), global); 9265 9266 // Should return 10, instead of 11 9267 v8::Handle<Value> value = v8_compile("other.accessible")->Run(); 9268 CHECK(value->IsNumber()); 9269 CHECK_EQ(10, value->Int32Value()); 9270 9271 value = v8_compile("other.unreachable")->Run(); 9272 CHECK(value->IsUndefined()); 9273 9274 context1->Exit(); 9275 context0->Exit(); 9276 } 9277 9278 9279 static int named_access_count = 0; 9280 static int indexed_access_count = 0; 9281 9282 static bool NamedAccessCounter(Local<v8::Object> global, 9283 Local<Value> name, 9284 v8::AccessType type, 9285 Local<Value> data) { 9286 named_access_count++; 9287 return true; 9288 } 9289 9290 9291 static bool IndexedAccessCounter(Local<v8::Object> global, 9292 uint32_t key, 9293 v8::AccessType type, 9294 Local<Value> data) { 9295 indexed_access_count++; 9296 return true; 9297 } 9298 9299 9300 // This one is too easily disturbed by other tests. 9301 TEST(AccessControlIC) { 9302 named_access_count = 0; 9303 indexed_access_count = 0; 9304 9305 v8::Isolate* isolate = CcTest::isolate(); 9306 v8::HandleScope handle_scope(isolate); 9307 9308 // Create an environment. 9309 v8::Local<Context> context0 = Context::New(isolate); 9310 context0->Enter(); 9311 9312 // Create an object that requires access-check functions to be 9313 // called for cross-domain access. 9314 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 9315 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9316 IndexedAccessCounter); 9317 Local<v8::Object> object = object_template->NewInstance(); 9318 9319 v8::HandleScope scope1(isolate); 9320 9321 // Create another environment. 9322 v8::Local<Context> context1 = Context::New(isolate); 9323 context1->Enter(); 9324 9325 // Make easy access to the object from the other environment. 9326 v8::Handle<v8::Object> global1 = context1->Global(); 9327 global1->Set(v8_str("obj"), object); 9328 9329 v8::Handle<Value> value; 9330 9331 // Check that the named access-control function is called every time. 9332 CompileRun("function testProp(obj) {" 9333 " for (var i = 0; i < 10; i++) obj.prop = 1;" 9334 " for (var j = 0; j < 10; j++) obj.prop;" 9335 " return obj.prop" 9336 "}"); 9337 value = CompileRun("testProp(obj)"); 9338 CHECK(value->IsNumber()); 9339 CHECK_EQ(1, value->Int32Value()); 9340 CHECK_EQ(21, named_access_count); 9341 9342 // Check that the named access-control function is called every time. 9343 CompileRun("var p = 'prop';" 9344 "function testKeyed(obj) {" 9345 " for (var i = 0; i < 10; i++) obj[p] = 1;" 9346 " for (var j = 0; j < 10; j++) obj[p];" 9347 " return obj[p];" 9348 "}"); 9349 // Use obj which requires access checks. No inline caching is used 9350 // in that case. 9351 value = CompileRun("testKeyed(obj)"); 9352 CHECK(value->IsNumber()); 9353 CHECK_EQ(1, value->Int32Value()); 9354 CHECK_EQ(42, named_access_count); 9355 // Force the inline caches into generic state and try again. 9356 CompileRun("testKeyed({ a: 0 })"); 9357 CompileRun("testKeyed({ b: 0 })"); 9358 value = CompileRun("testKeyed(obj)"); 9359 CHECK(value->IsNumber()); 9360 CHECK_EQ(1, value->Int32Value()); 9361 CHECK_EQ(63, named_access_count); 9362 9363 // Check that the indexed access-control function is called every time. 9364 CompileRun("function testIndexed(obj) {" 9365 " for (var i = 0; i < 10; i++) obj[0] = 1;" 9366 " for (var j = 0; j < 10; j++) obj[0];" 9367 " return obj[0]" 9368 "}"); 9369 value = CompileRun("testIndexed(obj)"); 9370 CHECK(value->IsNumber()); 9371 CHECK_EQ(1, value->Int32Value()); 9372 CHECK_EQ(21, indexed_access_count); 9373 // Force the inline caches into generic state. 9374 CompileRun("testIndexed(new Array(1))"); 9375 // Test that the indexed access check is called. 9376 value = CompileRun("testIndexed(obj)"); 9377 CHECK(value->IsNumber()); 9378 CHECK_EQ(1, value->Int32Value()); 9379 CHECK_EQ(42, indexed_access_count); 9380 9381 // Check that the named access check is called when invoking 9382 // functions on an object that requires access checks. 9383 CompileRun("obj.f = function() {}"); 9384 CompileRun("function testCallNormal(obj) {" 9385 " for (var i = 0; i < 10; i++) obj.f();" 9386 "}"); 9387 CompileRun("testCallNormal(obj)"); 9388 CHECK_EQ(74, named_access_count); 9389 9390 // Force obj into slow case. 9391 value = CompileRun("delete obj.prop"); 9392 CHECK(value->BooleanValue()); 9393 // Force inline caches into dictionary probing mode. 9394 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 9395 // Test that the named access check is called. 9396 value = CompileRun("testProp(obj);"); 9397 CHECK(value->IsNumber()); 9398 CHECK_EQ(1, value->Int32Value()); 9399 CHECK_EQ(96, named_access_count); 9400 9401 // Force the call inline cache into dictionary probing mode. 9402 CompileRun("o.f = function() {}; testCallNormal(o)"); 9403 // Test that the named access check is still called for each 9404 // invocation of the function. 9405 value = CompileRun("testCallNormal(obj)"); 9406 CHECK_EQ(106, named_access_count); 9407 9408 context1->Exit(); 9409 context0->Exit(); 9410 } 9411 9412 9413 static bool NamedAccessFlatten(Local<v8::Object> global, 9414 Local<Value> name, 9415 v8::AccessType type, 9416 Local<Value> data) { 9417 char buf[100]; 9418 int len; 9419 9420 CHECK(name->IsString()); 9421 9422 memset(buf, 0x1, sizeof(buf)); 9423 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 9424 CHECK_EQ(4, len); 9425 9426 uint16_t buf2[100]; 9427 9428 memset(buf, 0x1, sizeof(buf)); 9429 len = name.As<String>()->Write(buf2); 9430 CHECK_EQ(4, len); 9431 9432 return true; 9433 } 9434 9435 9436 static bool IndexedAccessFlatten(Local<v8::Object> global, 9437 uint32_t key, 9438 v8::AccessType type, 9439 Local<Value> data) { 9440 return true; 9441 } 9442 9443 9444 // Regression test. In access checks, operations that may cause 9445 // garbage collection are not allowed. It used to be the case that 9446 // using the Write operation on a string could cause a garbage 9447 // collection due to flattening of the string. This is no longer the 9448 // case. 9449 THREADED_TEST(AccessControlFlatten) { 9450 named_access_count = 0; 9451 indexed_access_count = 0; 9452 9453 v8::Isolate* isolate = CcTest::isolate(); 9454 v8::HandleScope handle_scope(isolate); 9455 9456 // Create an environment. 9457 v8::Local<Context> context0 = Context::New(isolate); 9458 context0->Enter(); 9459 9460 // Create an object that requires access-check functions to be 9461 // called for cross-domain access. 9462 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 9463 object_template->SetAccessCheckCallbacks(NamedAccessFlatten, 9464 IndexedAccessFlatten); 9465 Local<v8::Object> object = object_template->NewInstance(); 9466 9467 v8::HandleScope scope1(isolate); 9468 9469 // Create another environment. 9470 v8::Local<Context> context1 = Context::New(isolate); 9471 context1->Enter(); 9472 9473 // Make easy access to the object from the other environment. 9474 v8::Handle<v8::Object> global1 = context1->Global(); 9475 global1->Set(v8_str("obj"), object); 9476 9477 v8::Handle<Value> value; 9478 9479 value = v8_compile("var p = 'as' + 'df';")->Run(); 9480 value = v8_compile("obj[p];")->Run(); 9481 9482 context1->Exit(); 9483 context0->Exit(); 9484 } 9485 9486 9487 static void AccessControlNamedGetter( 9488 Local<String>, 9489 const v8::PropertyCallbackInfo<v8::Value>& info) { 9490 info.GetReturnValue().Set(42); 9491 } 9492 9493 9494 static void AccessControlNamedSetter( 9495 Local<String>, 9496 Local<Value> value, 9497 const v8::PropertyCallbackInfo<v8::Value>& info) { 9498 info.GetReturnValue().Set(value); 9499 } 9500 9501 9502 static void AccessControlIndexedGetter( 9503 uint32_t index, 9504 const v8::PropertyCallbackInfo<v8::Value>& info) { 9505 info.GetReturnValue().Set(v8_num(42)); 9506 } 9507 9508 9509 static void AccessControlIndexedSetter( 9510 uint32_t, 9511 Local<Value> value, 9512 const v8::PropertyCallbackInfo<v8::Value>& info) { 9513 info.GetReturnValue().Set(value); 9514 } 9515 9516 9517 THREADED_TEST(AccessControlInterceptorIC) { 9518 named_access_count = 0; 9519 indexed_access_count = 0; 9520 9521 v8::Isolate* isolate = CcTest::isolate(); 9522 v8::HandleScope handle_scope(isolate); 9523 9524 // Create an environment. 9525 v8::Local<Context> context0 = Context::New(isolate); 9526 context0->Enter(); 9527 9528 // Create an object that requires access-check functions to be 9529 // called for cross-domain access. The object also has interceptors 9530 // interceptor. 9531 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 9532 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 9533 IndexedAccessCounter); 9534 object_template->SetNamedPropertyHandler(AccessControlNamedGetter, 9535 AccessControlNamedSetter); 9536 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter, 9537 AccessControlIndexedSetter); 9538 Local<v8::Object> object = object_template->NewInstance(); 9539 9540 v8::HandleScope scope1(isolate); 9541 9542 // Create another environment. 9543 v8::Local<Context> context1 = Context::New(isolate); 9544 context1->Enter(); 9545 9546 // Make easy access to the object from the other environment. 9547 v8::Handle<v8::Object> global1 = context1->Global(); 9548 global1->Set(v8_str("obj"), object); 9549 9550 v8::Handle<Value> value; 9551 9552 // Check that the named access-control function is called every time 9553 // eventhough there is an interceptor on the object. 9554 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run(); 9555 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;" 9556 "obj.x")->Run(); 9557 CHECK(value->IsNumber()); 9558 CHECK_EQ(42, value->Int32Value()); 9559 CHECK_EQ(21, named_access_count); 9560 9561 value = v8_compile("var p = 'x';")->Run(); 9562 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run(); 9563 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];" 9564 "obj[p]")->Run(); 9565 CHECK(value->IsNumber()); 9566 CHECK_EQ(42, value->Int32Value()); 9567 CHECK_EQ(42, named_access_count); 9568 9569 // Check that the indexed access-control function is called every 9570 // time eventhough there is an interceptor on the object. 9571 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run(); 9572 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];" 9573 "obj[0]")->Run(); 9574 CHECK(value->IsNumber()); 9575 CHECK_EQ(42, value->Int32Value()); 9576 CHECK_EQ(21, indexed_access_count); 9577 9578 context1->Exit(); 9579 context0->Exit(); 9580 } 9581 9582 9583 THREADED_TEST(Version) { 9584 v8::V8::GetVersion(); 9585 } 9586 9587 9588 static void InstanceFunctionCallback( 9589 const v8::FunctionCallbackInfo<v8::Value>& args) { 9590 ApiTestFuzzer::Fuzz(); 9591 args.GetReturnValue().Set(v8_num(12)); 9592 } 9593 9594 9595 THREADED_TEST(InstanceProperties) { 9596 LocalContext context; 9597 v8::HandleScope handle_scope(context->GetIsolate()); 9598 9599 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9600 Local<ObjectTemplate> instance = t->InstanceTemplate(); 9601 9602 instance->Set(v8_str("x"), v8_num(42)); 9603 instance->Set(v8_str("f"), 9604 v8::FunctionTemplate::New(InstanceFunctionCallback)); 9605 9606 Local<Value> o = t->GetFunction()->NewInstance(); 9607 9608 context->Global()->Set(v8_str("i"), o); 9609 Local<Value> value = Script::Compile(v8_str("i.x"))->Run(); 9610 CHECK_EQ(42, value->Int32Value()); 9611 9612 value = Script::Compile(v8_str("i.f()"))->Run(); 9613 CHECK_EQ(12, value->Int32Value()); 9614 } 9615 9616 9617 static void GlobalObjectInstancePropertiesGet( 9618 Local<String> key, 9619 const v8::PropertyCallbackInfo<v8::Value>&) { 9620 ApiTestFuzzer::Fuzz(); 9621 } 9622 9623 9624 THREADED_TEST(GlobalObjectInstanceProperties) { 9625 v8::HandleScope handle_scope(CcTest::isolate()); 9626 9627 Local<Value> global_object; 9628 9629 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9630 t->InstanceTemplate()->SetNamedPropertyHandler( 9631 GlobalObjectInstancePropertiesGet); 9632 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9633 instance_template->Set(v8_str("x"), v8_num(42)); 9634 instance_template->Set(v8_str("f"), 9635 v8::FunctionTemplate::New(InstanceFunctionCallback)); 9636 9637 // The script to check how Crankshaft compiles missing global function 9638 // invocations. function g is not defined and should throw on call. 9639 const char* script = 9640 "function wrapper(call) {" 9641 " var x = 0, y = 1;" 9642 " for (var i = 0; i < 1000; i++) {" 9643 " x += i * 100;" 9644 " y += i * 100;" 9645 " }" 9646 " if (call) g();" 9647 "}" 9648 "for (var i = 0; i < 17; i++) wrapper(false);" 9649 "var thrown = 0;" 9650 "try { wrapper(true); } catch (e) { thrown = 1; };" 9651 "thrown"; 9652 9653 { 9654 LocalContext env(NULL, instance_template); 9655 // Hold on to the global object so it can be used again in another 9656 // environment initialization. 9657 global_object = env->Global(); 9658 9659 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 9660 CHECK_EQ(42, value->Int32Value()); 9661 value = Script::Compile(v8_str("f()"))->Run(); 9662 CHECK_EQ(12, value->Int32Value()); 9663 value = Script::Compile(v8_str(script))->Run(); 9664 CHECK_EQ(1, value->Int32Value()); 9665 } 9666 9667 { 9668 // Create new environment reusing the global object. 9669 LocalContext env(NULL, instance_template, global_object); 9670 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 9671 CHECK_EQ(42, value->Int32Value()); 9672 value = Script::Compile(v8_str("f()"))->Run(); 9673 CHECK_EQ(12, value->Int32Value()); 9674 value = Script::Compile(v8_str(script))->Run(); 9675 CHECK_EQ(1, value->Int32Value()); 9676 } 9677 } 9678 9679 9680 THREADED_TEST(CallKnownGlobalReceiver) { 9681 v8::HandleScope handle_scope(CcTest::isolate()); 9682 9683 Local<Value> global_object; 9684 9685 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9686 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9687 9688 // The script to check that we leave global object not 9689 // global object proxy on stack when we deoptimize from inside 9690 // arguments evaluation. 9691 // To provoke error we need to both force deoptimization 9692 // from arguments evaluation and to force CallIC to take 9693 // CallIC_Miss code path that can't cope with global proxy. 9694 const char* script = 9695 "function bar(x, y) { try { } finally { } }" 9696 "function baz(x) { try { } finally { } }" 9697 "function bom(x) { try { } finally { } }" 9698 "function foo(x) { bar([x], bom(2)); }" 9699 "for (var i = 0; i < 10000; i++) foo(1);" 9700 "foo"; 9701 9702 Local<Value> foo; 9703 { 9704 LocalContext env(NULL, instance_template); 9705 // Hold on to the global object so it can be used again in another 9706 // environment initialization. 9707 global_object = env->Global(); 9708 foo = Script::Compile(v8_str(script))->Run(); 9709 } 9710 9711 { 9712 // Create new environment reusing the global object. 9713 LocalContext env(NULL, instance_template, global_object); 9714 env->Global()->Set(v8_str("foo"), foo); 9715 Script::Compile(v8_str("foo()"))->Run(); 9716 } 9717 } 9718 9719 9720 static void ShadowFunctionCallback( 9721 const v8::FunctionCallbackInfo<v8::Value>& args) { 9722 ApiTestFuzzer::Fuzz(); 9723 args.GetReturnValue().Set(v8_num(42)); 9724 } 9725 9726 9727 static int shadow_y; 9728 static int shadow_y_setter_call_count; 9729 static int shadow_y_getter_call_count; 9730 9731 9732 static void ShadowYSetter(Local<String>, 9733 Local<Value>, 9734 const v8::PropertyCallbackInfo<void>&) { 9735 shadow_y_setter_call_count++; 9736 shadow_y = 42; 9737 } 9738 9739 9740 static void ShadowYGetter(Local<String> name, 9741 const v8::PropertyCallbackInfo<v8::Value>& info) { 9742 ApiTestFuzzer::Fuzz(); 9743 shadow_y_getter_call_count++; 9744 info.GetReturnValue().Set(v8_num(shadow_y)); 9745 } 9746 9747 9748 static void ShadowIndexedGet(uint32_t index, 9749 const v8::PropertyCallbackInfo<v8::Value>&) { 9750 } 9751 9752 9753 static void ShadowNamedGet(Local<String> key, 9754 const v8::PropertyCallbackInfo<v8::Value>&) { 9755 } 9756 9757 9758 THREADED_TEST(ShadowObject) { 9759 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 9760 v8::HandleScope handle_scope(CcTest::isolate()); 9761 9762 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(); 9763 LocalContext context(NULL, global_template); 9764 9765 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9766 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet); 9767 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet); 9768 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 9769 Local<ObjectTemplate> instance = t->InstanceTemplate(); 9770 9771 proto->Set(v8_str("f"), 9772 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>())); 9773 proto->Set(v8_str("x"), v8_num(12)); 9774 9775 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 9776 9777 Local<Value> o = t->GetFunction()->NewInstance(); 9778 context->Global()->Set(v8_str("__proto__"), o); 9779 9780 Local<Value> value = 9781 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run(); 9782 CHECK(value->IsBoolean()); 9783 CHECK(!value->BooleanValue()); 9784 9785 value = Script::Compile(v8_str("x"))->Run(); 9786 CHECK_EQ(12, value->Int32Value()); 9787 9788 value = Script::Compile(v8_str("f()"))->Run(); 9789 CHECK_EQ(42, value->Int32Value()); 9790 9791 Script::Compile(v8_str("y = 43"))->Run(); 9792 CHECK_EQ(1, shadow_y_setter_call_count); 9793 value = Script::Compile(v8_str("y"))->Run(); 9794 CHECK_EQ(1, shadow_y_getter_call_count); 9795 CHECK_EQ(42, value->Int32Value()); 9796 } 9797 9798 9799 THREADED_TEST(HiddenPrototype) { 9800 LocalContext context; 9801 v8::HandleScope handle_scope(context->GetIsolate()); 9802 9803 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 9804 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9805 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9806 t1->SetHiddenPrototype(true); 9807 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 9808 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9809 t2->SetHiddenPrototype(true); 9810 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 9811 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9812 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 9813 9814 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 9815 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9816 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9817 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9818 9819 // Setting the prototype on an object skips hidden prototypes. 9820 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9821 o0->Set(v8_str("__proto__"), o1); 9822 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9823 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9824 o0->Set(v8_str("__proto__"), o2); 9825 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9826 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9827 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9828 o0->Set(v8_str("__proto__"), o3); 9829 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9830 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9831 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9832 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 9833 9834 // Getting the prototype of o0 should get the first visible one 9835 // which is o3. Therefore, z should not be defined on the prototype 9836 // object. 9837 Local<Value> proto = o0->Get(v8_str("__proto__")); 9838 CHECK(proto->IsObject()); 9839 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined()); 9840 } 9841 9842 9843 THREADED_TEST(HiddenPrototypeSet) { 9844 LocalContext context; 9845 v8::HandleScope handle_scope(context->GetIsolate()); 9846 9847 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(); 9848 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(); 9849 ht->SetHiddenPrototype(true); 9850 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(); 9851 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9852 9853 Local<v8::Object> o = ot->GetFunction()->NewInstance(); 9854 Local<v8::Object> h = ht->GetFunction()->NewInstance(); 9855 Local<v8::Object> p = pt->GetFunction()->NewInstance(); 9856 o->Set(v8_str("__proto__"), h); 9857 h->Set(v8_str("__proto__"), p); 9858 9859 // Setting a property that exists on the hidden prototype goes there. 9860 o->Set(v8_str("x"), v8_num(7)); 9861 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value()); 9862 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value()); 9863 CHECK(p->Get(v8_str("x"))->IsUndefined()); 9864 9865 // Setting a new property should not be forwarded to the hidden prototype. 9866 o->Set(v8_str("y"), v8_num(6)); 9867 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value()); 9868 CHECK(h->Get(v8_str("y"))->IsUndefined()); 9869 CHECK(p->Get(v8_str("y"))->IsUndefined()); 9870 9871 // Setting a property that only exists on a prototype of the hidden prototype 9872 // is treated normally again. 9873 p->Set(v8_str("z"), v8_num(8)); 9874 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value()); 9875 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 9876 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 9877 o->Set(v8_str("z"), v8_num(9)); 9878 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value()); 9879 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 9880 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 9881 } 9882 9883 9884 // Regression test for issue 2457. 9885 THREADED_TEST(HiddenPrototypeIdentityHash) { 9886 LocalContext context; 9887 v8::HandleScope handle_scope(context->GetIsolate()); 9888 9889 Handle<FunctionTemplate> t = FunctionTemplate::New(); 9890 t->SetHiddenPrototype(true); 9891 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 9892 Handle<Object> p = t->GetFunction()->NewInstance(); 9893 Handle<Object> o = Object::New(); 9894 o->SetPrototype(p); 9895 9896 int hash = o->GetIdentityHash(); 9897 USE(hash); 9898 o->Set(v8_str("foo"), v8_num(42)); 9899 ASSERT_EQ(hash, o->GetIdentityHash()); 9900 } 9901 9902 9903 THREADED_TEST(SetPrototype) { 9904 LocalContext context; 9905 v8::HandleScope handle_scope(context->GetIsolate()); 9906 9907 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 9908 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9909 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9910 t1->SetHiddenPrototype(true); 9911 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 9912 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9913 t2->SetHiddenPrototype(true); 9914 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 9915 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9916 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 9917 9918 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 9919 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9920 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9921 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9922 9923 // Setting the prototype on an object does not skip hidden prototypes. 9924 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9925 CHECK(o0->SetPrototype(o1)); 9926 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9927 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9928 CHECK(o1->SetPrototype(o2)); 9929 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9930 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9931 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9932 CHECK(o2->SetPrototype(o3)); 9933 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9934 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9935 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9936 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 9937 9938 // Getting the prototype of o0 should get the first visible one 9939 // which is o3. Therefore, z should not be defined on the prototype 9940 // object. 9941 Local<Value> proto = o0->Get(v8_str("__proto__")); 9942 CHECK(proto->IsObject()); 9943 CHECK_EQ(proto.As<v8::Object>(), o3); 9944 9945 // However, Object::GetPrototype ignores hidden prototype. 9946 Local<Value> proto0 = o0->GetPrototype(); 9947 CHECK(proto0->IsObject()); 9948 CHECK_EQ(proto0.As<v8::Object>(), o1); 9949 9950 Local<Value> proto1 = o1->GetPrototype(); 9951 CHECK(proto1->IsObject()); 9952 CHECK_EQ(proto1.As<v8::Object>(), o2); 9953 9954 Local<Value> proto2 = o2->GetPrototype(); 9955 CHECK(proto2->IsObject()); 9956 CHECK_EQ(proto2.As<v8::Object>(), o3); 9957 } 9958 9959 9960 // Getting property names of an object with a prototype chain that 9961 // triggers dictionary elements in GetLocalPropertyNames() shouldn't 9962 // crash the runtime. 9963 THREADED_TEST(Regress91517) { 9964 i::FLAG_allow_natives_syntax = true; 9965 LocalContext context; 9966 v8::HandleScope handle_scope(context->GetIsolate()); 9967 9968 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9969 t1->SetHiddenPrototype(true); 9970 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 9971 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9972 t2->SetHiddenPrototype(true); 9973 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 9974 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New()); 9975 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 9976 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9977 t3->SetHiddenPrototype(true); 9978 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 9979 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(); 9980 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 9981 9982 // Force dictionary-based properties. 9983 i::ScopedVector<char> name_buf(1024); 9984 for (int i = 1; i <= 1000; i++) { 9985 i::OS::SNPrintF(name_buf, "sdf%d", i); 9986 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 9987 } 9988 9989 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9990 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9991 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9992 Local<v8::Object> o4 = t4->GetFunction()->NewInstance(); 9993 9994 // Create prototype chain of hidden prototypes. 9995 CHECK(o4->SetPrototype(o3)); 9996 CHECK(o3->SetPrototype(o2)); 9997 CHECK(o2->SetPrototype(o1)); 9998 9999 // Call the runtime version of GetLocalPropertyNames() on the natively 10000 // created object through JavaScript. 10001 context->Global()->Set(v8_str("obj"), o4); 10002 CompileRun("var names = %GetLocalPropertyNames(obj, true);"); 10003 10004 ExpectInt32("names.length", 1006); 10005 ExpectTrue("names.indexOf(\"baz\") >= 0"); 10006 ExpectTrue("names.indexOf(\"boo\") >= 0"); 10007 ExpectTrue("names.indexOf(\"foo\") >= 0"); 10008 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 10009 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 10010 ExpectFalse("names[1005] == undefined"); 10011 } 10012 10013 10014 THREADED_TEST(FunctionReadOnlyPrototype) { 10015 LocalContext context; 10016 v8::HandleScope handle_scope(context->GetIsolate()); 10017 10018 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 10019 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42)); 10020 t1->ReadOnlyPrototype(); 10021 context->Global()->Set(v8_str("func1"), t1->GetFunction()); 10022 // Configured value of ReadOnly flag. 10023 CHECK(CompileRun( 10024 "(function() {" 10025 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 10026 " return (descriptor['writable'] == false);" 10027 "})()")->BooleanValue()); 10028 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value()); 10029 CHECK_EQ(42, 10030 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value()); 10031 10032 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 10033 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42)); 10034 context->Global()->Set(v8_str("func2"), t2->GetFunction()); 10035 // Default value of ReadOnly flag. 10036 CHECK(CompileRun( 10037 "(function() {" 10038 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 10039 " return (descriptor['writable'] == true);" 10040 "})()")->BooleanValue()); 10041 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value()); 10042 } 10043 10044 10045 THREADED_TEST(SetPrototypeThrows) { 10046 LocalContext context; 10047 v8::HandleScope handle_scope(context->GetIsolate()); 10048 10049 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10050 10051 Local<v8::Object> o0 = t->GetFunction()->NewInstance(); 10052 Local<v8::Object> o1 = t->GetFunction()->NewInstance(); 10053 10054 CHECK(o0->SetPrototype(o1)); 10055 // If setting the prototype leads to the cycle, SetPrototype should 10056 // return false and keep VM in sane state. 10057 v8::TryCatch try_catch; 10058 CHECK(!o1->SetPrototype(o0)); 10059 CHECK(!try_catch.HasCaught()); 10060 ASSERT(!CcTest::i_isolate()->has_pending_exception()); 10061 10062 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); 10063 } 10064 10065 10066 THREADED_TEST(FunctionRemovePrototype) { 10067 LocalContext context; 10068 v8::HandleScope handle_scope(context->GetIsolate()); 10069 10070 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 10071 t1->RemovePrototype(); 10072 Local<v8::Function> fun = t1->GetFunction(); 10073 context->Global()->Set(v8_str("fun"), fun); 10074 CHECK(!CompileRun("'prototype' in fun")->BooleanValue()); 10075 10076 v8::TryCatch try_catch; 10077 CompileRun("new fun()"); 10078 CHECK(try_catch.HasCaught()); 10079 10080 try_catch.Reset(); 10081 fun->NewInstance(); 10082 CHECK(try_catch.HasCaught()); 10083 } 10084 10085 10086 THREADED_TEST(GetterSetterExceptions) { 10087 LocalContext context; 10088 v8::HandleScope handle_scope(context->GetIsolate()); 10089 CompileRun( 10090 "function Foo() { };" 10091 "function Throw() { throw 5; };" 10092 "var x = { };" 10093 "x.__defineSetter__('set', Throw);" 10094 "x.__defineGetter__('get', Throw);"); 10095 Local<v8::Object> x = 10096 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); 10097 v8::TryCatch try_catch; 10098 x->Set(v8_str("set"), v8::Integer::New(8)); 10099 x->Get(v8_str("get")); 10100 x->Set(v8_str("set"), v8::Integer::New(8)); 10101 x->Get(v8_str("get")); 10102 x->Set(v8_str("set"), v8::Integer::New(8)); 10103 x->Get(v8_str("get")); 10104 x->Set(v8_str("set"), v8::Integer::New(8)); 10105 x->Get(v8_str("get")); 10106 } 10107 10108 10109 THREADED_TEST(Constructor) { 10110 LocalContext context; 10111 v8::HandleScope handle_scope(context->GetIsolate()); 10112 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 10113 templ->SetClassName(v8_str("Fun")); 10114 Local<Function> cons = templ->GetFunction(); 10115 context->Global()->Set(v8_str("Fun"), cons); 10116 Local<v8::Object> inst = cons->NewInstance(); 10117 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst)); 10118 CHECK(obj->IsJSObject()); 10119 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 10120 CHECK(value->BooleanValue()); 10121 } 10122 10123 10124 static void ConstructorCallback( 10125 const v8::FunctionCallbackInfo<v8::Value>& args) { 10126 ApiTestFuzzer::Fuzz(); 10127 Local<Object> This; 10128 10129 if (args.IsConstructCall()) { 10130 Local<Object> Holder = args.Holder(); 10131 This = Object::New(); 10132 Local<Value> proto = Holder->GetPrototype(); 10133 if (proto->IsObject()) { 10134 This->SetPrototype(proto); 10135 } 10136 } else { 10137 This = args.This(); 10138 } 10139 10140 This->Set(v8_str("a"), args[0]); 10141 args.GetReturnValue().Set(This); 10142 } 10143 10144 10145 static void FakeConstructorCallback( 10146 const v8::FunctionCallbackInfo<v8::Value>& args) { 10147 ApiTestFuzzer::Fuzz(); 10148 args.GetReturnValue().Set(args[0]); 10149 } 10150 10151 10152 THREADED_TEST(ConstructorForObject) { 10153 LocalContext context; 10154 v8::Isolate* isolate = context->GetIsolate(); 10155 v8::HandleScope handle_scope(isolate); 10156 10157 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10158 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 10159 Local<Object> instance = instance_template->NewInstance(); 10160 context->Global()->Set(v8_str("obj"), instance); 10161 v8::TryCatch try_catch; 10162 Local<Value> value; 10163 CHECK(!try_catch.HasCaught()); 10164 10165 // Call the Object's constructor with a 32-bit signed integer. 10166 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 10167 CHECK(!try_catch.HasCaught()); 10168 CHECK(value->IsInt32()); 10169 CHECK_EQ(28, value->Int32Value()); 10170 10171 Local<Value> args1[] = { v8_num(28) }; 10172 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); 10173 CHECK(value_obj1->IsObject()); 10174 Local<Object> object1 = Local<Object>::Cast(value_obj1); 10175 value = object1->Get(v8_str("a")); 10176 CHECK(value->IsInt32()); 10177 CHECK(!try_catch.HasCaught()); 10178 CHECK_EQ(28, value->Int32Value()); 10179 10180 // Call the Object's constructor with a String. 10181 value = CompileRun( 10182 "(function() { var o = new obj('tipli'); return o.a; })()"); 10183 CHECK(!try_catch.HasCaught()); 10184 CHECK(value->IsString()); 10185 String::Utf8Value string_value1(value->ToString()); 10186 CHECK_EQ("tipli", *string_value1); 10187 10188 Local<Value> args2[] = { v8_str("tipli") }; 10189 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); 10190 CHECK(value_obj2->IsObject()); 10191 Local<Object> object2 = Local<Object>::Cast(value_obj2); 10192 value = object2->Get(v8_str("a")); 10193 CHECK(!try_catch.HasCaught()); 10194 CHECK(value->IsString()); 10195 String::Utf8Value string_value2(value->ToString()); 10196 CHECK_EQ("tipli", *string_value2); 10197 10198 // Call the Object's constructor with a Boolean. 10199 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 10200 CHECK(!try_catch.HasCaught()); 10201 CHECK(value->IsBoolean()); 10202 CHECK_EQ(true, value->BooleanValue()); 10203 10204 Handle<Value> args3[] = { v8::True(isolate) }; 10205 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); 10206 CHECK(value_obj3->IsObject()); 10207 Local<Object> object3 = Local<Object>::Cast(value_obj3); 10208 value = object3->Get(v8_str("a")); 10209 CHECK(!try_catch.HasCaught()); 10210 CHECK(value->IsBoolean()); 10211 CHECK_EQ(true, value->BooleanValue()); 10212 10213 // Call the Object's constructor with undefined. 10214 Handle<Value> args4[] = { v8::Undefined(isolate) }; 10215 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); 10216 CHECK(value_obj4->IsObject()); 10217 Local<Object> object4 = Local<Object>::Cast(value_obj4); 10218 value = object4->Get(v8_str("a")); 10219 CHECK(!try_catch.HasCaught()); 10220 CHECK(value->IsUndefined()); 10221 10222 // Call the Object's constructor with null. 10223 Handle<Value> args5[] = { v8::Null(isolate) }; 10224 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); 10225 CHECK(value_obj5->IsObject()); 10226 Local<Object> object5 = Local<Object>::Cast(value_obj5); 10227 value = object5->Get(v8_str("a")); 10228 CHECK(!try_catch.HasCaught()); 10229 CHECK(value->IsNull()); 10230 } 10231 10232 // Check exception handling when there is no constructor set for the Object. 10233 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10234 Local<Object> instance = instance_template->NewInstance(); 10235 context->Global()->Set(v8_str("obj2"), instance); 10236 v8::TryCatch try_catch; 10237 Local<Value> value; 10238 CHECK(!try_catch.HasCaught()); 10239 10240 value = CompileRun("new obj2(28)"); 10241 CHECK(try_catch.HasCaught()); 10242 String::Utf8Value exception_value1(try_catch.Exception()); 10243 CHECK_EQ("TypeError: object is not a function", *exception_value1); 10244 try_catch.Reset(); 10245 10246 Local<Value> args[] = { v8_num(29) }; 10247 value = instance->CallAsConstructor(1, args); 10248 CHECK(try_catch.HasCaught()); 10249 String::Utf8Value exception_value2(try_catch.Exception()); 10250 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); 10251 try_catch.Reset(); 10252 } 10253 10254 // Check the case when constructor throws exception. 10255 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10256 instance_template->SetCallAsFunctionHandler(ThrowValue); 10257 Local<Object> instance = instance_template->NewInstance(); 10258 context->Global()->Set(v8_str("obj3"), instance); 10259 v8::TryCatch try_catch; 10260 Local<Value> value; 10261 CHECK(!try_catch.HasCaught()); 10262 10263 value = CompileRun("new obj3(22)"); 10264 CHECK(try_catch.HasCaught()); 10265 String::Utf8Value exception_value1(try_catch.Exception()); 10266 CHECK_EQ("22", *exception_value1); 10267 try_catch.Reset(); 10268 10269 Local<Value> args[] = { v8_num(23) }; 10270 value = instance->CallAsConstructor(1, args); 10271 CHECK(try_catch.HasCaught()); 10272 String::Utf8Value exception_value2(try_catch.Exception()); 10273 CHECK_EQ("23", *exception_value2); 10274 try_catch.Reset(); 10275 } 10276 10277 // Check whether constructor returns with an object or non-object. 10278 { Local<FunctionTemplate> function_template = 10279 FunctionTemplate::New(FakeConstructorCallback); 10280 Local<Function> function = function_template->GetFunction(); 10281 Local<Object> instance1 = function; 10282 context->Global()->Set(v8_str("obj4"), instance1); 10283 v8::TryCatch try_catch; 10284 Local<Value> value; 10285 CHECK(!try_catch.HasCaught()); 10286 10287 CHECK(instance1->IsObject()); 10288 CHECK(instance1->IsFunction()); 10289 10290 value = CompileRun("new obj4(28)"); 10291 CHECK(!try_catch.HasCaught()); 10292 CHECK(value->IsObject()); 10293 10294 Local<Value> args1[] = { v8_num(28) }; 10295 value = instance1->CallAsConstructor(1, args1); 10296 CHECK(!try_catch.HasCaught()); 10297 CHECK(value->IsObject()); 10298 10299 Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10300 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 10301 Local<Object> instance2 = instance_template->NewInstance(); 10302 context->Global()->Set(v8_str("obj5"), instance2); 10303 CHECK(!try_catch.HasCaught()); 10304 10305 CHECK(instance2->IsObject()); 10306 CHECK(!instance2->IsFunction()); 10307 10308 value = CompileRun("new obj5(28)"); 10309 CHECK(!try_catch.HasCaught()); 10310 CHECK(!value->IsObject()); 10311 10312 Local<Value> args2[] = { v8_num(28) }; 10313 value = instance2->CallAsConstructor(1, args2); 10314 CHECK(!try_catch.HasCaught()); 10315 CHECK(!value->IsObject()); 10316 } 10317 } 10318 10319 10320 THREADED_TEST(FunctionDescriptorException) { 10321 LocalContext context; 10322 v8::HandleScope handle_scope(context->GetIsolate()); 10323 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 10324 templ->SetClassName(v8_str("Fun")); 10325 Local<Function> cons = templ->GetFunction(); 10326 context->Global()->Set(v8_str("Fun"), cons); 10327 Local<Value> value = CompileRun( 10328 "function test() {" 10329 " try {" 10330 " (new Fun()).blah()" 10331 " } catch (e) {" 10332 " var str = String(e);" 10333 " if (str.indexOf('TypeError') == -1) return 1;" 10334 " if (str.indexOf('[object Fun]') != -1) return 2;" 10335 " if (str.indexOf('#<Fun>') == -1) return 3;" 10336 " return 0;" 10337 " }" 10338 " return 4;" 10339 "}" 10340 "test();"); 10341 CHECK_EQ(0, value->Int32Value()); 10342 } 10343 10344 10345 THREADED_TEST(EvalAliasedDynamic) { 10346 LocalContext current; 10347 v8::HandleScope scope(current->GetIsolate()); 10348 10349 // Tests where aliased eval can only be resolved dynamically. 10350 Local<Script> script = 10351 Script::Compile(v8_str("function f(x) { " 10352 " var foo = 2;" 10353 " with (x) { return eval('foo'); }" 10354 "}" 10355 "foo = 0;" 10356 "result1 = f(new Object());" 10357 "result2 = f(this);" 10358 "var x = new Object();" 10359 "x.eval = function(x) { return 1; };" 10360 "result3 = f(x);")); 10361 script->Run(); 10362 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value()); 10363 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); 10364 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); 10365 10366 v8::TryCatch try_catch; 10367 script = 10368 Script::Compile(v8_str("function f(x) { " 10369 " var bar = 2;" 10370 " with (x) { return eval('bar'); }" 10371 "}" 10372 "result4 = f(this)")); 10373 script->Run(); 10374 CHECK(!try_catch.HasCaught()); 10375 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value()); 10376 10377 try_catch.Reset(); 10378 } 10379 10380 10381 THREADED_TEST(CrossEval) { 10382 v8::HandleScope scope(CcTest::isolate()); 10383 LocalContext other; 10384 LocalContext current; 10385 10386 Local<String> token = v8_str("<security token>"); 10387 other->SetSecurityToken(token); 10388 current->SetSecurityToken(token); 10389 10390 // Set up reference from current to other. 10391 current->Global()->Set(v8_str("other"), other->Global()); 10392 10393 // Check that new variables are introduced in other context. 10394 Local<Script> script = 10395 Script::Compile(v8_str("other.eval('var foo = 1234')")); 10396 script->Run(); 10397 Local<Value> foo = other->Global()->Get(v8_str("foo")); 10398 CHECK_EQ(1234, foo->Int32Value()); 10399 CHECK(!current->Global()->Has(v8_str("foo"))); 10400 10401 // Check that writing to non-existing properties introduces them in 10402 // the other context. 10403 script = 10404 Script::Compile(v8_str("other.eval('na = 1234')")); 10405 script->Run(); 10406 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value()); 10407 CHECK(!current->Global()->Has(v8_str("na"))); 10408 10409 // Check that global variables in current context are not visible in other 10410 // context. 10411 v8::TryCatch try_catch; 10412 script = 10413 Script::Compile(v8_str("var bar = 42; other.eval('bar');")); 10414 Local<Value> result = script->Run(); 10415 CHECK(try_catch.HasCaught()); 10416 try_catch.Reset(); 10417 10418 // Check that local variables in current context are not visible in other 10419 // context. 10420 script = 10421 Script::Compile(v8_str("(function() { " 10422 " var baz = 87;" 10423 " return other.eval('baz');" 10424 "})();")); 10425 result = script->Run(); 10426 CHECK(try_catch.HasCaught()); 10427 try_catch.Reset(); 10428 10429 // Check that global variables in the other environment are visible 10430 // when evaluting code. 10431 other->Global()->Set(v8_str("bis"), v8_num(1234)); 10432 script = Script::Compile(v8_str("other.eval('bis')")); 10433 CHECK_EQ(1234, script->Run()->Int32Value()); 10434 CHECK(!try_catch.HasCaught()); 10435 10436 // Check that the 'this' pointer points to the global object evaluating 10437 // code. 10438 other->Global()->Set(v8_str("t"), other->Global()); 10439 script = Script::Compile(v8_str("other.eval('this == t')")); 10440 result = script->Run(); 10441 CHECK(result->IsTrue()); 10442 CHECK(!try_catch.HasCaught()); 10443 10444 // Check that variables introduced in with-statement are not visible in 10445 // other context. 10446 script = 10447 Script::Compile(v8_str("with({x:2}){other.eval('x')}")); 10448 result = script->Run(); 10449 CHECK(try_catch.HasCaught()); 10450 try_catch.Reset(); 10451 10452 // Check that you cannot use 'eval.call' with another object than the 10453 // current global object. 10454 script = 10455 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')")); 10456 result = script->Run(); 10457 CHECK(try_catch.HasCaught()); 10458 } 10459 10460 10461 // Test that calling eval in a context which has been detached from 10462 // its global throws an exception. This behavior is consistent with 10463 // other JavaScript implementations. 10464 THREADED_TEST(EvalInDetachedGlobal) { 10465 v8::Isolate* isolate = CcTest::isolate(); 10466 v8::HandleScope scope(isolate); 10467 10468 v8::Local<Context> context0 = Context::New(isolate); 10469 v8::Local<Context> context1 = Context::New(isolate); 10470 10471 // Set up function in context0 that uses eval from context0. 10472 context0->Enter(); 10473 v8::Handle<v8::Value> fun = 10474 CompileRun("var x = 42;" 10475 "(function() {" 10476 " var e = eval;" 10477 " return function(s) { return e(s); }" 10478 "})()"); 10479 context0->Exit(); 10480 10481 // Put the function into context1 and call it before and after 10482 // detaching the global. Before detaching, the call succeeds and 10483 // after detaching and exception is thrown. 10484 context1->Enter(); 10485 context1->Global()->Set(v8_str("fun"), fun); 10486 v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); 10487 CHECK_EQ(42, x_value->Int32Value()); 10488 context0->DetachGlobal(); 10489 v8::TryCatch catcher; 10490 x_value = CompileRun("fun('x')"); 10491 CHECK(x_value.IsEmpty()); 10492 CHECK(catcher.HasCaught()); 10493 context1->Exit(); 10494 } 10495 10496 10497 THREADED_TEST(CrossLazyLoad) { 10498 v8::HandleScope scope(CcTest::isolate()); 10499 LocalContext other; 10500 LocalContext current; 10501 10502 Local<String> token = v8_str("<security token>"); 10503 other->SetSecurityToken(token); 10504 current->SetSecurityToken(token); 10505 10506 // Set up reference from current to other. 10507 current->Global()->Set(v8_str("other"), other->Global()); 10508 10509 // Trigger lazy loading in other context. 10510 Local<Script> script = 10511 Script::Compile(v8_str("other.eval('new Date(42)')")); 10512 Local<Value> value = script->Run(); 10513 CHECK_EQ(42.0, value->NumberValue()); 10514 } 10515 10516 10517 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 10518 ApiTestFuzzer::Fuzz(); 10519 if (args.IsConstructCall()) { 10520 if (args[0]->IsInt32()) { 10521 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value())); 10522 return; 10523 } 10524 } 10525 10526 args.GetReturnValue().Set(args[0]); 10527 } 10528 10529 10530 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 10531 args.GetReturnValue().Set(args.This()); 10532 } 10533 10534 10535 // Test that a call handler can be set for objects which will allow 10536 // non-function objects created through the API to be called as 10537 // functions. 10538 THREADED_TEST(CallAsFunction) { 10539 LocalContext context; 10540 v8::HandleScope scope(context->GetIsolate()); 10541 10542 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10543 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10544 instance_template->SetCallAsFunctionHandler(call_as_function); 10545 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10546 context->Global()->Set(v8_str("obj"), instance); 10547 v8::TryCatch try_catch; 10548 Local<Value> value; 10549 CHECK(!try_catch.HasCaught()); 10550 10551 value = CompileRun("obj(42)"); 10552 CHECK(!try_catch.HasCaught()); 10553 CHECK_EQ(42, value->Int32Value()); 10554 10555 value = CompileRun("(function(o){return o(49)})(obj)"); 10556 CHECK(!try_catch.HasCaught()); 10557 CHECK_EQ(49, value->Int32Value()); 10558 10559 // test special case of call as function 10560 value = CompileRun("[obj]['0'](45)"); 10561 CHECK(!try_catch.HasCaught()); 10562 CHECK_EQ(45, value->Int32Value()); 10563 10564 value = CompileRun("obj.call = Function.prototype.call;" 10565 "obj.call(null, 87)"); 10566 CHECK(!try_catch.HasCaught()); 10567 CHECK_EQ(87, value->Int32Value()); 10568 10569 // Regression tests for bug #1116356: Calling call through call/apply 10570 // must work for non-function receivers. 10571 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 10572 value = CompileRun(apply_99); 10573 CHECK(!try_catch.HasCaught()); 10574 CHECK_EQ(99, value->Int32Value()); 10575 10576 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 10577 value = CompileRun(call_17); 10578 CHECK(!try_catch.HasCaught()); 10579 CHECK_EQ(17, value->Int32Value()); 10580 10581 // Check that the call-as-function handler can be called through 10582 // new. 10583 value = CompileRun("new obj(43)"); 10584 CHECK(!try_catch.HasCaught()); 10585 CHECK_EQ(-43, value->Int32Value()); 10586 10587 // Check that the call-as-function handler can be called through 10588 // the API. 10589 v8::Handle<Value> args[] = { v8_num(28) }; 10590 value = instance->CallAsFunction(instance, 1, args); 10591 CHECK(!try_catch.HasCaught()); 10592 CHECK_EQ(28, value->Int32Value()); 10593 } 10594 10595 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10596 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 10597 USE(instance_template); 10598 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10599 context->Global()->Set(v8_str("obj2"), instance); 10600 v8::TryCatch try_catch; 10601 Local<Value> value; 10602 CHECK(!try_catch.HasCaught()); 10603 10604 // Call an object without call-as-function handler through the JS 10605 value = CompileRun("obj2(28)"); 10606 CHECK(value.IsEmpty()); 10607 CHECK(try_catch.HasCaught()); 10608 String::Utf8Value exception_value1(try_catch.Exception()); 10609 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", 10610 *exception_value1); 10611 try_catch.Reset(); 10612 10613 // Call an object without call-as-function handler through the API 10614 value = CompileRun("obj2(28)"); 10615 v8::Handle<Value> args[] = { v8_num(28) }; 10616 value = instance->CallAsFunction(instance, 1, args); 10617 CHECK(value.IsEmpty()); 10618 CHECK(try_catch.HasCaught()); 10619 String::Utf8Value exception_value2(try_catch.Exception()); 10620 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); 10621 try_catch.Reset(); 10622 } 10623 10624 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10625 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10626 instance_template->SetCallAsFunctionHandler(ThrowValue); 10627 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10628 context->Global()->Set(v8_str("obj3"), instance); 10629 v8::TryCatch try_catch; 10630 Local<Value> value; 10631 CHECK(!try_catch.HasCaught()); 10632 10633 // Catch the exception which is thrown by call-as-function handler 10634 value = CompileRun("obj3(22)"); 10635 CHECK(try_catch.HasCaught()); 10636 String::Utf8Value exception_value1(try_catch.Exception()); 10637 CHECK_EQ("22", *exception_value1); 10638 try_catch.Reset(); 10639 10640 v8::Handle<Value> args[] = { v8_num(23) }; 10641 value = instance->CallAsFunction(instance, 1, args); 10642 CHECK(try_catch.HasCaught()); 10643 String::Utf8Value exception_value2(try_catch.Exception()); 10644 CHECK_EQ("23", *exception_value2); 10645 try_catch.Reset(); 10646 } 10647 10648 { v8::Isolate* isolate = context->GetIsolate(); 10649 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10650 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10651 instance_template->SetCallAsFunctionHandler(ReturnThis); 10652 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10653 10654 Local<v8::Value> a1 = 10655 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL); 10656 CHECK(a1->StrictEquals(instance)); 10657 Local<v8::Value> a2 = 10658 instance->CallAsFunction(v8::Null(isolate), 0, NULL); 10659 CHECK(a2->StrictEquals(instance)); 10660 Local<v8::Value> a3 = 10661 instance->CallAsFunction(v8_num(42), 0, NULL); 10662 CHECK(a3->StrictEquals(instance)); 10663 Local<v8::Value> a4 = 10664 instance->CallAsFunction(v8_str("hello"), 0, NULL); 10665 CHECK(a4->StrictEquals(instance)); 10666 Local<v8::Value> a5 = 10667 instance->CallAsFunction(v8::True(isolate), 0, NULL); 10668 CHECK(a5->StrictEquals(instance)); 10669 } 10670 10671 { v8::Isolate* isolate = context->GetIsolate(); 10672 CompileRun( 10673 "function ReturnThisSloppy() {" 10674 " return this;" 10675 "}" 10676 "function ReturnThisStrict() {" 10677 " 'use strict';" 10678 " return this;" 10679 "}"); 10680 Local<Function> ReturnThisSloppy = 10681 Local<Function>::Cast( 10682 context->Global()->Get(v8_str("ReturnThisSloppy"))); 10683 Local<Function> ReturnThisStrict = 10684 Local<Function>::Cast( 10685 context->Global()->Get(v8_str("ReturnThisStrict"))); 10686 10687 Local<v8::Value> a1 = 10688 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL); 10689 CHECK(a1->StrictEquals(context->Global())); 10690 Local<v8::Value> a2 = 10691 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL); 10692 CHECK(a2->StrictEquals(context->Global())); 10693 Local<v8::Value> a3 = 10694 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL); 10695 CHECK(a3->IsNumberObject()); 10696 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf()); 10697 Local<v8::Value> a4 = 10698 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL); 10699 CHECK(a4->IsStringObject()); 10700 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello"))); 10701 Local<v8::Value> a5 = 10702 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL); 10703 CHECK(a5->IsBooleanObject()); 10704 CHECK(a5.As<v8::BooleanObject>()->ValueOf()); 10705 10706 Local<v8::Value> a6 = 10707 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL); 10708 CHECK(a6->IsUndefined()); 10709 Local<v8::Value> a7 = 10710 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL); 10711 CHECK(a7->IsNull()); 10712 Local<v8::Value> a8 = 10713 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL); 10714 CHECK(a8->StrictEquals(v8_num(42))); 10715 Local<v8::Value> a9 = 10716 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL); 10717 CHECK(a9->StrictEquals(v8_str("hello"))); 10718 Local<v8::Value> a10 = 10719 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL); 10720 CHECK(a10->StrictEquals(v8::True(isolate))); 10721 } 10722 } 10723 10724 10725 // Check whether a non-function object is callable. 10726 THREADED_TEST(CallableObject) { 10727 LocalContext context; 10728 v8::HandleScope scope(context->GetIsolate()); 10729 10730 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10731 instance_template->SetCallAsFunctionHandler(call_as_function); 10732 Local<Object> instance = instance_template->NewInstance(); 10733 v8::TryCatch try_catch; 10734 10735 CHECK(instance->IsCallable()); 10736 CHECK(!try_catch.HasCaught()); 10737 } 10738 10739 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10740 Local<Object> instance = instance_template->NewInstance(); 10741 v8::TryCatch try_catch; 10742 10743 CHECK(!instance->IsCallable()); 10744 CHECK(!try_catch.HasCaught()); 10745 } 10746 10747 { Local<FunctionTemplate> function_template = 10748 FunctionTemplate::New(call_as_function); 10749 Local<Function> function = function_template->GetFunction(); 10750 Local<Object> instance = function; 10751 v8::TryCatch try_catch; 10752 10753 CHECK(instance->IsCallable()); 10754 CHECK(!try_catch.HasCaught()); 10755 } 10756 10757 { Local<FunctionTemplate> function_template = FunctionTemplate::New(); 10758 Local<Function> function = function_template->GetFunction(); 10759 Local<Object> instance = function; 10760 v8::TryCatch try_catch; 10761 10762 CHECK(instance->IsCallable()); 10763 CHECK(!try_catch.HasCaught()); 10764 } 10765 } 10766 10767 10768 static int CountHandles() { 10769 return v8::HandleScope::NumberOfHandles(); 10770 } 10771 10772 10773 static int Recurse(int depth, int iterations) { 10774 v8::HandleScope scope(CcTest::isolate()); 10775 if (depth == 0) return CountHandles(); 10776 for (int i = 0; i < iterations; i++) { 10777 Local<v8::Number> n(v8::Integer::New(42)); 10778 } 10779 return Recurse(depth - 1, iterations); 10780 } 10781 10782 10783 THREADED_TEST(HandleIteration) { 10784 static const int kIterations = 500; 10785 static const int kNesting = 200; 10786 CHECK_EQ(0, CountHandles()); 10787 { 10788 v8::HandleScope scope1(CcTest::isolate()); 10789 CHECK_EQ(0, CountHandles()); 10790 for (int i = 0; i < kIterations; i++) { 10791 Local<v8::Number> n(v8::Integer::New(42)); 10792 CHECK_EQ(i + 1, CountHandles()); 10793 } 10794 10795 CHECK_EQ(kIterations, CountHandles()); 10796 { 10797 v8::HandleScope scope2(CcTest::isolate()); 10798 for (int j = 0; j < kIterations; j++) { 10799 Local<v8::Number> n(v8::Integer::New(42)); 10800 CHECK_EQ(j + 1 + kIterations, CountHandles()); 10801 } 10802 } 10803 CHECK_EQ(kIterations, CountHandles()); 10804 } 10805 CHECK_EQ(0, CountHandles()); 10806 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations)); 10807 } 10808 10809 10810 static void InterceptorHasOwnPropertyGetter( 10811 Local<String> name, 10812 const v8::PropertyCallbackInfo<v8::Value>& info) { 10813 ApiTestFuzzer::Fuzz(); 10814 } 10815 10816 10817 THREADED_TEST(InterceptorHasOwnProperty) { 10818 LocalContext context; 10819 v8::HandleScope scope(context->GetIsolate()); 10820 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 10821 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 10822 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter); 10823 Local<Function> function = fun_templ->GetFunction(); 10824 context->Global()->Set(v8_str("constructor"), function); 10825 v8::Handle<Value> value = CompileRun( 10826 "var o = new constructor();" 10827 "o.hasOwnProperty('ostehaps');"); 10828 CHECK_EQ(false, value->BooleanValue()); 10829 value = CompileRun( 10830 "o.ostehaps = 42;" 10831 "o.hasOwnProperty('ostehaps');"); 10832 CHECK_EQ(true, value->BooleanValue()); 10833 value = CompileRun( 10834 "var p = new constructor();" 10835 "p.hasOwnProperty('ostehaps');"); 10836 CHECK_EQ(false, value->BooleanValue()); 10837 } 10838 10839 10840 static void InterceptorHasOwnPropertyGetterGC( 10841 Local<String> name, 10842 const v8::PropertyCallbackInfo<v8::Value>& info) { 10843 ApiTestFuzzer::Fuzz(); 10844 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 10845 } 10846 10847 10848 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { 10849 LocalContext context; 10850 v8::HandleScope scope(context->GetIsolate()); 10851 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 10852 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 10853 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); 10854 Local<Function> function = fun_templ->GetFunction(); 10855 context->Global()->Set(v8_str("constructor"), function); 10856 // Let's first make some stuff so we can be sure to get a good GC. 10857 CompileRun( 10858 "function makestr(size) {" 10859 " switch (size) {" 10860 " case 1: return 'f';" 10861 " case 2: return 'fo';" 10862 " case 3: return 'foo';" 10863 " }" 10864 " return makestr(size >> 1) + makestr((size + 1) >> 1);" 10865 "}" 10866 "var x = makestr(12345);" 10867 "x = makestr(31415);" 10868 "x = makestr(23456);"); 10869 v8::Handle<Value> value = CompileRun( 10870 "var o = new constructor();" 10871 "o.__proto__ = new String(x);" 10872 "o.hasOwnProperty('ostehaps');"); 10873 CHECK_EQ(false, value->BooleanValue()); 10874 } 10875 10876 10877 typedef void (*NamedPropertyGetter)( 10878 Local<String> property, 10879 const v8::PropertyCallbackInfo<v8::Value>& info); 10880 10881 10882 static void CheckInterceptorLoadIC(NamedPropertyGetter getter, 10883 const char* source, 10884 int expected) { 10885 v8::HandleScope scope(CcTest::isolate()); 10886 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10887 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data")); 10888 LocalContext context; 10889 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10890 v8::Handle<Value> value = CompileRun(source); 10891 CHECK_EQ(expected, value->Int32Value()); 10892 } 10893 10894 10895 static void InterceptorLoadICGetter( 10896 Local<String> name, 10897 const v8::PropertyCallbackInfo<v8::Value>& info) { 10898 ApiTestFuzzer::Fuzz(); 10899 v8::Isolate* isolate = CcTest::isolate(); 10900 CHECK_EQ(isolate, info.GetIsolate()); 10901 CHECK_EQ(v8_str("data"), info.Data()); 10902 CHECK_EQ(v8_str("x"), name); 10903 info.GetReturnValue().Set(v8::Integer::New(42)); 10904 } 10905 10906 10907 // This test should hit the load IC for the interceptor case. 10908 THREADED_TEST(InterceptorLoadIC) { 10909 CheckInterceptorLoadIC(InterceptorLoadICGetter, 10910 "var result = 0;" 10911 "for (var i = 0; i < 1000; i++) {" 10912 " result = o.x;" 10913 "}", 10914 42); 10915 } 10916 10917 10918 // Below go several tests which verify that JITing for various 10919 // configurations of interceptor and explicit fields works fine 10920 // (those cases are special cased to get better performance). 10921 10922 static void InterceptorLoadXICGetter( 10923 Local<String> name, 10924 const v8::PropertyCallbackInfo<v8::Value>& info) { 10925 ApiTestFuzzer::Fuzz(); 10926 info.GetReturnValue().Set( 10927 v8_str("x")->Equals(name) ? 10928 v8::Handle<v8::Value>(v8::Integer::New(42)) : 10929 v8::Handle<v8::Value>()); 10930 } 10931 10932 10933 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { 10934 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10935 "var result = 0;" 10936 "o.y = 239;" 10937 "for (var i = 0; i < 1000; i++) {" 10938 " result = o.y;" 10939 "}", 10940 239); 10941 } 10942 10943 10944 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) { 10945 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10946 "var result = 0;" 10947 "o.__proto__ = { 'y': 239 };" 10948 "for (var i = 0; i < 1000; i++) {" 10949 " result = o.y + o.x;" 10950 "}", 10951 239 + 42); 10952 } 10953 10954 10955 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) { 10956 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10957 "var result = 0;" 10958 "o.__proto__.y = 239;" 10959 "for (var i = 0; i < 1000; i++) {" 10960 " result = o.y + o.x;" 10961 "}", 10962 239 + 42); 10963 } 10964 10965 10966 THREADED_TEST(InterceptorLoadICUndefined) { 10967 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10968 "var result = 0;" 10969 "for (var i = 0; i < 1000; i++) {" 10970 " result = (o.y == undefined) ? 239 : 42;" 10971 "}", 10972 239); 10973 } 10974 10975 10976 THREADED_TEST(InterceptorLoadICWithOverride) { 10977 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10978 "fst = new Object(); fst.__proto__ = o;" 10979 "snd = new Object(); snd.__proto__ = fst;" 10980 "var result1 = 0;" 10981 "for (var i = 0; i < 1000; i++) {" 10982 " result1 = snd.x;" 10983 "}" 10984 "fst.x = 239;" 10985 "var result = 0;" 10986 "for (var i = 0; i < 1000; i++) {" 10987 " result = snd.x;" 10988 "}" 10989 "result + result1", 10990 239 + 42); 10991 } 10992 10993 10994 // Test the case when we stored field into 10995 // a stub, but interceptor produced value on its own. 10996 THREADED_TEST(InterceptorLoadICFieldNotNeeded) { 10997 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10998 "proto = new Object();" 10999 "o.__proto__ = proto;" 11000 "proto.x = 239;" 11001 "for (var i = 0; i < 1000; i++) {" 11002 " o.x;" 11003 // Now it should be ICed and keep a reference to x defined on proto 11004 "}" 11005 "var result = 0;" 11006 "for (var i = 0; i < 1000; i++) {" 11007 " result += o.x;" 11008 "}" 11009 "result;", 11010 42 * 1000); 11011 } 11012 11013 11014 // Test the case when we stored field into 11015 // a stub, but it got invalidated later on. 11016 THREADED_TEST(InterceptorLoadICInvalidatedField) { 11017 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11018 "proto1 = new Object();" 11019 "proto2 = new Object();" 11020 "o.__proto__ = proto1;" 11021 "proto1.__proto__ = proto2;" 11022 "proto2.y = 239;" 11023 "for (var i = 0; i < 1000; i++) {" 11024 " o.y;" 11025 // Now it should be ICed and keep a reference to y defined on proto2 11026 "}" 11027 "proto1.y = 42;" 11028 "var result = 0;" 11029 "for (var i = 0; i < 1000; i++) {" 11030 " result += o.y;" 11031 "}" 11032 "result;", 11033 42 * 1000); 11034 } 11035 11036 11037 static int interceptor_load_not_handled_calls = 0; 11038 static void InterceptorLoadNotHandled( 11039 Local<String> name, 11040 const v8::PropertyCallbackInfo<v8::Value>& info) { 11041 ++interceptor_load_not_handled_calls; 11042 } 11043 11044 11045 // Test how post-interceptor lookups are done in the non-cacheable 11046 // case: the interceptor should not be invoked during this lookup. 11047 THREADED_TEST(InterceptorLoadICPostInterceptor) { 11048 interceptor_load_not_handled_calls = 0; 11049 CheckInterceptorLoadIC(InterceptorLoadNotHandled, 11050 "receiver = new Object();" 11051 "receiver.__proto__ = o;" 11052 "proto = new Object();" 11053 "/* Make proto a slow-case object. */" 11054 "for (var i = 0; i < 1000; i++) {" 11055 " proto[\"xxxxxxxx\" + i] = [];" 11056 "}" 11057 "proto.x = 17;" 11058 "o.__proto__ = proto;" 11059 "var result = 0;" 11060 "for (var i = 0; i < 1000; i++) {" 11061 " result += receiver.x;" 11062 "}" 11063 "result;", 11064 17 * 1000); 11065 CHECK_EQ(1000, interceptor_load_not_handled_calls); 11066 } 11067 11068 11069 // Test the case when we stored field into 11070 // a stub, but it got invalidated later on due to override on 11071 // global object which is between interceptor and fields' holders. 11072 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) { 11073 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 11074 "o.__proto__ = this;" // set a global to be a proto of o. 11075 "this.__proto__.y = 239;" 11076 "for (var i = 0; i < 10; i++) {" 11077 " if (o.y != 239) throw 'oops: ' + o.y;" 11078 // Now it should be ICed and keep a reference to y defined on field_holder. 11079 "}" 11080 "this.y = 42;" // Assign on a global. 11081 "var result = 0;" 11082 "for (var i = 0; i < 10; i++) {" 11083 " result += o.y;" 11084 "}" 11085 "result;", 11086 42 * 10); 11087 } 11088 11089 11090 static void SetOnThis(Local<String> name, 11091 Local<Value> value, 11092 const v8::PropertyCallbackInfo<void>& info) { 11093 info.This()->ForceSet(name, value); 11094 } 11095 11096 11097 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) { 11098 v8::HandleScope scope(CcTest::isolate()); 11099 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11100 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11101 templ->SetAccessor(v8_str("y"), Return239Callback); 11102 LocalContext context; 11103 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11104 11105 // Check the case when receiver and interceptor's holder 11106 // are the same objects. 11107 v8::Handle<Value> value = CompileRun( 11108 "var result = 0;" 11109 "for (var i = 0; i < 7; i++) {" 11110 " result = o.y;" 11111 "}"); 11112 CHECK_EQ(239, value->Int32Value()); 11113 11114 // Check the case when interceptor's holder is in proto chain 11115 // of receiver. 11116 value = CompileRun( 11117 "r = { __proto__: o };" 11118 "var result = 0;" 11119 "for (var i = 0; i < 7; i++) {" 11120 " result = r.y;" 11121 "}"); 11122 CHECK_EQ(239, value->Int32Value()); 11123 } 11124 11125 11126 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) { 11127 v8::HandleScope scope(CcTest::isolate()); 11128 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11129 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11130 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 11131 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11132 11133 LocalContext context; 11134 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11135 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11136 11137 // Check the case when receiver and interceptor's holder 11138 // are the same objects. 11139 v8::Handle<Value> value = CompileRun( 11140 "o.__proto__ = p;" 11141 "var result = 0;" 11142 "for (var i = 0; i < 7; i++) {" 11143 " result = o.x + o.y;" 11144 "}"); 11145 CHECK_EQ(239 + 42, value->Int32Value()); 11146 11147 // Check the case when interceptor's holder is in proto chain 11148 // of receiver. 11149 value = CompileRun( 11150 "r = { __proto__: o };" 11151 "var result = 0;" 11152 "for (var i = 0; i < 7; i++) {" 11153 " result = r.x + r.y;" 11154 "}"); 11155 CHECK_EQ(239 + 42, value->Int32Value()); 11156 } 11157 11158 11159 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) { 11160 v8::HandleScope scope(CcTest::isolate()); 11161 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11162 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11163 templ->SetAccessor(v8_str("y"), Return239Callback); 11164 11165 LocalContext context; 11166 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11167 11168 v8::Handle<Value> value = CompileRun( 11169 "fst = new Object(); fst.__proto__ = o;" 11170 "snd = new Object(); snd.__proto__ = fst;" 11171 "var result1 = 0;" 11172 "for (var i = 0; i < 7; i++) {" 11173 " result1 = snd.x;" 11174 "}" 11175 "fst.x = 239;" 11176 "var result = 0;" 11177 "for (var i = 0; i < 7; i++) {" 11178 " result = snd.x;" 11179 "}" 11180 "result + result1"); 11181 CHECK_EQ(239 + 42, value->Int32Value()); 11182 } 11183 11184 11185 // Test the case when we stored callback into 11186 // a stub, but interceptor produced value on its own. 11187 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) { 11188 v8::HandleScope scope(CcTest::isolate()); 11189 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11190 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11191 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 11192 templ_p->SetAccessor(v8_str("y"), Return239Callback); 11193 11194 LocalContext context; 11195 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11196 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11197 11198 v8::Handle<Value> value = CompileRun( 11199 "o.__proto__ = p;" 11200 "for (var i = 0; i < 7; i++) {" 11201 " o.x;" 11202 // Now it should be ICed and keep a reference to x defined on p 11203 "}" 11204 "var result = 0;" 11205 "for (var i = 0; i < 7; i++) {" 11206 " result += o.x;" 11207 "}" 11208 "result"); 11209 CHECK_EQ(42 * 7, value->Int32Value()); 11210 } 11211 11212 11213 // Test the case when we stored callback into 11214 // a stub, but it got invalidated later on. 11215 THREADED_TEST(InterceptorLoadICInvalidatedCallback) { 11216 v8::HandleScope scope(CcTest::isolate()); 11217 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11218 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11219 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 11220 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11221 11222 LocalContext context; 11223 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11224 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11225 11226 v8::Handle<Value> value = CompileRun( 11227 "inbetween = new Object();" 11228 "o.__proto__ = inbetween;" 11229 "inbetween.__proto__ = p;" 11230 "for (var i = 0; i < 10; i++) {" 11231 " o.y;" 11232 // Now it should be ICed and keep a reference to y defined on p 11233 "}" 11234 "inbetween.y = 42;" 11235 "var result = 0;" 11236 "for (var i = 0; i < 10; i++) {" 11237 " result += o.y;" 11238 "}" 11239 "result"); 11240 CHECK_EQ(42 * 10, value->Int32Value()); 11241 } 11242 11243 11244 // Test the case when we stored callback into 11245 // a stub, but it got invalidated later on due to override on 11246 // global object which is between interceptor and callbacks' holders. 11247 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) { 11248 v8::HandleScope scope(CcTest::isolate()); 11249 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11250 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11251 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 11252 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 11253 11254 LocalContext context; 11255 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11256 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 11257 11258 v8::Handle<Value> value = CompileRun( 11259 "o.__proto__ = this;" 11260 "this.__proto__ = p;" 11261 "for (var i = 0; i < 10; i++) {" 11262 " if (o.y != 239) throw 'oops: ' + o.y;" 11263 // Now it should be ICed and keep a reference to y defined on p 11264 "}" 11265 "this.y = 42;" 11266 "var result = 0;" 11267 "for (var i = 0; i < 10; i++) {" 11268 " result += o.y;" 11269 "}" 11270 "result"); 11271 CHECK_EQ(42 * 10, value->Int32Value()); 11272 } 11273 11274 11275 static void InterceptorLoadICGetter0( 11276 Local<String> name, 11277 const v8::PropertyCallbackInfo<v8::Value>& info) { 11278 ApiTestFuzzer::Fuzz(); 11279 CHECK(v8_str("x")->Equals(name)); 11280 info.GetReturnValue().Set(v8::Integer::New(0)); 11281 } 11282 11283 11284 THREADED_TEST(InterceptorReturningZero) { 11285 CheckInterceptorLoadIC(InterceptorLoadICGetter0, 11286 "o.x == undefined ? 1 : 0", 11287 0); 11288 } 11289 11290 11291 static void InterceptorStoreICSetter( 11292 Local<String> key, 11293 Local<Value> value, 11294 const v8::PropertyCallbackInfo<v8::Value>& info) { 11295 CHECK(v8_str("x")->Equals(key)); 11296 CHECK_EQ(42, value->Int32Value()); 11297 info.GetReturnValue().Set(value); 11298 } 11299 11300 11301 // This test should hit the store IC for the interceptor case. 11302 THREADED_TEST(InterceptorStoreIC) { 11303 v8::HandleScope scope(CcTest::isolate()); 11304 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11305 templ->SetNamedPropertyHandler(InterceptorLoadICGetter, 11306 InterceptorStoreICSetter, 11307 0, 0, 0, v8_str("data")); 11308 LocalContext context; 11309 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11310 CompileRun( 11311 "for (var i = 0; i < 1000; i++) {" 11312 " o.x = 42;" 11313 "}"); 11314 } 11315 11316 11317 THREADED_TEST(InterceptorStoreICWithNoSetter) { 11318 v8::HandleScope scope(CcTest::isolate()); 11319 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11320 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11321 LocalContext context; 11322 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11323 v8::Handle<Value> value = CompileRun( 11324 "for (var i = 0; i < 1000; i++) {" 11325 " o.y = 239;" 11326 "}" 11327 "42 + o.y"); 11328 CHECK_EQ(239 + 42, value->Int32Value()); 11329 } 11330 11331 11332 11333 11334 v8::Handle<Value> call_ic_function; 11335 v8::Handle<Value> call_ic_function2; 11336 v8::Handle<Value> call_ic_function3; 11337 11338 static void InterceptorCallICGetter( 11339 Local<String> name, 11340 const v8::PropertyCallbackInfo<v8::Value>& info) { 11341 ApiTestFuzzer::Fuzz(); 11342 CHECK(v8_str("x")->Equals(name)); 11343 info.GetReturnValue().Set(call_ic_function); 11344 } 11345 11346 11347 // This test should hit the call IC for the interceptor case. 11348 THREADED_TEST(InterceptorCallIC) { 11349 v8::HandleScope scope(CcTest::isolate()); 11350 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11351 templ->SetNamedPropertyHandler(InterceptorCallICGetter); 11352 LocalContext context; 11353 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11354 call_ic_function = 11355 v8_compile("function f(x) { return x + 1; }; f")->Run(); 11356 v8::Handle<Value> value = CompileRun( 11357 "var result = 0;" 11358 "for (var i = 0; i < 1000; i++) {" 11359 " result = o.x(41);" 11360 "}"); 11361 CHECK_EQ(42, value->Int32Value()); 11362 } 11363 11364 11365 // This test checks that if interceptor doesn't provide 11366 // a value, we can fetch regular value. 11367 THREADED_TEST(InterceptorCallICSeesOthers) { 11368 v8::HandleScope scope(CcTest::isolate()); 11369 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11370 templ->SetNamedPropertyHandler(NoBlockGetterX); 11371 LocalContext context; 11372 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11373 v8::Handle<Value> value = CompileRun( 11374 "o.x = function f(x) { return x + 1; };" 11375 "var result = 0;" 11376 "for (var i = 0; i < 7; i++) {" 11377 " result = o.x(41);" 11378 "}"); 11379 CHECK_EQ(42, value->Int32Value()); 11380 } 11381 11382 11383 static v8::Handle<Value> call_ic_function4; 11384 static void InterceptorCallICGetter4( 11385 Local<String> name, 11386 const v8::PropertyCallbackInfo<v8::Value>& info) { 11387 ApiTestFuzzer::Fuzz(); 11388 CHECK(v8_str("x")->Equals(name)); 11389 info.GetReturnValue().Set(call_ic_function4); 11390 } 11391 11392 11393 // This test checks that if interceptor provides a function, 11394 // even if we cached shadowed variant, interceptor's function 11395 // is invoked 11396 THREADED_TEST(InterceptorCallICCacheableNotNeeded) { 11397 v8::HandleScope scope(CcTest::isolate()); 11398 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11399 templ->SetNamedPropertyHandler(InterceptorCallICGetter4); 11400 LocalContext context; 11401 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11402 call_ic_function4 = 11403 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11404 v8::Handle<Value> value = CompileRun( 11405 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };" 11406 "var result = 0;" 11407 "for (var i = 0; i < 1000; i++) {" 11408 " result = o.x(42);" 11409 "}"); 11410 CHECK_EQ(41, value->Int32Value()); 11411 } 11412 11413 11414 // Test the case when we stored cacheable lookup into 11415 // a stub, but it got invalidated later on 11416 THREADED_TEST(InterceptorCallICInvalidatedCacheable) { 11417 v8::HandleScope scope(CcTest::isolate()); 11418 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11419 templ->SetNamedPropertyHandler(NoBlockGetterX); 11420 LocalContext context; 11421 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11422 v8::Handle<Value> value = CompileRun( 11423 "proto1 = new Object();" 11424 "proto2 = new Object();" 11425 "o.__proto__ = proto1;" 11426 "proto1.__proto__ = proto2;" 11427 "proto2.y = function(x) { return x + 1; };" 11428 // Invoke it many times to compile a stub 11429 "for (var i = 0; i < 7; i++) {" 11430 " o.y(42);" 11431 "}" 11432 "proto1.y = function(x) { return x - 1; };" 11433 "var result = 0;" 11434 "for (var i = 0; i < 7; i++) {" 11435 " result += o.y(42);" 11436 "}"); 11437 CHECK_EQ(41 * 7, value->Int32Value()); 11438 } 11439 11440 11441 // This test checks that if interceptor doesn't provide a function, 11442 // cached constant function is used 11443 THREADED_TEST(InterceptorCallICConstantFunctionUsed) { 11444 v8::HandleScope scope(CcTest::isolate()); 11445 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11446 templ->SetNamedPropertyHandler(NoBlockGetterX); 11447 LocalContext context; 11448 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11449 v8::Handle<Value> value = CompileRun( 11450 "function inc(x) { return x + 1; };" 11451 "inc(1);" 11452 "o.x = inc;" 11453 "var result = 0;" 11454 "for (var i = 0; i < 1000; i++) {" 11455 " result = o.x(42);" 11456 "}"); 11457 CHECK_EQ(43, value->Int32Value()); 11458 } 11459 11460 11461 static v8::Handle<Value> call_ic_function5; 11462 static void InterceptorCallICGetter5( 11463 Local<String> name, 11464 const v8::PropertyCallbackInfo<v8::Value>& info) { 11465 ApiTestFuzzer::Fuzz(); 11466 if (v8_str("x")->Equals(name)) 11467 info.GetReturnValue().Set(call_ic_function5); 11468 } 11469 11470 11471 // This test checks that if interceptor provides a function, 11472 // even if we cached constant function, interceptor's function 11473 // is invoked 11474 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { 11475 v8::HandleScope scope(CcTest::isolate()); 11476 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11477 templ->SetNamedPropertyHandler(InterceptorCallICGetter5); 11478 LocalContext context; 11479 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11480 call_ic_function5 = 11481 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11482 v8::Handle<Value> value = CompileRun( 11483 "function inc(x) { return x + 1; };" 11484 "inc(1);" 11485 "o.x = inc;" 11486 "var result = 0;" 11487 "for (var i = 0; i < 1000; i++) {" 11488 " result = o.x(42);" 11489 "}"); 11490 CHECK_EQ(41, value->Int32Value()); 11491 } 11492 11493 11494 static v8::Handle<Value> call_ic_function6; 11495 static void InterceptorCallICGetter6( 11496 Local<String> name, 11497 const v8::PropertyCallbackInfo<v8::Value>& info) { 11498 ApiTestFuzzer::Fuzz(); 11499 if (v8_str("x")->Equals(name)) 11500 info.GetReturnValue().Set(call_ic_function6); 11501 } 11502 11503 11504 // Same test as above, except the code is wrapped in a function 11505 // to test the optimized compiler. 11506 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) { 11507 i::FLAG_allow_natives_syntax = true; 11508 v8::HandleScope scope(CcTest::isolate()); 11509 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11510 templ->SetNamedPropertyHandler(InterceptorCallICGetter6); 11511 LocalContext context; 11512 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11513 call_ic_function6 = 11514 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11515 v8::Handle<Value> value = CompileRun( 11516 "function inc(x) { return x + 1; };" 11517 "inc(1);" 11518 "o.x = inc;" 11519 "function test() {" 11520 " var result = 0;" 11521 " for (var i = 0; i < 1000; i++) {" 11522 " result = o.x(42);" 11523 " }" 11524 " return result;" 11525 "};" 11526 "test();" 11527 "test();" 11528 "test();" 11529 "%OptimizeFunctionOnNextCall(test);" 11530 "test()"); 11531 CHECK_EQ(41, value->Int32Value()); 11532 } 11533 11534 11535 // Test the case when we stored constant function into 11536 // a stub, but it got invalidated later on 11537 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { 11538 v8::HandleScope scope(CcTest::isolate()); 11539 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11540 templ->SetNamedPropertyHandler(NoBlockGetterX); 11541 LocalContext context; 11542 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11543 v8::Handle<Value> value = CompileRun( 11544 "function inc(x) { return x + 1; };" 11545 "inc(1);" 11546 "proto1 = new Object();" 11547 "proto2 = new Object();" 11548 "o.__proto__ = proto1;" 11549 "proto1.__proto__ = proto2;" 11550 "proto2.y = inc;" 11551 // Invoke it many times to compile a stub 11552 "for (var i = 0; i < 7; i++) {" 11553 " o.y(42);" 11554 "}" 11555 "proto1.y = function(x) { return x - 1; };" 11556 "var result = 0;" 11557 "for (var i = 0; i < 7; i++) {" 11558 " result += o.y(42);" 11559 "}"); 11560 CHECK_EQ(41 * 7, value->Int32Value()); 11561 } 11562 11563 11564 // Test the case when we stored constant function into 11565 // a stub, but it got invalidated later on due to override on 11566 // global object which is between interceptor and constant function' holders. 11567 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) { 11568 v8::HandleScope scope(CcTest::isolate()); 11569 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11570 templ->SetNamedPropertyHandler(NoBlockGetterX); 11571 LocalContext context; 11572 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11573 v8::Handle<Value> value = CompileRun( 11574 "function inc(x) { return x + 1; };" 11575 "inc(1);" 11576 "o.__proto__ = this;" 11577 "this.__proto__.y = inc;" 11578 // Invoke it many times to compile a stub 11579 "for (var i = 0; i < 7; i++) {" 11580 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);" 11581 "}" 11582 "this.y = function(x) { return x - 1; };" 11583 "var result = 0;" 11584 "for (var i = 0; i < 7; i++) {" 11585 " result += o.y(42);" 11586 "}"); 11587 CHECK_EQ(41 * 7, value->Int32Value()); 11588 } 11589 11590 11591 // Test the case when actual function to call sits on global object. 11592 THREADED_TEST(InterceptorCallICCachedFromGlobal) { 11593 v8::HandleScope scope(CcTest::isolate()); 11594 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11595 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 11596 11597 LocalContext context; 11598 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11599 11600 v8::Handle<Value> value = CompileRun( 11601 "try {" 11602 " o.__proto__ = this;" 11603 " for (var i = 0; i < 10; i++) {" 11604 " var v = o.parseFloat('239');" 11605 " if (v != 239) throw v;" 11606 // Now it should be ICed and keep a reference to parseFloat. 11607 " }" 11608 " var result = 0;" 11609 " for (var i = 0; i < 10; i++) {" 11610 " result += o.parseFloat('239');" 11611 " }" 11612 " result" 11613 "} catch(e) {" 11614 " e" 11615 "};"); 11616 CHECK_EQ(239 * 10, value->Int32Value()); 11617 } 11618 11619 static void InterceptorCallICFastApi( 11620 Local<String> name, 11621 const v8::PropertyCallbackInfo<v8::Value>& info) { 11622 ApiTestFuzzer::Fuzz(); 11623 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 11624 int* call_count = 11625 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 11626 ++(*call_count); 11627 if ((*call_count) % 20 == 0) { 11628 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 11629 } 11630 } 11631 11632 static void FastApiCallback_TrivialSignature( 11633 const v8::FunctionCallbackInfo<v8::Value>& args) { 11634 ApiTestFuzzer::Fuzz(); 11635 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 11636 v8::Isolate* isolate = CcTest::isolate(); 11637 CHECK_EQ(isolate, args.GetIsolate()); 11638 CHECK_EQ(args.This(), args.Holder()); 11639 CHECK(args.Data()->Equals(v8_str("method_data"))); 11640 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 11641 } 11642 11643 static void FastApiCallback_SimpleSignature( 11644 const v8::FunctionCallbackInfo<v8::Value>& args) { 11645 ApiTestFuzzer::Fuzz(); 11646 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 11647 v8::Isolate* isolate = CcTest::isolate(); 11648 CHECK_EQ(isolate, args.GetIsolate()); 11649 CHECK_EQ(args.This()->GetPrototype(), args.Holder()); 11650 CHECK(args.Data()->Equals(v8_str("method_data"))); 11651 // Note, we're using HasRealNamedProperty instead of Has to avoid 11652 // invoking the interceptor again. 11653 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo"))); 11654 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 11655 } 11656 11657 11658 // Helper to maximize the odds of object moving. 11659 static void GenerateSomeGarbage() { 11660 CompileRun( 11661 "var garbage;" 11662 "for (var i = 0; i < 1000; i++) {" 11663 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 11664 "}" 11665 "garbage = undefined;"); 11666 } 11667 11668 11669 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 11670 static int count = 0; 11671 if (count++ % 3 == 0) { 11672 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 11673 // This should move the stub 11674 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 11675 } 11676 } 11677 11678 11679 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 11680 LocalContext context; 11681 v8::HandleScope scope(context->GetIsolate()); 11682 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 11683 nativeobject_templ->Set(context->GetIsolate(), "callback", 11684 v8::FunctionTemplate::New(DirectApiCallback)); 11685 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 11686 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 11687 // call the api function multiple times to ensure direct call stub creation. 11688 CompileRun( 11689 "function f() {" 11690 " for (var i = 1; i <= 30; i++) {" 11691 " nativeobject.callback();" 11692 " }" 11693 "}" 11694 "f();"); 11695 } 11696 11697 11698 void ThrowingDirectApiCallback( 11699 const v8::FunctionCallbackInfo<v8::Value>& args) { 11700 args.GetIsolate()->ThrowException(v8_str("g")); 11701 } 11702 11703 11704 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 11705 LocalContext context; 11706 v8::HandleScope scope(context->GetIsolate()); 11707 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 11708 nativeobject_templ->Set(context->GetIsolate(), "callback", 11709 v8::FunctionTemplate::New(ThrowingDirectApiCallback)); 11710 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 11711 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 11712 // call the api function multiple times to ensure direct call stub creation. 11713 v8::Handle<Value> result = CompileRun( 11714 "var result = '';" 11715 "function f() {" 11716 " for (var i = 1; i <= 5; i++) {" 11717 " try { nativeobject.callback(); } catch (e) { result += e; }" 11718 " }" 11719 "}" 11720 "f(); result;"); 11721 CHECK_EQ(v8_str("ggggg"), result); 11722 } 11723 11724 11725 static Handle<Value> DoDirectGetter() { 11726 if (++p_getter_count % 3 == 0) { 11727 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 11728 GenerateSomeGarbage(); 11729 } 11730 return v8_str("Direct Getter Result"); 11731 } 11732 11733 static void DirectGetterCallback( 11734 Local<String> name, 11735 const v8::PropertyCallbackInfo<v8::Value>& info) { 11736 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 11737 info.GetReturnValue().Set(DoDirectGetter()); 11738 } 11739 11740 11741 template<typename Accessor> 11742 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 11743 LocalContext context; 11744 v8::HandleScope scope(context->GetIsolate()); 11745 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 11746 obj->SetAccessor(v8_str("p1"), accessor); 11747 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 11748 p_getter_count = 0; 11749 v8::Handle<v8::Value> result = CompileRun( 11750 "function f() {" 11751 " for (var i = 0; i < 30; i++) o1.p1;" 11752 " return o1.p1" 11753 "}" 11754 "f();"); 11755 CHECK_EQ(v8_str("Direct Getter Result"), result); 11756 CHECK_EQ(31, p_getter_count); 11757 } 11758 11759 11760 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 11761 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 11762 } 11763 11764 11765 void ThrowingDirectGetterCallback( 11766 Local<String> name, 11767 const v8::PropertyCallbackInfo<v8::Value>& info) { 11768 info.GetIsolate()->ThrowException(v8_str("g")); 11769 } 11770 11771 11772 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 11773 LocalContext context; 11774 v8::HandleScope scope(context->GetIsolate()); 11775 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 11776 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 11777 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 11778 v8::Handle<Value> result = CompileRun( 11779 "var result = '';" 11780 "for (var i = 0; i < 5; i++) {" 11781 " try { o1.p1; } catch (e) { result += e; }" 11782 "}" 11783 "result;"); 11784 CHECK_EQ(v8_str("ggggg"), result); 11785 } 11786 11787 11788 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 11789 int interceptor_call_count = 0; 11790 v8::HandleScope scope(CcTest::isolate()); 11791 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11792 v8::Handle<v8::FunctionTemplate> method_templ = 11793 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 11794 v8_str("method_data"), 11795 v8::Handle<v8::Signature>()); 11796 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11797 proto_templ->Set(v8_str("method"), method_templ); 11798 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11799 templ->SetNamedPropertyHandler( 11800 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11801 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11802 LocalContext context; 11803 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11804 GenerateSomeGarbage(); 11805 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11806 CompileRun( 11807 "var result = 0;" 11808 "for (var i = 0; i < 100; i++) {" 11809 " result = o.method(41);" 11810 "}"); 11811 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11812 CHECK_EQ(100, interceptor_call_count); 11813 } 11814 11815 11816 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 11817 int interceptor_call_count = 0; 11818 v8::HandleScope scope(CcTest::isolate()); 11819 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11820 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 11821 FastApiCallback_SimpleSignature, v8_str("method_data"), 11822 v8::Signature::New(CcTest::isolate(), fun_templ)); 11823 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11824 proto_templ->Set(v8_str("method"), method_templ); 11825 fun_templ->SetHiddenPrototype(true); 11826 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11827 templ->SetNamedPropertyHandler( 11828 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11829 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11830 LocalContext context; 11831 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11832 GenerateSomeGarbage(); 11833 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11834 CompileRun( 11835 "o.foo = 17;" 11836 "var receiver = {};" 11837 "receiver.__proto__ = o;" 11838 "var result = 0;" 11839 "for (var i = 0; i < 100; i++) {" 11840 " result = receiver.method(41);" 11841 "}"); 11842 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11843 CHECK_EQ(100, interceptor_call_count); 11844 } 11845 11846 11847 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 11848 int interceptor_call_count = 0; 11849 v8::HandleScope scope(CcTest::isolate()); 11850 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11851 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 11852 FastApiCallback_SimpleSignature, v8_str("method_data"), 11853 v8::Signature::New(CcTest::isolate(), fun_templ)); 11854 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11855 proto_templ->Set(v8_str("method"), method_templ); 11856 fun_templ->SetHiddenPrototype(true); 11857 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11858 templ->SetNamedPropertyHandler( 11859 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11860 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11861 LocalContext context; 11862 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11863 GenerateSomeGarbage(); 11864 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11865 CompileRun( 11866 "o.foo = 17;" 11867 "var receiver = {};" 11868 "receiver.__proto__ = o;" 11869 "var result = 0;" 11870 "var saved_result = 0;" 11871 "for (var i = 0; i < 100; i++) {" 11872 " result = receiver.method(41);" 11873 " if (i == 50) {" 11874 " saved_result = result;" 11875 " receiver = {method: function(x) { return x - 1 }};" 11876 " }" 11877 "}"); 11878 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 11879 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11880 CHECK_GE(interceptor_call_count, 50); 11881 } 11882 11883 11884 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 11885 int interceptor_call_count = 0; 11886 v8::HandleScope scope(CcTest::isolate()); 11887 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11888 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 11889 FastApiCallback_SimpleSignature, v8_str("method_data"), 11890 v8::Signature::New(CcTest::isolate(), fun_templ)); 11891 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11892 proto_templ->Set(v8_str("method"), method_templ); 11893 fun_templ->SetHiddenPrototype(true); 11894 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11895 templ->SetNamedPropertyHandler( 11896 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11897 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11898 LocalContext context; 11899 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11900 GenerateSomeGarbage(); 11901 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11902 CompileRun( 11903 "o.foo = 17;" 11904 "var receiver = {};" 11905 "receiver.__proto__ = o;" 11906 "var result = 0;" 11907 "var saved_result = 0;" 11908 "for (var i = 0; i < 100; i++) {" 11909 " result = receiver.method(41);" 11910 " if (i == 50) {" 11911 " saved_result = result;" 11912 " o.method = function(x) { return x - 1 };" 11913 " }" 11914 "}"); 11915 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 11916 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11917 CHECK_GE(interceptor_call_count, 50); 11918 } 11919 11920 11921 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 11922 int interceptor_call_count = 0; 11923 v8::HandleScope scope(CcTest::isolate()); 11924 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11925 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 11926 FastApiCallback_SimpleSignature, v8_str("method_data"), 11927 v8::Signature::New(CcTest::isolate(), fun_templ)); 11928 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11929 proto_templ->Set(v8_str("method"), method_templ); 11930 fun_templ->SetHiddenPrototype(true); 11931 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11932 templ->SetNamedPropertyHandler( 11933 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11934 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11935 LocalContext context; 11936 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11937 GenerateSomeGarbage(); 11938 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11939 v8::TryCatch try_catch; 11940 CompileRun( 11941 "o.foo = 17;" 11942 "var receiver = {};" 11943 "receiver.__proto__ = o;" 11944 "var result = 0;" 11945 "var saved_result = 0;" 11946 "for (var i = 0; i < 100; i++) {" 11947 " result = receiver.method(41);" 11948 " if (i == 50) {" 11949 " saved_result = result;" 11950 " receiver = 333;" 11951 " }" 11952 "}"); 11953 CHECK(try_catch.HasCaught()); 11954 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 11955 try_catch.Exception()->ToString()); 11956 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11957 CHECK_GE(interceptor_call_count, 50); 11958 } 11959 11960 11961 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 11962 int interceptor_call_count = 0; 11963 v8::HandleScope scope(CcTest::isolate()); 11964 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11965 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 11966 FastApiCallback_SimpleSignature, v8_str("method_data"), 11967 v8::Signature::New(CcTest::isolate(), fun_templ)); 11968 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11969 proto_templ->Set(v8_str("method"), method_templ); 11970 fun_templ->SetHiddenPrototype(true); 11971 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11972 templ->SetNamedPropertyHandler( 11973 InterceptorCallICFastApi, NULL, NULL, NULL, NULL, 11974 v8::External::New(CcTest::isolate(), &interceptor_call_count)); 11975 LocalContext context; 11976 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11977 GenerateSomeGarbage(); 11978 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11979 v8::TryCatch try_catch; 11980 CompileRun( 11981 "o.foo = 17;" 11982 "var receiver = {};" 11983 "receiver.__proto__ = o;" 11984 "var result = 0;" 11985 "var saved_result = 0;" 11986 "for (var i = 0; i < 100; i++) {" 11987 " result = receiver.method(41);" 11988 " if (i == 50) {" 11989 " saved_result = result;" 11990 " receiver = {method: receiver.method};" 11991 " }" 11992 "}"); 11993 CHECK(try_catch.HasCaught()); 11994 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 11995 try_catch.Exception()->ToString()); 11996 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11997 CHECK_GE(interceptor_call_count, 50); 11998 } 11999 12000 12001 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 12002 v8::HandleScope scope(CcTest::isolate()); 12003 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 12004 v8::Handle<v8::FunctionTemplate> method_templ = 12005 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 12006 v8_str("method_data"), 12007 v8::Handle<v8::Signature>()); 12008 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12009 proto_templ->Set(v8_str("method"), method_templ); 12010 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12011 USE(templ); 12012 LocalContext context; 12013 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12014 GenerateSomeGarbage(); 12015 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12016 CompileRun( 12017 "var result = 0;" 12018 "for (var i = 0; i < 100; i++) {" 12019 " result = o.method(41);" 12020 "}"); 12021 12022 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12023 } 12024 12025 12026 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 12027 v8::HandleScope scope(CcTest::isolate()); 12028 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 12029 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12030 FastApiCallback_SimpleSignature, v8_str("method_data"), 12031 v8::Signature::New(CcTest::isolate(), fun_templ)); 12032 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12033 proto_templ->Set(v8_str("method"), method_templ); 12034 fun_templ->SetHiddenPrototype(true); 12035 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12036 CHECK(!templ.IsEmpty()); 12037 LocalContext context; 12038 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12039 GenerateSomeGarbage(); 12040 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12041 CompileRun( 12042 "o.foo = 17;" 12043 "var receiver = {};" 12044 "receiver.__proto__ = o;" 12045 "var result = 0;" 12046 "for (var i = 0; i < 100; i++) {" 12047 " result = receiver.method(41);" 12048 "}"); 12049 12050 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 12051 } 12052 12053 12054 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 12055 v8::HandleScope scope(CcTest::isolate()); 12056 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 12057 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12058 FastApiCallback_SimpleSignature, v8_str("method_data"), 12059 v8::Signature::New(CcTest::isolate(), fun_templ)); 12060 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12061 proto_templ->Set(v8_str("method"), method_templ); 12062 fun_templ->SetHiddenPrototype(true); 12063 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12064 CHECK(!templ.IsEmpty()); 12065 LocalContext context; 12066 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12067 GenerateSomeGarbage(); 12068 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12069 CompileRun( 12070 "o.foo = 17;" 12071 "var receiver = {};" 12072 "receiver.__proto__ = o;" 12073 "var result = 0;" 12074 "var saved_result = 0;" 12075 "for (var i = 0; i < 100; i++) {" 12076 " result = receiver.method(41);" 12077 " if (i == 50) {" 12078 " saved_result = result;" 12079 " receiver = {method: function(x) { return x - 1 }};" 12080 " }" 12081 "}"); 12082 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 12083 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12084 } 12085 12086 12087 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 12088 v8::HandleScope scope(CcTest::isolate()); 12089 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 12090 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12091 FastApiCallback_SimpleSignature, v8_str("method_data"), 12092 v8::Signature::New(CcTest::isolate(), fun_templ)); 12093 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12094 proto_templ->Set(v8_str("method"), method_templ); 12095 fun_templ->SetHiddenPrototype(true); 12096 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12097 CHECK(!templ.IsEmpty()); 12098 LocalContext context; 12099 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12100 GenerateSomeGarbage(); 12101 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12102 v8::TryCatch try_catch; 12103 CompileRun( 12104 "o.foo = 17;" 12105 "var receiver = {};" 12106 "receiver.__proto__ = o;" 12107 "var result = 0;" 12108 "var saved_result = 0;" 12109 "for (var i = 0; i < 100; i++) {" 12110 " result = receiver.method(41);" 12111 " if (i == 50) {" 12112 " saved_result = result;" 12113 " receiver = 333;" 12114 " }" 12115 "}"); 12116 CHECK(try_catch.HasCaught()); 12117 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 12118 try_catch.Exception()->ToString()); 12119 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12120 } 12121 12122 12123 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 12124 v8::HandleScope scope(CcTest::isolate()); 12125 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 12126 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New( 12127 FastApiCallback_SimpleSignature, v8_str("method_data"), 12128 v8::Signature::New(CcTest::isolate(), fun_templ)); 12129 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 12130 proto_templ->Set(v8_str("method"), method_templ); 12131 fun_templ->SetHiddenPrototype(true); 12132 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 12133 CHECK(!templ.IsEmpty()); 12134 LocalContext context; 12135 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 12136 GenerateSomeGarbage(); 12137 context->Global()->Set(v8_str("o"), fun->NewInstance()); 12138 v8::TryCatch try_catch; 12139 CompileRun( 12140 "o.foo = 17;" 12141 "var receiver = {};" 12142 "receiver.__proto__ = o;" 12143 "var result = 0;" 12144 "var saved_result = 0;" 12145 "for (var i = 0; i < 100; i++) {" 12146 " result = receiver.method(41);" 12147 " if (i == 50) {" 12148 " saved_result = result;" 12149 " receiver = Object.create(receiver);" 12150 " }" 12151 "}"); 12152 CHECK(try_catch.HasCaught()); 12153 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 12154 try_catch.Exception()->ToString()); 12155 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12156 } 12157 12158 12159 v8::Handle<Value> keyed_call_ic_function; 12160 12161 static void InterceptorKeyedCallICGetter( 12162 Local<String> name, 12163 const v8::PropertyCallbackInfo<v8::Value>& info) { 12164 ApiTestFuzzer::Fuzz(); 12165 if (v8_str("x")->Equals(name)) { 12166 info.GetReturnValue().Set(keyed_call_ic_function); 12167 } 12168 } 12169 12170 12171 // Test the case when we stored cacheable lookup into 12172 // a stub, but the function name changed (to another cacheable function). 12173 THREADED_TEST(InterceptorKeyedCallICKeyChange1) { 12174 v8::HandleScope scope(CcTest::isolate()); 12175 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12176 templ->SetNamedPropertyHandler(NoBlockGetterX); 12177 LocalContext context; 12178 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12179 CompileRun( 12180 "proto = new Object();" 12181 "proto.y = function(x) { return x + 1; };" 12182 "proto.z = function(x) { return x - 1; };" 12183 "o.__proto__ = proto;" 12184 "var result = 0;" 12185 "var method = 'y';" 12186 "for (var i = 0; i < 10; i++) {" 12187 " if (i == 5) { method = 'z'; };" 12188 " result += o[method](41);" 12189 "}"); 12190 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12191 } 12192 12193 12194 // Test the case when we stored cacheable lookup into 12195 // a stub, but the function name changed (and the new function is present 12196 // both before and after the interceptor in the prototype chain). 12197 THREADED_TEST(InterceptorKeyedCallICKeyChange2) { 12198 v8::HandleScope scope(CcTest::isolate()); 12199 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12200 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); 12201 LocalContext context; 12202 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); 12203 keyed_call_ic_function = 12204 v8_compile("function f(x) { return x - 1; }; f")->Run(); 12205 CompileRun( 12206 "o = new Object();" 12207 "proto2 = new Object();" 12208 "o.y = function(x) { return x + 1; };" 12209 "proto2.y = function(x) { return x + 2; };" 12210 "o.__proto__ = proto1;" 12211 "proto1.__proto__ = proto2;" 12212 "var result = 0;" 12213 "var method = 'x';" 12214 "for (var i = 0; i < 10; i++) {" 12215 " if (i == 5) { method = 'y'; };" 12216 " result += o[method](41);" 12217 "}"); 12218 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12219 } 12220 12221 12222 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit 12223 // on the global object. 12224 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { 12225 v8::HandleScope scope(CcTest::isolate()); 12226 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12227 templ->SetNamedPropertyHandler(NoBlockGetterX); 12228 LocalContext context; 12229 context->Global()->Set(v8_str("o"), templ->NewInstance()); 12230 CompileRun( 12231 "function inc(x) { return x + 1; };" 12232 "inc(1);" 12233 "function dec(x) { return x - 1; };" 12234 "dec(1);" 12235 "o.__proto__ = this;" 12236 "this.__proto__.x = inc;" 12237 "this.__proto__.y = dec;" 12238 "var result = 0;" 12239 "var method = 'x';" 12240 "for (var i = 0; i < 10; i++) {" 12241 " if (i == 5) { method = 'y'; };" 12242 " result += o[method](41);" 12243 "}"); 12244 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12245 } 12246 12247 12248 // Test the case when actual function to call sits on global object. 12249 THREADED_TEST(InterceptorKeyedCallICFromGlobal) { 12250 v8::HandleScope scope(CcTest::isolate()); 12251 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 12252 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12253 LocalContext context; 12254 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12255 12256 CompileRun( 12257 "function len(x) { return x.length; };" 12258 "o.__proto__ = this;" 12259 "var m = 'parseFloat';" 12260 "var result = 0;" 12261 "for (var i = 0; i < 10; i++) {" 12262 " if (i == 5) {" 12263 " m = 'len';" 12264 " saved_result = result;" 12265 " };" 12266 " result = o[m]('239');" 12267 "}"); 12268 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); 12269 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 12270 } 12271 12272 12273 // Test the map transition before the interceptor. 12274 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { 12275 v8::HandleScope scope(CcTest::isolate()); 12276 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 12277 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12278 LocalContext context; 12279 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); 12280 12281 CompileRun( 12282 "var o = new Object();" 12283 "o.__proto__ = proto;" 12284 "o.method = function(x) { return x + 1; };" 12285 "var m = 'method';" 12286 "var result = 0;" 12287 "for (var i = 0; i < 10; i++) {" 12288 " if (i == 5) { o.method = function(x) { return x - 1; }; };" 12289 " result += o[m](41);" 12290 "}"); 12291 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12292 } 12293 12294 12295 // Test the map transition after the interceptor. 12296 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { 12297 v8::HandleScope scope(CcTest::isolate()); 12298 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 12299 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 12300 LocalContext context; 12301 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 12302 12303 CompileRun( 12304 "var proto = new Object();" 12305 "o.__proto__ = proto;" 12306 "proto.method = function(x) { return x + 1; };" 12307 "var m = 'method';" 12308 "var result = 0;" 12309 "for (var i = 0; i < 10; i++) {" 12310 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" 12311 " result += o[m](41);" 12312 "}"); 12313 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 12314 } 12315 12316 12317 static int interceptor_call_count = 0; 12318 12319 static void InterceptorICRefErrorGetter( 12320 Local<String> name, 12321 const v8::PropertyCallbackInfo<v8::Value>& info) { 12322 ApiTestFuzzer::Fuzz(); 12323 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { 12324 info.GetReturnValue().Set(call_ic_function2); 12325 } 12326 } 12327 12328 12329 // This test should hit load and call ICs for the interceptor case. 12330 // Once in a while, the interceptor will reply that a property was not 12331 // found in which case we should get a reference error. 12332 THREADED_TEST(InterceptorICReferenceErrors) { 12333 v8::HandleScope scope(CcTest::isolate()); 12334 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12335 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter); 12336 LocalContext context(0, templ, v8::Handle<Value>()); 12337 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); 12338 v8::Handle<Value> value = CompileRun( 12339 "function f() {" 12340 " for (var i = 0; i < 1000; i++) {" 12341 " try { x; } catch(e) { return true; }" 12342 " }" 12343 " return false;" 12344 "};" 12345 "f();"); 12346 CHECK_EQ(true, value->BooleanValue()); 12347 interceptor_call_count = 0; 12348 value = CompileRun( 12349 "function g() {" 12350 " for (var i = 0; i < 1000; i++) {" 12351 " try { x(42); } catch(e) { return true; }" 12352 " }" 12353 " return false;" 12354 "};" 12355 "g();"); 12356 CHECK_EQ(true, value->BooleanValue()); 12357 } 12358 12359 12360 static int interceptor_ic_exception_get_count = 0; 12361 12362 static void InterceptorICExceptionGetter( 12363 Local<String> name, 12364 const v8::PropertyCallbackInfo<v8::Value>& info) { 12365 ApiTestFuzzer::Fuzz(); 12366 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { 12367 info.GetReturnValue().Set(call_ic_function3); 12368 } 12369 if (interceptor_ic_exception_get_count == 20) { 12370 info.GetIsolate()->ThrowException(v8_num(42)); 12371 return; 12372 } 12373 } 12374 12375 12376 // Test interceptor load/call IC where the interceptor throws an 12377 // exception once in a while. 12378 THREADED_TEST(InterceptorICGetterExceptions) { 12379 interceptor_ic_exception_get_count = 0; 12380 v8::HandleScope scope(CcTest::isolate()); 12381 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12382 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter); 12383 LocalContext context(0, templ, v8::Handle<Value>()); 12384 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); 12385 v8::Handle<Value> value = CompileRun( 12386 "function f() {" 12387 " for (var i = 0; i < 100; i++) {" 12388 " try { x; } catch(e) { return true; }" 12389 " }" 12390 " return false;" 12391 "};" 12392 "f();"); 12393 CHECK_EQ(true, value->BooleanValue()); 12394 interceptor_ic_exception_get_count = 0; 12395 value = CompileRun( 12396 "function f() {" 12397 " for (var i = 0; i < 100; i++) {" 12398 " try { x(42); } catch(e) { return true; }" 12399 " }" 12400 " return false;" 12401 "};" 12402 "f();"); 12403 CHECK_EQ(true, value->BooleanValue()); 12404 } 12405 12406 12407 static int interceptor_ic_exception_set_count = 0; 12408 12409 static void InterceptorICExceptionSetter( 12410 Local<String> key, 12411 Local<Value> value, 12412 const v8::PropertyCallbackInfo<v8::Value>& info) { 12413 ApiTestFuzzer::Fuzz(); 12414 if (++interceptor_ic_exception_set_count > 20) { 12415 info.GetIsolate()->ThrowException(v8_num(42)); 12416 } 12417 } 12418 12419 12420 // Test interceptor store IC where the interceptor throws an exception 12421 // once in a while. 12422 THREADED_TEST(InterceptorICSetterExceptions) { 12423 interceptor_ic_exception_set_count = 0; 12424 v8::HandleScope scope(CcTest::isolate()); 12425 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12426 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter); 12427 LocalContext context(0, templ, v8::Handle<Value>()); 12428 v8::Handle<Value> value = CompileRun( 12429 "function f() {" 12430 " for (var i = 0; i < 100; i++) {" 12431 " try { x = 42; } catch(e) { return true; }" 12432 " }" 12433 " return false;" 12434 "};" 12435 "f();"); 12436 CHECK_EQ(true, value->BooleanValue()); 12437 } 12438 12439 12440 // Test that we ignore null interceptors. 12441 THREADED_TEST(NullNamedInterceptor) { 12442 v8::HandleScope scope(CcTest::isolate()); 12443 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12444 templ->SetNamedPropertyHandler( 12445 static_cast<v8::NamedPropertyGetterCallback>(0)); 12446 LocalContext context; 12447 templ->Set(CcTest::isolate(), "x", v8_num(42)); 12448 v8::Handle<v8::Object> obj = templ->NewInstance(); 12449 context->Global()->Set(v8_str("obj"), obj); 12450 v8::Handle<Value> value = CompileRun("obj.x"); 12451 CHECK(value->IsInt32()); 12452 CHECK_EQ(42, value->Int32Value()); 12453 } 12454 12455 12456 // Test that we ignore null interceptors. 12457 THREADED_TEST(NullIndexedInterceptor) { 12458 v8::HandleScope scope(CcTest::isolate()); 12459 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 12460 templ->SetIndexedPropertyHandler( 12461 static_cast<v8::IndexedPropertyGetterCallback>(0)); 12462 LocalContext context; 12463 templ->Set(CcTest::isolate(), "42", v8_num(42)); 12464 v8::Handle<v8::Object> obj = templ->NewInstance(); 12465 context->Global()->Set(v8_str("obj"), obj); 12466 v8::Handle<Value> value = CompileRun("obj[42]"); 12467 CHECK(value->IsInt32()); 12468 CHECK_EQ(42, value->Int32Value()); 12469 } 12470 12471 12472 THREADED_TEST(NamedPropertyHandlerGetterAttributes) { 12473 v8::HandleScope scope(CcTest::isolate()); 12474 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 12475 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter); 12476 LocalContext env; 12477 env->Global()->Set(v8_str("obj"), 12478 templ->GetFunction()->NewInstance()); 12479 ExpectTrue("obj.x === 42"); 12480 ExpectTrue("!obj.propertyIsEnumerable('x')"); 12481 } 12482 12483 12484 static void ThrowingGetter(Local<String> name, 12485 const v8::PropertyCallbackInfo<v8::Value>& info) { 12486 ApiTestFuzzer::Fuzz(); 12487 info.GetIsolate()->ThrowException(Handle<Value>()); 12488 info.GetReturnValue().SetUndefined(); 12489 } 12490 12491 12492 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 12493 LocalContext context; 12494 HandleScope scope(context->GetIsolate()); 12495 12496 Local<FunctionTemplate> templ = FunctionTemplate::New(); 12497 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 12498 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 12499 12500 Local<Object> instance = templ->GetFunction()->NewInstance(); 12501 12502 Local<Object> another = Object::New(); 12503 another->SetPrototype(instance); 12504 12505 Local<Object> with_js_getter = CompileRun( 12506 "o = {};\n" 12507 "o.__defineGetter__('f', function() { throw undefined; });\n" 12508 "o\n").As<Object>(); 12509 CHECK(!with_js_getter.IsEmpty()); 12510 12511 TryCatch try_catch; 12512 12513 Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); 12514 CHECK(try_catch.HasCaught()); 12515 try_catch.Reset(); 12516 CHECK(result.IsEmpty()); 12517 12518 result = another->GetRealNamedProperty(v8_str("f")); 12519 CHECK(try_catch.HasCaught()); 12520 try_catch.Reset(); 12521 CHECK(result.IsEmpty()); 12522 12523 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); 12524 CHECK(try_catch.HasCaught()); 12525 try_catch.Reset(); 12526 CHECK(result.IsEmpty()); 12527 12528 result = another->Get(v8_str("f")); 12529 CHECK(try_catch.HasCaught()); 12530 try_catch.Reset(); 12531 CHECK(result.IsEmpty()); 12532 12533 result = with_js_getter->GetRealNamedProperty(v8_str("f")); 12534 CHECK(try_catch.HasCaught()); 12535 try_catch.Reset(); 12536 CHECK(result.IsEmpty()); 12537 12538 result = with_js_getter->Get(v8_str("f")); 12539 CHECK(try_catch.HasCaught()); 12540 try_catch.Reset(); 12541 CHECK(result.IsEmpty()); 12542 } 12543 12544 12545 static void ThrowingCallbackWithTryCatch( 12546 const v8::FunctionCallbackInfo<v8::Value>& args) { 12547 TryCatch try_catch; 12548 // Verboseness is important: it triggers message delivery which can call into 12549 // external code. 12550 try_catch.SetVerbose(true); 12551 CompileRun("throw 'from JS';"); 12552 CHECK(try_catch.HasCaught()); 12553 CHECK(!CcTest::i_isolate()->has_pending_exception()); 12554 CHECK(!CcTest::i_isolate()->has_scheduled_exception()); 12555 } 12556 12557 12558 static int call_depth; 12559 12560 12561 static void WithTryCatch(Handle<Message> message, Handle<Value> data) { 12562 TryCatch try_catch; 12563 } 12564 12565 12566 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) { 12567 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 12568 } 12569 12570 12571 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) { 12572 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi")); 12573 } 12574 12575 12576 static void WebKitLike(Handle<Message> message, Handle<Value> data) { 12577 Handle<String> errorMessageString = message->Get(); 12578 CHECK(!errorMessageString.IsEmpty()); 12579 message->GetStackTrace(); 12580 message->GetScriptResourceName(); 12581 } 12582 12583 12584 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 12585 LocalContext context; 12586 HandleScope scope(context->GetIsolate()); 12587 12588 Local<Function> func = 12589 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction(); 12590 context->Global()->Set(v8_str("func"), func); 12591 12592 MessageCallback callbacks[] = 12593 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 12594 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 12595 MessageCallback callback = callbacks[i]; 12596 if (callback != NULL) { 12597 V8::AddMessageListener(callback); 12598 } 12599 // Some small number to control number of times message handler should 12600 // throw an exception. 12601 call_depth = 5; 12602 ExpectFalse( 12603 "var thrown = false;\n" 12604 "try { func(); } catch(e) { thrown = true; }\n" 12605 "thrown\n"); 12606 if (callback != NULL) { 12607 V8::RemoveMessageListeners(callback); 12608 } 12609 } 12610 } 12611 12612 12613 static void ParentGetter(Local<String> name, 12614 const v8::PropertyCallbackInfo<v8::Value>& info) { 12615 ApiTestFuzzer::Fuzz(); 12616 info.GetReturnValue().Set(v8_num(1)); 12617 } 12618 12619 12620 static void ChildGetter(Local<String> name, 12621 const v8::PropertyCallbackInfo<v8::Value>& info) { 12622 ApiTestFuzzer::Fuzz(); 12623 info.GetReturnValue().Set(v8_num(42)); 12624 } 12625 12626 12627 THREADED_TEST(Overriding) { 12628 i::FLAG_es5_readonly = true; 12629 LocalContext context; 12630 v8::HandleScope scope(context->GetIsolate()); 12631 12632 // Parent template. 12633 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(); 12634 Local<ObjectTemplate> parent_instance_templ = 12635 parent_templ->InstanceTemplate(); 12636 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 12637 12638 // Template that inherits from the parent template. 12639 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(); 12640 Local<ObjectTemplate> child_instance_templ = 12641 child_templ->InstanceTemplate(); 12642 child_templ->Inherit(parent_templ); 12643 // Override 'f'. The child version of 'f' should get called for child 12644 // instances. 12645 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 12646 // Add 'g' twice. The 'g' added last should get called for instances. 12647 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 12648 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 12649 12650 // Add 'h' as an accessor to the proto template with ReadOnly attributes 12651 // so 'h' can be shadowed on the instance object. 12652 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 12653 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 12654 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 12655 12656 // Add 'i' as an accessor to the instance template with ReadOnly attributes 12657 // but the attribute does not have effect because it is duplicated with 12658 // NULL setter. 12659 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 12660 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 12661 12662 12663 12664 // Instantiate the child template. 12665 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance(); 12666 12667 // Check that the child function overrides the parent one. 12668 context->Global()->Set(v8_str("o"), instance); 12669 Local<Value> value = v8_compile("o.f")->Run(); 12670 // Check that the 'g' that was added last is hit. 12671 CHECK_EQ(42, value->Int32Value()); 12672 value = v8_compile("o.g")->Run(); 12673 CHECK_EQ(42, value->Int32Value()); 12674 12675 // Check that 'h' cannot be shadowed. 12676 value = v8_compile("o.h = 3; o.h")->Run(); 12677 CHECK_EQ(1, value->Int32Value()); 12678 12679 // Check that 'i' cannot be shadowed or changed. 12680 value = v8_compile("o.i = 3; o.i")->Run(); 12681 CHECK_EQ(42, value->Int32Value()); 12682 } 12683 12684 12685 static void IsConstructHandler( 12686 const v8::FunctionCallbackInfo<v8::Value>& args) { 12687 ApiTestFuzzer::Fuzz(); 12688 args.GetReturnValue().Set(args.IsConstructCall()); 12689 } 12690 12691 12692 THREADED_TEST(IsConstructCall) { 12693 v8::HandleScope scope(CcTest::isolate()); 12694 12695 // Function template with call handler. 12696 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 12697 templ->SetCallHandler(IsConstructHandler); 12698 12699 LocalContext context; 12700 12701 context->Global()->Set(v8_str("f"), templ->GetFunction()); 12702 Local<Value> value = v8_compile("f()")->Run(); 12703 CHECK(!value->BooleanValue()); 12704 value = v8_compile("new f()")->Run(); 12705 CHECK(value->BooleanValue()); 12706 } 12707 12708 12709 THREADED_TEST(ObjectProtoToString) { 12710 v8::HandleScope scope(CcTest::isolate()); 12711 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 12712 templ->SetClassName(v8_str("MyClass")); 12713 12714 LocalContext context; 12715 12716 Local<String> customized_tostring = v8_str("customized toString"); 12717 12718 // Replace Object.prototype.toString 12719 v8_compile("Object.prototype.toString = function() {" 12720 " return 'customized toString';" 12721 "}")->Run(); 12722 12723 // Normal ToString call should call replaced Object.prototype.toString 12724 Local<v8::Object> instance = templ->GetFunction()->NewInstance(); 12725 Local<String> value = instance->ToString(); 12726 CHECK(value->IsString() && value->Equals(customized_tostring)); 12727 12728 // ObjectProtoToString should not call replace toString function. 12729 value = instance->ObjectProtoToString(); 12730 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]"))); 12731 12732 // Check global 12733 value = context->Global()->ObjectProtoToString(); 12734 CHECK(value->IsString() && value->Equals(v8_str("[object global]"))); 12735 12736 // Check ordinary object 12737 Local<Value> object = v8_compile("new Object()")->Run(); 12738 value = object.As<v8::Object>()->ObjectProtoToString(); 12739 CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); 12740 } 12741 12742 12743 THREADED_TEST(ObjectGetConstructorName) { 12744 LocalContext context; 12745 v8::HandleScope scope(context->GetIsolate()); 12746 v8_compile("function Parent() {};" 12747 "function Child() {};" 12748 "Child.prototype = new Parent();" 12749 "var outer = { inner: function() { } };" 12750 "var p = new Parent();" 12751 "var c = new Child();" 12752 "var x = new outer.inner();")->Run(); 12753 12754 Local<v8::Value> p = context->Global()->Get(v8_str("p")); 12755 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals( 12756 v8_str("Parent"))); 12757 12758 Local<v8::Value> c = context->Global()->Get(v8_str("c")); 12759 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals( 12760 v8_str("Child"))); 12761 12762 Local<v8::Value> x = context->Global()->Get(v8_str("x")); 12763 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals( 12764 v8_str("outer.inner"))); 12765 } 12766 12767 12768 bool ApiTestFuzzer::fuzzing_ = false; 12769 i::Semaphore ApiTestFuzzer::all_tests_done_(0); 12770 int ApiTestFuzzer::active_tests_; 12771 int ApiTestFuzzer::tests_being_run_; 12772 int ApiTestFuzzer::current_; 12773 12774 12775 // We are in a callback and want to switch to another thread (if we 12776 // are currently running the thread fuzzing test). 12777 void ApiTestFuzzer::Fuzz() { 12778 if (!fuzzing_) return; 12779 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 12780 test->ContextSwitch(); 12781 } 12782 12783 12784 // Let the next thread go. Since it is also waiting on the V8 lock it may 12785 // not start immediately. 12786 bool ApiTestFuzzer::NextThread() { 12787 int test_position = GetNextTestNumber(); 12788 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 12789 if (test_position == current_) { 12790 if (kLogThreading) 12791 printf("Stay with %s\n", test_name); 12792 return false; 12793 } 12794 if (kLogThreading) { 12795 printf("Switch from %s to %s\n", 12796 test_name, 12797 RegisterThreadedTest::nth(test_position)->name()); 12798 } 12799 current_ = test_position; 12800 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal(); 12801 return true; 12802 } 12803 12804 12805 void ApiTestFuzzer::Run() { 12806 // When it is our turn... 12807 gate_.Wait(); 12808 { 12809 // ... get the V8 lock and start running the test. 12810 v8::Locker locker(CcTest::isolate()); 12811 CallTest(); 12812 } 12813 // This test finished. 12814 active_ = false; 12815 active_tests_--; 12816 // If it was the last then signal that fact. 12817 if (active_tests_ == 0) { 12818 all_tests_done_.Signal(); 12819 } else { 12820 // Otherwise select a new test and start that. 12821 NextThread(); 12822 } 12823 } 12824 12825 12826 static unsigned linear_congruential_generator; 12827 12828 12829 void ApiTestFuzzer::SetUp(PartOfTest part) { 12830 linear_congruential_generator = i::FLAG_testing_prng_seed; 12831 fuzzing_ = true; 12832 int count = RegisterThreadedTest::count(); 12833 int start = count * part / (LAST_PART + 1); 12834 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 12835 active_tests_ = tests_being_run_ = end - start + 1; 12836 for (int i = 0; i < tests_being_run_; i++) { 12837 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 12838 } 12839 for (int i = 0; i < active_tests_; i++) { 12840 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 12841 } 12842 } 12843 12844 12845 static void CallTestNumber(int test_number) { 12846 (RegisterThreadedTest::nth(test_number)->callback())(); 12847 } 12848 12849 12850 void ApiTestFuzzer::RunAllTests() { 12851 // Set off the first test. 12852 current_ = -1; 12853 NextThread(); 12854 // Wait till they are all done. 12855 all_tests_done_.Wait(); 12856 } 12857 12858 12859 int ApiTestFuzzer::GetNextTestNumber() { 12860 int next_test; 12861 do { 12862 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 12863 linear_congruential_generator *= 1664525u; 12864 linear_congruential_generator += 1013904223u; 12865 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 12866 return next_test; 12867 } 12868 12869 12870 void ApiTestFuzzer::ContextSwitch() { 12871 // If the new thread is the same as the current thread there is nothing to do. 12872 if (NextThread()) { 12873 // Now it can start. 12874 v8::Unlocker unlocker(CcTest::isolate()); 12875 // Wait till someone starts us again. 12876 gate_.Wait(); 12877 // And we're off. 12878 } 12879 } 12880 12881 12882 void ApiTestFuzzer::TearDown() { 12883 fuzzing_ = false; 12884 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 12885 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 12886 if (fuzzer != NULL) fuzzer->Join(); 12887 } 12888 } 12889 12890 12891 // Lets not be needlessly self-referential. 12892 TEST(Threading1) { 12893 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 12894 ApiTestFuzzer::RunAllTests(); 12895 ApiTestFuzzer::TearDown(); 12896 } 12897 12898 12899 TEST(Threading2) { 12900 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 12901 ApiTestFuzzer::RunAllTests(); 12902 ApiTestFuzzer::TearDown(); 12903 } 12904 12905 12906 TEST(Threading3) { 12907 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 12908 ApiTestFuzzer::RunAllTests(); 12909 ApiTestFuzzer::TearDown(); 12910 } 12911 12912 12913 TEST(Threading4) { 12914 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 12915 ApiTestFuzzer::RunAllTests(); 12916 ApiTestFuzzer::TearDown(); 12917 } 12918 12919 12920 void ApiTestFuzzer::CallTest() { 12921 v8::Isolate::Scope scope(CcTest::isolate()); 12922 if (kLogThreading) 12923 printf("Start test %d\n", test_number_); 12924 CallTestNumber(test_number_); 12925 if (kLogThreading) 12926 printf("End test %d\n", test_number_); 12927 } 12928 12929 12930 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 12931 v8::Isolate* isolate = args.GetIsolate(); 12932 CHECK(v8::Locker::IsLocked(isolate)); 12933 ApiTestFuzzer::Fuzz(); 12934 v8::Unlocker unlocker(isolate); 12935 const char* code = "throw 7;"; 12936 { 12937 v8::Locker nested_locker(isolate); 12938 v8::HandleScope scope(isolate); 12939 v8::Handle<Value> exception; 12940 { v8::TryCatch try_catch; 12941 v8::Handle<Value> value = CompileRun(code); 12942 CHECK(value.IsEmpty()); 12943 CHECK(try_catch.HasCaught()); 12944 // Make sure to wrap the exception in a new handle because 12945 // the handle returned from the TryCatch is destroyed 12946 // when the TryCatch is destroyed. 12947 exception = Local<Value>::New(isolate, try_catch.Exception()); 12948 } 12949 args.GetIsolate()->ThrowException(exception); 12950 } 12951 } 12952 12953 12954 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 12955 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 12956 ApiTestFuzzer::Fuzz(); 12957 v8::Unlocker unlocker(CcTest::isolate()); 12958 const char* code = "throw 7;"; 12959 { 12960 v8::Locker nested_locker(CcTest::isolate()); 12961 v8::HandleScope scope(args.GetIsolate()); 12962 v8::Handle<Value> value = CompileRun(code); 12963 CHECK(value.IsEmpty()); 12964 args.GetReturnValue().Set(v8_str("foo")); 12965 } 12966 } 12967 12968 12969 // These are locking tests that don't need to be run again 12970 // as part of the locking aggregation tests. 12971 TEST(NestedLockers) { 12972 v8::Locker locker(CcTest::isolate()); 12973 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 12974 LocalContext env; 12975 v8::HandleScope scope(env->GetIsolate()); 12976 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS); 12977 Local<Function> fun = fun_templ->GetFunction(); 12978 env->Global()->Set(v8_str("throw_in_js"), fun); 12979 Local<Script> script = v8_compile("(function () {" 12980 " try {" 12981 " throw_in_js();" 12982 " return 42;" 12983 " } catch (e) {" 12984 " return e * 13;" 12985 " }" 12986 "})();"); 12987 CHECK_EQ(91, script->Run()->Int32Value()); 12988 } 12989 12990 12991 // These are locking tests that don't need to be run again 12992 // as part of the locking aggregation tests. 12993 TEST(NestedLockersNoTryCatch) { 12994 v8::Locker locker(CcTest::isolate()); 12995 LocalContext env; 12996 v8::HandleScope scope(env->GetIsolate()); 12997 Local<v8::FunctionTemplate> fun_templ = 12998 v8::FunctionTemplate::New(ThrowInJSNoCatch); 12999 Local<Function> fun = fun_templ->GetFunction(); 13000 env->Global()->Set(v8_str("throw_in_js"), fun); 13001 Local<Script> script = v8_compile("(function () {" 13002 " try {" 13003 " throw_in_js();" 13004 " return 42;" 13005 " } catch (e) {" 13006 " return e * 13;" 13007 " }" 13008 "})();"); 13009 CHECK_EQ(91, script->Run()->Int32Value()); 13010 } 13011 13012 13013 THREADED_TEST(RecursiveLocking) { 13014 v8::Locker locker(CcTest::isolate()); 13015 { 13016 v8::Locker locker2(CcTest::isolate()); 13017 CHECK(v8::Locker::IsLocked(CcTest::isolate())); 13018 } 13019 } 13020 13021 13022 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 13023 ApiTestFuzzer::Fuzz(); 13024 v8::Unlocker unlocker(CcTest::isolate()); 13025 } 13026 13027 13028 THREADED_TEST(LockUnlockLock) { 13029 { 13030 v8::Locker locker(CcTest::isolate()); 13031 v8::HandleScope scope(CcTest::isolate()); 13032 LocalContext env; 13033 Local<v8::FunctionTemplate> fun_templ = 13034 v8::FunctionTemplate::New(UnlockForAMoment); 13035 Local<Function> fun = fun_templ->GetFunction(); 13036 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13037 Local<Script> script = v8_compile("(function () {" 13038 " unlock_for_a_moment();" 13039 " return 42;" 13040 "})();"); 13041 CHECK_EQ(42, script->Run()->Int32Value()); 13042 } 13043 { 13044 v8::Locker locker(CcTest::isolate()); 13045 v8::HandleScope scope(CcTest::isolate()); 13046 LocalContext env; 13047 Local<v8::FunctionTemplate> fun_templ = 13048 v8::FunctionTemplate::New(UnlockForAMoment); 13049 Local<Function> fun = fun_templ->GetFunction(); 13050 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 13051 Local<Script> script = v8_compile("(function () {" 13052 " unlock_for_a_moment();" 13053 " return 42;" 13054 "})();"); 13055 CHECK_EQ(42, script->Run()->Int32Value()); 13056 } 13057 } 13058 13059 13060 static int GetGlobalObjectsCount() { 13061 CcTest::heap()->EnsureHeapIsIterable(); 13062 int count = 0; 13063 i::HeapIterator it(CcTest::heap()); 13064 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 13065 if (object->IsJSGlobalObject()) count++; 13066 return count; 13067 } 13068 13069 13070 static void CheckSurvivingGlobalObjectsCount(int expected) { 13071 // We need to collect all garbage twice to be sure that everything 13072 // has been collected. This is because inline caches are cleared in 13073 // the first garbage collection but some of the maps have already 13074 // been marked at that point. Therefore some of the maps are not 13075 // collected until the second garbage collection. 13076 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13077 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 13078 int count = GetGlobalObjectsCount(); 13079 #ifdef DEBUG 13080 if (count != expected) CcTest::heap()->TracePathToGlobal(); 13081 #endif 13082 CHECK_EQ(expected, count); 13083 } 13084 13085 13086 TEST(DontLeakGlobalObjects) { 13087 // Regression test for issues 1139850 and 1174891. 13088 13089 v8::V8::Initialize(); 13090 13091 for (int i = 0; i < 5; i++) { 13092 { v8::HandleScope scope(CcTest::isolate()); 13093 LocalContext context; 13094 } 13095 v8::V8::ContextDisposedNotification(); 13096 CheckSurvivingGlobalObjectsCount(0); 13097 13098 { v8::HandleScope scope(CcTest::isolate()); 13099 LocalContext context; 13100 v8_compile("Date")->Run(); 13101 } 13102 v8::V8::ContextDisposedNotification(); 13103 CheckSurvivingGlobalObjectsCount(0); 13104 13105 { v8::HandleScope scope(CcTest::isolate()); 13106 LocalContext context; 13107 v8_compile("/aaa/")->Run(); 13108 } 13109 v8::V8::ContextDisposedNotification(); 13110 CheckSurvivingGlobalObjectsCount(0); 13111 13112 { v8::HandleScope scope(CcTest::isolate()); 13113 const char* extension_list[] = { "v8/gc" }; 13114 v8::ExtensionConfiguration extensions(1, extension_list); 13115 LocalContext context(&extensions); 13116 v8_compile("gc();")->Run(); 13117 } 13118 v8::V8::ContextDisposedNotification(); 13119 CheckSurvivingGlobalObjectsCount(0); 13120 } 13121 } 13122 13123 13124 TEST(CopyablePersistent) { 13125 LocalContext context; 13126 v8::Isolate* isolate = context->GetIsolate(); 13127 i::GlobalHandles* globals = 13128 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13129 int initial_handles = globals->global_handles_count(); 13130 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> > 13131 CopyableObject; 13132 { 13133 CopyableObject handle1; 13134 { 13135 v8::HandleScope scope(isolate); 13136 handle1.Reset(isolate, v8::Object::New()); 13137 } 13138 CHECK_EQ(initial_handles + 1, globals->global_handles_count()); 13139 CopyableObject handle2; 13140 handle2 = handle1; 13141 CHECK(handle1 == handle2); 13142 CHECK_EQ(initial_handles + 2, globals->global_handles_count()); 13143 CopyableObject handle3(handle2); 13144 CHECK(handle1 == handle3); 13145 CHECK_EQ(initial_handles + 3, globals->global_handles_count()); 13146 } 13147 // Verify autodispose 13148 CHECK_EQ(initial_handles, globals->global_handles_count()); 13149 } 13150 13151 13152 static void WeakApiCallback( 13153 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) { 13154 Local<Value> value = data.GetValue()->Get(v8_str("key")); 13155 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value())); 13156 data.GetParameter()->Reset(); 13157 delete data.GetParameter(); 13158 } 13159 13160 13161 TEST(WeakCallbackApi) { 13162 LocalContext context; 13163 v8::Isolate* isolate = context->GetIsolate(); 13164 i::GlobalHandles* globals = 13165 reinterpret_cast<i::Isolate*>(isolate)->global_handles(); 13166 int initial_handles = globals->global_handles_count(); 13167 { 13168 v8::HandleScope scope(isolate); 13169 v8::Local<v8::Object> obj = v8::Object::New(); 13170 obj->Set(v8_str("key"), v8::Integer::New(231, isolate)); 13171 v8::Persistent<v8::Object>* handle = 13172 new v8::Persistent<v8::Object>(isolate, obj); 13173 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle, 13174 WeakApiCallback); 13175 } 13176 reinterpret_cast<i::Isolate*>(isolate)->heap()-> 13177 CollectAllGarbage(i::Heap::kNoGCFlags); 13178 // Verify disposed. 13179 CHECK_EQ(initial_handles, globals->global_handles_count()); 13180 } 13181 13182 13183 v8::Persistent<v8::Object> some_object; 13184 v8::Persistent<v8::Object> bad_handle; 13185 13186 void NewPersistentHandleCallback( 13187 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13188 v8::HandleScope scope(data.GetIsolate()); 13189 bad_handle.Reset(data.GetIsolate(), some_object); 13190 data.GetParameter()->Reset(); 13191 } 13192 13193 13194 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 13195 LocalContext context; 13196 v8::Isolate* isolate = context->GetIsolate(); 13197 13198 v8::Persistent<v8::Object> handle1, handle2; 13199 { 13200 v8::HandleScope scope(isolate); 13201 some_object.Reset(isolate, v8::Object::New()); 13202 handle1.Reset(isolate, v8::Object::New()); 13203 handle2.Reset(isolate, v8::Object::New()); 13204 } 13205 // Note: order is implementation dependent alas: currently 13206 // global handle nodes are processed by PostGarbageCollectionProcessing 13207 // in reverse allocation order, so if second allocated handle is deleted, 13208 // weak callback of the first handle would be able to 'reallocate' it. 13209 handle1.SetWeak(&handle1, NewPersistentHandleCallback); 13210 handle2.Reset(); 13211 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13212 } 13213 13214 13215 v8::Persistent<v8::Object> to_be_disposed; 13216 13217 void DisposeAndForceGcCallback( 13218 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13219 to_be_disposed.Reset(); 13220 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 13221 data.GetParameter()->Reset(); 13222 } 13223 13224 13225 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 13226 LocalContext context; 13227 v8::Isolate* isolate = context->GetIsolate(); 13228 13229 v8::Persistent<v8::Object> handle1, handle2; 13230 { 13231 v8::HandleScope scope(isolate); 13232 handle1.Reset(isolate, v8::Object::New()); 13233 handle2.Reset(isolate, v8::Object::New()); 13234 } 13235 handle1.SetWeak(&handle1, DisposeAndForceGcCallback); 13236 to_be_disposed.Reset(isolate, handle2); 13237 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13238 } 13239 13240 void DisposingCallback( 13241 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13242 data.GetParameter()->Reset(); 13243 } 13244 13245 void HandleCreatingCallback( 13246 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { 13247 v8::HandleScope scope(data.GetIsolate()); 13248 v8::Persistent<v8::Object>(data.GetIsolate(), v8::Object::New()); 13249 data.GetParameter()->Reset(); 13250 } 13251 13252 13253 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 13254 LocalContext context; 13255 v8::Isolate* isolate = context->GetIsolate(); 13256 13257 v8::Persistent<v8::Object> handle1, handle2, handle3; 13258 { 13259 v8::HandleScope scope(isolate); 13260 handle3.Reset(isolate, v8::Object::New()); 13261 handle2.Reset(isolate, v8::Object::New()); 13262 handle1.Reset(isolate, v8::Object::New()); 13263 } 13264 handle2.SetWeak(&handle2, DisposingCallback); 13265 handle3.SetWeak(&handle3, HandleCreatingCallback); 13266 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 13267 } 13268 13269 13270 THREADED_TEST(CheckForCrossContextObjectLiterals) { 13271 v8::V8::Initialize(); 13272 13273 const int nof = 2; 13274 const char* sources[nof] = { 13275 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 13276 "Object()" 13277 }; 13278 13279 for (int i = 0; i < nof; i++) { 13280 const char* source = sources[i]; 13281 { v8::HandleScope scope(CcTest::isolate()); 13282 LocalContext context; 13283 CompileRun(source); 13284 } 13285 { v8::HandleScope scope(CcTest::isolate()); 13286 LocalContext context; 13287 CompileRun(source); 13288 } 13289 } 13290 } 13291 13292 13293 static v8::Handle<Value> NestedScope(v8::Local<Context> env) { 13294 v8::HandleScope inner(env->GetIsolate()); 13295 env->Enter(); 13296 v8::Handle<Value> three = v8_num(3); 13297 v8::Handle<Value> value = inner.Close(three); 13298 env->Exit(); 13299 return value; 13300 } 13301 13302 13303 THREADED_TEST(NestedHandleScopeAndContexts) { 13304 v8::Isolate* isolate = CcTest::isolate(); 13305 v8::HandleScope outer(isolate); 13306 v8::Local<Context> env = Context::New(isolate); 13307 env->Enter(); 13308 v8::Handle<Value> value = NestedScope(env); 13309 v8::Handle<String> str(value->ToString()); 13310 CHECK(!str.IsEmpty()); 13311 env->Exit(); 13312 } 13313 13314 13315 static bool MatchPointers(void* key1, void* key2) { 13316 return key1 == key2; 13317 } 13318 13319 13320 struct SymbolInfo { 13321 size_t id; 13322 size_t size; 13323 std::string name; 13324 }; 13325 13326 13327 class SetFunctionEntryHookTest { 13328 public: 13329 SetFunctionEntryHookTest() { 13330 CHECK(instance_ == NULL); 13331 instance_ = this; 13332 } 13333 ~SetFunctionEntryHookTest() { 13334 CHECK(instance_ == this); 13335 instance_ = NULL; 13336 } 13337 void Reset() { 13338 symbols_.clear(); 13339 symbol_locations_.clear(); 13340 invocations_.clear(); 13341 } 13342 void RunTest(); 13343 void OnJitEvent(const v8::JitCodeEvent* event); 13344 static void JitEvent(const v8::JitCodeEvent* event) { 13345 CHECK(instance_ != NULL); 13346 instance_->OnJitEvent(event); 13347 } 13348 13349 void OnEntryHook(uintptr_t function, 13350 uintptr_t return_addr_location); 13351 static void EntryHook(uintptr_t function, 13352 uintptr_t return_addr_location) { 13353 CHECK(instance_ != NULL); 13354 instance_->OnEntryHook(function, return_addr_location); 13355 } 13356 13357 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 13358 CHECK(instance_ != NULL); 13359 args.GetReturnValue().Set(v8_num(42)); 13360 } 13361 void RunLoopInNewEnv(v8::Isolate* isolate); 13362 13363 // Records addr as location of symbol. 13364 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 13365 13366 // Finds the symbol containing addr 13367 SymbolInfo* FindSymbolForAddr(i::Address addr); 13368 // Returns the number of invocations where the caller name contains 13369 // \p caller_name and the function name contains \p function_name. 13370 int CountInvocations(const char* caller_name, 13371 const char* function_name); 13372 13373 i::Handle<i::JSFunction> foo_func_; 13374 i::Handle<i::JSFunction> bar_func_; 13375 13376 typedef std::map<size_t, SymbolInfo> SymbolMap; 13377 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 13378 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 13379 SymbolMap symbols_; 13380 SymbolLocationMap symbol_locations_; 13381 InvocationMap invocations_; 13382 13383 static SetFunctionEntryHookTest* instance_; 13384 }; 13385 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 13386 13387 13388 // Returns true if addr is in the range [start, start+len). 13389 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 13390 if (start <= addr && start + len > addr) 13391 return true; 13392 13393 return false; 13394 } 13395 13396 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 13397 SymbolInfo* symbol) { 13398 // Insert the symbol at the new location. 13399 SymbolLocationMap::iterator it = 13400 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 13401 // Now erase symbols to the left and right that overlap this one. 13402 while (it != symbol_locations_.begin()) { 13403 SymbolLocationMap::iterator left = it; 13404 --left; 13405 if (!Overlaps(left->first, left->second->size, addr)) 13406 break; 13407 symbol_locations_.erase(left); 13408 } 13409 13410 // Now erase symbols to the left and right that overlap this one. 13411 while (true) { 13412 SymbolLocationMap::iterator right = it; 13413 ++right; 13414 if (right == symbol_locations_.end()) 13415 break; 13416 if (!Overlaps(addr, symbol->size, right->first)) 13417 break; 13418 symbol_locations_.erase(right); 13419 } 13420 } 13421 13422 13423 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 13424 switch (event->type) { 13425 case v8::JitCodeEvent::CODE_ADDED: { 13426 CHECK(event->code_start != NULL); 13427 CHECK_NE(0, static_cast<int>(event->code_len)); 13428 CHECK(event->name.str != NULL); 13429 size_t symbol_id = symbols_.size(); 13430 13431 // Record the new symbol. 13432 SymbolInfo& info = symbols_[symbol_id]; 13433 info.id = symbol_id; 13434 info.size = event->code_len; 13435 info.name.assign(event->name.str, event->name.str + event->name.len); 13436 13437 // And record it's location. 13438 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 13439 } 13440 break; 13441 13442 case v8::JitCodeEvent::CODE_MOVED: { 13443 // We would like to never see code move that we haven't seen before, 13444 // but the code creation event does not happen until the line endings 13445 // have been calculated (this is so that we can report the line in the 13446 // script at which the function source is found, see 13447 // Compiler::RecordFunctionCompilation) and the line endings 13448 // calculations can cause a GC, which can move the newly created code 13449 // before its existence can be logged. 13450 SymbolLocationMap::iterator it( 13451 symbol_locations_.find( 13452 reinterpret_cast<i::Address>(event->code_start))); 13453 if (it != symbol_locations_.end()) { 13454 // Found a symbol at this location, move it. 13455 SymbolInfo* info = it->second; 13456 symbol_locations_.erase(it); 13457 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 13458 info); 13459 } 13460 } 13461 default: 13462 break; 13463 } 13464 } 13465 13466 void SetFunctionEntryHookTest::OnEntryHook( 13467 uintptr_t function, uintptr_t return_addr_location) { 13468 // Get the function's code object. 13469 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 13470 reinterpret_cast<i::Address>(function)); 13471 CHECK(function_code != NULL); 13472 13473 // Then try and look up the caller's code object. 13474 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 13475 13476 // Count the invocation. 13477 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 13478 SymbolInfo* function_symbol = 13479 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 13480 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 13481 13482 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 13483 // Check that we have a symbol for the "bar" function at the right location. 13484 SymbolLocationMap::iterator it( 13485 symbol_locations_.find(function_code->instruction_start())); 13486 CHECK(it != symbol_locations_.end()); 13487 } 13488 13489 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 13490 // Check that we have a symbol for "foo" at the right location. 13491 SymbolLocationMap::iterator it( 13492 symbol_locations_.find(function_code->instruction_start())); 13493 CHECK(it != symbol_locations_.end()); 13494 } 13495 } 13496 13497 13498 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 13499 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 13500 // Do we have a direct hit on a symbol? 13501 if (it != symbol_locations_.end()) { 13502 if (it->first == addr) 13503 return it->second; 13504 } 13505 13506 // If not a direct hit, it'll have to be the previous symbol. 13507 if (it == symbol_locations_.begin()) 13508 return NULL; 13509 13510 --it; 13511 size_t offs = addr - it->first; 13512 if (offs < it->second->size) 13513 return it->second; 13514 13515 return NULL; 13516 } 13517 13518 13519 int SetFunctionEntryHookTest::CountInvocations( 13520 const char* caller_name, const char* function_name) { 13521 InvocationMap::iterator it(invocations_.begin()); 13522 int invocations = 0; 13523 for (; it != invocations_.end(); ++it) { 13524 SymbolInfo* caller = it->first.first; 13525 SymbolInfo* function = it->first.second; 13526 13527 // Filter out non-matching functions. 13528 if (function_name != NULL) { 13529 if (function->name.find(function_name) == std::string::npos) 13530 continue; 13531 } 13532 13533 // Filter out non-matching callers. 13534 if (caller_name != NULL) { 13535 if (caller == NULL) 13536 continue; 13537 if (caller->name.find(caller_name) == std::string::npos) 13538 continue; 13539 } 13540 13541 // It matches add the invocation count to the tally. 13542 invocations += it->second; 13543 } 13544 13545 return invocations; 13546 } 13547 13548 13549 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 13550 v8::HandleScope outer(isolate); 13551 v8::Local<Context> env = Context::New(isolate); 13552 env->Enter(); 13553 13554 Local<ObjectTemplate> t = ObjectTemplate::New(); 13555 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback)); 13556 env->Global()->Set(v8_str("obj"), t->NewInstance()); 13557 13558 const char* script = 13559 "function bar() {\n" 13560 " var sum = 0;\n" 13561 " for (i = 0; i < 100; ++i)\n" 13562 " sum = foo(i);\n" 13563 " return sum;\n" 13564 "}\n" 13565 "function foo(i) { return i * i; }\n" 13566 "// Invoke on the runtime function.\n" 13567 "obj.asdf()"; 13568 CompileRun(script); 13569 bar_func_ = i::Handle<i::JSFunction>::cast( 13570 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar")))); 13571 ASSERT(!bar_func_.is_null()); 13572 13573 foo_func_ = 13574 i::Handle<i::JSFunction>::cast( 13575 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo")))); 13576 ASSERT(!foo_func_.is_null()); 13577 13578 v8::Handle<v8::Value> value = CompileRun("bar();"); 13579 CHECK(value->IsNumber()); 13580 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 13581 13582 // Test the optimized codegen path. 13583 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 13584 "bar();"); 13585 CHECK(value->IsNumber()); 13586 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 13587 13588 env->Exit(); 13589 } 13590 13591 13592 void SetFunctionEntryHookTest::RunTest() { 13593 // Work in a new isolate throughout. 13594 v8::Isolate* isolate = v8::Isolate::New(); 13595 13596 // Test setting the entry hook on the new isolate. 13597 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 13598 13599 // Replacing the hook, once set should fail. 13600 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 13601 13602 { 13603 v8::Isolate::Scope scope(isolate); 13604 13605 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent); 13606 13607 RunLoopInNewEnv(isolate); 13608 13609 // Check the exepected invocation counts. 13610 CHECK_EQ(2, CountInvocations(NULL, "bar")); 13611 CHECK_EQ(200, CountInvocations("bar", "foo")); 13612 CHECK_EQ(200, CountInvocations(NULL, "foo")); 13613 13614 // Verify that we have an entry hook on some specific stubs. 13615 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 13616 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 13617 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 13618 } 13619 isolate->Dispose(); 13620 13621 Reset(); 13622 13623 // Make sure a second isolate is unaffected by the previous entry hook. 13624 isolate = v8::Isolate::New(); 13625 { 13626 v8::Isolate::Scope scope(isolate); 13627 13628 // Reset the entry count to zero and set the entry hook. 13629 RunLoopInNewEnv(isolate); 13630 13631 // We should record no invocations in this isolate. 13632 CHECK_EQ(0, static_cast<int>(invocations_.size())); 13633 } 13634 // Since the isolate has been used, we shouldn't be able to set an entry 13635 // hook anymore. 13636 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 13637 13638 isolate->Dispose(); 13639 } 13640 13641 13642 TEST(SetFunctionEntryHook) { 13643 // FunctionEntryHook does not work well with experimental natives. 13644 // Experimental natives are compiled during snapshot deserialization. 13645 // This test breaks because InstallGetter (function from snapshot that 13646 // only gets called from experimental natives) is compiled with entry hooks. 13647 i::FLAG_allow_natives_syntax = true; 13648 i::FLAG_use_inlining = false; 13649 13650 SetFunctionEntryHookTest test; 13651 test.RunTest(); 13652 } 13653 13654 13655 static i::HashMap* code_map = NULL; 13656 static i::HashMap* jitcode_line_info = NULL; 13657 static int saw_bar = 0; 13658 static int move_events = 0; 13659 13660 13661 static bool FunctionNameIs(const char* expected, 13662 const v8::JitCodeEvent* event) { 13663 // Log lines for functions are of the general form: 13664 // "LazyCompile:<type><function_name>", where the type is one of 13665 // "*", "~" or "". 13666 static const char kPreamble[] = "LazyCompile:"; 13667 static size_t kPreambleLen = sizeof(kPreamble) - 1; 13668 13669 if (event->name.len < sizeof(kPreamble) - 1 || 13670 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 13671 return false; 13672 } 13673 13674 const char* tail = event->name.str + kPreambleLen; 13675 size_t tail_len = event->name.len - kPreambleLen; 13676 size_t expected_len = strlen(expected); 13677 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 13678 --tail_len; 13679 ++tail; 13680 } 13681 13682 // Check for tails like 'bar :1'. 13683 if (tail_len > expected_len + 2 && 13684 tail[expected_len] == ' ' && 13685 tail[expected_len + 1] == ':' && 13686 tail[expected_len + 2] && 13687 !strncmp(tail, expected, expected_len)) { 13688 return true; 13689 } 13690 13691 if (tail_len != expected_len) 13692 return false; 13693 13694 return strncmp(tail, expected, expected_len) == 0; 13695 } 13696 13697 13698 static void event_handler(const v8::JitCodeEvent* event) { 13699 CHECK(event != NULL); 13700 CHECK(code_map != NULL); 13701 CHECK(jitcode_line_info != NULL); 13702 13703 class DummyJitCodeLineInfo { 13704 }; 13705 13706 switch (event->type) { 13707 case v8::JitCodeEvent::CODE_ADDED: { 13708 CHECK(event->code_start != NULL); 13709 CHECK_NE(0, static_cast<int>(event->code_len)); 13710 CHECK(event->name.str != NULL); 13711 i::HashMap::Entry* entry = 13712 code_map->Lookup(event->code_start, 13713 i::ComputePointerHash(event->code_start), 13714 true); 13715 entry->value = reinterpret_cast<void*>(event->code_len); 13716 13717 if (FunctionNameIs("bar", event)) { 13718 ++saw_bar; 13719 } 13720 } 13721 break; 13722 13723 case v8::JitCodeEvent::CODE_MOVED: { 13724 uint32_t hash = i::ComputePointerHash(event->code_start); 13725 // We would like to never see code move that we haven't seen before, 13726 // but the code creation event does not happen until the line endings 13727 // have been calculated (this is so that we can report the line in the 13728 // script at which the function source is found, see 13729 // Compiler::RecordFunctionCompilation) and the line endings 13730 // calculations can cause a GC, which can move the newly created code 13731 // before its existence can be logged. 13732 i::HashMap::Entry* entry = 13733 code_map->Lookup(event->code_start, hash, false); 13734 if (entry != NULL) { 13735 ++move_events; 13736 13737 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 13738 code_map->Remove(event->code_start, hash); 13739 13740 entry = code_map->Lookup(event->new_code_start, 13741 i::ComputePointerHash(event->new_code_start), 13742 true); 13743 CHECK(entry != NULL); 13744 entry->value = reinterpret_cast<void*>(event->code_len); 13745 } 13746 } 13747 break; 13748 13749 case v8::JitCodeEvent::CODE_REMOVED: 13750 // Object/code removal events are currently not dispatched from the GC. 13751 CHECK(false); 13752 break; 13753 13754 // For CODE_START_LINE_INFO_RECORDING event, we will create one 13755 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 13756 // record it in jitcode_line_info. 13757 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 13758 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 13759 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 13760 temp_event->user_data = line_info; 13761 i::HashMap::Entry* entry = 13762 jitcode_line_info->Lookup(line_info, 13763 i::ComputePointerHash(line_info), 13764 true); 13765 entry->value = reinterpret_cast<void*>(line_info); 13766 } 13767 break; 13768 // For these two events, we will check whether the event->user_data 13769 // data structure is created before during CODE_START_LINE_INFO_RECORDING 13770 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 13771 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 13772 CHECK(event->user_data != NULL); 13773 uint32_t hash = i::ComputePointerHash(event->user_data); 13774 i::HashMap::Entry* entry = 13775 jitcode_line_info->Lookup(event->user_data, hash, false); 13776 CHECK(entry != NULL); 13777 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 13778 } 13779 break; 13780 13781 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 13782 CHECK(event->user_data != NULL); 13783 uint32_t hash = i::ComputePointerHash(event->user_data); 13784 i::HashMap::Entry* entry = 13785 jitcode_line_info->Lookup(event->user_data, hash, false); 13786 CHECK(entry != NULL); 13787 } 13788 break; 13789 13790 default: 13791 // Impossible event. 13792 CHECK(false); 13793 break; 13794 } 13795 } 13796 13797 13798 UNINITIALIZED_TEST(SetJitCodeEventHandler) { 13799 i::FLAG_stress_compaction = true; 13800 i::FLAG_incremental_marking = false; 13801 const char* script = 13802 "function bar() {" 13803 " var sum = 0;" 13804 " for (i = 0; i < 100; ++i)" 13805 " sum = foo(i);" 13806 " return sum;" 13807 "}" 13808 "function foo(i) { return i * i; };" 13809 "bar();"; 13810 13811 // Run this test in a new isolate to make sure we don't 13812 // have remnants of state from other code. 13813 v8::Isolate* isolate = v8::Isolate::New(); 13814 isolate->Enter(); 13815 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap(); 13816 13817 { 13818 v8::HandleScope scope(isolate); 13819 i::HashMap code(MatchPointers); 13820 code_map = &code; 13821 13822 i::HashMap lineinfo(MatchPointers); 13823 jitcode_line_info = &lineinfo; 13824 13825 saw_bar = 0; 13826 move_events = 0; 13827 13828 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 13829 13830 // Generate new code objects sparsely distributed across several 13831 // different fragmented code-space pages. 13832 const int kIterations = 10; 13833 for (int i = 0; i < kIterations; ++i) { 13834 LocalContext env(isolate); 13835 i::AlwaysAllocateScope always_allocate; 13836 SimulateFullSpace(heap->code_space()); 13837 CompileRun(script); 13838 13839 // Keep a strong reference to the code object in the handle scope. 13840 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast( 13841 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code()); 13842 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast( 13843 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code()); 13844 13845 // Clear the compilation cache to get more wastage. 13846 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear(); 13847 } 13848 13849 // Force code movement. 13850 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler"); 13851 13852 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 13853 13854 CHECK_LE(kIterations, saw_bar); 13855 CHECK_LT(0, move_events); 13856 13857 code_map = NULL; 13858 jitcode_line_info = NULL; 13859 } 13860 13861 isolate->Exit(); 13862 isolate->Dispose(); 13863 13864 // Do this in a new isolate. 13865 isolate = v8::Isolate::New(); 13866 isolate->Enter(); 13867 13868 // Verify that we get callbacks for existing code objects when we 13869 // request enumeration of existing code. 13870 { 13871 v8::HandleScope scope(isolate); 13872 LocalContext env(isolate); 13873 CompileRun(script); 13874 13875 // Now get code through initial iteration. 13876 i::HashMap code(MatchPointers); 13877 code_map = &code; 13878 13879 i::HashMap lineinfo(MatchPointers); 13880 jitcode_line_info = &lineinfo; 13881 13882 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler); 13883 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 13884 13885 jitcode_line_info = NULL; 13886 // We expect that we got some events. Note that if we could get code removal 13887 // notifications, we could compare two collections, one created by listening 13888 // from the time of creation of an isolate, and the other by subscribing 13889 // with EnumExisting. 13890 CHECK_LT(0, code.occupancy()); 13891 13892 code_map = NULL; 13893 } 13894 13895 isolate->Exit(); 13896 isolate->Dispose(); 13897 } 13898 13899 13900 THREADED_TEST(ExternalAllocatedMemory) { 13901 v8::Isolate* isolate = CcTest::isolate(); 13902 v8::HandleScope outer(isolate); 13903 v8::Local<Context> env(Context::New(isolate)); 13904 CHECK(!env.IsEmpty()); 13905 const int64_t kSize = 1024*1024; 13906 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0); 13907 CHECK_EQ(baseline + kSize, 13908 isolate->AdjustAmountOfExternalAllocatedMemory(kSize)); 13909 CHECK_EQ(baseline, 13910 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)); 13911 } 13912 13913 13914 // Regression test for issue 54, object templates with internal fields 13915 // but no accessors or interceptors did not get their internal field 13916 // count set on instances. 13917 THREADED_TEST(Regress54) { 13918 LocalContext context; 13919 v8::Isolate* isolate = context->GetIsolate(); 13920 v8::HandleScope outer(isolate); 13921 static v8::Persistent<v8::ObjectTemplate> templ; 13922 if (templ.IsEmpty()) { 13923 v8::HandleScope inner(isolate); 13924 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New(); 13925 local->SetInternalFieldCount(1); 13926 templ.Reset(isolate, inner.Close(local)); 13927 } 13928 v8::Handle<v8::Object> result = 13929 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance(); 13930 CHECK_EQ(1, result->InternalFieldCount()); 13931 } 13932 13933 13934 // If part of the threaded tests, this test makes ThreadingTest fail 13935 // on mac. 13936 TEST(CatchStackOverflow) { 13937 LocalContext context; 13938 v8::HandleScope scope(context->GetIsolate()); 13939 v8::TryCatch try_catch; 13940 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8( 13941 context->GetIsolate(), 13942 "function f() {" 13943 " return f();" 13944 "}" 13945 "" 13946 "f();")); 13947 v8::Handle<v8::Value> result = script->Run(); 13948 CHECK(result.IsEmpty()); 13949 } 13950 13951 13952 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, 13953 const char* resource_name, 13954 int line_offset) { 13955 v8::HandleScope scope(CcTest::isolate()); 13956 v8::TryCatch try_catch; 13957 v8::Handle<v8::Value> result = script->Run(); 13958 CHECK(result.IsEmpty()); 13959 CHECK(try_catch.HasCaught()); 13960 v8::Handle<v8::Message> message = try_catch.Message(); 13961 CHECK(!message.IsEmpty()); 13962 CHECK_EQ(10 + line_offset, message->GetLineNumber()); 13963 CHECK_EQ(91, message->GetStartPosition()); 13964 CHECK_EQ(92, message->GetEndPosition()); 13965 CHECK_EQ(2, message->GetStartColumn()); 13966 CHECK_EQ(3, message->GetEndColumn()); 13967 v8::String::Utf8Value line(message->GetSourceLine()); 13968 CHECK_EQ(" throw 'nirk';", *line); 13969 v8::String::Utf8Value name(message->GetScriptResourceName()); 13970 CHECK_EQ(resource_name, *name); 13971 } 13972 13973 13974 THREADED_TEST(TryCatchSourceInfo) { 13975 LocalContext context; 13976 v8::HandleScope scope(context->GetIsolate()); 13977 v8::Handle<v8::String> source = v8::String::NewFromUtf8( 13978 context->GetIsolate(), 13979 "function Foo() {\n" 13980 " return Bar();\n" 13981 "}\n" 13982 "\n" 13983 "function Bar() {\n" 13984 " return Baz();\n" 13985 "}\n" 13986 "\n" 13987 "function Baz() {\n" 13988 " throw 'nirk';\n" 13989 "}\n" 13990 "\n" 13991 "Foo();\n"); 13992 13993 const char* resource_name; 13994 v8::Handle<v8::Script> script; 13995 resource_name = "test.js"; 13996 script = v8::Script::Compile( 13997 source, v8::String::NewFromUtf8(context->GetIsolate(), resource_name)); 13998 CheckTryCatchSourceInfo(script, resource_name, 0); 13999 14000 resource_name = "test1.js"; 14001 v8::ScriptOrigin origin1( 14002 v8::String::NewFromUtf8(context->GetIsolate(), resource_name)); 14003 script = v8::Script::Compile(source, &origin1); 14004 CheckTryCatchSourceInfo(script, resource_name, 0); 14005 14006 resource_name = "test2.js"; 14007 v8::ScriptOrigin origin2( 14008 v8::String::NewFromUtf8(context->GetIsolate(), resource_name), 14009 v8::Integer::New(7)); 14010 script = v8::Script::Compile(source, &origin2); 14011 CheckTryCatchSourceInfo(script, resource_name, 7); 14012 } 14013 14014 14015 THREADED_TEST(CompilationCache) { 14016 LocalContext context; 14017 v8::HandleScope scope(context->GetIsolate()); 14018 v8::Handle<v8::String> source0 = 14019 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14020 v8::Handle<v8::String> source1 = 14021 v8::String::NewFromUtf8(context->GetIsolate(), "1234"); 14022 v8::Handle<v8::Script> script0 = v8::Script::Compile( 14023 source0, v8::String::NewFromUtf8(context->GetIsolate(), "test.js")); 14024 v8::Handle<v8::Script> script1 = v8::Script::Compile( 14025 source1, v8::String::NewFromUtf8(context->GetIsolate(), "test.js")); 14026 v8::Handle<v8::Script> script2 = 14027 v8::Script::Compile(source0); // different origin 14028 CHECK_EQ(1234, script0->Run()->Int32Value()); 14029 CHECK_EQ(1234, script1->Run()->Int32Value()); 14030 CHECK_EQ(1234, script2->Run()->Int32Value()); 14031 } 14032 14033 14034 static void FunctionNameCallback( 14035 const v8::FunctionCallbackInfo<v8::Value>& args) { 14036 ApiTestFuzzer::Fuzz(); 14037 args.GetReturnValue().Set(v8_num(42)); 14038 } 14039 14040 14041 THREADED_TEST(CallbackFunctionName) { 14042 LocalContext context; 14043 v8::HandleScope scope(context->GetIsolate()); 14044 Local<ObjectTemplate> t = ObjectTemplate::New(); 14045 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback)); 14046 context->Global()->Set(v8_str("obj"), t->NewInstance()); 14047 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name"); 14048 CHECK(value->IsString()); 14049 v8::String::Utf8Value name(value); 14050 CHECK_EQ("asdf", *name); 14051 } 14052 14053 14054 THREADED_TEST(DateAccess) { 14055 LocalContext context; 14056 v8::HandleScope scope(context->GetIsolate()); 14057 v8::Handle<v8::Value> date = 14058 v8::Date::New(context->GetIsolate(), 1224744689038.0); 14059 CHECK(date->IsDate()); 14060 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 14061 } 14062 14063 14064 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) { 14065 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14066 v8::Handle<v8::Array> props = obj->GetPropertyNames(); 14067 CHECK_EQ(elmc, props->Length()); 14068 for (int i = 0; i < elmc; i++) { 14069 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 14070 CHECK_EQ(elmv[i], *elm); 14071 } 14072 } 14073 14074 14075 void CheckOwnProperties(v8::Handle<v8::Value> val, 14076 int elmc, 14077 const char* elmv[]) { 14078 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 14079 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames(); 14080 CHECK_EQ(elmc, props->Length()); 14081 for (int i = 0; i < elmc; i++) { 14082 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 14083 CHECK_EQ(elmv[i], *elm); 14084 } 14085 } 14086 14087 14088 THREADED_TEST(PropertyEnumeration) { 14089 LocalContext context; 14090 v8::HandleScope scope(context->GetIsolate()); 14091 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8( 14092 context->GetIsolate(), 14093 "var result = [];" 14094 "result[0] = {};" 14095 "result[1] = {a: 1, b: 2};" 14096 "result[2] = [1, 2, 3];" 14097 "var proto = {x: 1, y: 2, z: 3};" 14098 "var x = { __proto__: proto, w: 0, z: 1 };" 14099 "result[3] = x;" 14100 "result;"))->Run(); 14101 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14102 CHECK_EQ(4, elms->Length()); 14103 int elmc0 = 0; 14104 const char** elmv0 = NULL; 14105 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 14106 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 14107 int elmc1 = 2; 14108 const char* elmv1[] = {"a", "b"}; 14109 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 14110 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 14111 int elmc2 = 3; 14112 const char* elmv2[] = {"0", "1", "2"}; 14113 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 14114 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 14115 int elmc3 = 4; 14116 const char* elmv3[] = {"w", "z", "x", "y"}; 14117 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3); 14118 int elmc4 = 2; 14119 const char* elmv4[] = {"w", "z"}; 14120 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4); 14121 } 14122 14123 14124 THREADED_TEST(PropertyEnumeration2) { 14125 LocalContext context; 14126 v8::HandleScope scope(context->GetIsolate()); 14127 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8( 14128 context->GetIsolate(), 14129 "var result = [];" 14130 "result[0] = {};" 14131 "result[1] = {a: 1, b: 2};" 14132 "result[2] = [1, 2, 3];" 14133 "var proto = {x: 1, y: 2, z: 3};" 14134 "var x = { __proto__: proto, w: 0, z: 1 };" 14135 "result[3] = x;" 14136 "result;"))->Run(); 14137 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 14138 CHECK_EQ(4, elms->Length()); 14139 int elmc0 = 0; 14140 const char** elmv0 = NULL; 14141 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 14142 14143 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0)); 14144 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames(); 14145 CHECK_EQ(0, props->Length()); 14146 for (uint32_t i = 0; i < props->Length(); i++) { 14147 printf("p[%d]\n", i); 14148 } 14149 } 14150 14151 static bool NamedSetAccessBlocker(Local<v8::Object> obj, 14152 Local<Value> name, 14153 v8::AccessType type, 14154 Local<Value> data) { 14155 return type != v8::ACCESS_SET; 14156 } 14157 14158 14159 static bool IndexedSetAccessBlocker(Local<v8::Object> obj, 14160 uint32_t key, 14161 v8::AccessType type, 14162 Local<Value> data) { 14163 return type != v8::ACCESS_SET; 14164 } 14165 14166 14167 THREADED_TEST(DisableAccessChecksWhileConfiguring) { 14168 LocalContext context; 14169 v8::Isolate* isolate = context->GetIsolate(); 14170 v8::HandleScope scope(isolate); 14171 Local<ObjectTemplate> templ = ObjectTemplate::New(); 14172 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14173 IndexedSetAccessBlocker); 14174 templ->Set(v8_str("x"), v8::True(isolate)); 14175 Local<v8::Object> instance = templ->NewInstance(); 14176 context->Global()->Set(v8_str("obj"), instance); 14177 Local<Value> value = CompileRun("obj.x"); 14178 CHECK(value->BooleanValue()); 14179 } 14180 14181 14182 static bool NamedGetAccessBlocker(Local<v8::Object> obj, 14183 Local<Value> name, 14184 v8::AccessType type, 14185 Local<Value> data) { 14186 return false; 14187 } 14188 14189 14190 static bool IndexedGetAccessBlocker(Local<v8::Object> obj, 14191 uint32_t key, 14192 v8::AccessType type, 14193 Local<Value> data) { 14194 return false; 14195 } 14196 14197 14198 14199 THREADED_TEST(AccessChecksReenabledCorrectly) { 14200 LocalContext context; 14201 v8::HandleScope scope(context->GetIsolate()); 14202 Local<ObjectTemplate> templ = ObjectTemplate::New(); 14203 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14204 IndexedGetAccessBlocker); 14205 templ->Set(v8_str("a"), v8_str("a")); 14206 // Add more than 8 (see kMaxFastProperties) properties 14207 // so that the constructor will force copying map. 14208 // Cannot sprintf, gcc complains unsafety. 14209 char buf[4]; 14210 for (char i = '0'; i <= '9' ; i++) { 14211 buf[0] = i; 14212 for (char j = '0'; j <= '9'; j++) { 14213 buf[1] = j; 14214 for (char k = '0'; k <= '9'; k++) { 14215 buf[2] = k; 14216 buf[3] = 0; 14217 templ->Set(v8_str(buf), v8::Number::New(k)); 14218 } 14219 } 14220 } 14221 14222 Local<v8::Object> instance_1 = templ->NewInstance(); 14223 context->Global()->Set(v8_str("obj_1"), instance_1); 14224 14225 Local<Value> value_1 = CompileRun("obj_1.a"); 14226 CHECK(value_1->IsUndefined()); 14227 14228 Local<v8::Object> instance_2 = templ->NewInstance(); 14229 context->Global()->Set(v8_str("obj_2"), instance_2); 14230 14231 Local<Value> value_2 = CompileRun("obj_2.a"); 14232 CHECK(value_2->IsUndefined()); 14233 } 14234 14235 14236 // This tests that access check information remains on the global 14237 // object template when creating contexts. 14238 THREADED_TEST(AccessControlRepeatedContextCreation) { 14239 v8::Isolate* isolate = CcTest::isolate(); 14240 v8::HandleScope handle_scope(isolate); 14241 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 14242 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, 14243 IndexedSetAccessBlocker); 14244 i::Handle<i::ObjectTemplateInfo> internal_template = 14245 v8::Utils::OpenHandle(*global_template); 14246 CHECK(!internal_template->constructor()->IsUndefined()); 14247 i::Handle<i::FunctionTemplateInfo> constructor( 14248 i::FunctionTemplateInfo::cast(internal_template->constructor())); 14249 CHECK(!constructor->access_check_info()->IsUndefined()); 14250 v8::Local<Context> context0(Context::New(isolate, NULL, global_template)); 14251 CHECK(!context0.IsEmpty()); 14252 CHECK(!constructor->access_check_info()->IsUndefined()); 14253 } 14254 14255 14256 THREADED_TEST(TurnOnAccessCheck) { 14257 v8::Isolate* isolate = CcTest::isolate(); 14258 v8::HandleScope handle_scope(isolate); 14259 14260 // Create an environment with access check to the global object disabled by 14261 // default. 14262 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 14263 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 14264 IndexedGetAccessBlocker, 14265 v8::Handle<v8::Value>(), 14266 false); 14267 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14268 Context::Scope context_scope(context); 14269 14270 // Set up a property and a number of functions. 14271 context->Global()->Set(v8_str("a"), v8_num(1)); 14272 CompileRun("function f1() {return a;}" 14273 "function f2() {return a;}" 14274 "function g1() {return h();}" 14275 "function g2() {return h();}" 14276 "function h() {return 1;}"); 14277 Local<Function> f1 = 14278 Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14279 Local<Function> f2 = 14280 Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14281 Local<Function> g1 = 14282 Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14283 Local<Function> g2 = 14284 Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14285 Local<Function> h = 14286 Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14287 14288 // Get the global object. 14289 v8::Handle<v8::Object> global = context->Global(); 14290 14291 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14292 // uses the runtime system to retreive property a whereas f2 uses global load 14293 // inline cache. 14294 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14295 for (int i = 0; i < 4; i++) { 14296 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14297 } 14298 14299 // Same for g1 and g2. 14300 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14301 for (int i = 0; i < 4; i++) { 14302 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14303 } 14304 14305 // Detach the global and turn on access check. 14306 Local<Object> hidden_global = Local<Object>::Cast( 14307 context->Global()->GetPrototype()); 14308 context->DetachGlobal(); 14309 hidden_global->TurnOnAccessCheck(); 14310 14311 // Failing access check to property get results in undefined. 14312 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14313 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14314 14315 // Failing access check to function call results in exception. 14316 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14317 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14318 14319 // No failing access check when just returning a constant. 14320 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 14321 } 14322 14323 14324 static const char* kPropertyA = "a"; 14325 static const char* kPropertyH = "h"; 14326 14327 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, 14328 Local<Value> name, 14329 v8::AccessType type, 14330 Local<Value> data) { 14331 if (!name->IsString()) return false; 14332 i::Handle<i::String> name_handle = 14333 v8::Utils::OpenHandle(String::Cast(*name)); 14334 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA)) 14335 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH)); 14336 } 14337 14338 14339 THREADED_TEST(TurnOnAccessCheckAndRecompile) { 14340 v8::Isolate* isolate = CcTest::isolate(); 14341 v8::HandleScope handle_scope(isolate); 14342 14343 // Create an environment with access check to the global object disabled by 14344 // default. When the registered access checker will block access to properties 14345 // a and h. 14346 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 14347 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, 14348 IndexedGetAccessBlocker, 14349 v8::Handle<v8::Value>(), 14350 false); 14351 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 14352 Context::Scope context_scope(context); 14353 14354 // Set up a property and a number of functions. 14355 context->Global()->Set(v8_str("a"), v8_num(1)); 14356 static const char* source = "function f1() {return a;}" 14357 "function f2() {return a;}" 14358 "function g1() {return h();}" 14359 "function g2() {return h();}" 14360 "function h() {return 1;}"; 14361 14362 CompileRun(source); 14363 Local<Function> f1; 14364 Local<Function> f2; 14365 Local<Function> g1; 14366 Local<Function> g2; 14367 Local<Function> h; 14368 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 14369 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 14370 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 14371 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 14372 h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 14373 14374 // Get the global object. 14375 v8::Handle<v8::Object> global = context->Global(); 14376 14377 // Call f1 one time and f2 a number of times. This will ensure that f1 still 14378 // uses the runtime system to retreive property a whereas f2 uses global load 14379 // inline cache. 14380 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 14381 for (int i = 0; i < 4; i++) { 14382 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 14383 } 14384 14385 // Same for g1 and g2. 14386 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 14387 for (int i = 0; i < 4; i++) { 14388 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 14389 } 14390 14391 // Detach the global and turn on access check now blocking access to property 14392 // a and function h. 14393 Local<Object> hidden_global = Local<Object>::Cast( 14394 context->Global()->GetPrototype()); 14395 context->DetachGlobal(); 14396 hidden_global->TurnOnAccessCheck(); 14397 14398 // Failing access check to property get results in undefined. 14399 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14400 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14401 14402 // Failing access check to function call results in exception. 14403 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14404 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14405 14406 // No failing access check when just returning a constant. 14407 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 14408 14409 // Now compile the source again. And get the newly compiled functions, except 14410 // for h for which access is blocked. 14411 CompileRun(source); 14412 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1"))); 14413 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2"))); 14414 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1"))); 14415 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2"))); 14416 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined()); 14417 14418 // Failing access check to property get results in undefined. 14419 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 14420 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 14421 14422 // Failing access check to function call results in exception. 14423 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 14424 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 14425 } 14426 14427 14428 // This test verifies that pre-compilation (aka preparsing) can be called 14429 // without initializing the whole VM. Thus we cannot run this test in a 14430 // multi-threaded setup. 14431 TEST(PreCompile) { 14432 // TODO(155): This test would break without the initialization of V8. This is 14433 // a workaround for now to make this test not fail. 14434 v8::V8::Initialize(); 14435 v8::Isolate* isolate = CcTest::isolate(); 14436 const char* script = "function foo(a) { return a+1; }"; 14437 v8::ScriptData* sd = 14438 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14439 CHECK_NE(sd->Length(), 0); 14440 CHECK_NE(sd->Data(), NULL); 14441 CHECK(!sd->HasError()); 14442 delete sd; 14443 } 14444 14445 14446 TEST(PreCompileWithError) { 14447 v8::V8::Initialize(); 14448 v8::Isolate* isolate = CcTest::isolate(); 14449 const char* script = "function foo(a) { return 1 * * 2; }"; 14450 v8::ScriptData* sd = 14451 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14452 CHECK(sd->HasError()); 14453 delete sd; 14454 } 14455 14456 14457 TEST(Regress31661) { 14458 v8::V8::Initialize(); 14459 v8::Isolate* isolate = CcTest::isolate(); 14460 const char* script = " The Definintive Guide"; 14461 v8::ScriptData* sd = 14462 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14463 CHECK(sd->HasError()); 14464 delete sd; 14465 } 14466 14467 14468 // Tests that ScriptData can be serialized and deserialized. 14469 TEST(PreCompileSerialization) { 14470 v8::V8::Initialize(); 14471 v8::Isolate* isolate = CcTest::isolate(); 14472 const char* script = "function foo(a) { return a+1; }"; 14473 v8::ScriptData* sd = 14474 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14475 14476 // Serialize. 14477 int serialized_data_length = sd->Length(); 14478 char* serialized_data = i::NewArray<char>(serialized_data_length); 14479 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length); 14480 14481 // Deserialize. 14482 v8::ScriptData* deserialized_sd = 14483 v8::ScriptData::New(serialized_data, serialized_data_length); 14484 14485 // Verify that the original is the same as the deserialized. 14486 CHECK_EQ(sd->Length(), deserialized_sd->Length()); 14487 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length())); 14488 CHECK_EQ(sd->HasError(), deserialized_sd->HasError()); 14489 14490 delete sd; 14491 delete deserialized_sd; 14492 } 14493 14494 14495 // Attempts to deserialize bad data. 14496 TEST(PreCompileDeserializationError) { 14497 v8::V8::Initialize(); 14498 const char* data = "DONT CARE"; 14499 int invalid_size = 3; 14500 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size); 14501 14502 CHECK_EQ(0, sd->Length()); 14503 14504 delete sd; 14505 } 14506 14507 14508 // Attempts to deserialize bad data. 14509 TEST(PreCompileInvalidPreparseDataError) { 14510 v8::V8::Initialize(); 14511 v8::Isolate* isolate = CcTest::isolate(); 14512 LocalContext context; 14513 v8::HandleScope scope(context->GetIsolate()); 14514 14515 const char* script = "function foo(){ return 5;}\n" 14516 "function bar(){ return 6 + 7;} foo();"; 14517 v8::ScriptData* sd = 14518 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14519 CHECK(!sd->HasError()); 14520 // ScriptDataImpl private implementation details 14521 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; 14522 const int kFunctionEntrySize = i::FunctionEntry::kSize; 14523 const int kFunctionEntryStartOffset = 0; 14524 const int kFunctionEntryEndOffset = 1; 14525 unsigned* sd_data = 14526 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 14527 14528 // Overwrite function bar's end position with 0. 14529 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; 14530 v8::TryCatch try_catch; 14531 14532 Local<String> source = String::NewFromUtf8(isolate, script); 14533 Local<Script> compiled_script = Script::New(source, NULL, sd); 14534 CHECK(try_catch.HasCaught()); 14535 String::Utf8Value exception_value(try_catch.Message()->Get()); 14536 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar", 14537 *exception_value); 14538 14539 try_catch.Reset(); 14540 14541 // Overwrite function bar's start position with 200. The function entry 14542 // will not be found when searching for it by position and we should fall 14543 // back on eager compilation. 14544 sd = v8::ScriptData::PreCompile(isolate, script, i::StrLength(script)); 14545 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 14546 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = 14547 200; 14548 compiled_script = Script::New(source, NULL, sd); 14549 CHECK(!try_catch.HasCaught()); 14550 14551 delete sd; 14552 } 14553 14554 14555 // Verifies that the Handle<String> and const char* versions of the API produce 14556 // the same results (at least for one trivial case). 14557 TEST(PreCompileAPIVariationsAreSame) { 14558 v8::V8::Initialize(); 14559 v8::Isolate* isolate = CcTest::isolate(); 14560 v8::HandleScope scope(isolate); 14561 14562 const char* cstring = "function foo(a) { return a+1; }"; 14563 14564 v8::ScriptData* sd_from_cstring = 14565 v8::ScriptData::PreCompile(isolate, cstring, i::StrLength(cstring)); 14566 14567 TestAsciiResource* resource = new TestAsciiResource(cstring); 14568 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile( 14569 v8::String::NewExternal(isolate, resource)); 14570 14571 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile( 14572 v8::String::NewFromUtf8(isolate, cstring)); 14573 14574 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length()); 14575 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 14576 sd_from_external_string->Data(), 14577 sd_from_cstring->Length())); 14578 14579 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length()); 14580 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 14581 sd_from_string->Data(), 14582 sd_from_cstring->Length())); 14583 14584 14585 delete sd_from_cstring; 14586 delete sd_from_external_string; 14587 delete sd_from_string; 14588 } 14589 14590 14591 // This tests that we do not allow dictionary load/call inline caches 14592 // to use functions that have not yet been compiled. The potential 14593 // problem of loading a function that has not yet been compiled can 14594 // arise because we share code between contexts via the compilation 14595 // cache. 14596 THREADED_TEST(DictionaryICLoadedFunction) { 14597 v8::HandleScope scope(CcTest::isolate()); 14598 // Test LoadIC. 14599 for (int i = 0; i < 2; i++) { 14600 LocalContext context; 14601 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 14602 context->Global()->Delete(v8_str("tmp")); 14603 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 14604 } 14605 // Test CallIC. 14606 for (int i = 0; i < 2; i++) { 14607 LocalContext context; 14608 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate())); 14609 context->Global()->Delete(v8_str("tmp")); 14610 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 14611 } 14612 } 14613 14614 14615 // Test that cross-context new calls use the context of the callee to 14616 // create the new JavaScript object. 14617 THREADED_TEST(CrossContextNew) { 14618 v8::Isolate* isolate = CcTest::isolate(); 14619 v8::HandleScope scope(isolate); 14620 v8::Local<Context> context0 = Context::New(isolate); 14621 v8::Local<Context> context1 = Context::New(isolate); 14622 14623 // Allow cross-domain access. 14624 Local<String> token = v8_str("<security token>"); 14625 context0->SetSecurityToken(token); 14626 context1->SetSecurityToken(token); 14627 14628 // Set an 'x' property on the Object prototype and define a 14629 // constructor function in context0. 14630 context0->Enter(); 14631 CompileRun("Object.prototype.x = 42; function C() {};"); 14632 context0->Exit(); 14633 14634 // Call the constructor function from context0 and check that the 14635 // result has the 'x' property. 14636 context1->Enter(); 14637 context1->Global()->Set(v8_str("other"), context0->Global()); 14638 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 14639 CHECK(value->IsInt32()); 14640 CHECK_EQ(42, value->Int32Value()); 14641 context1->Exit(); 14642 } 14643 14644 14645 // Verify that we can clone an object 14646 TEST(ObjectClone) { 14647 LocalContext env; 14648 v8::HandleScope scope(env->GetIsolate()); 14649 14650 const char* sample = 14651 "var rv = {};" \ 14652 "rv.alpha = 'hello';" \ 14653 "rv.beta = 123;" \ 14654 "rv;"; 14655 14656 // Create an object, verify basics. 14657 Local<Value> val = CompileRun(sample); 14658 CHECK(val->IsObject()); 14659 Local<v8::Object> obj = val.As<v8::Object>(); 14660 obj->Set(v8_str("gamma"), v8_str("cloneme")); 14661 14662 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); 14663 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 14664 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma"))); 14665 14666 // Clone it. 14667 Local<v8::Object> clone = obj->Clone(); 14668 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 14669 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta"))); 14670 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 14671 14672 // Set a property on the clone, verify each object. 14673 clone->Set(v8_str("beta"), v8::Integer::New(456)); 14674 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 14675 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta"))); 14676 } 14677 14678 14679 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { 14680 public: 14681 explicit AsciiVectorResource(i::Vector<const char> vector) 14682 : data_(vector) {} 14683 virtual ~AsciiVectorResource() {} 14684 virtual size_t length() const { return data_.length(); } 14685 virtual const char* data() const { return data_.start(); } 14686 private: 14687 i::Vector<const char> data_; 14688 }; 14689 14690 14691 class UC16VectorResource : public v8::String::ExternalStringResource { 14692 public: 14693 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 14694 : data_(vector) {} 14695 virtual ~UC16VectorResource() {} 14696 virtual size_t length() const { return data_.length(); } 14697 virtual const i::uc16* data() const { return data_.start(); } 14698 private: 14699 i::Vector<const i::uc16> data_; 14700 }; 14701 14702 14703 static void MorphAString(i::String* string, 14704 AsciiVectorResource* ascii_resource, 14705 UC16VectorResource* uc16_resource) { 14706 CHECK(i::StringShape(string).IsExternal()); 14707 if (string->IsOneByteRepresentation()) { 14708 // Check old map is not internalized or long. 14709 CHECK(string->map() == CcTest::heap()->external_ascii_string_map()); 14710 // Morph external string to be TwoByte string. 14711 string->set_map(CcTest::heap()->external_string_map()); 14712 i::ExternalTwoByteString* morphed = 14713 i::ExternalTwoByteString::cast(string); 14714 morphed->set_resource(uc16_resource); 14715 } else { 14716 // Check old map is not internalized or long. 14717 CHECK(string->map() == CcTest::heap()->external_string_map()); 14718 // Morph external string to be ASCII string. 14719 string->set_map(CcTest::heap()->external_ascii_string_map()); 14720 i::ExternalAsciiString* morphed = 14721 i::ExternalAsciiString::cast(string); 14722 morphed->set_resource(ascii_resource); 14723 } 14724 } 14725 14726 14727 // Test that we can still flatten a string if the components it is built up 14728 // from have been turned into 16 bit strings in the mean time. 14729 THREADED_TEST(MorphCompositeStringTest) { 14730 char utf_buffer[129]; 14731 const char* c_string = "Now is the time for all good men" 14732 " to come to the aid of the party"; 14733 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 14734 { 14735 LocalContext env; 14736 i::Factory* factory = CcTest::i_isolate()->factory(); 14737 v8::HandleScope scope(env->GetIsolate()); 14738 AsciiVectorResource ascii_resource( 14739 i::Vector<const char>(c_string, i::StrLength(c_string))); 14740 UC16VectorResource uc16_resource( 14741 i::Vector<const uint16_t>(two_byte_string, 14742 i::StrLength(c_string))); 14743 14744 Local<String> lhs(v8::Utils::ToLocal( 14745 factory->NewExternalStringFromAscii(&ascii_resource))); 14746 Local<String> rhs(v8::Utils::ToLocal( 14747 factory->NewExternalStringFromAscii(&ascii_resource))); 14748 14749 env->Global()->Set(v8_str("lhs"), lhs); 14750 env->Global()->Set(v8_str("rhs"), rhs); 14751 14752 CompileRun( 14753 "var cons = lhs + rhs;" 14754 "var slice = lhs.substring(1, lhs.length - 1);" 14755 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 14756 14757 CHECK(lhs->IsOneByte()); 14758 CHECK(rhs->IsOneByte()); 14759 14760 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource); 14761 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource); 14762 14763 // This should UTF-8 without flattening, since everything is ASCII. 14764 Handle<String> cons = v8_compile("cons")->Run().As<String>(); 14765 CHECK_EQ(128, cons->Utf8Length()); 14766 int nchars = -1; 14767 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 14768 CHECK_EQ(128, nchars); 14769 CHECK_EQ(0, strcmp( 14770 utf_buffer, 14771 "Now is the time for all good men to come to the aid of the party" 14772 "Now is the time for all good men to come to the aid of the party")); 14773 14774 // Now do some stuff to make sure the strings are flattened, etc. 14775 CompileRun( 14776 "/[^a-z]/.test(cons);" 14777 "/[^a-z]/.test(slice);" 14778 "/[^a-z]/.test(slice_on_cons);"); 14779 const char* expected_cons = 14780 "Now is the time for all good men to come to the aid of the party" 14781 "Now is the time for all good men to come to the aid of the party"; 14782 const char* expected_slice = 14783 "ow is the time for all good men to come to the aid of the part"; 14784 const char* expected_slice_on_cons = 14785 "ow is the time for all good men to come to the aid of the party" 14786 "Now is the time for all good men to come to the aid of the part"; 14787 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons), 14788 env->Global()->Get(v8_str("cons"))); 14789 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice), 14790 env->Global()->Get(v8_str("slice"))); 14791 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons), 14792 env->Global()->Get(v8_str("slice_on_cons"))); 14793 } 14794 i::DeleteArray(two_byte_string); 14795 } 14796 14797 14798 TEST(CompileExternalTwoByteSource) { 14799 LocalContext context; 14800 v8::HandleScope scope(context->GetIsolate()); 14801 14802 // This is a very short list of sources, which currently is to check for a 14803 // regression caused by r2703. 14804 const char* ascii_sources[] = { 14805 "0.5", 14806 "-0.5", // This mainly testes PushBack in the Scanner. 14807 "--0.5", // This mainly testes PushBack in the Scanner. 14808 NULL 14809 }; 14810 14811 // Compile the sources as external two byte strings. 14812 for (int i = 0; ascii_sources[i] != NULL; i++) { 14813 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]); 14814 UC16VectorResource uc16_resource( 14815 i::Vector<const uint16_t>(two_byte_string, 14816 i::StrLength(ascii_sources[i]))); 14817 v8::Local<v8::String> source = 14818 v8::String::NewExternal(context->GetIsolate(), &uc16_resource); 14819 v8::Script::Compile(source); 14820 i::DeleteArray(two_byte_string); 14821 } 14822 } 14823 14824 14825 #ifndef V8_INTERPRETED_REGEXP 14826 14827 struct RegExpInterruptionData { 14828 int loop_count; 14829 UC16VectorResource* string_resource; 14830 v8::Persistent<v8::String> string; 14831 } regexp_interruption_data; 14832 14833 14834 class RegExpInterruptionThread : public i::Thread { 14835 public: 14836 explicit RegExpInterruptionThread(v8::Isolate* isolate) 14837 : Thread("TimeoutThread"), isolate_(isolate) {} 14838 14839 virtual void Run() { 14840 for (regexp_interruption_data.loop_count = 0; 14841 regexp_interruption_data.loop_count < 7; 14842 regexp_interruption_data.loop_count++) { 14843 i::OS::Sleep(50); // Wait a bit before requesting GC. 14844 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); 14845 } 14846 i::OS::Sleep(50); // Wait a bit before terminating. 14847 v8::V8::TerminateExecution(isolate_); 14848 } 14849 14850 private: 14851 v8::Isolate* isolate_; 14852 }; 14853 14854 14855 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) { 14856 if (regexp_interruption_data.loop_count != 2) return; 14857 v8::HandleScope scope(CcTest::isolate()); 14858 v8::Local<v8::String> string = v8::Local<v8::String>::New( 14859 CcTest::isolate(), regexp_interruption_data.string); 14860 string->MakeExternal(regexp_interruption_data.string_resource); 14861 } 14862 14863 14864 // Test that RegExp execution can be interrupted. Specifically, we test 14865 // * interrupting with GC 14866 // * turn the subject string from one-byte internal to two-byte external string 14867 // * force termination 14868 TEST(RegExpInterruption) { 14869 v8::HandleScope scope(CcTest::isolate()); 14870 LocalContext env; 14871 14872 RegExpInterruptionThread timeout_thread(CcTest::isolate()); 14873 14874 v8::V8::AddGCPrologueCallback(RunBeforeGC); 14875 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 14876 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content); 14877 v8::Local<v8::String> string = v8_str(ascii_content); 14878 14879 CcTest::global()->Set(v8_str("a"), string); 14880 regexp_interruption_data.string.Reset(CcTest::isolate(), string); 14881 regexp_interruption_data.string_resource = new UC16VectorResource( 14882 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content))); 14883 14884 v8::TryCatch try_catch; 14885 timeout_thread.Start(); 14886 14887 CompileRun("/((a*)*)*b/.exec(a)"); 14888 CHECK(try_catch.HasTerminated()); 14889 14890 timeout_thread.Join(); 14891 14892 delete regexp_interruption_data.string_resource; 14893 regexp_interruption_data.string.Reset(); 14894 } 14895 14896 #endif // V8_INTERPRETED_REGEXP 14897 14898 14899 // Test that we cannot set a property on the global object if there 14900 // is a read-only property in the prototype chain. 14901 TEST(ReadOnlyPropertyInGlobalProto) { 14902 i::FLAG_es5_readonly = true; 14903 v8::HandleScope scope(CcTest::isolate()); 14904 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14905 LocalContext context(0, templ); 14906 v8::Handle<v8::Object> global = context->Global(); 14907 v8::Handle<v8::Object> global_proto = 14908 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); 14909 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly); 14910 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly); 14911 // Check without 'eval' or 'with'. 14912 v8::Handle<v8::Value> res = 14913 CompileRun("function f() { x = 42; return x; }; f()"); 14914 CHECK_EQ(v8::Integer::New(0), res); 14915 // Check with 'eval'. 14916 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 14917 CHECK_EQ(v8::Integer::New(0), res); 14918 // Check with 'with'. 14919 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 14920 CHECK_EQ(v8::Integer::New(0), res); 14921 } 14922 14923 static int force_set_set_count = 0; 14924 static int force_set_get_count = 0; 14925 bool pass_on_get = false; 14926 14927 static void ForceSetGetter(v8::Local<v8::String> name, 14928 const v8::PropertyCallbackInfo<v8::Value>& info) { 14929 force_set_get_count++; 14930 if (pass_on_get) { 14931 return; 14932 } 14933 info.GetReturnValue().Set(3); 14934 } 14935 14936 static void ForceSetSetter(v8::Local<v8::String> name, 14937 v8::Local<v8::Value> value, 14938 const v8::PropertyCallbackInfo<void>& info) { 14939 force_set_set_count++; 14940 } 14941 14942 static void ForceSetInterceptSetter( 14943 v8::Local<v8::String> name, 14944 v8::Local<v8::Value> value, 14945 const v8::PropertyCallbackInfo<v8::Value>& info) { 14946 force_set_set_count++; 14947 info.GetReturnValue().SetUndefined(); 14948 } 14949 14950 14951 TEST(ForceSet) { 14952 force_set_get_count = 0; 14953 force_set_set_count = 0; 14954 pass_on_get = false; 14955 14956 v8::HandleScope scope(CcTest::isolate()); 14957 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14958 v8::Handle<v8::String> access_property = 14959 v8::String::NewFromUtf8(CcTest::isolate(), "a"); 14960 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); 14961 LocalContext context(NULL, templ); 14962 v8::Handle<v8::Object> global = context->Global(); 14963 14964 // Ordinary properties 14965 v8::Handle<v8::String> simple_property = 14966 v8::String::NewFromUtf8(CcTest::isolate(), "p"); 14967 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly); 14968 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14969 // This should fail because the property is read-only 14970 global->Set(simple_property, v8::Int32::New(5)); 14971 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14972 // This should succeed even though the property is read-only 14973 global->ForceSet(simple_property, v8::Int32::New(6)); 14974 CHECK_EQ(6, global->Get(simple_property)->Int32Value()); 14975 14976 // Accessors 14977 CHECK_EQ(0, force_set_set_count); 14978 CHECK_EQ(0, force_set_get_count); 14979 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 14980 // CHECK_EQ the property shouldn't override it, just call the setter 14981 // which in this case does nothing. 14982 global->Set(access_property, v8::Int32::New(7)); 14983 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 14984 CHECK_EQ(1, force_set_set_count); 14985 CHECK_EQ(2, force_set_get_count); 14986 // Forcing the property to be set should override the accessor without 14987 // calling it 14988 global->ForceSet(access_property, v8::Int32::New(8)); 14989 CHECK_EQ(8, global->Get(access_property)->Int32Value()); 14990 CHECK_EQ(1, force_set_set_count); 14991 CHECK_EQ(2, force_set_get_count); 14992 } 14993 14994 14995 TEST(ForceSetWithInterceptor) { 14996 force_set_get_count = 0; 14997 force_set_set_count = 0; 14998 pass_on_get = false; 14999 15000 v8::HandleScope scope(CcTest::isolate()); 15001 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 15002 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); 15003 LocalContext context(NULL, templ); 15004 v8::Handle<v8::Object> global = context->Global(); 15005 15006 v8::Handle<v8::String> some_property = 15007 v8::String::NewFromUtf8(CcTest::isolate(), "a"); 15008 CHECK_EQ(0, force_set_set_count); 15009 CHECK_EQ(0, force_set_get_count); 15010 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15011 // Setting the property shouldn't override it, just call the setter 15012 // which in this case does nothing. 15013 global->Set(some_property, v8::Int32::New(7)); 15014 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15015 CHECK_EQ(1, force_set_set_count); 15016 CHECK_EQ(2, force_set_get_count); 15017 // Getting the property when the interceptor returns an empty handle 15018 // should yield undefined, since the property isn't present on the 15019 // object itself yet. 15020 pass_on_get = true; 15021 CHECK(global->Get(some_property)->IsUndefined()); 15022 CHECK_EQ(1, force_set_set_count); 15023 CHECK_EQ(3, force_set_get_count); 15024 // Forcing the property to be set should cause the value to be 15025 // set locally without calling the interceptor. 15026 global->ForceSet(some_property, v8::Int32::New(8)); 15027 CHECK_EQ(8, global->Get(some_property)->Int32Value()); 15028 CHECK_EQ(1, force_set_set_count); 15029 CHECK_EQ(4, force_set_get_count); 15030 // Reenabling the interceptor should cause it to take precedence over 15031 // the property 15032 pass_on_get = false; 15033 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 15034 CHECK_EQ(1, force_set_set_count); 15035 CHECK_EQ(5, force_set_get_count); 15036 // The interceptor should also work for other properties 15037 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(CcTest::isolate(), "b")) 15038 ->Int32Value()); 15039 CHECK_EQ(1, force_set_set_count); 15040 CHECK_EQ(6, force_set_get_count); 15041 } 15042 15043 15044 THREADED_TEST(ForceDelete) { 15045 v8::HandleScope scope(CcTest::isolate()); 15046 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 15047 LocalContext context(NULL, templ); 15048 v8::Handle<v8::Object> global = context->Global(); 15049 15050 // Ordinary properties 15051 v8::Handle<v8::String> simple_property = 15052 v8::String::NewFromUtf8(CcTest::isolate(), "p"); 15053 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete); 15054 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15055 // This should fail because the property is dont-delete. 15056 CHECK(!global->Delete(simple_property)); 15057 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 15058 // This should succeed even though the property is dont-delete. 15059 CHECK(global->ForceDelete(simple_property)); 15060 CHECK(global->Get(simple_property)->IsUndefined()); 15061 } 15062 15063 15064 static int force_delete_interceptor_count = 0; 15065 static bool pass_on_delete = false; 15066 15067 15068 static void ForceDeleteDeleter( 15069 v8::Local<v8::String> name, 15070 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 15071 force_delete_interceptor_count++; 15072 if (pass_on_delete) return; 15073 info.GetReturnValue().Set(true); 15074 } 15075 15076 15077 THREADED_TEST(ForceDeleteWithInterceptor) { 15078 force_delete_interceptor_count = 0; 15079 pass_on_delete = false; 15080 15081 v8::HandleScope scope(CcTest::isolate()); 15082 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 15083 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter); 15084 LocalContext context(NULL, templ); 15085 v8::Handle<v8::Object> global = context->Global(); 15086 15087 v8::Handle<v8::String> some_property = 15088 v8::String::NewFromUtf8(CcTest::isolate(), "a"); 15089 global->Set(some_property, v8::Integer::New(42), v8::DontDelete); 15090 15091 // Deleting a property should get intercepted and nothing should 15092 // happen. 15093 CHECK_EQ(0, force_delete_interceptor_count); 15094 CHECK(global->Delete(some_property)); 15095 CHECK_EQ(1, force_delete_interceptor_count); 15096 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15097 // Deleting the property when the interceptor returns an empty 15098 // handle should not delete the property since it is DontDelete. 15099 pass_on_delete = true; 15100 CHECK(!global->Delete(some_property)); 15101 CHECK_EQ(2, force_delete_interceptor_count); 15102 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 15103 // Forcing the property to be deleted should delete the value 15104 // without calling the interceptor. 15105 CHECK(global->ForceDelete(some_property)); 15106 CHECK(global->Get(some_property)->IsUndefined()); 15107 CHECK_EQ(2, force_delete_interceptor_count); 15108 } 15109 15110 15111 // Make sure that forcing a delete invalidates any IC stubs, so we 15112 // don't read the hole value. 15113 THREADED_TEST(ForceDeleteIC) { 15114 LocalContext context; 15115 v8::HandleScope scope(context->GetIsolate()); 15116 // Create a DontDelete variable on the global object. 15117 CompileRun("this.__proto__ = { foo: 'horse' };" 15118 "var foo = 'fish';" 15119 "function f() { return foo.length; }"); 15120 // Initialize the IC for foo in f. 15121 CompileRun("for (var i = 0; i < 4; i++) f();"); 15122 // Make sure the value of foo is correct before the deletion. 15123 CHECK_EQ(4, CompileRun("f()")->Int32Value()); 15124 // Force the deletion of foo. 15125 CHECK(context->Global()->ForceDelete(v8_str("foo"))); 15126 // Make sure the value for foo is read from the prototype, and that 15127 // we don't get in trouble with reading the deleted cell value 15128 // sentinel. 15129 CHECK_EQ(5, CompileRun("f()")->Int32Value()); 15130 } 15131 15132 15133 TEST(InlinedFunctionAcrossContexts) { 15134 i::FLAG_allow_natives_syntax = true; 15135 v8::Isolate* isolate = CcTest::isolate(); 15136 v8::HandleScope outer_scope(isolate); 15137 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate); 15138 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate); 15139 ctx1->Enter(); 15140 15141 { 15142 v8::HandleScope inner_scope(CcTest::isolate()); 15143 CompileRun("var G = 42; function foo() { return G; }"); 15144 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo")); 15145 ctx2->Enter(); 15146 ctx2->Global()->Set(v8_str("o"), foo); 15147 v8::Local<v8::Value> res = CompileRun( 15148 "function f() { return o(); }" 15149 "for (var i = 0; i < 10; ++i) f();" 15150 "%OptimizeFunctionOnNextCall(f);" 15151 "f();"); 15152 CHECK_EQ(42, res->Int32Value()); 15153 ctx2->Exit(); 15154 v8::Handle<v8::String> G_property = 15155 v8::String::NewFromUtf8(CcTest::isolate(), "G"); 15156 CHECK(ctx1->Global()->ForceDelete(G_property)); 15157 ctx2->Enter(); 15158 ExpectString( 15159 "(function() {" 15160 " try {" 15161 " return f();" 15162 " } catch(e) {" 15163 " return e.toString();" 15164 " }" 15165 " })()", 15166 "ReferenceError: G is not defined"); 15167 ctx2->Exit(); 15168 ctx1->Exit(); 15169 } 15170 } 15171 15172 15173 static v8::Local<Context> calling_context0; 15174 static v8::Local<Context> calling_context1; 15175 static v8::Local<Context> calling_context2; 15176 15177 15178 // Check that the call to the callback is initiated in 15179 // calling_context2, the directly calling context is calling_context1 15180 // and the callback itself is in calling_context0. 15181 static void GetCallingContextCallback( 15182 const v8::FunctionCallbackInfo<v8::Value>& args) { 15183 ApiTestFuzzer::Fuzz(); 15184 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0); 15185 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1); 15186 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2); 15187 args.GetReturnValue().Set(42); 15188 } 15189 15190 15191 THREADED_TEST(GetCurrentContextWhenNotInContext) { 15192 i::Isolate* isolate = CcTest::i_isolate(); 15193 CHECK(isolate != NULL); 15194 CHECK(isolate->context() == NULL); 15195 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 15196 v8::HandleScope scope(v8_isolate); 15197 // The following should not crash, but return an empty handle. 15198 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 15199 CHECK(current.IsEmpty()); 15200 } 15201 15202 15203 THREADED_TEST(GetCallingContext) { 15204 v8::Isolate* isolate = CcTest::isolate(); 15205 v8::HandleScope scope(isolate); 15206 15207 Local<Context> calling_context0(Context::New(isolate)); 15208 Local<Context> calling_context1(Context::New(isolate)); 15209 Local<Context> calling_context2(Context::New(isolate)); 15210 ::calling_context0 = calling_context0; 15211 ::calling_context1 = calling_context1; 15212 ::calling_context2 = calling_context2; 15213 15214 // Allow cross-domain access. 15215 Local<String> token = v8_str("<security token>"); 15216 calling_context0->SetSecurityToken(token); 15217 calling_context1->SetSecurityToken(token); 15218 calling_context2->SetSecurityToken(token); 15219 15220 // Create an object with a C++ callback in context0. 15221 calling_context0->Enter(); 15222 Local<v8::FunctionTemplate> callback_templ = 15223 v8::FunctionTemplate::New(GetCallingContextCallback); 15224 calling_context0->Global()->Set(v8_str("callback"), 15225 callback_templ->GetFunction()); 15226 calling_context0->Exit(); 15227 15228 // Expose context0 in context1 and set up a function that calls the 15229 // callback function. 15230 calling_context1->Enter(); 15231 calling_context1->Global()->Set(v8_str("context0"), 15232 calling_context0->Global()); 15233 CompileRun("function f() { context0.callback() }"); 15234 calling_context1->Exit(); 15235 15236 // Expose context1 in context2 and call the callback function in 15237 // context0 indirectly through f in context1. 15238 calling_context2->Enter(); 15239 calling_context2->Global()->Set(v8_str("context1"), 15240 calling_context1->Global()); 15241 CompileRun("context1.f()"); 15242 calling_context2->Exit(); 15243 ::calling_context0.Clear(); 15244 ::calling_context1.Clear(); 15245 ::calling_context2.Clear(); 15246 } 15247 15248 15249 // Check that a variable declaration with no explicit initialization 15250 // value does shadow an existing property in the prototype chain. 15251 THREADED_TEST(InitGlobalVarInProtoChain) { 15252 i::FLAG_es52_globals = true; 15253 LocalContext context; 15254 v8::HandleScope scope(context->GetIsolate()); 15255 // Introduce a variable in the prototype chain. 15256 CompileRun("__proto__.x = 42"); 15257 v8::Handle<v8::Value> result = CompileRun("var x = 43; x"); 15258 CHECK(!result->IsUndefined()); 15259 CHECK_EQ(43, result->Int32Value()); 15260 } 15261 15262 15263 // Regression test for issue 398. 15264 // If a function is added to an object, creating a constant function 15265 // field, and the result is cloned, replacing the constant function on the 15266 // original should not affect the clone. 15267 // See http://code.google.com/p/v8/issues/detail?id=398 15268 THREADED_TEST(ReplaceConstantFunction) { 15269 LocalContext context; 15270 v8::HandleScope scope(context->GetIsolate()); 15271 v8::Handle<v8::Object> obj = v8::Object::New(); 15272 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 15273 v8::Handle<v8::String> foo_string = 15274 v8::String::NewFromUtf8(context->GetIsolate(), "foo"); 15275 obj->Set(foo_string, func_templ->GetFunction()); 15276 v8::Handle<v8::Object> obj_clone = obj->Clone(); 15277 obj_clone->Set(foo_string, 15278 v8::String::NewFromUtf8(context->GetIsolate(), "Hello")); 15279 CHECK(!obj->Get(foo_string)->IsUndefined()); 15280 } 15281 15282 15283 static void CheckElementValue(i::Isolate* isolate, 15284 int expected, 15285 i::Handle<i::Object> obj, 15286 int offset) { 15287 i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked(); 15288 CHECK_EQ(expected, i::Smi::cast(element)->value()); 15289 } 15290 15291 15292 THREADED_TEST(PixelArray) { 15293 LocalContext context; 15294 i::Isolate* isolate = CcTest::i_isolate(); 15295 i::Factory* factory = isolate->factory(); 15296 v8::HandleScope scope(context->GetIsolate()); 15297 const int kElementCount = 260; 15298 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 15299 i::Handle<i::ExternalPixelArray> pixels = 15300 i::Handle<i::ExternalPixelArray>::cast( 15301 factory->NewExternalArray(kElementCount, 15302 v8::kExternalPixelArray, 15303 pixel_data)); 15304 // Force GC to trigger verification. 15305 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15306 for (int i = 0; i < kElementCount; i++) { 15307 pixels->set(i, i % 256); 15308 } 15309 // Force GC to trigger verification. 15310 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15311 for (int i = 0; i < kElementCount; i++) { 15312 CHECK_EQ(i % 256, pixels->get_scalar(i)); 15313 CHECK_EQ(i % 256, pixel_data[i]); 15314 } 15315 15316 v8::Handle<v8::Object> obj = v8::Object::New(); 15317 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15318 // Set the elements to be the pixels. 15319 // jsobj->set_elements(*pixels); 15320 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 15321 CheckElementValue(isolate, 1, jsobj, 1); 15322 obj->Set(v8_str("field"), v8::Int32::New(1503)); 15323 context->Global()->Set(v8_str("pixels"), obj); 15324 v8::Handle<v8::Value> result = CompileRun("pixels.field"); 15325 CHECK_EQ(1503, result->Int32Value()); 15326 result = CompileRun("pixels[1]"); 15327 CHECK_EQ(1, result->Int32Value()); 15328 15329 result = CompileRun("var sum = 0;" 15330 "for (var i = 0; i < 8; i++) {" 15331 " sum += pixels[i] = pixels[i] = -i;" 15332 "}" 15333 "sum;"); 15334 CHECK_EQ(-28, result->Int32Value()); 15335 15336 result = CompileRun("var sum = 0;" 15337 "for (var i = 0; i < 8; i++) {" 15338 " sum += pixels[i] = pixels[i] = 0;" 15339 "}" 15340 "sum;"); 15341 CHECK_EQ(0, result->Int32Value()); 15342 15343 result = CompileRun("var sum = 0;" 15344 "for (var i = 0; i < 8; i++) {" 15345 " sum += pixels[i] = pixels[i] = 255;" 15346 "}" 15347 "sum;"); 15348 CHECK_EQ(8 * 255, result->Int32Value()); 15349 15350 result = CompileRun("var sum = 0;" 15351 "for (var i = 0; i < 8; i++) {" 15352 " sum += pixels[i] = pixels[i] = 256 + i;" 15353 "}" 15354 "sum;"); 15355 CHECK_EQ(2076, result->Int32Value()); 15356 15357 result = CompileRun("var sum = 0;" 15358 "for (var i = 0; i < 8; i++) {" 15359 " sum += pixels[i] = pixels[i] = i;" 15360 "}" 15361 "sum;"); 15362 CHECK_EQ(28, result->Int32Value()); 15363 15364 result = CompileRun("var sum = 0;" 15365 "for (var i = 0; i < 8; i++) {" 15366 " sum += pixels[i];" 15367 "}" 15368 "sum;"); 15369 CHECK_EQ(28, result->Int32Value()); 15370 15371 i::Handle<i::Smi> value(i::Smi::FromInt(2), 15372 reinterpret_cast<i::Isolate*>(context->GetIsolate())); 15373 i::Handle<i::Object> no_failure; 15374 no_failure = 15375 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 15376 ASSERT(!no_failure.is_null()); 15377 i::USE(no_failure); 15378 CheckElementValue(isolate, 2, jsobj, 1); 15379 *value.location() = i::Smi::FromInt(256); 15380 no_failure = 15381 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 15382 ASSERT(!no_failure.is_null()); 15383 i::USE(no_failure); 15384 CheckElementValue(isolate, 255, jsobj, 1); 15385 *value.location() = i::Smi::FromInt(-1); 15386 no_failure = 15387 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 15388 ASSERT(!no_failure.is_null()); 15389 i::USE(no_failure); 15390 CheckElementValue(isolate, 0, jsobj, 1); 15391 15392 result = CompileRun("for (var i = 0; i < 8; i++) {" 15393 " pixels[i] = (i * 65) - 109;" 15394 "}" 15395 "pixels[1] + pixels[6];"); 15396 CHECK_EQ(255, result->Int32Value()); 15397 CheckElementValue(isolate, 0, jsobj, 0); 15398 CheckElementValue(isolate, 0, jsobj, 1); 15399 CheckElementValue(isolate, 21, jsobj, 2); 15400 CheckElementValue(isolate, 86, jsobj, 3); 15401 CheckElementValue(isolate, 151, jsobj, 4); 15402 CheckElementValue(isolate, 216, jsobj, 5); 15403 CheckElementValue(isolate, 255, jsobj, 6); 15404 CheckElementValue(isolate, 255, jsobj, 7); 15405 result = CompileRun("var sum = 0;" 15406 "for (var i = 0; i < 8; i++) {" 15407 " sum += pixels[i];" 15408 "}" 15409 "sum;"); 15410 CHECK_EQ(984, result->Int32Value()); 15411 15412 result = CompileRun("for (var i = 0; i < 8; i++) {" 15413 " pixels[i] = (i * 1.1);" 15414 "}" 15415 "pixels[1] + pixels[6];"); 15416 CHECK_EQ(8, result->Int32Value()); 15417 CheckElementValue(isolate, 0, jsobj, 0); 15418 CheckElementValue(isolate, 1, jsobj, 1); 15419 CheckElementValue(isolate, 2, jsobj, 2); 15420 CheckElementValue(isolate, 3, jsobj, 3); 15421 CheckElementValue(isolate, 4, jsobj, 4); 15422 CheckElementValue(isolate, 6, jsobj, 5); 15423 CheckElementValue(isolate, 7, jsobj, 6); 15424 CheckElementValue(isolate, 8, jsobj, 7); 15425 15426 result = CompileRun("for (var i = 0; i < 8; i++) {" 15427 " pixels[7] = undefined;" 15428 "}" 15429 "pixels[7];"); 15430 CHECK_EQ(0, result->Int32Value()); 15431 CheckElementValue(isolate, 0, jsobj, 7); 15432 15433 result = CompileRun("for (var i = 0; i < 8; i++) {" 15434 " pixels[6] = '2.3';" 15435 "}" 15436 "pixels[6];"); 15437 CHECK_EQ(2, result->Int32Value()); 15438 CheckElementValue(isolate, 2, jsobj, 6); 15439 15440 result = CompileRun("for (var i = 0; i < 8; i++) {" 15441 " pixels[5] = NaN;" 15442 "}" 15443 "pixels[5];"); 15444 CHECK_EQ(0, result->Int32Value()); 15445 CheckElementValue(isolate, 0, jsobj, 5); 15446 15447 result = CompileRun("for (var i = 0; i < 8; i++) {" 15448 " pixels[8] = Infinity;" 15449 "}" 15450 "pixels[8];"); 15451 CHECK_EQ(255, result->Int32Value()); 15452 CheckElementValue(isolate, 255, jsobj, 8); 15453 15454 result = CompileRun("for (var i = 0; i < 8; i++) {" 15455 " pixels[9] = -Infinity;" 15456 "}" 15457 "pixels[9];"); 15458 CHECK_EQ(0, result->Int32Value()); 15459 CheckElementValue(isolate, 0, jsobj, 9); 15460 15461 result = CompileRun("pixels[3] = 33;" 15462 "delete pixels[3];" 15463 "pixels[3];"); 15464 CHECK_EQ(33, result->Int32Value()); 15465 15466 result = CompileRun("pixels[0] = 10; pixels[1] = 11;" 15467 "pixels[2] = 12; pixels[3] = 13;" 15468 "pixels.__defineGetter__('2'," 15469 "function() { return 120; });" 15470 "pixels[2];"); 15471 CHECK_EQ(12, result->Int32Value()); 15472 15473 result = CompileRun("var js_array = new Array(40);" 15474 "js_array[0] = 77;" 15475 "js_array;"); 15476 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15477 15478 result = CompileRun("pixels[1] = 23;" 15479 "pixels.__proto__ = [];" 15480 "js_array.__proto__ = pixels;" 15481 "js_array.concat(pixels);"); 15482 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15483 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 15484 15485 result = CompileRun("pixels[1] = 23;"); 15486 CHECK_EQ(23, result->Int32Value()); 15487 15488 // Test for index greater than 255. Regression test for: 15489 // http://code.google.com/p/chromium/issues/detail?id=26337. 15490 result = CompileRun("pixels[256] = 255;"); 15491 CHECK_EQ(255, result->Int32Value()); 15492 result = CompileRun("var i = 0;" 15493 "for (var j = 0; j < 8; j++) { i = pixels[256]; }" 15494 "i"); 15495 CHECK_EQ(255, result->Int32Value()); 15496 15497 // Make sure that pixel array ICs recognize when a non-pixel array 15498 // is passed to it. 15499 result = CompileRun("function pa_load(p) {" 15500 " var sum = 0;" 15501 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15502 " return sum;" 15503 "}" 15504 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15505 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15506 "just_ints = new Object();" 15507 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15508 "for (var i = 0; i < 10; ++i) {" 15509 " result = pa_load(just_ints);" 15510 "}" 15511 "result"); 15512 CHECK_EQ(32640, result->Int32Value()); 15513 15514 // Make sure that pixel array ICs recognize out-of-bound accesses. 15515 result = CompileRun("function pa_load(p, start) {" 15516 " var sum = 0;" 15517 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15518 " return sum;" 15519 "}" 15520 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15521 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15522 "for (var i = 0; i < 10; ++i) {" 15523 " result = pa_load(pixels,-10);" 15524 "}" 15525 "result"); 15526 CHECK_EQ(0, result->Int32Value()); 15527 15528 // Make sure that generic ICs properly handles a pixel array. 15529 result = CompileRun("function pa_load(p) {" 15530 " var sum = 0;" 15531 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15532 " return sum;" 15533 "}" 15534 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15535 "just_ints = new Object();" 15536 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15537 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 15538 "for (var i = 0; i < 10; ++i) {" 15539 " result = pa_load(pixels);" 15540 "}" 15541 "result"); 15542 CHECK_EQ(32640, result->Int32Value()); 15543 15544 // Make sure that generic load ICs recognize out-of-bound accesses in 15545 // pixel arrays. 15546 result = CompileRun("function pa_load(p, start) {" 15547 " var sum = 0;" 15548 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15549 " return sum;" 15550 "}" 15551 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15552 "just_ints = new Object();" 15553 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15554 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }" 15555 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15556 "for (var i = 0; i < 10; ++i) {" 15557 " result = pa_load(pixels,-10);" 15558 "}" 15559 "result"); 15560 CHECK_EQ(0, result->Int32Value()); 15561 15562 // Make sure that generic ICs properly handles other types than pixel 15563 // arrays (that the inlined fast pixel array test leaves the right information 15564 // in the right registers). 15565 result = CompileRun("function pa_load(p) {" 15566 " var sum = 0;" 15567 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15568 " return sum;" 15569 "}" 15570 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15571 "just_ints = new Object();" 15572 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15573 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 15574 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15575 "sparse_array = new Object();" 15576 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }" 15577 "sparse_array[1000000] = 3;" 15578 "for (var i = 0; i < 10; ++i) {" 15579 " result = pa_load(sparse_array);" 15580 "}" 15581 "result"); 15582 CHECK_EQ(32640, result->Int32Value()); 15583 15584 // Make sure that pixel array store ICs clamp values correctly. 15585 result = CompileRun("function pa_store(p) {" 15586 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 15587 "}" 15588 "pa_store(pixels);" 15589 "var sum = 0;" 15590 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15591 "sum"); 15592 CHECK_EQ(48896, result->Int32Value()); 15593 15594 // Make sure that pixel array stores correctly handle accesses outside 15595 // of the pixel array.. 15596 result = CompileRun("function pa_store(p,start) {" 15597 " for (var j = 0; j < 256; j++) {" 15598 " p[j+start] = j * 2;" 15599 " }" 15600 "}" 15601 "pa_store(pixels,0);" 15602 "pa_store(pixels,-128);" 15603 "var sum = 0;" 15604 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15605 "sum"); 15606 CHECK_EQ(65280, result->Int32Value()); 15607 15608 // Make sure that the generic store stub correctly handle accesses outside 15609 // of the pixel array.. 15610 result = CompileRun("function pa_store(p,start) {" 15611 " for (var j = 0; j < 256; j++) {" 15612 " p[j+start] = j * 2;" 15613 " }" 15614 "}" 15615 "pa_store(pixels,0);" 15616 "just_ints = new Object();" 15617 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15618 "pa_store(just_ints, 0);" 15619 "pa_store(pixels,-128);" 15620 "var sum = 0;" 15621 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15622 "sum"); 15623 CHECK_EQ(65280, result->Int32Value()); 15624 15625 // Make sure that the generic keyed store stub clamps pixel array values 15626 // correctly. 15627 result = CompileRun("function pa_store(p) {" 15628 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 15629 "}" 15630 "pa_store(pixels);" 15631 "just_ints = new Object();" 15632 "pa_store(just_ints);" 15633 "pa_store(pixels);" 15634 "var sum = 0;" 15635 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15636 "sum"); 15637 CHECK_EQ(48896, result->Int32Value()); 15638 15639 // Make sure that pixel array loads are optimized by crankshaft. 15640 result = CompileRun("function pa_load(p) {" 15641 " var sum = 0;" 15642 " for (var i=0; i<256; ++i) {" 15643 " sum += p[i];" 15644 " }" 15645 " return sum; " 15646 "}" 15647 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15648 "for (var i = 0; i < 5000; ++i) {" 15649 " result = pa_load(pixels);" 15650 "}" 15651 "result"); 15652 CHECK_EQ(32640, result->Int32Value()); 15653 15654 // Make sure that pixel array stores are optimized by crankshaft. 15655 result = CompileRun("function pa_init(p) {" 15656 "for (var i = 0; i < 256; ++i) { p[i] = i; }" 15657 "}" 15658 "function pa_load(p) {" 15659 " var sum = 0;" 15660 " for (var i=0; i<256; ++i) {" 15661 " sum += p[i];" 15662 " }" 15663 " return sum; " 15664 "}" 15665 "for (var i = 0; i < 5000; ++i) {" 15666 " pa_init(pixels);" 15667 "}" 15668 "result = pa_load(pixels);" 15669 "result"); 15670 CHECK_EQ(32640, result->Int32Value()); 15671 15672 free(pixel_data); 15673 } 15674 15675 15676 THREADED_TEST(PixelArrayInfo) { 15677 LocalContext context; 15678 v8::HandleScope scope(context->GetIsolate()); 15679 for (int size = 0; size < 100; size += 10) { 15680 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size)); 15681 v8::Handle<v8::Object> obj = v8::Object::New(); 15682 obj->SetIndexedPropertiesToPixelData(pixel_data, size); 15683 CHECK(obj->HasIndexedPropertiesInPixelData()); 15684 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData()); 15685 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength()); 15686 free(pixel_data); 15687 } 15688 } 15689 15690 15691 static void NotHandledIndexedPropertyGetter( 15692 uint32_t index, 15693 const v8::PropertyCallbackInfo<v8::Value>& info) { 15694 ApiTestFuzzer::Fuzz(); 15695 } 15696 15697 15698 static void NotHandledIndexedPropertySetter( 15699 uint32_t index, 15700 Local<Value> value, 15701 const v8::PropertyCallbackInfo<v8::Value>& info) { 15702 ApiTestFuzzer::Fuzz(); 15703 } 15704 15705 15706 THREADED_TEST(PixelArrayWithInterceptor) { 15707 LocalContext context; 15708 i::Factory* factory = CcTest::i_isolate()->factory(); 15709 v8::HandleScope scope(context->GetIsolate()); 15710 const int kElementCount = 260; 15711 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 15712 i::Handle<i::ExternalPixelArray> pixels = 15713 i::Handle<i::ExternalPixelArray>::cast( 15714 factory->NewExternalArray(kElementCount, 15715 v8::kExternalPixelArray, 15716 pixel_data)); 15717 for (int i = 0; i < kElementCount; i++) { 15718 pixels->set(i, i % 256); 15719 } 15720 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 15721 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter, 15722 NotHandledIndexedPropertySetter); 15723 v8::Handle<v8::Object> obj = templ->NewInstance(); 15724 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 15725 context->Global()->Set(v8_str("pixels"), obj); 15726 v8::Handle<v8::Value> result = CompileRun("pixels[1]"); 15727 CHECK_EQ(1, result->Int32Value()); 15728 result = CompileRun("var sum = 0;" 15729 "for (var i = 0; i < 8; i++) {" 15730 " sum += pixels[i] = pixels[i] = -i;" 15731 "}" 15732 "sum;"); 15733 CHECK_EQ(-28, result->Int32Value()); 15734 result = CompileRun("pixels.hasOwnProperty('1')"); 15735 CHECK(result->BooleanValue()); 15736 free(pixel_data); 15737 } 15738 15739 15740 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) { 15741 switch (array_type) { 15742 case v8::kExternalByteArray: 15743 case v8::kExternalUnsignedByteArray: 15744 case v8::kExternalPixelArray: 15745 return 1; 15746 break; 15747 case v8::kExternalShortArray: 15748 case v8::kExternalUnsignedShortArray: 15749 return 2; 15750 break; 15751 case v8::kExternalIntArray: 15752 case v8::kExternalUnsignedIntArray: 15753 case v8::kExternalFloatArray: 15754 return 4; 15755 break; 15756 case v8::kExternalDoubleArray: 15757 return 8; 15758 break; 15759 default: 15760 UNREACHABLE(); 15761 return -1; 15762 } 15763 UNREACHABLE(); 15764 return -1; 15765 } 15766 15767 15768 template <class ExternalArrayClass, class ElementType> 15769 static void ObjectWithExternalArrayTestHelper( 15770 Handle<Context> context, 15771 v8::Handle<Object> obj, 15772 int element_count, 15773 v8::ExternalArrayType array_type, 15774 int64_t low, int64_t high) { 15775 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15776 i::Isolate* isolate = jsobj->GetIsolate(); 15777 obj->Set(v8_str("field"), v8::Int32::New(1503)); 15778 context->Global()->Set(v8_str("ext_array"), obj); 15779 v8::Handle<v8::Value> result = CompileRun("ext_array.field"); 15780 CHECK_EQ(1503, result->Int32Value()); 15781 result = CompileRun("ext_array[1]"); 15782 CHECK_EQ(1, result->Int32Value()); 15783 15784 // Check pass through of assigned smis 15785 result = CompileRun("var sum = 0;" 15786 "for (var i = 0; i < 8; i++) {" 15787 " sum += ext_array[i] = ext_array[i] = -i;" 15788 "}" 15789 "sum;"); 15790 CHECK_EQ(-28, result->Int32Value()); 15791 15792 // Check assigned smis 15793 result = CompileRun("for (var i = 0; i < 8; i++) {" 15794 " ext_array[i] = i;" 15795 "}" 15796 "var sum = 0;" 15797 "for (var i = 0; i < 8; i++) {" 15798 " sum += ext_array[i];" 15799 "}" 15800 "sum;"); 15801 CHECK_EQ(28, result->Int32Value()); 15802 15803 // Check assigned smis in reverse order 15804 result = CompileRun("for (var i = 8; --i >= 0; ) {" 15805 " ext_array[i] = i;" 15806 "}" 15807 "var sum = 0;" 15808 "for (var i = 0; i < 8; i++) {" 15809 " sum += ext_array[i];" 15810 "}" 15811 "sum;"); 15812 CHECK_EQ(28, result->Int32Value()); 15813 15814 // Check pass through of assigned HeapNumbers 15815 result = CompileRun("var sum = 0;" 15816 "for (var i = 0; i < 16; i+=2) {" 15817 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 15818 "}" 15819 "sum;"); 15820 CHECK_EQ(-28, result->Int32Value()); 15821 15822 // Check assigned HeapNumbers 15823 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 15824 " ext_array[i] = (i * 0.5);" 15825 "}" 15826 "var sum = 0;" 15827 "for (var i = 0; i < 16; i+=2) {" 15828 " sum += ext_array[i];" 15829 "}" 15830 "sum;"); 15831 CHECK_EQ(28, result->Int32Value()); 15832 15833 // Check assigned HeapNumbers in reverse order 15834 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 15835 " ext_array[i] = (i * 0.5);" 15836 "}" 15837 "var sum = 0;" 15838 "for (var i = 0; i < 16; i+=2) {" 15839 " sum += ext_array[i];" 15840 "}" 15841 "sum;"); 15842 CHECK_EQ(28, result->Int32Value()); 15843 15844 i::ScopedVector<char> test_buf(1024); 15845 15846 // Check legal boundary conditions. 15847 // The repeated loads and stores ensure the ICs are exercised. 15848 const char* boundary_program = 15849 "var res = 0;" 15850 "for (var i = 0; i < 16; i++) {" 15851 " ext_array[i] = %lld;" 15852 " if (i > 8) {" 15853 " res = ext_array[i];" 15854 " }" 15855 "}" 15856 "res;"; 15857 i::OS::SNPrintF(test_buf, 15858 boundary_program, 15859 low); 15860 result = CompileRun(test_buf.start()); 15861 CHECK_EQ(low, result->IntegerValue()); 15862 15863 i::OS::SNPrintF(test_buf, 15864 boundary_program, 15865 high); 15866 result = CompileRun(test_buf.start()); 15867 CHECK_EQ(high, result->IntegerValue()); 15868 15869 // Check misprediction of type in IC. 15870 result = CompileRun("var tmp_array = ext_array;" 15871 "var sum = 0;" 15872 "for (var i = 0; i < 8; i++) {" 15873 " tmp_array[i] = i;" 15874 " sum += tmp_array[i];" 15875 " if (i == 4) {" 15876 " tmp_array = {};" 15877 " }" 15878 "}" 15879 "sum;"); 15880 // Force GC to trigger verification. 15881 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 15882 CHECK_EQ(28, result->Int32Value()); 15883 15884 // Make sure out-of-range loads do not throw. 15885 i::OS::SNPrintF(test_buf, 15886 "var caught_exception = false;" 15887 "try {" 15888 " ext_array[%d];" 15889 "} catch (e) {" 15890 " caught_exception = true;" 15891 "}" 15892 "caught_exception;", 15893 element_count); 15894 result = CompileRun(test_buf.start()); 15895 CHECK_EQ(false, result->BooleanValue()); 15896 15897 // Make sure out-of-range stores do not throw. 15898 i::OS::SNPrintF(test_buf, 15899 "var caught_exception = false;" 15900 "try {" 15901 " ext_array[%d] = 1;" 15902 "} catch (e) {" 15903 " caught_exception = true;" 15904 "}" 15905 "caught_exception;", 15906 element_count); 15907 result = CompileRun(test_buf.start()); 15908 CHECK_EQ(false, result->BooleanValue()); 15909 15910 // Check other boundary conditions, values and operations. 15911 result = CompileRun("for (var i = 0; i < 8; i++) {" 15912 " ext_array[7] = undefined;" 15913 "}" 15914 "ext_array[7];"); 15915 CHECK_EQ(0, result->Int32Value()); 15916 if (array_type == v8::kExternalDoubleArray || 15917 array_type == v8::kExternalFloatArray) { 15918 CHECK_EQ(static_cast<int>(i::OS::nan_value()), 15919 static_cast<int>( 15920 jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number())); 15921 } else { 15922 CheckElementValue(isolate, 0, jsobj, 7); 15923 } 15924 15925 result = CompileRun("for (var i = 0; i < 8; i++) {" 15926 " ext_array[6] = '2.3';" 15927 "}" 15928 "ext_array[6];"); 15929 CHECK_EQ(2, result->Int32Value()); 15930 CHECK_EQ(2, 15931 static_cast<int>( 15932 jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number())); 15933 15934 if (array_type != v8::kExternalFloatArray && 15935 array_type != v8::kExternalDoubleArray) { 15936 // Though the specification doesn't state it, be explicit about 15937 // converting NaNs and +/-Infinity to zero. 15938 result = CompileRun("for (var i = 0; i < 8; i++) {" 15939 " ext_array[i] = 5;" 15940 "}" 15941 "for (var i = 0; i < 8; i++) {" 15942 " ext_array[i] = NaN;" 15943 "}" 15944 "ext_array[5];"); 15945 CHECK_EQ(0, result->Int32Value()); 15946 CheckElementValue(isolate, 0, jsobj, 5); 15947 15948 result = CompileRun("for (var i = 0; i < 8; i++) {" 15949 " ext_array[i] = 5;" 15950 "}" 15951 "for (var i = 0; i < 8; i++) {" 15952 " ext_array[i] = Infinity;" 15953 "}" 15954 "ext_array[5];"); 15955 int expected_value = 15956 (array_type == v8::kExternalPixelArray) ? 255 : 0; 15957 CHECK_EQ(expected_value, result->Int32Value()); 15958 CheckElementValue(isolate, expected_value, jsobj, 5); 15959 15960 result = CompileRun("for (var i = 0; i < 8; i++) {" 15961 " ext_array[i] = 5;" 15962 "}" 15963 "for (var i = 0; i < 8; i++) {" 15964 " ext_array[i] = -Infinity;" 15965 "}" 15966 "ext_array[5];"); 15967 CHECK_EQ(0, result->Int32Value()); 15968 CheckElementValue(isolate, 0, jsobj, 5); 15969 15970 // Check truncation behavior of integral arrays. 15971 const char* unsigned_data = 15972 "var source_data = [0.6, 10.6];" 15973 "var expected_results = [0, 10];"; 15974 const char* signed_data = 15975 "var source_data = [0.6, 10.6, -0.6, -10.6];" 15976 "var expected_results = [0, 10, 0, -10];"; 15977 const char* pixel_data = 15978 "var source_data = [0.6, 10.6];" 15979 "var expected_results = [1, 11];"; 15980 bool is_unsigned = 15981 (array_type == v8::kExternalUnsignedByteArray || 15982 array_type == v8::kExternalUnsignedShortArray || 15983 array_type == v8::kExternalUnsignedIntArray); 15984 bool is_pixel_data = array_type == v8::kExternalPixelArray; 15985 15986 i::OS::SNPrintF(test_buf, 15987 "%s" 15988 "var all_passed = true;" 15989 "for (var i = 0; i < source_data.length; i++) {" 15990 " for (var j = 0; j < 8; j++) {" 15991 " ext_array[j] = source_data[i];" 15992 " }" 15993 " all_passed = all_passed &&" 15994 " (ext_array[5] == expected_results[i]);" 15995 "}" 15996 "all_passed;", 15997 (is_unsigned ? 15998 unsigned_data : 15999 (is_pixel_data ? pixel_data : signed_data))); 16000 result = CompileRun(test_buf.start()); 16001 CHECK_EQ(true, result->BooleanValue()); 16002 } 16003 16004 i::Handle<ExternalArrayClass> array( 16005 ExternalArrayClass::cast(jsobj->elements())); 16006 for (int i = 0; i < element_count; i++) { 16007 array->set(i, static_cast<ElementType>(i)); 16008 } 16009 16010 // Test complex assignments 16011 result = CompileRun("function ee_op_test_complex_func(sum) {" 16012 " for (var i = 0; i < 40; ++i) {" 16013 " sum += (ext_array[i] += 1);" 16014 " sum += (ext_array[i] -= 1);" 16015 " } " 16016 " return sum;" 16017 "}" 16018 "sum=0;" 16019 "for (var i=0;i<10000;++i) {" 16020 " sum=ee_op_test_complex_func(sum);" 16021 "}" 16022 "sum;"); 16023 CHECK_EQ(16000000, result->Int32Value()); 16024 16025 // Test count operations 16026 result = CompileRun("function ee_op_test_count_func(sum) {" 16027 " for (var i = 0; i < 40; ++i) {" 16028 " sum += (++ext_array[i]);" 16029 " sum += (--ext_array[i]);" 16030 " } " 16031 " return sum;" 16032 "}" 16033 "sum=0;" 16034 "for (var i=0;i<10000;++i) {" 16035 " sum=ee_op_test_count_func(sum);" 16036 "}" 16037 "sum;"); 16038 CHECK_EQ(16000000, result->Int32Value()); 16039 16040 result = CompileRun("ext_array[3] = 33;" 16041 "delete ext_array[3];" 16042 "ext_array[3];"); 16043 CHECK_EQ(33, result->Int32Value()); 16044 16045 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 16046 "ext_array[2] = 12; ext_array[3] = 13;" 16047 "ext_array.__defineGetter__('2'," 16048 "function() { return 120; });" 16049 "ext_array[2];"); 16050 CHECK_EQ(12, result->Int32Value()); 16051 16052 result = CompileRun("var js_array = new Array(40);" 16053 "js_array[0] = 77;" 16054 "js_array;"); 16055 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16056 16057 result = CompileRun("ext_array[1] = 23;" 16058 "ext_array.__proto__ = [];" 16059 "js_array.__proto__ = ext_array;" 16060 "js_array.concat(ext_array);"); 16061 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 16062 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 16063 16064 result = CompileRun("ext_array[1] = 23;"); 16065 CHECK_EQ(23, result->Int32Value()); 16066 } 16067 16068 16069 template <class ExternalArrayClass, class ElementType> 16070 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, 16071 int64_t low, 16072 int64_t high) { 16073 LocalContext context; 16074 i::Isolate* isolate = CcTest::i_isolate(); 16075 i::Factory* factory = isolate->factory(); 16076 v8::HandleScope scope(context->GetIsolate()); 16077 const int kElementCount = 40; 16078 int element_size = ExternalArrayElementSize(array_type); 16079 ElementType* array_data = 16080 static_cast<ElementType*>(malloc(kElementCount * element_size)); 16081 i::Handle<ExternalArrayClass> array = 16082 i::Handle<ExternalArrayClass>::cast( 16083 factory->NewExternalArray(kElementCount, array_type, array_data)); 16084 // Force GC to trigger verification. 16085 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16086 for (int i = 0; i < kElementCount; i++) { 16087 array->set(i, static_cast<ElementType>(i)); 16088 } 16089 // Force GC to trigger verification. 16090 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 16091 for (int i = 0; i < kElementCount; i++) { 16092 CHECK_EQ(static_cast<int64_t>(i), 16093 static_cast<int64_t>(array->get_scalar(i))); 16094 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); 16095 } 16096 16097 v8::Handle<v8::Object> obj = v8::Object::New(); 16098 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 16099 // Set the elements to be the external array. 16100 obj->SetIndexedPropertiesToExternalArrayData(array_data, 16101 array_type, 16102 kElementCount); 16103 CHECK_EQ(1, 16104 static_cast<int>( 16105 jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number())); 16106 16107 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16108 context.local(), obj, kElementCount, array_type, low, high); 16109 16110 v8::Handle<v8::Value> result; 16111 16112 // Test more complex manipulations which cause eax to contain values 16113 // that won't be completely overwritten by loads from the arrays. 16114 // This catches bugs in the instructions used for the KeyedLoadIC 16115 // for byte and word types. 16116 { 16117 const int kXSize = 300; 16118 const int kYSize = 300; 16119 const int kLargeElementCount = kXSize * kYSize * 4; 16120 ElementType* large_array_data = 16121 static_cast<ElementType*>(malloc(kLargeElementCount * element_size)); 16122 v8::Handle<v8::Object> large_obj = v8::Object::New(); 16123 // Set the elements to be the external array. 16124 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data, 16125 array_type, 16126 kLargeElementCount); 16127 context->Global()->Set(v8_str("large_array"), large_obj); 16128 // Initialize contents of a few rows. 16129 for (int x = 0; x < 300; x++) { 16130 int row = 0; 16131 int offset = row * 300 * 4; 16132 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16133 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16134 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16135 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16136 row = 150; 16137 offset = row * 300 * 4; 16138 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16139 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16140 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16141 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16142 row = 298; 16143 offset = row * 300 * 4; 16144 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 16145 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 16146 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 16147 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 16148 } 16149 // The goal of the code below is to make "offset" large enough 16150 // that the computation of the index (which goes into eax) has 16151 // high bits set which will not be overwritten by a byte or short 16152 // load. 16153 result = CompileRun("var failed = false;" 16154 "var offset = 0;" 16155 "for (var i = 0; i < 300; i++) {" 16156 " if (large_array[4 * i] != 127 ||" 16157 " large_array[4 * i + 1] != 0 ||" 16158 " large_array[4 * i + 2] != 0 ||" 16159 " large_array[4 * i + 3] != 127) {" 16160 " failed = true;" 16161 " }" 16162 "}" 16163 "offset = 150 * 300 * 4;" 16164 "for (var i = 0; i < 300; i++) {" 16165 " if (large_array[offset + 4 * i] != 127 ||" 16166 " large_array[offset + 4 * i + 1] != 0 ||" 16167 " large_array[offset + 4 * i + 2] != 0 ||" 16168 " large_array[offset + 4 * i + 3] != 127) {" 16169 " failed = true;" 16170 " }" 16171 "}" 16172 "offset = 298 * 300 * 4;" 16173 "for (var i = 0; i < 300; i++) {" 16174 " if (large_array[offset + 4 * i] != 127 ||" 16175 " large_array[offset + 4 * i + 1] != 0 ||" 16176 " large_array[offset + 4 * i + 2] != 0 ||" 16177 " large_array[offset + 4 * i + 3] != 127) {" 16178 " failed = true;" 16179 " }" 16180 "}" 16181 "!failed;"); 16182 CHECK_EQ(true, result->BooleanValue()); 16183 free(large_array_data); 16184 } 16185 16186 // The "" property descriptor is overloaded to store information about 16187 // the external array. Ensure that setting and accessing the "" property 16188 // works (it should overwrite the information cached about the external 16189 // array in the DescriptorArray) in various situations. 16190 result = CompileRun("ext_array[''] = 23; ext_array['']"); 16191 CHECK_EQ(23, result->Int32Value()); 16192 16193 // Property "" set after the external array is associated with the object. 16194 { 16195 v8::Handle<v8::Object> obj2 = v8::Object::New(); 16196 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256)); 16197 obj2->Set(v8_str(""), v8::Int32::New(1503)); 16198 // Set the elements to be the external array. 16199 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16200 array_type, 16201 kElementCount); 16202 context->Global()->Set(v8_str("ext_array"), obj2); 16203 result = CompileRun("ext_array['']"); 16204 CHECK_EQ(1503, result->Int32Value()); 16205 } 16206 16207 // Property "" set after the external array is associated with the object. 16208 { 16209 v8::Handle<v8::Object> obj2 = v8::Object::New(); 16210 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 16211 // Set the elements to be the external array. 16212 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16213 array_type, 16214 kElementCount); 16215 obj2->Set(v8_str(""), v8::Int32::New(1503)); 16216 context->Global()->Set(v8_str("ext_array"), obj2); 16217 result = CompileRun("ext_array['']"); 16218 CHECK_EQ(1503, result->Int32Value()); 16219 } 16220 16221 // Should reuse the map from previous test. 16222 { 16223 v8::Handle<v8::Object> obj2 = v8::Object::New(); 16224 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 16225 // Set the elements to be the external array. Should re-use the map 16226 // from previous test. 16227 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 16228 array_type, 16229 kElementCount); 16230 context->Global()->Set(v8_str("ext_array"), obj2); 16231 result = CompileRun("ext_array['']"); 16232 } 16233 16234 // Property "" is a constant function that shouldn't not be interfered with 16235 // when an external array is set. 16236 { 16237 v8::Handle<v8::Object> obj2 = v8::Object::New(); 16238 // Start 16239 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 16240 16241 // Add a constant function to an object. 16242 context->Global()->Set(v8_str("ext_array"), obj2); 16243 result = CompileRun("ext_array[''] = function() {return 1503;};" 16244 "ext_array['']();"); 16245 16246 // Add an external array transition to the same map that 16247 // has the constant transition. 16248 v8::Handle<v8::Object> obj3 = v8::Object::New(); 16249 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 16250 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16251 array_type, 16252 kElementCount); 16253 context->Global()->Set(v8_str("ext_array"), obj3); 16254 } 16255 16256 // If a external array transition is in the map, it should get clobbered 16257 // by a constant function. 16258 { 16259 // Add an external array transition. 16260 v8::Handle<v8::Object> obj3 = v8::Object::New(); 16261 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 16262 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 16263 array_type, 16264 kElementCount); 16265 16266 // Add a constant function to the same map that just got an external array 16267 // transition. 16268 v8::Handle<v8::Object> obj2 = v8::Object::New(); 16269 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 16270 context->Global()->Set(v8_str("ext_array"), obj2); 16271 result = CompileRun("ext_array[''] = function() {return 1503;};" 16272 "ext_array['']();"); 16273 } 16274 16275 free(array_data); 16276 } 16277 16278 16279 THREADED_TEST(ExternalByteArray) { 16280 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>( 16281 v8::kExternalByteArray, 16282 -128, 16283 127); 16284 } 16285 16286 16287 THREADED_TEST(ExternalUnsignedByteArray) { 16288 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>( 16289 v8::kExternalUnsignedByteArray, 16290 0, 16291 255); 16292 } 16293 16294 16295 THREADED_TEST(ExternalPixelArray) { 16296 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>( 16297 v8::kExternalPixelArray, 16298 0, 16299 255); 16300 } 16301 16302 16303 THREADED_TEST(ExternalShortArray) { 16304 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>( 16305 v8::kExternalShortArray, 16306 -32768, 16307 32767); 16308 } 16309 16310 16311 THREADED_TEST(ExternalUnsignedShortArray) { 16312 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>( 16313 v8::kExternalUnsignedShortArray, 16314 0, 16315 65535); 16316 } 16317 16318 16319 THREADED_TEST(ExternalIntArray) { 16320 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>( 16321 v8::kExternalIntArray, 16322 INT_MIN, // -2147483648 16323 INT_MAX); // 2147483647 16324 } 16325 16326 16327 THREADED_TEST(ExternalUnsignedIntArray) { 16328 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>( 16329 v8::kExternalUnsignedIntArray, 16330 0, 16331 UINT_MAX); // 4294967295 16332 } 16333 16334 16335 THREADED_TEST(ExternalFloatArray) { 16336 ExternalArrayTestHelper<i::ExternalFloatArray, float>( 16337 v8::kExternalFloatArray, 16338 -500, 16339 500); 16340 } 16341 16342 16343 THREADED_TEST(ExternalDoubleArray) { 16344 ExternalArrayTestHelper<i::ExternalDoubleArray, double>( 16345 v8::kExternalDoubleArray, 16346 -500, 16347 500); 16348 } 16349 16350 16351 THREADED_TEST(ExternalArrays) { 16352 TestExternalByteArray(); 16353 TestExternalUnsignedByteArray(); 16354 TestExternalShortArray(); 16355 TestExternalUnsignedShortArray(); 16356 TestExternalIntArray(); 16357 TestExternalUnsignedIntArray(); 16358 TestExternalFloatArray(); 16359 } 16360 16361 16362 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) { 16363 LocalContext context; 16364 v8::HandleScope scope(context->GetIsolate()); 16365 for (int size = 0; size < 100; size += 10) { 16366 int element_size = ExternalArrayElementSize(array_type); 16367 void* external_data = malloc(size * element_size); 16368 v8::Handle<v8::Object> obj = v8::Object::New(); 16369 obj->SetIndexedPropertiesToExternalArrayData( 16370 external_data, array_type, size); 16371 CHECK(obj->HasIndexedPropertiesInExternalArrayData()); 16372 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData()); 16373 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType()); 16374 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength()); 16375 free(external_data); 16376 } 16377 } 16378 16379 16380 THREADED_TEST(ExternalArrayInfo) { 16381 ExternalArrayInfoTestHelper(v8::kExternalByteArray); 16382 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray); 16383 ExternalArrayInfoTestHelper(v8::kExternalShortArray); 16384 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray); 16385 ExternalArrayInfoTestHelper(v8::kExternalIntArray); 16386 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray); 16387 ExternalArrayInfoTestHelper(v8::kExternalFloatArray); 16388 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray); 16389 ExternalArrayInfoTestHelper(v8::kExternalPixelArray); 16390 } 16391 16392 16393 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) { 16394 v8::Handle<v8::Object> obj = v8::Object::New(); 16395 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 16396 last_location = last_message = NULL; 16397 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size); 16398 CHECK(!obj->HasIndexedPropertiesInExternalArrayData()); 16399 CHECK_NE(NULL, last_location); 16400 CHECK_NE(NULL, last_message); 16401 } 16402 16403 16404 TEST(ExternalArrayLimits) { 16405 LocalContext context; 16406 v8::HandleScope scope(context->GetIsolate()); 16407 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000); 16408 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff); 16409 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000); 16410 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff); 16411 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000); 16412 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff); 16413 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000); 16414 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff); 16415 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000); 16416 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff); 16417 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000); 16418 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff); 16419 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000); 16420 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff); 16421 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000); 16422 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff); 16423 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000); 16424 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff); 16425 } 16426 16427 16428 template <typename ElementType, typename TypedArray, 16429 class ExternalArrayClass> 16430 void TypedArrayTestHelper(v8::ExternalArrayType array_type, 16431 int64_t low, int64_t high) { 16432 const int kElementCount = 50; 16433 16434 i::ScopedVector<ElementType> backing_store(kElementCount+2); 16435 16436 LocalContext env; 16437 v8::Isolate* isolate = env->GetIsolate(); 16438 v8::HandleScope handle_scope(isolate); 16439 16440 Local<v8::ArrayBuffer> ab = 16441 v8::ArrayBuffer::New(isolate, backing_store.start(), 16442 (kElementCount + 2) * sizeof(ElementType)); 16443 Local<TypedArray> ta = 16444 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 16445 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 16446 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 16447 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset())); 16448 CHECK_EQ(kElementCount*sizeof(ElementType), 16449 static_cast<int>(ta->ByteLength())); 16450 CHECK_EQ(ab, ta->Buffer()); 16451 16452 ElementType* data = backing_store.start() + 2; 16453 for (int i = 0; i < kElementCount; i++) { 16454 data[i] = static_cast<ElementType>(i); 16455 } 16456 16457 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16458 env.local(), ta, kElementCount, array_type, low, high); 16459 } 16460 16461 16462 THREADED_TEST(Uint8Array) { 16463 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>( 16464 v8::kExternalUnsignedByteArray, 0, 0xFF); 16465 } 16466 16467 16468 THREADED_TEST(Int8Array) { 16469 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>( 16470 v8::kExternalByteArray, -0x80, 0x7F); 16471 } 16472 16473 16474 THREADED_TEST(Uint16Array) { 16475 TypedArrayTestHelper<uint16_t, 16476 v8::Uint16Array, 16477 i::ExternalUnsignedShortArray>( 16478 v8::kExternalUnsignedShortArray, 0, 0xFFFF); 16479 } 16480 16481 16482 THREADED_TEST(Int16Array) { 16483 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>( 16484 v8::kExternalShortArray, -0x8000, 0x7FFF); 16485 } 16486 16487 16488 THREADED_TEST(Uint32Array) { 16489 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>( 16490 v8::kExternalUnsignedIntArray, 0, UINT_MAX); 16491 } 16492 16493 16494 THREADED_TEST(Int32Array) { 16495 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>( 16496 v8::kExternalIntArray, INT_MIN, INT_MAX); 16497 } 16498 16499 16500 THREADED_TEST(Float32Array) { 16501 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>( 16502 v8::kExternalFloatArray, -500, 500); 16503 } 16504 16505 16506 THREADED_TEST(Float64Array) { 16507 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>( 16508 v8::kExternalDoubleArray, -500, 500); 16509 } 16510 16511 16512 THREADED_TEST(Uint8ClampedArray) { 16513 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>( 16514 v8::kExternalPixelArray, 0, 0xFF); 16515 } 16516 16517 16518 THREADED_TEST(DataView) { 16519 const int kSize = 50; 16520 16521 i::ScopedVector<uint8_t> backing_store(kSize+2); 16522 16523 LocalContext env; 16524 v8::Isolate* isolate = env->GetIsolate(); 16525 v8::HandleScope handle_scope(isolate); 16526 16527 Local<v8::ArrayBuffer> ab = 16528 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize); 16529 Local<v8::DataView> dv = 16530 v8::DataView::New(ab, 2, kSize); 16531 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 16532 CHECK_EQ(2, static_cast<int>(dv->ByteOffset())); 16533 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 16534 CHECK_EQ(ab, dv->Buffer()); 16535 } 16536 16537 16538 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 16539 THREADED_TEST(Is##View) { \ 16540 LocalContext env; \ 16541 v8::Isolate* isolate = env->GetIsolate(); \ 16542 v8::HandleScope handle_scope(isolate); \ 16543 \ 16544 Handle<Value> result = CompileRun( \ 16545 "var ab = new ArrayBuffer(128);" \ 16546 "new " #View "(ab)"); \ 16547 CHECK(result->IsArrayBufferView()); \ 16548 CHECK(result->Is##View()); \ 16549 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 16550 } 16551 16552 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 16553 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 16554 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 16555 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 16556 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 16557 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 16558 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 16559 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 16560 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 16561 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 16562 16563 #undef IS_ARRAY_BUFFER_VIEW_TEST 16564 16565 16566 16567 THREADED_TEST(ScriptContextDependence) { 16568 LocalContext c1; 16569 v8::HandleScope scope(c1->GetIsolate()); 16570 const char *source = "foo"; 16571 v8::Handle<v8::Script> dep = 16572 v8::Script::Compile(v8::String::NewFromUtf8(c1->GetIsolate(), source)); 16573 v8::Handle<v8::Script> indep = 16574 v8::Script::New(v8::String::NewFromUtf8(c1->GetIsolate(), source)); 16575 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"), 16576 v8::Integer::New(100)); 16577 CHECK_EQ(dep->Run()->Int32Value(), 100); 16578 CHECK_EQ(indep->Run()->Int32Value(), 100); 16579 LocalContext c2; 16580 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"), 16581 v8::Integer::New(101)); 16582 CHECK_EQ(dep->Run()->Int32Value(), 100); 16583 CHECK_EQ(indep->Run()->Int32Value(), 101); 16584 } 16585 16586 16587 THREADED_TEST(StackTrace) { 16588 LocalContext context; 16589 v8::HandleScope scope(context->GetIsolate()); 16590 v8::TryCatch try_catch; 16591 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 16592 v8::Handle<v8::String> src = 16593 v8::String::NewFromUtf8(context->GetIsolate(), source); 16594 v8::Handle<v8::String> origin = 16595 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test"); 16596 v8::Script::New(src, origin)->Run(); 16597 CHECK(try_catch.HasCaught()); 16598 v8::String::Utf8Value stack(try_catch.StackTrace()); 16599 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 16600 } 16601 16602 16603 // Checks that a StackFrame has certain expected values. 16604 void checkStackFrame(const char* expected_script_name, 16605 const char* expected_func_name, int expected_line_number, 16606 int expected_column, bool is_eval, bool is_constructor, 16607 v8::Handle<v8::StackFrame> frame) { 16608 v8::HandleScope scope(CcTest::isolate()); 16609 v8::String::Utf8Value func_name(frame->GetFunctionName()); 16610 v8::String::Utf8Value script_name(frame->GetScriptName()); 16611 if (*script_name == NULL) { 16612 // The situation where there is no associated script, like for evals. 16613 CHECK(expected_script_name == NULL); 16614 } else { 16615 CHECK(strstr(*script_name, expected_script_name) != NULL); 16616 } 16617 CHECK(strstr(*func_name, expected_func_name) != NULL); 16618 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 16619 CHECK_EQ(expected_column, frame->GetColumn()); 16620 CHECK_EQ(is_eval, frame->IsEval()); 16621 CHECK_EQ(is_constructor, frame->IsConstructor()); 16622 } 16623 16624 16625 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 16626 v8::HandleScope scope(args.GetIsolate()); 16627 const char* origin = "capture-stack-trace-test"; 16628 const int kOverviewTest = 1; 16629 const int kDetailedTest = 2; 16630 16631 ASSERT(args.Length() == 1); 16632 16633 int testGroup = args[0]->Int32Value(); 16634 if (testGroup == kOverviewTest) { 16635 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16636 args.GetIsolate(), 10, v8::StackTrace::kOverview); 16637 CHECK_EQ(4, stackTrace->GetFrameCount()); 16638 checkStackFrame(origin, "bar", 2, 10, false, false, 16639 stackTrace->GetFrame(0)); 16640 checkStackFrame(origin, "foo", 6, 3, false, false, 16641 stackTrace->GetFrame(1)); 16642 // This is the source string inside the eval which has the call to foo. 16643 checkStackFrame(NULL, "", 1, 5, false, false, 16644 stackTrace->GetFrame(2)); 16645 // The last frame is an anonymous function which has the initial eval call. 16646 checkStackFrame(origin, "", 8, 7, false, false, 16647 stackTrace->GetFrame(3)); 16648 16649 CHECK(stackTrace->AsArray()->IsArray()); 16650 } else if (testGroup == kDetailedTest) { 16651 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16652 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 16653 CHECK_EQ(4, stackTrace->GetFrameCount()); 16654 checkStackFrame(origin, "bat", 4, 22, false, false, 16655 stackTrace->GetFrame(0)); 16656 checkStackFrame(origin, "baz", 8, 3, false, true, 16657 stackTrace->GetFrame(1)); 16658 #ifdef ENABLE_DEBUGGER_SUPPORT 16659 bool is_eval = true; 16660 #else // ENABLE_DEBUGGER_SUPPORT 16661 bool is_eval = false; 16662 #endif // ENABLE_DEBUGGER_SUPPORT 16663 16664 // This is the source string inside the eval which has the call to baz. 16665 checkStackFrame(NULL, "", 1, 5, is_eval, false, 16666 stackTrace->GetFrame(2)); 16667 // The last frame is an anonymous function which has the initial eval call. 16668 checkStackFrame(origin, "", 10, 1, false, false, 16669 stackTrace->GetFrame(3)); 16670 16671 CHECK(stackTrace->AsArray()->IsArray()); 16672 } 16673 } 16674 16675 16676 // Tests the C++ StackTrace API. 16677 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 16678 // THREADED_TEST(CaptureStackTrace) { 16679 TEST(CaptureStackTrace) { 16680 v8::HandleScope scope(CcTest::isolate()); 16681 v8::Handle<v8::String> origin = 16682 v8::String::NewFromUtf8(CcTest::isolate(), "capture-stack-trace-test"); 16683 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16684 templ->Set(v8_str("AnalyzeStackInNativeCode"), 16685 v8::FunctionTemplate::New(AnalyzeStackInNativeCode)); 16686 LocalContext context(0, templ); 16687 16688 // Test getting OVERVIEW information. Should ignore information that is not 16689 // script name, function name, line number, and column offset. 16690 const char *overview_source = 16691 "function bar() {\n" 16692 " var y; AnalyzeStackInNativeCode(1);\n" 16693 "}\n" 16694 "function foo() {\n" 16695 "\n" 16696 " bar();\n" 16697 "}\n" 16698 "var x;eval('new foo();');"; 16699 v8::Handle<v8::String> overview_src = 16700 v8::String::NewFromUtf8(CcTest::isolate(), overview_source); 16701 v8::Handle<Value> overview_result( 16702 v8::Script::New(overview_src, origin)->Run()); 16703 CHECK(!overview_result.IsEmpty()); 16704 CHECK(overview_result->IsObject()); 16705 16706 // Test getting DETAILED information. 16707 const char *detailed_source = 16708 "function bat() {AnalyzeStackInNativeCode(2);\n" 16709 "}\n" 16710 "\n" 16711 "function baz() {\n" 16712 " bat();\n" 16713 "}\n" 16714 "eval('new baz();');"; 16715 v8::Handle<v8::String> detailed_src = 16716 v8::String::NewFromUtf8(CcTest::isolate(), detailed_source); 16717 // Make the script using a non-zero line and column offset. 16718 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3); 16719 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5); 16720 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 16721 v8::Handle<v8::Script> detailed_script( 16722 v8::Script::New(detailed_src, &detailed_origin)); 16723 v8::Handle<Value> detailed_result(detailed_script->Run()); 16724 CHECK(!detailed_result.IsEmpty()); 16725 CHECK(detailed_result->IsObject()); 16726 } 16727 16728 16729 static void StackTraceForUncaughtExceptionListener( 16730 v8::Handle<v8::Message> message, 16731 v8::Handle<Value>) { 16732 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16733 CHECK_EQ(2, stack_trace->GetFrameCount()); 16734 checkStackFrame("origin", "foo", 2, 3, false, false, 16735 stack_trace->GetFrame(0)); 16736 checkStackFrame("origin", "bar", 5, 3, false, false, 16737 stack_trace->GetFrame(1)); 16738 } 16739 16740 16741 TEST(CaptureStackTraceForUncaughtException) { 16742 report_count = 0; 16743 LocalContext env; 16744 v8::HandleScope scope(env->GetIsolate()); 16745 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener); 16746 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16747 16748 Script::Compile(v8_str("function foo() {\n" 16749 " throw 1;\n" 16750 "};\n" 16751 "function bar() {\n" 16752 " foo();\n" 16753 "};"), 16754 v8_str("origin"))->Run(); 16755 v8::Local<v8::Object> global = env->Global(); 16756 Local<Value> trouble = global->Get(v8_str("bar")); 16757 CHECK(trouble->IsFunction()); 16758 Function::Cast(*trouble)->Call(global, 0, NULL); 16759 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16760 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 16761 } 16762 16763 16764 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 16765 LocalContext env; 16766 v8::HandleScope scope(env->GetIsolate()); 16767 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, 16768 1024, 16769 v8::StackTrace::kDetailed); 16770 16771 CompileRun( 16772 "var setters = ['column', 'lineNumber', 'scriptName',\n" 16773 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 16774 " 'isConstructor'];\n" 16775 "for (var i = 0; i < setters.length; i++) {\n" 16776 " var prop = setters[i];\n" 16777 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 16778 "}\n"); 16779 CompileRun("throw 'exception';"); 16780 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16781 } 16782 16783 16784 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message, 16785 v8::Handle<v8::Value> data) { 16786 // Use the frame where JavaScript is called from. 16787 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16788 CHECK(!stack_trace.IsEmpty()); 16789 int frame_count = stack_trace->GetFrameCount(); 16790 CHECK_EQ(3, frame_count); 16791 int line_number[] = {1, 2, 5}; 16792 for (int i = 0; i < frame_count; i++) { 16793 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16794 } 16795 } 16796 16797 16798 // Test that we only return the stack trace at the site where the exception 16799 // is first thrown (not where it is rethrown). 16800 TEST(RethrowStackTrace) { 16801 LocalContext env; 16802 v8::HandleScope scope(env->GetIsolate()); 16803 // We make sure that 16804 // - the stack trace of the ReferenceError in g() is reported. 16805 // - the stack trace is not overwritten when e1 is rethrown by t(). 16806 // - the stack trace of e2 does not overwrite that of e1. 16807 const char* source = 16808 "function g() { error; } \n" 16809 "function f() { g(); } \n" 16810 "function t(e) { throw e; } \n" 16811 "try { \n" 16812 " f(); \n" 16813 "} catch (e1) { \n" 16814 " try { \n" 16815 " error; \n" 16816 " } catch (e2) { \n" 16817 " t(e1); \n" 16818 " } \n" 16819 "} \n"; 16820 v8::V8::AddMessageListener(RethrowStackTraceHandler); 16821 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16822 CompileRun(source); 16823 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16824 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler); 16825 } 16826 16827 16828 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message, 16829 v8::Handle<v8::Value> data) { 16830 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16831 CHECK(!stack_trace.IsEmpty()); 16832 int frame_count = stack_trace->GetFrameCount(); 16833 CHECK_EQ(2, frame_count); 16834 int line_number[] = {3, 7}; 16835 for (int i = 0; i < frame_count; i++) { 16836 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16837 } 16838 } 16839 16840 16841 // Test that we do not recognize identity for primitive exceptions. 16842 TEST(RethrowPrimitiveStackTrace) { 16843 LocalContext env; 16844 v8::HandleScope scope(env->GetIsolate()); 16845 // We do not capture stack trace for non Error objects on creation time. 16846 // Instead, we capture the stack trace on last throw. 16847 const char* source = 16848 "function g() { throw 404; } \n" 16849 "function f() { g(); } \n" 16850 "function t(e) { throw e; } \n" 16851 "try { \n" 16852 " f(); \n" 16853 "} catch (e1) { \n" 16854 " t(e1) \n" 16855 "} \n"; 16856 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler); 16857 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16858 CompileRun(source); 16859 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16860 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 16861 } 16862 16863 16864 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message, 16865 v8::Handle<v8::Value> data) { 16866 // Use the frame where JavaScript is called from. 16867 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16868 CHECK(!stack_trace.IsEmpty()); 16869 CHECK_EQ(1, stack_trace->GetFrameCount()); 16870 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 16871 } 16872 16873 16874 // Test that the stack trace is captured when the error object is created and 16875 // not where it is thrown. 16876 TEST(RethrowExistingStackTrace) { 16877 LocalContext env; 16878 v8::HandleScope scope(env->GetIsolate()); 16879 const char* source = 16880 "var e = new Error(); \n" 16881 "throw e; \n"; 16882 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler); 16883 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16884 CompileRun(source); 16885 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16886 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler); 16887 } 16888 16889 16890 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message, 16891 v8::Handle<v8::Value> data) { 16892 // Use the frame where JavaScript is called from. 16893 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16894 CHECK(!stack_trace.IsEmpty()); 16895 CHECK_EQ(1, stack_trace->GetFrameCount()); 16896 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 16897 } 16898 16899 16900 // Test that the stack trace is captured where the bogus Error object is thrown. 16901 TEST(RethrowBogusErrorStackTrace) { 16902 LocalContext env; 16903 v8::HandleScope scope(env->GetIsolate()); 16904 const char* source = 16905 "var e = {__proto__: new Error()} \n" 16906 "throw e; \n"; 16907 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler); 16908 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16909 CompileRun(source); 16910 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16911 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 16912 } 16913 16914 16915 void AnalyzeStackOfEvalWithSourceURL( 16916 const v8::FunctionCallbackInfo<v8::Value>& args) { 16917 v8::HandleScope scope(args.GetIsolate()); 16918 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16919 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 16920 CHECK_EQ(5, stackTrace->GetFrameCount()); 16921 v8::Handle<v8::String> url = v8_str("eval_url"); 16922 for (int i = 0; i < 3; i++) { 16923 v8::Handle<v8::String> name = 16924 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 16925 CHECK(!name.IsEmpty()); 16926 CHECK_EQ(url, name); 16927 } 16928 } 16929 16930 16931 TEST(SourceURLInStackTrace) { 16932 v8::HandleScope scope(CcTest::isolate()); 16933 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16934 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 16935 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL)); 16936 LocalContext context(0, templ); 16937 16938 const char *source = 16939 "function outer() {\n" 16940 "function bar() {\n" 16941 " AnalyzeStackOfEvalWithSourceURL();\n" 16942 "}\n" 16943 "function foo() {\n" 16944 "\n" 16945 " bar();\n" 16946 "}\n" 16947 "foo();\n" 16948 "}\n" 16949 "eval('(' + outer +')()%s');"; 16950 16951 i::ScopedVector<char> code(1024); 16952 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url"); 16953 CHECK(CompileRun(code.start())->IsUndefined()); 16954 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url"); 16955 CHECK(CompileRun(code.start())->IsUndefined()); 16956 } 16957 16958 16959 static int scriptIdInStack[2]; 16960 16961 void AnalyzeScriptIdInStack( 16962 const v8::FunctionCallbackInfo<v8::Value>& args) { 16963 v8::HandleScope scope(args.GetIsolate()); 16964 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 16965 args.GetIsolate(), 10, v8::StackTrace::kScriptId); 16966 CHECK_EQ(2, stackTrace->GetFrameCount()); 16967 for (int i = 0; i < 2; i++) { 16968 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId(); 16969 } 16970 } 16971 16972 16973 TEST(ScriptIdInStackTrace) { 16974 v8::HandleScope scope(CcTest::isolate()); 16975 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16976 templ->Set(v8_str("AnalyzeScriptIdInStack"), 16977 v8::FunctionTemplate::New(AnalyzeScriptIdInStack)); 16978 LocalContext context(0, templ); 16979 16980 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 16981 CcTest::isolate(), 16982 "function foo() {\n" 16983 " AnalyzeScriptIdInStack();" 16984 "}\n" 16985 "foo();\n"); 16986 v8::ScriptOrigin origin = 16987 v8::ScriptOrigin(v8::String::NewFromUtf8(CcTest::isolate(), "test")); 16988 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); 16989 script->Run(); 16990 for (int i = 0; i < 2; i++) { 16991 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo); 16992 CHECK_EQ(scriptIdInStack[i], script->GetId()); 16993 } 16994 } 16995 16996 16997 void AnalyzeStackOfInlineScriptWithSourceURL( 16998 const v8::FunctionCallbackInfo<v8::Value>& args) { 16999 v8::HandleScope scope(args.GetIsolate()); 17000 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17001 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17002 CHECK_EQ(4, stackTrace->GetFrameCount()); 17003 v8::Handle<v8::String> url = v8_str("url"); 17004 for (int i = 0; i < 3; i++) { 17005 v8::Handle<v8::String> name = 17006 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17007 CHECK(!name.IsEmpty()); 17008 CHECK_EQ(url, name); 17009 } 17010 } 17011 17012 17013 TEST(InlineScriptWithSourceURLInStackTrace) { 17014 v8::HandleScope scope(CcTest::isolate()); 17015 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17016 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 17017 v8::FunctionTemplate::New( 17018 AnalyzeStackOfInlineScriptWithSourceURL)); 17019 LocalContext context(0, templ); 17020 17021 const char *source = 17022 "function outer() {\n" 17023 "function bar() {\n" 17024 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 17025 "}\n" 17026 "function foo() {\n" 17027 "\n" 17028 " bar();\n" 17029 "}\n" 17030 "foo();\n" 17031 "}\n" 17032 "outer()\n%s"; 17033 17034 i::ScopedVector<char> code(1024); 17035 i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); 17036 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17037 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); 17038 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 17039 } 17040 17041 17042 void AnalyzeStackOfDynamicScriptWithSourceURL( 17043 const v8::FunctionCallbackInfo<v8::Value>& args) { 17044 v8::HandleScope scope(args.GetIsolate()); 17045 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace( 17046 args.GetIsolate(), 10, v8::StackTrace::kDetailed); 17047 CHECK_EQ(4, stackTrace->GetFrameCount()); 17048 v8::Handle<v8::String> url = v8_str("source_url"); 17049 for (int i = 0; i < 3; i++) { 17050 v8::Handle<v8::String> name = 17051 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 17052 CHECK(!name.IsEmpty()); 17053 CHECK_EQ(url, name); 17054 } 17055 } 17056 17057 17058 TEST(DynamicWithSourceURLInStackTrace) { 17059 v8::HandleScope scope(CcTest::isolate()); 17060 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17061 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 17062 v8::FunctionTemplate::New( 17063 AnalyzeStackOfDynamicScriptWithSourceURL)); 17064 LocalContext context(0, templ); 17065 17066 const char *source = 17067 "function outer() {\n" 17068 "function bar() {\n" 17069 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 17070 "}\n" 17071 "function foo() {\n" 17072 "\n" 17073 " bar();\n" 17074 "}\n" 17075 "foo();\n" 17076 "}\n" 17077 "outer()\n%s"; 17078 17079 i::ScopedVector<char> code(1024); 17080 i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); 17081 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17082 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); 17083 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 17084 } 17085 17086 17087 static void CreateGarbageInOldSpace() { 17088 i::Factory* factory = CcTest::i_isolate()->factory(); 17089 v8::HandleScope scope(CcTest::isolate()); 17090 i::AlwaysAllocateScope always_allocate; 17091 for (int i = 0; i < 1000; i++) { 17092 factory->NewFixedArray(1000, i::TENURED); 17093 } 17094 } 17095 17096 17097 // Test that idle notification can be handled and eventually returns true. 17098 TEST(IdleNotification) { 17099 const intptr_t MB = 1024 * 1024; 17100 LocalContext env; 17101 v8::HandleScope scope(env->GetIsolate()); 17102 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17103 CreateGarbageInOldSpace(); 17104 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17105 CHECK_GT(size_with_garbage, initial_size + MB); 17106 bool finished = false; 17107 for (int i = 0; i < 200 && !finished; i++) { 17108 finished = v8::V8::IdleNotification(); 17109 } 17110 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17111 CHECK(finished); 17112 CHECK_LT(final_size, initial_size + 1); 17113 } 17114 17115 17116 // Test that idle notification can be handled and eventually collects garbage. 17117 TEST(IdleNotificationWithSmallHint) { 17118 const intptr_t MB = 1024 * 1024; 17119 const int IdlePauseInMs = 900; 17120 LocalContext env; 17121 v8::HandleScope scope(env->GetIsolate()); 17122 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17123 CreateGarbageInOldSpace(); 17124 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17125 CHECK_GT(size_with_garbage, initial_size + MB); 17126 bool finished = false; 17127 for (int i = 0; i < 200 && !finished; i++) { 17128 finished = v8::V8::IdleNotification(IdlePauseInMs); 17129 } 17130 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17131 CHECK(finished); 17132 CHECK_LT(final_size, initial_size + 1); 17133 } 17134 17135 17136 // Test that idle notification can be handled and eventually collects garbage. 17137 TEST(IdleNotificationWithLargeHint) { 17138 const intptr_t MB = 1024 * 1024; 17139 const int IdlePauseInMs = 900; 17140 LocalContext env; 17141 v8::HandleScope scope(env->GetIsolate()); 17142 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17143 CreateGarbageInOldSpace(); 17144 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17145 CHECK_GT(size_with_garbage, initial_size + MB); 17146 bool finished = false; 17147 for (int i = 0; i < 200 && !finished; i++) { 17148 finished = v8::V8::IdleNotification(IdlePauseInMs); 17149 } 17150 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17151 CHECK(finished); 17152 CHECK_LT(final_size, initial_size + 1); 17153 } 17154 17155 17156 TEST(Regress2107) { 17157 const intptr_t MB = 1024 * 1024; 17158 const int kShortIdlePauseInMs = 100; 17159 const int kLongIdlePauseInMs = 1000; 17160 LocalContext env; 17161 v8::Isolate* isolate = env->GetIsolate(); 17162 v8::HandleScope scope(env->GetIsolate()); 17163 intptr_t initial_size = CcTest::heap()->SizeOfObjects(); 17164 // Send idle notification to start a round of incremental GCs. 17165 v8::V8::IdleNotification(kShortIdlePauseInMs); 17166 // Emulate 7 page reloads. 17167 for (int i = 0; i < 7; i++) { 17168 { 17169 v8::HandleScope inner_scope(env->GetIsolate()); 17170 v8::Local<v8::Context> ctx = v8::Context::New(isolate); 17171 ctx->Enter(); 17172 CreateGarbageInOldSpace(); 17173 ctx->Exit(); 17174 } 17175 v8::V8::ContextDisposedNotification(); 17176 v8::V8::IdleNotification(kLongIdlePauseInMs); 17177 } 17178 // Create garbage and check that idle notification still collects it. 17179 CreateGarbageInOldSpace(); 17180 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); 17181 CHECK_GT(size_with_garbage, initial_size + MB); 17182 bool finished = false; 17183 for (int i = 0; i < 200 && !finished; i++) { 17184 finished = v8::V8::IdleNotification(kShortIdlePauseInMs); 17185 } 17186 intptr_t final_size = CcTest::heap()->SizeOfObjects(); 17187 CHECK_LT(final_size, initial_size + 1); 17188 } 17189 17190 17191 TEST(Regress2333) { 17192 LocalContext env; 17193 for (int i = 0; i < 3; i++) { 17194 CcTest::heap()->PerformScavenge(); 17195 } 17196 } 17197 17198 static uint32_t* stack_limit; 17199 17200 static void GetStackLimitCallback( 17201 const v8::FunctionCallbackInfo<v8::Value>& args) { 17202 stack_limit = reinterpret_cast<uint32_t*>( 17203 CcTest::i_isolate()->stack_guard()->real_climit()); 17204 } 17205 17206 17207 // Uses the address of a local variable to determine the stack top now. 17208 // Given a size, returns an address that is that far from the current 17209 // top of stack. 17210 static uint32_t* ComputeStackLimit(uint32_t size) { 17211 uint32_t* answer = &size - (size / sizeof(size)); 17212 // If the size is very large and the stack is very near the bottom of 17213 // memory then the calculation above may wrap around and give an address 17214 // that is above the (downwards-growing) stack. In that case we return 17215 // a very low address. 17216 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 17217 return answer; 17218 } 17219 17220 17221 // We need at least 165kB for an x64 debug build with clang and ASAN. 17222 static const int stack_breathing_room = 256 * i::KB; 17223 17224 17225 TEST(SetResourceConstraints) { 17226 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 17227 17228 // Set stack limit. 17229 v8::ResourceConstraints constraints; 17230 constraints.set_stack_limit(set_limit); 17231 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints)); 17232 17233 // Execute a script. 17234 LocalContext env; 17235 v8::HandleScope scope(env->GetIsolate()); 17236 Local<v8::FunctionTemplate> fun_templ = 17237 v8::FunctionTemplate::New(GetStackLimitCallback); 17238 Local<Function> fun = fun_templ->GetFunction(); 17239 env->Global()->Set(v8_str("get_stack_limit"), fun); 17240 CompileRun("get_stack_limit();"); 17241 17242 CHECK(stack_limit == set_limit); 17243 } 17244 17245 17246 TEST(SetResourceConstraintsInThread) { 17247 uint32_t* set_limit; 17248 { 17249 v8::Locker locker(CcTest::isolate()); 17250 set_limit = ComputeStackLimit(stack_breathing_room); 17251 17252 // Set stack limit. 17253 v8::ResourceConstraints constraints; 17254 constraints.set_stack_limit(set_limit); 17255 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints)); 17256 17257 // Execute a script. 17258 v8::HandleScope scope(CcTest::isolate()); 17259 LocalContext env; 17260 Local<v8::FunctionTemplate> fun_templ = 17261 v8::FunctionTemplate::New(GetStackLimitCallback); 17262 Local<Function> fun = fun_templ->GetFunction(); 17263 env->Global()->Set(v8_str("get_stack_limit"), fun); 17264 CompileRun("get_stack_limit();"); 17265 17266 CHECK(stack_limit == set_limit); 17267 } 17268 { 17269 v8::Locker locker(CcTest::isolate()); 17270 CHECK(stack_limit == set_limit); 17271 } 17272 } 17273 17274 17275 THREADED_TEST(GetHeapStatistics) { 17276 LocalContext c1; 17277 v8::HandleScope scope(c1->GetIsolate()); 17278 v8::HeapStatistics heap_statistics; 17279 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0); 17280 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0); 17281 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 17282 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 17283 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 17284 } 17285 17286 17287 class VisitorImpl : public v8::ExternalResourceVisitor { 17288 public: 17289 explicit VisitorImpl(TestResource** resource) { 17290 for (int i = 0; i < 4; i++) { 17291 resource_[i] = resource[i]; 17292 found_resource_[i] = false; 17293 } 17294 } 17295 virtual ~VisitorImpl() {} 17296 virtual void VisitExternalString(v8::Handle<v8::String> string) { 17297 if (!string->IsExternal()) { 17298 CHECK(string->IsExternalAscii()); 17299 return; 17300 } 17301 v8::String::ExternalStringResource* resource = 17302 string->GetExternalStringResource(); 17303 CHECK(resource); 17304 for (int i = 0; i < 4; i++) { 17305 if (resource_[i] == resource) { 17306 CHECK(!found_resource_[i]); 17307 found_resource_[i] = true; 17308 } 17309 } 17310 } 17311 void CheckVisitedResources() { 17312 for (int i = 0; i < 4; i++) { 17313 CHECK(found_resource_[i]); 17314 } 17315 } 17316 17317 private: 17318 v8::String::ExternalStringResource* resource_[4]; 17319 bool found_resource_[4]; 17320 }; 17321 17322 17323 TEST(VisitExternalStrings) { 17324 LocalContext env; 17325 v8::HandleScope scope(env->GetIsolate()); 17326 const char* string = "Some string"; 17327 uint16_t* two_byte_string = AsciiToTwoByteString(string); 17328 TestResource* resource[4]; 17329 resource[0] = new TestResource(two_byte_string); 17330 v8::Local<v8::String> string0 = 17331 v8::String::NewExternal(env->GetIsolate(), resource[0]); 17332 resource[1] = new TestResource(two_byte_string); 17333 v8::Local<v8::String> string1 = 17334 v8::String::NewExternal(env->GetIsolate(), resource[1]); 17335 17336 // Externalized symbol. 17337 resource[2] = new TestResource(two_byte_string); 17338 v8::Local<v8::String> string2 = v8::String::NewFromUtf8( 17339 env->GetIsolate(), string, v8::String::kInternalizedString); 17340 CHECK(string2->MakeExternal(resource[2])); 17341 17342 // Symbolized External. 17343 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 17344 v8::Local<v8::String> string3 = 17345 v8::String::NewExternal(env->GetIsolate(), resource[3]); 17346 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string. 17347 // Turn into a symbol. 17348 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 17349 CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure()); 17350 CHECK(string3_i->IsInternalizedString()); 17351 17352 // We need to add usages for string* to avoid warnings in GCC 4.7 17353 CHECK(string0->IsExternal()); 17354 CHECK(string1->IsExternal()); 17355 CHECK(string2->IsExternal()); 17356 CHECK(string3->IsExternal()); 17357 17358 VisitorImpl visitor(resource); 17359 v8::V8::VisitExternalResources(&visitor); 17360 visitor.CheckVisitedResources(); 17361 } 17362 17363 17364 TEST(ExternalStringCollectedAtTearDown) { 17365 int destroyed = 0; 17366 v8::Isolate* isolate = v8::Isolate::New(); 17367 { v8::Isolate::Scope isolate_scope(isolate); 17368 v8::HandleScope handle_scope(isolate); 17369 const char* s = "One string to test them all, one string to find them."; 17370 TestAsciiResource* inscription = 17371 new TestAsciiResource(i::StrDup(s), &destroyed); 17372 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription); 17373 // Ring is still alive. Orcs are roaming freely across our lands. 17374 CHECK_EQ(0, destroyed); 17375 USE(ring); 17376 } 17377 17378 isolate->Dispose(); 17379 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice. 17380 CHECK_EQ(1, destroyed); 17381 } 17382 17383 17384 static double DoubleFromBits(uint64_t value) { 17385 double target; 17386 i::OS::MemCopy(&target, &value, sizeof(target)); 17387 return target; 17388 } 17389 17390 17391 static uint64_t DoubleToBits(double value) { 17392 uint64_t target; 17393 i::OS::MemCopy(&target, &value, sizeof(target)); 17394 return target; 17395 } 17396 17397 17398 static double DoubleToDateTime(double input) { 17399 double date_limit = 864e13; 17400 if (std::isnan(input) || input < -date_limit || input > date_limit) { 17401 return i::OS::nan_value(); 17402 } 17403 return (input < 0) ? -(floor(-input)) : floor(input); 17404 } 17405 17406 17407 // We don't have a consistent way to write 64-bit constants syntactically, so we 17408 // split them into two 32-bit constants and combine them programmatically. 17409 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 17410 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 17411 } 17412 17413 17414 THREADED_TEST(QuietSignalingNaNs) { 17415 LocalContext context; 17416 v8::HandleScope scope(context->GetIsolate()); 17417 v8::TryCatch try_catch; 17418 17419 // Special double values. 17420 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 17421 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 17422 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 17423 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 17424 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 17425 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 17426 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 17427 17428 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 17429 // on either side of the epoch. 17430 double date_limit = 864e13; 17431 17432 double test_values[] = { 17433 snan, 17434 qnan, 17435 infinity, 17436 max_normal, 17437 date_limit + 1, 17438 date_limit, 17439 min_normal, 17440 max_denormal, 17441 min_denormal, 17442 0, 17443 -0, 17444 -min_denormal, 17445 -max_denormal, 17446 -min_normal, 17447 -date_limit, 17448 -date_limit - 1, 17449 -max_normal, 17450 -infinity, 17451 -qnan, 17452 -snan 17453 }; 17454 int num_test_values = 20; 17455 17456 for (int i = 0; i < num_test_values; i++) { 17457 double test_value = test_values[i]; 17458 17459 // Check that Number::New preserves non-NaNs and quiets SNaNs. 17460 v8::Handle<v8::Value> number = v8::Number::New(test_value); 17461 double stored_number = number->NumberValue(); 17462 if (!std::isnan(test_value)) { 17463 CHECK_EQ(test_value, stored_number); 17464 } else { 17465 uint64_t stored_bits = DoubleToBits(stored_number); 17466 // Check if quiet nan (bits 51..62 all set). 17467 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 17468 // Most significant fraction bit for quiet nan is set to 0 17469 // on MIPS architecture. Allowed by IEEE-754. 17470 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17471 #else 17472 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17473 #endif 17474 } 17475 17476 // Check that Date::New preserves non-NaNs in the date range and 17477 // quiets SNaNs. 17478 v8::Handle<v8::Value> date = 17479 v8::Date::New(context->GetIsolate(), test_value); 17480 double expected_stored_date = DoubleToDateTime(test_value); 17481 double stored_date = date->NumberValue(); 17482 if (!std::isnan(expected_stored_date)) { 17483 CHECK_EQ(expected_stored_date, stored_date); 17484 } else { 17485 uint64_t stored_bits = DoubleToBits(stored_date); 17486 // Check if quiet nan (bits 51..62 all set). 17487 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 17488 // Most significant fraction bit for quiet nan is set to 0 17489 // on MIPS architecture. Allowed by IEEE-754. 17490 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17491 #else 17492 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17493 #endif 17494 } 17495 } 17496 } 17497 17498 17499 static void SpaghettiIncident( 17500 const v8::FunctionCallbackInfo<v8::Value>& args) { 17501 v8::HandleScope scope(args.GetIsolate()); 17502 v8::TryCatch tc; 17503 v8::Handle<v8::String> str(args[0]->ToString()); 17504 USE(str); 17505 if (tc.HasCaught()) 17506 tc.ReThrow(); 17507 } 17508 17509 17510 // Test that an exception can be propagated down through a spaghetti 17511 // stack using ReThrow. 17512 THREADED_TEST(SpaghettiStackReThrow) { 17513 v8::HandleScope scope(CcTest::isolate()); 17514 LocalContext context; 17515 context->Global()->Set( 17516 v8::String::NewFromUtf8(CcTest::isolate(), "s"), 17517 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction()); 17518 v8::TryCatch try_catch; 17519 CompileRun( 17520 "var i = 0;" 17521 "var o = {" 17522 " toString: function () {" 17523 " if (i == 10) {" 17524 " throw 'Hey!';" 17525 " } else {" 17526 " i++;" 17527 " return s(o);" 17528 " }" 17529 " }" 17530 "};" 17531 "s(o);"); 17532 CHECK(try_catch.HasCaught()); 17533 v8::String::Utf8Value value(try_catch.Exception()); 17534 CHECK_EQ(0, strcmp(*value, "Hey!")); 17535 } 17536 17537 17538 TEST(Regress528) { 17539 v8::V8::Initialize(); 17540 v8::Isolate* isolate = CcTest::isolate(); 17541 v8::HandleScope scope(isolate); 17542 v8::Local<Context> other_context; 17543 int gc_count; 17544 17545 // Create a context used to keep the code from aging in the compilation 17546 // cache. 17547 other_context = Context::New(isolate); 17548 17549 // Context-dependent context data creates reference from the compilation 17550 // cache to the global object. 17551 const char* source_simple = "1"; 17552 { 17553 v8::HandleScope scope(isolate); 17554 v8::Local<Context> context = Context::New(isolate); 17555 17556 context->Enter(); 17557 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, ""); 17558 context->SetEmbedderData(0, obj); 17559 CompileRun(source_simple); 17560 context->Exit(); 17561 } 17562 v8::V8::ContextDisposedNotification(); 17563 for (gc_count = 1; gc_count < 10; gc_count++) { 17564 other_context->Enter(); 17565 CompileRun(source_simple); 17566 other_context->Exit(); 17567 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 17568 if (GetGlobalObjectsCount() == 1) break; 17569 } 17570 CHECK_GE(2, gc_count); 17571 CHECK_EQ(1, GetGlobalObjectsCount()); 17572 17573 // Eval in a function creates reference from the compilation cache to the 17574 // global object. 17575 const char* source_eval = "function f(){eval('1')}; f()"; 17576 { 17577 v8::HandleScope scope(isolate); 17578 v8::Local<Context> context = Context::New(isolate); 17579 17580 context->Enter(); 17581 CompileRun(source_eval); 17582 context->Exit(); 17583 } 17584 v8::V8::ContextDisposedNotification(); 17585 for (gc_count = 1; gc_count < 10; gc_count++) { 17586 other_context->Enter(); 17587 CompileRun(source_eval); 17588 other_context->Exit(); 17589 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 17590 if (GetGlobalObjectsCount() == 1) break; 17591 } 17592 CHECK_GE(2, gc_count); 17593 CHECK_EQ(1, GetGlobalObjectsCount()); 17594 17595 // Looking up the line number for an exception creates reference from the 17596 // compilation cache to the global object. 17597 const char* source_exception = "function f(){throw 1;} f()"; 17598 { 17599 v8::HandleScope scope(isolate); 17600 v8::Local<Context> context = Context::New(isolate); 17601 17602 context->Enter(); 17603 v8::TryCatch try_catch; 17604 CompileRun(source_exception); 17605 CHECK(try_catch.HasCaught()); 17606 v8::Handle<v8::Message> message = try_catch.Message(); 17607 CHECK(!message.IsEmpty()); 17608 CHECK_EQ(1, message->GetLineNumber()); 17609 context->Exit(); 17610 } 17611 v8::V8::ContextDisposedNotification(); 17612 for (gc_count = 1; gc_count < 10; gc_count++) { 17613 other_context->Enter(); 17614 CompileRun(source_exception); 17615 other_context->Exit(); 17616 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 17617 if (GetGlobalObjectsCount() == 1) break; 17618 } 17619 CHECK_GE(2, gc_count); 17620 CHECK_EQ(1, GetGlobalObjectsCount()); 17621 17622 v8::V8::ContextDisposedNotification(); 17623 } 17624 17625 17626 THREADED_TEST(ScriptOrigin) { 17627 LocalContext env; 17628 v8::HandleScope scope(env->GetIsolate()); 17629 v8::ScriptOrigin origin = 17630 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 17631 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 17632 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 17633 v8::Script::Compile(script, &origin)->Run(); 17634 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17635 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 17636 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17637 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 17638 17639 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 17640 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName())); 17641 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value()); 17642 17643 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 17644 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName())); 17645 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value()); 17646 } 17647 17648 17649 THREADED_TEST(FunctionGetInferredName) { 17650 LocalContext env; 17651 v8::HandleScope scope(env->GetIsolate()); 17652 v8::ScriptOrigin origin = 17653 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 17654 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 17655 env->GetIsolate(), 17656 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 17657 v8::Script::Compile(script, &origin)->Run(); 17658 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17659 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 17660 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); 17661 } 17662 17663 17664 THREADED_TEST(FunctionGetDisplayName) { 17665 LocalContext env; 17666 v8::HandleScope scope(env->GetIsolate()); 17667 const char* code = "var error = false;" 17668 "function a() { this.x = 1; };" 17669 "a.displayName = 'display_a';" 17670 "var b = (function() {" 17671 " var f = function() { this.x = 2; };" 17672 " f.displayName = 'display_b';" 17673 " return f;" 17674 "})();" 17675 "var c = function() {};" 17676 "c.__defineGetter__('displayName', function() {" 17677 " error = true;" 17678 " throw new Error();" 17679 "});" 17680 "function d() {};" 17681 "d.__defineGetter__('displayName', function() {" 17682 " error = true;" 17683 " return 'wrong_display_name';" 17684 "});" 17685 "function e() {};" 17686 "e.displayName = 'wrong_display_name';" 17687 "e.__defineSetter__('displayName', function() {" 17688 " error = true;" 17689 " throw new Error();" 17690 "});" 17691 "function f() {};" 17692 "f.displayName = { 'foo': 6, toString: function() {" 17693 " error = true;" 17694 " return 'wrong_display_name';" 17695 "}};" 17696 "var g = function() {" 17697 " arguments.callee.displayName = 'set_in_runtime';" 17698 "}; g();" 17699 ; 17700 v8::ScriptOrigin origin = 17701 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 17702 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin) 17703 ->Run(); 17704 v8::Local<v8::Value> error = 17705 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error")); 17706 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( 17707 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a"))); 17708 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( 17709 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b"))); 17710 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( 17711 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"))); 17712 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( 17713 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d"))); 17714 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( 17715 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e"))); 17716 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17717 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 17718 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17719 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 17720 CHECK_EQ(false, error->BooleanValue()); 17721 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName())); 17722 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName())); 17723 CHECK(c->GetDisplayName()->IsUndefined()); 17724 CHECK(d->GetDisplayName()->IsUndefined()); 17725 CHECK(e->GetDisplayName()->IsUndefined()); 17726 CHECK(f->GetDisplayName()->IsUndefined()); 17727 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())); 17728 } 17729 17730 17731 THREADED_TEST(ScriptLineNumber) { 17732 LocalContext env; 17733 v8::HandleScope scope(env->GetIsolate()); 17734 v8::ScriptOrigin origin = 17735 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test")); 17736 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 17737 env->GetIsolate(), "function f() {}\n\nfunction g() {}"); 17738 v8::Script::Compile(script, &origin)->Run(); 17739 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17740 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f"))); 17741 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17742 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g"))); 17743 CHECK_EQ(0, f->GetScriptLineNumber()); 17744 CHECK_EQ(2, g->GetScriptLineNumber()); 17745 } 17746 17747 17748 THREADED_TEST(ScriptColumnNumber) { 17749 LocalContext env; 17750 v8::HandleScope scope(env->GetIsolate()); 17751 v8::ScriptOrigin origin = 17752 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"), 17753 v8::Integer::New(3), v8::Integer::New(2)); 17754 v8::Handle<v8::String> script = v8::String::NewFromUtf8( 17755 env->GetIsolate(), "function foo() {}\n\n function bar() {}"); 17756 v8::Script::Compile(script, &origin)->Run(); 17757 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 17758 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo"))); 17759 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 17760 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "bar"))); 17761 CHECK_EQ(14, foo->GetScriptColumnNumber()); 17762 CHECK_EQ(17, bar->GetScriptColumnNumber()); 17763 } 17764 17765 17766 THREADED_TEST(FunctionIsBuiltin) { 17767 LocalContext env; 17768 v8::HandleScope scope(env->GetIsolate()); 17769 v8::Local<v8::Function> f; 17770 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); 17771 CHECK(f->IsBuiltin()); 17772 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); 17773 CHECK(f->IsBuiltin()); 17774 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); 17775 CHECK(f->IsBuiltin()); 17776 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); 17777 CHECK(f->IsBuiltin()); 17778 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); 17779 CHECK(!f->IsBuiltin()); 17780 } 17781 17782 17783 THREADED_TEST(FunctionGetScriptId) { 17784 LocalContext env; 17785 v8::HandleScope scope(env->GetIsolate()); 17786 v8::ScriptOrigin origin = 17787 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"), 17788 v8::Integer::New(3), v8::Integer::New(2)); 17789 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8( 17790 env->GetIsolate(), "function foo() {}\n\n function bar() {}"); 17791 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); 17792 script->Run(); 17793 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 17794 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo"))); 17795 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 17796 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "bar"))); 17797 CHECK_EQ(script->GetId(), foo->ScriptId()); 17798 CHECK_EQ(script->GetId(), bar->ScriptId()); 17799 } 17800 17801 17802 static void GetterWhichReturns42( 17803 Local<String> name, 17804 const v8::PropertyCallbackInfo<v8::Value>& info) { 17805 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17806 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17807 info.GetReturnValue().Set(v8_num(42)); 17808 } 17809 17810 17811 static void SetterWhichSetsYOnThisTo23( 17812 Local<String> name, 17813 Local<Value> value, 17814 const v8::PropertyCallbackInfo<void>& info) { 17815 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17816 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17817 info.This()->Set(v8_str("y"), v8_num(23)); 17818 } 17819 17820 17821 void FooGetInterceptor(Local<String> name, 17822 const v8::PropertyCallbackInfo<v8::Value>& info) { 17823 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17824 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17825 if (!name->Equals(v8_str("foo"))) return; 17826 info.GetReturnValue().Set(v8_num(42)); 17827 } 17828 17829 17830 void FooSetInterceptor(Local<String> name, 17831 Local<Value> value, 17832 const v8::PropertyCallbackInfo<v8::Value>& info) { 17833 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17834 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17835 if (!name->Equals(v8_str("foo"))) return; 17836 info.This()->Set(v8_str("y"), v8_num(23)); 17837 info.GetReturnValue().Set(v8_num(23)); 17838 } 17839 17840 17841 TEST(SetterOnConstructorPrototype) { 17842 v8::HandleScope scope(CcTest::isolate()); 17843 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17844 templ->SetAccessor(v8_str("x"), 17845 GetterWhichReturns42, 17846 SetterWhichSetsYOnThisTo23); 17847 LocalContext context; 17848 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17849 CompileRun("function C1() {" 17850 " this.x = 23;" 17851 "};" 17852 "C1.prototype = P;" 17853 "function C2() {" 17854 " this.x = 23" 17855 "};" 17856 "C2.prototype = { };" 17857 "C2.prototype.__proto__ = P;"); 17858 17859 v8::Local<v8::Script> script; 17860 script = v8::Script::Compile(v8_str("new C1();")); 17861 for (int i = 0; i < 10; i++) { 17862 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17863 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 17864 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 17865 } 17866 17867 script = v8::Script::Compile(v8_str("new C2();")); 17868 for (int i = 0; i < 10; i++) { 17869 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 17870 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value()); 17871 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value()); 17872 } 17873 } 17874 17875 17876 static void NamedPropertyGetterWhichReturns42( 17877 Local<String> name, 17878 const v8::PropertyCallbackInfo<v8::Value>& info) { 17879 info.GetReturnValue().Set(v8_num(42)); 17880 } 17881 17882 17883 static void NamedPropertySetterWhichSetsYOnThisTo23( 17884 Local<String> name, 17885 Local<Value> value, 17886 const v8::PropertyCallbackInfo<v8::Value>& info) { 17887 if (name->Equals(v8_str("x"))) { 17888 info.This()->Set(v8_str("y"), v8_num(23)); 17889 } 17890 } 17891 17892 17893 THREADED_TEST(InterceptorOnConstructorPrototype) { 17894 v8::HandleScope scope(CcTest::isolate()); 17895 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17896 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42, 17897 NamedPropertySetterWhichSetsYOnThisTo23); 17898 LocalContext context; 17899 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17900 CompileRun("function C1() {" 17901 " this.x = 23;" 17902 "};" 17903 "C1.prototype = P;" 17904 "function C2() {" 17905 " this.x = 23" 17906 "};" 17907 "C2.prototype = { };" 17908 "C2.prototype.__proto__ = P;"); 17909 17910 v8::Local<v8::Script> script; 17911 script = v8::Script::Compile(v8_str("new C1();")); 17912 for (int i = 0; i < 10; i++) { 17913 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17914 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 17915 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 17916 } 17917 17918 script = v8::Script::Compile(v8_str("new C2();")); 17919 for (int i = 0; i < 10; i++) { 17920 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 17921 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value()); 17922 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value()); 17923 } 17924 } 17925 17926 17927 TEST(Regress618) { 17928 const char* source = "function C1() {" 17929 " this.x = 23;" 17930 "};" 17931 "C1.prototype = P;"; 17932 17933 LocalContext context; 17934 v8::HandleScope scope(context->GetIsolate()); 17935 v8::Local<v8::Script> script; 17936 17937 // Use a simple object as prototype. 17938 v8::Local<v8::Object> prototype = v8::Object::New(); 17939 prototype->Set(v8_str("y"), v8_num(42)); 17940 context->Global()->Set(v8_str("P"), prototype); 17941 17942 // This compile will add the code to the compilation cache. 17943 CompileRun(source); 17944 17945 script = v8::Script::Compile(v8_str("new C1();")); 17946 // Allow enough iterations for the inobject slack tracking logic 17947 // to finalize instance size and install the fast construct stub. 17948 for (int i = 0; i < 256; i++) { 17949 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17950 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 17951 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 17952 } 17953 17954 // Use an API object with accessors as prototype. 17955 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17956 templ->SetAccessor(v8_str("x"), 17957 GetterWhichReturns42, 17958 SetterWhichSetsYOnThisTo23); 17959 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17960 17961 // This compile will get the code from the compilation cache. 17962 CompileRun(source); 17963 17964 script = v8::Script::Compile(v8_str("new C1();")); 17965 for (int i = 0; i < 10; i++) { 17966 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17967 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 17968 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 17969 } 17970 } 17971 17972 v8::Isolate* gc_callbacks_isolate = NULL; 17973 int prologue_call_count = 0; 17974 int epilogue_call_count = 0; 17975 int prologue_call_count_second = 0; 17976 int epilogue_call_count_second = 0; 17977 17978 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) { 17979 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 17980 ++prologue_call_count; 17981 } 17982 17983 17984 void PrologueCallback(v8::Isolate* isolate, 17985 v8::GCType, 17986 v8::GCCallbackFlags flags) { 17987 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 17988 CHECK_EQ(gc_callbacks_isolate, isolate); 17989 ++prologue_call_count; 17990 } 17991 17992 17993 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) { 17994 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 17995 ++epilogue_call_count; 17996 } 17997 17998 17999 void EpilogueCallback(v8::Isolate* isolate, 18000 v8::GCType, 18001 v8::GCCallbackFlags flags) { 18002 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18003 CHECK_EQ(gc_callbacks_isolate, isolate); 18004 ++epilogue_call_count; 18005 } 18006 18007 18008 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18009 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18010 ++prologue_call_count_second; 18011 } 18012 18013 18014 void PrologueCallbackSecond(v8::Isolate* isolate, 18015 v8::GCType, 18016 v8::GCCallbackFlags flags) { 18017 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18018 CHECK_EQ(gc_callbacks_isolate, isolate); 18019 ++prologue_call_count_second; 18020 } 18021 18022 18023 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) { 18024 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18025 ++epilogue_call_count_second; 18026 } 18027 18028 18029 void EpilogueCallbackSecond(v8::Isolate* isolate, 18030 v8::GCType, 18031 v8::GCCallbackFlags flags) { 18032 CHECK_EQ(flags, v8::kNoGCCallbackFlags); 18033 CHECK_EQ(gc_callbacks_isolate, isolate); 18034 ++epilogue_call_count_second; 18035 } 18036 18037 18038 TEST(GCCallbacksOld) { 18039 LocalContext context; 18040 18041 v8::V8::AddGCPrologueCallback(PrologueCallback); 18042 v8::V8::AddGCEpilogueCallback(EpilogueCallback); 18043 CHECK_EQ(0, prologue_call_count); 18044 CHECK_EQ(0, epilogue_call_count); 18045 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18046 CHECK_EQ(1, prologue_call_count); 18047 CHECK_EQ(1, epilogue_call_count); 18048 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); 18049 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); 18050 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18051 CHECK_EQ(2, prologue_call_count); 18052 CHECK_EQ(2, epilogue_call_count); 18053 CHECK_EQ(1, prologue_call_count_second); 18054 CHECK_EQ(1, epilogue_call_count_second); 18055 v8::V8::RemoveGCPrologueCallback(PrologueCallback); 18056 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); 18057 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18058 CHECK_EQ(2, prologue_call_count); 18059 CHECK_EQ(2, epilogue_call_count); 18060 CHECK_EQ(2, prologue_call_count_second); 18061 CHECK_EQ(2, epilogue_call_count_second); 18062 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); 18063 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18064 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18065 CHECK_EQ(2, prologue_call_count); 18066 CHECK_EQ(2, epilogue_call_count); 18067 CHECK_EQ(2, prologue_call_count_second); 18068 CHECK_EQ(2, epilogue_call_count_second); 18069 } 18070 18071 18072 TEST(GCCallbacks) { 18073 LocalContext context; 18074 v8::Isolate* isolate = context->GetIsolate(); 18075 gc_callbacks_isolate = isolate; 18076 isolate->AddGCPrologueCallback(PrologueCallback); 18077 isolate->AddGCEpilogueCallback(EpilogueCallback); 18078 CHECK_EQ(0, prologue_call_count); 18079 CHECK_EQ(0, epilogue_call_count); 18080 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18081 CHECK_EQ(1, prologue_call_count); 18082 CHECK_EQ(1, epilogue_call_count); 18083 isolate->AddGCPrologueCallback(PrologueCallbackSecond); 18084 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond); 18085 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18086 CHECK_EQ(2, prologue_call_count); 18087 CHECK_EQ(2, epilogue_call_count); 18088 CHECK_EQ(1, prologue_call_count_second); 18089 CHECK_EQ(1, epilogue_call_count_second); 18090 isolate->RemoveGCPrologueCallback(PrologueCallback); 18091 isolate->RemoveGCEpilogueCallback(EpilogueCallback); 18092 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18093 CHECK_EQ(2, prologue_call_count); 18094 CHECK_EQ(2, epilogue_call_count); 18095 CHECK_EQ(2, prologue_call_count_second); 18096 CHECK_EQ(2, epilogue_call_count_second); 18097 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond); 18098 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond); 18099 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18100 CHECK_EQ(2, prologue_call_count); 18101 CHECK_EQ(2, epilogue_call_count); 18102 CHECK_EQ(2, prologue_call_count_second); 18103 CHECK_EQ(2, epilogue_call_count_second); 18104 } 18105 18106 18107 THREADED_TEST(AddToJSFunctionResultCache) { 18108 i::FLAG_stress_compaction = false; 18109 i::FLAG_allow_natives_syntax = true; 18110 v8::HandleScope scope(CcTest::isolate()); 18111 18112 LocalContext context; 18113 18114 const char* code = 18115 "(function() {" 18116 " var key0 = 'a';" 18117 " var key1 = 'b';" 18118 " var r0 = %_GetFromCache(0, key0);" 18119 " var r1 = %_GetFromCache(0, key1);" 18120 " var r0_ = %_GetFromCache(0, key0);" 18121 " if (r0 !== r0_)" 18122 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;" 18123 " var r1_ = %_GetFromCache(0, key1);" 18124 " if (r1 !== r1_)" 18125 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" 18126 " return 'PASSED';" 18127 "})()"; 18128 CcTest::heap()->ClearJSFunctionResultCaches(); 18129 ExpectString(code, "PASSED"); 18130 } 18131 18132 18133 static const int k0CacheSize = 16; 18134 18135 THREADED_TEST(FillJSFunctionResultCache) { 18136 i::FLAG_allow_natives_syntax = true; 18137 LocalContext context; 18138 v8::HandleScope scope(context->GetIsolate()); 18139 18140 const char* code = 18141 "(function() {" 18142 " var k = 'a';" 18143 " var r = %_GetFromCache(0, k);" 18144 " for (var i = 0; i < 16; i++) {" 18145 " %_GetFromCache(0, 'a' + i);" 18146 " };" 18147 " if (r === %_GetFromCache(0, k))" 18148 " return 'FAILED: k0CacheSize is too small';" 18149 " return 'PASSED';" 18150 "})()"; 18151 CcTest::heap()->ClearJSFunctionResultCaches(); 18152 ExpectString(code, "PASSED"); 18153 } 18154 18155 18156 THREADED_TEST(RoundRobinGetFromCache) { 18157 i::FLAG_allow_natives_syntax = true; 18158 LocalContext context; 18159 v8::HandleScope scope(context->GetIsolate()); 18160 18161 const char* code = 18162 "(function() {" 18163 " var keys = [];" 18164 " for (var i = 0; i < 16; i++) keys.push(i);" 18165 " var values = [];" 18166 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 18167 " for (var i = 0; i < 16; i++) {" 18168 " var v = %_GetFromCache(0, keys[i]);" 18169 " if (v.toString() !== values[i].toString())" 18170 " return 'Wrong value for ' + " 18171 " keys[i] + ': ' + v + ' vs. ' + values[i];" 18172 " };" 18173 " return 'PASSED';" 18174 "})()"; 18175 CcTest::heap()->ClearJSFunctionResultCaches(); 18176 ExpectString(code, "PASSED"); 18177 } 18178 18179 18180 THREADED_TEST(ReverseGetFromCache) { 18181 i::FLAG_allow_natives_syntax = true; 18182 LocalContext context; 18183 v8::HandleScope scope(context->GetIsolate()); 18184 18185 const char* code = 18186 "(function() {" 18187 " var keys = [];" 18188 " for (var i = 0; i < 16; i++) keys.push(i);" 18189 " var values = [];" 18190 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 18191 " for (var i = 15; i >= 16; i--) {" 18192 " var v = %_GetFromCache(0, keys[i]);" 18193 " if (v !== values[i])" 18194 " return 'Wrong value for ' + " 18195 " keys[i] + ': ' + v + ' vs. ' + values[i];" 18196 " };" 18197 " return 'PASSED';" 18198 "})()"; 18199 CcTest::heap()->ClearJSFunctionResultCaches(); 18200 ExpectString(code, "PASSED"); 18201 } 18202 18203 18204 THREADED_TEST(TestEviction) { 18205 i::FLAG_allow_natives_syntax = true; 18206 LocalContext context; 18207 v8::HandleScope scope(context->GetIsolate()); 18208 18209 const char* code = 18210 "(function() {" 18211 " for (var i = 0; i < 2*16; i++) {" 18212 " %_GetFromCache(0, 'a' + i);" 18213 " };" 18214 " return 'PASSED';" 18215 "})()"; 18216 CcTest::heap()->ClearJSFunctionResultCaches(); 18217 ExpectString(code, "PASSED"); 18218 } 18219 18220 18221 THREADED_TEST(TwoByteStringInAsciiCons) { 18222 // See Chromium issue 47824. 18223 LocalContext context; 18224 v8::HandleScope scope(context->GetIsolate()); 18225 18226 const char* init_code = 18227 "var str1 = 'abelspendabel';" 18228 "var str2 = str1 + str1 + str1;" 18229 "str2;"; 18230 Local<Value> result = CompileRun(init_code); 18231 18232 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 18233 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 18234 18235 CHECK(result->IsString()); 18236 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 18237 int length = string->length(); 18238 CHECK(string->IsOneByteRepresentation()); 18239 18240 FlattenString(string); 18241 i::Handle<i::String> flat_string = FlattenGetString(string); 18242 18243 CHECK(string->IsOneByteRepresentation()); 18244 CHECK(flat_string->IsOneByteRepresentation()); 18245 18246 // Create external resource. 18247 uint16_t* uc16_buffer = new uint16_t[length + 1]; 18248 18249 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 18250 uc16_buffer[length] = 0; 18251 18252 TestResource resource(uc16_buffer); 18253 18254 flat_string->MakeExternal(&resource); 18255 18256 CHECK(flat_string->IsTwoByteRepresentation()); 18257 18258 // If the cons string has been short-circuited, skip the following checks. 18259 if (!string.is_identical_to(flat_string)) { 18260 // At this point, we should have a Cons string which is flat and ASCII, 18261 // with a first half that is a two-byte string (although it only contains 18262 // ASCII characters). This is a valid sequence of steps, and it can happen 18263 // in real pages. 18264 CHECK(string->IsOneByteRepresentation()); 18265 i::ConsString* cons = i::ConsString::cast(*string); 18266 CHECK_EQ(0, cons->second()->length()); 18267 CHECK(cons->first()->IsTwoByteRepresentation()); 18268 } 18269 18270 // Check that some string operations work. 18271 18272 // Atom RegExp. 18273 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 18274 CHECK_EQ(6, reresult->Int32Value()); 18275 18276 // Nonatom RegExp. 18277 reresult = CompileRun("str2.match(/abe./g).length;"); 18278 CHECK_EQ(6, reresult->Int32Value()); 18279 18280 reresult = CompileRun("str2.search(/bel/g);"); 18281 CHECK_EQ(1, reresult->Int32Value()); 18282 18283 reresult = CompileRun("str2.search(/be./g);"); 18284 CHECK_EQ(1, reresult->Int32Value()); 18285 18286 ExpectTrue("/bel/g.test(str2);"); 18287 18288 ExpectTrue("/be./g.test(str2);"); 18289 18290 reresult = CompileRun("/bel/g.exec(str2);"); 18291 CHECK(!reresult->IsNull()); 18292 18293 reresult = CompileRun("/be./g.exec(str2);"); 18294 CHECK(!reresult->IsNull()); 18295 18296 ExpectString("str2.substring(2, 10);", "elspenda"); 18297 18298 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 18299 18300 ExpectString("str2.charAt(2);", "e"); 18301 18302 ExpectObject("str2.indexOf('els');", indexof); 18303 18304 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 18305 18306 reresult = CompileRun("str2.charCodeAt(2);"); 18307 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 18308 } 18309 18310 18311 TEST(ContainsOnlyOneByte) { 18312 v8::V8::Initialize(); 18313 v8::Isolate* isolate = CcTest::isolate(); 18314 v8::HandleScope scope(isolate); 18315 // Make a buffer long enough that it won't automatically be converted. 18316 const int length = 512; 18317 // Ensure word aligned assignment. 18318 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 18319 i::SmartArrayPointer<uintptr_t> 18320 aligned_contents(new uintptr_t[aligned_length]); 18321 uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents); 18322 // Set to contain only one byte. 18323 for (int i = 0; i < length-1; i++) { 18324 string_contents[i] = 0x41; 18325 } 18326 string_contents[length-1] = 0; 18327 // Simple case. 18328 Handle<String> string; 18329 string = String::NewExternal(isolate, new TestResource(string_contents)); 18330 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18331 // Counter example. 18332 string = String::NewFromTwoByte(isolate, string_contents); 18333 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 18334 // Test left right and balanced cons strings. 18335 Handle<String> base = String::NewFromUtf8(isolate, "a"); 18336 Handle<String> left = base; 18337 Handle<String> right = base; 18338 for (int i = 0; i < 1000; i++) { 18339 left = String::Concat(base, left); 18340 right = String::Concat(right, base); 18341 } 18342 Handle<String> balanced = String::Concat(left, base); 18343 balanced = String::Concat(balanced, right); 18344 Handle<String> cons_strings[] = {left, balanced, right}; 18345 Handle<String> two_byte = 18346 String::NewExternal(isolate, new TestResource(string_contents)); 18347 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) { 18348 // Base assumptions. 18349 string = cons_strings[i]; 18350 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 18351 // Test left and right concatentation. 18352 string = String::Concat(two_byte, cons_strings[i]); 18353 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18354 string = String::Concat(cons_strings[i], two_byte); 18355 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 18356 } 18357 // Set bits in different positions 18358 // for strings of different lengths and alignments. 18359 for (int alignment = 0; alignment < 7; alignment++) { 18360 for (int size = 2; alignment + size < length; size *= 2) { 18361 int zero_offset = size + alignment; 18362 string_contents[zero_offset] = 0; 18363 for (int i = 0; i < size; i++) { 18364 int shift = 8 + (i % 7); 18365 string_contents[alignment + i] = 1 << shift; 18366 string = String::NewExternal( 18367 isolate, new TestResource(string_contents + alignment)); 18368 CHECK_EQ(size, string->Length()); 18369 CHECK(!string->ContainsOnlyOneByte()); 18370 string_contents[alignment + i] = 0x41; 18371 } 18372 string_contents[zero_offset] = 0x41; 18373 } 18374 } 18375 } 18376 18377 18378 // Failed access check callback that performs a GC on each invocation. 18379 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 18380 v8::AccessType type, 18381 Local<v8::Value> data) { 18382 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18383 } 18384 18385 18386 TEST(GCInFailedAccessCheckCallback) { 18387 // Install a failed access check callback that performs a GC on each 18388 // invocation. Then force the callback to be called from va 18389 18390 v8::V8::Initialize(); 18391 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 18392 18393 v8::HandleScope scope(CcTest::isolate()); 18394 18395 // Create an ObjectTemplate for global objects and install access 18396 // check callbacks that will block access. 18397 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 18398 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 18399 IndexedGetAccessBlocker, 18400 v8::Handle<v8::Value>(), 18401 false); 18402 18403 // Create a context and set an x property on it's global object. 18404 LocalContext context0(NULL, global_template); 18405 context0->Global()->Set(v8_str("x"), v8_num(42)); 18406 v8::Handle<v8::Object> global0 = context0->Global(); 18407 18408 // Create a context with a different security token so that the 18409 // failed access check callback will be called on each access. 18410 LocalContext context1(NULL, global_template); 18411 context1->Global()->Set(v8_str("other"), global0); 18412 18413 // Get property with failed access check. 18414 ExpectUndefined("other.x"); 18415 18416 // Get element with failed access check. 18417 ExpectUndefined("other[0]"); 18418 18419 // Set property with failed access check. 18420 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); 18421 CHECK(result->IsObject()); 18422 18423 // Set element with failed access check. 18424 result = CompileRun("other[0] = new Object()"); 18425 CHECK(result->IsObject()); 18426 18427 // Get property attribute with failed access check. 18428 ExpectFalse("\'x\' in other"); 18429 18430 // Get property attribute for element with failed access check. 18431 ExpectFalse("0 in other"); 18432 18433 // Delete property. 18434 ExpectFalse("delete other.x"); 18435 18436 // Delete element. 18437 CHECK_EQ(false, global0->Delete(0)); 18438 18439 // DefineAccessor. 18440 CHECK_EQ(false, 18441 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); 18442 18443 // Define JavaScript accessor. 18444 ExpectUndefined("Object.prototype.__defineGetter__.call(" 18445 " other, \'x\', function() { return 42; })"); 18446 18447 // LookupAccessor. 18448 ExpectUndefined("Object.prototype.__lookupGetter__.call(" 18449 " other, \'x\')"); 18450 18451 // HasLocalElement. 18452 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); 18453 18454 CHECK_EQ(false, global0->HasRealIndexedProperty(0)); 18455 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); 18456 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); 18457 18458 // Reset the failed access check callback so it does not influence 18459 // the other tests. 18460 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 18461 } 18462 18463 18464 TEST(IsolateNewDispose) { 18465 v8::Isolate* current_isolate = CcTest::isolate(); 18466 v8::Isolate* isolate = v8::Isolate::New(); 18467 CHECK(isolate != NULL); 18468 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 18469 CHECK(current_isolate != isolate); 18470 CHECK(current_isolate == CcTest::isolate()); 18471 18472 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 18473 last_location = last_message = NULL; 18474 isolate->Dispose(); 18475 CHECK_EQ(last_location, NULL); 18476 CHECK_EQ(last_message, NULL); 18477 } 18478 18479 18480 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) { 18481 v8::Isolate* isolate = v8::Isolate::New(); 18482 CHECK(isolate); 18483 isolate->Enter(); 18484 v8::HandleScope scope(isolate); 18485 LocalContext context(isolate); 18486 // Run something in this isolate. 18487 ExpectTrue("true"); 18488 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 18489 last_location = last_message = NULL; 18490 // Still entered, should fail. 18491 isolate->Dispose(); 18492 CHECK_NE(last_location, NULL); 18493 CHECK_NE(last_message, NULL); 18494 } 18495 18496 18497 TEST(RunTwoIsolatesOnSingleThread) { 18498 // Run isolate 1. 18499 v8::Isolate* isolate1 = v8::Isolate::New(); 18500 isolate1->Enter(); 18501 v8::Persistent<v8::Context> context1; 18502 { 18503 v8::HandleScope scope(isolate1); 18504 context1.Reset(isolate1, Context::New(isolate1)); 18505 } 18506 18507 { 18508 v8::HandleScope scope(isolate1); 18509 v8::Local<v8::Context> context = 18510 v8::Local<v8::Context>::New(isolate1, context1); 18511 v8::Context::Scope context_scope(context); 18512 // Run something in new isolate. 18513 CompileRun("var foo = 'isolate 1';"); 18514 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18515 } 18516 18517 // Run isolate 2. 18518 v8::Isolate* isolate2 = v8::Isolate::New(); 18519 v8::Persistent<v8::Context> context2; 18520 18521 { 18522 v8::Isolate::Scope iscope(isolate2); 18523 v8::HandleScope scope(isolate2); 18524 context2.Reset(isolate2, Context::New(isolate2)); 18525 v8::Local<v8::Context> context = 18526 v8::Local<v8::Context>::New(isolate2, context2); 18527 v8::Context::Scope context_scope(context); 18528 18529 // Run something in new isolate. 18530 CompileRun("var foo = 'isolate 2';"); 18531 ExpectString("function f() { return foo; }; f()", "isolate 2"); 18532 } 18533 18534 { 18535 v8::HandleScope scope(isolate1); 18536 v8::Local<v8::Context> context = 18537 v8::Local<v8::Context>::New(isolate1, context1); 18538 v8::Context::Scope context_scope(context); 18539 // Now again in isolate 1 18540 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18541 } 18542 18543 isolate1->Exit(); 18544 18545 // Run some stuff in default isolate. 18546 v8::Persistent<v8::Context> context_default; 18547 { 18548 v8::Isolate* isolate = CcTest::isolate(); 18549 v8::Isolate::Scope iscope(isolate); 18550 v8::HandleScope scope(isolate); 18551 context_default.Reset(isolate, Context::New(isolate)); 18552 } 18553 18554 { 18555 v8::HandleScope scope(CcTest::isolate()); 18556 v8::Local<v8::Context> context = 18557 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 18558 v8::Context::Scope context_scope(context); 18559 // Variables in other isolates should be not available, verify there 18560 // is an exception. 18561 ExpectTrue("function f() {" 18562 " try {" 18563 " foo;" 18564 " return false;" 18565 " } catch(e) {" 18566 " return true;" 18567 " }" 18568 "};" 18569 "var isDefaultIsolate = true;" 18570 "f()"); 18571 } 18572 18573 isolate1->Enter(); 18574 18575 { 18576 v8::Isolate::Scope iscope(isolate2); 18577 v8::HandleScope scope(isolate2); 18578 v8::Local<v8::Context> context = 18579 v8::Local<v8::Context>::New(isolate2, context2); 18580 v8::Context::Scope context_scope(context); 18581 ExpectString("function f() { return foo; }; f()", "isolate 2"); 18582 } 18583 18584 { 18585 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18586 v8::Local<v8::Context> context = 18587 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 18588 v8::Context::Scope context_scope(context); 18589 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18590 } 18591 18592 { 18593 v8::Isolate::Scope iscope(isolate2); 18594 context2.Reset(); 18595 } 18596 18597 context1.Reset(); 18598 isolate1->Exit(); 18599 18600 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 18601 last_location = last_message = NULL; 18602 18603 isolate1->Dispose(); 18604 CHECK_EQ(last_location, NULL); 18605 CHECK_EQ(last_message, NULL); 18606 18607 isolate2->Dispose(); 18608 CHECK_EQ(last_location, NULL); 18609 CHECK_EQ(last_message, NULL); 18610 18611 // Check that default isolate still runs. 18612 { 18613 v8::HandleScope scope(CcTest::isolate()); 18614 v8::Local<v8::Context> context = 18615 v8::Local<v8::Context>::New(CcTest::isolate(), context_default); 18616 v8::Context::Scope context_scope(context); 18617 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 18618 } 18619 } 18620 18621 18622 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 18623 v8::Isolate::Scope isolate_scope(isolate); 18624 v8::HandleScope scope(isolate); 18625 LocalContext context(isolate); 18626 i::ScopedVector<char> code(1024); 18627 i::OS::SNPrintF(code, "function fib(n) {" 18628 " if (n <= 2) return 1;" 18629 " return fib(n-1) + fib(n-2);" 18630 "}" 18631 "fib(%d)", limit); 18632 Local<Value> value = CompileRun(code.start()); 18633 CHECK(value->IsNumber()); 18634 return static_cast<int>(value->NumberValue()); 18635 } 18636 18637 class IsolateThread : public v8::internal::Thread { 18638 public: 18639 IsolateThread(v8::Isolate* isolate, int fib_limit) 18640 : Thread("IsolateThread"), 18641 isolate_(isolate), 18642 fib_limit_(fib_limit), 18643 result_(0) { } 18644 18645 void Run() { 18646 result_ = CalcFibonacci(isolate_, fib_limit_); 18647 } 18648 18649 int result() { return result_; } 18650 18651 private: 18652 v8::Isolate* isolate_; 18653 int fib_limit_; 18654 int result_; 18655 }; 18656 18657 18658 TEST(MultipleIsolatesOnIndividualThreads) { 18659 v8::Isolate* isolate1 = v8::Isolate::New(); 18660 v8::Isolate* isolate2 = v8::Isolate::New(); 18661 18662 IsolateThread thread1(isolate1, 21); 18663 IsolateThread thread2(isolate2, 12); 18664 18665 // Compute some fibonacci numbers on 3 threads in 3 isolates. 18666 thread1.Start(); 18667 thread2.Start(); 18668 18669 int result1 = CalcFibonacci(CcTest::isolate(), 21); 18670 int result2 = CalcFibonacci(CcTest::isolate(), 12); 18671 18672 thread1.Join(); 18673 thread2.Join(); 18674 18675 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 18676 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 18677 CHECK_EQ(result1, 10946); 18678 CHECK_EQ(result2, 144); 18679 CHECK_EQ(result1, thread1.result()); 18680 CHECK_EQ(result2, thread2.result()); 18681 18682 isolate1->Dispose(); 18683 isolate2->Dispose(); 18684 } 18685 18686 18687 TEST(IsolateDifferentContexts) { 18688 v8::Isolate* isolate = v8::Isolate::New(); 18689 Local<v8::Context> context; 18690 { 18691 v8::Isolate::Scope isolate_scope(isolate); 18692 v8::HandleScope handle_scope(isolate); 18693 context = v8::Context::New(isolate); 18694 v8::Context::Scope context_scope(context); 18695 Local<Value> v = CompileRun("2"); 18696 CHECK(v->IsNumber()); 18697 CHECK_EQ(2, static_cast<int>(v->NumberValue())); 18698 } 18699 { 18700 v8::Isolate::Scope isolate_scope(isolate); 18701 v8::HandleScope handle_scope(isolate); 18702 context = v8::Context::New(isolate); 18703 v8::Context::Scope context_scope(context); 18704 Local<Value> v = CompileRun("22"); 18705 CHECK(v->IsNumber()); 18706 CHECK_EQ(22, static_cast<int>(v->NumberValue())); 18707 } 18708 } 18709 18710 class InitDefaultIsolateThread : public v8::internal::Thread { 18711 public: 18712 enum TestCase { 18713 IgnoreOOM, 18714 SetResourceConstraints, 18715 SetFatalHandler, 18716 SetCounterFunction, 18717 SetCreateHistogramFunction, 18718 SetAddHistogramSampleFunction 18719 }; 18720 18721 explicit InitDefaultIsolateThread(TestCase testCase) 18722 : Thread("InitDefaultIsolateThread"), 18723 testCase_(testCase), 18724 result_(false) { } 18725 18726 void Run() { 18727 v8::Isolate* isolate = v8::Isolate::New(); 18728 isolate->Enter(); 18729 switch (testCase_) { 18730 case IgnoreOOM: 18731 v8::V8::IgnoreOutOfMemoryException(); 18732 break; 18733 18734 case SetResourceConstraints: { 18735 static const int K = 1024; 18736 v8::ResourceConstraints constraints; 18737 constraints.set_max_young_space_size(256 * K); 18738 constraints.set_max_old_space_size(4 * K * K); 18739 v8::SetResourceConstraints(CcTest::isolate(), &constraints); 18740 break; 18741 } 18742 18743 case SetFatalHandler: 18744 v8::V8::SetFatalErrorHandler(NULL); 18745 break; 18746 18747 case SetCounterFunction: 18748 v8::V8::SetCounterFunction(NULL); 18749 break; 18750 18751 case SetCreateHistogramFunction: 18752 v8::V8::SetCreateHistogramFunction(NULL); 18753 break; 18754 18755 case SetAddHistogramSampleFunction: 18756 v8::V8::SetAddHistogramSampleFunction(NULL); 18757 break; 18758 } 18759 isolate->Exit(); 18760 isolate->Dispose(); 18761 result_ = true; 18762 } 18763 18764 bool result() { return result_; } 18765 18766 private: 18767 TestCase testCase_; 18768 bool result_; 18769 }; 18770 18771 18772 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 18773 InitDefaultIsolateThread thread(testCase); 18774 thread.Start(); 18775 thread.Join(); 18776 CHECK_EQ(thread.result(), true); 18777 } 18778 18779 18780 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 18781 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM); 18782 } 18783 18784 18785 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 18786 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 18787 } 18788 18789 18790 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 18791 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 18792 } 18793 18794 18795 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 18796 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 18797 } 18798 18799 18800 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 18801 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 18802 } 18803 18804 18805 TEST(InitializeDefaultIsolateOnSecondaryThread6) { 18806 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 18807 } 18808 18809 18810 TEST(StringCheckMultipleContexts) { 18811 const char* code = 18812 "(function() { return \"a\".charAt(0); })()"; 18813 18814 { 18815 // Run the code twice in the first context to initialize the call IC. 18816 LocalContext context1; 18817 v8::HandleScope scope(context1->GetIsolate()); 18818 ExpectString(code, "a"); 18819 ExpectString(code, "a"); 18820 } 18821 18822 { 18823 // Change the String.prototype in the second context and check 18824 // that the right function gets called. 18825 LocalContext context2; 18826 v8::HandleScope scope(context2->GetIsolate()); 18827 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 18828 ExpectString(code, "not a"); 18829 } 18830 } 18831 18832 18833 TEST(NumberCheckMultipleContexts) { 18834 const char* code = 18835 "(function() { return (42).toString(); })()"; 18836 18837 { 18838 // Run the code twice in the first context to initialize the call IC. 18839 LocalContext context1; 18840 v8::HandleScope scope(context1->GetIsolate()); 18841 ExpectString(code, "42"); 18842 ExpectString(code, "42"); 18843 } 18844 18845 { 18846 // Change the Number.prototype in the second context and check 18847 // that the right function gets called. 18848 LocalContext context2; 18849 v8::HandleScope scope(context2->GetIsolate()); 18850 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 18851 ExpectString(code, "not 42"); 18852 } 18853 } 18854 18855 18856 TEST(BooleanCheckMultipleContexts) { 18857 const char* code = 18858 "(function() { return true.toString(); })()"; 18859 18860 { 18861 // Run the code twice in the first context to initialize the call IC. 18862 LocalContext context1; 18863 v8::HandleScope scope(context1->GetIsolate()); 18864 ExpectString(code, "true"); 18865 ExpectString(code, "true"); 18866 } 18867 18868 { 18869 // Change the Boolean.prototype in the second context and check 18870 // that the right function gets called. 18871 LocalContext context2; 18872 v8::HandleScope scope(context2->GetIsolate()); 18873 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 18874 ExpectString(code, ""); 18875 } 18876 } 18877 18878 18879 TEST(DontDeleteCellLoadIC) { 18880 const char* function_code = 18881 "function readCell() { while (true) { return cell; } }"; 18882 18883 { 18884 // Run the code twice in the first context to initialize the load 18885 // IC for a don't delete cell. 18886 LocalContext context1; 18887 v8::HandleScope scope(context1->GetIsolate()); 18888 CompileRun("var cell = \"first\";"); 18889 ExpectBoolean("delete cell", false); 18890 CompileRun(function_code); 18891 ExpectString("readCell()", "first"); 18892 ExpectString("readCell()", "first"); 18893 } 18894 18895 { 18896 // Use a deletable cell in the second context. 18897 LocalContext context2; 18898 v8::HandleScope scope(context2->GetIsolate()); 18899 CompileRun("cell = \"second\";"); 18900 CompileRun(function_code); 18901 ExpectString("readCell()", "second"); 18902 ExpectBoolean("delete cell", true); 18903 ExpectString("(function() {" 18904 " try {" 18905 " return readCell();" 18906 " } catch(e) {" 18907 " return e.toString();" 18908 " }" 18909 "})()", 18910 "ReferenceError: cell is not defined"); 18911 CompileRun("cell = \"new_second\";"); 18912 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 18913 ExpectString("readCell()", "new_second"); 18914 ExpectString("readCell()", "new_second"); 18915 } 18916 } 18917 18918 18919 TEST(DontDeleteCellLoadICForceDelete) { 18920 const char* function_code = 18921 "function readCell() { while (true) { return cell; } }"; 18922 18923 // Run the code twice to initialize the load IC for a don't delete 18924 // cell. 18925 LocalContext context; 18926 v8::HandleScope scope(context->GetIsolate()); 18927 CompileRun("var cell = \"value\";"); 18928 ExpectBoolean("delete cell", false); 18929 CompileRun(function_code); 18930 ExpectString("readCell()", "value"); 18931 ExpectString("readCell()", "value"); 18932 18933 // Delete the cell using the API and check the inlined code works 18934 // correctly. 18935 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 18936 ExpectString("(function() {" 18937 " try {" 18938 " return readCell();" 18939 " } catch(e) {" 18940 " return e.toString();" 18941 " }" 18942 "})()", 18943 "ReferenceError: cell is not defined"); 18944 } 18945 18946 18947 TEST(DontDeleteCellLoadICAPI) { 18948 const char* function_code = 18949 "function readCell() { while (true) { return cell; } }"; 18950 18951 // Run the code twice to initialize the load IC for a don't delete 18952 // cell created using the API. 18953 LocalContext context; 18954 v8::HandleScope scope(context->GetIsolate()); 18955 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); 18956 ExpectBoolean("delete cell", false); 18957 CompileRun(function_code); 18958 ExpectString("readCell()", "value"); 18959 ExpectString("readCell()", "value"); 18960 18961 // Delete the cell using the API and check the inlined code works 18962 // correctly. 18963 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 18964 ExpectString("(function() {" 18965 " try {" 18966 " return readCell();" 18967 " } catch(e) {" 18968 " return e.toString();" 18969 " }" 18970 "})()", 18971 "ReferenceError: cell is not defined"); 18972 } 18973 18974 18975 class Visitor42 : public v8::PersistentHandleVisitor { 18976 public: 18977 explicit Visitor42(v8::Persistent<v8::Object>* object) 18978 : counter_(0), object_(object) { } 18979 18980 virtual void VisitPersistentHandle(Persistent<Value>* value, 18981 uint16_t class_id) { 18982 if (class_id != 42) return; 18983 CHECK_EQ(42, value->WrapperClassId()); 18984 v8::Isolate* isolate = CcTest::isolate(); 18985 v8::HandleScope handle_scope(isolate); 18986 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 18987 v8::Handle<v8::Value> object = 18988 v8::Local<v8::Object>::New(isolate, *object_); 18989 CHECK(handle->IsObject()); 18990 CHECK_EQ(Handle<Object>::Cast(handle), object); 18991 ++counter_; 18992 } 18993 18994 int counter_; 18995 v8::Persistent<v8::Object>* object_; 18996 }; 18997 18998 18999 TEST(PersistentHandleVisitor) { 19000 LocalContext context; 19001 v8::Isolate* isolate = context->GetIsolate(); 19002 v8::HandleScope scope(isolate); 19003 v8::Persistent<v8::Object> object(isolate, v8::Object::New()); 19004 CHECK_EQ(0, object.WrapperClassId()); 19005 object.SetWrapperClassId(42); 19006 CHECK_EQ(42, object.WrapperClassId()); 19007 19008 Visitor42 visitor(&object); 19009 v8::V8::VisitHandlesWithClassIds(&visitor); 19010 CHECK_EQ(1, visitor.counter_); 19011 19012 object.Reset(); 19013 } 19014 19015 19016 TEST(WrapperClassId) { 19017 LocalContext context; 19018 v8::Isolate* isolate = context->GetIsolate(); 19019 v8::HandleScope scope(isolate); 19020 v8::Persistent<v8::Object> object(isolate, v8::Object::New()); 19021 CHECK_EQ(0, object.WrapperClassId()); 19022 object.SetWrapperClassId(65535); 19023 CHECK_EQ(65535, object.WrapperClassId()); 19024 object.Reset(); 19025 } 19026 19027 19028 TEST(PersistentHandleInNewSpaceVisitor) { 19029 LocalContext context; 19030 v8::Isolate* isolate = context->GetIsolate(); 19031 v8::HandleScope scope(isolate); 19032 v8::Persistent<v8::Object> object1(isolate, v8::Object::New()); 19033 CHECK_EQ(0, object1.WrapperClassId()); 19034 object1.SetWrapperClassId(42); 19035 CHECK_EQ(42, object1.WrapperClassId()); 19036 19037 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 19038 19039 v8::Persistent<v8::Object> object2(isolate, v8::Object::New()); 19040 CHECK_EQ(0, object2.WrapperClassId()); 19041 object2.SetWrapperClassId(42); 19042 CHECK_EQ(42, object2.WrapperClassId()); 19043 19044 Visitor42 visitor(&object2); 19045 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); 19046 CHECK_EQ(1, visitor.counter_); 19047 19048 object1.Reset(); 19049 object2.Reset(); 19050 } 19051 19052 19053 TEST(RegExp) { 19054 LocalContext context; 19055 v8::HandleScope scope(context->GetIsolate()); 19056 19057 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone); 19058 CHECK(re->IsRegExp()); 19059 CHECK(re->GetSource()->Equals(v8_str("foo"))); 19060 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19061 19062 re = v8::RegExp::New(v8_str("bar"), 19063 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19064 v8::RegExp::kGlobal)); 19065 CHECK(re->IsRegExp()); 19066 CHECK(re->GetSource()->Equals(v8_str("bar"))); 19067 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 19068 static_cast<int>(re->GetFlags())); 19069 19070 re = v8::RegExp::New(v8_str("baz"), 19071 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19072 v8::RegExp::kMultiline)); 19073 CHECK(re->IsRegExp()); 19074 CHECK(re->GetSource()->Equals(v8_str("baz"))); 19075 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19076 static_cast<int>(re->GetFlags())); 19077 19078 re = CompileRun("/quux/").As<v8::RegExp>(); 19079 CHECK(re->IsRegExp()); 19080 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19081 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19082 19083 re = CompileRun("/quux/gm").As<v8::RegExp>(); 19084 CHECK(re->IsRegExp()); 19085 CHECK(re->GetSource()->Equals(v8_str("quux"))); 19086 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 19087 static_cast<int>(re->GetFlags())); 19088 19089 // Override the RegExp constructor and check the API constructor 19090 // still works. 19091 CompileRun("RegExp = function() {}"); 19092 19093 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone); 19094 CHECK(re->IsRegExp()); 19095 CHECK(re->GetSource()->Equals(v8_str("foobar"))); 19096 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 19097 19098 re = v8::RegExp::New(v8_str("foobarbaz"), 19099 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 19100 v8::RegExp::kMultiline)); 19101 CHECK(re->IsRegExp()); 19102 CHECK(re->GetSource()->Equals(v8_str("foobarbaz"))); 19103 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 19104 static_cast<int>(re->GetFlags())); 19105 19106 context->Global()->Set(v8_str("re"), re); 19107 ExpectTrue("re.test('FoobarbaZ')"); 19108 19109 // RegExps are objects on which you can set properties. 19110 re->Set(v8_str("property"), v8::Integer::New(32)); 19111 v8::Handle<v8::Value> value(CompileRun("re.property")); 19112 CHECK_EQ(32, value->Int32Value()); 19113 19114 v8::TryCatch try_catch; 19115 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); 19116 CHECK(re.IsEmpty()); 19117 CHECK(try_catch.HasCaught()); 19118 context->Global()->Set(v8_str("ex"), try_catch.Exception()); 19119 ExpectTrue("ex instanceof SyntaxError"); 19120 } 19121 19122 19123 THREADED_TEST(Equals) { 19124 LocalContext localContext; 19125 v8::HandleScope handleScope(localContext->GetIsolate()); 19126 19127 v8::Handle<v8::Object> globalProxy = localContext->Global(); 19128 v8::Handle<Value> global = globalProxy->GetPrototype(); 19129 19130 CHECK(global->StrictEquals(global)); 19131 CHECK(!global->StrictEquals(globalProxy)); 19132 CHECK(!globalProxy->StrictEquals(global)); 19133 CHECK(globalProxy->StrictEquals(globalProxy)); 19134 19135 CHECK(global->Equals(global)); 19136 CHECK(!global->Equals(globalProxy)); 19137 CHECK(!globalProxy->Equals(global)); 19138 CHECK(globalProxy->Equals(globalProxy)); 19139 } 19140 19141 19142 static void Getter(v8::Local<v8::String> property, 19143 const v8::PropertyCallbackInfo<v8::Value>& info ) { 19144 info.GetReturnValue().Set(v8_str("42!")); 19145 } 19146 19147 19148 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 19149 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate()); 19150 result->Set(0, v8_str("universalAnswer")); 19151 info.GetReturnValue().Set(result); 19152 } 19153 19154 19155 TEST(NamedEnumeratorAndForIn) { 19156 LocalContext context; 19157 v8::HandleScope handle_scope(context->GetIsolate()); 19158 v8::Context::Scope context_scope(context.local()); 19159 19160 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(); 19161 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); 19162 context->Global()->Set(v8_str("o"), tmpl->NewInstance()); 19163 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 19164 "var result = []; for (var k in o) result.push(k); result")); 19165 CHECK_EQ(1, result->Length()); 19166 CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); 19167 } 19168 19169 19170 TEST(DefinePropertyPostDetach) { 19171 LocalContext context; 19172 v8::HandleScope scope(context->GetIsolate()); 19173 v8::Handle<v8::Object> proxy = context->Global(); 19174 v8::Handle<v8::Function> define_property = 19175 CompileRun("(function() {" 19176 " Object.defineProperty(" 19177 " this," 19178 " 1," 19179 " { configurable: true, enumerable: true, value: 3 });" 19180 "})").As<Function>(); 19181 context->DetachGlobal(); 19182 define_property->Call(proxy, 0, NULL); 19183 } 19184 19185 19186 static void InstallContextId(v8::Handle<Context> context, int id) { 19187 Context::Scope scope(context); 19188 CompileRun("Object.prototype").As<Object>()-> 19189 Set(v8_str("context_id"), v8::Integer::New(id)); 19190 } 19191 19192 19193 static void CheckContextId(v8::Handle<Object> object, int expected) { 19194 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value()); 19195 } 19196 19197 19198 THREADED_TEST(CreationContext) { 19199 HandleScope handle_scope(CcTest::isolate()); 19200 Handle<Context> context1 = Context::New(CcTest::isolate()); 19201 InstallContextId(context1, 1); 19202 Handle<Context> context2 = Context::New(CcTest::isolate()); 19203 InstallContextId(context2, 2); 19204 Handle<Context> context3 = Context::New(CcTest::isolate()); 19205 InstallContextId(context3, 3); 19206 19207 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(); 19208 19209 Local<Object> object1; 19210 Local<Function> func1; 19211 { 19212 Context::Scope scope(context1); 19213 object1 = Object::New(); 19214 func1 = tmpl->GetFunction(); 19215 } 19216 19217 Local<Object> object2; 19218 Local<Function> func2; 19219 { 19220 Context::Scope scope(context2); 19221 object2 = Object::New(); 19222 func2 = tmpl->GetFunction(); 19223 } 19224 19225 Local<Object> instance1; 19226 Local<Object> instance2; 19227 19228 { 19229 Context::Scope scope(context3); 19230 instance1 = func1->NewInstance(); 19231 instance2 = func2->NewInstance(); 19232 } 19233 19234 CHECK(object1->CreationContext() == context1); 19235 CheckContextId(object1, 1); 19236 CHECK(func1->CreationContext() == context1); 19237 CheckContextId(func1, 1); 19238 CHECK(instance1->CreationContext() == context1); 19239 CheckContextId(instance1, 1); 19240 CHECK(object2->CreationContext() == context2); 19241 CheckContextId(object2, 2); 19242 CHECK(func2->CreationContext() == context2); 19243 CheckContextId(func2, 2); 19244 CHECK(instance2->CreationContext() == context2); 19245 CheckContextId(instance2, 2); 19246 19247 { 19248 Context::Scope scope(context1); 19249 CHECK(object1->CreationContext() == context1); 19250 CheckContextId(object1, 1); 19251 CHECK(func1->CreationContext() == context1); 19252 CheckContextId(func1, 1); 19253 CHECK(instance1->CreationContext() == context1); 19254 CheckContextId(instance1, 1); 19255 CHECK(object2->CreationContext() == context2); 19256 CheckContextId(object2, 2); 19257 CHECK(func2->CreationContext() == context2); 19258 CheckContextId(func2, 2); 19259 CHECK(instance2->CreationContext() == context2); 19260 CheckContextId(instance2, 2); 19261 } 19262 19263 { 19264 Context::Scope scope(context2); 19265 CHECK(object1->CreationContext() == context1); 19266 CheckContextId(object1, 1); 19267 CHECK(func1->CreationContext() == context1); 19268 CheckContextId(func1, 1); 19269 CHECK(instance1->CreationContext() == context1); 19270 CheckContextId(instance1, 1); 19271 CHECK(object2->CreationContext() == context2); 19272 CheckContextId(object2, 2); 19273 CHECK(func2->CreationContext() == context2); 19274 CheckContextId(func2, 2); 19275 CHECK(instance2->CreationContext() == context2); 19276 CheckContextId(instance2, 2); 19277 } 19278 } 19279 19280 19281 THREADED_TEST(CreationContextOfJsFunction) { 19282 HandleScope handle_scope(CcTest::isolate()); 19283 Handle<Context> context = Context::New(CcTest::isolate()); 19284 InstallContextId(context, 1); 19285 19286 Local<Object> function; 19287 { 19288 Context::Scope scope(context); 19289 function = CompileRun("function foo() {}; foo").As<Object>(); 19290 } 19291 19292 CHECK(function->CreationContext() == context); 19293 CheckContextId(function, 1); 19294 } 19295 19296 19297 void HasOwnPropertyIndexedPropertyGetter( 19298 uint32_t index, 19299 const v8::PropertyCallbackInfo<v8::Value>& info) { 19300 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 19301 } 19302 19303 19304 void HasOwnPropertyNamedPropertyGetter( 19305 Local<String> property, 19306 const v8::PropertyCallbackInfo<v8::Value>& info) { 19307 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes")); 19308 } 19309 19310 19311 void HasOwnPropertyIndexedPropertyQuery( 19312 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 19313 if (index == 42) info.GetReturnValue().Set(1); 19314 } 19315 19316 19317 void HasOwnPropertyNamedPropertyQuery( 19318 Local<String> property, 19319 const v8::PropertyCallbackInfo<v8::Integer>& info) { 19320 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1); 19321 } 19322 19323 19324 void HasOwnPropertyNamedPropertyQuery2( 19325 Local<String> property, 19326 const v8::PropertyCallbackInfo<v8::Integer>& info) { 19327 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1); 19328 } 19329 19330 19331 void HasOwnPropertyAccessorGetter( 19332 Local<String> property, 19333 const v8::PropertyCallbackInfo<v8::Value>& info) { 19334 info.GetReturnValue().Set(v8_str("yes")); 19335 } 19336 19337 19338 TEST(HasOwnProperty) { 19339 LocalContext env; 19340 v8::HandleScope scope(env->GetIsolate()); 19341 { // Check normal properties and defined getters. 19342 Handle<Value> value = CompileRun( 19343 "function Foo() {" 19344 " this.foo = 11;" 19345 " this.__defineGetter__('baz', function() { return 1; });" 19346 "};" 19347 "function Bar() { " 19348 " this.bar = 13;" 19349 " this.__defineGetter__('bla', function() { return 2; });" 19350 "};" 19351 "Bar.prototype = new Foo();" 19352 "new Bar();"); 19353 CHECK(value->IsObject()); 19354 Handle<Object> object = value->ToObject(); 19355 CHECK(object->Has(v8_str("foo"))); 19356 CHECK(!object->HasOwnProperty(v8_str("foo"))); 19357 CHECK(object->HasOwnProperty(v8_str("bar"))); 19358 CHECK(object->Has(v8_str("baz"))); 19359 CHECK(!object->HasOwnProperty(v8_str("baz"))); 19360 CHECK(object->HasOwnProperty(v8_str("bla"))); 19361 } 19362 { // Check named getter interceptors. 19363 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19364 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter); 19365 Handle<Object> instance = templ->NewInstance(); 19366 CHECK(!instance->HasOwnProperty(v8_str("42"))); 19367 CHECK(instance->HasOwnProperty(v8_str("foo"))); 19368 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 19369 } 19370 { // Check indexed getter interceptors. 19371 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19372 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter); 19373 Handle<Object> instance = templ->NewInstance(); 19374 CHECK(instance->HasOwnProperty(v8_str("42"))); 19375 CHECK(!instance->HasOwnProperty(v8_str("43"))); 19376 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 19377 } 19378 { // Check named query interceptors. 19379 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19380 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery); 19381 Handle<Object> instance = templ->NewInstance(); 19382 CHECK(instance->HasOwnProperty(v8_str("foo"))); 19383 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 19384 } 19385 { // Check indexed query interceptors. 19386 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19387 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery); 19388 Handle<Object> instance = templ->NewInstance(); 19389 CHECK(instance->HasOwnProperty(v8_str("42"))); 19390 CHECK(!instance->HasOwnProperty(v8_str("41"))); 19391 } 19392 { // Check callbacks. 19393 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19394 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 19395 Handle<Object> instance = templ->NewInstance(); 19396 CHECK(instance->HasOwnProperty(v8_str("foo"))); 19397 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 19398 } 19399 { // Check that query wins on disagreement. 19400 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19401 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter, 19402 0, 19403 HasOwnPropertyNamedPropertyQuery2); 19404 Handle<Object> instance = templ->NewInstance(); 19405 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 19406 CHECK(instance->HasOwnProperty(v8_str("bar"))); 19407 } 19408 } 19409 19410 19411 TEST(IndexedInterceptorWithStringProto) { 19412 v8::HandleScope scope(CcTest::isolate()); 19413 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 19414 templ->SetIndexedPropertyHandler(NULL, 19415 NULL, 19416 HasOwnPropertyIndexedPropertyQuery); 19417 LocalContext context; 19418 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 19419 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 19420 // These should be intercepted. 19421 CHECK(CompileRun("42 in obj")->BooleanValue()); 19422 CHECK(CompileRun("'42' in obj")->BooleanValue()); 19423 // These should fall through to the String prototype. 19424 CHECK(CompileRun("0 in obj")->BooleanValue()); 19425 CHECK(CompileRun("'0' in obj")->BooleanValue()); 19426 // And these should both fail. 19427 CHECK(!CompileRun("32 in obj")->BooleanValue()); 19428 CHECK(!CompileRun("'32' in obj")->BooleanValue()); 19429 } 19430 19431 19432 void CheckCodeGenerationAllowed() { 19433 Handle<Value> result = CompileRun("eval('42')"); 19434 CHECK_EQ(42, result->Int32Value()); 19435 result = CompileRun("(function(e) { return e('42'); })(eval)"); 19436 CHECK_EQ(42, result->Int32Value()); 19437 result = CompileRun("var f = new Function('return 42'); f()"); 19438 CHECK_EQ(42, result->Int32Value()); 19439 } 19440 19441 19442 void CheckCodeGenerationDisallowed() { 19443 TryCatch try_catch; 19444 19445 Handle<Value> result = CompileRun("eval('42')"); 19446 CHECK(result.IsEmpty()); 19447 CHECK(try_catch.HasCaught()); 19448 try_catch.Reset(); 19449 19450 result = CompileRun("(function(e) { return e('42'); })(eval)"); 19451 CHECK(result.IsEmpty()); 19452 CHECK(try_catch.HasCaught()); 19453 try_catch.Reset(); 19454 19455 result = CompileRun("var f = new Function('return 42'); f()"); 19456 CHECK(result.IsEmpty()); 19457 CHECK(try_catch.HasCaught()); 19458 } 19459 19460 19461 bool CodeGenerationAllowed(Local<Context> context) { 19462 ApiTestFuzzer::Fuzz(); 19463 return true; 19464 } 19465 19466 19467 bool CodeGenerationDisallowed(Local<Context> context) { 19468 ApiTestFuzzer::Fuzz(); 19469 return false; 19470 } 19471 19472 19473 THREADED_TEST(AllowCodeGenFromStrings) { 19474 LocalContext context; 19475 v8::HandleScope scope(context->GetIsolate()); 19476 19477 // eval and the Function constructor allowed by default. 19478 CHECK(context->IsCodeGenerationFromStringsAllowed()); 19479 CheckCodeGenerationAllowed(); 19480 19481 // Disallow eval and the Function constructor. 19482 context->AllowCodeGenerationFromStrings(false); 19483 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 19484 CheckCodeGenerationDisallowed(); 19485 19486 // Allow again. 19487 context->AllowCodeGenerationFromStrings(true); 19488 CheckCodeGenerationAllowed(); 19489 19490 // Disallow but setting a global callback that will allow the calls. 19491 context->AllowCodeGenerationFromStrings(false); 19492 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed); 19493 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 19494 CheckCodeGenerationAllowed(); 19495 19496 // Set a callback that disallows the code generation. 19497 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 19498 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 19499 CheckCodeGenerationDisallowed(); 19500 } 19501 19502 19503 TEST(SetErrorMessageForCodeGenFromStrings) { 19504 LocalContext context; 19505 v8::HandleScope scope(context->GetIsolate()); 19506 TryCatch try_catch; 19507 19508 Handle<String> message = v8_str("Message") ; 19509 Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); 19510 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 19511 context->AllowCodeGenerationFromStrings(false); 19512 context->SetErrorMessageForCodeGenerationFromStrings(message); 19513 Handle<Value> result = CompileRun("eval('42')"); 19514 CHECK(result.IsEmpty()); 19515 CHECK(try_catch.HasCaught()); 19516 Handle<String> actual_message = try_catch.Message()->Get(); 19517 CHECK(expected_message->Equals(actual_message)); 19518 } 19519 19520 19521 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 19522 } 19523 19524 19525 THREADED_TEST(CallAPIFunctionOnNonObject) { 19526 LocalContext context; 19527 v8::HandleScope scope(context->GetIsolate()); 19528 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis); 19529 Handle<Function> function = templ->GetFunction(); 19530 context->Global()->Set(v8_str("f"), function); 19531 TryCatch try_catch; 19532 CompileRun("f.call(2)"); 19533 } 19534 19535 19536 // Regression test for issue 1470. 19537 THREADED_TEST(ReadOnlyIndexedProperties) { 19538 v8::HandleScope scope(CcTest::isolate()); 19539 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19540 19541 LocalContext context; 19542 Local<v8::Object> obj = templ->NewInstance(); 19543 context->Global()->Set(v8_str("obj"), obj); 19544 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); 19545 obj->Set(v8_str("1"), v8_str("foobar")); 19546 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); 19547 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); 19548 obj->Set(v8_num(2), v8_str("foobar")); 19549 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); 19550 19551 // Test non-smi case. 19552 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); 19553 obj->Set(v8_str("2000000000"), v8_str("foobar")); 19554 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); 19555 } 19556 19557 19558 THREADED_TEST(Regress1516) { 19559 LocalContext context; 19560 v8::HandleScope scope(context->GetIsolate()); 19561 19562 { v8::HandleScope temp_scope(context->GetIsolate()); 19563 CompileRun("({'a': 0})"); 19564 } 19565 19566 int elements; 19567 { i::MapCache* map_cache = 19568 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache()); 19569 elements = map_cache->NumberOfElements(); 19570 CHECK_LE(1, elements); 19571 } 19572 19573 CcTest::heap()->CollectAllGarbage( 19574 i::Heap::kAbortIncrementalMarkingMask); 19575 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache(); 19576 if (raw_map_cache != CcTest::heap()->undefined_value()) { 19577 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache); 19578 CHECK_GT(elements, map_cache->NumberOfElements()); 19579 } 19580 } 19581 } 19582 19583 19584 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, 19585 Local<Value> name, 19586 v8::AccessType type, 19587 Local<Value> data) { 19588 // Only block read access to __proto__. 19589 if (type == v8::ACCESS_GET && 19590 name->IsString() && 19591 name->ToString()->Length() == 9 && 19592 name->ToString()->Utf8Length() == 9) { 19593 char buffer[10]; 19594 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); 19595 return strncmp(buffer, "__proto__", 9) != 0; 19596 } 19597 19598 return true; 19599 } 19600 19601 19602 THREADED_TEST(Regress93759) { 19603 v8::Isolate* isolate = CcTest::isolate(); 19604 HandleScope scope(isolate); 19605 19606 // Template for object with security check. 19607 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(); 19608 // We don't do indexing, so any callback can be used for that. 19609 no_proto_template->SetAccessCheckCallbacks( 19610 BlockProtoNamedSecurityTestCallback, 19611 IndexedSecurityTestCallback); 19612 19613 // Templates for objects with hidden prototypes and possibly security check. 19614 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New(); 19615 hidden_proto_template->SetHiddenPrototype(true); 19616 19617 Local<FunctionTemplate> protected_hidden_proto_template = 19618 v8::FunctionTemplate::New(); 19619 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( 19620 BlockProtoNamedSecurityTestCallback, 19621 IndexedSecurityTestCallback); 19622 protected_hidden_proto_template->SetHiddenPrototype(true); 19623 19624 // Context for "foreign" objects used in test. 19625 Local<Context> context = v8::Context::New(isolate); 19626 context->Enter(); 19627 19628 // Plain object, no security check. 19629 Local<Object> simple_object = Object::New(); 19630 19631 // Object with explicit security check. 19632 Local<Object> protected_object = 19633 no_proto_template->NewInstance(); 19634 19635 // JSGlobalProxy object, always have security check. 19636 Local<Object> proxy_object = 19637 context->Global(); 19638 19639 // Global object, the prototype of proxy_object. No security checks. 19640 Local<Object> global_object = 19641 proxy_object->GetPrototype()->ToObject(); 19642 19643 // Hidden prototype without security check. 19644 Local<Object> hidden_prototype = 19645 hidden_proto_template->GetFunction()->NewInstance(); 19646 Local<Object> object_with_hidden = 19647 Object::New(); 19648 object_with_hidden->SetPrototype(hidden_prototype); 19649 19650 // Hidden prototype with security check on the hidden prototype. 19651 Local<Object> protected_hidden_prototype = 19652 protected_hidden_proto_template->GetFunction()->NewInstance(); 19653 Local<Object> object_with_protected_hidden = 19654 Object::New(); 19655 object_with_protected_hidden->SetPrototype(protected_hidden_prototype); 19656 19657 context->Exit(); 19658 19659 // Template for object for second context. Values to test are put on it as 19660 // properties. 19661 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 19662 global_template->Set(v8_str("simple"), simple_object); 19663 global_template->Set(v8_str("protected"), protected_object); 19664 global_template->Set(v8_str("global"), global_object); 19665 global_template->Set(v8_str("proxy"), proxy_object); 19666 global_template->Set(v8_str("hidden"), object_with_hidden); 19667 global_template->Set(v8_str("phidden"), object_with_protected_hidden); 19668 19669 LocalContext context2(NULL, global_template); 19670 19671 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 19672 CHECK(result1->Equals(simple_object->GetPrototype())); 19673 19674 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 19675 CHECK(result2->Equals(Undefined(isolate))); 19676 19677 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 19678 CHECK(result3->Equals(global_object->GetPrototype())); 19679 19680 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 19681 CHECK(result4->Equals(Undefined(isolate))); 19682 19683 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 19684 CHECK(result5->Equals( 19685 object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); 19686 19687 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); 19688 CHECK(result6->Equals(Undefined(isolate))); 19689 } 19690 19691 19692 THREADED_TEST(Regress125988) { 19693 v8::HandleScope scope(CcTest::isolate()); 19694 Handle<FunctionTemplate> intercept = FunctionTemplate::New(); 19695 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter); 19696 LocalContext env; 19697 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction()); 19698 CompileRun("var a = new Object();" 19699 "var b = new Intercept();" 19700 "var c = new Object();" 19701 "c.__proto__ = b;" 19702 "b.__proto__ = a;" 19703 "a.x = 23;" 19704 "for (var i = 0; i < 3; i++) c.x;"); 19705 ExpectBoolean("c.hasOwnProperty('x')", false); 19706 ExpectInt32("c.x", 23); 19707 CompileRun("a.y = 42;" 19708 "for (var i = 0; i < 3; i++) c.x;"); 19709 ExpectBoolean("c.hasOwnProperty('x')", false); 19710 ExpectInt32("c.x", 23); 19711 ExpectBoolean("c.hasOwnProperty('y')", false); 19712 ExpectInt32("c.y", 42); 19713 } 19714 19715 19716 static void TestReceiver(Local<Value> expected_result, 19717 Local<Value> expected_receiver, 19718 const char* code) { 19719 Local<Value> result = CompileRun(code); 19720 CHECK(result->IsObject()); 19721 CHECK(expected_receiver->Equals(result->ToObject()->Get(1))); 19722 CHECK(expected_result->Equals(result->ToObject()->Get(0))); 19723 } 19724 19725 19726 THREADED_TEST(ForeignFunctionReceiver) { 19727 v8::Isolate* isolate = CcTest::isolate(); 19728 HandleScope scope(isolate); 19729 19730 // Create two contexts with different "id" properties ('i' and 'o'). 19731 // Call a function both from its own context and from a the foreign 19732 // context, and see what "this" is bound to (returning both "this" 19733 // and "this.id" for comparison). 19734 19735 Local<Context> foreign_context = v8::Context::New(isolate); 19736 foreign_context->Enter(); 19737 Local<Value> foreign_function = 19738 CompileRun("function func() { return { 0: this.id, " 19739 " 1: this, " 19740 " toString: function() { " 19741 " return this[0];" 19742 " }" 19743 " };" 19744 "}" 19745 "var id = 'i';" 19746 "func;"); 19747 CHECK(foreign_function->IsFunction()); 19748 foreign_context->Exit(); 19749 19750 LocalContext context; 19751 19752 Local<String> password = v8_str("Password"); 19753 // Don't get hit by security checks when accessing foreign_context's 19754 // global receiver (aka. global proxy). 19755 context->SetSecurityToken(password); 19756 foreign_context->SetSecurityToken(password); 19757 19758 Local<String> i = v8_str("i"); 19759 Local<String> o = v8_str("o"); 19760 Local<String> id = v8_str("id"); 19761 19762 CompileRun("function ownfunc() { return { 0: this.id, " 19763 " 1: this, " 19764 " toString: function() { " 19765 " return this[0];" 19766 " }" 19767 " };" 19768 "}" 19769 "var id = 'o';" 19770 "ownfunc"); 19771 context->Global()->Set(v8_str("func"), foreign_function); 19772 19773 // Sanity check the contexts. 19774 CHECK(i->Equals(foreign_context->Global()->Get(id))); 19775 CHECK(o->Equals(context->Global()->Get(id))); 19776 19777 // Checking local function's receiver. 19778 // Calling function using its call/apply methods. 19779 TestReceiver(o, context->Global(), "ownfunc.call()"); 19780 TestReceiver(o, context->Global(), "ownfunc.apply()"); 19781 // Making calls through built-in functions. 19782 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 19783 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))); 19784 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))); 19785 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))); 19786 // Calling with environment record as base. 19787 TestReceiver(o, context->Global(), "ownfunc()"); 19788 // Calling with no base. 19789 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 19790 19791 // Checking foreign function return value. 19792 // Calling function using its call/apply methods. 19793 TestReceiver(i, foreign_context->Global(), "func.call()"); 19794 TestReceiver(i, foreign_context->Global(), "func.apply()"); 19795 // Calling function using another context's call/apply methods. 19796 TestReceiver(i, foreign_context->Global(), 19797 "Function.prototype.call.call(func)"); 19798 TestReceiver(i, foreign_context->Global(), 19799 "Function.prototype.call.apply(func)"); 19800 TestReceiver(i, foreign_context->Global(), 19801 "Function.prototype.apply.call(func)"); 19802 TestReceiver(i, foreign_context->Global(), 19803 "Function.prototype.apply.apply(func)"); 19804 // Making calls through built-in functions. 19805 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 19806 // ToString(func()) is func()[0], i.e., the returned this.id. 19807 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]"))); 19808 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]"))); 19809 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]"))); 19810 19811 // TODO(1547): Make the following also return "i". 19812 // Calling with environment record as base. 19813 TestReceiver(o, context->Global(), "func()"); 19814 // Calling with no base. 19815 TestReceiver(o, context->Global(), "(1,func)()"); 19816 } 19817 19818 19819 uint8_t callback_fired = 0; 19820 19821 19822 void CallCompletedCallback1() { 19823 i::OS::Print("Firing callback 1.\n"); 19824 callback_fired ^= 1; // Toggle first bit. 19825 } 19826 19827 19828 void CallCompletedCallback2() { 19829 i::OS::Print("Firing callback 2.\n"); 19830 callback_fired ^= 2; // Toggle second bit. 19831 } 19832 19833 19834 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 19835 int32_t level = args[0]->Int32Value(); 19836 if (level < 3) { 19837 level++; 19838 i::OS::Print("Entering recursion level %d.\n", level); 19839 char script[64]; 19840 i::Vector<char> script_vector(script, sizeof(script)); 19841 i::OS::SNPrintF(script_vector, "recursion(%d)", level); 19842 CompileRun(script_vector.start()); 19843 i::OS::Print("Leaving recursion level %d.\n", level); 19844 CHECK_EQ(0, callback_fired); 19845 } else { 19846 i::OS::Print("Recursion ends.\n"); 19847 CHECK_EQ(0, callback_fired); 19848 } 19849 } 19850 19851 19852 TEST(CallCompletedCallback) { 19853 LocalContext env; 19854 v8::HandleScope scope(env->GetIsolate()); 19855 v8::Handle<v8::FunctionTemplate> recursive_runtime = 19856 v8::FunctionTemplate::New(RecursiveCall); 19857 env->Global()->Set(v8_str("recursion"), 19858 recursive_runtime->GetFunction()); 19859 // Adding the same callback a second time has no effect. 19860 v8::V8::AddCallCompletedCallback(CallCompletedCallback1); 19861 v8::V8::AddCallCompletedCallback(CallCompletedCallback1); 19862 v8::V8::AddCallCompletedCallback(CallCompletedCallback2); 19863 i::OS::Print("--- Script (1) ---\n"); 19864 Local<Script> script = v8::Script::Compile( 19865 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)")); 19866 script->Run(); 19867 CHECK_EQ(3, callback_fired); 19868 19869 i::OS::Print("\n--- Script (2) ---\n"); 19870 callback_fired = 0; 19871 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1); 19872 script->Run(); 19873 CHECK_EQ(2, callback_fired); 19874 19875 i::OS::Print("\n--- Function ---\n"); 19876 callback_fired = 0; 19877 Local<Function> recursive_function = 19878 Local<Function>::Cast(env->Global()->Get(v8_str("recursion"))); 19879 v8::Handle<Value> args[] = { v8_num(0) }; 19880 recursive_function->Call(env->Global(), 1, args); 19881 CHECK_EQ(2, callback_fired); 19882 } 19883 19884 19885 void CallCompletedCallbackNoException() { 19886 v8::HandleScope scope(CcTest::isolate()); 19887 CompileRun("1+1;"); 19888 } 19889 19890 19891 void CallCompletedCallbackException() { 19892 v8::HandleScope scope(CcTest::isolate()); 19893 CompileRun("throw 'second exception';"); 19894 } 19895 19896 19897 TEST(CallCompletedCallbackOneException) { 19898 LocalContext env; 19899 v8::HandleScope scope(env->GetIsolate()); 19900 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException); 19901 CompileRun("throw 'exception';"); 19902 } 19903 19904 19905 TEST(CallCompletedCallbackTwoExceptions) { 19906 LocalContext env; 19907 v8::HandleScope scope(env->GetIsolate()); 19908 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException); 19909 CompileRun("throw 'first exception';"); 19910 } 19911 19912 19913 static int probes_counter = 0; 19914 static int misses_counter = 0; 19915 static int updates_counter = 0; 19916 19917 19918 static int* LookupCounter(const char* name) { 19919 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 19920 return &probes_counter; 19921 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 19922 return &misses_counter; 19923 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 19924 return &updates_counter; 19925 } 19926 return NULL; 19927 } 19928 19929 19930 static const char* kMegamorphicTestProgram = 19931 "function ClassA() { };" 19932 "function ClassB() { };" 19933 "ClassA.prototype.foo = function() { };" 19934 "ClassB.prototype.foo = function() { };" 19935 "function fooify(obj) { obj.foo(); };" 19936 "var a = new ClassA();" 19937 "var b = new ClassB();" 19938 "for (var i = 0; i < 10000; i++) {" 19939 " fooify(a);" 19940 " fooify(b);" 19941 "}"; 19942 19943 19944 static void StubCacheHelper(bool primary) { 19945 V8::SetCounterFunction(LookupCounter); 19946 USE(kMegamorphicTestProgram); 19947 #ifdef DEBUG 19948 i::FLAG_native_code_counters = true; 19949 if (primary) { 19950 i::FLAG_test_primary_stub_cache = true; 19951 } else { 19952 i::FLAG_test_secondary_stub_cache = true; 19953 } 19954 i::FLAG_crankshaft = false; 19955 LocalContext env; 19956 v8::HandleScope scope(env->GetIsolate()); 19957 int initial_probes = probes_counter; 19958 int initial_misses = misses_counter; 19959 int initial_updates = updates_counter; 19960 CompileRun(kMegamorphicTestProgram); 19961 int probes = probes_counter - initial_probes; 19962 int misses = misses_counter - initial_misses; 19963 int updates = updates_counter - initial_updates; 19964 CHECK_LT(updates, 10); 19965 CHECK_LT(misses, 10); 19966 CHECK_GE(probes, 10000); 19967 #endif 19968 } 19969 19970 19971 TEST(SecondaryStubCache) { 19972 StubCacheHelper(true); 19973 } 19974 19975 19976 TEST(PrimaryStubCache) { 19977 StubCacheHelper(false); 19978 } 19979 19980 19981 static int cow_arrays_created_runtime = 0; 19982 19983 19984 static int* LookupCounterCOWArrays(const char* name) { 19985 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) { 19986 return &cow_arrays_created_runtime; 19987 } 19988 return NULL; 19989 } 19990 19991 19992 TEST(CheckCOWArraysCreatedRuntimeCounter) { 19993 V8::SetCounterFunction(LookupCounterCOWArrays); 19994 #ifdef DEBUG 19995 i::FLAG_native_code_counters = true; 19996 LocalContext env; 19997 v8::HandleScope scope(env->GetIsolate()); 19998 int initial_cow_arrays = cow_arrays_created_runtime; 19999 CompileRun("var o = [1, 2, 3];"); 20000 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays); 20001 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};"); 20002 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays); 20003 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};"); 20004 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays); 20005 #endif 20006 } 20007 20008 20009 TEST(StaticGetters) { 20010 LocalContext context; 20011 i::Factory* factory = CcTest::i_isolate()->factory(); 20012 v8::Isolate* isolate = CcTest::isolate(); 20013 v8::HandleScope scope(isolate); 20014 i::Handle<i::Object> undefined_value = factory->undefined_value(); 20015 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 20016 i::Handle<i::Object> null_value = factory->null_value(); 20017 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 20018 i::Handle<i::Object> true_value = factory->true_value(); 20019 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 20020 i::Handle<i::Object> false_value = factory->false_value(); 20021 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 20022 } 20023 20024 20025 UNINITIALIZED_TEST(IsolateEmbedderData) { 20026 CcTest::DisableAutomaticDispose(); 20027 v8::Isolate* isolate = v8::Isolate::New(); 20028 isolate->Enter(); 20029 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 20030 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20031 CHECK_EQ(NULL, isolate->GetData(slot)); 20032 CHECK_EQ(NULL, i_isolate->GetData(slot)); 20033 } 20034 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20035 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 20036 isolate->SetData(slot, data); 20037 } 20038 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20039 void* data = reinterpret_cast<void*>(0xacce55ed + slot); 20040 CHECK_EQ(data, isolate->GetData(slot)); 20041 CHECK_EQ(data, i_isolate->GetData(slot)); 20042 } 20043 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20044 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 20045 isolate->SetData(slot, data); 20046 } 20047 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) { 20048 void* data = reinterpret_cast<void*>(0xdecea5ed + slot); 20049 CHECK_EQ(data, isolate->GetData(slot)); 20050 CHECK_EQ(data, i_isolate->GetData(slot)); 20051 } 20052 isolate->Exit(); 20053 isolate->Dispose(); 20054 } 20055 20056 20057 TEST(StringEmpty) { 20058 LocalContext context; 20059 i::Factory* factory = CcTest::i_isolate()->factory(); 20060 v8::Isolate* isolate = CcTest::isolate(); 20061 v8::HandleScope scope(isolate); 20062 i::Handle<i::Object> empty_string = factory->empty_string(); 20063 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string); 20064 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 20065 } 20066 20067 20068 static int instance_checked_getter_count = 0; 20069 static void InstanceCheckedGetter( 20070 Local<String> name, 20071 const v8::PropertyCallbackInfo<v8::Value>& info) { 20072 CHECK_EQ(name, v8_str("foo")); 20073 instance_checked_getter_count++; 20074 info.GetReturnValue().Set(v8_num(11)); 20075 } 20076 20077 20078 static int instance_checked_setter_count = 0; 20079 static void InstanceCheckedSetter(Local<String> name, 20080 Local<Value> value, 20081 const v8::PropertyCallbackInfo<void>& info) { 20082 CHECK_EQ(name, v8_str("foo")); 20083 CHECK_EQ(value, v8_num(23)); 20084 instance_checked_setter_count++; 20085 } 20086 20087 20088 static void CheckInstanceCheckedResult(int getters, 20089 int setters, 20090 bool expects_callbacks, 20091 TryCatch* try_catch) { 20092 if (expects_callbacks) { 20093 CHECK(!try_catch->HasCaught()); 20094 CHECK_EQ(getters, instance_checked_getter_count); 20095 CHECK_EQ(setters, instance_checked_setter_count); 20096 } else { 20097 CHECK(try_catch->HasCaught()); 20098 CHECK_EQ(0, instance_checked_getter_count); 20099 CHECK_EQ(0, instance_checked_setter_count); 20100 } 20101 try_catch->Reset(); 20102 } 20103 20104 20105 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 20106 instance_checked_getter_count = 0; 20107 instance_checked_setter_count = 0; 20108 TryCatch try_catch; 20109 20110 // Test path through generic runtime code. 20111 CompileRun("obj.foo"); 20112 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 20113 CompileRun("obj.foo = 23"); 20114 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 20115 20116 // Test path through generated LoadIC and StoredIC. 20117 CompileRun("function test_get(o) { o.foo; }" 20118 "test_get(obj);"); 20119 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 20120 CompileRun("test_get(obj);"); 20121 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 20122 CompileRun("test_get(obj);"); 20123 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 20124 CompileRun("function test_set(o) { o.foo = 23; }" 20125 "test_set(obj);"); 20126 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 20127 CompileRun("test_set(obj);"); 20128 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 20129 CompileRun("test_set(obj);"); 20130 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 20131 20132 // Test path through optimized code. 20133 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 20134 "test_get(obj);"); 20135 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 20136 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 20137 "test_set(obj);"); 20138 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 20139 20140 // Cleanup so that closures start out fresh in next check. 20141 CompileRun("%DeoptimizeFunction(test_get);" 20142 "%ClearFunctionTypeFeedback(test_get);" 20143 "%DeoptimizeFunction(test_set);" 20144 "%ClearFunctionTypeFeedback(test_set);"); 20145 } 20146 20147 20148 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 20149 v8::internal::FLAG_allow_natives_syntax = true; 20150 LocalContext context; 20151 v8::HandleScope scope(context->GetIsolate()); 20152 20153 Local<FunctionTemplate> templ = FunctionTemplate::New(); 20154 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 20155 inst->SetAccessor(v8_str("foo"), 20156 InstanceCheckedGetter, InstanceCheckedSetter, 20157 Handle<Value>(), 20158 v8::DEFAULT, 20159 v8::None, 20160 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20161 context->Global()->Set(v8_str("f"), templ->GetFunction()); 20162 20163 printf("Testing positive ...\n"); 20164 CompileRun("var obj = new f();"); 20165 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20166 CheckInstanceCheckedAccessors(true); 20167 20168 printf("Testing negative ...\n"); 20169 CompileRun("var obj = {};" 20170 "obj.__proto__ = new f();"); 20171 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20172 CheckInstanceCheckedAccessors(false); 20173 } 20174 20175 20176 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 20177 v8::internal::FLAG_allow_natives_syntax = true; 20178 LocalContext context; 20179 v8::HandleScope scope(context->GetIsolate()); 20180 20181 Local<FunctionTemplate> templ = FunctionTemplate::New(); 20182 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 20183 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 20184 inst->SetAccessor(v8_str("foo"), 20185 InstanceCheckedGetter, InstanceCheckedSetter, 20186 Handle<Value>(), 20187 v8::DEFAULT, 20188 v8::None, 20189 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20190 context->Global()->Set(v8_str("f"), templ->GetFunction()); 20191 20192 printf("Testing positive ...\n"); 20193 CompileRun("var obj = new f();"); 20194 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20195 CheckInstanceCheckedAccessors(true); 20196 20197 printf("Testing negative ...\n"); 20198 CompileRun("var obj = {};" 20199 "obj.__proto__ = new f();"); 20200 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20201 CheckInstanceCheckedAccessors(false); 20202 } 20203 20204 20205 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 20206 v8::internal::FLAG_allow_natives_syntax = true; 20207 LocalContext context; 20208 v8::HandleScope scope(context->GetIsolate()); 20209 20210 Local<FunctionTemplate> templ = FunctionTemplate::New(); 20211 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 20212 proto->SetAccessor(v8_str("foo"), 20213 InstanceCheckedGetter, InstanceCheckedSetter, 20214 Handle<Value>(), 20215 v8::DEFAULT, 20216 v8::None, 20217 v8::AccessorSignature::New(context->GetIsolate(), templ)); 20218 context->Global()->Set(v8_str("f"), templ->GetFunction()); 20219 20220 printf("Testing positive ...\n"); 20221 CompileRun("var obj = new f();"); 20222 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20223 CheckInstanceCheckedAccessors(true); 20224 20225 printf("Testing negative ...\n"); 20226 CompileRun("var obj = {};" 20227 "obj.__proto__ = new f();"); 20228 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20229 CheckInstanceCheckedAccessors(false); 20230 20231 printf("Testing positive with modified prototype chain ...\n"); 20232 CompileRun("var obj = new f();" 20233 "var pro = {};" 20234 "pro.__proto__ = obj.__proto__;" 20235 "obj.__proto__ = pro;"); 20236 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 20237 CheckInstanceCheckedAccessors(true); 20238 } 20239 20240 20241 TEST(TryFinallyMessage) { 20242 LocalContext context; 20243 v8::HandleScope scope(context->GetIsolate()); 20244 { 20245 // Test that the original error message is not lost if there is a 20246 // recursive call into Javascript is done in the finally block, e.g. to 20247 // initialize an IC. (crbug.com/129171) 20248 TryCatch try_catch; 20249 const char* trigger_ic = 20250 "try { \n" 20251 " throw new Error('test'); \n" 20252 "} finally { \n" 20253 " var x = 0; \n" 20254 " x++; \n" // Trigger an IC initialization here. 20255 "} \n"; 20256 CompileRun(trigger_ic); 20257 CHECK(try_catch.HasCaught()); 20258 Local<Message> message = try_catch.Message(); 20259 CHECK(!message.IsEmpty()); 20260 CHECK_EQ(2, message->GetLineNumber()); 20261 } 20262 20263 { 20264 // Test that the original exception message is indeed overwritten if 20265 // a new error is thrown in the finally block. 20266 TryCatch try_catch; 20267 const char* throw_again = 20268 "try { \n" 20269 " throw new Error('test'); \n" 20270 "} finally { \n" 20271 " var x = 0; \n" 20272 " x++; \n" 20273 " throw new Error('again'); \n" // This is the new uncaught error. 20274 "} \n"; 20275 CompileRun(throw_again); 20276 CHECK(try_catch.HasCaught()); 20277 Local<Message> message = try_catch.Message(); 20278 CHECK(!message.IsEmpty()); 20279 CHECK_EQ(6, message->GetLineNumber()); 20280 } 20281 } 20282 20283 20284 static void Helper137002(bool do_store, 20285 bool polymorphic, 20286 bool remove_accessor, 20287 bool interceptor) { 20288 LocalContext context; 20289 Local<ObjectTemplate> templ = ObjectTemplate::New(); 20290 if (interceptor) { 20291 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor); 20292 } else { 20293 templ->SetAccessor(v8_str("foo"), 20294 GetterWhichReturns42, 20295 SetterWhichSetsYOnThisTo23); 20296 } 20297 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 20298 20299 // Turn monomorphic on slow object with native accessor, then turn 20300 // polymorphic, finally optimize to create negative lookup and fail. 20301 CompileRun(do_store ? 20302 "function f(x) { x.foo = void 0; }" : 20303 "function f(x) { return x.foo; }"); 20304 CompileRun("obj.y = void 0;"); 20305 if (!interceptor) { 20306 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 20307 } 20308 CompileRun("obj.__proto__ = null;" 20309 "f(obj); f(obj); f(obj);"); 20310 if (polymorphic) { 20311 CompileRun("f({});"); 20312 } 20313 CompileRun("obj.y = void 0;" 20314 "%OptimizeFunctionOnNextCall(f);"); 20315 if (remove_accessor) { 20316 CompileRun("delete obj.foo;"); 20317 } 20318 CompileRun("var result = f(obj);"); 20319 if (do_store) { 20320 CompileRun("result = obj.y;"); 20321 } 20322 if (remove_accessor && !interceptor) { 20323 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); 20324 } else { 20325 CHECK_EQ(do_store ? 23 : 42, 20326 context->Global()->Get(v8_str("result"))->Int32Value()); 20327 } 20328 } 20329 20330 20331 THREADED_TEST(Regress137002a) { 20332 i::FLAG_allow_natives_syntax = true; 20333 i::FLAG_compilation_cache = false; 20334 v8::HandleScope scope(CcTest::isolate()); 20335 for (int i = 0; i < 16; i++) { 20336 Helper137002(i & 8, i & 4, i & 2, i & 1); 20337 } 20338 } 20339 20340 20341 THREADED_TEST(Regress137002b) { 20342 i::FLAG_allow_natives_syntax = true; 20343 LocalContext context; 20344 v8::HandleScope scope(context->GetIsolate()); 20345 Local<ObjectTemplate> templ = ObjectTemplate::New(); 20346 templ->SetAccessor(v8_str("foo"), 20347 GetterWhichReturns42, 20348 SetterWhichSetsYOnThisTo23); 20349 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 20350 20351 // Turn monomorphic on slow object with native accessor, then just 20352 // delete the property and fail. 20353 CompileRun("function load(x) { return x.foo; }" 20354 "function store(x) { x.foo = void 0; }" 20355 "function keyed_load(x, key) { return x[key]; }" 20356 // Second version of function has a different source (add void 0) 20357 // so that it does not share code with the first version. This 20358 // ensures that the ICs are monomorphic. 20359 "function load2(x) { void 0; return x.foo; }" 20360 "function store2(x) { void 0; x.foo = void 0; }" 20361 "function keyed_load2(x, key) { void 0; return x[key]; }" 20362 20363 "obj.y = void 0;" 20364 "obj.__proto__ = null;" 20365 "var subobj = {};" 20366 "subobj.y = void 0;" 20367 "subobj.__proto__ = obj;" 20368 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 20369 20370 // Make the ICs monomorphic. 20371 "load(obj); load(obj);" 20372 "load2(subobj); load2(subobj);" 20373 "store(obj); store(obj);" 20374 "store2(subobj); store2(subobj);" 20375 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 20376 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 20377 20378 // Actually test the shiny new ICs and better not crash. This 20379 // serves as a regression test for issue 142088 as well. 20380 "load(obj);" 20381 "load2(subobj);" 20382 "store(obj);" 20383 "store2(subobj);" 20384 "keyed_load(obj, 'foo');" 20385 "keyed_load2(subobj, 'foo');" 20386 20387 // Delete the accessor. It better not be called any more now. 20388 "delete obj.foo;" 20389 "obj.y = void 0;" 20390 "subobj.y = void 0;" 20391 20392 "var load_result = load(obj);" 20393 "var load_result2 = load2(subobj);" 20394 "var keyed_load_result = keyed_load(obj, 'foo');" 20395 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 20396 "store(obj);" 20397 "store2(subobj);" 20398 "var y_from_obj = obj.y;" 20399 "var y_from_subobj = subobj.y;"); 20400 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); 20401 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); 20402 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); 20403 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); 20404 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); 20405 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); 20406 } 20407 20408 20409 THREADED_TEST(Regress142088) { 20410 i::FLAG_allow_natives_syntax = true; 20411 LocalContext context; 20412 v8::HandleScope scope(context->GetIsolate()); 20413 Local<ObjectTemplate> templ = ObjectTemplate::New(); 20414 templ->SetAccessor(v8_str("foo"), 20415 GetterWhichReturns42, 20416 SetterWhichSetsYOnThisTo23); 20417 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 20418 20419 CompileRun("function load(x) { return x.foo; }" 20420 "var o = Object.create(obj);" 20421 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 20422 "load(o); load(o); load(o); load(o);"); 20423 } 20424 20425 20426 THREADED_TEST(Regress137496) { 20427 i::FLAG_expose_gc = true; 20428 LocalContext context; 20429 v8::HandleScope scope(context->GetIsolate()); 20430 20431 // Compile a try-finally clause where the finally block causes a GC 20432 // while there still is a message pending for external reporting. 20433 TryCatch try_catch; 20434 try_catch.SetVerbose(true); 20435 CompileRun("try { throw new Error(); } finally { gc(); }"); 20436 CHECK(try_catch.HasCaught()); 20437 } 20438 20439 20440 THREADED_TEST(Regress149912) { 20441 LocalContext context; 20442 v8::HandleScope scope(context->GetIsolate()); 20443 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20444 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 20445 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 20446 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();"); 20447 } 20448 20449 20450 THREADED_TEST(Regress157124) { 20451 LocalContext context; 20452 v8::HandleScope scope(context->GetIsolate()); 20453 Local<ObjectTemplate> templ = ObjectTemplate::New(); 20454 Local<Object> obj = templ->NewInstance(); 20455 obj->GetIdentityHash(); 20456 obj->DeleteHiddenValue(v8_str("Bug")); 20457 } 20458 20459 20460 THREADED_TEST(Regress2535) { 20461 i::FLAG_harmony_collections = true; 20462 LocalContext context; 20463 v8::HandleScope scope(context->GetIsolate()); 20464 Local<Value> set_value = CompileRun("new Set();"); 20465 Local<Object> set_object(Local<Object>::Cast(set_value)); 20466 CHECK_EQ(0, set_object->InternalFieldCount()); 20467 Local<Value> map_value = CompileRun("new Map();"); 20468 Local<Object> map_object(Local<Object>::Cast(map_value)); 20469 CHECK_EQ(0, map_object->InternalFieldCount()); 20470 } 20471 20472 20473 THREADED_TEST(Regress2746) { 20474 LocalContext context; 20475 v8::Isolate* isolate = context->GetIsolate(); 20476 v8::HandleScope scope(isolate); 20477 Local<Object> obj = Object::New(); 20478 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key"); 20479 obj->SetHiddenValue(key, v8::Undefined(isolate)); 20480 Local<Value> value = obj->GetHiddenValue(key); 20481 CHECK(!value.IsEmpty()); 20482 CHECK(value->IsUndefined()); 20483 } 20484 20485 20486 THREADED_TEST(Regress260106) { 20487 LocalContext context; 20488 v8::HandleScope scope(context->GetIsolate()); 20489 Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler); 20490 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 20491 Local<Function> function = templ->GetFunction(); 20492 CHECK(!function.IsEmpty()); 20493 CHECK(function->IsFunction()); 20494 } 20495 20496 20497 THREADED_TEST(JSONParseObject) { 20498 LocalContext context; 20499 HandleScope scope(context->GetIsolate()); 20500 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}")); 20501 Handle<Object> global = context->Global(); 20502 global->Set(v8_str("obj"), obj); 20503 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 20504 } 20505 20506 20507 THREADED_TEST(JSONParseNumber) { 20508 LocalContext context; 20509 HandleScope scope(context->GetIsolate()); 20510 Local<Value> obj = v8::JSON::Parse(v8_str("42")); 20511 Handle<Object> global = context->Global(); 20512 global->Set(v8_str("obj"), obj); 20513 ExpectString("JSON.stringify(obj)", "42"); 20514 } 20515 20516 20517 #if V8_OS_POSIX 20518 class ThreadInterruptTest { 20519 public: 20520 ThreadInterruptTest() : sem_(0), sem_value_(0) { } 20521 ~ThreadInterruptTest() {} 20522 20523 void RunTest() { 20524 InterruptThread i_thread(this); 20525 i_thread.Start(); 20526 20527 sem_.Wait(); 20528 CHECK_EQ(kExpectedValue, sem_value_); 20529 } 20530 20531 private: 20532 static const int kExpectedValue = 1; 20533 20534 class InterruptThread : public i::Thread { 20535 public: 20536 explicit InterruptThread(ThreadInterruptTest* test) 20537 : Thread("InterruptThread"), test_(test) {} 20538 20539 virtual void Run() { 20540 struct sigaction action; 20541 20542 // Ensure that we'll enter waiting condition 20543 i::OS::Sleep(100); 20544 20545 // Setup signal handler 20546 memset(&action, 0, sizeof(action)); 20547 action.sa_handler = SignalHandler; 20548 sigaction(SIGCHLD, &action, NULL); 20549 20550 // Send signal 20551 kill(getpid(), SIGCHLD); 20552 20553 // Ensure that if wait has returned because of error 20554 i::OS::Sleep(100); 20555 20556 // Set value and signal semaphore 20557 test_->sem_value_ = 1; 20558 test_->sem_.Signal(); 20559 } 20560 20561 static void SignalHandler(int signal) { 20562 } 20563 20564 private: 20565 ThreadInterruptTest* test_; 20566 }; 20567 20568 i::Semaphore sem_; 20569 volatile int sem_value_; 20570 }; 20571 20572 20573 THREADED_TEST(SemaphoreInterruption) { 20574 ThreadInterruptTest().RunTest(); 20575 } 20576 20577 20578 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global, 20579 Local<Value> name, 20580 v8::AccessType type, 20581 Local<Value> data) { 20582 i::PrintF("Named access blocked.\n"); 20583 return false; 20584 } 20585 20586 20587 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global, 20588 uint32_t key, 20589 v8::AccessType type, 20590 Local<Value> data) { 20591 i::PrintF("Indexed access blocked.\n"); 20592 return false; 20593 } 20594 20595 20596 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20597 CHECK(false); 20598 } 20599 20600 20601 TEST(JSONStringifyAccessCheck) { 20602 v8::V8::Initialize(); 20603 v8::HandleScope scope(CcTest::isolate()); 20604 20605 // Create an ObjectTemplate for global objects and install access 20606 // check callbacks that will block access. 20607 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 20608 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 20609 IndexAccessAlwaysBlocked); 20610 20611 // Create a context and set an x property on it's global object. 20612 LocalContext context0(NULL, global_template); 20613 v8::Handle<v8::Object> global0 = context0->Global(); 20614 global0->Set(v8_str("x"), v8_num(42)); 20615 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 20616 20617 for (int i = 0; i < 2; i++) { 20618 if (i == 1) { 20619 // Install a toJSON function on the second run. 20620 v8::Handle<v8::FunctionTemplate> toJSON = 20621 v8::FunctionTemplate::New(UnreachableCallback); 20622 20623 global0->Set(v8_str("toJSON"), toJSON->GetFunction()); 20624 } 20625 // Create a context with a different security token so that the 20626 // failed access check callback will be called on each access. 20627 LocalContext context1(NULL, global_template); 20628 context1->Global()->Set(v8_str("other"), global0); 20629 20630 ExpectString("JSON.stringify(other)", "{}"); 20631 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })", 20632 "{\"a\":{},\"b\":[\"c\"]}"); 20633 ExpectString("JSON.stringify([other, 'b', 'c'])", 20634 "[{},\"b\",\"c\"]"); 20635 20636 v8::Handle<v8::Array> array = v8::Array::New(CcTest::isolate(), 2); 20637 array->Set(0, v8_str("a")); 20638 array->Set(1, v8_str("b")); 20639 context1->Global()->Set(v8_str("array"), array); 20640 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); 20641 array->TurnOnAccessCheck(); 20642 ExpectString("JSON.stringify(array)", "[]"); 20643 ExpectString("JSON.stringify([array])", "[[]]"); 20644 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}"); 20645 } 20646 } 20647 20648 20649 bool access_check_fail_thrown = false; 20650 bool catch_callback_called = false; 20651 20652 20653 // Failed access check callback that performs a GC on each invocation. 20654 void FailedAccessCheckThrows(Local<v8::Object> target, 20655 v8::AccessType type, 20656 Local<v8::Value> data) { 20657 access_check_fail_thrown = true; 20658 i::PrintF("Access check failed. Error thrown.\n"); 20659 CcTest::isolate()->ThrowException( 20660 v8::Exception::Error(v8_str("cross context"))); 20661 } 20662 20663 20664 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20665 for (int i = 0; i < args.Length(); i++) { 20666 i::PrintF("%s\n", *String::Utf8Value(args[i])); 20667 } 20668 catch_callback_called = true; 20669 } 20670 20671 20672 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20673 args[0]->ToObject()->HasOwnProperty(args[1]->ToString()); 20674 } 20675 20676 20677 void CheckCorrectThrow(const char* script) { 20678 // Test that the script, when wrapped into a try-catch, triggers the catch 20679 // clause due to failed access check throwing an exception. 20680 // The subsequent try-catch should run without any exception. 20681 access_check_fail_thrown = false; 20682 catch_callback_called = false; 20683 i::ScopedVector<char> source(1024); 20684 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 20685 CompileRun(source.start()); 20686 CHECK(access_check_fail_thrown); 20687 CHECK(catch_callback_called); 20688 20689 access_check_fail_thrown = false; 20690 catch_callback_called = false; 20691 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 20692 CHECK(!access_check_fail_thrown); 20693 CHECK(!catch_callback_called); 20694 } 20695 20696 20697 TEST(AccessCheckThrows) { 20698 i::FLAG_allow_natives_syntax = true; 20699 v8::V8::Initialize(); 20700 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 20701 v8::HandleScope scope(CcTest::isolate()); 20702 20703 // Create an ObjectTemplate for global objects and install access 20704 // check callbacks that will block access. 20705 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 20706 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 20707 IndexAccessAlwaysBlocked); 20708 20709 // Create a context and set an x property on it's global object. 20710 LocalContext context0(NULL, global_template); 20711 context0->Global()->Set(v8_str("x"), v8_num(42)); 20712 v8::Handle<v8::Object> global0 = context0->Global(); 20713 20714 // Create a context with a different security token so that the 20715 // failed access check callback will be called on each access. 20716 LocalContext context1(NULL, global_template); 20717 context1->Global()->Set(v8_str("other"), global0); 20718 20719 v8::Handle<v8::FunctionTemplate> catcher_fun = 20720 v8::FunctionTemplate::New(CatcherCallback); 20721 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction()); 20722 20723 v8::Handle<v8::FunctionTemplate> has_own_property_fun = 20724 v8::FunctionTemplate::New(HasOwnPropertyCallback); 20725 context1->Global()->Set(v8_str("has_own_property"), 20726 has_own_property_fun->GetFunction()); 20727 20728 { v8::TryCatch try_catch; 20729 access_check_fail_thrown = false; 20730 CompileRun("other.x;"); 20731 CHECK(access_check_fail_thrown); 20732 CHECK(try_catch.HasCaught()); 20733 } 20734 20735 CheckCorrectThrow("other.x"); 20736 CheckCorrectThrow("other[1]"); 20737 CheckCorrectThrow("JSON.stringify(other)"); 20738 CheckCorrectThrow("has_own_property(other, 'x')"); 20739 CheckCorrectThrow("%GetProperty(other, 'x')"); 20740 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)"); 20741 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')"); 20742 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); 20743 CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); 20744 CheckCorrectThrow("%HasLocalProperty(other, 'x')"); 20745 CheckCorrectThrow("%HasProperty(other, 'x')"); 20746 CheckCorrectThrow("%HasElement(other, 1)"); 20747 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); 20748 CheckCorrectThrow("%GetPropertyNames(other)"); 20749 CheckCorrectThrow("%GetLocalPropertyNames(other, true)"); 20750 CheckCorrectThrow("%DefineOrRedefineAccessorProperty(" 20751 "other, 'x', null, null, 1)"); 20752 20753 // Reset the failed access check callback so it does not influence 20754 // the other tests. 20755 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 20756 } 20757 20758 20759 THREADED_TEST(Regress256330) { 20760 i::FLAG_allow_natives_syntax = true; 20761 LocalContext context; 20762 v8::HandleScope scope(context->GetIsolate()); 20763 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20764 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 20765 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 20766 CompileRun("\"use strict\"; var o = new Bug;" 20767 "function f(o) { o.x = 10; };" 20768 "f(o); f(o); f(o);" 20769 "%OptimizeFunctionOnNextCall(f);" 20770 "f(o);"); 20771 ExpectBoolean("%GetOptimizationStatus(f) != 2", true); 20772 } 20773 20774 20775 THREADED_TEST(CrankshaftInterceptorSetter) { 20776 i::FLAG_allow_natives_syntax = true; 20777 v8::HandleScope scope(CcTest::isolate()); 20778 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20779 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 20780 LocalContext env; 20781 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 20782 CompileRun("var obj = new Obj;" 20783 // Initialize fields to avoid transitions later. 20784 "obj.age = 0;" 20785 "obj.accessor_age = 42;" 20786 "function setter(i) { this.accessor_age = i; };" 20787 "function getter() { return this.accessor_age; };" 20788 "function setAge(i) { obj.age = i; };" 20789 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 20790 "setAge(1);" 20791 "setAge(2);" 20792 "setAge(3);" 20793 "%OptimizeFunctionOnNextCall(setAge);" 20794 "setAge(4);"); 20795 // All stores went through the interceptor. 20796 ExpectInt32("obj.interceptor_age", 4); 20797 ExpectInt32("obj.accessor_age", 42); 20798 } 20799 20800 20801 THREADED_TEST(CrankshaftInterceptorGetter) { 20802 i::FLAG_allow_natives_syntax = true; 20803 v8::HandleScope scope(CcTest::isolate()); 20804 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20805 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 20806 LocalContext env; 20807 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 20808 CompileRun("var obj = new Obj;" 20809 // Initialize fields to avoid transitions later. 20810 "obj.age = 1;" 20811 "obj.accessor_age = 42;" 20812 "function getter() { return this.accessor_age; };" 20813 "function getAge() { return obj.interceptor_age; };" 20814 "Object.defineProperty(obj, 'interceptor_age', { get:getter });" 20815 "getAge();" 20816 "getAge();" 20817 "getAge();" 20818 "%OptimizeFunctionOnNextCall(getAge);"); 20819 // Access through interceptor. 20820 ExpectInt32("getAge()", 1); 20821 } 20822 20823 20824 THREADED_TEST(CrankshaftInterceptorFieldRead) { 20825 i::FLAG_allow_natives_syntax = true; 20826 v8::HandleScope scope(CcTest::isolate()); 20827 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20828 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 20829 LocalContext env; 20830 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 20831 CompileRun("var obj = new Obj;" 20832 "obj.__proto__.interceptor_age = 42;" 20833 "obj.age = 100;" 20834 "function getAge() { return obj.interceptor_age; };"); 20835 ExpectInt32("getAge();", 100); 20836 ExpectInt32("getAge();", 100); 20837 ExpectInt32("getAge();", 100); 20838 CompileRun("%OptimizeFunctionOnNextCall(getAge);"); 20839 // Access through interceptor. 20840 ExpectInt32("getAge();", 100); 20841 } 20842 20843 20844 THREADED_TEST(CrankshaftInterceptorFieldWrite) { 20845 i::FLAG_allow_natives_syntax = true; 20846 v8::HandleScope scope(CcTest::isolate()); 20847 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20848 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 20849 LocalContext env; 20850 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 20851 CompileRun("var obj = new Obj;" 20852 "obj.age = 100000;" 20853 "function setAge(i) { obj.age = i };" 20854 "setAge(100);" 20855 "setAge(101);" 20856 "setAge(102);" 20857 "%OptimizeFunctionOnNextCall(setAge);" 20858 "setAge(103);"); 20859 ExpectInt32("obj.age", 100000); 20860 ExpectInt32("obj.interceptor_age", 103); 20861 } 20862 20863 20864 #endif // V8_OS_POSIX 20865 20866 20867 static Local<Value> function_new_expected_env; 20868 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) { 20869 CHECK_EQ(function_new_expected_env, info.Data()); 20870 info.GetReturnValue().Set(17); 20871 } 20872 20873 20874 THREADED_TEST(FunctionNew) { 20875 LocalContext env; 20876 v8::Isolate* isolate = env->GetIsolate(); 20877 v8::HandleScope scope(isolate); 20878 Local<Object> data = v8::Object::New(); 20879 function_new_expected_env = data; 20880 Local<Function> func = Function::New(isolate, FunctionNewCallback, data); 20881 env->Global()->Set(v8_str("func"), func); 20882 Local<Value> result = CompileRun("func();"); 20883 CHECK_EQ(v8::Integer::New(17, isolate), result); 20884 // Verify function not cached 20885 int serial_number = 20886 i::Smi::cast(v8::Utils::OpenHandle(*func) 20887 ->shared()->get_api_func_data()->serial_number())->value(); 20888 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); 20889 i::Object* elm = i_isolate->native_context()->function_cache() 20890 ->GetElementNoExceptionThrown(i_isolate, serial_number); 20891 CHECK(elm->IsUndefined()); 20892 // Verify that each Function::New creates a new function instance 20893 Local<Object> data2 = v8::Object::New(); 20894 function_new_expected_env = data2; 20895 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2); 20896 CHECK(!func2->IsNull()); 20897 CHECK_NE(func, func2); 20898 env->Global()->Set(v8_str("func2"), func2); 20899 Local<Value> result2 = CompileRun("func2();"); 20900 CHECK_EQ(v8::Integer::New(17, isolate), result2); 20901 } 20902 20903 20904 TEST(EscapeableHandleScope) { 20905 HandleScope outer_scope(CcTest::isolate()); 20906 LocalContext context; 20907 const int runs = 10; 20908 Local<String> values[runs]; 20909 for (int i = 0; i < runs; i++) { 20910 v8::EscapableHandleScope inner_scope(CcTest::isolate()); 20911 Local<String> value; 20912 if (i != 0) value = v8_str("escape value"); 20913 values[i] = inner_scope.Escape(value); 20914 } 20915 for (int i = 0; i < runs; i++) { 20916 Local<String> expected; 20917 if (i != 0) { 20918 CHECK_EQ(v8_str("escape value"), values[i]); 20919 } else { 20920 CHECK(values[i].IsEmpty()); 20921 } 20922 } 20923 } 20924