1 // Copyright 2011 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
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.
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.
34 #include "compilation-cache.h"
35 #include "execution.h"
41 #include "unicode-inl.h"
43 static const bool kLogThreading = false;
45 static bool IsNaN(double x) {
53 using ::v8::AccessorInfo;
54 using ::v8::Arguments;
56 using ::v8::Extension;
58 using ::v8::FunctionTemplate;
60 using ::v8::HandleScope;
63 using ::v8::MessageCallback;
65 using ::v8::ObjectTemplate;
66 using ::v8::Persistent;
68 using ::v8::StackTrace;
71 using ::v8::Undefined;
76 static void ExpectString(const char* code, const char* expected) {
77 Local<Value> result = CompileRun(code);
78 CHECK(result->IsString());
79 String::AsciiValue ascii(result);
80 CHECK_EQ(expected, *ascii);
83 static void ExpectInt32(const char* code, int expected) {
84 Local<Value> result = CompileRun(code);
85 CHECK(result->IsInt32());
86 CHECK_EQ(expected, result->Int32Value());
89 static void ExpectBoolean(const char* code, bool expected) {
90 Local<Value> result = CompileRun(code);
91 CHECK(result->IsBoolean());
92 CHECK_EQ(expected, result->BooleanValue());
96 static void ExpectTrue(const char* code) {
97 ExpectBoolean(code, true);
101 static void ExpectFalse(const char* code) {
102 ExpectBoolean(code, false);
106 static void ExpectObject(const char* code, Local<Value> expected) {
107 Local<Value> result = CompileRun(code);
108 CHECK(result->Equals(expected));
112 static void ExpectUndefined(const char* code) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->IsUndefined());
118 static int signature_callback_count;
119 static v8::Handle<Value> IncrementingSignatureCallback(
120 const v8::Arguments& args) {
121 ApiTestFuzzer::Fuzz();
122 signature_callback_count++;
123 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
124 for (int i = 0; i < args.Length(); i++)
125 result->Set(v8::Integer::New(i), args[i]);
130 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
131 ApiTestFuzzer::Fuzz();
132 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
133 for (int i = 0; i < args.Length(); i++) {
134 result->Set(v8::Integer::New(i), args[i]);
140 THREADED_TEST(Handles) {
141 v8::HandleScope scope;
142 Local<Context> local_env;
145 local_env = env.local();
148 // Local context should still be live.
149 CHECK(!local_env.IsEmpty());
152 v8::Handle<v8::Primitive> undef = v8::Undefined();
153 CHECK(!undef.IsEmpty());
154 CHECK(undef->IsUndefined());
156 const char* c_source = "1 + 2 + 3";
157 Local<String> source = String::New(c_source);
158 Local<Script> script = Script::Compile(source);
159 CHECK_EQ(6, script->Run()->Int32Value());
165 THREADED_TEST(ReceiverSignature) {
166 v8::HandleScope scope;
168 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
169 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
170 fun->PrototypeTemplate()->Set(
172 v8::FunctionTemplate::New(IncrementingSignatureCallback,
175 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
176 signature_callback_count = 0;
180 CHECK_EQ(1, signature_callback_count);
181 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
182 sub_fun->Inherit(fun);
183 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
185 "var o = new SubFun();"
187 CHECK_EQ(2, signature_callback_count);
189 v8::TryCatch try_catch;
192 "o.m = Fun.prototype.m;"
194 CHECK_EQ(2, signature_callback_count);
195 CHECK(try_catch.HasCaught());
197 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
198 sub_fun->Inherit(fun);
199 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
201 "var o = new UnrelFun();"
202 "o.m = Fun.prototype.m;"
204 CHECK_EQ(2, signature_callback_count);
205 CHECK(try_catch.HasCaught());
209 THREADED_TEST(ArgumentSignature) {
210 v8::HandleScope scope;
212 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
213 cons->SetClassName(v8_str("Cons"));
214 v8::Handle<v8::Signature> sig =
215 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
216 v8::Handle<v8::FunctionTemplate> fun =
217 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
218 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
219 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
221 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
222 CHECK(value1->IsTrue());
224 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
225 CHECK(value2->IsTrue());
227 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
228 CHECK(value3->IsTrue());
230 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
231 cons1->SetClassName(v8_str("Cons1"));
232 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
233 cons2->SetClassName(v8_str("Cons2"));
234 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
235 cons3->SetClassName(v8_str("Cons3"));
237 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
238 v8::Handle<v8::Signature> wsig =
239 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
240 v8::Handle<v8::FunctionTemplate> fun2 =
241 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
243 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
244 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
245 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
246 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
247 v8::Handle<Value> value4 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
249 "'[object Cons1],[object Cons2],[object Cons3]'");
250 CHECK(value4->IsTrue());
252 v8::Handle<Value> value5 = CompileRun(
253 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
254 CHECK(value5->IsTrue());
256 v8::Handle<Value> value6 = CompileRun(
257 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
258 CHECK(value6->IsTrue());
260 v8::Handle<Value> value7 = CompileRun(
261 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
262 "'[object Cons1],[object Cons2],[object Cons3],d';");
263 CHECK(value7->IsTrue());
265 v8::Handle<Value> value8 = CompileRun(
266 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
267 CHECK(value8->IsTrue());
271 THREADED_TEST(HulIgennem) {
272 v8::HandleScope scope;
274 v8::Handle<v8::Primitive> undef = v8::Undefined();
275 Local<String> undef_str = undef->ToString();
276 char* value = i::NewArray<char>(undef_str->Length() + 1);
277 undef_str->WriteAscii(value);
278 CHECK_EQ(0, strcmp(value, "undefined"));
279 i::DeleteArray(value);
283 THREADED_TEST(Access) {
284 v8::HandleScope scope;
286 Local<v8::Object> obj = v8::Object::New();
287 Local<Value> foo_before = obj->Get(v8_str("foo"));
288 CHECK(foo_before->IsUndefined());
289 Local<String> bar_str = v8_str("bar");
290 obj->Set(v8_str("foo"), bar_str);
291 Local<Value> foo_after = obj->Get(v8_str("foo"));
292 CHECK(!foo_after->IsUndefined());
293 CHECK(foo_after->IsString());
294 CHECK_EQ(bar_str, foo_after);
298 THREADED_TEST(AccessElement) {
299 v8::HandleScope scope;
301 Local<v8::Object> obj = v8::Object::New();
302 Local<Value> before = obj->Get(1);
303 CHECK(before->IsUndefined());
304 Local<String> bar_str = v8_str("bar");
305 obj->Set(1, bar_str);
306 Local<Value> after = obj->Get(1);
307 CHECK(!after->IsUndefined());
308 CHECK(after->IsString());
309 CHECK_EQ(bar_str, after);
311 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
312 CHECK_EQ(v8_str("a"), value->Get(0));
313 CHECK_EQ(v8_str("b"), value->Get(1));
317 THREADED_TEST(Script) {
318 v8::HandleScope scope;
320 const char* c_source = "1 + 2 + 3";
321 Local<String> source = String::New(c_source);
322 Local<Script> script = Script::Compile(source);
323 CHECK_EQ(6, script->Run()->Int32Value());
327 static uint16_t* AsciiToTwoByteString(const char* source) {
328 int array_length = i::StrLength(source) + 1;
329 uint16_t* converted = i::NewArray<uint16_t>(array_length);
330 for (int i = 0; i < array_length; i++) converted[i] = source[i];
335 class TestResource: public String::ExternalStringResource {
337 explicit TestResource(uint16_t* data, int* counter = NULL)
338 : data_(data), length_(0), counter_(counter) {
339 while (data[length_]) ++length_;
343 i::DeleteArray(data_);
344 if (counter_ != NULL) ++*counter_;
347 const uint16_t* data() const {
351 size_t length() const {
361 class TestAsciiResource: public String::ExternalAsciiStringResource {
363 explicit TestAsciiResource(const char* data, int* counter = NULL)
364 : data_(data), length_(strlen(data)), counter_(counter) { }
366 ~TestAsciiResource() {
367 i::DeleteArray(data_);
368 if (counter_ != NULL) ++*counter_;
371 const char* data() const {
375 size_t length() const {
385 THREADED_TEST(ScriptUsingStringResource) {
386 int dispose_count = 0;
387 const char* c_source = "1 + 2 * 3";
388 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
390 v8::HandleScope scope;
392 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
393 Local<String> source = String::NewExternal(resource);
394 Local<Script> script = Script::Compile(source);
395 Local<Value> value = script->Run();
396 CHECK(value->IsNumber());
397 CHECK_EQ(7, value->Int32Value());
398 CHECK(source->IsExternal());
400 static_cast<TestResource*>(source->GetExternalStringResource()));
401 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
402 CHECK_EQ(0, dispose_count);
404 v8::internal::Isolate::Current()->compilation_cache()->Clear();
405 HEAP->CollectAllAvailableGarbage();
406 CHECK_EQ(1, dispose_count);
410 THREADED_TEST(ScriptUsingAsciiStringResource) {
411 int dispose_count = 0;
412 const char* c_source = "1 + 2 * 3";
414 v8::HandleScope scope;
416 Local<String> source =
417 String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
419 Local<Script> script = Script::Compile(source);
420 Local<Value> value = script->Run();
421 CHECK(value->IsNumber());
422 CHECK_EQ(7, value->Int32Value());
423 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
424 CHECK_EQ(0, dispose_count);
426 i::Isolate::Current()->compilation_cache()->Clear();
427 HEAP->CollectAllAvailableGarbage();
428 CHECK_EQ(1, dispose_count);
432 THREADED_TEST(ScriptMakingExternalString) {
433 int dispose_count = 0;
434 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
436 v8::HandleScope scope;
438 Local<String> source = String::New(two_byte_source);
439 // Trigger GCs so that the newly allocated string moves to old gen.
440 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
441 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
442 bool success = source->MakeExternal(new TestResource(two_byte_source,
445 Local<Script> script = Script::Compile(source);
446 Local<Value> value = script->Run();
447 CHECK(value->IsNumber());
448 CHECK_EQ(7, value->Int32Value());
449 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
450 CHECK_EQ(0, dispose_count);
452 i::Isolate::Current()->compilation_cache()->Clear();
453 // TODO(1608): This should use kAbortIncrementalMarking.
454 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
455 CHECK_EQ(1, dispose_count);
459 THREADED_TEST(ScriptMakingExternalAsciiString) {
460 int dispose_count = 0;
461 const char* c_source = "1 + 2 * 3";
463 v8::HandleScope scope;
465 Local<String> source = v8_str(c_source);
466 // Trigger GCs so that the newly allocated string moves to old gen.
467 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
468 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
469 bool success = source->MakeExternal(
470 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
472 Local<Script> script = Script::Compile(source);
473 Local<Value> value = script->Run();
474 CHECK(value->IsNumber());
475 CHECK_EQ(7, value->Int32Value());
476 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
477 CHECK_EQ(0, dispose_count);
479 i::Isolate::Current()->compilation_cache()->Clear();
480 // TODO(1608): This should use kAbortIncrementalMarking.
481 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
482 CHECK_EQ(1, dispose_count);
486 TEST(MakingExternalStringConditions) {
487 v8::HandleScope scope;
490 // Free some space in the new space so that we can check freshness.
491 HEAP->CollectGarbage(i::NEW_SPACE);
492 HEAP->CollectGarbage(i::NEW_SPACE);
494 uint16_t* two_byte_string = AsciiToTwoByteString("small");
495 Local<String> small_string = String::New(two_byte_string);
496 i::DeleteArray(two_byte_string);
498 // We should refuse to externalize newly created small string.
499 CHECK(!small_string->CanMakeExternal());
500 // Trigger GCs so that the newly allocated string moves to old gen.
501 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
502 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
503 // Old space strings should be accepted.
504 CHECK(small_string->CanMakeExternal());
506 two_byte_string = AsciiToTwoByteString("small 2");
507 small_string = String::New(two_byte_string);
508 i::DeleteArray(two_byte_string);
510 // We should refuse externalizing newly created small string.
511 CHECK(!small_string->CanMakeExternal());
512 for (int i = 0; i < 100; i++) {
513 String::Value value(small_string);
515 // Frequently used strings should be accepted.
516 CHECK(small_string->CanMakeExternal());
518 const int buf_size = 10 * 1024;
519 char* buf = i::NewArray<char>(buf_size);
520 memset(buf, 'a', buf_size);
521 buf[buf_size - 1] = '\0';
523 two_byte_string = AsciiToTwoByteString(buf);
524 Local<String> large_string = String::New(two_byte_string);
526 i::DeleteArray(two_byte_string);
527 // Large strings should be immediately accepted.
528 CHECK(large_string->CanMakeExternal());
532 TEST(MakingExternalAsciiStringConditions) {
533 v8::HandleScope scope;
536 // Free some space in the new space so that we can check freshness.
537 HEAP->CollectGarbage(i::NEW_SPACE);
538 HEAP->CollectGarbage(i::NEW_SPACE);
540 Local<String> small_string = String::New("small");
541 // We should refuse to externalize newly created small string.
542 CHECK(!small_string->CanMakeExternal());
543 // Trigger GCs so that the newly allocated string moves to old gen.
544 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
545 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
546 // Old space strings should be accepted.
547 CHECK(small_string->CanMakeExternal());
549 small_string = String::New("small 2");
550 // We should refuse externalizing newly created small string.
551 CHECK(!small_string->CanMakeExternal());
552 for (int i = 0; i < 100; i++) {
553 String::Value value(small_string);
555 // Frequently used strings should be accepted.
556 CHECK(small_string->CanMakeExternal());
558 const int buf_size = 10 * 1024;
559 char* buf = i::NewArray<char>(buf_size);
560 memset(buf, 'a', buf_size);
561 buf[buf_size - 1] = '\0';
562 Local<String> large_string = String::New(buf);
564 // Large strings should be immediately accepted.
565 CHECK(large_string->CanMakeExternal());
569 THREADED_TEST(UsingExternalString) {
571 v8::HandleScope scope;
572 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
573 Local<String> string =
574 String::NewExternal(new TestResource(two_byte_string));
575 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
576 // Trigger GCs so that the newly allocated string moves to old gen.
577 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
578 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
579 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
580 CHECK(isymbol->IsSymbol());
582 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
583 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
587 THREADED_TEST(UsingExternalAsciiString) {
589 v8::HandleScope scope;
590 const char* one_byte_string = "test string";
591 Local<String> string = String::NewExternal(
592 new TestAsciiResource(i::StrDup(one_byte_string)));
593 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
594 // Trigger GCs so that the newly allocated string moves to old gen.
595 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
596 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
597 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
598 CHECK(isymbol->IsSymbol());
600 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
601 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
605 THREADED_TEST(ScavengeExternalString) {
606 int dispose_count = 0;
607 bool in_new_space = false;
609 v8::HandleScope scope;
610 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
611 Local<String> string =
612 String::NewExternal(new TestResource(two_byte_string,
614 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
615 HEAP->CollectGarbage(i::NEW_SPACE);
616 in_new_space = HEAP->InNewSpace(*istring);
617 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
618 CHECK_EQ(0, dispose_count);
620 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
621 CHECK_EQ(1, dispose_count);
625 THREADED_TEST(ScavengeExternalAsciiString) {
626 int dispose_count = 0;
627 bool in_new_space = false;
629 v8::HandleScope scope;
630 const char* one_byte_string = "test string";
631 Local<String> string = String::NewExternal(
632 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
633 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
634 HEAP->CollectGarbage(i::NEW_SPACE);
635 in_new_space = HEAP->InNewSpace(*istring);
636 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
637 CHECK_EQ(0, dispose_count);
639 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
640 CHECK_EQ(1, dispose_count);
644 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
646 // Only used by non-threaded tests, so it can use static fields.
647 static int dispose_calls;
648 static int dispose_count;
650 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651 : TestAsciiResource(data, &dispose_count),
652 dispose_(dispose) { }
656 if (dispose_) delete this;
663 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
664 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
667 TEST(ExternalStringWithDisposeHandling) {
668 const char* c_source = "1 + 2 * 3";
670 // Use a stack allocated external string resource allocated object.
671 TestAsciiResourceWithDisposeControl::dispose_count = 0;
672 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
673 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
675 v8::HandleScope scope;
677 Local<String> source = String::NewExternal(&res_stack);
678 Local<Script> script = Script::Compile(source);
679 Local<Value> value = script->Run();
680 CHECK(value->IsNumber());
681 CHECK_EQ(7, value->Int32Value());
682 HEAP->CollectAllAvailableGarbage();
683 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
685 i::Isolate::Current()->compilation_cache()->Clear();
686 HEAP->CollectAllAvailableGarbage();
687 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
688 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
690 // Use a heap allocated external string resource allocated object.
691 TestAsciiResourceWithDisposeControl::dispose_count = 0;
692 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693 TestAsciiResource* res_heap =
694 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
696 v8::HandleScope scope;
698 Local<String> source = String::NewExternal(res_heap);
699 Local<Script> script = Script::Compile(source);
700 Local<Value> value = script->Run();
701 CHECK(value->IsNumber());
702 CHECK_EQ(7, value->Int32Value());
703 HEAP->CollectAllAvailableGarbage();
704 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
706 i::Isolate::Current()->compilation_cache()->Clear();
707 HEAP->CollectAllAvailableGarbage();
708 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
709 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
713 THREADED_TEST(StringConcat) {
715 v8::HandleScope scope;
717 const char* one_byte_string_1 = "function a_times_t";
718 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
719 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
721 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
723 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
724 Local<String> left = v8_str(one_byte_string_1);
726 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
727 Local<String> right = String::New(two_byte_source);
728 i::DeleteArray(two_byte_source);
730 Local<String> source = String::Concat(left, right);
731 right = String::NewExternal(
732 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
733 source = String::Concat(source, right);
734 right = String::NewExternal(
735 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
736 source = String::Concat(source, right);
737 right = v8_str(one_byte_string_2);
738 source = String::Concat(source, right);
740 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
741 right = String::New(two_byte_source);
742 i::DeleteArray(two_byte_source);
744 source = String::Concat(source, right);
745 right = String::NewExternal(
746 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
747 source = String::Concat(source, right);
748 Local<Script> script = Script::Compile(source);
749 Local<Value> value = script->Run();
750 CHECK(value->IsNumber());
751 CHECK_EQ(68, value->Int32Value());
753 i::Isolate::Current()->compilation_cache()->Clear();
754 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
755 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
759 THREADED_TEST(GlobalProperties) {
760 v8::HandleScope scope;
762 v8::Handle<v8::Object> global = env->Global();
763 global->Set(v8_str("pi"), v8_num(3.1415926));
764 Local<Value> pi = global->Get(v8_str("pi"));
765 CHECK_EQ(3.1415926, pi->NumberValue());
769 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
770 ApiTestFuzzer::Fuzz();
775 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
776 ApiTestFuzzer::Fuzz();
777 args.This()->Set(v8_str("x"), v8_num(1));
778 args.This()->Set(v8_str("y"), v8_num(2));
782 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
783 ApiTestFuzzer::Fuzz();
788 THREADED_TEST(FunctionTemplate) {
789 v8::HandleScope scope;
792 Local<v8::FunctionTemplate> fun_templ =
793 v8::FunctionTemplate::New(handle_call);
794 Local<Function> fun = fun_templ->GetFunction();
795 env->Global()->Set(v8_str("obj"), fun);
796 Local<Script> script = v8_compile("obj()");
797 CHECK_EQ(102, script->Run()->Int32Value());
799 // Use SetCallHandler to initialize a function template, should work like the
802 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
803 fun_templ->SetCallHandler(handle_call);
804 Local<Function> fun = fun_templ->GetFunction();
805 env->Global()->Set(v8_str("obj"), fun);
806 Local<Script> script = v8_compile("obj()");
807 CHECK_EQ(102, script->Run()->Int32Value());
809 // Test constructor calls.
811 Local<v8::FunctionTemplate> fun_templ =
812 v8::FunctionTemplate::New(construct_call);
813 fun_templ->SetClassName(v8_str("funky"));
814 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
815 Local<Function> fun = fun_templ->GetFunction();
816 env->Global()->Set(v8_str("obj"), fun);
817 Local<Script> script = v8_compile("var s = new obj(); s.x");
818 CHECK_EQ(1, script->Run()->Int32Value());
820 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
821 CHECK_EQ(v8_str("[object funky]"), result);
823 result = v8_compile("(new obj()).m")->Run();
824 CHECK_EQ(239, result->Int32Value());
829 static void* expected_ptr;
830 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
831 void* ptr = v8::External::Unwrap(args.Data());
832 CHECK_EQ(expected_ptr, ptr);
837 static void TestExternalPointerWrapping() {
838 v8::HandleScope scope;
841 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
843 v8::Handle<v8::Object> obj = v8::Object::New();
844 obj->Set(v8_str("func"),
845 v8::FunctionTemplate::New(callback, data)->GetFunction());
846 env->Global()->Set(v8_str("obj"), obj);
850 " for (var i = 0; i < 13; i++) obj.func();\n"
852 "foo(), true")->BooleanValue());
856 THREADED_TEST(ExternalWrap) {
857 // Check heap allocated object.
860 TestExternalPointerWrapping();
863 // Check stack allocated object.
866 TestExternalPointerWrapping();
868 // Check not aligned addresses.
870 char* s = new char[n];
871 for (int i = 0; i < n; i++) {
872 expected_ptr = s + i;
873 TestExternalPointerWrapping();
878 // Check several invalid addresses.
879 expected_ptr = reinterpret_cast<void*>(1);
880 TestExternalPointerWrapping();
882 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
883 TestExternalPointerWrapping();
885 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
886 TestExternalPointerWrapping();
888 #if defined(V8_HOST_ARCH_X64)
889 // Check a value with a leading 1 bit in x64 Smi encoding.
890 expected_ptr = reinterpret_cast<void*>(0x400000000);
891 TestExternalPointerWrapping();
893 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
894 TestExternalPointerWrapping();
896 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
897 TestExternalPointerWrapping();
902 THREADED_TEST(FindInstanceInPrototypeChain) {
903 v8::HandleScope scope;
906 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
907 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
908 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
909 derived->Inherit(base);
911 Local<v8::Function> base_function = base->GetFunction();
912 Local<v8::Function> derived_function = derived->GetFunction();
913 Local<v8::Function> other_function = other->GetFunction();
915 Local<v8::Object> base_instance = base_function->NewInstance();
916 Local<v8::Object> derived_instance = derived_function->NewInstance();
917 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
918 Local<v8::Object> other_instance = other_function->NewInstance();
919 derived_instance2->Set(v8_str("__proto__"), derived_instance);
920 other_instance->Set(v8_str("__proto__"), derived_instance2);
922 // base_instance is only an instance of base.
923 CHECK_EQ(base_instance,
924 base_instance->FindInstanceInPrototypeChain(base));
925 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
926 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
928 // derived_instance is an instance of base and derived.
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(base));
931 CHECK_EQ(derived_instance,
932 derived_instance->FindInstanceInPrototypeChain(derived));
933 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
935 // other_instance is an instance of other and its immediate
936 // prototype derived_instance2 is an instance of base and derived.
937 // Note, derived_instance is an instance of base and derived too,
938 // but it comes after derived_instance2 in the prototype chain of
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(base));
942 CHECK_EQ(derived_instance2,
943 other_instance->FindInstanceInPrototypeChain(derived));
944 CHECK_EQ(other_instance,
945 other_instance->FindInstanceInPrototypeChain(other));
949 THREADED_TEST(TinyInteger) {
950 v8::HandleScope scope;
953 Local<v8::Integer> value_obj = v8::Integer::New(value);
954 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
958 THREADED_TEST(BigSmiInteger) {
959 v8::HandleScope scope;
961 int32_t value = i::Smi::kMaxValue;
962 // We cannot add one to a Smi::kMaxValue without wrapping.
963 if (i::kSmiValueSize < 32) {
964 CHECK(i::Smi::IsValid(value));
965 CHECK(!i::Smi::IsValid(value + 1));
966 Local<v8::Integer> value_obj = v8::Integer::New(value);
967 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
972 THREADED_TEST(BigInteger) {
973 v8::HandleScope scope;
975 // We cannot add one to a Smi::kMaxValue without wrapping.
976 if (i::kSmiValueSize < 32) {
977 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
978 // The code will not be run in that case, due to the "if" guard.
980 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
981 CHECK(value > i::Smi::kMaxValue);
982 CHECK(!i::Smi::IsValid(value));
983 Local<v8::Integer> value_obj = v8::Integer::New(value);
984 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
989 THREADED_TEST(TinyUnsignedInteger) {
990 v8::HandleScope scope;
992 uint32_t value = 239;
993 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
994 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
998 THREADED_TEST(BigUnsignedSmiInteger) {
999 v8::HandleScope scope;
1001 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1002 CHECK(i::Smi::IsValid(value));
1003 CHECK(!i::Smi::IsValid(value + 1));
1004 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1005 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1009 THREADED_TEST(BigUnsignedInteger) {
1010 v8::HandleScope scope;
1012 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1013 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1014 CHECK(!i::Smi::IsValid(value));
1015 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1016 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1020 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1021 v8::HandleScope scope;
1023 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1024 uint32_t value = INT32_MAX_AS_UINT + 1;
1025 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1026 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1027 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1031 THREADED_TEST(IsNativeError) {
1032 v8::HandleScope scope;
1034 v8::Handle<Value> syntax_error = CompileRun(
1035 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1036 CHECK(syntax_error->IsNativeError());
1037 v8::Handle<Value> not_error = CompileRun("{a:42}");
1038 CHECK(!not_error->IsNativeError());
1039 v8::Handle<Value> not_object = CompileRun("42");
1040 CHECK(!not_object->IsNativeError());
1044 THREADED_TEST(StringObject) {
1045 v8::HandleScope scope;
1047 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1048 CHECK(boxed_string->IsStringObject());
1049 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1050 CHECK(!unboxed_string->IsStringObject());
1051 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1052 CHECK(!boxed_not_string->IsStringObject());
1053 v8::Handle<Value> not_object = CompileRun("0");
1054 CHECK(!not_object->IsStringObject());
1055 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1056 CHECK(!as_boxed.IsEmpty());
1057 Local<v8::String> the_string = as_boxed->StringValue();
1058 CHECK(!the_string.IsEmpty());
1059 ExpectObject("\"test\"", the_string);
1060 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1061 CHECK(new_boxed_string->IsStringObject());
1062 as_boxed = new_boxed_string.As<v8::StringObject>();
1063 the_string = as_boxed->StringValue();
1064 CHECK(!the_string.IsEmpty());
1065 ExpectObject("\"test\"", the_string);
1069 THREADED_TEST(NumberObject) {
1070 v8::HandleScope scope;
1072 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1073 CHECK(boxed_number->IsNumberObject());
1074 v8::Handle<Value> unboxed_number = CompileRun("42");
1075 CHECK(!unboxed_number->IsNumberObject());
1076 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1077 CHECK(!boxed_not_number->IsNumberObject());
1078 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1079 CHECK(!as_boxed.IsEmpty());
1080 double the_number = as_boxed->NumberValue();
1081 CHECK_EQ(42.0, the_number);
1082 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1083 CHECK(new_boxed_number->IsNumberObject());
1084 as_boxed = new_boxed_number.As<v8::NumberObject>();
1085 the_number = as_boxed->NumberValue();
1086 CHECK_EQ(43.0, the_number);
1090 THREADED_TEST(BooleanObject) {
1091 v8::HandleScope scope;
1093 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1094 CHECK(boxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1096 CHECK(!unboxed_boolean->IsBooleanObject());
1097 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1098 CHECK(!boxed_not_boolean->IsBooleanObject());
1099 v8::Handle<v8::BooleanObject> as_boxed =
1100 boxed_boolean.As<v8::BooleanObject>();
1101 CHECK(!as_boxed.IsEmpty());
1102 bool the_boolean = as_boxed->BooleanValue();
1103 CHECK_EQ(true, the_boolean);
1104 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1105 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1106 CHECK(boxed_true->IsBooleanObject());
1107 CHECK(boxed_false->IsBooleanObject());
1108 as_boxed = boxed_true.As<v8::BooleanObject>();
1109 CHECK_EQ(true, as_boxed->BooleanValue());
1110 as_boxed = boxed_false.As<v8::BooleanObject>();
1111 CHECK_EQ(false, as_boxed->BooleanValue());
1115 THREADED_TEST(Number) {
1116 v8::HandleScope scope;
1118 double PI = 3.1415926;
1119 Local<v8::Number> pi_obj = v8::Number::New(PI);
1120 CHECK_EQ(PI, pi_obj->NumberValue());
1124 THREADED_TEST(ToNumber) {
1125 v8::HandleScope scope;
1127 Local<String> str = v8_str("3.1415926");
1128 CHECK_EQ(3.1415926, str->NumberValue());
1129 v8::Handle<v8::Boolean> t = v8::True();
1130 CHECK_EQ(1.0, t->NumberValue());
1131 v8::Handle<v8::Boolean> f = v8::False();
1132 CHECK_EQ(0.0, f->NumberValue());
1136 THREADED_TEST(Date) {
1137 v8::HandleScope scope;
1139 double PI = 3.1415926;
1140 Local<Value> date = v8::Date::New(PI);
1141 CHECK_EQ(3.0, date->NumberValue());
1142 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1143 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1147 THREADED_TEST(Boolean) {
1148 v8::HandleScope scope;
1150 v8::Handle<v8::Boolean> t = v8::True();
1152 v8::Handle<v8::Boolean> f = v8::False();
1154 v8::Handle<v8::Primitive> u = v8::Undefined();
1155 CHECK(!u->BooleanValue());
1156 v8::Handle<v8::Primitive> n = v8::Null();
1157 CHECK(!n->BooleanValue());
1158 v8::Handle<String> str1 = v8_str("");
1159 CHECK(!str1->BooleanValue());
1160 v8::Handle<String> str2 = v8_str("x");
1161 CHECK(str2->BooleanValue());
1162 CHECK(!v8::Number::New(0)->BooleanValue());
1163 CHECK(v8::Number::New(-1)->BooleanValue());
1164 CHECK(v8::Number::New(1)->BooleanValue());
1165 CHECK(v8::Number::New(42)->BooleanValue());
1166 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1170 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1171 ApiTestFuzzer::Fuzz();
1172 return v8_num(13.4);
1176 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1177 ApiTestFuzzer::Fuzz();
1182 THREADED_TEST(GlobalPrototype) {
1183 v8::HandleScope scope;
1184 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1185 func_templ->PrototypeTemplate()->Set(
1187 v8::FunctionTemplate::New(DummyCallHandler));
1188 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1189 templ->Set("x", v8_num(200));
1190 templ->SetAccessor(v8_str("m"), GetM);
1191 LocalContext env(0, templ);
1192 v8::Handle<v8::Object> obj(env->Global());
1193 v8::Handle<Script> script(v8_compile("dummy()"));
1194 v8::Handle<Value> result(script->Run());
1195 CHECK_EQ(13.4, result->NumberValue());
1196 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1197 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1201 THREADED_TEST(ObjectTemplate) {
1202 v8::HandleScope scope;
1203 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1204 templ1->Set("x", v8_num(10));
1205 templ1->Set("y", v8_num(13));
1207 Local<v8::Object> instance1 = templ1->NewInstance();
1208 env->Global()->Set(v8_str("p"), instance1);
1209 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1210 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1211 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1212 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1213 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1214 templ2->Set("a", v8_num(12));
1215 templ2->Set("b", templ1);
1216 Local<v8::Object> instance2 = templ2->NewInstance();
1217 env->Global()->Set(v8_str("q"), instance2);
1218 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1220 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1221 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1225 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1226 ApiTestFuzzer::Fuzz();
1227 return v8_num(17.2);
1231 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1232 ApiTestFuzzer::Fuzz();
1233 return v8_num(15.2);
1237 THREADED_TEST(DescriptorInheritance) {
1238 v8::HandleScope scope;
1239 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1240 super->PrototypeTemplate()->Set("flabby",
1241 v8::FunctionTemplate::New(GetFlabby));
1242 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1244 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1246 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1247 base1->Inherit(super);
1248 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1250 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1251 base2->Inherit(super);
1252 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1256 env->Global()->Set(v8_str("s"), super->GetFunction());
1257 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1258 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1260 // Checks right __proto__ chain.
1261 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1262 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1264 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1266 // Instance accessor should not be visible on function object or its prototype
1267 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1268 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1269 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1271 env->Global()->Set(v8_str("obj"),
1272 base1->GetFunction()->NewInstance());
1273 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1274 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1275 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1276 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1277 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1279 env->Global()->Set(v8_str("obj2"),
1280 base2->GetFunction()->NewInstance());
1281 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1282 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1283 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1284 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1285 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1287 // base1 and base2 cannot cross reference to each's prototype
1288 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1289 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1293 int echo_named_call_count;
1296 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1297 const AccessorInfo& info) {
1298 ApiTestFuzzer::Fuzz();
1299 CHECK_EQ(v8_str("data"), info.Data());
1300 echo_named_call_count++;
1304 // Helper functions for Interceptor/Accessor interaction tests
1306 Handle<Value> SimpleAccessorGetter(Local<String> name,
1307 const AccessorInfo& info) {
1308 Handle<Object> self = info.This();
1309 return self->Get(String::Concat(v8_str("accessor_"), name));
1312 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1313 const AccessorInfo& info) {
1314 Handle<Object> self = info.This();
1315 self->Set(String::Concat(v8_str("accessor_"), name), value);
1318 Handle<Value> EmptyInterceptorGetter(Local<String> name,
1319 const AccessorInfo& info) {
1320 return Handle<Value>();
1323 Handle<Value> EmptyInterceptorSetter(Local<String> name,
1325 const AccessorInfo& info) {
1326 return Handle<Value>();
1329 Handle<Value> InterceptorGetter(Local<String> name,
1330 const AccessorInfo& info) {
1331 // Intercept names that start with 'interceptor_'.
1332 String::AsciiValue ascii(name);
1333 char* name_str = *ascii;
1334 char prefix[] = "interceptor_";
1336 for (i = 0; name_str[i] && prefix[i]; ++i) {
1337 if (name_str[i] != prefix[i]) return Handle<Value>();
1339 Handle<Object> self = info.This();
1340 return self->GetHiddenValue(v8_str(name_str + i));
1343 Handle<Value> InterceptorSetter(Local<String> name,
1345 const AccessorInfo& info) {
1346 // Intercept accesses that set certain integer values.
1347 if (value->IsInt32() && value->Int32Value() < 10000) {
1348 Handle<Object> self = info.This();
1349 self->SetHiddenValue(name, value);
1352 return Handle<Value>();
1355 void AddAccessor(Handle<FunctionTemplate> templ,
1356 Handle<String> name,
1357 v8::AccessorGetter getter,
1358 v8::AccessorSetter setter) {
1359 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1362 void AddInterceptor(Handle<FunctionTemplate> templ,
1363 v8::NamedPropertyGetter getter,
1364 v8::NamedPropertySetter setter) {
1365 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1368 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1369 v8::HandleScope scope;
1370 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1371 Handle<FunctionTemplate> child = FunctionTemplate::New();
1372 child->Inherit(parent);
1373 AddAccessor(parent, v8_str("age"),
1374 SimpleAccessorGetter, SimpleAccessorSetter);
1375 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1377 env->Global()->Set(v8_str("Child"), child->GetFunction());
1378 CompileRun("var child = new Child;"
1380 ExpectBoolean("child.hasOwnProperty('age')", false);
1381 ExpectInt32("child.age", 10);
1382 ExpectInt32("child.accessor_age", 10);
1385 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1386 v8::HandleScope scope;
1387 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1388 Handle<FunctionTemplate> child = FunctionTemplate::New();
1389 child->Inherit(parent);
1390 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1392 env->Global()->Set(v8_str("Child"), child->GetFunction());
1393 CompileRun("var child = new Child;"
1394 "var parent = child.__proto__;"
1395 "Object.defineProperty(parent, 'age', "
1396 " {get: function(){ return this.accessor_age; }, "
1397 " set: function(v){ this.accessor_age = v; }, "
1398 " enumerable: true, configurable: true});"
1400 ExpectBoolean("child.hasOwnProperty('age')", false);
1401 ExpectInt32("child.age", 10);
1402 ExpectInt32("child.accessor_age", 10);
1405 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1406 v8::HandleScope scope;
1407 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1408 Handle<FunctionTemplate> child = FunctionTemplate::New();
1409 child->Inherit(parent);
1410 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1412 env->Global()->Set(v8_str("Child"), child->GetFunction());
1413 CompileRun("var child = new Child;"
1414 "var parent = child.__proto__;"
1415 "parent.name = 'Alice';");
1416 ExpectBoolean("child.hasOwnProperty('name')", false);
1417 ExpectString("child.name", "Alice");
1418 CompileRun("child.name = 'Bob';");
1419 ExpectString("child.name", "Bob");
1420 ExpectBoolean("child.hasOwnProperty('name')", true);
1421 ExpectString("parent.name", "Alice");
1424 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1425 v8::HandleScope scope;
1426 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1427 Handle<FunctionTemplate> child = FunctionTemplate::New();
1428 child->Inherit(parent);
1429 AddAccessor(parent, v8_str("age"),
1430 SimpleAccessorGetter, SimpleAccessorSetter);
1431 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1433 env->Global()->Set(v8_str("Child"), child->GetFunction());
1434 CompileRun("var child = new Child;"
1435 "function setAge(i){ child.age = i; };"
1436 "for(var i = 0; i <= 10000; i++) setAge(i);");
1437 // All i < 10000 go to the interceptor.
1438 ExpectInt32("child.interceptor_age", 9999);
1439 // The last i goes to the accessor.
1440 ExpectInt32("child.accessor_age", 10000);
1443 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1444 v8::HandleScope scope;
1445 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1446 Handle<FunctionTemplate> child = FunctionTemplate::New();
1447 child->Inherit(parent);
1448 AddAccessor(parent, v8_str("age"),
1449 SimpleAccessorGetter, SimpleAccessorSetter);
1450 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1452 env->Global()->Set(v8_str("Child"), child->GetFunction());
1453 CompileRun("var child = new Child;"
1454 "function setAge(i){ child.age = i; };"
1455 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1456 // All i >= 10000 go to the accessor.
1457 ExpectInt32("child.accessor_age", 10000);
1458 // The last i goes to the interceptor.
1459 ExpectInt32("child.interceptor_age", 9999);
1462 THREADED_TEST(SwitchFromInterceptorToProperty) {
1463 v8::HandleScope scope;
1464 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1465 Handle<FunctionTemplate> child = FunctionTemplate::New();
1466 child->Inherit(parent);
1467 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1469 env->Global()->Set(v8_str("Child"), child->GetFunction());
1470 CompileRun("var child = new Child;"
1471 "function setAge(i){ child.age = i; };"
1472 "for(var i = 0; i <= 10000; i++) setAge(i);");
1473 // All i < 10000 go to the interceptor.
1474 ExpectInt32("child.interceptor_age", 9999);
1475 // The last i goes to child's own property.
1476 ExpectInt32("child.age", 10000);
1479 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1480 v8::HandleScope scope;
1481 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1482 Handle<FunctionTemplate> child = FunctionTemplate::New();
1483 child->Inherit(parent);
1484 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1486 env->Global()->Set(v8_str("Child"), child->GetFunction());
1487 CompileRun("var child = new Child;"
1488 "function setAge(i){ child.age = i; };"
1489 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1490 // All i >= 10000 go to child's own property.
1491 ExpectInt32("child.age", 10000);
1492 // The last i goes to the interceptor.
1493 ExpectInt32("child.interceptor_age", 9999);
1496 THREADED_TEST(NamedPropertyHandlerGetter) {
1497 echo_named_call_count = 0;
1498 v8::HandleScope scope;
1499 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1500 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1504 env->Global()->Set(v8_str("obj"),
1505 templ->GetFunction()->NewInstance());
1506 CHECK_EQ(echo_named_call_count, 0);
1507 v8_compile("obj.x")->Run();
1508 CHECK_EQ(echo_named_call_count, 1);
1509 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1510 v8::Handle<Value> str = CompileRun(code);
1511 String::AsciiValue value(str);
1512 CHECK_EQ(*value, "oddlepoddle");
1513 // Check default behavior
1514 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1515 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1516 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1520 int echo_indexed_call_count = 0;
1523 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1524 const AccessorInfo& info) {
1525 ApiTestFuzzer::Fuzz();
1526 CHECK_EQ(v8_num(637), info.Data());
1527 echo_indexed_call_count++;
1528 return v8_num(index);
1532 THREADED_TEST(IndexedPropertyHandlerGetter) {
1533 v8::HandleScope scope;
1534 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1535 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1539 env->Global()->Set(v8_str("obj"),
1540 templ->GetFunction()->NewInstance());
1541 Local<Script> script = v8_compile("obj[900]");
1542 CHECK_EQ(script->Run()->Int32Value(), 900);
1546 v8::Handle<v8::Object> bottom;
1548 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1550 const AccessorInfo& info) {
1551 ApiTestFuzzer::Fuzz();
1552 CHECK(info.This()->Equals(bottom));
1553 return v8::Handle<Value>();
1556 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1558 const AccessorInfo& info) {
1559 ApiTestFuzzer::Fuzz();
1560 CHECK(info.This()->Equals(bottom));
1561 return v8::Handle<Value>();
1565 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1567 const AccessorInfo& info) {
1568 ApiTestFuzzer::Fuzz();
1569 CHECK(info.This()->Equals(bottom));
1570 return v8::Handle<Value>();
1574 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1576 const AccessorInfo& info) {
1577 ApiTestFuzzer::Fuzz();
1578 CHECK(info.This()->Equals(bottom));
1579 return v8::Handle<Value>();
1582 v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1584 const AccessorInfo& info) {
1585 ApiTestFuzzer::Fuzz();
1586 CHECK(info.This()->Equals(bottom));
1587 return v8::Handle<v8::Integer>();
1591 v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1592 const AccessorInfo& info) {
1593 ApiTestFuzzer::Fuzz();
1594 CHECK(info.This()->Equals(bottom));
1595 return v8::Handle<v8::Integer>();
1599 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1601 const AccessorInfo& info) {
1602 ApiTestFuzzer::Fuzz();
1603 CHECK(info.This()->Equals(bottom));
1604 return v8::Handle<v8::Boolean>();
1608 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1609 Local<String> property,
1610 const AccessorInfo& info) {
1611 ApiTestFuzzer::Fuzz();
1612 CHECK(info.This()->Equals(bottom));
1613 return v8::Handle<v8::Boolean>();
1617 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1618 const AccessorInfo& info) {
1619 ApiTestFuzzer::Fuzz();
1620 CHECK(info.This()->Equals(bottom));
1621 return v8::Handle<v8::Array>();
1625 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1626 const AccessorInfo& info) {
1627 ApiTestFuzzer::Fuzz();
1628 CHECK(info.This()->Equals(bottom));
1629 return v8::Handle<v8::Array>();
1633 THREADED_TEST(PropertyHandlerInPrototype) {
1634 v8::HandleScope scope;
1637 // Set up a prototype chain with three interceptors.
1638 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1639 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1640 CheckThisIndexedPropertyHandler,
1641 CheckThisIndexedPropertySetter,
1642 CheckThisIndexedPropertyQuery,
1643 CheckThisIndexedPropertyDeleter,
1644 CheckThisIndexedPropertyEnumerator);
1646 templ->InstanceTemplate()->SetNamedPropertyHandler(
1647 CheckThisNamedPropertyHandler,
1648 CheckThisNamedPropertySetter,
1649 CheckThisNamedPropertyQuery,
1650 CheckThisNamedPropertyDeleter,
1651 CheckThisNamedPropertyEnumerator);
1653 bottom = templ->GetFunction()->NewInstance();
1654 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1655 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1657 bottom->Set(v8_str("__proto__"), middle);
1658 middle->Set(v8_str("__proto__"), top);
1659 env->Global()->Set(v8_str("obj"), bottom);
1661 // Indexed and named get.
1662 Script::Compile(v8_str("obj[0]"))->Run();
1663 Script::Compile(v8_str("obj.x"))->Run();
1665 // Indexed and named set.
1666 Script::Compile(v8_str("obj[1] = 42"))->Run();
1667 Script::Compile(v8_str("obj.y = 42"))->Run();
1669 // Indexed and named query.
1670 Script::Compile(v8_str("0 in obj"))->Run();
1671 Script::Compile(v8_str("'x' in obj"))->Run();
1673 // Indexed and named deleter.
1674 Script::Compile(v8_str("delete obj[0]"))->Run();
1675 Script::Compile(v8_str("delete obj.x"))->Run();
1678 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1682 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1683 const AccessorInfo& info) {
1684 ApiTestFuzzer::Fuzz();
1685 if (v8_str("pre")->Equals(key)) {
1686 return v8_str("PrePropertyHandler: pre");
1688 return v8::Handle<String>();
1692 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1693 const AccessorInfo&) {
1694 if (v8_str("pre")->Equals(key)) {
1695 return v8::Integer::New(v8::None);
1698 return v8::Handle<v8::Integer>(); // do not intercept the call
1702 THREADED_TEST(PrePropertyHandler) {
1703 v8::HandleScope scope;
1704 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1705 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1707 PrePropertyHandlerQuery);
1708 LocalContext env(NULL, desc->InstanceTemplate());
1709 Script::Compile(v8_str(
1710 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1711 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1712 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1713 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1714 CHECK_EQ(v8_str("Object: on"), result_on);
1715 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1716 CHECK(result_post.IsEmpty());
1720 THREADED_TEST(UndefinedIsNotEnumerable) {
1721 v8::HandleScope scope;
1723 v8::Handle<Value> result = Script::Compile(v8_str(
1724 "this.propertyIsEnumerable(undefined)"))->Run();
1725 CHECK(result->IsFalse());
1729 v8::Handle<Script> call_recursively_script;
1730 static const int kTargetRecursionDepth = 200; // near maximum
1733 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1734 ApiTestFuzzer::Fuzz();
1735 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1736 if (depth == kTargetRecursionDepth) return v8::Undefined();
1737 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1738 return call_recursively_script->Run();
1742 static v8::Handle<Value> CallFunctionRecursivelyCall(
1743 const v8::Arguments& args) {
1744 ApiTestFuzzer::Fuzz();
1745 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1746 if (depth == kTargetRecursionDepth) {
1747 printf("[depth = %d]\n", depth);
1748 return v8::Undefined();
1750 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1751 v8::Handle<Value> function =
1752 args.This()->Get(v8_str("callFunctionRecursively"));
1753 return function.As<Function>()->Call(args.This(), 0, NULL);
1757 THREADED_TEST(DeepCrossLanguageRecursion) {
1758 v8::HandleScope scope;
1759 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1760 global->Set(v8_str("callScriptRecursively"),
1761 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1762 global->Set(v8_str("callFunctionRecursively"),
1763 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1764 LocalContext env(NULL, global);
1766 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1767 call_recursively_script = v8_compile("callScriptRecursively()");
1768 v8::Handle<Value> result(call_recursively_script->Run());
1769 call_recursively_script = v8::Handle<Script>();
1771 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1772 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1776 static v8::Handle<Value>
1777 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1778 ApiTestFuzzer::Fuzz();
1779 return v8::ThrowException(key);
1783 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1785 const AccessorInfo&) {
1786 v8::ThrowException(key);
1787 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1791 THREADED_TEST(CallbackExceptionRegression) {
1792 v8::HandleScope scope;
1793 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1794 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1795 ThrowingPropertyHandlerSet);
1797 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1798 v8::Handle<Value> otto = Script::Compile(v8_str(
1799 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1800 CHECK_EQ(v8_str("otto"), otto);
1801 v8::Handle<Value> netto = Script::Compile(v8_str(
1802 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1803 CHECK_EQ(v8_str("netto"), netto);
1807 THREADED_TEST(FunctionPrototype) {
1808 v8::HandleScope scope;
1809 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1810 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1812 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1813 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1814 CHECK_EQ(script->Run()->Int32Value(), 321);
1818 THREADED_TEST(InternalFields) {
1819 v8::HandleScope scope;
1822 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1823 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1824 instance_templ->SetInternalFieldCount(1);
1825 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1826 CHECK_EQ(1, obj->InternalFieldCount());
1827 CHECK(obj->GetInternalField(0)->IsUndefined());
1828 obj->SetInternalField(0, v8_num(17));
1829 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1833 THREADED_TEST(GlobalObjectInternalFields) {
1834 v8::HandleScope scope;
1835 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1836 global_template->SetInternalFieldCount(1);
1837 LocalContext env(NULL, global_template);
1838 v8::Handle<v8::Object> global_proxy = env->Global();
1839 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1840 CHECK_EQ(1, global->InternalFieldCount());
1841 CHECK(global->GetInternalField(0)->IsUndefined());
1842 global->SetInternalField(0, v8_num(17));
1843 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1847 THREADED_TEST(InternalFieldsNativePointers) {
1848 v8::HandleScope scope;
1851 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1852 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1853 instance_templ->SetInternalFieldCount(1);
1854 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1855 CHECK_EQ(1, obj->InternalFieldCount());
1856 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1858 char* data = new char[100];
1860 void* aligned = data;
1861 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1862 void* unaligned = data + 1;
1863 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1865 // Check reading and writing aligned pointers.
1866 obj->SetPointerInInternalField(0, aligned);
1867 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1868 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1870 // Check reading and writing unaligned pointers.
1871 obj->SetPointerInInternalField(0, unaligned);
1872 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1873 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1879 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1880 v8::HandleScope scope;
1883 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1884 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1885 instance_templ->SetInternalFieldCount(1);
1886 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1887 CHECK_EQ(1, obj->InternalFieldCount());
1888 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1890 char* data = new char[100];
1892 void* aligned = data;
1893 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1894 void* unaligned = data + 1;
1895 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1897 obj->SetPointerInInternalField(0, aligned);
1898 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1899 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1901 obj->SetPointerInInternalField(0, unaligned);
1902 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1903 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1905 obj->SetInternalField(0, v8::External::Wrap(aligned));
1906 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1907 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1909 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1910 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1911 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1917 THREADED_TEST(IdentityHash) {
1918 v8::HandleScope scope;
1921 // Ensure that the test starts with an fresh heap to test whether the hash
1922 // code is based on the address.
1923 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1924 Local<v8::Object> obj = v8::Object::New();
1925 int hash = obj->GetIdentityHash();
1926 int hash1 = obj->GetIdentityHash();
1927 CHECK_EQ(hash, hash1);
1928 int hash2 = v8::Object::New()->GetIdentityHash();
1929 // Since the identity hash is essentially a random number two consecutive
1930 // objects should not be assigned the same hash code. If the test below fails
1931 // the random number generator should be evaluated.
1932 CHECK_NE(hash, hash2);
1933 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1934 int hash3 = v8::Object::New()->GetIdentityHash();
1935 // Make sure that the identity hash is not based on the initial address of
1936 // the object alone. If the test below fails the random number generator
1937 // should be evaluated.
1938 CHECK_NE(hash, hash3);
1939 int hash4 = obj->GetIdentityHash();
1940 CHECK_EQ(hash, hash4);
1942 // Check identity hashes behaviour in the presence of JS accessors.
1943 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1945 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1946 Local<v8::Object> o1 = v8::Object::New();
1947 Local<v8::Object> o2 = v8::Object::New();
1948 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1952 "function cnst() { return 42; };\n"
1953 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1954 Local<v8::Object> o1 = v8::Object::New();
1955 Local<v8::Object> o2 = v8::Object::New();
1956 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1961 THREADED_TEST(HiddenProperties) {
1962 v8::HandleScope scope;
1965 v8::Local<v8::Object> obj = v8::Object::New();
1966 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1967 v8::Local<v8::String> empty = v8_str("");
1968 v8::Local<v8::String> prop_name = v8_str("prop_name");
1970 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1972 // Make sure delete of a non-existent hidden value works
1973 CHECK(obj->DeleteHiddenValue(key));
1975 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1976 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1977 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1978 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1980 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1982 // Make sure we do not find the hidden property.
1983 CHECK(!obj->Has(empty));
1984 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1985 CHECK(obj->Get(empty)->IsUndefined());
1986 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1987 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1988 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1989 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1991 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1993 // Add another property and delete it afterwards to force the object in
1995 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1996 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1997 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1998 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1999 CHECK(obj->Delete(prop_name));
2000 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2002 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2004 CHECK(obj->DeleteHiddenValue(key));
2005 CHECK(obj->GetHiddenValue(key).IsEmpty());
2009 THREADED_TEST(Regress97784) {
2010 // Regression test for crbug.com/97784
2011 // Messing with the Object.prototype should not have effect on
2012 // hidden properties.
2013 v8::HandleScope scope;
2016 v8::Local<v8::Object> obj = v8::Object::New();
2017 v8::Local<v8::String> key = v8_str("hidden");
2020 "set_called = false;"
2021 "Object.defineProperty("
2022 " Object.prototype,"
2024 " {get: function() { return 45; },"
2025 " set: function() { set_called = true; }})");
2027 CHECK(obj->GetHiddenValue(key).IsEmpty());
2028 // Make sure that the getter and setter from Object.prototype is not invoked.
2029 // If it did we would have full access to the hidden properties in
2031 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2032 ExpectFalse("set_called");
2033 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2037 static bool interceptor_for_hidden_properties_called;
2038 static v8::Handle<Value> InterceptorForHiddenProperties(
2039 Local<String> name, const AccessorInfo& info) {
2040 interceptor_for_hidden_properties_called = true;
2041 return v8::Handle<Value>();
2045 THREADED_TEST(HiddenPropertiesWithInterceptors) {
2046 v8::HandleScope scope;
2047 LocalContext context;
2049 interceptor_for_hidden_properties_called = false;
2051 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2053 // Associate an interceptor with an object and start setting hidden values.
2054 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2055 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2056 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2057 Local<v8::Function> function = fun_templ->GetFunction();
2058 Local<v8::Object> obj = function->NewInstance();
2059 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2060 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2061 CHECK(!interceptor_for_hidden_properties_called);
2065 THREADED_TEST(External) {
2066 v8::HandleScope scope;
2068 Local<v8::External> ext = v8::External::New(&x);
2070 env->Global()->Set(v8_str("ext"), ext);
2071 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2072 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2073 int* ptr = static_cast<int*>(reext->Value());
2078 // Make sure unaligned pointers are wrapped properly.
2079 char* data = i::StrDup("0123456789");
2080 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2081 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2082 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2083 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2085 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2086 CHECK_EQ('0', *char_ptr);
2087 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2088 CHECK_EQ('1', *char_ptr);
2089 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2090 CHECK_EQ('2', *char_ptr);
2091 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2092 CHECK_EQ('3', *char_ptr);
2093 i::DeleteArray(data);
2097 THREADED_TEST(GlobalHandle) {
2098 v8::Persistent<String> global;
2100 v8::HandleScope scope;
2101 Local<String> str = v8_str("str");
2102 global = v8::Persistent<String>::New(str);
2104 CHECK_EQ(global->Length(), 3);
2109 class WeakCallCounter {
2111 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2112 int id() { return id_; }
2113 void increment() { number_of_weak_calls_++; }
2114 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2117 int number_of_weak_calls_;
2121 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2122 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2123 CHECK_EQ(1234, counter->id());
2124 counter->increment();
2129 THREADED_TEST(ApiObjectGroups) {
2133 Persistent<Object> g1s1;
2134 Persistent<Object> g1s2;
2135 Persistent<Object> g1c1;
2136 Persistent<Object> g2s1;
2137 Persistent<Object> g2s2;
2138 Persistent<Object> g2c1;
2140 WeakCallCounter counter(1234);
2144 g1s1 = Persistent<Object>::New(Object::New());
2145 g1s2 = Persistent<Object>::New(Object::New());
2146 g1c1 = Persistent<Object>::New(Object::New());
2147 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2148 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2149 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2151 g2s1 = Persistent<Object>::New(Object::New());
2152 g2s2 = Persistent<Object>::New(Object::New());
2153 g2c1 = Persistent<Object>::New(Object::New());
2154 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2155 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2156 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2159 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2161 // Connect group 1 and 2, make a cycle.
2162 CHECK(g1s2->Set(0, g2s2));
2163 CHECK(g2s1->Set(0, g1s1));
2166 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2167 Persistent<Value> g1_children[] = { g1c1 };
2168 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2169 Persistent<Value> g2_children[] = { g2c1 };
2170 V8::AddObjectGroup(g1_objects, 2);
2171 V8::AddImplicitReferences(g1s1, g1_children, 1);
2172 V8::AddObjectGroup(g2_objects, 2);
2173 V8::AddImplicitReferences(g2s2, g2_children, 1);
2175 // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2176 // incremental garbage collection is stopped.
2177 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2179 // All object should be alive.
2180 CHECK_EQ(0, counter.NumberOfWeakCalls());
2183 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2184 // But make children strong roots---all the objects (except for children)
2185 // should be collectable now.
2189 // Groups are deleted, rebuild groups.
2191 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2192 Persistent<Value> g1_children[] = { g1c1 };
2193 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2194 Persistent<Value> g2_children[] = { g2c1 };
2195 V8::AddObjectGroup(g1_objects, 2);
2196 V8::AddImplicitReferences(g1s1, g1_children, 1);
2197 V8::AddObjectGroup(g2_objects, 2);
2198 V8::AddImplicitReferences(g2s2, g2_children, 1);
2201 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2203 // All objects should be gone. 5 global handles in total.
2204 CHECK_EQ(5, counter.NumberOfWeakCalls());
2206 // And now make children weak again and collect them.
2207 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2208 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2210 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2211 CHECK_EQ(7, counter.NumberOfWeakCalls());
2215 THREADED_TEST(ApiObjectGroupsCycle) {
2219 WeakCallCounter counter(1234);
2221 Persistent<Object> g1s1;
2222 Persistent<Object> g1s2;
2223 Persistent<Object> g2s1;
2224 Persistent<Object> g2s2;
2225 Persistent<Object> g3s1;
2226 Persistent<Object> g3s2;
2230 g1s1 = Persistent<Object>::New(Object::New());
2231 g1s2 = Persistent<Object>::New(Object::New());
2232 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2233 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2235 g2s1 = Persistent<Object>::New(Object::New());
2236 g2s2 = Persistent<Object>::New(Object::New());
2237 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2238 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2240 g3s1 = Persistent<Object>::New(Object::New());
2241 g3s2 = Persistent<Object>::New(Object::New());
2242 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2243 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2246 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2248 // Connect groups. We're building the following cycle:
2249 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2252 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2253 Persistent<Value> g1_children[] = { g2s1 };
2254 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2255 Persistent<Value> g2_children[] = { g3s1 };
2256 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2257 Persistent<Value> g3_children[] = { g1s1 };
2258 V8::AddObjectGroup(g1_objects, 2);
2259 V8::AddImplicitReferences(g1s1, g1_children, 1);
2260 V8::AddObjectGroup(g2_objects, 2);
2261 V8::AddImplicitReferences(g2s1, g2_children, 1);
2262 V8::AddObjectGroup(g3_objects, 2);
2263 V8::AddImplicitReferences(g3s1, g3_children, 1);
2265 // Do a single full GC
2266 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2268 // All object should be alive.
2269 CHECK_EQ(0, counter.NumberOfWeakCalls());
2272 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2274 // Groups are deleted, rebuild groups.
2276 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2277 Persistent<Value> g1_children[] = { g2s1 };
2278 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2279 Persistent<Value> g2_children[] = { g3s1 };
2280 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2281 Persistent<Value> g3_children[] = { g1s1 };
2282 V8::AddObjectGroup(g1_objects, 2);
2283 V8::AddImplicitReferences(g1s1, g1_children, 1);
2284 V8::AddObjectGroup(g2_objects, 2);
2285 V8::AddImplicitReferences(g2s1, g2_children, 1);
2286 V8::AddObjectGroup(g3_objects, 2);
2287 V8::AddImplicitReferences(g3s1, g3_children, 1);
2290 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2292 // All objects should be gone. 7 global handles in total.
2293 CHECK_EQ(7, counter.NumberOfWeakCalls());
2297 THREADED_TEST(ScriptException) {
2298 v8::HandleScope scope;
2300 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2301 v8::TryCatch try_catch;
2302 Local<Value> result = script->Run();
2303 CHECK(result.IsEmpty());
2304 CHECK(try_catch.HasCaught());
2305 String::AsciiValue exception_value(try_catch.Exception());
2306 CHECK_EQ(*exception_value, "panama!");
2310 bool message_received;
2313 static void check_message(v8::Handle<v8::Message> message,
2314 v8::Handle<Value> data) {
2315 CHECK_EQ(5.76, data->NumberValue());
2316 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2317 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2318 message_received = true;
2322 THREADED_TEST(MessageHandlerData) {
2323 message_received = false;
2324 v8::HandleScope scope;
2325 CHECK(!message_received);
2326 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2327 LocalContext context;
2328 v8::ScriptOrigin origin =
2329 v8::ScriptOrigin(v8_str("6.75"));
2330 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2332 script->SetData(v8_str("7.56"));
2334 CHECK(message_received);
2335 // clear out the message listener
2336 v8::V8::RemoveMessageListeners(check_message);
2340 THREADED_TEST(GetSetProperty) {
2341 v8::HandleScope scope;
2342 LocalContext context;
2343 context->Global()->Set(v8_str("foo"), v8_num(14));
2344 context->Global()->Set(v8_str("12"), v8_num(92));
2345 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2346 context->Global()->Set(v8_num(13), v8_num(56));
2347 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2348 CHECK_EQ(14, foo->Int32Value());
2349 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2350 CHECK_EQ(92, twelve->Int32Value());
2351 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2352 CHECK_EQ(32, sixteen->Int32Value());
2353 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2354 CHECK_EQ(56, thirteen->Int32Value());
2355 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2356 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2357 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2358 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2359 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2360 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2361 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2362 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2363 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2367 THREADED_TEST(PropertyAttributes) {
2368 v8::HandleScope scope;
2369 LocalContext context;
2371 Local<String> prop = v8_str("none");
2372 context->Global()->Set(prop, v8_num(7));
2373 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2375 prop = v8_str("read_only");
2376 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2377 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2378 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2379 Script::Compile(v8_str("read_only = 9"))->Run();
2380 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2381 context->Global()->Set(prop, v8_num(10));
2382 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2384 prop = v8_str("dont_delete");
2385 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2386 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2387 Script::Compile(v8_str("delete dont_delete"))->Run();
2388 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2389 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2391 prop = v8_str("dont_enum");
2392 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2393 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2395 prop = v8_str("absent");
2396 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2397 Local<Value> fake_prop = v8_num(1);
2398 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2401 Local<Value> exception =
2402 CompileRun("({ toString: function() { throw 'exception';} })");
2403 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2404 CHECK(try_catch.HasCaught());
2405 String::AsciiValue exception_value(try_catch.Exception());
2406 CHECK_EQ("exception", *exception_value);
2411 THREADED_TEST(Array) {
2412 v8::HandleScope scope;
2413 LocalContext context;
2414 Local<v8::Array> array = v8::Array::New();
2415 CHECK_EQ(0, array->Length());
2416 CHECK(array->Get(0)->IsUndefined());
2417 CHECK(!array->Has(0));
2418 CHECK(array->Get(100)->IsUndefined());
2419 CHECK(!array->Has(100));
2420 array->Set(2, v8_num(7));
2421 CHECK_EQ(3, array->Length());
2422 CHECK(!array->Has(0));
2423 CHECK(!array->Has(1));
2424 CHECK(array->Has(2));
2425 CHECK_EQ(7, array->Get(2)->Int32Value());
2426 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2427 Local<v8::Array> arr = obj.As<v8::Array>();
2428 CHECK_EQ(3, arr->Length());
2429 CHECK_EQ(1, arr->Get(0)->Int32Value());
2430 CHECK_EQ(2, arr->Get(1)->Int32Value());
2431 CHECK_EQ(3, arr->Get(2)->Int32Value());
2432 array = v8::Array::New(27);
2433 CHECK_EQ(27, array->Length());
2434 array = v8::Array::New(-27);
2435 CHECK_EQ(0, array->Length());
2439 v8::Handle<Value> HandleF(const v8::Arguments& args) {
2440 v8::HandleScope scope;
2441 ApiTestFuzzer::Fuzz();
2442 Local<v8::Array> result = v8::Array::New(args.Length());
2443 for (int i = 0; i < args.Length(); i++)
2444 result->Set(i, args[i]);
2445 return scope.Close(result);
2449 THREADED_TEST(Vector) {
2450 v8::HandleScope scope;
2451 Local<ObjectTemplate> global = ObjectTemplate::New();
2452 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2453 LocalContext context(0, global);
2455 const char* fun = "f()";
2456 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2457 CHECK_EQ(0, a0->Length());
2459 const char* fun2 = "f(11)";
2460 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2461 CHECK_EQ(1, a1->Length());
2462 CHECK_EQ(11, a1->Get(0)->Int32Value());
2464 const char* fun3 = "f(12, 13)";
2465 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2466 CHECK_EQ(2, a2->Length());
2467 CHECK_EQ(12, a2->Get(0)->Int32Value());
2468 CHECK_EQ(13, a2->Get(1)->Int32Value());
2470 const char* fun4 = "f(14, 15, 16)";
2471 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2472 CHECK_EQ(3, a3->Length());
2473 CHECK_EQ(14, a3->Get(0)->Int32Value());
2474 CHECK_EQ(15, a3->Get(1)->Int32Value());
2475 CHECK_EQ(16, a3->Get(2)->Int32Value());
2477 const char* fun5 = "f(17, 18, 19, 20)";
2478 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2479 CHECK_EQ(4, a4->Length());
2480 CHECK_EQ(17, a4->Get(0)->Int32Value());
2481 CHECK_EQ(18, a4->Get(1)->Int32Value());
2482 CHECK_EQ(19, a4->Get(2)->Int32Value());
2483 CHECK_EQ(20, a4->Get(3)->Int32Value());
2487 THREADED_TEST(FunctionCall) {
2488 v8::HandleScope scope;
2489 LocalContext context;
2493 " for (var i = 0; i < arguments.length; i++) {"
2494 " result.push(arguments[i]);"
2498 Local<Function> Foo =
2499 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2501 v8::Handle<Value>* args0 = NULL;
2502 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2503 CHECK_EQ(0, a0->Length());
2505 v8::Handle<Value> args1[] = { v8_num(1.1) };
2506 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2507 CHECK_EQ(1, a1->Length());
2508 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2510 v8::Handle<Value> args2[] = { v8_num(2.2),
2512 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2513 CHECK_EQ(2, a2->Length());
2514 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2515 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2517 v8::Handle<Value> args3[] = { v8_num(4.4),
2520 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2521 CHECK_EQ(3, a3->Length());
2522 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2523 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2524 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2526 v8::Handle<Value> args4[] = { v8_num(7.7),
2530 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2531 CHECK_EQ(4, a4->Length());
2532 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2533 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2534 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2535 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2539 static const char* js_code_causing_out_of_memory =
2540 "var a = new Array(); while(true) a.push(a);";
2543 // These tests run for a long time and prevent us from running tests
2544 // that come after them so they cannot run in parallel.
2546 // It's not possible to read a snapshot into a heap with different dimensions.
2547 if (i::Snapshot::IsEnabled()) return;
2549 static const int K = 1024;
2550 v8::ResourceConstraints constraints;
2551 constraints.set_max_young_space_size(256 * K);
2552 constraints.set_max_old_space_size(4 * K * K);
2553 v8::SetResourceConstraints(&constraints);
2555 // Execute a script that causes out of memory.
2556 v8::HandleScope scope;
2557 LocalContext context;
2558 v8::V8::IgnoreOutOfMemoryException();
2559 Local<Script> script =
2560 Script::Compile(String::New(js_code_causing_out_of_memory));
2561 Local<Value> result = script->Run();
2563 // Check for out of memory state.
2564 CHECK(result.IsEmpty());
2565 CHECK(context->HasOutOfMemoryException());
2569 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2570 ApiTestFuzzer::Fuzz();
2572 v8::HandleScope scope;
2573 LocalContext context;
2574 Local<Script> script =
2575 Script::Compile(String::New(js_code_causing_out_of_memory));
2576 Local<Value> result = script->Run();
2578 // Check for out of memory state.
2579 CHECK(result.IsEmpty());
2580 CHECK(context->HasOutOfMemoryException());
2586 TEST(OutOfMemoryNested) {
2587 // It's not possible to read a snapshot into a heap with different dimensions.
2588 if (i::Snapshot::IsEnabled()) return;
2590 static const int K = 1024;
2591 v8::ResourceConstraints constraints;
2592 constraints.set_max_young_space_size(256 * K);
2593 constraints.set_max_old_space_size(4 * K * K);
2594 v8::SetResourceConstraints(&constraints);
2596 v8::HandleScope scope;
2597 Local<ObjectTemplate> templ = ObjectTemplate::New();
2598 templ->Set(v8_str("ProvokeOutOfMemory"),
2599 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2600 LocalContext context(0, templ);
2601 v8::V8::IgnoreOutOfMemoryException();
2602 Local<Value> result = CompileRun(
2603 "var thrown = false;"
2605 " ProvokeOutOfMemory();"
2609 // Check for out of memory state.
2610 CHECK(result.IsEmpty());
2611 CHECK(context->HasOutOfMemoryException());
2615 TEST(HugeConsStringOutOfMemory) {
2616 // It's not possible to read a snapshot into a heap with different dimensions.
2617 if (i::Snapshot::IsEnabled()) return;
2619 static const int K = 1024;
2620 v8::ResourceConstraints constraints;
2621 constraints.set_max_young_space_size(256 * K);
2622 constraints.set_max_old_space_size(2 * K * K);
2623 v8::SetResourceConstraints(&constraints);
2625 // Execute a script that causes out of memory.
2626 v8::V8::IgnoreOutOfMemoryException();
2628 v8::HandleScope scope;
2629 LocalContext context;
2631 // Build huge string. This should fail with out of memory exception.
2632 Local<Value> result = CompileRun(
2633 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2634 "for (var i = 0; i < 22; i++) { str = str + str; }");
2636 // Check for out of memory state.
2637 CHECK(result.IsEmpty());
2638 CHECK(context->HasOutOfMemoryException());
2642 THREADED_TEST(ConstructCall) {
2643 v8::HandleScope scope;
2644 LocalContext context;
2648 " for (var i = 0; i < arguments.length; i++) {"
2649 " result.push(arguments[i]);"
2653 Local<Function> Foo =
2654 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2656 v8::Handle<Value>* args0 = NULL;
2657 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2658 CHECK_EQ(0, a0->Length());
2660 v8::Handle<Value> args1[] = { v8_num(1.1) };
2661 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2662 CHECK_EQ(1, a1->Length());
2663 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2665 v8::Handle<Value> args2[] = { v8_num(2.2),
2667 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2668 CHECK_EQ(2, a2->Length());
2669 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2670 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2672 v8::Handle<Value> args3[] = { v8_num(4.4),
2675 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2676 CHECK_EQ(3, a3->Length());
2677 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2678 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2679 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2681 v8::Handle<Value> args4[] = { v8_num(7.7),
2685 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2686 CHECK_EQ(4, a4->Length());
2687 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2688 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2689 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2690 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2694 static void CheckUncle(v8::TryCatch* try_catch) {
2695 CHECK(try_catch->HasCaught());
2696 String::AsciiValue str_value(try_catch->Exception());
2697 CHECK_EQ(*str_value, "uncle?");
2702 THREADED_TEST(ConversionNumber) {
2703 v8::HandleScope scope;
2705 // Very large number.
2706 CompileRun("var obj = Math.pow(2,32) * 1237;");
2707 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2708 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2709 CHECK_EQ(0, obj->ToInt32()->Value());
2710 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2712 CompileRun("var obj = -1234567890123;");
2713 obj = env->Global()->Get(v8_str("obj"));
2714 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2715 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2716 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2717 // Small positive integer.
2718 CompileRun("var obj = 42;");
2719 obj = env->Global()->Get(v8_str("obj"));
2720 CHECK_EQ(42.0, obj->ToNumber()->Value());
2721 CHECK_EQ(42, obj->ToInt32()->Value());
2722 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2723 // Negative integer.
2724 CompileRun("var obj = -37;");
2725 obj = env->Global()->Get(v8_str("obj"));
2726 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2727 CHECK_EQ(-37, obj->ToInt32()->Value());
2728 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2729 // Positive non-int32 integer.
2730 CompileRun("var obj = 0x81234567;");
2731 obj = env->Global()->Get(v8_str("obj"));
2732 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2733 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2734 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2736 CompileRun("var obj = 42.3;");
2737 obj = env->Global()->Get(v8_str("obj"));
2738 CHECK_EQ(42.3, obj->ToNumber()->Value());
2739 CHECK_EQ(42, obj->ToInt32()->Value());
2740 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2741 // Large negative fraction.
2742 CompileRun("var obj = -5726623061.75;");
2743 obj = env->Global()->Get(v8_str("obj"));
2744 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2745 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2746 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2750 THREADED_TEST(isNumberType) {
2751 v8::HandleScope scope;
2753 // Very large number.
2754 CompileRun("var obj = Math.pow(2,32) * 1237;");
2755 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2756 CHECK(!obj->IsInt32());
2757 CHECK(!obj->IsUint32());
2758 // Large negative number.
2759 CompileRun("var obj = -1234567890123;");
2760 obj = env->Global()->Get(v8_str("obj"));
2761 CHECK(!obj->IsInt32());
2762 CHECK(!obj->IsUint32());
2763 // Small positive integer.
2764 CompileRun("var obj = 42;");
2765 obj = env->Global()->Get(v8_str("obj"));
2766 CHECK(obj->IsInt32());
2767 CHECK(obj->IsUint32());
2768 // Negative integer.
2769 CompileRun("var obj = -37;");
2770 obj = env->Global()->Get(v8_str("obj"));
2771 CHECK(obj->IsInt32());
2772 CHECK(!obj->IsUint32());
2773 // Positive non-int32 integer.
2774 CompileRun("var obj = 0x81234567;");
2775 obj = env->Global()->Get(v8_str("obj"));
2776 CHECK(!obj->IsInt32());
2777 CHECK(obj->IsUint32());
2779 CompileRun("var obj = 42.3;");
2780 obj = env->Global()->Get(v8_str("obj"));
2781 CHECK(!obj->IsInt32());
2782 CHECK(!obj->IsUint32());
2783 // Large negative fraction.
2784 CompileRun("var obj = -5726623061.75;");
2785 obj = env->Global()->Get(v8_str("obj"));
2786 CHECK(!obj->IsInt32());
2787 CHECK(!obj->IsUint32());
2791 THREADED_TEST(ConversionException) {
2792 v8::HandleScope scope;
2795 "function TestClass() { };"
2796 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2797 "var obj = new TestClass();");
2798 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2800 v8::TryCatch try_catch;
2802 Local<Value> to_string_result = obj->ToString();
2803 CHECK(to_string_result.IsEmpty());
2804 CheckUncle(&try_catch);
2806 Local<Value> to_number_result = obj->ToNumber();
2807 CHECK(to_number_result.IsEmpty());
2808 CheckUncle(&try_catch);
2810 Local<Value> to_integer_result = obj->ToInteger();
2811 CHECK(to_integer_result.IsEmpty());
2812 CheckUncle(&try_catch);
2814 Local<Value> to_uint32_result = obj->ToUint32();
2815 CHECK(to_uint32_result.IsEmpty());
2816 CheckUncle(&try_catch);
2818 Local<Value> to_int32_result = obj->ToInt32();
2819 CHECK(to_int32_result.IsEmpty());
2820 CheckUncle(&try_catch);
2822 Local<Value> to_object_result = v8::Undefined()->ToObject();
2823 CHECK(to_object_result.IsEmpty());
2824 CHECK(try_catch.HasCaught());
2827 int32_t int32_value = obj->Int32Value();
2828 CHECK_EQ(0, int32_value);
2829 CheckUncle(&try_catch);
2831 uint32_t uint32_value = obj->Uint32Value();
2832 CHECK_EQ(0, uint32_value);
2833 CheckUncle(&try_catch);
2835 double number_value = obj->NumberValue();
2836 CHECK_NE(0, IsNaN(number_value));
2837 CheckUncle(&try_catch);
2839 int64_t integer_value = obj->IntegerValue();
2840 CHECK_EQ(0.0, static_cast<double>(integer_value));
2841 CheckUncle(&try_catch);
2845 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2846 ApiTestFuzzer::Fuzz();
2847 return v8::ThrowException(v8_str("konto"));
2851 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2852 if (args.Length() < 1) return v8::False();
2853 v8::HandleScope scope;
2854 v8::TryCatch try_catch;
2855 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2856 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2857 return v8::Boolean::New(try_catch.HasCaught());
2861 THREADED_TEST(APICatch) {
2862 v8::HandleScope scope;
2863 Local<ObjectTemplate> templ = ObjectTemplate::New();
2864 templ->Set(v8_str("ThrowFromC"),
2865 v8::FunctionTemplate::New(ThrowFromC));
2866 LocalContext context(0, templ);
2868 "var thrown = false;"
2874 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2875 CHECK(thrown->BooleanValue());
2879 THREADED_TEST(APIThrowTryCatch) {
2880 v8::HandleScope scope;
2881 Local<ObjectTemplate> templ = ObjectTemplate::New();
2882 templ->Set(v8_str("ThrowFromC"),
2883 v8::FunctionTemplate::New(ThrowFromC));
2884 LocalContext context(0, templ);
2885 v8::TryCatch try_catch;
2886 CompileRun("ThrowFromC();");
2887 CHECK(try_catch.HasCaught());
2891 // Test that a try-finally block doesn't shadow a try-catch block
2892 // when setting up an external handler.
2894 // BUG(271): Some of the exception propagation does not work on the
2895 // ARM simulator because the simulator separates the C++ stack and the
2896 // JS stack. This test therefore fails on the simulator. The test is
2897 // not threaded to allow the threading tests to run on the simulator.
2898 TEST(TryCatchInTryFinally) {
2899 v8::HandleScope scope;
2900 Local<ObjectTemplate> templ = ObjectTemplate::New();
2901 templ->Set(v8_str("CCatcher"),
2902 v8::FunctionTemplate::New(CCatcher));
2903 LocalContext context(0, templ);
2904 Local<Value> result = CompileRun("try {"
2906 " CCatcher('throw 7;');"
2911 CHECK(result->IsTrue());
2915 static void check_reference_error_message(
2916 v8::Handle<v8::Message> message,
2917 v8::Handle<v8::Value> data) {
2918 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2919 CHECK(message->Get()->Equals(v8_str(reference_error)));
2923 static v8::Handle<Value> Fail(const v8::Arguments& args) {
2924 ApiTestFuzzer::Fuzz();
2926 return v8::Undefined();
2930 // Test that overwritten methods are not invoked on uncaught exception
2931 // formatting. However, they are invoked when performing normal error
2932 // string conversions.
2933 TEST(APIThrowMessageOverwrittenToString) {
2934 v8::HandleScope scope;
2935 v8::V8::AddMessageListener(check_reference_error_message);
2936 Local<ObjectTemplate> templ = ObjectTemplate::New();
2937 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2938 LocalContext context(NULL, templ);
2939 CompileRun("asdf;");
2940 CompileRun("var limit = {};"
2941 "limit.valueOf = fail;"
2942 "Error.stackTraceLimit = limit;");
2944 CompileRun("Array.prototype.pop = fail;");
2945 CompileRun("Object.prototype.hasOwnProperty = fail;");
2946 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2947 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2948 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2949 CompileRun("ReferenceError.prototype.toString ="
2950 " function() { return 'Whoops' }");
2951 CompileRun("asdf;");
2952 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2953 CompileRun("asdf;");
2954 CompileRun("ReferenceError.prototype.constructor = void 0;");
2955 CompileRun("asdf;");
2956 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2957 CompileRun("asdf;");
2958 CompileRun("ReferenceError.prototype = new Object();");
2959 CompileRun("asdf;");
2960 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2961 CHECK(string->Equals(v8_str("Whoops")));
2962 CompileRun("ReferenceError.prototype.constructor = new Object();"
2963 "ReferenceError.prototype.constructor.name = 1;"
2964 "Number.prototype.toString = function() { return 'Whoops'; };"
2965 "ReferenceError.prototype.toString = Object.prototype.toString;");
2966 CompileRun("asdf;");
2967 v8::V8::RemoveMessageListeners(check_message);
2971 static void receive_message(v8::Handle<v8::Message> message,
2972 v8::Handle<v8::Value> data) {
2974 message_received = true;
2978 TEST(APIThrowMessage) {
2979 message_received = false;
2980 v8::HandleScope scope;
2981 v8::V8::AddMessageListener(receive_message);
2982 Local<ObjectTemplate> templ = ObjectTemplate::New();
2983 templ->Set(v8_str("ThrowFromC"),
2984 v8::FunctionTemplate::New(ThrowFromC));
2985 LocalContext context(0, templ);
2986 CompileRun("ThrowFromC();");
2987 CHECK(message_received);
2988 v8::V8::RemoveMessageListeners(check_message);
2992 TEST(APIThrowMessageAndVerboseTryCatch) {
2993 message_received = false;
2994 v8::HandleScope scope;
2995 v8::V8::AddMessageListener(receive_message);
2996 Local<ObjectTemplate> templ = ObjectTemplate::New();
2997 templ->Set(v8_str("ThrowFromC"),
2998 v8::FunctionTemplate::New(ThrowFromC));
2999 LocalContext context(0, templ);
3000 v8::TryCatch try_catch;
3001 try_catch.SetVerbose(true);
3002 Local<Value> result = CompileRun("ThrowFromC();");
3003 CHECK(try_catch.HasCaught());
3004 CHECK(result.IsEmpty());
3005 CHECK(message_received);
3006 v8::V8::RemoveMessageListeners(check_message);
3010 TEST(APIStackOverflowAndVerboseTryCatch) {
3011 message_received = false;
3012 v8::HandleScope scope;
3013 v8::V8::AddMessageListener(receive_message);
3014 LocalContext context;
3015 v8::TryCatch try_catch;
3016 try_catch.SetVerbose(true);
3017 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3018 CHECK(try_catch.HasCaught());
3019 CHECK(result.IsEmpty());
3020 CHECK(message_received);
3021 v8::V8::RemoveMessageListeners(receive_message);
3025 THREADED_TEST(ExternalScriptException) {
3026 v8::HandleScope scope;
3027 Local<ObjectTemplate> templ = ObjectTemplate::New();
3028 templ->Set(v8_str("ThrowFromC"),
3029 v8::FunctionTemplate::New(ThrowFromC));
3030 LocalContext context(0, templ);
3032 v8::TryCatch try_catch;
3033 Local<Script> script
3034 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3035 Local<Value> result = script->Run();
3036 CHECK(result.IsEmpty());
3037 CHECK(try_catch.HasCaught());
3038 String::AsciiValue exception_value(try_catch.Exception());
3039 CHECK_EQ("konto", *exception_value);
3044 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3045 ApiTestFuzzer::Fuzz();
3046 CHECK_EQ(4, args.Length());
3047 int count = args[0]->Int32Value();
3048 int cInterval = args[2]->Int32Value();
3050 return v8::ThrowException(v8_str("FromC"));
3052 Local<v8::Object> global = Context::GetCurrent()->Global();
3053 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3054 v8::Handle<Value> argv[] = { v8_num(count - 1),
3058 if (count % cInterval == 0) {
3059 v8::TryCatch try_catch;
3060 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3061 int expected = args[3]->Int32Value();
3062 if (try_catch.HasCaught()) {
3063 CHECK_EQ(expected, count);
3064 CHECK(result.IsEmpty());
3065 CHECK(!i::Isolate::Current()->has_scheduled_exception());
3067 CHECK_NE(expected, count);
3071 return fun.As<Function>()->Call(global, 4, argv);
3077 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3078 ApiTestFuzzer::Fuzz();
3079 CHECK_EQ(3, args.Length());
3080 bool equality = args[0]->BooleanValue();
3081 int count = args[1]->Int32Value();
3082 int expected = args[2]->Int32Value();
3084 CHECK_EQ(count, expected);
3086 CHECK_NE(count, expected);
3088 return v8::Undefined();
3092 THREADED_TEST(EvalInTryFinally) {
3093 v8::HandleScope scope;
3094 LocalContext context;
3095 v8::TryCatch try_catch;
3096 CompileRun("(function() {"
3098 " eval('asldkf (*&^&*^');"
3103 CHECK(!try_catch.HasCaught());
3107 // This test works by making a stack of alternating JavaScript and C
3108 // activations. These activations set up exception handlers with regular
3109 // intervals, one interval for C activations and another for JavaScript
3110 // activations. When enough activations have been created an exception is
3111 // thrown and we check that the right activation catches the exception and that
3112 // no other activations do. The right activation is always the topmost one with
3113 // a handler, regardless of whether it is in JavaScript or C.
3115 // The notation used to describe a test case looks like this:
3117 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3119 // Each entry is an activation, either JS or C. The index is the count at that
3120 // level. Stars identify activations with exception handlers, the @ identifies
3121 // the exception handler that should catch the exception.
3123 // BUG(271): Some of the exception propagation does not work on the
3124 // ARM simulator because the simulator separates the C++ stack and the
3125 // JS stack. This test therefore fails on the simulator. The test is
3126 // not threaded to allow the threading tests to run on the simulator.
3127 TEST(ExceptionOrder) {
3128 v8::HandleScope scope;
3129 Local<ObjectTemplate> templ = ObjectTemplate::New();
3130 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3131 templ->Set(v8_str("CThrowCountDown"),
3132 v8::FunctionTemplate::New(CThrowCountDown));
3133 LocalContext context(0, templ);
3135 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3136 " if (count == 0) throw 'FromJS';"
3137 " if (count % jsInterval == 0) {"
3139 " var value = CThrowCountDown(count - 1,"
3143 " check(false, count, expected);"
3146 " check(true, count, expected);"
3149 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3152 Local<Function> fun =
3153 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3156 // count jsInterval cInterval expected
3158 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3159 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3160 fun->Call(fun, argc, a0);
3162 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3163 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3164 fun->Call(fun, argc, a1);
3166 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3167 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3168 fun->Call(fun, argc, a2);
3170 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3171 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3172 fun->Call(fun, argc, a3);
3174 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3175 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3176 fun->Call(fun, argc, a4);
3178 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3179 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3180 fun->Call(fun, argc, a5);
3184 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3185 ApiTestFuzzer::Fuzz();
3186 CHECK_EQ(1, args.Length());
3187 return v8::ThrowException(args[0]);
3191 THREADED_TEST(ThrowValues) {
3192 v8::HandleScope scope;
3193 Local<ObjectTemplate> templ = ObjectTemplate::New();
3194 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3195 LocalContext context(0, templ);
3196 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3197 "function Run(obj) {"
3203 " return 'no exception';"
3205 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3206 CHECK_EQ(5, result->Length());
3207 CHECK(result->Get(v8::Integer::New(0))->IsString());
3208 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3209 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3210 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3211 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3212 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3213 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3217 THREADED_TEST(CatchZero) {
3218 v8::HandleScope scope;
3219 LocalContext context;
3220 v8::TryCatch try_catch;
3221 CHECK(!try_catch.HasCaught());
3222 Script::Compile(v8_str("throw 10"))->Run();
3223 CHECK(try_catch.HasCaught());
3224 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3226 CHECK(!try_catch.HasCaught());
3227 Script::Compile(v8_str("throw 0"))->Run();
3228 CHECK(try_catch.HasCaught());
3229 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3233 THREADED_TEST(CatchExceptionFromWith) {
3234 v8::HandleScope scope;
3235 LocalContext context;
3236 v8::TryCatch try_catch;
3237 CHECK(!try_catch.HasCaught());
3238 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3239 CHECK(try_catch.HasCaught());
3243 THREADED_TEST(TryCatchAndFinallyHidingException) {
3244 v8::HandleScope scope;
3245 LocalContext context;
3246 v8::TryCatch try_catch;
3247 CHECK(!try_catch.HasCaught());
3248 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3249 CompileRun("f({toString: function() { throw 42; }});");
3250 CHECK(!try_catch.HasCaught());
3254 v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3255 v8::TryCatch try_catch;
3256 return v8::Undefined();
3260 THREADED_TEST(TryCatchAndFinally) {
3261 v8::HandleScope scope;
3262 LocalContext context;
3263 context->Global()->Set(
3264 v8_str("native_with_try_catch"),
3265 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3266 v8::TryCatch try_catch;
3267 CHECK(!try_catch.HasCaught());
3270 " throw new Error('a');\n"
3272 " native_with_try_catch();\n"
3274 CHECK(try_catch.HasCaught());
3278 THREADED_TEST(Equality) {
3279 v8::HandleScope scope;
3280 LocalContext context;
3281 // Check that equality works at all before relying on CHECK_EQ
3282 CHECK(v8_str("a")->Equals(v8_str("a")));
3283 CHECK(!v8_str("a")->Equals(v8_str("b")));
3285 CHECK_EQ(v8_str("a"), v8_str("a"));
3286 CHECK_NE(v8_str("a"), v8_str("b"));
3287 CHECK_EQ(v8_num(1), v8_num(1));
3288 CHECK_EQ(v8_num(1.00), v8_num(1));
3289 CHECK_NE(v8_num(1), v8_num(2));
3291 // Assume String is not symbol.
3292 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3293 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3294 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3295 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3296 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3297 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3298 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3299 CHECK(!not_a_number->StrictEquals(not_a_number));
3300 CHECK(v8::False()->StrictEquals(v8::False()));
3301 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3303 v8::Handle<v8::Object> obj = v8::Object::New();
3304 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3305 CHECK(alias->StrictEquals(obj));
3310 THREADED_TEST(MultiRun) {
3311 v8::HandleScope scope;
3312 LocalContext context;
3313 Local<Script> script = Script::Compile(v8_str("x"));
3314 for (int i = 0; i < 10; i++)
3319 static v8::Handle<Value> GetXValue(Local<String> name,
3320 const AccessorInfo& info) {
3321 ApiTestFuzzer::Fuzz();
3322 CHECK_EQ(info.Data(), v8_str("donut"));
3323 CHECK_EQ(name, v8_str("x"));
3328 THREADED_TEST(SimplePropertyRead) {
3329 v8::HandleScope scope;
3330 Local<ObjectTemplate> templ = ObjectTemplate::New();
3331 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3332 LocalContext context;
3333 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3334 Local<Script> script = Script::Compile(v8_str("obj.x"));
3335 for (int i = 0; i < 10; i++) {
3336 Local<Value> result = script->Run();
3337 CHECK_EQ(result, v8_str("x"));
3341 THREADED_TEST(DefinePropertyOnAPIAccessor) {
3342 v8::HandleScope scope;
3343 Local<ObjectTemplate> templ = ObjectTemplate::New();
3344 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3345 LocalContext context;
3346 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3348 // Uses getOwnPropertyDescriptor to check the configurable status
3349 Local<Script> script_desc
3350 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3352 "prop.configurable;"));
3353 Local<Value> result = script_desc->Run();
3354 CHECK_EQ(result->BooleanValue(), true);
3356 // Redefine get - but still configurable
3357 Local<Script> script_define
3358 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3359 " configurable: true };"
3360 "Object.defineProperty(obj, 'x', desc);"
3362 result = script_define->Run();
3363 CHECK_EQ(result, v8_num(42));
3365 // Check that the accessor is still configurable
3366 result = script_desc->Run();
3367 CHECK_EQ(result->BooleanValue(), true);
3369 // Redefine to a non-configurable
3371 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3372 " configurable: false };"
3373 "Object.defineProperty(obj, 'x', desc);"
3375 result = script_define->Run();
3376 CHECK_EQ(result, v8_num(43));
3377 result = script_desc->Run();
3378 CHECK_EQ(result->BooleanValue(), false);
3380 // Make sure that it is not possible to redefine again
3381 v8::TryCatch try_catch;
3382 result = script_define->Run();
3383 CHECK(try_catch.HasCaught());
3384 String::AsciiValue exception_value(try_catch.Exception());
3385 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3388 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3389 v8::HandleScope scope;
3390 Local<ObjectTemplate> templ = ObjectTemplate::New();
3391 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3392 LocalContext context;
3393 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3395 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3396 "Object.getOwnPropertyDescriptor( "
3398 "prop.configurable;"));
3399 Local<Value> result = script_desc->Run();
3400 CHECK_EQ(result->BooleanValue(), true);
3402 Local<Script> script_define =
3403 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3404 " configurable: true };"
3405 "Object.defineProperty(obj, 'x', desc);"
3407 result = script_define->Run();
3408 CHECK_EQ(result, v8_num(42));
3411 result = script_desc->Run();
3412 CHECK_EQ(result->BooleanValue(), true);
3416 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3417 " configurable: false };"
3418 "Object.defineProperty(obj, 'x', desc);"
3420 result = script_define->Run();
3421 CHECK_EQ(result, v8_num(43));
3422 result = script_desc->Run();
3424 CHECK_EQ(result->BooleanValue(), false);
3426 v8::TryCatch try_catch;
3427 result = script_define->Run();
3428 CHECK(try_catch.HasCaught());
3429 String::AsciiValue exception_value(try_catch.Exception());
3430 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3434 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3436 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3440 THREADED_TEST(DefineAPIAccessorOnObject) {
3441 v8::HandleScope scope;
3442 Local<ObjectTemplate> templ = ObjectTemplate::New();
3443 LocalContext context;
3445 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3446 CompileRun("var obj2 = {};");
3448 CHECK(CompileRun("obj1.x")->IsUndefined());
3449 CHECK(CompileRun("obj2.x")->IsUndefined());
3451 CHECK(GetGlobalProperty(&context, "obj1")->
3452 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3454 ExpectString("obj1.x", "x");
3455 CHECK(CompileRun("obj2.x")->IsUndefined());
3457 CHECK(GetGlobalProperty(&context, "obj2")->
3458 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3460 ExpectString("obj1.x", "x");
3461 ExpectString("obj2.x", "x");
3463 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3464 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3466 CompileRun("Object.defineProperty(obj1, 'x',"
3467 "{ get: function() { return 'y'; }, configurable: true })");
3469 ExpectString("obj1.x", "y");
3470 ExpectString("obj2.x", "x");
3472 CompileRun("Object.defineProperty(obj2, 'x',"
3473 "{ get: function() { return 'y'; }, configurable: true })");
3475 ExpectString("obj1.x", "y");
3476 ExpectString("obj2.x", "y");
3478 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3479 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3481 CHECK(GetGlobalProperty(&context, "obj1")->
3482 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3483 CHECK(GetGlobalProperty(&context, "obj2")->
3484 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3486 ExpectString("obj1.x", "x");
3487 ExpectString("obj2.x", "x");
3489 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3490 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3492 // Define getters/setters, but now make them not configurable.
3493 CompileRun("Object.defineProperty(obj1, 'x',"
3494 "{ get: function() { return 'z'; }, configurable: false })");
3495 CompileRun("Object.defineProperty(obj2, 'x',"
3496 "{ get: function() { return 'z'; }, configurable: false })");
3498 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3499 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3501 ExpectString("obj1.x", "z");
3502 ExpectString("obj2.x", "z");
3504 CHECK(!GetGlobalProperty(&context, "obj1")->
3505 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3506 CHECK(!GetGlobalProperty(&context, "obj2")->
3507 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3509 ExpectString("obj1.x", "z");
3510 ExpectString("obj2.x", "z");
3514 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3515 v8::HandleScope scope;
3516 Local<ObjectTemplate> templ = ObjectTemplate::New();
3517 LocalContext context;
3519 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3520 CompileRun("var obj2 = {};");
3522 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3525 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3526 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3529 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3531 ExpectString("obj1.x", "x");
3532 ExpectString("obj2.x", "x");
3534 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3535 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3537 CHECK(!GetGlobalProperty(&context, "obj1")->
3538 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3539 CHECK(!GetGlobalProperty(&context, "obj2")->
3540 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3543 v8::TryCatch try_catch;
3544 CompileRun("Object.defineProperty(obj1, 'x',"
3545 "{get: function() { return 'func'; }})");
3546 CHECK(try_catch.HasCaught());
3547 String::AsciiValue exception_value(try_catch.Exception());
3548 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3551 v8::TryCatch try_catch;
3552 CompileRun("Object.defineProperty(obj2, 'x',"
3553 "{get: function() { return 'func'; }})");
3554 CHECK(try_catch.HasCaught());
3555 String::AsciiValue exception_value(try_catch.Exception());
3556 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3561 static v8::Handle<Value> Get239Value(Local<String> name,
3562 const AccessorInfo& info) {
3563 ApiTestFuzzer::Fuzz();
3564 CHECK_EQ(info.Data(), v8_str("donut"));
3565 CHECK_EQ(name, v8_str("239"));
3570 THREADED_TEST(ElementAPIAccessor) {
3571 v8::HandleScope scope;
3572 Local<ObjectTemplate> templ = ObjectTemplate::New();
3573 LocalContext context;
3575 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3576 CompileRun("var obj2 = {};");
3578 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3582 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3587 ExpectString("obj1[239]", "239");
3588 ExpectString("obj2[239]", "239");
3589 ExpectString("obj1['239']", "239");
3590 ExpectString("obj2['239']", "239");
3594 v8::Persistent<Value> xValue;
3597 static void SetXValue(Local<String> name,
3599 const AccessorInfo& info) {
3600 CHECK_EQ(value, v8_num(4));
3601 CHECK_EQ(info.Data(), v8_str("donut"));
3602 CHECK_EQ(name, v8_str("x"));
3603 CHECK(xValue.IsEmpty());
3604 xValue = v8::Persistent<Value>::New(value);
3608 THREADED_TEST(SimplePropertyWrite) {
3609 v8::HandleScope scope;
3610 Local<ObjectTemplate> templ = ObjectTemplate::New();
3611 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3612 LocalContext context;
3613 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3614 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3615 for (int i = 0; i < 10; i++) {
3616 CHECK(xValue.IsEmpty());
3618 CHECK_EQ(v8_num(4), xValue);
3620 xValue = v8::Persistent<Value>();
3625 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3626 const AccessorInfo& info) {
3627 ApiTestFuzzer::Fuzz();
3628 CHECK(info.Data()->IsUndefined());
3633 THREADED_TEST(NamedInterceptorPropertyRead) {
3634 v8::HandleScope scope;
3635 Local<ObjectTemplate> templ = ObjectTemplate::New();
3636 templ->SetNamedPropertyHandler(XPropertyGetter);
3637 LocalContext context;
3638 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639 Local<Script> script = Script::Compile(v8_str("obj.x"));
3640 for (int i = 0; i < 10; i++) {
3641 Local<Value> result = script->Run();
3642 CHECK_EQ(result, v8_str("x"));
3647 THREADED_TEST(NamedInterceptorDictionaryIC) {
3648 v8::HandleScope scope;
3649 Local<ObjectTemplate> templ = ObjectTemplate::New();
3650 templ->SetNamedPropertyHandler(XPropertyGetter);
3651 LocalContext context;
3652 // Create an object with a named interceptor.
3653 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3654 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3655 for (int i = 0; i < 10; i++) {
3656 Local<Value> result = script->Run();
3657 CHECK_EQ(result, v8_str("x"));
3659 // Create a slow case object and a function accessing a property in
3660 // that slow case object (with dictionary probing in generated
3661 // code). Then force object with a named interceptor into slow-case,
3662 // pass it to the function, and check that the interceptor is called
3663 // instead of accessing the local property.
3664 Local<Value> result =
3665 CompileRun("function get_x(o) { return o.x; };"
3666 "var obj = { x : 42, y : 0 };"
3668 "for (var i = 0; i < 10; i++) get_x(obj);"
3669 "interceptor_obj.x = 42;"
3670 "interceptor_obj.y = 10;"
3671 "delete interceptor_obj.y;"
3672 "get_x(interceptor_obj)");
3673 CHECK_EQ(result, v8_str("x"));
3677 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3678 v8::HandleScope scope;
3680 v8::Persistent<Context> context1 = Context::New();
3683 Local<ObjectTemplate> templ = ObjectTemplate::New();
3684 templ->SetNamedPropertyHandler(XPropertyGetter);
3685 // Create an object with a named interceptor.
3686 v8::Local<v8::Object> object = templ->NewInstance();
3687 context1->Global()->Set(v8_str("interceptor_obj"), object);
3689 // Force the object into the slow case.
3690 CompileRun("interceptor_obj.y = 0;"
3691 "delete interceptor_obj.y;");
3695 // Introduce the object into a different context.
3696 // Repeat named loads to exercise ICs.
3697 LocalContext context2;
3698 context2->Global()->Set(v8_str("interceptor_obj"), object);
3699 Local<Value> result =
3700 CompileRun("function get_x(o) { return o.x; }"
3701 "interceptor_obj.x = 42;"
3702 "for (var i=0; i != 10; i++) {"
3703 " get_x(interceptor_obj);"
3705 "get_x(interceptor_obj)");
3706 // Check that the interceptor was actually invoked.
3707 CHECK_EQ(result, v8_str("x"));
3710 // Return to the original context and force some object to the slow case
3711 // to cause the NormalizedMapCache to verify.
3713 CompileRun("var obj = { x : 0 }; delete obj.x;");
3720 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3721 const AccessorInfo& info) {
3722 // Set x on the prototype object and do not handle the get request.
3723 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3724 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3725 return v8::Handle<Value>();
3729 // This is a regression test for http://crbug.com/20104. Map
3730 // transitions should not interfere with post interceptor lookup.
3731 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3732 v8::HandleScope scope;
3733 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3734 Local<v8::ObjectTemplate> instance_template
3735 = function_template->InstanceTemplate();
3736 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3737 LocalContext context;
3738 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3739 // Create an instance of F and introduce a map transition for x.
3740 CompileRun("var o = new F(); o.x = 23;");
3741 // Create an instance of F and invoke the getter. The result should be 23.
3742 Local<Value> result = CompileRun("o = new F(); o.x");
3743 CHECK_EQ(result->Int32Value(), 23);
3747 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3748 const AccessorInfo& info) {
3749 ApiTestFuzzer::Fuzz();
3751 return v8::Handle<Value>(v8_num(625));
3753 return v8::Handle<Value>();
3757 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3759 const AccessorInfo& info) {
3760 ApiTestFuzzer::Fuzz();
3764 return v8::Handle<Value>();
3768 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3769 v8::HandleScope scope;
3770 Local<ObjectTemplate> templ = ObjectTemplate::New();
3771 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3772 IndexedPropertySetter);
3773 LocalContext context;
3774 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3775 Local<Script> getter_script = Script::Compile(v8_str(
3776 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3777 Local<Script> setter_script = Script::Compile(v8_str(
3778 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3781 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3782 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3784 "obj.foo;")); // This setter should not run, due to the interceptor.
3785 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3787 Local<Value> result = getter_script->Run();
3788 CHECK_EQ(v8_num(5), result);
3789 result = setter_script->Run();
3790 CHECK_EQ(v8_num(23), result);
3791 result = interceptor_setter_script->Run();
3792 CHECK_EQ(v8_num(23), result);
3793 result = interceptor_getter_script->Run();
3794 CHECK_EQ(v8_num(625), result);
3798 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3800 const AccessorInfo& info) {
3801 ApiTestFuzzer::Fuzz();
3803 return v8::Handle<Value>(v8_num(index));
3805 return v8::Handle<Value>();
3809 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3812 const AccessorInfo& info) {
3813 ApiTestFuzzer::Fuzz();
3815 return v8::Handle<Value>(v8_num(index));
3817 return v8::Handle<Value>();
3821 Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3822 const AccessorInfo& info) {
3823 // Force the list of returned keys to be stored in a FastDoubleArray.
3824 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3825 "keys = new Array(); keys[125000] = 1;"
3826 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3827 "keys.length = 25; keys;"));
3828 Local<Value> result = indexed_property_names_script->Run();
3829 return Local<v8::Array>(::v8::Array::Cast(*result));
3833 // Make sure that the the interceptor code in the runtime properly handles
3834 // merging property name lists for double-array-backed arrays.
3835 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3836 v8::HandleScope scope;
3837 Local<ObjectTemplate> templ = ObjectTemplate::New();
3838 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3839 UnboxedDoubleIndexedPropertySetter,
3842 UnboxedDoubleIndexedPropertyEnumerator);
3843 LocalContext context;
3844 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3845 // When obj is created, force it to be Stored in a FastDoubleArray.
3846 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3847 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3849 "for (x in obj) {key_count++;};"
3851 Local<Value> result = create_unboxed_double_script->Run();
3852 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3853 Local<Script> key_count_check = Script::Compile(v8_str(
3855 result = key_count_check->Run();
3856 CHECK_EQ(v8_num(40013), result);
3860 Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3861 const AccessorInfo& info) {
3862 // Force the list of returned keys to be stored in a Arguments object.
3863 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3865 " return arguments;"
3867 "keys = f(0, 1, 2, 3);"
3869 Local<Value> result = indexed_property_names_script->Run();
3870 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3874 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3876 const AccessorInfo& info) {
3877 ApiTestFuzzer::Fuzz();
3879 return v8::Handle<Value>(v8_num(index));
3881 return v8::Handle<Value>();
3885 // Make sure that the the interceptor code in the runtime properly handles
3886 // merging property name lists for non-string arguments arrays.
3887 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3888 v8::HandleScope scope;
3889 Local<ObjectTemplate> templ = ObjectTemplate::New();
3890 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3894 NonStrictArgsIndexedPropertyEnumerator);
3895 LocalContext context;
3896 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3897 Local<Script> create_args_script =
3898 Script::Compile(v8_str(
3899 "var key_count = 0;"
3900 "for (x in obj) {key_count++;} key_count;"));
3901 Local<Value> result = create_args_script->Run();
3902 CHECK_EQ(v8_num(4), result);
3906 static v8::Handle<Value> IdentityIndexedPropertyGetter(
3908 const AccessorInfo& info) {
3909 return v8::Integer::NewFromUnsigned(index);
3913 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3914 v8::HandleScope scope;
3915 Local<ObjectTemplate> templ = ObjectTemplate::New();
3916 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3918 LocalContext context;
3919 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3921 // Check fast object case.
3922 const char* fast_case_code =
3923 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3924 ExpectString(fast_case_code, "0");
3927 const char* slow_case_code =
3928 "obj.x = 1; delete obj.x;"
3929 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3930 ExpectString(slow_case_code, "1");
3934 THREADED_TEST(IndexedInterceptorWithNoSetter) {
3935 v8::HandleScope scope;
3936 Local<ObjectTemplate> templ = ObjectTemplate::New();
3937 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3939 LocalContext context;
3940 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3945 " for (var i = 0; i < 100; i++) {"
3947 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3953 ExpectString(code, "PASSED");
3957 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3958 v8::HandleScope scope;
3959 Local<ObjectTemplate> templ = ObjectTemplate::New();
3960 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3962 LocalContext context;
3963 Local<v8::Object> obj = templ->NewInstance();
3964 obj->TurnOnAccessCheck();
3965 context->Global()->Set(v8_str("obj"), obj);
3969 " for (var i = 0; i < 100; i++) {"
3971 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3977 ExpectString(code, "PASSED");
3981 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3982 i::FLAG_allow_natives_syntax = true;
3983 v8::HandleScope scope;
3984 Local<ObjectTemplate> templ = ObjectTemplate::New();
3985 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3987 LocalContext context;
3988 Local<v8::Object> obj = templ->NewInstance();
3989 context->Global()->Set(v8_str("obj"), obj);
3993 " for (var i = 0; i < 100; i++) {"
3994 " var expected = i;"
3996 " %EnableAccessChecks(obj);"
3997 " expected = undefined;"
4000 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4001 " if (i == 5) %DisableAccessChecks(obj);"
4007 ExpectString(code, "PASSED");
4011 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4012 v8::HandleScope scope;
4013 Local<ObjectTemplate> templ = ObjectTemplate::New();
4014 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4016 LocalContext context;
4017 Local<v8::Object> obj = templ->NewInstance();
4018 context->Global()->Set(v8_str("obj"), obj);
4022 " for (var i = 0; i < 100; i++) {"
4024 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4030 ExpectString(code, "PASSED");
4034 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4035 v8::HandleScope scope;
4036 Local<ObjectTemplate> templ = ObjectTemplate::New();
4037 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4039 LocalContext context;
4040 Local<v8::Object> obj = templ->NewInstance();
4041 context->Global()->Set(v8_str("obj"), obj);
4045 " for (var i = 0; i < 100; i++) {"
4046 " var expected = i;"
4050 " expected = undefined;"
4053 " /* probe minimal Smi number on 32-bit platforms */"
4054 " key = -(1 << 30);"
4055 " expected = undefined;"
4058 " /* probe minimal Smi number on 64-bit platforms */"
4060 " expected = undefined;"
4062 " var v = obj[key];"
4063 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4069 ExpectString(code, "PASSED");
4073 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4074 v8::HandleScope scope;
4075 Local<ObjectTemplate> templ = ObjectTemplate::New();
4076 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4078 LocalContext context;
4079 Local<v8::Object> obj = templ->NewInstance();
4080 context->Global()->Set(v8_str("obj"), obj);
4084 " for (var i = 0; i < 100; i++) {"
4085 " var expected = i;"
4089 " expected = undefined;"
4091 " var v = obj[key];"
4092 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4098 ExpectString(code, "PASSED");
4102 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4103 v8::HandleScope scope;
4104 Local<ObjectTemplate> templ = ObjectTemplate::New();
4105 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4107 LocalContext context;
4108 Local<v8::Object> obj = templ->NewInstance();
4109 context->Global()->Set(v8_str("obj"), obj);
4112 "var original = obj;"
4114 " for (var i = 0; i < 100; i++) {"
4115 " var expected = i;"
4117 " obj = {50: 'foobar'};"
4118 " expected = 'foobar';"
4121 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4122 " if (i == 50) obj = original;"
4128 ExpectString(code, "PASSED");
4132 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4133 v8::HandleScope scope;
4134 Local<ObjectTemplate> templ = ObjectTemplate::New();
4135 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4137 LocalContext context;
4138 Local<v8::Object> obj = templ->NewInstance();
4139 context->Global()->Set(v8_str("obj"), obj);
4142 "var original = obj;"
4144 " for (var i = 0; i < 100; i++) {"
4145 " var expected = i;"
4148 " expected = undefined;"
4151 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152 " if (i == 5) obj = original;"
4158 ExpectString(code, "PASSED");
4162 THREADED_TEST(IndexedInterceptorOnProto) {
4163 v8::HandleScope scope;
4164 Local<ObjectTemplate> templ = ObjectTemplate::New();
4165 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4167 LocalContext context;
4168 Local<v8::Object> obj = templ->NewInstance();
4169 context->Global()->Set(v8_str("obj"), obj);
4172 "var o = {__proto__: obj};"
4174 " for (var i = 0; i < 100; i++) {"
4176 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4182 ExpectString(code, "PASSED");
4186 THREADED_TEST(MultiContexts) {
4187 v8::HandleScope scope;
4188 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4189 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4191 Local<String> password = v8_str("Password");
4193 // Create an environment
4194 LocalContext context0(0, templ);
4195 context0->SetSecurityToken(password);
4196 v8::Handle<v8::Object> global0 = context0->Global();
4197 global0->Set(v8_str("custom"), v8_num(1234));
4198 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4200 // Create an independent environment
4201 LocalContext context1(0, templ);
4202 context1->SetSecurityToken(password);
4203 v8::Handle<v8::Object> global1 = context1->Global();
4204 global1->Set(v8_str("custom"), v8_num(1234));
4205 CHECK_NE(global0, global1);
4206 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4207 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4209 // Now create a new context with the old global
4210 LocalContext context2(0, templ, global1);
4211 context2->SetSecurityToken(password);
4212 v8::Handle<v8::Object> global2 = context2->Global();
4213 CHECK_EQ(global1, global2);
4214 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4215 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4219 THREADED_TEST(FunctionPrototypeAcrossContexts) {
4220 // Make sure that functions created by cloning boilerplates cannot
4221 // communicate through their __proto__ field.
4223 v8::HandleScope scope;
4226 v8::Handle<v8::Object> global0 =
4228 v8::Handle<v8::Object> object0 =
4229 global0->Get(v8_str("Object")).As<v8::Object>();
4230 v8::Handle<v8::Object> tostring0 =
4231 object0->Get(v8_str("toString")).As<v8::Object>();
4232 v8::Handle<v8::Object> proto0 =
4233 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4234 proto0->Set(v8_str("custom"), v8_num(1234));
4237 v8::Handle<v8::Object> global1 =
4239 v8::Handle<v8::Object> object1 =
4240 global1->Get(v8_str("Object")).As<v8::Object>();
4241 v8::Handle<v8::Object> tostring1 =
4242 object1->Get(v8_str("toString")).As<v8::Object>();
4243 v8::Handle<v8::Object> proto1 =
4244 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4245 CHECK(!proto1->Has(v8_str("custom")));
4249 THREADED_TEST(Regress892105) {
4250 // Make sure that object and array literals created by cloning
4251 // boilerplates cannot communicate through their __proto__
4252 // field. This is rather difficult to check, but we try to add stuff
4253 // to Object.prototype and Array.prototype and create a new
4254 // environment. This should succeed.
4256 v8::HandleScope scope;
4258 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4259 "Array.prototype.arr = 4567;"
4263 Local<Script> script0 = Script::Compile(source);
4264 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4267 Local<Script> script1 = Script::Compile(source);
4268 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4272 THREADED_TEST(UndetectableObject) {
4273 v8::HandleScope scope;
4276 Local<v8::FunctionTemplate> desc =
4277 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4278 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4280 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4281 env->Global()->Set(v8_str("undetectable"), obj);
4283 ExpectString("undetectable.toString()", "[object Object]");
4284 ExpectString("typeof undetectable", "undefined");
4285 ExpectString("typeof(undetectable)", "undefined");
4286 ExpectBoolean("typeof undetectable == 'undefined'", true);
4287 ExpectBoolean("typeof undetectable == 'object'", false);
4288 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4289 ExpectBoolean("!undetectable", true);
4291 ExpectObject("true&&undetectable", obj);
4292 ExpectBoolean("false&&undetectable", false);
4293 ExpectBoolean("true||undetectable", true);
4294 ExpectObject("false||undetectable", obj);
4296 ExpectObject("undetectable&&true", obj);
4297 ExpectObject("undetectable&&false", obj);
4298 ExpectBoolean("undetectable||true", true);
4299 ExpectBoolean("undetectable||false", false);
4301 ExpectBoolean("undetectable==null", true);
4302 ExpectBoolean("null==undetectable", true);
4303 ExpectBoolean("undetectable==undefined", true);
4304 ExpectBoolean("undefined==undetectable", true);
4305 ExpectBoolean("undetectable==undetectable", true);
4308 ExpectBoolean("undetectable===null", false);
4309 ExpectBoolean("null===undetectable", false);
4310 ExpectBoolean("undetectable===undefined", false);
4311 ExpectBoolean("undefined===undetectable", false);
4312 ExpectBoolean("undetectable===undetectable", true);
4316 THREADED_TEST(VoidLiteral) {
4317 v8::HandleScope scope;
4320 Local<v8::FunctionTemplate> desc =
4321 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4322 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4324 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4325 env->Global()->Set(v8_str("undetectable"), obj);
4327 ExpectBoolean("undefined == void 0", true);
4328 ExpectBoolean("undetectable == void 0", true);
4329 ExpectBoolean("null == void 0", true);
4330 ExpectBoolean("undefined === void 0", true);
4331 ExpectBoolean("undetectable === void 0", false);
4332 ExpectBoolean("null === void 0", false);
4334 ExpectBoolean("void 0 == undefined", true);
4335 ExpectBoolean("void 0 == undetectable", true);
4336 ExpectBoolean("void 0 == null", true);
4337 ExpectBoolean("void 0 === undefined", true);
4338 ExpectBoolean("void 0 === undetectable", false);
4339 ExpectBoolean("void 0 === null", false);
4341 ExpectString("(function() {"
4343 " return x === void 0;"
4345 " return e.toString();"
4348 "ReferenceError: x is not defined");
4349 ExpectString("(function() {"
4351 " return void 0 === x;"
4353 " return e.toString();"
4356 "ReferenceError: x is not defined");
4360 THREADED_TEST(ExtensibleOnUndetectable) {
4361 v8::HandleScope scope;
4364 Local<v8::FunctionTemplate> desc =
4365 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4366 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4368 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4369 env->Global()->Set(v8_str("undetectable"), obj);
4371 Local<String> source = v8_str("undetectable.x = 42;"
4374 Local<Script> script = Script::Compile(source);
4376 CHECK_EQ(v8::Integer::New(42), script->Run());
4378 ExpectBoolean("Object.isExtensible(undetectable)", true);
4380 source = v8_str("Object.preventExtensions(undetectable);");
4381 script = Script::Compile(source);
4383 ExpectBoolean("Object.isExtensible(undetectable)", false);
4385 source = v8_str("undetectable.y = 2000;");
4386 script = Script::Compile(source);
4387 Local<Value> result(script->Run());
4388 ExpectBoolean("undetectable.y == undefined", true);
4393 THREADED_TEST(UndetectableString) {
4394 v8::HandleScope scope;
4397 Local<String> obj = String::NewUndetectable("foo");
4398 env->Global()->Set(v8_str("undetectable"), obj);
4400 ExpectString("undetectable", "foo");
4401 ExpectString("typeof undetectable", "undefined");
4402 ExpectString("typeof(undetectable)", "undefined");
4403 ExpectBoolean("typeof undetectable == 'undefined'", true);
4404 ExpectBoolean("typeof undetectable == 'string'", false);
4405 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4406 ExpectBoolean("!undetectable", true);
4408 ExpectObject("true&&undetectable", obj);
4409 ExpectBoolean("false&&undetectable", false);
4410 ExpectBoolean("true||undetectable", true);
4411 ExpectObject("false||undetectable", obj);
4413 ExpectObject("undetectable&&true", obj);
4414 ExpectObject("undetectable&&false", obj);
4415 ExpectBoolean("undetectable||true", true);
4416 ExpectBoolean("undetectable||false", false);
4418 ExpectBoolean("undetectable==null", true);
4419 ExpectBoolean("null==undetectable", true);
4420 ExpectBoolean("undetectable==undefined", true);
4421 ExpectBoolean("undefined==undetectable", true);
4422 ExpectBoolean("undetectable==undetectable", true);
4425 ExpectBoolean("undetectable===null", false);
4426 ExpectBoolean("null===undetectable", false);
4427 ExpectBoolean("undetectable===undefined", false);
4428 ExpectBoolean("undefined===undetectable", false);
4429 ExpectBoolean("undetectable===undetectable", true);
4433 TEST(UndetectableOptimized) {
4434 i::FLAG_allow_natives_syntax = true;
4435 v8::HandleScope scope;
4438 Local<String> obj = String::NewUndetectable("foo");
4439 env->Global()->Set(v8_str("undetectable"), obj);
4440 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4443 "function testBranch() {"
4444 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4445 " if (%_IsUndetectableObject(detectable)) throw 2;"
4447 "function testBool() {"
4448 " var b1 = !%_IsUndetectableObject(undetectable);"
4449 " var b2 = %_IsUndetectableObject(detectable);"
4454 "%OptimizeFunctionOnNextCall(testBranch);"
4455 "%OptimizeFunctionOnNextCall(testBool);"
4456 "for (var i = 0; i < 10; i++) {"
4465 template <typename T> static void USE(T) { }
4468 // This test is not intended to be run, just type checked.
4469 static inline void PersistentHandles() {
4470 USE(PersistentHandles);
4471 Local<String> str = v8_str("foo");
4472 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4474 Local<Script> scr = Script::Compile(v8_str(""));
4475 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4477 Local<ObjectTemplate> templ = ObjectTemplate::New();
4478 v8::Persistent<ObjectTemplate> p_templ =
4479 v8::Persistent<ObjectTemplate>::New(templ);
4484 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4485 ApiTestFuzzer::Fuzz();
4486 return v8::Undefined();
4490 THREADED_TEST(GlobalObjectTemplate) {
4491 v8::HandleScope handle_scope;
4492 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4493 global_template->Set(v8_str("JSNI_Log"),
4494 v8::FunctionTemplate::New(HandleLogDelegator));
4495 v8::Persistent<Context> context = Context::New(0, global_template);
4496 Context::Scope context_scope(context);
4497 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4502 static const char* kSimpleExtensionSource =
4508 THREADED_TEST(SimpleExtensions) {
4509 v8::HandleScope handle_scope;
4510 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4511 const char* extension_names[] = { "simpletest" };
4512 v8::ExtensionConfiguration extensions(1, extension_names);
4513 v8::Handle<Context> context = Context::New(&extensions);
4514 Context::Scope lock(context);
4515 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4516 CHECK_EQ(result, v8::Integer::New(4));
4520 static const char* kEmbeddedExtensionSource =
4521 "function Ret54321(){return 54321;}~~@@$"
4522 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4523 static const int kEmbeddedExtensionSourceValidLen = 34;
4526 THREADED_TEST(ExtensionMissingSourceLength) {
4527 v8::HandleScope handle_scope;
4528 v8::RegisterExtension(new Extension("srclentest_fail",
4529 kEmbeddedExtensionSource));
4530 const char* extension_names[] = { "srclentest_fail" };
4531 v8::ExtensionConfiguration extensions(1, extension_names);
4532 v8::Handle<Context> context = Context::New(&extensions);
4533 CHECK_EQ(0, *context);
4537 THREADED_TEST(ExtensionWithSourceLength) {
4538 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4539 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4540 v8::HandleScope handle_scope;
4541 i::ScopedVector<char> extension_name(32);
4542 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4543 v8::RegisterExtension(new Extension(extension_name.start(),
4544 kEmbeddedExtensionSource, 0, 0,
4546 const char* extension_names[1] = { extension_name.start() };
4547 v8::ExtensionConfiguration extensions(1, extension_names);
4548 v8::Handle<Context> context = Context::New(&extensions);
4549 if (source_len == kEmbeddedExtensionSourceValidLen) {
4550 Context::Scope lock(context);
4551 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4552 CHECK_EQ(v8::Integer::New(54321), result);
4554 // Anything but exactly the right length should fail to compile.
4555 CHECK_EQ(0, *context);
4561 static const char* kEvalExtensionSource1 =
4562 "function UseEval1() {"
4564 " return eval('x');"
4568 static const char* kEvalExtensionSource2 =
4572 " return eval('x');"
4574 " this.UseEval2 = e;"
4578 THREADED_TEST(UseEvalFromExtension) {
4579 v8::HandleScope handle_scope;
4580 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4581 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4582 const char* extension_names[] = { "evaltest1", "evaltest2" };
4583 v8::ExtensionConfiguration extensions(2, extension_names);
4584 v8::Handle<Context> context = Context::New(&extensions);
4585 Context::Scope lock(context);
4586 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4587 CHECK_EQ(result, v8::Integer::New(42));
4588 result = Script::Compile(v8_str("UseEval2()"))->Run();
4589 CHECK_EQ(result, v8::Integer::New(42));
4593 static const char* kWithExtensionSource1 =
4594 "function UseWith1() {"
4596 " with({x:87}) { return x; }"
4601 static const char* kWithExtensionSource2 =
4605 " with ({x:87}) { return x; }"
4607 " this.UseWith2 = e;"
4611 THREADED_TEST(UseWithFromExtension) {
4612 v8::HandleScope handle_scope;
4613 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4614 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4615 const char* extension_names[] = { "withtest1", "withtest2" };
4616 v8::ExtensionConfiguration extensions(2, extension_names);
4617 v8::Handle<Context> context = Context::New(&extensions);
4618 Context::Scope lock(context);
4619 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4620 CHECK_EQ(result, v8::Integer::New(87));
4621 result = Script::Compile(v8_str("UseWith2()"))->Run();
4622 CHECK_EQ(result, v8::Integer::New(87));
4626 THREADED_TEST(AutoExtensions) {
4627 v8::HandleScope handle_scope;
4628 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4629 extension->set_auto_enable(true);
4630 v8::RegisterExtension(extension);
4631 v8::Handle<Context> context = Context::New();
4632 Context::Scope lock(context);
4633 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4634 CHECK_EQ(result, v8::Integer::New(4));
4638 static const char* kSyntaxErrorInExtensionSource =
4642 // Test that a syntax error in an extension does not cause a fatal
4643 // error but results in an empty context.
4644 THREADED_TEST(SyntaxErrorExtensions) {
4645 v8::HandleScope handle_scope;
4646 v8::RegisterExtension(new Extension("syntaxerror",
4647 kSyntaxErrorInExtensionSource));
4648 const char* extension_names[] = { "syntaxerror" };
4649 v8::ExtensionConfiguration extensions(1, extension_names);
4650 v8::Handle<Context> context = Context::New(&extensions);
4651 CHECK(context.IsEmpty());
4655 static const char* kExceptionInExtensionSource =
4659 // Test that an exception when installing an extension does not cause
4660 // a fatal error but results in an empty context.
4661 THREADED_TEST(ExceptionExtensions) {
4662 v8::HandleScope handle_scope;
4663 v8::RegisterExtension(new Extension("exception",
4664 kExceptionInExtensionSource));
4665 const char* extension_names[] = { "exception" };
4666 v8::ExtensionConfiguration extensions(1, extension_names);
4667 v8::Handle<Context> context = Context::New(&extensions);
4668 CHECK(context.IsEmpty());
4672 static const char* kNativeCallInExtensionSource =
4673 "function call_runtime_last_index_of(x) {"
4674 " return %StringLastIndexOf(x, 'bob', 10);"
4678 static const char* kNativeCallTest =
4679 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4681 // Test that a native runtime calls are supported in extensions.
4682 THREADED_TEST(NativeCallInExtensions) {
4683 v8::HandleScope handle_scope;
4684 v8::RegisterExtension(new Extension("nativecall",
4685 kNativeCallInExtensionSource));
4686 const char* extension_names[] = { "nativecall" };
4687 v8::ExtensionConfiguration extensions(1, extension_names);
4688 v8::Handle<Context> context = Context::New(&extensions);
4689 Context::Scope lock(context);
4690 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4691 CHECK_EQ(result, v8::Integer::New(3));
4695 class NativeFunctionExtension : public Extension {
4697 NativeFunctionExtension(const char* name,
4699 v8::InvocationCallback fun = &Echo)
4700 : Extension(name, source),
4703 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4704 v8::Handle<v8::String> name) {
4705 return v8::FunctionTemplate::New(function_);
4708 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4709 if (args.Length() >= 1) return (args[0]);
4710 return v8::Undefined();
4713 v8::InvocationCallback function_;
4717 THREADED_TEST(NativeFunctionDeclaration) {
4718 v8::HandleScope handle_scope;
4719 const char* name = "nativedecl";
4720 v8::RegisterExtension(new NativeFunctionExtension(name,
4721 "native function foo();"));
4722 const char* extension_names[] = { name };
4723 v8::ExtensionConfiguration extensions(1, extension_names);
4724 v8::Handle<Context> context = Context::New(&extensions);
4725 Context::Scope lock(context);
4726 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4727 CHECK_EQ(result, v8::Integer::New(42));
4731 THREADED_TEST(NativeFunctionDeclarationError) {
4732 v8::HandleScope handle_scope;
4733 const char* name = "nativedeclerr";
4734 // Syntax error in extension code.
4735 v8::RegisterExtension(new NativeFunctionExtension(name,
4736 "native\nfunction foo();"));
4737 const char* extension_names[] = { name };
4738 v8::ExtensionConfiguration extensions(1, extension_names);
4739 v8::Handle<Context> context(Context::New(&extensions));
4740 ASSERT(context.IsEmpty());
4743 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4744 v8::HandleScope handle_scope;
4745 const char* name = "nativedeclerresc";
4746 // Syntax error in extension code - escape code in "native" means that
4747 // it's not treated as a keyword.
4748 v8::RegisterExtension(new NativeFunctionExtension(
4750 "nativ\\u0065 function foo();"));
4751 const char* extension_names[] = { name };
4752 v8::ExtensionConfiguration extensions(1, extension_names);
4753 v8::Handle<Context> context(Context::New(&extensions));
4754 ASSERT(context.IsEmpty());
4758 static void CheckDependencies(const char* name, const char* expected) {
4759 v8::HandleScope handle_scope;
4760 v8::ExtensionConfiguration config(1, &name);
4761 LocalContext context(&config);
4762 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4773 THREADED_TEST(ExtensionDependency) {
4774 static const char* kEDeps[] = { "D" };
4775 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4776 static const char* kDDeps[] = { "B", "C" };
4777 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4778 static const char* kBCDeps[] = { "A" };
4779 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4780 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4781 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4782 CheckDependencies("A", "undefinedA");
4783 CheckDependencies("B", "undefinedAB");
4784 CheckDependencies("C", "undefinedAC");
4785 CheckDependencies("D", "undefinedABCD");
4786 CheckDependencies("E", "undefinedABCDE");
4787 v8::HandleScope handle_scope;
4788 static const char* exts[2] = { "C", "E" };
4789 v8::ExtensionConfiguration config(2, exts);
4790 LocalContext context(&config);
4791 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4795 static const char* kExtensionTestScript =
4796 "native function A();"
4797 "native function B();"
4798 "native function C();"
4800 " if (i == 0) return A();"
4801 " if (i == 1) return B();"
4802 " if (i == 2) return C();"
4806 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4807 ApiTestFuzzer::Fuzz();
4808 if (args.IsConstructCall()) {
4809 args.This()->Set(v8_str("data"), args.Data());
4816 class FunctionExtension : public Extension {
4818 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4819 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4820 v8::Handle<String> name);
4824 static int lookup_count = 0;
4825 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4826 v8::Handle<String> name) {
4828 if (name->Equals(v8_str("A"))) {
4829 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4830 } else if (name->Equals(v8_str("B"))) {
4831 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4832 } else if (name->Equals(v8_str("C"))) {
4833 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4835 return v8::Handle<v8::FunctionTemplate>();
4840 THREADED_TEST(FunctionLookup) {
4841 v8::RegisterExtension(new FunctionExtension());
4842 v8::HandleScope handle_scope;
4843 static const char* exts[1] = { "functiontest" };
4844 v8::ExtensionConfiguration config(1, exts);
4845 LocalContext context(&config);
4846 CHECK_EQ(3, lookup_count);
4847 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4848 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4849 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4853 THREADED_TEST(NativeFunctionConstructCall) {
4854 v8::RegisterExtension(new FunctionExtension());
4855 v8::HandleScope handle_scope;
4856 static const char* exts[1] = { "functiontest" };
4857 v8::ExtensionConfiguration config(1, exts);
4858 LocalContext context(&config);
4859 for (int i = 0; i < 10; i++) {
4860 // Run a few times to ensure that allocation of objects doesn't
4861 // change behavior of a constructor function.
4862 CHECK_EQ(v8::Integer::New(8),
4863 Script::Compile(v8_str("(new A()).data"))->Run());
4864 CHECK_EQ(v8::Integer::New(7),
4865 Script::Compile(v8_str("(new B()).data"))->Run());
4866 CHECK_EQ(v8::Integer::New(6),
4867 Script::Compile(v8_str("(new C()).data"))->Run());
4872 static const char* last_location;
4873 static const char* last_message;
4874 void StoringErrorCallback(const char* location, const char* message) {
4875 if (last_location == NULL) {
4876 last_location = location;
4877 last_message = message;
4882 // ErrorReporting creates a circular extensions configuration and
4883 // tests that the fatal error handler gets called. This renders V8
4884 // unusable and therefore this test cannot be run in parallel.
4885 TEST(ErrorReporting) {
4886 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4887 static const char* aDeps[] = { "B" };
4888 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4889 static const char* bDeps[] = { "A" };
4890 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4891 last_location = NULL;
4892 v8::ExtensionConfiguration config(1, bDeps);
4893 v8::Handle<Context> context = Context::New(&config);
4894 CHECK(context.IsEmpty());
4895 CHECK_NE(last_location, NULL);
4899 static const char* js_code_causing_huge_string_flattening =
4901 "for (var i = 0; i < 30; i++) {"
4907 void OOMCallback(const char* location, const char* message) {
4912 TEST(RegexpOutOfMemory) {
4913 // Execute a script that causes out of memory when flattening a string.
4914 v8::HandleScope scope;
4915 v8::V8::SetFatalErrorHandler(OOMCallback);
4916 LocalContext context;
4917 Local<Script> script =
4918 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4919 last_location = NULL;
4920 Local<Value> result(script->Run());
4922 CHECK(false); // Should not return.
4926 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4927 v8::Handle<Value> data) {
4928 CHECK_EQ(v8::Undefined(), data);
4929 CHECK(message->GetScriptResourceName()->IsUndefined());
4930 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4931 message->GetLineNumber();
4932 message->GetSourceLine();
4936 THREADED_TEST(ErrorWithMissingScriptInfo) {
4937 v8::HandleScope scope;
4938 LocalContext context;
4939 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4940 Script::Compile(v8_str("throw Error()"))->Run();
4941 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4945 int global_index = 0;
4949 Snorkel() { index_ = global_index++; }
4961 v8::Handle<Script> getScript() {
4962 if (script_.IsEmpty())
4963 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4964 return Local<Script>(*script_);
4968 static const int kObjectCount = 256;
4970 v8::Persistent<v8::Object> objects_[kObjectCount];
4971 v8::Persistent<Script> script_;
4974 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4975 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4980 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4981 const AccessorInfo& info) {
4983 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4985 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4987 v8::Handle<v8::Object> obj = v8::Object::New();
4988 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4989 if (!prev.IsEmpty()) {
4990 prev->Set(v8_str("next"), obj);
4991 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4992 whammy->objects_[whammy->cursor_].Clear();
4994 whammy->objects_[whammy->cursor_] = global;
4995 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4996 return whammy->getScript()->Run();
4999 THREADED_TEST(WeakReference) {
5000 v8::HandleScope handle_scope;
5001 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
5002 Whammy* whammy = new Whammy();
5003 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5005 v8::External::New(whammy));
5006 const char* extension_list[] = { "v8/gc" };
5007 v8::ExtensionConfiguration extensions(1, extension_list);
5008 v8::Persistent<Context> context = Context::New(&extensions);
5009 Context::Scope context_scope(context);
5011 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5012 context->Global()->Set(v8_str("whammy"), interceptor);
5015 "for (var i = 0; i < 10000; i++) {"
5016 " var obj = whammy.length;"
5017 " if (last) last.next = obj;"
5022 v8::Handle<Value> result = CompileRun(code);
5023 CHECK_EQ(4.0, result->NumberValue());
5029 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5032 *(reinterpret_cast<bool*>(data)) = true;
5036 THREADED_TEST(IndependentWeakHandle) {
5037 v8::Persistent<Context> context = Context::New();
5038 Context::Scope context_scope(context);
5040 v8::Persistent<v8::Object> object_a;
5043 v8::HandleScope handle_scope;
5044 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5047 bool object_a_disposed = false;
5048 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5049 object_a.MarkIndependent();
5050 HEAP->PerformScavenge();
5051 CHECK(object_a_disposed);
5055 static void InvokeScavenge() {
5056 HEAP->PerformScavenge();
5060 static void InvokeMarkSweep() {
5061 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5065 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5068 *(reinterpret_cast<bool*>(data)) = true;
5073 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5076 *(reinterpret_cast<bool*>(data)) = true;
5081 THREADED_TEST(GCFromWeakCallbacks) {
5082 v8::Persistent<Context> context = Context::New();
5083 Context::Scope context_scope(context);
5085 static const int kNumberOfGCTypes = 2;
5086 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5087 {&ForceScavenge, &ForceMarkSweep};
5089 typedef void (*GCInvoker)();
5090 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5092 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5093 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5094 v8::Persistent<v8::Object> object;
5096 v8::HandleScope handle_scope;
5097 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5099 bool disposed = false;
5100 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5101 object.MarkIndependent();
5102 invoke_gc[outer_gc]();
5109 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5111 *(reinterpret_cast<bool*>(data)) = true;
5115 THREADED_TEST(IndependentHandleRevival) {
5116 v8::Persistent<Context> context = Context::New();
5117 Context::Scope context_scope(context);
5119 v8::Persistent<v8::Object> object;
5121 v8::HandleScope handle_scope;
5122 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5123 object->Set(v8_str("x"), v8::Integer::New(1));
5124 v8::Local<String> y_str = v8_str("y");
5125 object->Set(y_str, y_str);
5127 bool revived = false;
5128 object.MakeWeak(&revived, &RevivingCallback);
5129 object.MarkIndependent();
5130 HEAP->PerformScavenge();
5132 HEAP->CollectAllGarbage(true);
5134 v8::HandleScope handle_scope;
5135 v8::Local<String> y_str = v8_str("y");
5136 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5137 CHECK(object->Get(y_str)->Equals(y_str));
5142 v8::Handle<Function> args_fun;
5145 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5146 ApiTestFuzzer::Fuzz();
5147 CHECK_EQ(args_fun, args.Callee());
5148 CHECK_EQ(3, args.Length());
5149 CHECK_EQ(v8::Integer::New(1), args[0]);
5150 CHECK_EQ(v8::Integer::New(2), args[1]);
5151 CHECK_EQ(v8::Integer::New(3), args[2]);
5152 CHECK_EQ(v8::Undefined(), args[3]);
5153 v8::HandleScope scope;
5154 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5155 return v8::Undefined();
5159 THREADED_TEST(Arguments) {
5160 v8::HandleScope scope;
5161 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5162 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5163 LocalContext context(NULL, global);
5164 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5165 v8_compile("f(1, 2, 3)")->Run();
5169 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5170 const AccessorInfo&) {
5171 return v8::Handle<Value>();
5175 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5176 const AccessorInfo&) {
5177 return v8::Handle<Value>();
5181 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5182 const AccessorInfo&) {
5183 if (!name->Equals(v8_str("foo"))) {
5184 return v8::Handle<v8::Boolean>(); // not intercepted
5187 return v8::False(); // intercepted, and don't delete the property
5191 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5193 return v8::Handle<v8::Boolean>(); // not intercepted
5196 return v8::False(); // intercepted, and don't delete the property
5200 THREADED_TEST(Deleter) {
5201 v8::HandleScope scope;
5202 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5203 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5204 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5205 LocalContext context;
5206 context->Global()->Set(v8_str("k"), obj->NewInstance());
5212 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5213 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5215 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5216 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5218 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5219 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5221 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5222 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5226 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5227 ApiTestFuzzer::Fuzz();
5228 if (name->Equals(v8_str("foo")) ||
5229 name->Equals(v8_str("bar")) ||
5230 name->Equals(v8_str("baz"))) {
5231 return v8::Undefined();
5233 return v8::Handle<Value>();
5237 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5238 ApiTestFuzzer::Fuzz();
5239 if (index == 0 || index == 1) return v8::Undefined();
5240 return v8::Handle<Value>();
5244 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5245 ApiTestFuzzer::Fuzz();
5246 v8::Handle<v8::Array> result = v8::Array::New(3);
5247 result->Set(v8::Integer::New(0), v8_str("foo"));
5248 result->Set(v8::Integer::New(1), v8_str("bar"));
5249 result->Set(v8::Integer::New(2), v8_str("baz"));
5254 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5255 ApiTestFuzzer::Fuzz();
5256 v8::Handle<v8::Array> result = v8::Array::New(2);
5257 result->Set(v8::Integer::New(0), v8_str("0"));
5258 result->Set(v8::Integer::New(1), v8_str("1"));
5263 THREADED_TEST(Enumerators) {
5264 v8::HandleScope scope;
5265 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5266 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5267 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5268 LocalContext context;
5269 context->Global()->Set(v8_str("k"), obj->NewInstance());
5270 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5275 "k[4294967295] = 0;"
5277 "k[4294967296] = 0;"
5281 "k[30000000000] = 0;"
5284 "for (var prop in k) {"
5285 " result.push(prop);"
5288 // Check that we get all the property names returned including the
5289 // ones from the enumerators in the right order: indexed properties
5290 // in numerical order, indexed interceptor properties, named
5291 // properties in insertion order, named interceptor properties.
5292 // This order is not mandated by the spec, so this test is just
5293 // documenting our behavior.
5294 CHECK_EQ(17, result->Length());
5295 // Indexed properties in numerical order.
5296 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5297 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5298 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5299 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5300 // Indexed interceptor properties in the order they are returned
5301 // from the enumerator interceptor.
5302 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5303 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5304 // Named properties in insertion order.
5305 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5306 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5307 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5308 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5309 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5310 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5311 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5312 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5313 // Named interceptor properties.
5314 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5315 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5316 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5321 int p_getter_count2;
5324 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5325 ApiTestFuzzer::Fuzz();
5327 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5328 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5329 if (name->Equals(v8_str("p1"))) {
5330 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5331 } else if (name->Equals(v8_str("p2"))) {
5332 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5333 } else if (name->Equals(v8_str("p3"))) {
5334 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5335 } else if (name->Equals(v8_str("p4"))) {
5336 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5338 return v8::Undefined();
5342 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5343 ApiTestFuzzer::Fuzz();
5344 LocalContext context;
5345 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5347 "o1.__proto__ = { };"
5348 "var o2 = { __proto__: o1 };"
5349 "var o3 = { __proto__: o2 };"
5350 "var o4 = { __proto__: o3 };"
5351 "for (var i = 0; i < 10; i++) o4.p4;"
5352 "for (var i = 0; i < 10; i++) o3.p3;"
5353 "for (var i = 0; i < 10; i++) o2.p2;"
5354 "for (var i = 0; i < 10; i++) o1.p1;");
5358 static v8::Handle<Value> PGetter2(Local<String> name,
5359 const AccessorInfo& info) {
5360 ApiTestFuzzer::Fuzz();
5362 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5363 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5364 if (name->Equals(v8_str("p1"))) {
5365 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5366 } else if (name->Equals(v8_str("p2"))) {
5367 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5368 } else if (name->Equals(v8_str("p3"))) {
5369 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5370 } else if (name->Equals(v8_str("p4"))) {
5371 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5373 return v8::Undefined();
5377 THREADED_TEST(GetterHolders) {
5378 v8::HandleScope scope;
5379 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5380 obj->SetAccessor(v8_str("p1"), PGetter);
5381 obj->SetAccessor(v8_str("p2"), PGetter);
5382 obj->SetAccessor(v8_str("p3"), PGetter);
5383 obj->SetAccessor(v8_str("p4"), PGetter);
5386 CHECK_EQ(40, p_getter_count);
5390 THREADED_TEST(PreInterceptorHolders) {
5391 v8::HandleScope scope;
5392 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5393 obj->SetNamedPropertyHandler(PGetter2);
5394 p_getter_count2 = 0;
5396 CHECK_EQ(40, p_getter_count2);
5400 THREADED_TEST(ObjectInstantiation) {
5401 v8::HandleScope scope;
5402 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5403 templ->SetAccessor(v8_str("t"), PGetter2);
5404 LocalContext context;
5405 context->Global()->Set(v8_str("o"), templ->NewInstance());
5406 for (int i = 0; i < 100; i++) {
5407 v8::HandleScope inner_scope;
5408 v8::Handle<v8::Object> obj = templ->NewInstance();
5409 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5410 context->Global()->Set(v8_str("o2"), obj);
5411 v8::Handle<Value> value =
5412 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5413 CHECK_EQ(v8::True(), value);
5414 context->Global()->Set(v8_str("o"), obj);
5419 static int StrCmp16(uint16_t* a, uint16_t* b) {
5421 if (*a == 0 && *b == 0) return 0;
5422 if (*a != *b) return 0 + *a - *b;
5429 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5431 if (n-- == 0) return 0;
5432 if (*a == 0 && *b == 0) return 0;
5433 if (*a != *b) return 0 + *a - *b;
5440 THREADED_TEST(StringWrite) {
5441 LocalContext context;
5442 v8::HandleScope scope;
5443 v8::Handle<String> str = v8_str("abcde");
5444 // abc<Icelandic eth><Unicode snowman>.
5445 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5446 const int kStride = 4; // Must match stride in for loops in JS below.
5449 "for (var i = 0; i < 0xd800; i += 4) {"
5450 " left = left + String.fromCharCode(i);"
5454 "for (var i = 0; i < 0xd800; i += 4) {"
5455 " right = String.fromCharCode(i) + right;"
5457 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5458 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5459 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5461 CHECK_EQ(5, str2->Length());
5462 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5463 CHECK_EQ(0xd800 / kStride, right_tree->Length());
5466 char utf8buf[0xd800 * 3];
5471 memset(utf8buf, 0x1, 1000);
5472 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5474 CHECK_EQ(5, charlen);
5475 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5477 memset(utf8buf, 0x1, 1000);
5478 len = str2->WriteUtf8(utf8buf, 8, &charlen);
5480 CHECK_EQ(5, charlen);
5481 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5483 memset(utf8buf, 0x1, 1000);
5484 len = str2->WriteUtf8(utf8buf, 7, &charlen);
5486 CHECK_EQ(4, charlen);
5487 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5489 memset(utf8buf, 0x1, 1000);
5490 len = str2->WriteUtf8(utf8buf, 6, &charlen);
5492 CHECK_EQ(4, charlen);
5493 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5495 memset(utf8buf, 0x1, 1000);
5496 len = str2->WriteUtf8(utf8buf, 5, &charlen);
5498 CHECK_EQ(4, charlen);
5499 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5501 memset(utf8buf, 0x1, 1000);
5502 len = str2->WriteUtf8(utf8buf, 4, &charlen);
5504 CHECK_EQ(3, charlen);
5505 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5507 memset(utf8buf, 0x1, 1000);
5508 len = str2->WriteUtf8(utf8buf, 3, &charlen);
5510 CHECK_EQ(3, charlen);
5511 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5513 memset(utf8buf, 0x1, 1000);
5514 len = str2->WriteUtf8(utf8buf, 2, &charlen);
5516 CHECK_EQ(2, charlen);
5517 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5519 memset(utf8buf, 0x1, sizeof(utf8buf));
5520 len = left_tree->Utf8Length();
5522 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5523 CHECK_EQ(utf8_expected, len);
5524 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5525 CHECK_EQ(utf8_expected, len);
5526 CHECK_EQ(0xd800 / kStride, charlen);
5527 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5528 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5529 CHECK_EQ(0xc0 - kStride,
5530 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5531 CHECK_EQ(1, utf8buf[utf8_expected]);
5533 memset(utf8buf, 0x1, sizeof(utf8buf));
5534 len = right_tree->Utf8Length();
5535 CHECK_EQ(utf8_expected, len);
5536 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5537 CHECK_EQ(utf8_expected, len);
5538 CHECK_EQ(0xd800 / kStride, charlen);
5539 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5540 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5541 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5542 CHECK_EQ(1, utf8buf[utf8_expected]);
5544 memset(buf, 0x1, sizeof(buf));
5545 memset(wbuf, 0x1, sizeof(wbuf));
5546 len = str->WriteAscii(buf);
5548 len = str->Write(wbuf);
5550 CHECK_EQ(0, strcmp("abcde", buf));
5551 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5552 CHECK_EQ(0, StrCmp16(answer1, wbuf));
5554 memset(buf, 0x1, sizeof(buf));
5555 memset(wbuf, 0x1, sizeof(wbuf));
5556 len = str->WriteAscii(buf, 0, 4);
5558 len = str->Write(wbuf, 0, 4);
5560 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5561 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5562 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5564 memset(buf, 0x1, sizeof(buf));
5565 memset(wbuf, 0x1, sizeof(wbuf));
5566 len = str->WriteAscii(buf, 0, 5);
5568 len = str->Write(wbuf, 0, 5);
5570 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5571 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5572 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5574 memset(buf, 0x1, sizeof(buf));
5575 memset(wbuf, 0x1, sizeof(wbuf));
5576 len = str->WriteAscii(buf, 0, 6);
5578 len = str->Write(wbuf, 0, 6);
5580 CHECK_EQ(0, strcmp("abcde", buf));
5581 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5582 CHECK_EQ(0, StrCmp16(answer4, wbuf));
5584 memset(buf, 0x1, sizeof(buf));
5585 memset(wbuf, 0x1, sizeof(wbuf));
5586 len = str->WriteAscii(buf, 4, -1);
5588 len = str->Write(wbuf, 4, -1);
5590 CHECK_EQ(0, strcmp("e", buf));
5591 uint16_t answer5[] = {'e', '\0'};
5592 CHECK_EQ(0, StrCmp16(answer5, wbuf));
5594 memset(buf, 0x1, sizeof(buf));
5595 memset(wbuf, 0x1, sizeof(wbuf));
5596 len = str->WriteAscii(buf, 4, 6);
5598 len = str->Write(wbuf, 4, 6);
5600 CHECK_EQ(0, strcmp("e", buf));
5601 CHECK_EQ(0, StrCmp16(answer5, wbuf));
5603 memset(buf, 0x1, sizeof(buf));
5604 memset(wbuf, 0x1, sizeof(wbuf));
5605 len = str->WriteAscii(buf, 4, 1);
5607 len = str->Write(wbuf, 4, 1);
5609 CHECK_EQ(0, strncmp("e\1", buf, 2));
5610 uint16_t answer6[] = {'e', 0x101};
5611 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5613 memset(buf, 0x1, sizeof(buf));
5614 memset(wbuf, 0x1, sizeof(wbuf));
5615 len = str->WriteAscii(buf, 3, 1);
5617 len = str->Write(wbuf, 3, 1);
5619 CHECK_EQ(0, strncmp("d\1", buf, 2));
5620 uint16_t answer7[] = {'d', 0x101};
5621 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5623 memset(wbuf, 0x1, sizeof(wbuf));
5625 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5627 CHECK_EQ('X', wbuf[5]);
5628 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5629 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5630 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5631 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5633 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5635 memset(buf, 0x1, sizeof(buf));
5637 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5639 CHECK_EQ('X', buf[5]);
5640 CHECK_EQ(0, strncmp("abcde", buf, 5));
5641 CHECK_NE(0, strcmp("abcde", buf));
5643 CHECK_EQ(0, strcmp("abcde", buf));
5645 memset(utf8buf, 0x1, sizeof(utf8buf));
5647 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5648 String::NO_NULL_TERMINATION);
5650 CHECK_EQ('X', utf8buf[8]);
5651 CHECK_EQ(5, charlen);
5652 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5653 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5655 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5659 THREADED_TEST(ToArrayIndex) {
5660 v8::HandleScope scope;
5661 LocalContext context;
5663 v8::Handle<String> str = v8_str("42");
5664 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5665 CHECK(!index.IsEmpty());
5666 CHECK_EQ(42.0, index->Uint32Value());
5667 str = v8_str("42asdf");
5668 index = str->ToArrayIndex();
5669 CHECK(index.IsEmpty());
5670 str = v8_str("-42");
5671 index = str->ToArrayIndex();
5672 CHECK(index.IsEmpty());
5673 str = v8_str("4294967295");
5674 index = str->ToArrayIndex();
5675 CHECK(!index.IsEmpty());
5676 CHECK_EQ(4294967295.0, index->Uint32Value());
5677 v8::Handle<v8::Number> num = v8::Number::New(1);
5678 index = num->ToArrayIndex();
5679 CHECK(!index.IsEmpty());
5680 CHECK_EQ(1.0, index->Uint32Value());
5681 num = v8::Number::New(-1);
5682 index = num->ToArrayIndex();
5683 CHECK(index.IsEmpty());
5684 v8::Handle<v8::Object> obj = v8::Object::New();
5685 index = obj->ToArrayIndex();
5686 CHECK(index.IsEmpty());
5690 THREADED_TEST(ErrorConstruction) {
5691 v8::HandleScope scope;
5692 LocalContext context;
5694 v8::Handle<String> foo = v8_str("foo");
5695 v8::Handle<String> message = v8_str("message");
5696 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5697 CHECK(range_error->IsObject());
5698 v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
5699 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
5700 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5701 CHECK(reference_error->IsObject());
5702 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
5703 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5704 CHECK(syntax_error->IsObject());
5705 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
5706 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5707 CHECK(type_error->IsObject());
5708 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
5709 v8::Handle<Value> error = v8::Exception::Error(foo);
5710 CHECK(error->IsObject());
5711 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
5715 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5716 ApiTestFuzzer::Fuzz();
5721 static void YSetter(Local<String> name,
5723 const AccessorInfo& info) {
5724 if (info.This()->Has(name)) {
5725 info.This()->Delete(name);
5727 info.This()->Set(name, value);
5731 THREADED_TEST(DeleteAccessor) {
5732 v8::HandleScope scope;
5733 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5734 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5735 LocalContext context;
5736 v8::Handle<v8::Object> holder = obj->NewInstance();
5737 context->Global()->Set(v8_str("holder"), holder);
5738 v8::Handle<Value> result = CompileRun(
5739 "holder.y = 11; holder.y = 12; holder.y");
5740 CHECK_EQ(12, result->Uint32Value());
5744 THREADED_TEST(TypeSwitch) {
5745 v8::HandleScope scope;
5746 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5747 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5748 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5749 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5750 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5751 LocalContext context;
5752 v8::Handle<v8::Object> obj0 = v8::Object::New();
5753 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5754 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5755 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5756 for (int i = 0; i < 10; i++) {
5757 CHECK_EQ(0, type_switch->match(obj0));
5758 CHECK_EQ(1, type_switch->match(obj1));
5759 CHECK_EQ(2, type_switch->match(obj2));
5760 CHECK_EQ(3, type_switch->match(obj3));
5761 CHECK_EQ(3, type_switch->match(obj3));
5762 CHECK_EQ(2, type_switch->match(obj2));
5763 CHECK_EQ(1, type_switch->match(obj1));
5764 CHECK_EQ(0, type_switch->match(obj0));
5769 // For use within the TestSecurityHandler() test.
5770 static bool g_security_callback_result = false;
5771 static bool NamedSecurityTestCallback(Local<v8::Object> global,
5773 v8::AccessType type,
5774 Local<Value> data) {
5775 // Always allow read access.
5776 if (type == v8::ACCESS_GET)
5779 // Sometimes allow other access.
5780 return g_security_callback_result;
5784 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5786 v8::AccessType type,
5787 Local<Value> data) {
5788 // Always allow read access.
5789 if (type == v8::ACCESS_GET)
5792 // Sometimes allow other access.
5793 return g_security_callback_result;
5797 static int trouble_nesting = 0;
5798 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5799 ApiTestFuzzer::Fuzz();
5802 // Call a JS function that throws an uncaught exception.
5803 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5804 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5805 arg_this->Get(v8_str("trouble_callee")) :
5806 arg_this->Get(v8_str("trouble_caller"));
5807 CHECK(trouble_callee->IsFunction());
5808 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5812 static int report_count = 0;
5813 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5814 v8::Handle<Value>) {
5819 // Counts uncaught exceptions, but other tests running in parallel
5820 // also have uncaught exceptions.
5821 TEST(ApiUncaughtException) {
5823 v8::HandleScope scope;
5825 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5827 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5828 v8::Local<v8::Object> global = env->Global();
5829 global->Set(v8_str("trouble"), fun->GetFunction());
5831 Script::Compile(v8_str("function trouble_callee() {"
5835 "function trouble_caller() {"
5838 Local<Value> trouble = global->Get(v8_str("trouble"));
5839 CHECK(trouble->IsFunction());
5840 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5841 CHECK(trouble_callee->IsFunction());
5842 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5843 CHECK(trouble_caller->IsFunction());
5844 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5845 CHECK_EQ(1, report_count);
5846 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5849 static const char* script_resource_name = "ExceptionInNativeScript.js";
5850 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5851 v8::Handle<Value>) {
5852 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5853 CHECK(!name_val.IsEmpty() && name_val->IsString());
5854 v8::String::AsciiValue name(message->GetScriptResourceName());
5855 CHECK_EQ(script_resource_name, *name);
5856 CHECK_EQ(3, message->GetLineNumber());
5857 v8::String::AsciiValue source_line(message->GetSourceLine());
5858 CHECK_EQ(" new o.foo();", *source_line);
5861 TEST(ExceptionInNativeScript) {
5862 v8::HandleScope scope;
5864 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5866 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5867 v8::Local<v8::Object> global = env->Global();
5868 global->Set(v8_str("trouble"), fun->GetFunction());
5870 Script::Compile(v8_str("function trouble() {\n"
5873 "};"), v8::String::New(script_resource_name))->Run();
5874 Local<Value> trouble = global->Get(v8_str("trouble"));
5875 CHECK(trouble->IsFunction());
5876 Function::Cast(*trouble)->Call(global, 0, NULL);
5877 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5881 TEST(CompilationErrorUsingTryCatchHandler) {
5882 v8::HandleScope scope;
5884 v8::TryCatch try_catch;
5885 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5886 CHECK_NE(NULL, *try_catch.Exception());
5887 CHECK(try_catch.HasCaught());
5891 TEST(TryCatchFinallyUsingTryCatchHandler) {
5892 v8::HandleScope scope;
5894 v8::TryCatch try_catch;
5895 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5896 CHECK(!try_catch.HasCaught());
5897 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5898 CHECK(try_catch.HasCaught());
5900 Script::Compile(v8_str("(function() {"
5901 "try { throw ''; } finally { return; }"
5903 CHECK(!try_catch.HasCaught());
5904 Script::Compile(v8_str("(function()"
5905 " { try { throw ''; } finally { throw 0; }"
5907 CHECK(try_catch.HasCaught());
5911 // SecurityHandler can't be run twice
5912 TEST(SecurityHandler) {
5913 v8::HandleScope scope0;
5914 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5915 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5916 IndexedSecurityTestCallback);
5917 // Create an environment
5918 v8::Persistent<Context> context0 =
5919 Context::New(NULL, global_template);
5922 v8::Handle<v8::Object> global0 = context0->Global();
5923 v8::Handle<Script> script0 = v8_compile("foo = 111");
5925 global0->Set(v8_str("0"), v8_num(999));
5926 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5927 CHECK_EQ(111, foo0->Int32Value());
5928 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5929 CHECK_EQ(999, z0->Int32Value());
5931 // Create another environment, should fail security checks.
5932 v8::HandleScope scope1;
5934 v8::Persistent<Context> context1 =
5935 Context::New(NULL, global_template);
5938 v8::Handle<v8::Object> global1 = context1->Global();
5939 global1->Set(v8_str("othercontext"), global0);
5940 // This set will fail the security check.
5941 v8::Handle<Script> script1 =
5942 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5944 // This read will pass the security check.
5945 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5946 CHECK_EQ(111, foo1->Int32Value());
5947 // This read will pass the security check.
5948 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5949 CHECK_EQ(999, z1->Int32Value());
5951 // Create another environment, should pass security checks.
5952 { g_security_callback_result = true; // allow security handler to pass.
5953 v8::HandleScope scope2;
5954 LocalContext context2;
5955 v8::Handle<v8::Object> global2 = context2->Global();
5956 global2->Set(v8_str("othercontext"), global0);
5957 v8::Handle<Script> script2 =
5958 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5960 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5961 CHECK_EQ(333, foo2->Int32Value());
5962 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5963 CHECK_EQ(888, z2->Int32Value());
5974 THREADED_TEST(SecurityChecks) {
5975 v8::HandleScope handle_scope;
5977 v8::Persistent<Context> env2 = Context::New();
5979 Local<Value> foo = v8_str("foo");
5980 Local<Value> bar = v8_str("bar");
5982 // Set to the same domain.
5983 env1->SetSecurityToken(foo);
5985 // Create a function in env1.
5986 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5987 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5988 CHECK(spy->IsFunction());
5990 // Create another function accessing global objects.
5991 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5992 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5993 CHECK(spy2->IsFunction());
5995 // Switch to env2 in the same domain and invoke spy on env2.
5997 env2->SetSecurityToken(foo);
5999 Context::Scope scope_env2(env2);
6000 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6001 CHECK(result->IsFunction());
6005 env2->SetSecurityToken(bar);
6006 Context::Scope scope_env2(env2);
6008 // Call cross_domain_call, it should throw an exception
6009 v8::TryCatch try_catch;
6010 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6011 CHECK(try_catch.HasCaught());
6018 // Regression test case for issue 1183439.
6019 THREADED_TEST(SecurityChecksForPrototypeChain) {
6020 v8::HandleScope scope;
6021 LocalContext current;
6022 v8::Persistent<Context> other = Context::New();
6024 // Change context to be able to get to the Object function in the
6025 // other context without hitting the security checks.
6026 v8::Local<Value> other_object;
6027 { Context::Scope scope(other);
6028 other_object = other->Global()->Get(v8_str("Object"));
6029 other->Global()->Set(v8_num(42), v8_num(87));
6032 current->Global()->Set(v8_str("other"), other->Global());
6033 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6035 // Make sure the security check fails here and we get an undefined
6036 // result instead of getting the Object function. Repeat in a loop
6037 // to make sure to exercise the IC code.
6038 v8::Local<Script> access_other0 = v8_compile("other.Object");
6039 v8::Local<Script> access_other1 = v8_compile("other[42]");
6040 for (int i = 0; i < 5; i++) {
6041 CHECK(!access_other0->Run()->Equals(other_object));
6042 CHECK(access_other0->Run()->IsUndefined());
6043 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6044 CHECK(access_other1->Run()->IsUndefined());
6047 // Create an object that has 'other' in its prototype chain and make
6048 // sure we cannot access the Object function indirectly through
6049 // that. Repeat in a loop to make sure to exercise the IC code.
6050 v8_compile("function F() { };"
6051 "F.prototype = other;"
6052 "var f = new F();")->Run();
6053 v8::Local<Script> access_f0 = v8_compile("f.Object");
6054 v8::Local<Script> access_f1 = v8_compile("f[42]");
6055 for (int j = 0; j < 5; j++) {
6056 CHECK(!access_f0->Run()->Equals(other_object));
6057 CHECK(access_f0->Run()->IsUndefined());
6058 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6059 CHECK(access_f1->Run()->IsUndefined());
6062 // Now it gets hairy: Set the prototype for the other global object
6063 // to be the current global object. The prototype chain for 'f' now
6064 // goes through 'other' but ends up in the current global object.
6065 { Context::Scope scope(other);
6066 other->Global()->Set(v8_str("__proto__"), current->Global());
6068 // Set a named and an index property on the current global
6069 // object. To force the lookup to go through the other global object,
6070 // the properties must not exist in the other global object.
6071 current->Global()->Set(v8_str("foo"), v8_num(100));
6072 current->Global()->Set(v8_num(99), v8_num(101));
6073 // Try to read the properties from f and make sure that the access
6074 // gets stopped by the security checks on the other global object.
6075 Local<Script> access_f2 = v8_compile("f.foo");
6076 Local<Script> access_f3 = v8_compile("f[99]");
6077 for (int k = 0; k < 5; k++) {
6078 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6079 CHECK(access_f2->Run()->IsUndefined());
6080 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6081 CHECK(access_f3->Run()->IsUndefined());
6087 THREADED_TEST(CrossDomainDelete) {
6088 v8::HandleScope handle_scope;
6090 v8::Persistent<Context> env2 = Context::New();
6092 Local<Value> foo = v8_str("foo");
6093 Local<Value> bar = v8_str("bar");
6095 // Set to the same domain.
6096 env1->SetSecurityToken(foo);
6097 env2->SetSecurityToken(foo);
6099 env1->Global()->Set(v8_str("prop"), v8_num(3));
6100 env2->Global()->Set(v8_str("env1"), env1->Global());
6102 // Change env2 to a different domain and delete env1.prop.
6103 env2->SetSecurityToken(bar);
6105 Context::Scope scope_env2(env2);
6106 Local<Value> result =
6107 Script::Compile(v8_str("delete env1.prop"))->Run();
6108 CHECK(result->IsFalse());
6111 // Check that env1.prop still exists.
6112 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6113 CHECK(v->IsNumber());
6114 CHECK_EQ(3, v->Int32Value());
6120 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6121 v8::HandleScope handle_scope;
6123 v8::Persistent<Context> env2 = Context::New();
6125 Local<Value> foo = v8_str("foo");
6126 Local<Value> bar = v8_str("bar");
6128 // Set to the same domain.
6129 env1->SetSecurityToken(foo);
6130 env2->SetSecurityToken(foo);
6132 env1->Global()->Set(v8_str("prop"), v8_num(3));
6133 env2->Global()->Set(v8_str("env1"), env1->Global());
6135 // env1.prop is enumerable in env2.
6136 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6138 Context::Scope scope_env2(env2);
6139 Local<Value> result = Script::Compile(test)->Run();
6140 CHECK(result->IsTrue());
6143 // Change env2 to a different domain and test again.
6144 env2->SetSecurityToken(bar);
6146 Context::Scope scope_env2(env2);
6147 Local<Value> result = Script::Compile(test)->Run();
6148 CHECK(result->IsFalse());
6155 THREADED_TEST(CrossDomainForIn) {
6156 v8::HandleScope handle_scope;
6158 v8::Persistent<Context> env2 = Context::New();
6160 Local<Value> foo = v8_str("foo");
6161 Local<Value> bar = v8_str("bar");
6163 // Set to the same domain.
6164 env1->SetSecurityToken(foo);
6165 env2->SetSecurityToken(foo);
6167 env1->Global()->Set(v8_str("prop"), v8_num(3));
6168 env2->Global()->Set(v8_str("env1"), env1->Global());
6170 // Change env2 to a different domain and set env1's global object
6171 // as the __proto__ of an object in env2 and enumerate properties
6172 // in for-in. It shouldn't enumerate properties on env1's global
6174 env2->SetSecurityToken(bar);
6176 Context::Scope scope_env2(env2);
6177 Local<Value> result =
6178 CompileRun("(function(){var obj = {'__proto__':env1};"
6179 "for (var p in obj)"
6180 " if (p == 'prop') return false;"
6181 "return true;})()");
6182 CHECK(result->IsTrue());
6188 TEST(ContextDetachGlobal) {
6189 v8::HandleScope handle_scope;
6191 v8::Persistent<Context> env2 = Context::New();
6193 Local<v8::Object> global1 = env1->Global();
6195 Local<Value> foo = v8_str("foo");
6197 // Set to the same domain.
6198 env1->SetSecurityToken(foo);
6199 env2->SetSecurityToken(foo);
6204 // Create a function in env2 and add a reference to it in env1.
6205 Local<v8::Object> global2 = env2->Global();
6206 global2->Set(v8_str("prop"), v8::Integer::New(1));
6207 CompileRun("function getProp() {return prop;}");
6209 env1->Global()->Set(v8_str("getProp"),
6210 global2->Get(v8_str("getProp")));
6212 // Detach env2's global, and reuse the global object of env2
6214 env2->DetachGlobal();
6215 // env2 has a new global object.
6216 CHECK(!env2->Global()->Equals(global2));
6218 v8::Persistent<Context> env3 =
6219 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6220 env3->SetSecurityToken(v8_str("bar"));
6223 Local<v8::Object> global3 = env3->Global();
6224 CHECK_EQ(global2, global3);
6225 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6226 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6227 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6228 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6231 // Call getProp in env1, and it should return the value 1
6233 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6234 CHECK(get_prop->IsFunction());
6235 v8::TryCatch try_catch;
6236 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6237 CHECK(!try_catch.HasCaught());
6238 CHECK_EQ(1, r->Int32Value());
6241 // Check that env3 is not accessible from env1
6243 Local<Value> r = global3->Get(v8_str("prop2"));
6244 CHECK(r->IsUndefined());
6252 TEST(DetachAndReattachGlobal) {
6253 v8::HandleScope scope;
6256 // Create second environment.
6257 v8::Persistent<Context> env2 = Context::New();
6259 Local<Value> foo = v8_str("foo");
6261 // Set same security token for env1 and env2.
6262 env1->SetSecurityToken(foo);
6263 env2->SetSecurityToken(foo);
6265 // Create a property on the global object in env2.
6267 v8::Context::Scope scope(env2);
6268 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6271 // Create a reference to env2 global from env1 global.
6272 env1->Global()->Set(v8_str("other"), env2->Global());
6274 // Check that we have access to other.p in env2 from env1.
6275 Local<Value> result = CompileRun("other.p");
6276 CHECK(result->IsInt32());
6277 CHECK_EQ(42, result->Int32Value());
6279 // Hold on to global from env2 and detach global from env2.
6280 Local<v8::Object> global2 = env2->Global();
6281 env2->DetachGlobal();
6283 // Check that the global has been detached. No other.p property can
6285 result = CompileRun("other.p");
6286 CHECK(result->IsUndefined());
6288 // Reuse global2 for env3.
6289 v8::Persistent<Context> env3 =
6290 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6291 CHECK_EQ(global2, env3->Global());
6293 // Start by using the same security token for env3 as for env1 and env2.
6294 env3->SetSecurityToken(foo);
6296 // Create a property on the global object in env3.
6298 v8::Context::Scope scope(env3);
6299 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6302 // Check that other.p is now the property in env3 and that we have access.
6303 result = CompileRun("other.p");
6304 CHECK(result->IsInt32());
6305 CHECK_EQ(24, result->Int32Value());
6307 // Change security token for env3 to something different from env1 and env2.
6308 env3->SetSecurityToken(v8_str("bar"));
6310 // Check that we do not have access to other.p in env1. |other| is now
6311 // the global object for env3 which has a different security token,
6312 // so access should be blocked.
6313 result = CompileRun("other.p");
6314 CHECK(result->IsUndefined());
6316 // Detach the global for env3 and reattach it to env2.
6317 env3->DetachGlobal();
6318 env2->ReattachGlobal(global2);
6320 // Check that we have access to other.p again in env1. |other| is now
6321 // the global object for env2 which has the same security token as env1.
6322 result = CompileRun("other.p");
6323 CHECK(result->IsInt32());
6324 CHECK_EQ(42, result->Int32Value());
6331 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6332 static bool NamedAccessBlocker(Local<v8::Object> global,
6334 v8::AccessType type,
6335 Local<Value> data) {
6336 return Context::GetCurrent()->Global()->Equals(global) ||
6337 allowed_access_type[type];
6341 static bool IndexedAccessBlocker(Local<v8::Object> global,
6343 v8::AccessType type,
6344 Local<Value> data) {
6345 return Context::GetCurrent()->Global()->Equals(global) ||
6346 allowed_access_type[type];
6350 static int g_echo_value = -1;
6351 static v8::Handle<Value> EchoGetter(Local<String> name,
6352 const AccessorInfo& info) {
6353 return v8_num(g_echo_value);
6357 static void EchoSetter(Local<String> name,
6359 const AccessorInfo&) {
6360 if (value->IsNumber())
6361 g_echo_value = value->Int32Value();
6365 static v8::Handle<Value> UnreachableGetter(Local<String> name,
6366 const AccessorInfo& info) {
6367 CHECK(false); // This function should not be called..
6368 return v8::Undefined();
6372 static void UnreachableSetter(Local<String>, Local<Value>,
6373 const AccessorInfo&) {
6374 CHECK(false); // This function should nto be called.
6378 TEST(AccessControl) {
6379 v8::HandleScope handle_scope;
6380 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6382 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6383 IndexedAccessBlocker);
6385 // Add an accessor accessible by cross-domain JS code.
6386 global_template->SetAccessor(
6387 v8_str("accessible_prop"),
6388 EchoGetter, EchoSetter,
6389 v8::Handle<Value>(),
6390 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6392 // Add an accessor that is not accessible by cross-domain JS code.
6393 global_template->SetAccessor(v8_str("blocked_prop"),
6394 UnreachableGetter, UnreachableSetter,
6395 v8::Handle<Value>(),
6398 // Create an environment
6399 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6402 v8::Handle<v8::Object> global0 = context0->Global();
6404 // Define a property with JS getter and setter.
6406 "function getter() { return 'getter'; };\n"
6407 "function setter() { return 'setter'; }\n"
6408 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6410 Local<Value> getter = global0->Get(v8_str("getter"));
6411 Local<Value> setter = global0->Get(v8_str("setter"));
6413 // And define normal element.
6414 global0->Set(239, v8_str("239"));
6416 // Define an element with JS getter and setter.
6418 "function el_getter() { return 'el_getter'; };\n"
6419 "function el_setter() { return 'el_setter'; };\n"
6420 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6422 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6423 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6425 v8::HandleScope scope1;
6427 v8::Persistent<Context> context1 = Context::New();
6430 v8::Handle<v8::Object> global1 = context1->Global();
6431 global1->Set(v8_str("other"), global0);
6433 // Access blocked property.
6434 CompileRun("other.blocked_prop = 1");
6436 ExpectUndefined("other.blocked_prop");
6438 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6439 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6441 // Enable ACCESS_HAS
6442 allowed_access_type[v8::ACCESS_HAS] = true;
6443 ExpectUndefined("other.blocked_prop");
6444 // ... and now we can get the descriptor...
6446 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6447 // ... and enumerate the property.
6448 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6449 allowed_access_type[v8::ACCESS_HAS] = false;
6451 // Access blocked element.
6452 CompileRun("other[239] = 1");
6454 ExpectUndefined("other[239]");
6455 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6456 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6458 // Enable ACCESS_HAS
6459 allowed_access_type[v8::ACCESS_HAS] = true;
6460 ExpectUndefined("other[239]");
6461 // ... and now we can get the descriptor...
6462 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6463 // ... and enumerate the property.
6464 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6465 allowed_access_type[v8::ACCESS_HAS] = false;
6467 // Access a property with JS accessor.
6468 CompileRun("other.js_accessor_p = 2");
6470 ExpectUndefined("other.js_accessor_p");
6472 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6474 // Enable ACCESS_HAS.
6475 allowed_access_type[v8::ACCESS_HAS] = true;
6476 ExpectUndefined("other.js_accessor_p");
6478 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6480 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6482 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6483 allowed_access_type[v8::ACCESS_HAS] = false;
6485 // Enable both ACCESS_HAS and ACCESS_GET.
6486 allowed_access_type[v8::ACCESS_HAS] = true;
6487 allowed_access_type[v8::ACCESS_GET] = true;
6489 ExpectString("other.js_accessor_p", "getter");
6491 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6493 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6495 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6497 allowed_access_type[v8::ACCESS_GET] = false;
6498 allowed_access_type[v8::ACCESS_HAS] = false;
6500 // Enable both ACCESS_HAS and ACCESS_SET.
6501 allowed_access_type[v8::ACCESS_HAS] = true;
6502 allowed_access_type[v8::ACCESS_SET] = true;
6504 ExpectUndefined("other.js_accessor_p");
6506 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6508 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6510 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6512 allowed_access_type[v8::ACCESS_SET] = false;
6513 allowed_access_type[v8::ACCESS_HAS] = false;
6515 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6516 allowed_access_type[v8::ACCESS_HAS] = true;
6517 allowed_access_type[v8::ACCESS_GET] = true;
6518 allowed_access_type[v8::ACCESS_SET] = true;
6520 ExpectString("other.js_accessor_p", "getter");
6522 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6524 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6526 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6528 allowed_access_type[v8::ACCESS_SET] = false;
6529 allowed_access_type[v8::ACCESS_GET] = false;
6530 allowed_access_type[v8::ACCESS_HAS] = false;
6532 // Access an element with JS accessor.
6533 CompileRun("other[42] = 2");
6535 ExpectUndefined("other[42]");
6536 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6538 // Enable ACCESS_HAS.
6539 allowed_access_type[v8::ACCESS_HAS] = true;
6540 ExpectUndefined("other[42]");
6541 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6542 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6543 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6544 allowed_access_type[v8::ACCESS_HAS] = false;
6546 // Enable both ACCESS_HAS and ACCESS_GET.
6547 allowed_access_type[v8::ACCESS_HAS] = true;
6548 allowed_access_type[v8::ACCESS_GET] = true;
6550 ExpectString("other[42]", "el_getter");
6551 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6552 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6553 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6555 allowed_access_type[v8::ACCESS_GET] = false;
6556 allowed_access_type[v8::ACCESS_HAS] = false;
6558 // Enable both ACCESS_HAS and ACCESS_SET.
6559 allowed_access_type[v8::ACCESS_HAS] = true;
6560 allowed_access_type[v8::ACCESS_SET] = true;
6562 ExpectUndefined("other[42]");
6563 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6564 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6565 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6567 allowed_access_type[v8::ACCESS_SET] = false;
6568 allowed_access_type[v8::ACCESS_HAS] = false;
6570 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6571 allowed_access_type[v8::ACCESS_HAS] = true;
6572 allowed_access_type[v8::ACCESS_GET] = true;
6573 allowed_access_type[v8::ACCESS_SET] = true;
6575 ExpectString("other[42]", "el_getter");
6576 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6577 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6578 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6580 allowed_access_type[v8::ACCESS_SET] = false;
6581 allowed_access_type[v8::ACCESS_GET] = false;
6582 allowed_access_type[v8::ACCESS_HAS] = false;
6584 v8::Handle<Value> value;
6586 // Access accessible property
6587 value = CompileRun("other.accessible_prop = 3");
6588 CHECK(value->IsNumber());
6589 CHECK_EQ(3, value->Int32Value());
6590 CHECK_EQ(3, g_echo_value);
6592 value = CompileRun("other.accessible_prop");
6593 CHECK(value->IsNumber());
6594 CHECK_EQ(3, value->Int32Value());
6597 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6598 CHECK(value->IsNumber());
6599 CHECK_EQ(3, value->Int32Value());
6601 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
6602 CHECK(value->IsTrue());
6604 // Enumeration doesn't enumerate accessors from inaccessible objects in
6605 // the prototype chain even if the accessors are in themselves accessible.
6607 CompileRun("(function(){var obj = {'__proto__':other};"
6608 "for (var p in obj)"
6609 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6612 "return true;})()");
6613 CHECK(value->IsTrue());
6622 TEST(AccessControlES5) {
6623 v8::HandleScope handle_scope;
6624 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6626 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6627 IndexedAccessBlocker);
6629 // Add accessible accessor.
6630 global_template->SetAccessor(
6631 v8_str("accessible_prop"),
6632 EchoGetter, EchoSetter,
6633 v8::Handle<Value>(),
6634 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6637 // Add an accessor that is not accessible by cross-domain JS code.
6638 global_template->SetAccessor(v8_str("blocked_prop"),
6639 UnreachableGetter, UnreachableSetter,
6640 v8::Handle<Value>(),
6643 // Create an environment
6644 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6647 v8::Handle<v8::Object> global0 = context0->Global();
6649 v8::Persistent<Context> context1 = Context::New();
6651 v8::Handle<v8::Object> global1 = context1->Global();
6652 global1->Set(v8_str("other"), global0);
6654 // Regression test for issue 1154.
6655 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6657 ExpectUndefined("other.blocked_prop");
6659 // Regression test for issue 1027.
6660 CompileRun("Object.defineProperty(\n"
6661 " other, 'blocked_prop', {configurable: false})");
6662 ExpectUndefined("other.blocked_prop");
6664 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6666 // Regression test for issue 1171.
6667 ExpectTrue("Object.isExtensible(other)");
6668 CompileRun("Object.preventExtensions(other)");
6669 ExpectTrue("Object.isExtensible(other)");
6671 // Object.seal and Object.freeze.
6672 CompileRun("Object.freeze(other)");
6673 ExpectTrue("Object.isExtensible(other)");
6675 CompileRun("Object.seal(other)");
6676 ExpectTrue("Object.isExtensible(other)");
6678 // Regression test for issue 1250.
6679 // Make sure that we can set the accessible accessors value using normal
6681 CompileRun("other.accessible_prop = 42");
6682 CHECK_EQ(42, g_echo_value);
6684 v8::Handle<Value> value;
6685 // We follow Safari in ignoring assignments to host object accessors.
6686 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6687 value = CompileRun("other.accessible_prop == 42");
6688 CHECK(value->IsTrue());
6692 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6694 v8::AccessType type,
6695 Local<Value> data) {
6700 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6702 v8::AccessType type,
6703 Local<Value> data) {
6708 THREADED_TEST(AccessControlGetOwnPropertyNames) {
6709 v8::HandleScope handle_scope;
6710 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6712 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6713 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6714 GetOwnPropertyNamesIndexedBlocker);
6716 // Create an environment
6717 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6720 v8::Handle<v8::Object> global0 = context0->Global();
6722 v8::HandleScope scope1;
6724 v8::Persistent<Context> context1 = Context::New();
6727 v8::Handle<v8::Object> global1 = context1->Global();
6728 global1->Set(v8_str("other"), global0);
6729 global1->Set(v8_str("object"), obj_template->NewInstance());
6731 v8::Handle<Value> value;
6733 // Attempt to get the property names of the other global object and
6734 // of an object that requires access checks. Accessing the other
6735 // global object should be blocked by access checks on the global
6736 // proxy object. Accessing the object that requires access checks
6737 // is blocked by the access checks on the object itself.
6738 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6739 CHECK(value->IsTrue());
6741 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6742 CHECK(value->IsTrue());
6751 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6752 v8::Handle<v8::Array> result = v8::Array::New(1);
6753 result->Set(0, v8_str("x"));
6758 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6759 v8::HandleScope handle_scope;
6760 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6762 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6763 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6764 NamedPropertyEnumerator);
6766 LocalContext context;
6767 v8::Handle<v8::Object> global = context->Global();
6768 global->Set(v8_str("object"), obj_template->NewInstance());
6770 v8::Handle<Value> value =
6771 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6772 CHECK_EQ(v8_str("x"), value);
6776 static v8::Handle<Value> ConstTenGetter(Local<String> name,
6777 const AccessorInfo& info) {
6782 THREADED_TEST(CrossDomainAccessors) {
6783 v8::HandleScope handle_scope;
6785 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6787 v8::Handle<v8::ObjectTemplate> global_template =
6788 func_template->InstanceTemplate();
6790 v8::Handle<v8::ObjectTemplate> proto_template =
6791 func_template->PrototypeTemplate();
6793 // Add an accessor to proto that's accessible by cross-domain JS code.
6794 proto_template->SetAccessor(v8_str("accessible"),
6796 v8::Handle<Value>(),
6799 // Add an accessor that is not accessible by cross-domain JS code.
6800 global_template->SetAccessor(v8_str("unreachable"),
6801 UnreachableGetter, 0,
6802 v8::Handle<Value>(),
6805 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6808 Local<v8::Object> global = context0->Global();
6809 // Add a normal property that shadows 'accessible'
6810 global->Set(v8_str("accessible"), v8_num(11));
6812 // Enter a new context.
6813 v8::HandleScope scope1;
6814 v8::Persistent<Context> context1 = Context::New();
6817 v8::Handle<v8::Object> global1 = context1->Global();
6818 global1->Set(v8_str("other"), global);
6820 // Should return 10, instead of 11
6821 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6822 CHECK(value->IsNumber());
6823 CHECK_EQ(10, value->Int32Value());
6825 value = v8_compile("other.unreachable")->Run();
6826 CHECK(value->IsUndefined());
6835 static int named_access_count = 0;
6836 static int indexed_access_count = 0;
6838 static bool NamedAccessCounter(Local<v8::Object> global,
6840 v8::AccessType type,
6841 Local<Value> data) {
6842 named_access_count++;
6847 static bool IndexedAccessCounter(Local<v8::Object> global,
6849 v8::AccessType type,
6850 Local<Value> data) {
6851 indexed_access_count++;
6856 // This one is too easily disturbed by other tests.
6857 TEST(AccessControlIC) {
6858 named_access_count = 0;
6859 indexed_access_count = 0;
6861 v8::HandleScope handle_scope;
6863 // Create an environment.
6864 v8::Persistent<Context> context0 = Context::New();
6867 // Create an object that requires access-check functions to be
6868 // called for cross-domain access.
6869 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6870 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6871 IndexedAccessCounter);
6872 Local<v8::Object> object = object_template->NewInstance();
6874 v8::HandleScope scope1;
6876 // Create another environment.
6877 v8::Persistent<Context> context1 = Context::New();
6880 // Make easy access to the object from the other environment.
6881 v8::Handle<v8::Object> global1 = context1->Global();
6882 global1->Set(v8_str("obj"), object);
6884 v8::Handle<Value> value;
6886 // Check that the named access-control function is called every time.
6887 CompileRun("function testProp(obj) {"
6888 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6889 " for (var j = 0; j < 10; j++) obj.prop;"
6892 value = CompileRun("testProp(obj)");
6893 CHECK(value->IsNumber());
6894 CHECK_EQ(1, value->Int32Value());
6895 CHECK_EQ(21, named_access_count);
6897 // Check that the named access-control function is called every time.
6898 CompileRun("var p = 'prop';"
6899 "function testKeyed(obj) {"
6900 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6901 " for (var j = 0; j < 10; j++) obj[p];"
6904 // Use obj which requires access checks. No inline caching is used
6906 value = CompileRun("testKeyed(obj)");
6907 CHECK(value->IsNumber());
6908 CHECK_EQ(1, value->Int32Value());
6909 CHECK_EQ(42, named_access_count);
6910 // Force the inline caches into generic state and try again.
6911 CompileRun("testKeyed({ a: 0 })");
6912 CompileRun("testKeyed({ b: 0 })");
6913 value = CompileRun("testKeyed(obj)");
6914 CHECK(value->IsNumber());
6915 CHECK_EQ(1, value->Int32Value());
6916 CHECK_EQ(63, named_access_count);
6918 // Check that the indexed access-control function is called every time.
6919 CompileRun("function testIndexed(obj) {"
6920 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6921 " for (var j = 0; j < 10; j++) obj[0];"
6924 value = CompileRun("testIndexed(obj)");
6925 CHECK(value->IsNumber());
6926 CHECK_EQ(1, value->Int32Value());
6927 CHECK_EQ(21, indexed_access_count);
6928 // Force the inline caches into generic state.
6929 CompileRun("testIndexed(new Array(1))");
6930 // Test that the indexed access check is called.
6931 value = CompileRun("testIndexed(obj)");
6932 CHECK(value->IsNumber());
6933 CHECK_EQ(1, value->Int32Value());
6934 CHECK_EQ(42, indexed_access_count);
6936 // Check that the named access check is called when invoking
6937 // functions on an object that requires access checks.
6938 CompileRun("obj.f = function() {}");
6939 CompileRun("function testCallNormal(obj) {"
6940 " for (var i = 0; i < 10; i++) obj.f();"
6942 CompileRun("testCallNormal(obj)");
6943 CHECK_EQ(74, named_access_count);
6945 // Force obj into slow case.
6946 value = CompileRun("delete obj.prop");
6947 CHECK(value->BooleanValue());
6948 // Force inline caches into dictionary probing mode.
6949 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6950 // Test that the named access check is called.
6951 value = CompileRun("testProp(obj);");
6952 CHECK(value->IsNumber());
6953 CHECK_EQ(1, value->Int32Value());
6954 CHECK_EQ(96, named_access_count);
6956 // Force the call inline cache into dictionary probing mode.
6957 CompileRun("o.f = function() {}; testCallNormal(o)");
6958 // Test that the named access check is still called for each
6959 // invocation of the function.
6960 value = CompileRun("testCallNormal(obj)");
6961 CHECK_EQ(106, named_access_count);
6970 static bool NamedAccessFlatten(Local<v8::Object> global,
6972 v8::AccessType type,
6973 Local<Value> data) {
6977 CHECK(name->IsString());
6979 memset(buf, 0x1, sizeof(buf));
6980 len = name.As<String>()->WriteAscii(buf);
6985 memset(buf, 0x1, sizeof(buf));
6986 len = name.As<String>()->Write(buf2);
6993 static bool IndexedAccessFlatten(Local<v8::Object> global,
6995 v8::AccessType type,
6996 Local<Value> data) {
7001 // Regression test. In access checks, operations that may cause
7002 // garbage collection are not allowed. It used to be the case that
7003 // using the Write operation on a string could cause a garbage
7004 // collection due to flattening of the string. This is no longer the
7006 THREADED_TEST(AccessControlFlatten) {
7007 named_access_count = 0;
7008 indexed_access_count = 0;
7010 v8::HandleScope handle_scope;
7012 // Create an environment.
7013 v8::Persistent<Context> context0 = Context::New();
7016 // Create an object that requires access-check functions to be
7017 // called for cross-domain access.
7018 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7019 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7020 IndexedAccessFlatten);
7021 Local<v8::Object> object = object_template->NewInstance();
7023 v8::HandleScope scope1;
7025 // Create another environment.
7026 v8::Persistent<Context> context1 = Context::New();
7029 // Make easy access to the object from the other environment.
7030 v8::Handle<v8::Object> global1 = context1->Global();
7031 global1->Set(v8_str("obj"), object);
7033 v8::Handle<Value> value;
7035 value = v8_compile("var p = 'as' + 'df';")->Run();
7036 value = v8_compile("obj[p];")->Run();
7045 static v8::Handle<Value> AccessControlNamedGetter(
7046 Local<String>, const AccessorInfo&) {
7047 return v8::Integer::New(42);
7051 static v8::Handle<Value> AccessControlNamedSetter(
7052 Local<String>, Local<Value> value, const AccessorInfo&) {
7057 static v8::Handle<Value> AccessControlIndexedGetter(
7059 const AccessorInfo& info) {
7064 static v8::Handle<Value> AccessControlIndexedSetter(
7065 uint32_t, Local<Value> value, const AccessorInfo&) {
7070 THREADED_TEST(AccessControlInterceptorIC) {
7071 named_access_count = 0;
7072 indexed_access_count = 0;
7074 v8::HandleScope handle_scope;
7076 // Create an environment.
7077 v8::Persistent<Context> context0 = Context::New();
7080 // Create an object that requires access-check functions to be
7081 // called for cross-domain access. The object also has interceptors
7083 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7084 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7085 IndexedAccessCounter);
7086 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7087 AccessControlNamedSetter);
7088 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7089 AccessControlIndexedSetter);
7090 Local<v8::Object> object = object_template->NewInstance();
7092 v8::HandleScope scope1;
7094 // Create another environment.
7095 v8::Persistent<Context> context1 = Context::New();
7098 // Make easy access to the object from the other environment.
7099 v8::Handle<v8::Object> global1 = context1->Global();
7100 global1->Set(v8_str("obj"), object);
7102 v8::Handle<Value> value;
7104 // Check that the named access-control function is called every time
7105 // eventhough there is an interceptor on the object.
7106 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7107 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7109 CHECK(value->IsNumber());
7110 CHECK_EQ(42, value->Int32Value());
7111 CHECK_EQ(21, named_access_count);
7113 value = v8_compile("var p = 'x';")->Run();
7114 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7115 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7117 CHECK(value->IsNumber());
7118 CHECK_EQ(42, value->Int32Value());
7119 CHECK_EQ(42, named_access_count);
7121 // Check that the indexed access-control function is called every
7122 // time eventhough there is an interceptor on the object.
7123 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7124 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7126 CHECK(value->IsNumber());
7127 CHECK_EQ(42, value->Int32Value());
7128 CHECK_EQ(21, indexed_access_count);
7137 THREADED_TEST(Version) {
7138 v8::V8::GetVersion();
7142 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7143 ApiTestFuzzer::Fuzz();
7148 THREADED_TEST(InstanceProperties) {
7149 v8::HandleScope handle_scope;
7150 LocalContext context;
7152 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7153 Local<ObjectTemplate> instance = t->InstanceTemplate();
7155 instance->Set(v8_str("x"), v8_num(42));
7156 instance->Set(v8_str("f"),
7157 v8::FunctionTemplate::New(InstanceFunctionCallback));
7159 Local<Value> o = t->GetFunction()->NewInstance();
7161 context->Global()->Set(v8_str("i"), o);
7162 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7163 CHECK_EQ(42, value->Int32Value());
7165 value = Script::Compile(v8_str("i.f()"))->Run();
7166 CHECK_EQ(12, value->Int32Value());
7170 static v8::Handle<Value>
7171 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7172 ApiTestFuzzer::Fuzz();
7173 return v8::Handle<Value>();
7177 THREADED_TEST(GlobalObjectInstanceProperties) {
7178 v8::HandleScope handle_scope;
7180 Local<Value> global_object;
7182 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7183 t->InstanceTemplate()->SetNamedPropertyHandler(
7184 GlobalObjectInstancePropertiesGet);
7185 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7186 instance_template->Set(v8_str("x"), v8_num(42));
7187 instance_template->Set(v8_str("f"),
7188 v8::FunctionTemplate::New(InstanceFunctionCallback));
7190 // The script to check how Crankshaft compiles missing global function
7191 // invocations. function g is not defined and should throw on call.
7192 const char* script =
7193 "function wrapper(call) {"
7194 " var x = 0, y = 1;"
7195 " for (var i = 0; i < 1000; i++) {"
7201 "for (var i = 0; i < 17; i++) wrapper(false);"
7203 "try { wrapper(true); } catch (e) { thrown = 1; };"
7207 LocalContext env(NULL, instance_template);
7208 // Hold on to the global object so it can be used again in another
7209 // environment initialization.
7210 global_object = env->Global();
7212 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7213 CHECK_EQ(42, value->Int32Value());
7214 value = Script::Compile(v8_str("f()"))->Run();
7215 CHECK_EQ(12, value->Int32Value());
7216 value = Script::Compile(v8_str(script))->Run();
7217 CHECK_EQ(1, value->Int32Value());
7221 // Create new environment reusing the global object.
7222 LocalContext env(NULL, instance_template, global_object);
7223 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7224 CHECK_EQ(42, value->Int32Value());
7225 value = Script::Compile(v8_str("f()"))->Run();
7226 CHECK_EQ(12, value->Int32Value());
7227 value = Script::Compile(v8_str(script))->Run();
7228 CHECK_EQ(1, value->Int32Value());
7233 THREADED_TEST(CallKnownGlobalReceiver) {
7234 v8::HandleScope handle_scope;
7236 Local<Value> global_object;
7238 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7239 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7241 // The script to check that we leave global object not
7242 // global object proxy on stack when we deoptimize from inside
7243 // arguments evaluation.
7244 // To provoke error we need to both force deoptimization
7245 // from arguments evaluation and to force CallIC to take
7246 // CallIC_Miss code path that can't cope with global proxy.
7247 const char* script =
7248 "function bar(x, y) { try { } finally { } }"
7249 "function baz(x) { try { } finally { } }"
7250 "function bom(x) { try { } finally { } }"
7251 "function foo(x) { bar([x], bom(2)); }"
7252 "for (var i = 0; i < 10000; i++) foo(1);"
7257 LocalContext env(NULL, instance_template);
7258 // Hold on to the global object so it can be used again in another
7259 // environment initialization.
7260 global_object = env->Global();
7261 foo = Script::Compile(v8_str(script))->Run();
7265 // Create new environment reusing the global object.
7266 LocalContext env(NULL, instance_template, global_object);
7267 env->Global()->Set(v8_str("foo"), foo);
7268 Local<Value> value(Script::Compile(v8_str("foo()"))->Run());
7273 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7274 ApiTestFuzzer::Fuzz();
7279 static int shadow_y;
7280 static int shadow_y_setter_call_count;
7281 static int shadow_y_getter_call_count;
7284 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7285 shadow_y_setter_call_count++;
7290 static v8::Handle<Value> ShadowYGetter(Local<String> name,
7291 const AccessorInfo& info) {
7292 ApiTestFuzzer::Fuzz();
7293 shadow_y_getter_call_count++;
7294 return v8_num(shadow_y);
7298 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7299 const AccessorInfo& info) {
7300 return v8::Handle<Value>();
7304 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7305 const AccessorInfo&) {
7306 return v8::Handle<Value>();
7310 THREADED_TEST(ShadowObject) {
7311 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7312 v8::HandleScope handle_scope;
7314 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7315 LocalContext context(NULL, global_template);
7317 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7318 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7319 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7320 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7321 Local<ObjectTemplate> instance = t->InstanceTemplate();
7323 // Only allow calls of f on instances of t.
7324 Local<v8::Signature> signature = v8::Signature::New(t);
7325 proto->Set(v8_str("f"),
7326 v8::FunctionTemplate::New(ShadowFunctionCallback,
7329 proto->Set(v8_str("x"), v8_num(12));
7331 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7333 Local<Value> o = t->GetFunction()->NewInstance();
7334 context->Global()->Set(v8_str("__proto__"), o);
7336 Local<Value> value =
7337 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7338 CHECK(value->IsBoolean());
7339 CHECK(!value->BooleanValue());
7341 value = Script::Compile(v8_str("x"))->Run();
7342 CHECK_EQ(12, value->Int32Value());
7344 value = Script::Compile(v8_str("f()"))->Run();
7345 CHECK_EQ(42, value->Int32Value());
7347 Script::Compile(v8_str("y = 42"))->Run();
7348 CHECK_EQ(1, shadow_y_setter_call_count);
7349 value = Script::Compile(v8_str("y"))->Run();
7350 CHECK_EQ(1, shadow_y_getter_call_count);
7351 CHECK_EQ(42, value->Int32Value());
7355 THREADED_TEST(HiddenPrototype) {
7356 v8::HandleScope handle_scope;
7357 LocalContext context;
7359 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7360 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7361 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7362 t1->SetHiddenPrototype(true);
7363 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7364 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7365 t2->SetHiddenPrototype(true);
7366 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7367 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7368 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7370 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7371 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7372 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7373 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7375 // Setting the prototype on an object skips hidden prototypes.
7376 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7377 o0->Set(v8_str("__proto__"), o1);
7378 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7379 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7380 o0->Set(v8_str("__proto__"), o2);
7381 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7382 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7383 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7384 o0->Set(v8_str("__proto__"), o3);
7385 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7386 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7387 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7388 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7390 // Getting the prototype of o0 should get the first visible one
7391 // which is o3. Therefore, z should not be defined on the prototype
7393 Local<Value> proto = o0->Get(v8_str("__proto__"));
7394 CHECK(proto->IsObject());
7395 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7399 THREADED_TEST(SetPrototype) {
7400 v8::HandleScope handle_scope;
7401 LocalContext context;
7403 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7404 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7405 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7406 t1->SetHiddenPrototype(true);
7407 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7408 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7409 t2->SetHiddenPrototype(true);
7410 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7411 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7412 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7414 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7415 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7416 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7417 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7419 // Setting the prototype on an object does not skip hidden prototypes.
7420 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7421 CHECK(o0->SetPrototype(o1));
7422 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7423 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7424 CHECK(o1->SetPrototype(o2));
7425 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7426 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7427 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7428 CHECK(o2->SetPrototype(o3));
7429 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7430 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7431 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7432 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7434 // Getting the prototype of o0 should get the first visible one
7435 // which is o3. Therefore, z should not be defined on the prototype
7437 Local<Value> proto = o0->Get(v8_str("__proto__"));
7438 CHECK(proto->IsObject());
7439 CHECK_EQ(proto.As<v8::Object>(), o3);
7441 // However, Object::GetPrototype ignores hidden prototype.
7442 Local<Value> proto0 = o0->GetPrototype();
7443 CHECK(proto0->IsObject());
7444 CHECK_EQ(proto0.As<v8::Object>(), o1);
7446 Local<Value> proto1 = o1->GetPrototype();
7447 CHECK(proto1->IsObject());
7448 CHECK_EQ(proto1.As<v8::Object>(), o2);
7450 Local<Value> proto2 = o2->GetPrototype();
7451 CHECK(proto2->IsObject());
7452 CHECK_EQ(proto2.As<v8::Object>(), o3);
7456 THREADED_TEST(FunctionReadOnlyPrototype) {
7457 v8::HandleScope handle_scope;
7458 LocalContext context;
7460 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7461 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7462 t1->ReadOnlyPrototype();
7463 context->Global()->Set(v8_str("func1"), t1->GetFunction());
7464 // Configured value of ReadOnly flag.
7467 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7468 " return (descriptor['writable'] == false);"
7469 "})()")->BooleanValue());
7470 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7472 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
7474 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7475 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7476 context->Global()->Set(v8_str("func2"), t2->GetFunction());
7477 // Default value of ReadOnly flag.
7480 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7481 " return (descriptor['writable'] == true);"
7482 "})()")->BooleanValue());
7483 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
7487 THREADED_TEST(SetPrototypeThrows) {
7488 v8::HandleScope handle_scope;
7489 LocalContext context;
7491 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7493 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7494 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7496 CHECK(o0->SetPrototype(o1));
7497 // If setting the prototype leads to the cycle, SetPrototype should
7498 // return false and keep VM in sane state.
7499 v8::TryCatch try_catch;
7500 CHECK(!o1->SetPrototype(o0));
7501 CHECK(!try_catch.HasCaught());
7502 ASSERT(!i::Isolate::Current()->has_pending_exception());
7504 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7508 THREADED_TEST(GetterSetterExceptions) {
7509 v8::HandleScope handle_scope;
7510 LocalContext context;
7512 "function Foo() { };"
7513 "function Throw() { throw 5; };"
7515 "x.__defineSetter__('set', Throw);"
7516 "x.__defineGetter__('get', Throw);");
7517 Local<v8::Object> x =
7518 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7519 v8::TryCatch try_catch;
7520 x->Set(v8_str("set"), v8::Integer::New(8));
7521 x->Get(v8_str("get"));
7522 x->Set(v8_str("set"), v8::Integer::New(8));
7523 x->Get(v8_str("get"));
7524 x->Set(v8_str("set"), v8::Integer::New(8));
7525 x->Get(v8_str("get"));
7526 x->Set(v8_str("set"), v8::Integer::New(8));
7527 x->Get(v8_str("get"));
7531 THREADED_TEST(Constructor) {
7532 v8::HandleScope handle_scope;
7533 LocalContext context;
7534 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7535 templ->SetClassName(v8_str("Fun"));
7536 Local<Function> cons = templ->GetFunction();
7537 context->Global()->Set(v8_str("Fun"), cons);
7538 Local<v8::Object> inst = cons->NewInstance();
7539 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
7540 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7541 CHECK(value->BooleanValue());
7545 static Handle<Value> ConstructorCallback(const Arguments& args) {
7546 ApiTestFuzzer::Fuzz();
7549 if (args.IsConstructCall()) {
7550 Local<Object> Holder = args.Holder();
7551 This = Object::New();
7552 Local<Value> proto = Holder->GetPrototype();
7553 if (proto->IsObject()) {
7554 This->SetPrototype(proto);
7560 This->Set(v8_str("a"), args[0]);
7565 static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7566 ApiTestFuzzer::Fuzz();
7571 THREADED_TEST(ConstructorForObject) {
7572 v8::HandleScope handle_scope;
7573 LocalContext context;
7575 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7576 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7577 Local<Object> instance = instance_template->NewInstance();
7578 context->Global()->Set(v8_str("obj"), instance);
7579 v8::TryCatch try_catch;
7581 CHECK(!try_catch.HasCaught());
7583 // Call the Object's constructor with a 32-bit signed integer.
7584 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7585 CHECK(!try_catch.HasCaught());
7586 CHECK(value->IsInt32());
7587 CHECK_EQ(28, value->Int32Value());
7589 Local<Value> args1[] = { v8_num(28) };
7590 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7591 CHECK(value_obj1->IsObject());
7592 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7593 value = object1->Get(v8_str("a"));
7594 CHECK(value->IsInt32());
7595 CHECK(!try_catch.HasCaught());
7596 CHECK_EQ(28, value->Int32Value());
7598 // Call the Object's constructor with a String.
7600 "(function() { var o = new obj('tipli'); return o.a; })()");
7601 CHECK(!try_catch.HasCaught());
7602 CHECK(value->IsString());
7603 String::AsciiValue string_value1(value->ToString());
7604 CHECK_EQ("tipli", *string_value1);
7606 Local<Value> args2[] = { v8_str("tipli") };
7607 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7608 CHECK(value_obj2->IsObject());
7609 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7610 value = object2->Get(v8_str("a"));
7611 CHECK(!try_catch.HasCaught());
7612 CHECK(value->IsString());
7613 String::AsciiValue string_value2(value->ToString());
7614 CHECK_EQ("tipli", *string_value2);
7616 // Call the Object's constructor with a Boolean.
7617 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7618 CHECK(!try_catch.HasCaught());
7619 CHECK(value->IsBoolean());
7620 CHECK_EQ(true, value->BooleanValue());
7622 Handle<Value> args3[] = { v8::True() };
7623 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7624 CHECK(value_obj3->IsObject());
7625 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7626 value = object3->Get(v8_str("a"));
7627 CHECK(!try_catch.HasCaught());
7628 CHECK(value->IsBoolean());
7629 CHECK_EQ(true, value->BooleanValue());
7631 // Call the Object's constructor with undefined.
7632 Handle<Value> args4[] = { v8::Undefined() };
7633 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7634 CHECK(value_obj4->IsObject());
7635 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7636 value = object4->Get(v8_str("a"));
7637 CHECK(!try_catch.HasCaught());
7638 CHECK(value->IsUndefined());
7640 // Call the Object's constructor with null.
7641 Handle<Value> args5[] = { v8::Null() };
7642 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7643 CHECK(value_obj5->IsObject());
7644 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7645 value = object5->Get(v8_str("a"));
7646 CHECK(!try_catch.HasCaught());
7647 CHECK(value->IsNull());
7650 // Check exception handling when there is no constructor set for the Object.
7651 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7652 Local<Object> instance = instance_template->NewInstance();
7653 context->Global()->Set(v8_str("obj2"), instance);
7654 v8::TryCatch try_catch;
7656 CHECK(!try_catch.HasCaught());
7658 value = CompileRun("new obj2(28)");
7659 CHECK(try_catch.HasCaught());
7660 String::AsciiValue exception_value1(try_catch.Exception());
7661 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7664 Local<Value> args[] = { v8_num(29) };
7665 value = instance->CallAsConstructor(1, args);
7666 CHECK(try_catch.HasCaught());
7667 String::AsciiValue exception_value2(try_catch.Exception());
7668 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7672 // Check the case when constructor throws exception.
7673 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7674 instance_template->SetCallAsFunctionHandler(ThrowValue);
7675 Local<Object> instance = instance_template->NewInstance();
7676 context->Global()->Set(v8_str("obj3"), instance);
7677 v8::TryCatch try_catch;
7679 CHECK(!try_catch.HasCaught());
7681 value = CompileRun("new obj3(22)");
7682 CHECK(try_catch.HasCaught());
7683 String::AsciiValue exception_value1(try_catch.Exception());
7684 CHECK_EQ("22", *exception_value1);
7687 Local<Value> args[] = { v8_num(23) };
7688 value = instance->CallAsConstructor(1, args);
7689 CHECK(try_catch.HasCaught());
7690 String::AsciiValue exception_value2(try_catch.Exception());
7691 CHECK_EQ("23", *exception_value2);
7695 // Check whether constructor returns with an object or non-object.
7696 { Local<FunctionTemplate> function_template =
7697 FunctionTemplate::New(FakeConstructorCallback);
7698 Local<Function> function = function_template->GetFunction();
7699 Local<Object> instance1 = function;
7700 context->Global()->Set(v8_str("obj4"), instance1);
7701 v8::TryCatch try_catch;
7703 CHECK(!try_catch.HasCaught());
7705 CHECK(instance1->IsObject());
7706 CHECK(instance1->IsFunction());
7708 value = CompileRun("new obj4(28)");
7709 CHECK(!try_catch.HasCaught());
7710 CHECK(value->IsObject());
7712 Local<Value> args1[] = { v8_num(28) };
7713 value = instance1->CallAsConstructor(1, args1);
7714 CHECK(!try_catch.HasCaught());
7715 CHECK(value->IsObject());
7717 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7718 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7719 Local<Object> instance2 = instance_template->NewInstance();
7720 context->Global()->Set(v8_str("obj5"), instance2);
7721 CHECK(!try_catch.HasCaught());
7723 CHECK(instance2->IsObject());
7724 CHECK(!instance2->IsFunction());
7726 value = CompileRun("new obj5(28)");
7727 CHECK(!try_catch.HasCaught());
7728 CHECK(!value->IsObject());
7730 Local<Value> args2[] = { v8_num(28) };
7731 value = instance2->CallAsConstructor(1, args2);
7732 CHECK(!try_catch.HasCaught());
7733 CHECK(!value->IsObject());
7738 THREADED_TEST(FunctionDescriptorException) {
7739 v8::HandleScope handle_scope;
7740 LocalContext context;
7741 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7742 templ->SetClassName(v8_str("Fun"));
7743 Local<Function> cons = templ->GetFunction();
7744 context->Global()->Set(v8_str("Fun"), cons);
7745 Local<Value> value = CompileRun(
7748 " (new Fun()).blah()"
7750 " var str = String(e);"
7751 " if (str.indexOf('TypeError') == -1) return 1;"
7752 " if (str.indexOf('[object Fun]') != -1) return 2;"
7753 " if (str.indexOf('#<Fun>') == -1) return 3;"
7759 CHECK_EQ(0, value->Int32Value());
7763 THREADED_TEST(EvalAliasedDynamic) {
7764 v8::HandleScope scope;
7765 LocalContext current;
7767 // Tests where aliased eval can only be resolved dynamically.
7768 Local<Script> script =
7769 Script::Compile(v8_str("function f(x) { "
7771 " with (x) { return eval('foo'); }"
7774 "result1 = f(new Object());"
7775 "result2 = f(this);"
7776 "var x = new Object();"
7777 "x.eval = function(x) { return 1; };"
7778 "result3 = f(x);"));
7780 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7781 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7782 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7784 v8::TryCatch try_catch;
7786 Script::Compile(v8_str("function f(x) { "
7788 " with (x) { return eval('bar'); }"
7790 "result4 = f(this)"));
7792 CHECK(!try_catch.HasCaught());
7793 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7799 THREADED_TEST(CrossEval) {
7800 v8::HandleScope scope;
7802 LocalContext current;
7804 Local<String> token = v8_str("<security token>");
7805 other->SetSecurityToken(token);
7806 current->SetSecurityToken(token);
7808 // Setup reference from current to other.
7809 current->Global()->Set(v8_str("other"), other->Global());
7811 // Check that new variables are introduced in other context.
7812 Local<Script> script =
7813 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7815 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7816 CHECK_EQ(1234, foo->Int32Value());
7817 CHECK(!current->Global()->Has(v8_str("foo")));
7819 // Check that writing to non-existing properties introduces them in
7820 // the other context.
7822 Script::Compile(v8_str("other.eval('na = 1234')"));
7824 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7825 CHECK(!current->Global()->Has(v8_str("na")));
7827 // Check that global variables in current context are not visible in other
7829 v8::TryCatch try_catch;
7831 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7832 Local<Value> result = script->Run();
7833 CHECK(try_catch.HasCaught());
7836 // Check that local variables in current context are not visible in other
7839 Script::Compile(v8_str("(function() { "
7841 " return other.eval('baz');"
7843 result = script->Run();
7844 CHECK(try_catch.HasCaught());
7847 // Check that global variables in the other environment are visible
7848 // when evaluting code.
7849 other->Global()->Set(v8_str("bis"), v8_num(1234));
7850 script = Script::Compile(v8_str("other.eval('bis')"));
7851 CHECK_EQ(1234, script->Run()->Int32Value());
7852 CHECK(!try_catch.HasCaught());
7854 // Check that the 'this' pointer points to the global object evaluating
7856 other->Global()->Set(v8_str("t"), other->Global());
7857 script = Script::Compile(v8_str("other.eval('this == t')"));
7858 result = script->Run();
7859 CHECK(result->IsTrue());
7860 CHECK(!try_catch.HasCaught());
7862 // Check that variables introduced in with-statement are not visible in
7865 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7866 result = script->Run();
7867 CHECK(try_catch.HasCaught());
7870 // Check that you cannot use 'eval.call' with another object than the
7871 // current global object.
7873 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7874 result = script->Run();
7875 CHECK(try_catch.HasCaught());
7879 // Test that calling eval in a context which has been detached from
7880 // its global throws an exception. This behavior is consistent with
7881 // other JavaScript implementations.
7882 THREADED_TEST(EvalInDetachedGlobal) {
7883 v8::HandleScope scope;
7885 v8::Persistent<Context> context0 = Context::New();
7886 v8::Persistent<Context> context1 = Context::New();
7888 // Setup function in context0 that uses eval from context0.
7890 v8::Handle<v8::Value> fun =
7891 CompileRun("var x = 42;"
7894 " return function(s) { return e(s); }"
7898 // Put the function into context1 and call it before and after
7899 // detaching the global. Before detaching, the call succeeds and
7900 // after detaching and exception is thrown.
7902 context1->Global()->Set(v8_str("fun"), fun);
7903 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7904 CHECK_EQ(42, x_value->Int32Value());
7905 context0->DetachGlobal();
7906 v8::TryCatch catcher;
7907 x_value = CompileRun("fun('x')");
7908 CHECK(x_value.IsEmpty());
7909 CHECK(catcher.HasCaught());
7917 THREADED_TEST(CrossLazyLoad) {
7918 v8::HandleScope scope;
7920 LocalContext current;
7922 Local<String> token = v8_str("<security token>");
7923 other->SetSecurityToken(token);
7924 current->SetSecurityToken(token);
7926 // Setup reference from current to other.
7927 current->Global()->Set(v8_str("other"), other->Global());
7929 // Trigger lazy loading in other context.
7930 Local<Script> script =
7931 Script::Compile(v8_str("other.eval('new Date(42)')"));
7932 Local<Value> value = script->Run();
7933 CHECK_EQ(42.0, value->NumberValue());
7937 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7938 ApiTestFuzzer::Fuzz();
7939 if (args.IsConstructCall()) {
7940 if (args[0]->IsInt32()) {
7941 return v8_num(-args[0]->Int32Value());
7949 // Test that a call handler can be set for objects which will allow
7950 // non-function objects created through the API to be called as
7952 THREADED_TEST(CallAsFunction) {
7953 v8::HandleScope scope;
7954 LocalContext context;
7956 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7957 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7958 instance_template->SetCallAsFunctionHandler(call_as_function);
7959 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7960 context->Global()->Set(v8_str("obj"), instance);
7961 v8::TryCatch try_catch;
7963 CHECK(!try_catch.HasCaught());
7965 value = CompileRun("obj(42)");
7966 CHECK(!try_catch.HasCaught());
7967 CHECK_EQ(42, value->Int32Value());
7969 value = CompileRun("(function(o){return o(49)})(obj)");
7970 CHECK(!try_catch.HasCaught());
7971 CHECK_EQ(49, value->Int32Value());
7973 // test special case of call as function
7974 value = CompileRun("[obj]['0'](45)");
7975 CHECK(!try_catch.HasCaught());
7976 CHECK_EQ(45, value->Int32Value());
7978 value = CompileRun("obj.call = Function.prototype.call;"
7979 "obj.call(null, 87)");
7980 CHECK(!try_catch.HasCaught());
7981 CHECK_EQ(87, value->Int32Value());
7983 // Regression tests for bug #1116356: Calling call through call/apply
7984 // must work for non-function receivers.
7985 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7986 value = CompileRun(apply_99);
7987 CHECK(!try_catch.HasCaught());
7988 CHECK_EQ(99, value->Int32Value());
7990 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7991 value = CompileRun(call_17);
7992 CHECK(!try_catch.HasCaught());
7993 CHECK_EQ(17, value->Int32Value());
7995 // Check that the call-as-function handler can be called through
7997 value = CompileRun("new obj(43)");
7998 CHECK(!try_catch.HasCaught());
7999 CHECK_EQ(-43, value->Int32Value());
8001 // Check that the call-as-function handler can be called through
8003 v8::Handle<Value> args[] = { v8_num(28) };
8004 value = instance->CallAsFunction(instance, 1, args);
8005 CHECK(!try_catch.HasCaught());
8006 CHECK_EQ(28, value->Int32Value());
8009 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8010 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8011 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8012 context->Global()->Set(v8_str("obj2"), instance);
8013 v8::TryCatch try_catch;
8015 CHECK(!try_catch.HasCaught());
8017 // Call an object without call-as-function handler through the JS
8018 value = CompileRun("obj2(28)");
8019 CHECK(value.IsEmpty());
8020 CHECK(try_catch.HasCaught());
8021 String::AsciiValue exception_value1(try_catch.Exception());
8022 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8026 // Call an object without call-as-function handler through the API
8027 value = CompileRun("obj2(28)");
8028 v8::Handle<Value> args[] = { v8_num(28) };
8029 value = instance->CallAsFunction(instance, 1, args);
8030 CHECK(value.IsEmpty());
8031 CHECK(try_catch.HasCaught());
8032 String::AsciiValue exception_value2(try_catch.Exception());
8033 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8037 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8038 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8039 instance_template->SetCallAsFunctionHandler(ThrowValue);
8040 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8041 context->Global()->Set(v8_str("obj3"), instance);
8042 v8::TryCatch try_catch;
8044 CHECK(!try_catch.HasCaught());
8046 // Catch the exception which is thrown by call-as-function handler
8047 value = CompileRun("obj3(22)");
8048 CHECK(try_catch.HasCaught());
8049 String::AsciiValue exception_value1(try_catch.Exception());
8050 CHECK_EQ("22", *exception_value1);
8053 v8::Handle<Value> args[] = { v8_num(23) };
8054 value = instance->CallAsFunction(instance, 1, args);
8055 CHECK(try_catch.HasCaught());
8056 String::AsciiValue exception_value2(try_catch.Exception());
8057 CHECK_EQ("23", *exception_value2);
8063 // Check whether a non-function object is callable.
8064 THREADED_TEST(CallableObject) {
8065 v8::HandleScope scope;
8066 LocalContext context;
8068 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8069 instance_template->SetCallAsFunctionHandler(call_as_function);
8070 Local<Object> instance = instance_template->NewInstance();
8071 v8::TryCatch try_catch;
8073 CHECK(instance->IsCallable());
8074 CHECK(!try_catch.HasCaught());
8077 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8078 Local<Object> instance = instance_template->NewInstance();
8079 v8::TryCatch try_catch;
8081 CHECK(!instance->IsCallable());
8082 CHECK(!try_catch.HasCaught());
8085 { Local<FunctionTemplate> function_template =
8086 FunctionTemplate::New(call_as_function);
8087 Local<Function> function = function_template->GetFunction();
8088 Local<Object> instance = function;
8089 v8::TryCatch try_catch;
8091 CHECK(instance->IsCallable());
8092 CHECK(!try_catch.HasCaught());
8095 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8096 Local<Function> function = function_template->GetFunction();
8097 Local<Object> instance = function;
8098 v8::TryCatch try_catch;
8100 CHECK(instance->IsCallable());
8101 CHECK(!try_catch.HasCaught());
8106 static int CountHandles() {
8107 return v8::HandleScope::NumberOfHandles();
8111 static int Recurse(int depth, int iterations) {
8112 v8::HandleScope scope;
8113 if (depth == 0) return CountHandles();
8114 for (int i = 0; i < iterations; i++) {
8115 Local<v8::Number> n(v8::Integer::New(42));
8117 return Recurse(depth - 1, iterations);
8121 THREADED_TEST(HandleIteration) {
8122 static const int kIterations = 500;
8123 static const int kNesting = 200;
8124 CHECK_EQ(0, CountHandles());
8126 v8::HandleScope scope1;
8127 CHECK_EQ(0, CountHandles());
8128 for (int i = 0; i < kIterations; i++) {
8129 Local<v8::Number> n(v8::Integer::New(42));
8130 CHECK_EQ(i + 1, CountHandles());
8133 CHECK_EQ(kIterations, CountHandles());
8135 v8::HandleScope scope2;
8136 for (int j = 0; j < kIterations; j++) {
8137 Local<v8::Number> n(v8::Integer::New(42));
8138 CHECK_EQ(j + 1 + kIterations, CountHandles());
8141 CHECK_EQ(kIterations, CountHandles());
8143 CHECK_EQ(0, CountHandles());
8144 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8148 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8150 const AccessorInfo& info) {
8151 ApiTestFuzzer::Fuzz();
8152 return v8::Handle<Value>();
8156 THREADED_TEST(InterceptorHasOwnProperty) {
8157 v8::HandleScope scope;
8158 LocalContext context;
8159 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8160 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8161 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8162 Local<Function> function = fun_templ->GetFunction();
8163 context->Global()->Set(v8_str("constructor"), function);
8164 v8::Handle<Value> value = CompileRun(
8165 "var o = new constructor();"
8166 "o.hasOwnProperty('ostehaps');");
8167 CHECK_EQ(false, value->BooleanValue());
8170 "o.hasOwnProperty('ostehaps');");
8171 CHECK_EQ(true, value->BooleanValue());
8173 "var p = new constructor();"
8174 "p.hasOwnProperty('ostehaps');");
8175 CHECK_EQ(false, value->BooleanValue());
8179 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8181 const AccessorInfo& info) {
8182 ApiTestFuzzer::Fuzz();
8183 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8184 return v8::Handle<Value>();
8188 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8189 v8::HandleScope scope;
8190 LocalContext context;
8191 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8192 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8193 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8194 Local<Function> function = fun_templ->GetFunction();
8195 context->Global()->Set(v8_str("constructor"), function);
8196 // Let's first make some stuff so we can be sure to get a good GC.
8198 "function makestr(size) {"
8200 " case 1: return 'f';"
8201 " case 2: return 'fo';"
8202 " case 3: return 'foo';"
8204 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8206 "var x = makestr(12345);"
8207 "x = makestr(31415);"
8208 "x = makestr(23456);");
8209 v8::Handle<Value> value = CompileRun(
8210 "var o = new constructor();"
8211 "o.__proto__ = new String(x);"
8212 "o.hasOwnProperty('ostehaps');");
8213 CHECK_EQ(false, value->BooleanValue());
8217 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8218 const AccessorInfo& info);
8221 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8224 v8::HandleScope scope;
8225 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8226 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8227 LocalContext context;
8228 context->Global()->Set(v8_str("o"), templ->NewInstance());
8229 v8::Handle<Value> value = CompileRun(source);
8230 CHECK_EQ(expected, value->Int32Value());
8234 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8235 const AccessorInfo& info) {
8236 ApiTestFuzzer::Fuzz();
8237 CHECK_EQ(v8_str("data"), info.Data());
8238 CHECK_EQ(v8_str("x"), name);
8239 return v8::Integer::New(42);
8243 // This test should hit the load IC for the interceptor case.
8244 THREADED_TEST(InterceptorLoadIC) {
8245 CheckInterceptorLoadIC(InterceptorLoadICGetter,
8247 "for (var i = 0; i < 1000; i++) {"
8254 // Below go several tests which verify that JITing for various
8255 // configurations of interceptor and explicit fields works fine
8256 // (those cases are special cased to get better performance).
8258 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8259 const AccessorInfo& info) {
8260 ApiTestFuzzer::Fuzz();
8261 return v8_str("x")->Equals(name)
8262 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8266 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8267 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8270 "for (var i = 0; i < 1000; i++) {"
8277 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8278 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8280 "o.__proto__ = { 'y': 239 };"
8281 "for (var i = 0; i < 1000; i++) {"
8282 " result = o.y + o.x;"
8288 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8289 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8291 "o.__proto__.y = 239;"
8292 "for (var i = 0; i < 1000; i++) {"
8293 " result = o.y + o.x;"
8299 THREADED_TEST(InterceptorLoadICUndefined) {
8300 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8302 "for (var i = 0; i < 1000; i++) {"
8303 " result = (o.y == undefined) ? 239 : 42;"
8309 THREADED_TEST(InterceptorLoadICWithOverride) {
8310 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8311 "fst = new Object(); fst.__proto__ = o;"
8312 "snd = new Object(); snd.__proto__ = fst;"
8314 "for (var i = 0; i < 1000; i++) {"
8319 "for (var i = 0; i < 1000; i++) {"
8327 // Test the case when we stored field into
8328 // a stub, but interceptor produced value on its own.
8329 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8330 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8331 "proto = new Object();"
8332 "o.__proto__ = proto;"
8334 "for (var i = 0; i < 1000; i++) {"
8336 // Now it should be ICed and keep a reference to x defined on proto
8339 "for (var i = 0; i < 1000; i++) {"
8347 // Test the case when we stored field into
8348 // a stub, but it got invalidated later on.
8349 THREADED_TEST(InterceptorLoadICInvalidatedField) {
8350 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8351 "proto1 = new Object();"
8352 "proto2 = new Object();"
8353 "o.__proto__ = proto1;"
8354 "proto1.__proto__ = proto2;"
8356 "for (var i = 0; i < 1000; i++) {"
8358 // Now it should be ICed and keep a reference to y defined on proto2
8362 "for (var i = 0; i < 1000; i++) {"
8370 static int interceptor_load_not_handled_calls = 0;
8371 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8372 const AccessorInfo& info) {
8373 ++interceptor_load_not_handled_calls;
8374 return v8::Handle<v8::Value>();
8378 // Test how post-interceptor lookups are done in the non-cacheable
8379 // case: the interceptor should not be invoked during this lookup.
8380 THREADED_TEST(InterceptorLoadICPostInterceptor) {
8381 interceptor_load_not_handled_calls = 0;
8382 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8383 "receiver = new Object();"
8384 "receiver.__proto__ = o;"
8385 "proto = new Object();"
8386 "/* Make proto a slow-case object. */"
8387 "for (var i = 0; i < 1000; i++) {"
8388 " proto[\"xxxxxxxx\" + i] = [];"
8391 "o.__proto__ = proto;"
8393 "for (var i = 0; i < 1000; i++) {"
8394 " result += receiver.x;"
8398 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8402 // Test the case when we stored field into
8403 // a stub, but it got invalidated later on due to override on
8404 // global object which is between interceptor and fields' holders.
8405 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8406 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8407 "o.__proto__ = this;" // set a global to be a proto of o.
8408 "this.__proto__.y = 239;"
8409 "for (var i = 0; i < 10; i++) {"
8410 " if (o.y != 239) throw 'oops: ' + o.y;"
8411 // Now it should be ICed and keep a reference to y defined on field_holder.
8413 "this.y = 42;" // Assign on a global.
8415 "for (var i = 0; i < 10; i++) {"
8423 static void SetOnThis(Local<String> name,
8425 const AccessorInfo& info) {
8426 info.This()->ForceSet(name, value);
8430 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8431 v8::HandleScope scope;
8432 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8433 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8434 templ->SetAccessor(v8_str("y"), Return239);
8435 LocalContext context;
8436 context->Global()->Set(v8_str("o"), templ->NewInstance());
8438 // Check the case when receiver and interceptor's holder
8439 // are the same objects.
8440 v8::Handle<Value> value = CompileRun(
8442 "for (var i = 0; i < 7; i++) {"
8445 CHECK_EQ(239, value->Int32Value());
8447 // Check the case when interceptor's holder is in proto chain
8450 "r = { __proto__: o };"
8452 "for (var i = 0; i < 7; i++) {"
8455 CHECK_EQ(239, value->Int32Value());
8459 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8460 v8::HandleScope scope;
8461 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8462 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8463 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8464 templ_p->SetAccessor(v8_str("y"), Return239);
8466 LocalContext context;
8467 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8468 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8470 // Check the case when receiver and interceptor's holder
8471 // are the same objects.
8472 v8::Handle<Value> value = CompileRun(
8475 "for (var i = 0; i < 7; i++) {"
8476 " result = o.x + o.y;"
8478 CHECK_EQ(239 + 42, value->Int32Value());
8480 // Check the case when interceptor's holder is in proto chain
8483 "r = { __proto__: o };"
8485 "for (var i = 0; i < 7; i++) {"
8486 " result = r.x + r.y;"
8488 CHECK_EQ(239 + 42, value->Int32Value());
8492 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8493 v8::HandleScope scope;
8494 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8495 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8496 templ->SetAccessor(v8_str("y"), Return239);
8498 LocalContext context;
8499 context->Global()->Set(v8_str("o"), templ->NewInstance());
8501 v8::Handle<Value> value = CompileRun(
8502 "fst = new Object(); fst.__proto__ = o;"
8503 "snd = new Object(); snd.__proto__ = fst;"
8505 "for (var i = 0; i < 7; i++) {"
8510 "for (var i = 0; i < 7; i++) {"
8513 "result + result1");
8514 CHECK_EQ(239 + 42, value->Int32Value());
8518 // Test the case when we stored callback into
8519 // a stub, but interceptor produced value on its own.
8520 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8521 v8::HandleScope scope;
8522 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8523 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8524 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8525 templ_p->SetAccessor(v8_str("y"), Return239);
8527 LocalContext context;
8528 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8529 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8531 v8::Handle<Value> value = CompileRun(
8533 "for (var i = 0; i < 7; i++) {"
8535 // Now it should be ICed and keep a reference to x defined on p
8538 "for (var i = 0; i < 7; i++) {"
8542 CHECK_EQ(42 * 7, value->Int32Value());
8546 // Test the case when we stored callback into
8547 // a stub, but it got invalidated later on.
8548 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8549 v8::HandleScope scope;
8550 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8551 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8552 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8553 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8555 LocalContext context;
8556 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8557 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8559 v8::Handle<Value> value = CompileRun(
8560 "inbetween = new Object();"
8561 "o.__proto__ = inbetween;"
8562 "inbetween.__proto__ = p;"
8563 "for (var i = 0; i < 10; i++) {"
8565 // Now it should be ICed and keep a reference to y defined on p
8569 "for (var i = 0; i < 10; i++) {"
8573 CHECK_EQ(42 * 10, value->Int32Value());
8577 // Test the case when we stored callback into
8578 // a stub, but it got invalidated later on due to override on
8579 // global object which is between interceptor and callbacks' holders.
8580 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8581 v8::HandleScope scope;
8582 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8583 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8584 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8585 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8587 LocalContext context;
8588 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8589 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8591 v8::Handle<Value> value = CompileRun(
8592 "o.__proto__ = this;"
8593 "this.__proto__ = p;"
8594 "for (var i = 0; i < 10; i++) {"
8595 " if (o.y != 239) throw 'oops: ' + o.y;"
8596 // Now it should be ICed and keep a reference to y defined on p
8600 "for (var i = 0; i < 10; i++) {"
8604 CHECK_EQ(42 * 10, value->Int32Value());
8608 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8609 const AccessorInfo& info) {
8610 ApiTestFuzzer::Fuzz();
8611 CHECK(v8_str("x")->Equals(name));
8612 return v8::Integer::New(0);
8616 THREADED_TEST(InterceptorReturningZero) {
8617 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8618 "o.x == undefined ? 1 : 0",
8623 static v8::Handle<Value> InterceptorStoreICSetter(
8624 Local<String> key, Local<Value> value, const AccessorInfo&) {
8625 CHECK(v8_str("x")->Equals(key));
8626 CHECK_EQ(42, value->Int32Value());
8631 // This test should hit the store IC for the interceptor case.
8632 THREADED_TEST(InterceptorStoreIC) {
8633 v8::HandleScope scope;
8634 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8635 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
8636 InterceptorStoreICSetter,
8637 0, 0, 0, v8_str("data"));
8638 LocalContext context;
8639 context->Global()->Set(v8_str("o"), templ->NewInstance());
8640 v8::Handle<Value> value(CompileRun(
8641 "for (var i = 0; i < 1000; i++) {"
8647 THREADED_TEST(InterceptorStoreICWithNoSetter) {
8648 v8::HandleScope scope;
8649 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8650 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8651 LocalContext context;
8652 context->Global()->Set(v8_str("o"), templ->NewInstance());
8653 v8::Handle<Value> value = CompileRun(
8654 "for (var i = 0; i < 1000; i++) {"
8658 CHECK_EQ(239 + 42, value->Int32Value());
8664 v8::Handle<Value> call_ic_function;
8665 v8::Handle<Value> call_ic_function2;
8666 v8::Handle<Value> call_ic_function3;
8668 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8669 const AccessorInfo& info) {
8670 ApiTestFuzzer::Fuzz();
8671 CHECK(v8_str("x")->Equals(name));
8672 return call_ic_function;
8676 // This test should hit the call IC for the interceptor case.
8677 THREADED_TEST(InterceptorCallIC) {
8678 v8::HandleScope scope;
8679 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8680 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8681 LocalContext context;
8682 context->Global()->Set(v8_str("o"), templ->NewInstance());
8684 v8_compile("function f(x) { return x + 1; }; f")->Run();
8685 v8::Handle<Value> value = CompileRun(
8687 "for (var i = 0; i < 1000; i++) {"
8688 " result = o.x(41);"
8690 CHECK_EQ(42, value->Int32Value());
8694 // This test checks that if interceptor doesn't provide
8695 // a value, we can fetch regular value.
8696 THREADED_TEST(InterceptorCallICSeesOthers) {
8697 v8::HandleScope scope;
8698 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8699 templ->SetNamedPropertyHandler(NoBlockGetterX);
8700 LocalContext context;
8701 context->Global()->Set(v8_str("o"), templ->NewInstance());
8702 v8::Handle<Value> value = CompileRun(
8703 "o.x = function f(x) { return x + 1; };"
8705 "for (var i = 0; i < 7; i++) {"
8706 " result = o.x(41);"
8708 CHECK_EQ(42, value->Int32Value());
8712 static v8::Handle<Value> call_ic_function4;
8713 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8714 const AccessorInfo& info) {
8715 ApiTestFuzzer::Fuzz();
8716 CHECK(v8_str("x")->Equals(name));
8717 return call_ic_function4;
8721 // This test checks that if interceptor provides a function,
8722 // even if we cached shadowed variant, interceptor's function
8724 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8725 v8::HandleScope scope;
8726 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8727 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8728 LocalContext context;
8729 context->Global()->Set(v8_str("o"), templ->NewInstance());
8731 v8_compile("function f(x) { return x - 1; }; f")->Run();
8732 v8::Handle<Value> value = CompileRun(
8733 "o.__proto__.x = function(x) { return x + 1; };"
8735 "for (var i = 0; i < 1000; i++) {"
8736 " result = o.x(42);"
8738 CHECK_EQ(41, value->Int32Value());
8742 // Test the case when we stored cacheable lookup into
8743 // a stub, but it got invalidated later on
8744 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8745 v8::HandleScope scope;
8746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8747 templ->SetNamedPropertyHandler(NoBlockGetterX);
8748 LocalContext context;
8749 context->Global()->Set(v8_str("o"), templ->NewInstance());
8750 v8::Handle<Value> value = CompileRun(
8751 "proto1 = new Object();"
8752 "proto2 = new Object();"
8753 "o.__proto__ = proto1;"
8754 "proto1.__proto__ = proto2;"
8755 "proto2.y = function(x) { return x + 1; };"
8756 // Invoke it many times to compile a stub
8757 "for (var i = 0; i < 7; i++) {"
8760 "proto1.y = function(x) { return x - 1; };"
8762 "for (var i = 0; i < 7; i++) {"
8763 " result += o.y(42);"
8765 CHECK_EQ(41 * 7, value->Int32Value());
8769 static v8::Handle<Value> call_ic_function5;
8770 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8771 const AccessorInfo& info) {
8772 ApiTestFuzzer::Fuzz();
8773 if (v8_str("x")->Equals(name))
8774 return call_ic_function5;
8776 return Local<Value>();
8780 // This test checks that if interceptor doesn't provide a function,
8781 // cached constant function is used
8782 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8783 v8::HandleScope scope;
8784 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8785 templ->SetNamedPropertyHandler(NoBlockGetterX);
8786 LocalContext context;
8787 context->Global()->Set(v8_str("o"), templ->NewInstance());
8788 v8::Handle<Value> value = CompileRun(
8789 "function inc(x) { return x + 1; };"
8793 "for (var i = 0; i < 1000; i++) {"
8794 " result = o.x(42);"
8796 CHECK_EQ(43, value->Int32Value());
8800 // This test checks that if interceptor provides a function,
8801 // even if we cached constant function, interceptor's function
8803 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8804 v8::HandleScope scope;
8805 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8806 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8807 LocalContext context;
8808 context->Global()->Set(v8_str("o"), templ->NewInstance());
8810 v8_compile("function f(x) { return x - 1; }; f")->Run();
8811 v8::Handle<Value> value = CompileRun(
8812 "function inc(x) { return x + 1; };"
8816 "for (var i = 0; i < 1000; i++) {"
8817 " result = o.x(42);"
8819 CHECK_EQ(41, value->Int32Value());
8823 // Test the case when we stored constant function into
8824 // a stub, but it got invalidated later on
8825 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8826 v8::HandleScope scope;
8827 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8828 templ->SetNamedPropertyHandler(NoBlockGetterX);
8829 LocalContext context;
8830 context->Global()->Set(v8_str("o"), templ->NewInstance());
8831 v8::Handle<Value> value = CompileRun(
8832 "function inc(x) { return x + 1; };"
8834 "proto1 = new Object();"
8835 "proto2 = new Object();"
8836 "o.__proto__ = proto1;"
8837 "proto1.__proto__ = proto2;"
8839 // Invoke it many times to compile a stub
8840 "for (var i = 0; i < 7; i++) {"
8843 "proto1.y = function(x) { return x - 1; };"
8845 "for (var i = 0; i < 7; i++) {"
8846 " result += o.y(42);"
8848 CHECK_EQ(41 * 7, value->Int32Value());
8852 // Test the case when we stored constant function into
8853 // a stub, but it got invalidated later on due to override on
8854 // global object which is between interceptor and constant function' holders.
8855 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8856 v8::HandleScope scope;
8857 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8858 templ->SetNamedPropertyHandler(NoBlockGetterX);
8859 LocalContext context;
8860 context->Global()->Set(v8_str("o"), templ->NewInstance());
8861 v8::Handle<Value> value = CompileRun(
8862 "function inc(x) { return x + 1; };"
8864 "o.__proto__ = this;"
8865 "this.__proto__.y = inc;"
8866 // Invoke it many times to compile a stub
8867 "for (var i = 0; i < 7; i++) {"
8868 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8870 "this.y = function(x) { return x - 1; };"
8872 "for (var i = 0; i < 7; i++) {"
8873 " result += o.y(42);"
8875 CHECK_EQ(41 * 7, value->Int32Value());
8879 // Test the case when actual function to call sits on global object.
8880 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8881 v8::HandleScope scope;
8882 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8883 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8885 LocalContext context;
8886 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8888 v8::Handle<Value> value = CompileRun(
8890 " o.__proto__ = this;"
8891 " for (var i = 0; i < 10; i++) {"
8892 " var v = o.parseFloat('239');"
8893 " if (v != 239) throw v;"
8894 // Now it should be ICed and keep a reference to parseFloat.
8897 " for (var i = 0; i < 10; i++) {"
8898 " result += o.parseFloat('239');"
8904 CHECK_EQ(239 * 10, value->Int32Value());
8907 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8908 const AccessorInfo& info) {
8909 ApiTestFuzzer::Fuzz();
8910 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8912 if ((*call_count) % 20 == 0) {
8913 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8915 return v8::Handle<Value>();
8918 static v8::Handle<Value> FastApiCallback_TrivialSignature(
8919 const v8::Arguments& args) {
8920 ApiTestFuzzer::Fuzz();
8921 CHECK_EQ(args.This(), args.Holder());
8922 CHECK(args.Data()->Equals(v8_str("method_data")));
8923 return v8::Integer::New(args[0]->Int32Value() + 1);
8926 static v8::Handle<Value> FastApiCallback_SimpleSignature(
8927 const v8::Arguments& args) {
8928 ApiTestFuzzer::Fuzz();
8929 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8930 CHECK(args.Data()->Equals(v8_str("method_data")));
8931 // Note, we're using HasRealNamedProperty instead of Has to avoid
8932 // invoking the interceptor again.
8933 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8934 return v8::Integer::New(args[0]->Int32Value() + 1);
8937 // Helper to maximize the odds of object moving.
8938 static void GenerateSomeGarbage() {
8941 "for (var i = 0; i < 1000; i++) {"
8942 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8944 "garbage = undefined;");
8948 v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8949 static int count = 0;
8950 if (count++ % 3 == 0) {
8951 HEAP-> CollectAllGarbage(true); // This should move the stub
8952 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8954 return v8::Handle<v8::Value>();
8958 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8959 v8::HandleScope scope;
8960 LocalContext context;
8961 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8962 nativeobject_templ->Set("callback",
8963 v8::FunctionTemplate::New(DirectApiCallback));
8964 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8965 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8966 // call the api function multiple times to ensure direct call stub creation.
8969 " for (var i = 1; i <= 30; i++) {"
8970 " nativeobject.callback();"
8977 v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8978 return v8::ThrowException(v8_str("g"));
8982 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8983 v8::HandleScope scope;
8984 LocalContext context;
8985 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8986 nativeobject_templ->Set("callback",
8987 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8988 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8989 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8990 // call the api function multiple times to ensure direct call stub creation.
8991 v8::Handle<Value> result = CompileRun(
8994 " for (var i = 1; i <= 5; i++) {"
8995 " try { nativeobject.callback(); } catch (e) { result += e; }"
8999 CHECK_EQ(v8_str("ggggg"), result);
9003 v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9004 const v8::AccessorInfo& info) {
9005 if (++p_getter_count % 3 == 0) {
9006 HEAP->CollectAllGarbage(true);
9007 GenerateSomeGarbage();
9009 return v8::Handle<v8::Value>();
9013 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9014 v8::HandleScope scope;
9015 LocalContext context;
9016 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9017 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9018 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9022 " for (var i = 0; i < 30; i++) o1.p1;"
9025 CHECK_EQ(30, p_getter_count);
9029 v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9030 Local<String> name, const v8::AccessorInfo& info) {
9031 return v8::ThrowException(v8_str("g"));
9035 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9036 v8::HandleScope scope;
9037 LocalContext context;
9038 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9039 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9040 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9041 v8::Handle<Value> result = CompileRun(
9043 "for (var i = 0; i < 5; i++) {"
9044 " try { o1.p1; } catch (e) { result += e; }"
9047 CHECK_EQ(v8_str("ggggg"), result);
9051 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9052 int interceptor_call_count = 0;
9053 v8::HandleScope scope;
9054 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9055 v8::Handle<v8::FunctionTemplate> method_templ =
9056 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9057 v8_str("method_data"),
9058 v8::Handle<v8::Signature>());
9059 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9060 proto_templ->Set(v8_str("method"), method_templ);
9061 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9062 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9063 NULL, NULL, NULL, NULL,
9064 v8::External::Wrap(&interceptor_call_count));
9065 LocalContext context;
9066 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9067 GenerateSomeGarbage();
9068 context->Global()->Set(v8_str("o"), fun->NewInstance());
9069 v8::Handle<Value> value(CompileRun(
9071 "for (var i = 0; i < 100; i++) {"
9072 " result = o.method(41);"
9074 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9075 CHECK_EQ(100, interceptor_call_count);
9078 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9079 int interceptor_call_count = 0;
9080 v8::HandleScope scope;
9081 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9082 v8::Handle<v8::FunctionTemplate> method_templ =
9083 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9084 v8_str("method_data"),
9085 v8::Signature::New(fun_templ));
9086 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9087 proto_templ->Set(v8_str("method"), method_templ);
9088 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9089 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9090 NULL, NULL, NULL, NULL,
9091 v8::External::Wrap(&interceptor_call_count));
9092 LocalContext context;
9093 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9094 GenerateSomeGarbage();
9095 context->Global()->Set(v8_str("o"), fun->NewInstance());
9096 v8::Handle<Value> value(CompileRun(
9098 "var receiver = {};"
9099 "receiver.__proto__ = o;"
9101 "for (var i = 0; i < 100; i++) {"
9102 " result = receiver.method(41);"
9104 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9105 CHECK_EQ(100, interceptor_call_count);
9108 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9109 int interceptor_call_count = 0;
9110 v8::HandleScope scope;
9111 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9112 v8::Handle<v8::FunctionTemplate> method_templ =
9113 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9114 v8_str("method_data"),
9115 v8::Signature::New(fun_templ));
9116 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9117 proto_templ->Set(v8_str("method"), method_templ);
9118 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9119 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9120 NULL, NULL, NULL, NULL,
9121 v8::External::Wrap(&interceptor_call_count));
9122 LocalContext context;
9123 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9124 GenerateSomeGarbage();
9125 context->Global()->Set(v8_str("o"), fun->NewInstance());
9126 v8::Handle<Value> value(CompileRun(
9128 "var receiver = {};"
9129 "receiver.__proto__ = o;"
9131 "var saved_result = 0;"
9132 "for (var i = 0; i < 100; i++) {"
9133 " result = receiver.method(41);"
9135 " saved_result = result;"
9136 " receiver = {method: function(x) { return x - 1 }};"
9139 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9140 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9141 CHECK_GE(interceptor_call_count, 50);
9144 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9145 int interceptor_call_count = 0;
9146 v8::HandleScope scope;
9147 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9148 v8::Handle<v8::FunctionTemplate> method_templ =
9149 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9150 v8_str("method_data"),
9151 v8::Signature::New(fun_templ));
9152 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9153 proto_templ->Set(v8_str("method"), method_templ);
9154 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9155 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9156 NULL, NULL, NULL, NULL,
9157 v8::External::Wrap(&interceptor_call_count));
9158 LocalContext context;
9159 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9160 GenerateSomeGarbage();
9161 context->Global()->Set(v8_str("o"), fun->NewInstance());
9162 v8::Handle<Value> value(CompileRun(
9164 "var receiver = {};"
9165 "receiver.__proto__ = o;"
9167 "var saved_result = 0;"
9168 "for (var i = 0; i < 100; i++) {"
9169 " result = receiver.method(41);"
9171 " saved_result = result;"
9172 " o.method = function(x) { return x - 1 };"
9175 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9176 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9177 CHECK_GE(interceptor_call_count, 50);
9180 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9181 int interceptor_call_count = 0;
9182 v8::HandleScope scope;
9183 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9184 v8::Handle<v8::FunctionTemplate> method_templ =
9185 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9186 v8_str("method_data"),
9187 v8::Signature::New(fun_templ));
9188 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9189 proto_templ->Set(v8_str("method"), method_templ);
9190 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9191 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9192 NULL, NULL, NULL, NULL,
9193 v8::External::Wrap(&interceptor_call_count));
9194 LocalContext context;
9195 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9196 GenerateSomeGarbage();
9197 context->Global()->Set(v8_str("o"), fun->NewInstance());
9198 v8::TryCatch try_catch;
9199 v8::Handle<Value> value(CompileRun(
9201 "var receiver = {};"
9202 "receiver.__proto__ = o;"
9204 "var saved_result = 0;"
9205 "for (var i = 0; i < 100; i++) {"
9206 " result = receiver.method(41);"
9208 " saved_result = result;"
9212 CHECK(try_catch.HasCaught());
9213 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9214 try_catch.Exception()->ToString());
9215 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9216 CHECK_GE(interceptor_call_count, 50);
9219 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9220 int interceptor_call_count = 0;
9221 v8::HandleScope scope;
9222 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9223 v8::Handle<v8::FunctionTemplate> method_templ =
9224 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9225 v8_str("method_data"),
9226 v8::Signature::New(fun_templ));
9227 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9228 proto_templ->Set(v8_str("method"), method_templ);
9229 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9230 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9231 NULL, NULL, NULL, NULL,
9232 v8::External::Wrap(&interceptor_call_count));
9233 LocalContext context;
9234 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9235 GenerateSomeGarbage();
9236 context->Global()->Set(v8_str("o"), fun->NewInstance());
9237 v8::TryCatch try_catch;
9238 v8::Handle<Value> value(CompileRun(
9240 "var receiver = {};"
9241 "receiver.__proto__ = o;"
9243 "var saved_result = 0;"
9244 "for (var i = 0; i < 100; i++) {"
9245 " result = receiver.method(41);"
9247 " saved_result = result;"
9248 " receiver = {method: receiver.method};"
9251 CHECK(try_catch.HasCaught());
9252 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9253 try_catch.Exception()->ToString());
9254 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9255 CHECK_GE(interceptor_call_count, 50);
9258 THREADED_TEST(CallICFastApi_TrivialSignature) {
9259 v8::HandleScope scope;
9260 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9261 v8::Handle<v8::FunctionTemplate> method_templ =
9262 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9263 v8_str("method_data"),
9264 v8::Handle<v8::Signature>());
9265 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9266 proto_templ->Set(v8_str("method"), method_templ);
9267 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9268 LocalContext context;
9269 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9270 GenerateSomeGarbage();
9271 context->Global()->Set(v8_str("o"), fun->NewInstance());
9272 v8::Handle<Value> value(CompileRun(
9274 "for (var i = 0; i < 100; i++) {"
9275 " result = o.method(41);"
9278 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9281 THREADED_TEST(CallICFastApi_SimpleSignature) {
9282 v8::HandleScope scope;
9283 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9284 v8::Handle<v8::FunctionTemplate> method_templ =
9285 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9286 v8_str("method_data"),
9287 v8::Signature::New(fun_templ));
9288 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9289 proto_templ->Set(v8_str("method"), method_templ);
9290 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9291 LocalContext context;
9292 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9293 GenerateSomeGarbage();
9294 context->Global()->Set(v8_str("o"), fun->NewInstance());
9295 v8::Handle<Value> value(CompileRun(
9297 "var receiver = {};"
9298 "receiver.__proto__ = o;"
9300 "for (var i = 0; i < 100; i++) {"
9301 " result = receiver.method(41);"
9304 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9307 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9308 v8::HandleScope scope;
9309 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9310 v8::Handle<v8::FunctionTemplate> method_templ =
9311 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9312 v8_str("method_data"),
9313 v8::Signature::New(fun_templ));
9314 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9315 proto_templ->Set(v8_str("method"), method_templ);
9316 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9317 LocalContext context;
9318 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9319 GenerateSomeGarbage();
9320 context->Global()->Set(v8_str("o"), fun->NewInstance());
9321 v8::Handle<Value> value(CompileRun(
9323 "var receiver = {};"
9324 "receiver.__proto__ = o;"
9326 "var saved_result = 0;"
9327 "for (var i = 0; i < 100; i++) {"
9328 " result = receiver.method(41);"
9330 " saved_result = result;"
9331 " receiver = {method: function(x) { return x - 1 }};"
9334 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9335 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9338 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9339 v8::HandleScope scope;
9340 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9341 v8::Handle<v8::FunctionTemplate> method_templ =
9342 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9343 v8_str("method_data"),
9344 v8::Signature::New(fun_templ));
9345 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9346 proto_templ->Set(v8_str("method"), method_templ);
9347 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9348 LocalContext context;
9349 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9350 GenerateSomeGarbage();
9351 context->Global()->Set(v8_str("o"), fun->NewInstance());
9352 v8::TryCatch try_catch;
9353 v8::Handle<Value> value(CompileRun(
9355 "var receiver = {};"
9356 "receiver.__proto__ = o;"
9358 "var saved_result = 0;"
9359 "for (var i = 0; i < 100; i++) {"
9360 " result = receiver.method(41);"
9362 " saved_result = result;"
9366 CHECK(try_catch.HasCaught());
9367 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9368 try_catch.Exception()->ToString());
9369 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9373 v8::Handle<Value> keyed_call_ic_function;
9375 static v8::Handle<Value> InterceptorKeyedCallICGetter(
9376 Local<String> name, const AccessorInfo& info) {
9377 ApiTestFuzzer::Fuzz();
9378 if (v8_str("x")->Equals(name)) {
9379 return keyed_call_ic_function;
9381 return v8::Handle<Value>();
9385 // Test the case when we stored cacheable lookup into
9386 // a stub, but the function name changed (to another cacheable function).
9387 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9388 v8::HandleScope scope;
9389 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9390 templ->SetNamedPropertyHandler(NoBlockGetterX);
9391 LocalContext context;
9392 context->Global()->Set(v8_str("o"), templ->NewInstance());
9393 v8::Handle<Value> value(CompileRun(
9394 "proto = new Object();"
9395 "proto.y = function(x) { return x + 1; };"
9396 "proto.z = function(x) { return x - 1; };"
9397 "o.__proto__ = proto;"
9400 "for (var i = 0; i < 10; i++) {"
9401 " if (i == 5) { method = 'z'; };"
9402 " result += o[method](41);"
9404 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9408 // Test the case when we stored cacheable lookup into
9409 // a stub, but the function name changed (and the new function is present
9410 // both before and after the interceptor in the prototype chain).
9411 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9412 v8::HandleScope scope;
9413 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9414 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9415 LocalContext context;
9416 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9417 keyed_call_ic_function =
9418 v8_compile("function f(x) { return x - 1; }; f")->Run();
9419 v8::Handle<Value> value(CompileRun(
9421 "proto2 = new Object();"
9422 "o.y = function(x) { return x + 1; };"
9423 "proto2.y = function(x) { return x + 2; };"
9424 "o.__proto__ = proto1;"
9425 "proto1.__proto__ = proto2;"
9428 "for (var i = 0; i < 10; i++) {"
9429 " if (i == 5) { method = 'y'; };"
9430 " result += o[method](41);"
9432 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9436 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9437 // on the global object.
9438 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9439 v8::HandleScope scope;
9440 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9441 templ->SetNamedPropertyHandler(NoBlockGetterX);
9442 LocalContext context;
9443 context->Global()->Set(v8_str("o"), templ->NewInstance());
9444 v8::Handle<Value> value(CompileRun(
9445 "function inc(x) { return x + 1; };"
9447 "function dec(x) { return x - 1; };"
9449 "o.__proto__ = this;"
9450 "this.__proto__.x = inc;"
9451 "this.__proto__.y = dec;"
9454 "for (var i = 0; i < 10; i++) {"
9455 " if (i == 5) { method = 'y'; };"
9456 " result += o[method](41);"
9458 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9462 // Test the case when actual function to call sits on global object.
9463 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9464 v8::HandleScope scope;
9465 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9466 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9467 LocalContext context;
9468 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9470 v8::Handle<Value> value(CompileRun(
9471 "function len(x) { return x.length; };"
9472 "o.__proto__ = this;"
9473 "var m = 'parseFloat';"
9475 "for (var i = 0; i < 10; i++) {"
9478 " saved_result = result;"
9480 " result = o[m]('239');"
9482 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9483 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9486 // Test the map transition before the interceptor.
9487 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9488 v8::HandleScope scope;
9489 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9490 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9491 LocalContext context;
9492 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9494 v8::Handle<Value> value(CompileRun(
9495 "var o = new Object();"
9496 "o.__proto__ = proto;"
9497 "o.method = function(x) { return x + 1; };"
9500 "for (var i = 0; i < 10; i++) {"
9501 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9502 " result += o[m](41);"
9504 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9508 // Test the map transition after the interceptor.
9509 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9510 v8::HandleScope scope;
9511 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9512 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9513 LocalContext context;
9514 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9516 v8::Handle<Value> value(CompileRun(
9517 "var proto = new Object();"
9518 "o.__proto__ = proto;"
9519 "proto.method = function(x) { return x + 1; };"
9522 "for (var i = 0; i < 10; i++) {"
9523 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9524 " result += o[m](41);"
9526 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9530 static int interceptor_call_count = 0;
9532 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9533 const AccessorInfo& info) {
9534 ApiTestFuzzer::Fuzz();
9535 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9536 return call_ic_function2;
9538 return v8::Handle<Value>();
9542 // This test should hit load and call ICs for the interceptor case.
9543 // Once in a while, the interceptor will reply that a property was not
9544 // found in which case we should get a reference error.
9545 THREADED_TEST(InterceptorICReferenceErrors) {
9546 v8::HandleScope scope;
9547 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9548 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9549 LocalContext context(0, templ, v8::Handle<Value>());
9550 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9551 v8::Handle<Value> value = CompileRun(
9553 " for (var i = 0; i < 1000; i++) {"
9554 " try { x; } catch(e) { return true; }"
9559 CHECK_EQ(true, value->BooleanValue());
9560 interceptor_call_count = 0;
9563 " for (var i = 0; i < 1000; i++) {"
9564 " try { x(42); } catch(e) { return true; }"
9569 CHECK_EQ(true, value->BooleanValue());
9573 static int interceptor_ic_exception_get_count = 0;
9575 static v8::Handle<Value> InterceptorICExceptionGetter(
9577 const AccessorInfo& info) {
9578 ApiTestFuzzer::Fuzz();
9579 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9580 return call_ic_function3;
9582 if (interceptor_ic_exception_get_count == 20) {
9583 return v8::ThrowException(v8_num(42));
9585 // Do not handle get for properties other than x.
9586 return v8::Handle<Value>();
9589 // Test interceptor load/call IC where the interceptor throws an
9590 // exception once in a while.
9591 THREADED_TEST(InterceptorICGetterExceptions) {
9592 interceptor_ic_exception_get_count = 0;
9593 v8::HandleScope scope;
9594 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9595 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9596 LocalContext context(0, templ, v8::Handle<Value>());
9597 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9598 v8::Handle<Value> value = CompileRun(
9600 " for (var i = 0; i < 100; i++) {"
9601 " try { x; } catch(e) { return true; }"
9606 CHECK_EQ(true, value->BooleanValue());
9607 interceptor_ic_exception_get_count = 0;
9610 " for (var i = 0; i < 100; i++) {"
9611 " try { x(42); } catch(e) { return true; }"
9616 CHECK_EQ(true, value->BooleanValue());
9620 static int interceptor_ic_exception_set_count = 0;
9622 static v8::Handle<Value> InterceptorICExceptionSetter(
9623 Local<String> key, Local<Value> value, const AccessorInfo&) {
9624 ApiTestFuzzer::Fuzz();
9625 if (++interceptor_ic_exception_set_count > 20) {
9626 return v8::ThrowException(v8_num(42));
9628 // Do not actually handle setting.
9629 return v8::Handle<Value>();
9632 // Test interceptor store IC where the interceptor throws an exception
9634 THREADED_TEST(InterceptorICSetterExceptions) {
9635 interceptor_ic_exception_set_count = 0;
9636 v8::HandleScope scope;
9637 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9638 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9639 LocalContext context(0, templ, v8::Handle<Value>());
9640 v8::Handle<Value> value = CompileRun(
9642 " for (var i = 0; i < 100; i++) {"
9643 " try { x = 42; } catch(e) { return true; }"
9648 CHECK_EQ(true, value->BooleanValue());
9652 // Test that we ignore null interceptors.
9653 THREADED_TEST(NullNamedInterceptor) {
9654 v8::HandleScope scope;
9655 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9656 templ->SetNamedPropertyHandler(0);
9657 LocalContext context;
9658 templ->Set("x", v8_num(42));
9659 v8::Handle<v8::Object> obj = templ->NewInstance();
9660 context->Global()->Set(v8_str("obj"), obj);
9661 v8::Handle<Value> value = CompileRun("obj.x");
9662 CHECK(value->IsInt32());
9663 CHECK_EQ(42, value->Int32Value());
9667 // Test that we ignore null interceptors.
9668 THREADED_TEST(NullIndexedInterceptor) {
9669 v8::HandleScope scope;
9670 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9671 templ->SetIndexedPropertyHandler(0);
9672 LocalContext context;
9673 templ->Set("42", v8_num(42));
9674 v8::Handle<v8::Object> obj = templ->NewInstance();
9675 context->Global()->Set(v8_str("obj"), obj);
9676 v8::Handle<Value> value = CompileRun("obj[42]");
9677 CHECK(value->IsInt32());
9678 CHECK_EQ(42, value->Int32Value());
9682 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9683 v8::HandleScope scope;
9684 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9685 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9687 env->Global()->Set(v8_str("obj"),
9688 templ->GetFunction()->NewInstance());
9689 ExpectTrue("obj.x === 42");
9690 ExpectTrue("!obj.propertyIsEnumerable('x')");
9694 static Handle<Value> ThrowingGetter(Local<String> name,
9695 const AccessorInfo& info) {
9696 ApiTestFuzzer::Fuzz();
9697 ThrowException(Handle<Value>());
9702 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9704 LocalContext context;
9706 Local<FunctionTemplate> templ = FunctionTemplate::New();
9707 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9708 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9710 Local<Object> instance = templ->GetFunction()->NewInstance();
9712 Local<Object> another = Object::New();
9713 another->SetPrototype(instance);
9715 Local<Object> with_js_getter = CompileRun(
9717 "o.__defineGetter__('f', function() { throw undefined; });\n"
9718 "o\n").As<Object>();
9719 CHECK(!with_js_getter.IsEmpty());
9723 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9724 CHECK(try_catch.HasCaught());
9726 CHECK(result.IsEmpty());
9728 result = another->GetRealNamedProperty(v8_str("f"));
9729 CHECK(try_catch.HasCaught());
9731 CHECK(result.IsEmpty());
9733 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9734 CHECK(try_catch.HasCaught());
9736 CHECK(result.IsEmpty());
9738 result = another->Get(v8_str("f"));
9739 CHECK(try_catch.HasCaught());
9741 CHECK(result.IsEmpty());
9743 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9744 CHECK(try_catch.HasCaught());
9746 CHECK(result.IsEmpty());
9748 result = with_js_getter->Get(v8_str("f"));
9749 CHECK(try_catch.HasCaught());
9751 CHECK(result.IsEmpty());
9755 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9757 // Verboseness is important: it triggers message delivery which can call into
9759 try_catch.SetVerbose(true);
9760 CompileRun("throw 'from JS';");
9761 CHECK(try_catch.HasCaught());
9762 CHECK(!i::Isolate::Current()->has_pending_exception());
9763 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9768 static int call_depth;
9771 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9776 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9777 if (--call_depth) CompileRun("throw 'ThrowInJS';");
9781 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9782 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9786 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9787 Handle<String> errorMessageString = message->Get();
9788 CHECK(!errorMessageString.IsEmpty());
9789 message->GetStackTrace();
9790 message->GetScriptResourceName();
9793 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9795 LocalContext context;
9797 Local<Function> func =
9798 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9799 context->Global()->Set(v8_str("func"), func);
9801 MessageCallback callbacks[] =
9802 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9803 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9804 MessageCallback callback = callbacks[i];
9805 if (callback != NULL) {
9806 V8::AddMessageListener(callback);
9808 // Some small number to control number of times message handler should
9809 // throw an exception.
9812 "var thrown = false;\n"
9813 "try { func(); } catch(e) { thrown = true; }\n"
9815 if (callback != NULL) {
9816 V8::RemoveMessageListeners(callback);
9822 static v8::Handle<Value> ParentGetter(Local<String> name,
9823 const AccessorInfo& info) {
9824 ApiTestFuzzer::Fuzz();
9829 static v8::Handle<Value> ChildGetter(Local<String> name,
9830 const AccessorInfo& info) {
9831 ApiTestFuzzer::Fuzz();
9836 THREADED_TEST(Overriding) {
9837 v8::HandleScope scope;
9838 LocalContext context;
9841 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9842 Local<ObjectTemplate> parent_instance_templ =
9843 parent_templ->InstanceTemplate();
9844 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9846 // Template that inherits from the parent template.
9847 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9848 Local<ObjectTemplate> child_instance_templ =
9849 child_templ->InstanceTemplate();
9850 child_templ->Inherit(parent_templ);
9851 // Override 'f'. The child version of 'f' should get called for child
9853 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9854 // Add 'g' twice. The 'g' added last should get called for instances.
9855 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9856 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9858 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9859 // so 'h' can be shadowed on the instance object.
9860 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9861 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9862 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9864 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9865 // but the attribute does not have effect because it is duplicated with
9867 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9868 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9872 // Instantiate the child template.
9873 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9875 // Check that the child function overrides the parent one.
9876 context->Global()->Set(v8_str("o"), instance);
9877 Local<Value> value = v8_compile("o.f")->Run();
9878 // Check that the 'g' that was added last is hit.
9879 CHECK_EQ(42, value->Int32Value());
9880 value = v8_compile("o.g")->Run();
9881 CHECK_EQ(42, value->Int32Value());
9883 // Check 'h' can be shadowed.
9884 value = v8_compile("o.h = 3; o.h")->Run();
9885 CHECK_EQ(3, value->Int32Value());
9887 // Check 'i' is cannot be shadowed or changed.
9888 value = v8_compile("o.i = 3; o.i")->Run();
9889 CHECK_EQ(42, value->Int32Value());
9893 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9894 ApiTestFuzzer::Fuzz();
9895 return v8::Boolean::New(args.IsConstructCall());
9899 THREADED_TEST(IsConstructCall) {
9900 v8::HandleScope scope;
9902 // Function template with call handler.
9903 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9904 templ->SetCallHandler(IsConstructHandler);
9906 LocalContext context;
9908 context->Global()->Set(v8_str("f"), templ->GetFunction());
9909 Local<Value> value = v8_compile("f()")->Run();
9910 CHECK(!value->BooleanValue());
9911 value = v8_compile("new f()")->Run();
9912 CHECK(value->BooleanValue());
9916 THREADED_TEST(ObjectProtoToString) {
9917 v8::HandleScope scope;
9918 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9919 templ->SetClassName(v8_str("MyClass"));
9921 LocalContext context;
9923 Local<String> customized_tostring = v8_str("customized toString");
9925 // Replace Object.prototype.toString
9926 v8_compile("Object.prototype.toString = function() {"
9927 " return 'customized toString';"
9930 // Normal ToString call should call replaced Object.prototype.toString
9931 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9932 Local<String> value = instance->ToString();
9933 CHECK(value->IsString() && value->Equals(customized_tostring));
9935 // ObjectProtoToString should not call replace toString function.
9936 value = instance->ObjectProtoToString();
9937 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9940 value = context->Global()->ObjectProtoToString();
9941 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9943 // Check ordinary object
9944 Local<Value> object = v8_compile("new Object()")->Run();
9945 value = object.As<v8::Object>()->ObjectProtoToString();
9946 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9950 THREADED_TEST(ObjectGetConstructorName) {
9951 v8::HandleScope scope;
9952 LocalContext context;
9953 v8_compile("function Parent() {};"
9954 "function Child() {};"
9955 "Child.prototype = new Parent();"
9956 "var outer = { inner: function() { } };"
9957 "var p = new Parent();"
9958 "var c = new Child();"
9959 "var x = new outer.inner();")->Run();
9961 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9962 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9965 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9966 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9969 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9970 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9971 v8_str("outer.inner")));
9975 bool ApiTestFuzzer::fuzzing_ = false;
9976 i::Semaphore* ApiTestFuzzer::all_tests_done_=
9977 i::OS::CreateSemaphore(0);
9978 int ApiTestFuzzer::active_tests_;
9979 int ApiTestFuzzer::tests_being_run_;
9980 int ApiTestFuzzer::current_;
9983 // We are in a callback and want to switch to another thread (if we
9984 // are currently running the thread fuzzing test).
9985 void ApiTestFuzzer::Fuzz() {
9986 if (!fuzzing_) return;
9987 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9988 test->ContextSwitch();
9992 // Let the next thread go. Since it is also waiting on the V8 lock it may
9993 // not start immediately.
9994 bool ApiTestFuzzer::NextThread() {
9995 int test_position = GetNextTestNumber();
9996 const char* test_name = RegisterThreadedTest::nth(current_)->name();
9997 if (test_position == current_) {
9999 printf("Stay with %s\n", test_name);
10002 if (kLogThreading) {
10003 printf("Switch from %s to %s\n",
10005 RegisterThreadedTest::nth(test_position)->name());
10007 current_ = test_position;
10008 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10013 void ApiTestFuzzer::Run() {
10014 // When it is our turn...
10017 // ... get the V8 lock and start running the test.
10021 // This test finished.
10024 // If it was the last then signal that fact.
10025 if (active_tests_ == 0) {
10026 all_tests_done_->Signal();
10028 // Otherwise select a new test and start that.
10034 static unsigned linear_congruential_generator;
10037 void ApiTestFuzzer::Setup(PartOfTest part) {
10038 linear_congruential_generator = i::FLAG_testing_prng_seed;
10040 int count = RegisterThreadedTest::count();
10041 int start = count * part / (LAST_PART + 1);
10042 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10043 active_tests_ = tests_being_run_ = end - start + 1;
10044 for (int i = 0; i < tests_being_run_; i++) {
10045 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10047 for (int i = 0; i < active_tests_; i++) {
10048 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10053 static void CallTestNumber(int test_number) {
10054 (RegisterThreadedTest::nth(test_number)->callback())();
10058 void ApiTestFuzzer::RunAllTests() {
10059 // Set off the first test.
10062 // Wait till they are all done.
10063 all_tests_done_->Wait();
10067 int ApiTestFuzzer::GetNextTestNumber() {
10070 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10071 linear_congruential_generator *= 1664525u;
10072 linear_congruential_generator += 1013904223u;
10073 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10078 void ApiTestFuzzer::ContextSwitch() {
10079 // If the new thread is the same as the current thread there is nothing to do.
10080 if (NextThread()) {
10081 // Now it can start.
10082 v8::Unlocker unlocker;
10083 // Wait till someone starts us again.
10090 void ApiTestFuzzer::TearDown() {
10092 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10093 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10094 if (fuzzer != NULL) fuzzer->Join();
10099 // Lets not be needlessly self-referential.
10101 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
10102 ApiTestFuzzer::RunAllTests();
10103 ApiTestFuzzer::TearDown();
10107 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
10108 ApiTestFuzzer::RunAllTests();
10109 ApiTestFuzzer::TearDown();
10113 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
10114 ApiTestFuzzer::RunAllTests();
10115 ApiTestFuzzer::TearDown();
10119 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
10120 ApiTestFuzzer::RunAllTests();
10121 ApiTestFuzzer::TearDown();
10124 void ApiTestFuzzer::CallTest() {
10126 printf("Start test %d\n", test_number_);
10127 CallTestNumber(test_number_);
10129 printf("End test %d\n", test_number_);
10133 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10134 CHECK(v8::Locker::IsLocked());
10135 ApiTestFuzzer::Fuzz();
10136 v8::Unlocker unlocker;
10137 const char* code = "throw 7;";
10139 v8::Locker nested_locker;
10140 v8::HandleScope scope;
10141 v8::Handle<Value> exception;
10142 { v8::TryCatch try_catch;
10143 v8::Handle<Value> value = CompileRun(code);
10144 CHECK(value.IsEmpty());
10145 CHECK(try_catch.HasCaught());
10146 // Make sure to wrap the exception in a new handle because
10147 // the handle returned from the TryCatch is destroyed
10148 // when the TryCatch is destroyed.
10149 exception = Local<Value>::New(try_catch.Exception());
10151 return v8::ThrowException(exception);
10156 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10157 CHECK(v8::Locker::IsLocked());
10158 ApiTestFuzzer::Fuzz();
10159 v8::Unlocker unlocker;
10160 const char* code = "throw 7;";
10162 v8::Locker nested_locker;
10163 v8::HandleScope scope;
10164 v8::Handle<Value> value = CompileRun(code);
10165 CHECK(value.IsEmpty());
10166 return v8_str("foo");
10171 // These are locking tests that don't need to be run again
10172 // as part of the locking aggregation tests.
10173 TEST(NestedLockers) {
10175 CHECK(v8::Locker::IsLocked());
10176 v8::HandleScope scope;
10178 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10179 Local<Function> fun = fun_templ->GetFunction();
10180 env->Global()->Set(v8_str("throw_in_js"), fun);
10181 Local<Script> script = v8_compile("(function () {"
10189 CHECK_EQ(91, script->Run()->Int32Value());
10193 // These are locking tests that don't need to be run again
10194 // as part of the locking aggregation tests.
10195 TEST(NestedLockersNoTryCatch) {
10197 v8::HandleScope scope;
10199 Local<v8::FunctionTemplate> fun_templ =
10200 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10201 Local<Function> fun = fun_templ->GetFunction();
10202 env->Global()->Set(v8_str("throw_in_js"), fun);
10203 Local<Script> script = v8_compile("(function () {"
10211 CHECK_EQ(91, script->Run()->Int32Value());
10215 THREADED_TEST(RecursiveLocking) {
10218 v8::Locker locker2;
10219 CHECK(v8::Locker::IsLocked());
10224 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10225 ApiTestFuzzer::Fuzz();
10226 v8::Unlocker unlocker;
10227 return v8::Undefined();
10231 THREADED_TEST(LockUnlockLock) {
10234 v8::HandleScope scope;
10236 Local<v8::FunctionTemplate> fun_templ =
10237 v8::FunctionTemplate::New(UnlockForAMoment);
10238 Local<Function> fun = fun_templ->GetFunction();
10239 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10240 Local<Script> script = v8_compile("(function () {"
10241 " unlock_for_a_moment();"
10244 CHECK_EQ(42, script->Run()->Int32Value());
10248 v8::HandleScope scope;
10250 Local<v8::FunctionTemplate> fun_templ =
10251 v8::FunctionTemplate::New(UnlockForAMoment);
10252 Local<Function> fun = fun_templ->GetFunction();
10253 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10254 Local<Script> script = v8_compile("(function () {"
10255 " unlock_for_a_moment();"
10258 CHECK_EQ(42, script->Run()->Int32Value());
10263 static int GetGlobalObjectsCount() {
10264 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10266 i::HeapIterator it;
10267 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10268 if (object->IsJSGlobalObject()) count++;
10273 static void CheckSurvivingGlobalObjectsCount(int expected) {
10274 // We need to collect all garbage twice to be sure that everything
10275 // has been collected. This is because inline caches are cleared in
10276 // the first garbage collection but some of the maps have already
10277 // been marked at that point. Therefore some of the maps are not
10278 // collected until the second garbage collection.
10279 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10280 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10281 int count = GetGlobalObjectsCount();
10283 if (count != expected) HEAP->TracePathToGlobal();
10285 CHECK_EQ(expected, count);
10289 TEST(DontLeakGlobalObjects) {
10290 // Regression test for issues 1139850 and 1174891.
10292 v8::V8::Initialize();
10294 for (int i = 0; i < 5; i++) {
10295 { v8::HandleScope scope;
10296 LocalContext context;
10298 CheckSurvivingGlobalObjectsCount(0);
10300 { v8::HandleScope scope;
10301 LocalContext context;
10302 v8_compile("Date")->Run();
10304 CheckSurvivingGlobalObjectsCount(0);
10306 { v8::HandleScope scope;
10307 LocalContext context;
10308 v8_compile("/aaa/")->Run();
10310 CheckSurvivingGlobalObjectsCount(0);
10312 { v8::HandleScope scope;
10313 const char* extension_list[] = { "v8/gc" };
10314 v8::ExtensionConfiguration extensions(1, extension_list);
10315 LocalContext context(&extensions);
10316 v8_compile("gc();")->Run();
10318 CheckSurvivingGlobalObjectsCount(0);
10323 v8::Persistent<v8::Object> some_object;
10324 v8::Persistent<v8::Object> bad_handle;
10326 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10327 v8::HandleScope scope;
10328 bad_handle = v8::Persistent<v8::Object>::New(some_object);
10333 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10334 LocalContext context;
10336 v8::Persistent<v8::Object> handle1, handle2;
10338 v8::HandleScope scope;
10339 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10340 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10341 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10343 // Note: order is implementation dependent alas: currently
10344 // global handle nodes are processed by PostGarbageCollectionProcessing
10345 // in reverse allocation order, so if second allocated handle is deleted,
10346 // weak callback of the first handle would be able to 'reallocate' it.
10347 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10349 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10353 v8::Persistent<v8::Object> to_be_disposed;
10355 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10356 to_be_disposed.Dispose();
10357 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10362 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10363 LocalContext context;
10365 v8::Persistent<v8::Object> handle1, handle2;
10367 v8::HandleScope scope;
10368 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10369 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10371 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10372 to_be_disposed = handle2;
10373 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10376 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10380 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10381 v8::HandleScope scope;
10382 v8::Persistent<v8::Object>::New(v8::Object::New());
10387 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10388 LocalContext context;
10390 v8::Persistent<v8::Object> handle1, handle2, handle3;
10392 v8::HandleScope scope;
10393 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10394 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10395 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10397 handle2.MakeWeak(NULL, DisposingCallback);
10398 handle3.MakeWeak(NULL, HandleCreatingCallback);
10399 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10403 THREADED_TEST(CheckForCrossContextObjectLiterals) {
10404 v8::V8::Initialize();
10407 const char* sources[nof] = {
10408 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10412 for (int i = 0; i < nof; i++) {
10413 const char* source = sources[i];
10414 { v8::HandleScope scope;
10415 LocalContext context;
10416 CompileRun(source);
10418 { v8::HandleScope scope;
10419 LocalContext context;
10420 CompileRun(source);
10426 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10427 v8::HandleScope inner;
10429 v8::Handle<Value> three = v8_num(3);
10430 v8::Handle<Value> value = inner.Close(three);
10436 THREADED_TEST(NestedHandleScopeAndContexts) {
10437 v8::HandleScope outer;
10438 v8::Persistent<Context> env = Context::New();
10440 v8::Handle<Value> value = NestedScope(env);
10441 v8::Handle<String> str(value->ToString());
10447 THREADED_TEST(ExternalAllocatedMemory) {
10448 v8::HandleScope outer;
10449 v8::Persistent<Context> env(Context::New());
10450 const int kSize = 1024*1024;
10451 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10452 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10456 THREADED_TEST(DisposeEnteredContext) {
10457 v8::HandleScope scope;
10458 LocalContext outer;
10459 { v8::Persistent<v8::Context> inner = v8::Context::New();
10468 // Regression test for issue 54, object templates with internal fields
10469 // but no accessors or interceptors did not get their internal field
10470 // count set on instances.
10471 THREADED_TEST(Regress54) {
10472 v8::HandleScope outer;
10473 LocalContext context;
10474 static v8::Persistent<v8::ObjectTemplate> templ;
10475 if (templ.IsEmpty()) {
10476 v8::HandleScope inner;
10477 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10478 local->SetInternalFieldCount(1);
10479 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10481 v8::Handle<v8::Object> result = templ->NewInstance();
10482 CHECK_EQ(1, result->InternalFieldCount());
10486 // If part of the threaded tests, this test makes ThreadingTest fail
10488 TEST(CatchStackOverflow) {
10489 v8::HandleScope scope;
10490 LocalContext context;
10491 v8::TryCatch try_catch;
10492 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10498 v8::Handle<v8::Value> result = script->Run();
10499 CHECK(result.IsEmpty());
10503 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10504 const char* resource_name,
10506 v8::HandleScope scope;
10507 v8::TryCatch try_catch;
10508 v8::Handle<v8::Value> result = script->Run();
10509 CHECK(result.IsEmpty());
10510 CHECK(try_catch.HasCaught());
10511 v8::Handle<v8::Message> message = try_catch.Message();
10512 CHECK(!message.IsEmpty());
10513 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10514 CHECK_EQ(91, message->GetStartPosition());
10515 CHECK_EQ(92, message->GetEndPosition());
10516 CHECK_EQ(2, message->GetStartColumn());
10517 CHECK_EQ(3, message->GetEndColumn());
10518 v8::String::AsciiValue line(message->GetSourceLine());
10519 CHECK_EQ(" throw 'nirk';", *line);
10520 v8::String::AsciiValue name(message->GetScriptResourceName());
10521 CHECK_EQ(resource_name, *name);
10525 THREADED_TEST(TryCatchSourceInfo) {
10526 v8::HandleScope scope;
10527 LocalContext context;
10528 v8::Handle<v8::String> source = v8::String::New(
10529 "function Foo() {\n"
10533 "function Bar() {\n"
10537 "function Baz() {\n"
10543 const char* resource_name;
10544 v8::Handle<v8::Script> script;
10545 resource_name = "test.js";
10546 script = v8::Script::Compile(source, v8::String::New(resource_name));
10547 CheckTryCatchSourceInfo(script, resource_name, 0);
10549 resource_name = "test1.js";
10550 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10551 script = v8::Script::Compile(source, &origin1);
10552 CheckTryCatchSourceInfo(script, resource_name, 0);
10554 resource_name = "test2.js";
10555 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10556 script = v8::Script::Compile(source, &origin2);
10557 CheckTryCatchSourceInfo(script, resource_name, 7);
10561 THREADED_TEST(CompilationCache) {
10562 v8::HandleScope scope;
10563 LocalContext context;
10564 v8::Handle<v8::String> source0 = v8::String::New("1234");
10565 v8::Handle<v8::String> source1 = v8::String::New("1234");
10566 v8::Handle<v8::Script> script0 =
10567 v8::Script::Compile(source0, v8::String::New("test.js"));
10568 v8::Handle<v8::Script> script1 =
10569 v8::Script::Compile(source1, v8::String::New("test.js"));
10570 v8::Handle<v8::Script> script2 =
10571 v8::Script::Compile(source0); // different origin
10572 CHECK_EQ(1234, script0->Run()->Int32Value());
10573 CHECK_EQ(1234, script1->Run()->Int32Value());
10574 CHECK_EQ(1234, script2->Run()->Int32Value());
10578 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10579 ApiTestFuzzer::Fuzz();
10584 THREADED_TEST(CallbackFunctionName) {
10585 v8::HandleScope scope;
10586 LocalContext context;
10587 Local<ObjectTemplate> t = ObjectTemplate::New();
10588 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10589 context->Global()->Set(v8_str("obj"), t->NewInstance());
10590 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10591 CHECK(value->IsString());
10592 v8::String::AsciiValue name(value);
10593 CHECK_EQ("asdf", *name);
10597 THREADED_TEST(DateAccess) {
10598 v8::HandleScope scope;
10599 LocalContext context;
10600 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10601 CHECK(date->IsDate());
10602 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
10606 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
10607 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10608 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10609 CHECK_EQ(elmc, props->Length());
10610 for (int i = 0; i < elmc; i++) {
10611 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10612 CHECK_EQ(elmv[i], *elm);
10617 void CheckOwnProperties(v8::Handle<v8::Value> val,
10619 const char* elmv[]) {
10620 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10621 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10622 CHECK_EQ(elmc, props->Length());
10623 for (int i = 0; i < elmc; i++) {
10624 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10625 CHECK_EQ(elmv[i], *elm);
10630 THREADED_TEST(PropertyEnumeration) {
10631 v8::HandleScope scope;
10632 LocalContext context;
10633 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10636 "result[1] = {a: 1, b: 2};"
10637 "result[2] = [1, 2, 3];"
10638 "var proto = {x: 1, y: 2, z: 3};"
10639 "var x = { __proto__: proto, w: 0, z: 1 };"
10641 "result;"))->Run();
10642 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10643 CHECK_EQ(4, elms->Length());
10645 const char** elmv0 = NULL;
10646 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10647 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10649 const char* elmv1[] = {"a", "b"};
10650 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10651 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10653 const char* elmv2[] = {"0", "1", "2"};
10654 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10655 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10657 const char* elmv3[] = {"w", "z", "x", "y"};
10658 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
10660 const char* elmv4[] = {"w", "z"};
10661 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
10664 THREADED_TEST(PropertyEnumeration2) {
10665 v8::HandleScope scope;
10666 LocalContext context;
10667 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10670 "result[1] = {a: 1, b: 2};"
10671 "result[2] = [1, 2, 3];"
10672 "var proto = {x: 1, y: 2, z: 3};"
10673 "var x = { __proto__: proto, w: 0, z: 1 };"
10675 "result;"))->Run();
10676 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10677 CHECK_EQ(4, elms->Length());
10679 const char** elmv0 = NULL;
10680 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10682 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10683 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10684 CHECK_EQ(0, props->Length());
10685 for (uint32_t i = 0; i < props->Length(); i++) {
10686 printf("p[%d]\n", i);
10690 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10692 v8::AccessType type,
10693 Local<Value> data) {
10694 return type != v8::ACCESS_SET;
10698 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10700 v8::AccessType type,
10701 Local<Value> data) {
10702 return type != v8::ACCESS_SET;
10706 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10707 v8::HandleScope scope;
10708 LocalContext context;
10709 Local<ObjectTemplate> templ = ObjectTemplate::New();
10710 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10711 IndexedSetAccessBlocker);
10712 templ->Set(v8_str("x"), v8::True());
10713 Local<v8::Object> instance = templ->NewInstance();
10714 context->Global()->Set(v8_str("obj"), instance);
10715 Local<Value> value = CompileRun("obj.x");
10716 CHECK(value->BooleanValue());
10720 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10722 v8::AccessType type,
10723 Local<Value> data) {
10728 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10730 v8::AccessType type,
10731 Local<Value> data) {
10737 THREADED_TEST(AccessChecksReenabledCorrectly) {
10738 v8::HandleScope scope;
10739 LocalContext context;
10740 Local<ObjectTemplate> templ = ObjectTemplate::New();
10741 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10742 IndexedGetAccessBlocker);
10743 templ->Set(v8_str("a"), v8_str("a"));
10744 // Add more than 8 (see kMaxFastProperties) properties
10745 // so that the constructor will force copying map.
10746 // Cannot sprintf, gcc complains unsafety.
10748 for (char i = '0'; i <= '9' ; i++) {
10750 for (char j = '0'; j <= '9'; j++) {
10752 for (char k = '0'; k <= '9'; k++) {
10755 templ->Set(v8_str(buf), v8::Number::New(k));
10760 Local<v8::Object> instance_1 = templ->NewInstance();
10761 context->Global()->Set(v8_str("obj_1"), instance_1);
10763 Local<Value> value_1 = CompileRun("obj_1.a");
10764 CHECK(value_1->IsUndefined());
10766 Local<v8::Object> instance_2 = templ->NewInstance();
10767 context->Global()->Set(v8_str("obj_2"), instance_2);
10769 Local<Value> value_2 = CompileRun("obj_2.a");
10770 CHECK(value_2->IsUndefined());
10774 // This tests that access check information remains on the global
10775 // object template when creating contexts.
10776 THREADED_TEST(AccessControlRepeatedContextCreation) {
10777 v8::HandleScope handle_scope;
10778 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10779 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10780 IndexedSetAccessBlocker);
10781 i::Handle<i::ObjectTemplateInfo> internal_template =
10782 v8::Utils::OpenHandle(*global_template);
10783 CHECK(!internal_template->constructor()->IsUndefined());
10784 i::Handle<i::FunctionTemplateInfo> constructor(
10785 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10786 CHECK(!constructor->access_check_info()->IsUndefined());
10787 v8::Persistent<Context> context0(Context::New(NULL, global_template));
10788 CHECK(!constructor->access_check_info()->IsUndefined());
10792 THREADED_TEST(TurnOnAccessCheck) {
10793 v8::HandleScope handle_scope;
10795 // Create an environment with access check to the global object disabled by
10797 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10798 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10799 IndexedGetAccessBlocker,
10800 v8::Handle<v8::Value>(),
10802 v8::Persistent<Context> context = Context::New(NULL, global_template);
10803 Context::Scope context_scope(context);
10805 // Set up a property and a number of functions.
10806 context->Global()->Set(v8_str("a"), v8_num(1));
10807 CompileRun("function f1() {return a;}"
10808 "function f2() {return a;}"
10809 "function g1() {return h();}"
10810 "function g2() {return h();}"
10811 "function h() {return 1;}");
10812 Local<Function> f1 =
10813 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10814 Local<Function> f2 =
10815 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10816 Local<Function> g1 =
10817 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10818 Local<Function> g2 =
10819 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10820 Local<Function> h =
10821 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10823 // Get the global object.
10824 v8::Handle<v8::Object> global = context->Global();
10826 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10827 // uses the runtime system to retreive property a whereas f2 uses global load
10829 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10830 for (int i = 0; i < 4; i++) {
10831 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10834 // Same for g1 and g2.
10835 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10836 for (int i = 0; i < 4; i++) {
10837 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10840 // Detach the global and turn on access check.
10841 context->DetachGlobal();
10842 context->Global()->TurnOnAccessCheck();
10844 // Failing access check to property get results in undefined.
10845 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10846 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10848 // Failing access check to function call results in exception.
10849 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10850 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10852 // No failing access check when just returning a constant.
10853 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10857 v8::Handle<v8::String> a;
10858 v8::Handle<v8::String> h;
10860 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10862 v8::AccessType type,
10863 Local<Value> data) {
10864 return !(name->Equals(a) || name->Equals(h));
10868 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10869 v8::HandleScope handle_scope;
10871 // Create an environment with access check to the global object disabled by
10872 // default. When the registered access checker will block access to properties
10876 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10877 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10878 IndexedGetAccessBlocker,
10879 v8::Handle<v8::Value>(),
10881 v8::Persistent<Context> context = Context::New(NULL, global_template);
10882 Context::Scope context_scope(context);
10884 // Set up a property and a number of functions.
10885 context->Global()->Set(v8_str("a"), v8_num(1));
10886 static const char* source = "function f1() {return a;}"
10887 "function f2() {return a;}"
10888 "function g1() {return h();}"
10889 "function g2() {return h();}"
10890 "function h() {return 1;}";
10892 CompileRun(source);
10893 Local<Function> f1;
10894 Local<Function> f2;
10895 Local<Function> g1;
10896 Local<Function> g2;
10898 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10899 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10900 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10901 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10902 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10904 // Get the global object.
10905 v8::Handle<v8::Object> global = context->Global();
10907 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10908 // uses the runtime system to retreive property a whereas f2 uses global load
10910 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10911 for (int i = 0; i < 4; i++) {
10912 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10915 // Same for g1 and g2.
10916 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10917 for (int i = 0; i < 4; i++) {
10918 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10921 // Detach the global and turn on access check now blocking access to property
10922 // a and function h.
10923 context->DetachGlobal();
10924 context->Global()->TurnOnAccessCheck();
10926 // Failing access check to property get results in undefined.
10927 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10928 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10930 // Failing access check to function call results in exception.
10931 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10932 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10934 // No failing access check when just returning a constant.
10935 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10937 // Now compile the source again. And get the newly compiled functions, except
10938 // for h for which access is blocked.
10939 CompileRun(source);
10940 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10941 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10942 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10943 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10944 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10946 // Failing access check to property get results in undefined.
10947 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10948 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10950 // Failing access check to function call results in exception.
10951 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10952 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10956 // This test verifies that pre-compilation (aka preparsing) can be called
10957 // without initializing the whole VM. Thus we cannot run this test in a
10958 // multi-threaded setup.
10960 // TODO(155): This test would break without the initialization of V8. This is
10961 // a workaround for now to make this test not fail.
10962 v8::V8::Initialize();
10963 const char* script = "function foo(a) { return a+1; }";
10964 v8::ScriptData* sd =
10965 v8::ScriptData::PreCompile(script, i::StrLength(script));
10966 CHECK_NE(sd->Length(), 0);
10967 CHECK_NE(sd->Data(), NULL);
10968 CHECK(!sd->HasError());
10973 TEST(PreCompileWithError) {
10974 v8::V8::Initialize();
10975 const char* script = "function foo(a) { return 1 * * 2; }";
10976 v8::ScriptData* sd =
10977 v8::ScriptData::PreCompile(script, i::StrLength(script));
10978 CHECK(sd->HasError());
10983 TEST(Regress31661) {
10984 v8::V8::Initialize();
10985 const char* script = " The Definintive Guide";
10986 v8::ScriptData* sd =
10987 v8::ScriptData::PreCompile(script, i::StrLength(script));
10988 CHECK(sd->HasError());
10993 // Tests that ScriptData can be serialized and deserialized.
10994 TEST(PreCompileSerialization) {
10995 v8::V8::Initialize();
10996 const char* script = "function foo(a) { return a+1; }";
10997 v8::ScriptData* sd =
10998 v8::ScriptData::PreCompile(script, i::StrLength(script));
11001 int serialized_data_length = sd->Length();
11002 char* serialized_data = i::NewArray<char>(serialized_data_length);
11003 memcpy(serialized_data, sd->Data(), serialized_data_length);
11006 v8::ScriptData* deserialized_sd =
11007 v8::ScriptData::New(serialized_data, serialized_data_length);
11009 // Verify that the original is the same as the deserialized.
11010 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11011 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11012 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11015 delete deserialized_sd;
11019 // Attempts to deserialize bad data.
11020 TEST(PreCompileDeserializationError) {
11021 v8::V8::Initialize();
11022 const char* data = "DONT CARE";
11023 int invalid_size = 3;
11024 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11026 CHECK_EQ(0, sd->Length());
11032 // Attempts to deserialize bad data.
11033 TEST(PreCompileInvalidPreparseDataError) {
11034 v8::V8::Initialize();
11035 v8::HandleScope scope;
11036 LocalContext context;
11038 const char* script = "function foo(){ return 5;}\n"
11039 "function bar(){ return 6 + 7;} foo();";
11040 v8::ScriptData* sd =
11041 v8::ScriptData::PreCompile(script, i::StrLength(script));
11042 CHECK(!sd->HasError());
11043 // ScriptDataImpl private implementation details
11044 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11045 const int kFunctionEntrySize = i::FunctionEntry::kSize;
11046 const int kFunctionEntryStartOffset = 0;
11047 const int kFunctionEntryEndOffset = 1;
11048 unsigned* sd_data =
11049 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11051 // Overwrite function bar's end position with 0.
11052 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11053 v8::TryCatch try_catch;
11055 Local<String> source = String::New(script);
11056 Local<Script> compiled_script = Script::New(source, NULL, sd);
11057 CHECK(try_catch.HasCaught());
11058 String::AsciiValue exception_value(try_catch.Message()->Get());
11059 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11064 // Overwrite function bar's start position with 200. The function entry
11065 // will not be found when searching for it by position and we should fall
11066 // back on eager compilation.
11067 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11068 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11069 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11071 compiled_script = Script::New(source, NULL, sd);
11072 CHECK(!try_catch.HasCaught());
11078 // Verifies that the Handle<String> and const char* versions of the API produce
11079 // the same results (at least for one trivial case).
11080 TEST(PreCompileAPIVariationsAreSame) {
11081 v8::V8::Initialize();
11082 v8::HandleScope scope;
11084 const char* cstring = "function foo(a) { return a+1; }";
11086 v8::ScriptData* sd_from_cstring =
11087 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11089 TestAsciiResource* resource = new TestAsciiResource(cstring);
11090 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
11091 v8::String::NewExternal(resource));
11093 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11094 v8::String::New(cstring));
11096 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
11097 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11098 sd_from_external_string->Data(),
11099 sd_from_cstring->Length()));
11101 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11102 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11103 sd_from_string->Data(),
11104 sd_from_cstring->Length()));
11107 delete sd_from_cstring;
11108 delete sd_from_external_string;
11109 delete sd_from_string;
11113 // This tests that we do not allow dictionary load/call inline caches
11114 // to use functions that have not yet been compiled. The potential
11115 // problem of loading a function that has not yet been compiled can
11116 // arise because we share code between contexts via the compilation
11118 THREADED_TEST(DictionaryICLoadedFunction) {
11119 v8::HandleScope scope;
11121 for (int i = 0; i < 2; i++) {
11122 LocalContext context;
11123 context->Global()->Set(v8_str("tmp"), v8::True());
11124 context->Global()->Delete(v8_str("tmp"));
11125 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11128 for (int i = 0; i < 2; i++) {
11129 LocalContext context;
11130 context->Global()->Set(v8_str("tmp"), v8::True());
11131 context->Global()->Delete(v8_str("tmp"));
11132 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11137 // Test that cross-context new calls use the context of the callee to
11138 // create the new JavaScript object.
11139 THREADED_TEST(CrossContextNew) {
11140 v8::HandleScope scope;
11141 v8::Persistent<Context> context0 = Context::New();
11142 v8::Persistent<Context> context1 = Context::New();
11144 // Allow cross-domain access.
11145 Local<String> token = v8_str("<security token>");
11146 context0->SetSecurityToken(token);
11147 context1->SetSecurityToken(token);
11149 // Set an 'x' property on the Object prototype and define a
11150 // constructor function in context0.
11152 CompileRun("Object.prototype.x = 42; function C() {};");
11155 // Call the constructor function from context0 and check that the
11156 // result has the 'x' property.
11158 context1->Global()->Set(v8_str("other"), context0->Global());
11159 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11160 CHECK(value->IsInt32());
11161 CHECK_EQ(42, value->Int32Value());
11164 // Dispose the contexts to allow them to be garbage collected.
11165 context0.Dispose();
11166 context1.Dispose();
11170 class RegExpInterruptTest {
11172 RegExpInterruptTest() : block_(NULL) {}
11173 ~RegExpInterruptTest() { delete block_; }
11175 block_ = i::OS::CreateSemaphore(0);
11177 gc_during_regexp_ = 0;
11178 regexp_success_ = false;
11179 gc_success_ = false;
11180 GCThread gc_thread(this);
11182 v8::Locker::StartPreemption(1);
11184 LongRunningRegExp();
11186 v8::Unlocker unlock;
11189 v8::Locker::StopPreemption();
11190 CHECK(regexp_success_);
11191 CHECK(gc_success_);
11195 // Number of garbage collections required.
11196 static const int kRequiredGCs = 5;
11198 class GCThread : public i::Thread {
11200 explicit GCThread(RegExpInterruptTest* test)
11201 : Thread("GCThread"), test_(test) {}
11202 virtual void Run() {
11203 test_->CollectGarbage();
11206 RegExpInterruptTest* test_;
11209 void CollectGarbage() {
11211 while (gc_during_regexp_ < kRequiredGCs) {
11214 // TODO(lrn): Perhaps create some garbage before collecting.
11215 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11220 gc_success_ = true;
11223 void LongRunningRegExp() {
11224 block_->Signal(); // Enable garbage collection thread on next preemption.
11226 while (gc_during_regexp_ < kRequiredGCs) {
11227 int gc_before = gc_count_;
11229 // Match 15-30 "a"'s against 14 and a "b".
11230 const char* c_source =
11231 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11232 ".exec('aaaaaaaaaaaaaaab') === null";
11233 Local<String> source = String::New(c_source);
11234 Local<Script> script = Script::Compile(source);
11235 Local<Value> result = script->Run();
11236 if (!result->BooleanValue()) {
11237 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
11242 // Match 15-30 "a"'s against 15 and a "b".
11243 const char* c_source =
11244 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11245 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11246 Local<String> source = String::New(c_source);
11247 Local<Script> script = Script::Compile(source);
11248 Local<Value> result = script->Run();
11249 if (!result->BooleanValue()) {
11250 gc_during_regexp_ = kRequiredGCs;
11254 int gc_after = gc_count_;
11255 gc_during_regexp_ += gc_after - gc_before;
11259 regexp_success_ = true;
11262 i::Semaphore* block_;
11264 int gc_during_regexp_;
11265 bool regexp_success_;
11270 // Test that a regular expression execution can be interrupted and
11271 // survive a garbage collection.
11272 TEST(RegExpInterruption) {
11274 v8::V8::Initialize();
11275 v8::HandleScope scope;
11276 Local<Context> local_env;
11279 local_env = env.local();
11282 // Local context should still be live.
11283 CHECK(!local_env.IsEmpty());
11284 local_env->Enter();
11286 // Should complete without problems.
11287 RegExpInterruptTest().RunTest();
11293 class ApplyInterruptTest {
11295 ApplyInterruptTest() : block_(NULL) {}
11296 ~ApplyInterruptTest() { delete block_; }
11298 block_ = i::OS::CreateSemaphore(0);
11300 gc_during_apply_ = 0;
11301 apply_success_ = false;
11302 gc_success_ = false;
11303 GCThread gc_thread(this);
11305 v8::Locker::StartPreemption(1);
11307 LongRunningApply();
11309 v8::Unlocker unlock;
11312 v8::Locker::StopPreemption();
11313 CHECK(apply_success_);
11314 CHECK(gc_success_);
11318 // Number of garbage collections required.
11319 static const int kRequiredGCs = 2;
11321 class GCThread : public i::Thread {
11323 explicit GCThread(ApplyInterruptTest* test)
11324 : Thread("GCThread"), test_(test) {}
11325 virtual void Run() {
11326 test_->CollectGarbage();
11329 ApplyInterruptTest* test_;
11332 void CollectGarbage() {
11334 while (gc_during_apply_ < kRequiredGCs) {
11337 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11342 gc_success_ = true;
11345 void LongRunningApply() {
11348 while (gc_during_apply_ < kRequiredGCs) {
11349 int gc_before = gc_count_;
11351 const char* c_source =
11352 "function do_very_little(bar) {"
11355 "for (var i = 0; i < 100000; i++) {"
11356 " do_very_little.apply(this, ['bar']);"
11358 Local<String> source = String::New(c_source);
11359 Local<Script> script = Script::Compile(source);
11360 Local<Value> result = script->Run();
11361 // Check that no exception was thrown.
11362 CHECK(!result.IsEmpty());
11364 int gc_after = gc_count_;
11365 gc_during_apply_ += gc_after - gc_before;
11368 apply_success_ = true;
11371 i::Semaphore* block_;
11373 int gc_during_apply_;
11374 bool apply_success_;
11379 // Test that nothing bad happens if we get a preemption just when we were
11380 // about to do an apply().
11381 TEST(ApplyInterruption) {
11383 v8::V8::Initialize();
11384 v8::HandleScope scope;
11385 Local<Context> local_env;
11388 local_env = env.local();
11391 // Local context should still be live.
11392 CHECK(!local_env.IsEmpty());
11393 local_env->Enter();
11395 // Should complete without problems.
11396 ApplyInterruptTest().RunTest();
11402 // Verify that we can clone an object
11403 TEST(ObjectClone) {
11404 v8::HandleScope scope;
11407 const char* sample =
11409 "rv.alpha = 'hello';" \
11413 // Create an object, verify basics.
11414 Local<Value> val = CompileRun(sample);
11415 CHECK(val->IsObject());
11416 Local<v8::Object> obj = val.As<v8::Object>();
11417 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11419 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11420 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11421 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11424 Local<v8::Object> clone = obj->Clone();
11425 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11426 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11427 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11429 // Set a property on the clone, verify each object.
11430 clone->Set(v8_str("beta"), v8::Integer::New(456));
11431 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11432 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11436 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11438 explicit AsciiVectorResource(i::Vector<const char> vector)
11440 virtual ~AsciiVectorResource() {}
11441 virtual size_t length() const { return data_.length(); }
11442 virtual const char* data() const { return data_.start(); }
11444 i::Vector<const char> data_;
11448 class UC16VectorResource : public v8::String::ExternalStringResource {
11450 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11452 virtual ~UC16VectorResource() {}
11453 virtual size_t length() const { return data_.length(); }
11454 virtual const i::uc16* data() const { return data_.start(); }
11456 i::Vector<const i::uc16> data_;
11460 static void MorphAString(i::String* string,
11461 AsciiVectorResource* ascii_resource,
11462 UC16VectorResource* uc16_resource) {
11463 CHECK(i::StringShape(string).IsExternal());
11464 if (string->IsAsciiRepresentation()) {
11465 // Check old map is not symbol or long.
11466 CHECK(string->map() == HEAP->external_ascii_string_map());
11467 // Morph external string to be TwoByte string.
11468 string->set_map(HEAP->external_string_map());
11469 i::ExternalTwoByteString* morphed =
11470 i::ExternalTwoByteString::cast(string);
11471 morphed->set_resource(uc16_resource);
11473 // Check old map is not symbol or long.
11474 CHECK(string->map() == HEAP->external_string_map());
11475 // Morph external string to be ASCII string.
11476 string->set_map(HEAP->external_ascii_string_map());
11477 i::ExternalAsciiString* morphed =
11478 i::ExternalAsciiString::cast(string);
11479 morphed->set_resource(ascii_resource);
11484 // Test that we can still flatten a string if the components it is built up
11485 // from have been turned into 16 bit strings in the mean time.
11486 THREADED_TEST(MorphCompositeStringTest) {
11487 char utf_buffer[129];
11488 const char* c_string = "Now is the time for all good men"
11489 " to come to the aid of the party";
11490 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11492 v8::HandleScope scope;
11494 AsciiVectorResource ascii_resource(
11495 i::Vector<const char>(c_string, i::StrLength(c_string)));
11496 UC16VectorResource uc16_resource(
11497 i::Vector<const uint16_t>(two_byte_string,
11498 i::StrLength(c_string)));
11500 Local<String> lhs(v8::Utils::ToLocal(
11501 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11502 Local<String> rhs(v8::Utils::ToLocal(
11503 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11505 env->Global()->Set(v8_str("lhs"), lhs);
11506 env->Global()->Set(v8_str("rhs"), rhs);
11509 "var cons = lhs + rhs;"
11510 "var slice = lhs.substring(1, lhs.length - 1);"
11511 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11513 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11514 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11516 // This should UTF-8 without flattening, since everything is ASCII.
11517 Handle<String> cons = v8_compile("cons")->Run().As<String>();
11518 CHECK_EQ(128, cons->Utf8Length());
11520 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11521 CHECK_EQ(128, nchars);
11522 CHECK_EQ(0, strcmp(
11524 "Now is the time for all good men to come to the aid of the party"
11525 "Now is the time for all good men to come to the aid of the party"));
11527 // Now do some stuff to make sure the strings are flattened, etc.
11529 "/[^a-z]/.test(cons);"
11530 "/[^a-z]/.test(slice);"
11531 "/[^a-z]/.test(slice_on_cons);");
11532 const char* expected_cons =
11533 "Now is the time for all good men to come to the aid of the party"
11534 "Now is the time for all good men to come to the aid of the party";
11535 const char* expected_slice =
11536 "ow is the time for all good men to come to the aid of the part";
11537 const char* expected_slice_on_cons =
11538 "ow is the time for all good men to come to the aid of the party"
11539 "Now is the time for all good men to come to the aid of the part";
11540 CHECK_EQ(String::New(expected_cons),
11541 env->Global()->Get(v8_str("cons")));
11542 CHECK_EQ(String::New(expected_slice),
11543 env->Global()->Get(v8_str("slice")));
11544 CHECK_EQ(String::New(expected_slice_on_cons),
11545 env->Global()->Get(v8_str("slice_on_cons")));
11547 i::DeleteArray(two_byte_string);
11551 TEST(CompileExternalTwoByteSource) {
11552 v8::HandleScope scope;
11553 LocalContext context;
11555 // This is a very short list of sources, which currently is to check for a
11556 // regression caused by r2703.
11557 const char* ascii_sources[] = {
11559 "-0.5", // This mainly testes PushBack in the Scanner.
11560 "--0.5", // This mainly testes PushBack in the Scanner.
11564 // Compile the sources as external two byte strings.
11565 for (int i = 0; ascii_sources[i] != NULL; i++) {
11566 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11567 UC16VectorResource uc16_resource(
11568 i::Vector<const uint16_t>(two_byte_string,
11569 i::StrLength(ascii_sources[i])));
11570 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11571 v8::Script::Compile(source);
11572 i::DeleteArray(two_byte_string);
11577 class RegExpStringModificationTest {
11579 RegExpStringModificationTest()
11580 : block_(i::OS::CreateSemaphore(0)),
11582 morphs_during_regexp_(0),
11583 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11584 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11585 ~RegExpStringModificationTest() { delete block_; }
11587 regexp_success_ = false;
11588 morph_success_ = false;
11590 // Initialize the contents of two_byte_content_ to be a uc16 representation
11591 // of "aaaaaaaaaaaaaab".
11592 for (int i = 0; i < 14; i++) {
11593 two_byte_content_[i] = 'a';
11595 two_byte_content_[14] = 'b';
11597 // Create the input string for the regexp - the one we are going to change
11599 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
11601 // Inject the input as a global variable.
11602 i::Handle<i::String> input_name =
11603 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11604 i::Isolate::Current()->global_context()->global()->SetProperty(
11608 i::kNonStrictMode)->ToObjectChecked();
11610 MorphThread morph_thread(this);
11611 morph_thread.Start();
11612 v8::Locker::StartPreemption(1);
11613 LongRunningRegExp();
11615 v8::Unlocker unlock;
11616 morph_thread.Join();
11618 v8::Locker::StopPreemption();
11619 CHECK(regexp_success_);
11620 CHECK(morph_success_);
11624 // Number of string modifications required.
11625 static const int kRequiredModifications = 5;
11626 static const int kMaxModifications = 100;
11628 class MorphThread : public i::Thread {
11630 explicit MorphThread(RegExpStringModificationTest* test)
11631 : Thread("MorphThread"), test_(test) {}
11632 virtual void Run() {
11633 test_->MorphString();
11636 RegExpStringModificationTest* test_;
11639 void MorphString() {
11641 while (morphs_during_regexp_ < kRequiredModifications &&
11642 morphs_ < kMaxModifications) {
11645 // Swap string between ascii and two-byte representation.
11646 i::String* string = *input_;
11647 MorphAString(string, &ascii_resource_, &uc16_resource_);
11652 morph_success_ = true;
11655 void LongRunningRegExp() {
11656 block_->Signal(); // Enable morphing thread on next preemption.
11657 while (morphs_during_regexp_ < kRequiredModifications &&
11658 morphs_ < kMaxModifications) {
11659 int morphs_before = morphs_;
11661 v8::HandleScope scope;
11662 // Match 15-30 "a"'s against 14 and a "b".
11663 const char* c_source =
11664 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11665 ".exec(input) === null";
11666 Local<String> source = String::New(c_source);
11667 Local<Script> script = Script::Compile(source);
11668 Local<Value> result = script->Run();
11669 CHECK(result->IsTrue());
11671 int morphs_after = morphs_;
11672 morphs_during_regexp_ += morphs_after - morphs_before;
11674 regexp_success_ = true;
11677 i::uc16 two_byte_content_[15];
11678 i::Semaphore* block_;
11680 int morphs_during_regexp_;
11681 bool regexp_success_;
11682 bool morph_success_;
11683 i::Handle<i::String> input_;
11684 AsciiVectorResource ascii_resource_;
11685 UC16VectorResource uc16_resource_;
11689 // Test that a regular expression execution can be interrupted and
11690 // the string changed without failing.
11691 TEST(RegExpStringModification) {
11693 v8::V8::Initialize();
11694 v8::HandleScope scope;
11695 Local<Context> local_env;
11698 local_env = env.local();
11701 // Local context should still be live.
11702 CHECK(!local_env.IsEmpty());
11703 local_env->Enter();
11705 // Should complete without problems.
11706 RegExpStringModificationTest().RunTest();
11712 // Test that we can set a property on the global object even if there
11713 // is a read-only property in the prototype chain.
11714 TEST(ReadOnlyPropertyInGlobalProto) {
11715 v8::HandleScope scope;
11716 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11717 LocalContext context(0, templ);
11718 v8::Handle<v8::Object> global = context->Global();
11719 v8::Handle<v8::Object> global_proto =
11720 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11721 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11722 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11723 // Check without 'eval' or 'with'.
11724 v8::Handle<v8::Value> res =
11725 CompileRun("function f() { x = 42; return x; }; f()");
11726 // Check with 'eval'.
11727 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11728 CHECK_EQ(v8::Integer::New(42), res);
11729 // Check with 'with'.
11730 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11731 CHECK_EQ(v8::Integer::New(42), res);
11734 static int force_set_set_count = 0;
11735 static int force_set_get_count = 0;
11736 bool pass_on_get = false;
11738 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11739 const v8::AccessorInfo& info) {
11740 force_set_get_count++;
11742 return v8::Handle<v8::Value>();
11744 return v8::Int32::New(3);
11748 static void ForceSetSetter(v8::Local<v8::String> name,
11749 v8::Local<v8::Value> value,
11750 const v8::AccessorInfo& info) {
11751 force_set_set_count++;
11754 static v8::Handle<v8::Value> ForceSetInterceptSetter(
11755 v8::Local<v8::String> name,
11756 v8::Local<v8::Value> value,
11757 const v8::AccessorInfo& info) {
11758 force_set_set_count++;
11759 return v8::Undefined();
11763 force_set_get_count = 0;
11764 force_set_set_count = 0;
11765 pass_on_get = false;
11767 v8::HandleScope scope;
11768 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11769 v8::Handle<v8::String> access_property = v8::String::New("a");
11770 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11771 LocalContext context(NULL, templ);
11772 v8::Handle<v8::Object> global = context->Global();
11774 // Ordinary properties
11775 v8::Handle<v8::String> simple_property = v8::String::New("p");
11776 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11777 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11778 // This should fail because the property is read-only
11779 global->Set(simple_property, v8::Int32::New(5));
11780 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11781 // This should succeed even though the property is read-only
11782 global->ForceSet(simple_property, v8::Int32::New(6));
11783 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11786 CHECK_EQ(0, force_set_set_count);
11787 CHECK_EQ(0, force_set_get_count);
11788 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11789 // CHECK_EQ the property shouldn't override it, just call the setter
11790 // which in this case does nothing.
11791 global->Set(access_property, v8::Int32::New(7));
11792 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11793 CHECK_EQ(1, force_set_set_count);
11794 CHECK_EQ(2, force_set_get_count);
11795 // Forcing the property to be set should override the accessor without
11797 global->ForceSet(access_property, v8::Int32::New(8));
11798 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11799 CHECK_EQ(1, force_set_set_count);
11800 CHECK_EQ(2, force_set_get_count);
11803 TEST(ForceSetWithInterceptor) {
11804 force_set_get_count = 0;
11805 force_set_set_count = 0;
11806 pass_on_get = false;
11808 v8::HandleScope scope;
11809 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11810 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11811 LocalContext context(NULL, templ);
11812 v8::Handle<v8::Object> global = context->Global();
11814 v8::Handle<v8::String> some_property = v8::String::New("a");
11815 CHECK_EQ(0, force_set_set_count);
11816 CHECK_EQ(0, force_set_get_count);
11817 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11818 // Setting the property shouldn't override it, just call the setter
11819 // which in this case does nothing.
11820 global->Set(some_property, v8::Int32::New(7));
11821 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11822 CHECK_EQ(1, force_set_set_count);
11823 CHECK_EQ(2, force_set_get_count);
11824 // Getting the property when the interceptor returns an empty handle
11825 // should yield undefined, since the property isn't present on the
11826 // object itself yet.
11827 pass_on_get = true;
11828 CHECK(global->Get(some_property)->IsUndefined());
11829 CHECK_EQ(1, force_set_set_count);
11830 CHECK_EQ(3, force_set_get_count);
11831 // Forcing the property to be set should cause the value to be
11832 // set locally without calling the interceptor.
11833 global->ForceSet(some_property, v8::Int32::New(8));
11834 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11835 CHECK_EQ(1, force_set_set_count);
11836 CHECK_EQ(4, force_set_get_count);
11837 // Reenabling the interceptor should cause it to take precedence over
11839 pass_on_get = false;
11840 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11841 CHECK_EQ(1, force_set_set_count);
11842 CHECK_EQ(5, force_set_get_count);
11843 // The interceptor should also work for other properties
11844 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11845 CHECK_EQ(1, force_set_set_count);
11846 CHECK_EQ(6, force_set_get_count);
11850 THREADED_TEST(ForceDelete) {
11851 v8::HandleScope scope;
11852 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11853 LocalContext context(NULL, templ);
11854 v8::Handle<v8::Object> global = context->Global();
11856 // Ordinary properties
11857 v8::Handle<v8::String> simple_property = v8::String::New("p");
11858 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11859 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11860 // This should fail because the property is dont-delete.
11861 CHECK(!global->Delete(simple_property));
11862 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11863 // This should succeed even though the property is dont-delete.
11864 CHECK(global->ForceDelete(simple_property));
11865 CHECK(global->Get(simple_property)->IsUndefined());
11869 static int force_delete_interceptor_count = 0;
11870 static bool pass_on_delete = false;
11873 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11874 v8::Local<v8::String> name,
11875 const v8::AccessorInfo& info) {
11876 force_delete_interceptor_count++;
11877 if (pass_on_delete) {
11878 return v8::Handle<v8::Boolean>();
11885 THREADED_TEST(ForceDeleteWithInterceptor) {
11886 force_delete_interceptor_count = 0;
11887 pass_on_delete = false;
11889 v8::HandleScope scope;
11890 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11891 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11892 LocalContext context(NULL, templ);
11893 v8::Handle<v8::Object> global = context->Global();
11895 v8::Handle<v8::String> some_property = v8::String::New("a");
11896 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11898 // Deleting a property should get intercepted and nothing should
11900 CHECK_EQ(0, force_delete_interceptor_count);
11901 CHECK(global->Delete(some_property));
11902 CHECK_EQ(1, force_delete_interceptor_count);
11903 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11904 // Deleting the property when the interceptor returns an empty
11905 // handle should not delete the property since it is DontDelete.
11906 pass_on_delete = true;
11907 CHECK(!global->Delete(some_property));
11908 CHECK_EQ(2, force_delete_interceptor_count);
11909 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11910 // Forcing the property to be deleted should delete the value
11911 // without calling the interceptor.
11912 CHECK(global->ForceDelete(some_property));
11913 CHECK(global->Get(some_property)->IsUndefined());
11914 CHECK_EQ(2, force_delete_interceptor_count);
11918 // Make sure that forcing a delete invalidates any IC stubs, so we
11919 // don't read the hole value.
11920 THREADED_TEST(ForceDeleteIC) {
11921 v8::HandleScope scope;
11922 LocalContext context;
11923 // Create a DontDelete variable on the global object.
11924 CompileRun("this.__proto__ = { foo: 'horse' };"
11925 "var foo = 'fish';"
11926 "function f() { return foo.length; }");
11927 // Initialize the IC for foo in f.
11928 CompileRun("for (var i = 0; i < 4; i++) f();");
11929 // Make sure the value of foo is correct before the deletion.
11930 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11931 // Force the deletion of foo.
11932 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11933 // Make sure the value for foo is read from the prototype, and that
11934 // we don't get in trouble with reading the deleted cell value
11936 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11940 v8::Persistent<Context> calling_context0;
11941 v8::Persistent<Context> calling_context1;
11942 v8::Persistent<Context> calling_context2;
11945 // Check that the call to the callback is initiated in
11946 // calling_context2, the directly calling context is calling_context1
11947 // and the callback itself is in calling_context0.
11948 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11949 ApiTestFuzzer::Fuzz();
11950 CHECK(Context::GetCurrent() == calling_context0);
11951 CHECK(Context::GetCalling() == calling_context1);
11952 CHECK(Context::GetEntered() == calling_context2);
11953 return v8::Integer::New(42);
11957 THREADED_TEST(GetCallingContext) {
11958 v8::HandleScope scope;
11960 calling_context0 = Context::New();
11961 calling_context1 = Context::New();
11962 calling_context2 = Context::New();
11964 // Allow cross-domain access.
11965 Local<String> token = v8_str("<security token>");
11966 calling_context0->SetSecurityToken(token);
11967 calling_context1->SetSecurityToken(token);
11968 calling_context2->SetSecurityToken(token);
11970 // Create an object with a C++ callback in context0.
11971 calling_context0->Enter();
11972 Local<v8::FunctionTemplate> callback_templ =
11973 v8::FunctionTemplate::New(GetCallingContextCallback);
11974 calling_context0->Global()->Set(v8_str("callback"),
11975 callback_templ->GetFunction());
11976 calling_context0->Exit();
11978 // Expose context0 in context1 and setup a function that calls the
11979 // callback function.
11980 calling_context1->Enter();
11981 calling_context1->Global()->Set(v8_str("context0"),
11982 calling_context0->Global());
11983 CompileRun("function f() { context0.callback() }");
11984 calling_context1->Exit();
11986 // Expose context1 in context2 and call the callback function in
11987 // context0 indirectly through f in context1.
11988 calling_context2->Enter();
11989 calling_context2->Global()->Set(v8_str("context1"),
11990 calling_context1->Global());
11991 CompileRun("context1.f()");
11992 calling_context2->Exit();
11994 // Dispose the contexts to allow them to be garbage collected.
11995 calling_context0.Dispose();
11996 calling_context1.Dispose();
11997 calling_context2.Dispose();
11998 calling_context0.Clear();
11999 calling_context1.Clear();
12000 calling_context2.Clear();
12004 // Check that a variable declaration with no explicit initialization
12005 // value does not shadow an existing property in the prototype chain.
12007 // This is consistent with Firefox and Safari.
12009 // See http://crbug.com/12548.
12010 THREADED_TEST(InitGlobalVarInProtoChain) {
12011 v8::HandleScope scope;
12012 LocalContext context;
12013 // Introduce a variable in the prototype chain.
12014 CompileRun("__proto__.x = 42");
12015 v8::Handle<v8::Value> result = CompileRun("var x; x");
12016 CHECK(!result->IsUndefined());
12017 CHECK_EQ(42, result->Int32Value());
12021 // Regression test for issue 398.
12022 // If a function is added to an object, creating a constant function
12023 // field, and the result is cloned, replacing the constant function on the
12024 // original should not affect the clone.
12025 // See http://code.google.com/p/v8/issues/detail?id=398
12026 THREADED_TEST(ReplaceConstantFunction) {
12027 v8::HandleScope scope;
12028 LocalContext context;
12029 v8::Handle<v8::Object> obj = v8::Object::New();
12030 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12031 v8::Handle<v8::String> foo_string = v8::String::New("foo");
12032 obj->Set(foo_string, func_templ->GetFunction());
12033 v8::Handle<v8::Object> obj_clone = obj->Clone();
12034 obj_clone->Set(foo_string, v8::String::New("Hello"));
12035 CHECK(!obj->Get(foo_string)->IsUndefined());
12039 // Regression test for http://crbug.com/16276.
12040 THREADED_TEST(Regress16276) {
12041 v8::HandleScope scope;
12042 LocalContext context;
12043 // Force the IC in f to be a dictionary load IC.
12044 CompileRun("function f(obj) { return obj.x; }\n"
12045 "var obj = { x: { foo: 42 }, y: 87 };\n"
12048 "for (var i = 0; i < 5; i++) f(obj);");
12049 // Detach the global object to make 'this' refer directly to the
12050 // global object (not the proxy), and make sure that the dictionary
12051 // load IC doesn't mess up loading directly from the global object.
12052 context->DetachGlobal();
12053 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12057 THREADED_TEST(PixelArray) {
12058 v8::HandleScope scope;
12059 LocalContext context;
12060 const int kElementCount = 260;
12061 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12062 i::Handle<i::ExternalPixelArray> pixels =
12063 i::Handle<i::ExternalPixelArray>::cast(
12064 FACTORY->NewExternalArray(kElementCount,
12065 v8::kExternalPixelArray,
12067 // Force GC to trigger verification.
12068 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12069 for (int i = 0; i < kElementCount; i++) {
12070 pixels->set(i, i % 256);
12072 // Force GC to trigger verification.
12073 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12074 for (int i = 0; i < kElementCount; i++) {
12075 CHECK_EQ(i % 256, pixels->get_scalar(i));
12076 CHECK_EQ(i % 256, pixel_data[i]);
12079 v8::Handle<v8::Object> obj = v8::Object::New();
12080 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12081 // Set the elements to be the pixels.
12082 // jsobj->set_elements(*pixels);
12083 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12084 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12085 obj->Set(v8_str("field"), v8::Int32::New(1503));
12086 context->Global()->Set(v8_str("pixels"), obj);
12087 v8::Handle<v8::Value> result = CompileRun("pixels.field");
12088 CHECK_EQ(1503, result->Int32Value());
12089 result = CompileRun("pixels[1]");
12090 CHECK_EQ(1, result->Int32Value());
12092 result = CompileRun("var sum = 0;"
12093 "for (var i = 0; i < 8; i++) {"
12094 " sum += pixels[i] = pixels[i] = -i;"
12097 CHECK_EQ(-28, result->Int32Value());
12099 result = CompileRun("var sum = 0;"
12100 "for (var i = 0; i < 8; i++) {"
12101 " sum += pixels[i] = pixels[i] = 0;"
12104 CHECK_EQ(0, result->Int32Value());
12106 result = CompileRun("var sum = 0;"
12107 "for (var i = 0; i < 8; i++) {"
12108 " sum += pixels[i] = pixels[i] = 255;"
12111 CHECK_EQ(8 * 255, result->Int32Value());
12113 result = CompileRun("var sum = 0;"
12114 "for (var i = 0; i < 8; i++) {"
12115 " sum += pixels[i] = pixels[i] = 256 + i;"
12118 CHECK_EQ(2076, result->Int32Value());
12120 result = CompileRun("var sum = 0;"
12121 "for (var i = 0; i < 8; i++) {"
12122 " sum += pixels[i] = pixels[i] = i;"
12125 CHECK_EQ(28, result->Int32Value());
12127 result = CompileRun("var sum = 0;"
12128 "for (var i = 0; i < 8; i++) {"
12129 " sum += pixels[i];"
12132 CHECK_EQ(28, result->Int32Value());
12134 i::Handle<i::Smi> value(i::Smi::FromInt(2));
12135 i::Handle<i::Object> no_failure;
12136 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12137 ASSERT(!no_failure.is_null());
12138 i::USE(no_failure);
12139 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12140 *value.location() = i::Smi::FromInt(256);
12141 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12142 ASSERT(!no_failure.is_null());
12143 i::USE(no_failure);
12145 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12146 *value.location() = i::Smi::FromInt(-1);
12147 no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12148 ASSERT(!no_failure.is_null());
12149 i::USE(no_failure);
12150 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12152 result = CompileRun("for (var i = 0; i < 8; i++) {"
12153 " pixels[i] = (i * 65) - 109;"
12155 "pixels[1] + pixels[6];");
12156 CHECK_EQ(255, result->Int32Value());
12157 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12158 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12160 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12162 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12164 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12166 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12168 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12170 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12171 result = CompileRun("var sum = 0;"
12172 "for (var i = 0; i < 8; i++) {"
12173 " sum += pixels[i];"
12176 CHECK_EQ(984, result->Int32Value());
12178 result = CompileRun("for (var i = 0; i < 8; i++) {"
12179 " pixels[i] = (i * 1.1);"
12181 "pixels[1] + pixels[6];");
12182 CHECK_EQ(8, result->Int32Value());
12183 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12184 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12185 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12186 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12187 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12188 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12189 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12190 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12192 result = CompileRun("for (var i = 0; i < 8; i++) {"
12193 " pixels[7] = undefined;"
12196 CHECK_EQ(0, result->Int32Value());
12197 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12199 result = CompileRun("for (var i = 0; i < 8; i++) {"
12200 " pixels[6] = '2.3';"
12203 CHECK_EQ(2, result->Int32Value());
12204 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12206 result = CompileRun("for (var i = 0; i < 8; i++) {"
12207 " pixels[5] = NaN;"
12210 CHECK_EQ(0, result->Int32Value());
12211 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12213 result = CompileRun("for (var i = 0; i < 8; i++) {"
12214 " pixels[8] = Infinity;"
12217 CHECK_EQ(255, result->Int32Value());
12219 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
12221 result = CompileRun("for (var i = 0; i < 8; i++) {"
12222 " pixels[9] = -Infinity;"
12225 CHECK_EQ(0, result->Int32Value());
12226 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
12228 result = CompileRun("pixels[3] = 33;"
12229 "delete pixels[3];"
12231 CHECK_EQ(33, result->Int32Value());
12233 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12234 "pixels[2] = 12; pixels[3] = 13;"
12235 "pixels.__defineGetter__('2',"
12236 "function() { return 120; });"
12238 CHECK_EQ(12, result->Int32Value());
12240 result = CompileRun("var js_array = new Array(40);"
12241 "js_array[0] = 77;"
12243 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12245 result = CompileRun("pixels[1] = 23;"
12246 "pixels.__proto__ = [];"
12247 "js_array.__proto__ = pixels;"
12248 "js_array.concat(pixels);");
12249 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12250 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12252 result = CompileRun("pixels[1] = 23;");
12253 CHECK_EQ(23, result->Int32Value());
12255 // Test for index greater than 255. Regression test for:
12256 // http://code.google.com/p/chromium/issues/detail?id=26337.
12257 result = CompileRun("pixels[256] = 255;");
12258 CHECK_EQ(255, result->Int32Value());
12259 result = CompileRun("var i = 0;"
12260 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12262 CHECK_EQ(255, result->Int32Value());
12264 // Make sure that pixel array ICs recognize when a non-pixel array
12265 // is passed to it.
12266 result = CompileRun("function pa_load(p) {"
12268 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12271 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12272 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12273 "just_ints = new Object();"
12274 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12275 "for (var i = 0; i < 10; ++i) {"
12276 " result = pa_load(just_ints);"
12279 CHECK_EQ(32640, result->Int32Value());
12281 // Make sure that pixel array ICs recognize out-of-bound accesses.
12282 result = CompileRun("function pa_load(p, start) {"
12284 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12287 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12288 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12289 "for (var i = 0; i < 10; ++i) {"
12290 " result = pa_load(pixels,-10);"
12293 CHECK_EQ(0, result->Int32Value());
12295 // Make sure that generic ICs properly handles a pixel array.
12296 result = CompileRun("function pa_load(p) {"
12298 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12301 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12302 "just_ints = new Object();"
12303 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12304 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12305 "for (var i = 0; i < 10; ++i) {"
12306 " result = pa_load(pixels);"
12309 CHECK_EQ(32640, result->Int32Value());
12311 // Make sure that generic load ICs recognize out-of-bound accesses in
12313 result = CompileRun("function pa_load(p, start) {"
12315 " for (var j = start; j < 256; j++) { sum += p[j]; }"
12318 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12319 "just_ints = new Object();"
12320 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12321 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12322 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12323 "for (var i = 0; i < 10; ++i) {"
12324 " result = pa_load(pixels,-10);"
12327 CHECK_EQ(0, result->Int32Value());
12329 // Make sure that generic ICs properly handles other types than pixel
12330 // arrays (that the inlined fast pixel array test leaves the right information
12331 // in the right registers).
12332 result = CompileRun("function pa_load(p) {"
12334 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
12337 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12338 "just_ints = new Object();"
12339 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12340 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12341 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12342 "sparse_array = new Object();"
12343 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12344 "sparse_array[1000000] = 3;"
12345 "for (var i = 0; i < 10; ++i) {"
12346 " result = pa_load(sparse_array);"
12349 CHECK_EQ(32640, result->Int32Value());
12351 // Make sure that pixel array store ICs clamp values correctly.
12352 result = CompileRun("function pa_store(p) {"
12353 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12355 "pa_store(pixels);"
12357 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12359 CHECK_EQ(48896, result->Int32Value());
12361 // Make sure that pixel array stores correctly handle accesses outside
12362 // of the pixel array..
12363 result = CompileRun("function pa_store(p,start) {"
12364 " for (var j = 0; j < 256; j++) {"
12365 " p[j+start] = j * 2;"
12368 "pa_store(pixels,0);"
12369 "pa_store(pixels,-128);"
12371 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12373 CHECK_EQ(65280, result->Int32Value());
12375 // Make sure that the generic store stub correctly handle accesses outside
12376 // of the pixel array..
12377 result = CompileRun("function pa_store(p,start) {"
12378 " for (var j = 0; j < 256; j++) {"
12379 " p[j+start] = j * 2;"
12382 "pa_store(pixels,0);"
12383 "just_ints = new Object();"
12384 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12385 "pa_store(just_ints, 0);"
12386 "pa_store(pixels,-128);"
12388 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12390 CHECK_EQ(65280, result->Int32Value());
12392 // Make sure that the generic keyed store stub clamps pixel array values
12394 result = CompileRun("function pa_store(p) {"
12395 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12397 "pa_store(pixels);"
12398 "just_ints = new Object();"
12399 "pa_store(just_ints);"
12400 "pa_store(pixels);"
12402 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12404 CHECK_EQ(48896, result->Int32Value());
12406 // Make sure that pixel array loads are optimized by crankshaft.
12407 result = CompileRun("function pa_load(p) {"
12409 " for (var i=0; i<256; ++i) {"
12414 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12415 "for (var i = 0; i < 5000; ++i) {"
12416 " result = pa_load(pixels);"
12419 CHECK_EQ(32640, result->Int32Value());
12421 // Make sure that pixel array stores are optimized by crankshaft.
12422 result = CompileRun("function pa_init(p) {"
12423 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12425 "function pa_load(p) {"
12427 " for (var i=0; i<256; ++i) {"
12432 "for (var i = 0; i < 5000; ++i) {"
12433 " pa_init(pixels);"
12435 "result = pa_load(pixels);"
12437 CHECK_EQ(32640, result->Int32Value());
12443 THREADED_TEST(PixelArrayInfo) {
12444 v8::HandleScope scope;
12445 LocalContext context;
12446 for (int size = 0; size < 100; size += 10) {
12447 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12448 v8::Handle<v8::Object> obj = v8::Object::New();
12449 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12450 CHECK(obj->HasIndexedPropertiesInPixelData());
12451 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12452 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12458 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12460 const AccessorInfo& info) {
12461 ApiTestFuzzer::Fuzz();
12462 return v8::Handle<Value>();
12466 static v8::Handle<Value> NotHandledIndexedPropertySetter(
12468 Local<Value> value,
12469 const AccessorInfo& info) {
12470 ApiTestFuzzer::Fuzz();
12471 return v8::Handle<Value>();
12475 THREADED_TEST(PixelArrayWithInterceptor) {
12476 v8::HandleScope scope;
12477 LocalContext context;
12478 const int kElementCount = 260;
12479 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12480 i::Handle<i::ExternalPixelArray> pixels =
12481 i::Handle<i::ExternalPixelArray>::cast(
12482 FACTORY->NewExternalArray(kElementCount,
12483 v8::kExternalPixelArray,
12485 for (int i = 0; i < kElementCount; i++) {
12486 pixels->set(i, i % 256);
12488 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12489 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12490 NotHandledIndexedPropertySetter);
12491 v8::Handle<v8::Object> obj = templ->NewInstance();
12492 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12493 context->Global()->Set(v8_str("pixels"), obj);
12494 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12495 CHECK_EQ(1, result->Int32Value());
12496 result = CompileRun("var sum = 0;"
12497 "for (var i = 0; i < 8; i++) {"
12498 " sum += pixels[i] = pixels[i] = -i;"
12501 CHECK_EQ(-28, result->Int32Value());
12502 result = CompileRun("pixels.hasOwnProperty('1')");
12503 CHECK(result->BooleanValue());
12508 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12509 switch (array_type) {
12510 case v8::kExternalByteArray:
12511 case v8::kExternalUnsignedByteArray:
12512 case v8::kExternalPixelArray:
12515 case v8::kExternalShortArray:
12516 case v8::kExternalUnsignedShortArray:
12519 case v8::kExternalIntArray:
12520 case v8::kExternalUnsignedIntArray:
12521 case v8::kExternalFloatArray:
12524 case v8::kExternalDoubleArray:
12536 template <class ExternalArrayClass, class ElementType>
12537 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12540 v8::HandleScope scope;
12541 LocalContext context;
12542 const int kElementCount = 40;
12543 int element_size = ExternalArrayElementSize(array_type);
12544 ElementType* array_data =
12545 static_cast<ElementType*>(malloc(kElementCount * element_size));
12546 i::Handle<ExternalArrayClass> array =
12547 i::Handle<ExternalArrayClass>::cast(
12548 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12549 // Force GC to trigger verification.
12550 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12551 for (int i = 0; i < kElementCount; i++) {
12552 array->set(i, static_cast<ElementType>(i));
12554 // Force GC to trigger verification.
12555 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12556 for (int i = 0; i < kElementCount; i++) {
12557 CHECK_EQ(static_cast<int64_t>(i),
12558 static_cast<int64_t>(array->get_scalar(i)));
12559 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12562 v8::Handle<v8::Object> obj = v8::Object::New();
12563 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12564 // Set the elements to be the external array.
12565 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12569 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
12570 obj->Set(v8_str("field"), v8::Int32::New(1503));
12571 context->Global()->Set(v8_str("ext_array"), obj);
12572 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12573 CHECK_EQ(1503, result->Int32Value());
12574 result = CompileRun("ext_array[1]");
12575 CHECK_EQ(1, result->Int32Value());
12577 // Check pass through of assigned smis
12578 result = CompileRun("var sum = 0;"
12579 "for (var i = 0; i < 8; i++) {"
12580 " sum += ext_array[i] = ext_array[i] = -i;"
12583 CHECK_EQ(-28, result->Int32Value());
12585 // Check assigned smis
12586 result = CompileRun("for (var i = 0; i < 8; i++) {"
12587 " ext_array[i] = i;"
12590 "for (var i = 0; i < 8; i++) {"
12591 " sum += ext_array[i];"
12594 CHECK_EQ(28, result->Int32Value());
12596 // Check assigned smis in reverse order
12597 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12598 " ext_array[i] = i;"
12601 "for (var i = 0; i < 8; i++) {"
12602 " sum += ext_array[i];"
12605 CHECK_EQ(28, result->Int32Value());
12607 // Check pass through of assigned HeapNumbers
12608 result = CompileRun("var sum = 0;"
12609 "for (var i = 0; i < 16; i+=2) {"
12610 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12613 CHECK_EQ(-28, result->Int32Value());
12615 // Check assigned HeapNumbers
12616 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12617 " ext_array[i] = (i * 0.5);"
12620 "for (var i = 0; i < 16; i+=2) {"
12621 " sum += ext_array[i];"
12624 CHECK_EQ(28, result->Int32Value());
12626 // Check assigned HeapNumbers in reverse order
12627 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12628 " ext_array[i] = (i * 0.5);"
12631 "for (var i = 0; i < 16; i+=2) {"
12632 " sum += ext_array[i];"
12635 CHECK_EQ(28, result->Int32Value());
12637 i::ScopedVector<char> test_buf(1024);
12639 // Check legal boundary conditions.
12640 // The repeated loads and stores ensure the ICs are exercised.
12641 const char* boundary_program =
12643 "for (var i = 0; i < 16; i++) {"
12644 " ext_array[i] = %lld;"
12646 " res = ext_array[i];"
12650 i::OS::SNPrintF(test_buf,
12653 result = CompileRun(test_buf.start());
12654 CHECK_EQ(low, result->IntegerValue());
12656 i::OS::SNPrintF(test_buf,
12659 result = CompileRun(test_buf.start());
12660 CHECK_EQ(high, result->IntegerValue());
12662 // Check misprediction of type in IC.
12663 result = CompileRun("var tmp_array = ext_array;"
12665 "for (var i = 0; i < 8; i++) {"
12666 " tmp_array[i] = i;"
12667 " sum += tmp_array[i];"
12673 // Force GC to trigger verification.
12674 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12675 CHECK_EQ(28, result->Int32Value());
12677 // Make sure out-of-range loads do not throw.
12678 i::OS::SNPrintF(test_buf,
12679 "var caught_exception = false;"
12683 " caught_exception = true;"
12685 "caught_exception;",
12687 result = CompileRun(test_buf.start());
12688 CHECK_EQ(false, result->BooleanValue());
12690 // Make sure out-of-range stores do not throw.
12691 i::OS::SNPrintF(test_buf,
12692 "var caught_exception = false;"
12694 " ext_array[%d] = 1;"
12696 " caught_exception = true;"
12698 "caught_exception;",
12700 result = CompileRun(test_buf.start());
12701 CHECK_EQ(false, result->BooleanValue());
12703 // Check other boundary conditions, values and operations.
12704 result = CompileRun("for (var i = 0; i < 8; i++) {"
12705 " ext_array[7] = undefined;"
12708 CHECK_EQ(0, result->Int32Value());
12710 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
12712 result = CompileRun("for (var i = 0; i < 8; i++) {"
12713 " ext_array[6] = '2.3';"
12716 CHECK_EQ(2, result->Int32Value());
12718 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
12720 if (array_type != v8::kExternalFloatArray &&
12721 array_type != v8::kExternalDoubleArray) {
12722 // Though the specification doesn't state it, be explicit about
12723 // converting NaNs and +/-Infinity to zero.
12724 result = CompileRun("for (var i = 0; i < 8; i++) {"
12725 " ext_array[i] = 5;"
12727 "for (var i = 0; i < 8; i++) {"
12728 " ext_array[i] = NaN;"
12731 CHECK_EQ(0, result->Int32Value());
12733 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12735 result = CompileRun("for (var i = 0; i < 8; i++) {"
12736 " ext_array[i] = 5;"
12738 "for (var i = 0; i < 8; i++) {"
12739 " ext_array[i] = Infinity;"
12742 int expected_value =
12743 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12744 CHECK_EQ(expected_value, result->Int32Value());
12745 CHECK_EQ(expected_value,
12746 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12748 result = CompileRun("for (var i = 0; i < 8; i++) {"
12749 " ext_array[i] = 5;"
12751 "for (var i = 0; i < 8; i++) {"
12752 " ext_array[i] = -Infinity;"
12755 CHECK_EQ(0, result->Int32Value());
12757 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12759 // Check truncation behavior of integral arrays.
12760 const char* unsigned_data =
12761 "var source_data = [0.6, 10.6];"
12762 "var expected_results = [0, 10];";
12763 const char* signed_data =
12764 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12765 "var expected_results = [0, 10, 0, -10];";
12766 const char* pixel_data =
12767 "var source_data = [0.6, 10.6];"
12768 "var expected_results = [1, 11];";
12770 (array_type == v8::kExternalUnsignedByteArray ||
12771 array_type == v8::kExternalUnsignedShortArray ||
12772 array_type == v8::kExternalUnsignedIntArray);
12773 bool is_pixel_data = array_type == v8::kExternalPixelArray;
12775 i::OS::SNPrintF(test_buf,
12777 "var all_passed = true;"
12778 "for (var i = 0; i < source_data.length; i++) {"
12779 " for (var j = 0; j < 8; j++) {"
12780 " ext_array[j] = source_data[i];"
12782 " all_passed = all_passed &&"
12783 " (ext_array[5] == expected_results[i]);"
12788 (is_pixel_data ? pixel_data : signed_data)));
12789 result = CompileRun(test_buf.start());
12790 CHECK_EQ(true, result->BooleanValue());
12793 for (int i = 0; i < kElementCount; i++) {
12794 array->set(i, static_cast<ElementType>(i));
12796 // Test complex assignments
12797 result = CompileRun("function ee_op_test_complex_func(sum) {"
12798 " for (var i = 0; i < 40; ++i) {"
12799 " sum += (ext_array[i] += 1);"
12800 " sum += (ext_array[i] -= 1);"
12805 "for (var i=0;i<10000;++i) {"
12806 " sum=ee_op_test_complex_func(sum);"
12809 CHECK_EQ(16000000, result->Int32Value());
12811 // Test count operations
12812 result = CompileRun("function ee_op_test_count_func(sum) {"
12813 " for (var i = 0; i < 40; ++i) {"
12814 " sum += (++ext_array[i]);"
12815 " sum += (--ext_array[i]);"
12820 "for (var i=0;i<10000;++i) {"
12821 " sum=ee_op_test_count_func(sum);"
12824 CHECK_EQ(16000000, result->Int32Value());
12826 result = CompileRun("ext_array[3] = 33;"
12827 "delete ext_array[3];"
12829 CHECK_EQ(33, result->Int32Value());
12831 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12832 "ext_array[2] = 12; ext_array[3] = 13;"
12833 "ext_array.__defineGetter__('2',"
12834 "function() { return 120; });"
12836 CHECK_EQ(12, result->Int32Value());
12838 result = CompileRun("var js_array = new Array(40);"
12839 "js_array[0] = 77;"
12841 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12843 result = CompileRun("ext_array[1] = 23;"
12844 "ext_array.__proto__ = [];"
12845 "js_array.__proto__ = ext_array;"
12846 "js_array.concat(ext_array);");
12847 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12848 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12850 result = CompileRun("ext_array[1] = 23;");
12851 CHECK_EQ(23, result->Int32Value());
12853 // Test more complex manipulations which cause eax to contain values
12854 // that won't be completely overwritten by loads from the arrays.
12855 // This catches bugs in the instructions used for the KeyedLoadIC
12856 // for byte and word types.
12858 const int kXSize = 300;
12859 const int kYSize = 300;
12860 const int kLargeElementCount = kXSize * kYSize * 4;
12861 ElementType* large_array_data =
12862 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12863 i::Handle<ExternalArrayClass> large_array(
12864 i::Handle<ExternalArrayClass>::cast(
12865 FACTORY->NewExternalArray(kLargeElementCount,
12868 v8::Handle<v8::Object> large_obj = v8::Object::New();
12869 // Set the elements to be the external array.
12870 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12872 kLargeElementCount);
12873 context->Global()->Set(v8_str("large_array"), large_obj);
12874 // Initialize contents of a few rows.
12875 for (int x = 0; x < 300; x++) {
12877 int offset = row * 300 * 4;
12878 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12879 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12880 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12881 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12883 offset = row * 300 * 4;
12884 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12885 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12886 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12887 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12889 offset = row * 300 * 4;
12890 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12891 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12892 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12893 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12895 // The goal of the code below is to make "offset" large enough
12896 // that the computation of the index (which goes into eax) has
12897 // high bits set which will not be overwritten by a byte or short
12899 result = CompileRun("var failed = false;"
12901 "for (var i = 0; i < 300; i++) {"
12902 " if (large_array[4 * i] != 127 ||"
12903 " large_array[4 * i + 1] != 0 ||"
12904 " large_array[4 * i + 2] != 0 ||"
12905 " large_array[4 * i + 3] != 127) {"
12909 "offset = 150 * 300 * 4;"
12910 "for (var i = 0; i < 300; i++) {"
12911 " if (large_array[offset + 4 * i] != 127 ||"
12912 " large_array[offset + 4 * i + 1] != 0 ||"
12913 " large_array[offset + 4 * i + 2] != 0 ||"
12914 " large_array[offset + 4 * i + 3] != 127) {"
12918 "offset = 298 * 300 * 4;"
12919 "for (var i = 0; i < 300; i++) {"
12920 " if (large_array[offset + 4 * i] != 127 ||"
12921 " large_array[offset + 4 * i + 1] != 0 ||"
12922 " large_array[offset + 4 * i + 2] != 0 ||"
12923 " large_array[offset + 4 * i + 3] != 127) {"
12928 CHECK_EQ(true, result->BooleanValue());
12929 free(large_array_data);
12932 // The "" property descriptor is overloaded to store information about
12933 // the external array. Ensure that setting and accessing the "" property
12934 // works (it should overwrite the information cached about the external
12935 // array in the DescriptorArray) in various situations.
12936 result = CompileRun("ext_array[''] = 23; ext_array['']");
12937 CHECK_EQ(23, result->Int32Value());
12939 // Property "" set after the external array is associated with the object.
12941 v8::Handle<v8::Object> obj2 = v8::Object::New();
12942 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12943 obj2->Set(v8_str(""), v8::Int32::New(1503));
12944 // Set the elements to be the external array.
12945 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12948 context->Global()->Set(v8_str("ext_array"), obj2);
12949 result = CompileRun("ext_array['']");
12950 CHECK_EQ(1503, result->Int32Value());
12953 // Property "" set after the external array is associated with the object.
12955 v8::Handle<v8::Object> obj2 = v8::Object::New();
12956 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12957 // Set the elements to be the external array.
12958 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12961 obj2->Set(v8_str(""), v8::Int32::New(1503));
12962 context->Global()->Set(v8_str("ext_array"), obj2);
12963 result = CompileRun("ext_array['']");
12964 CHECK_EQ(1503, result->Int32Value());
12967 // Should reuse the map from previous test.
12969 v8::Handle<v8::Object> obj2 = v8::Object::New();
12970 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12971 // Set the elements to be the external array. Should re-use the map
12972 // from previous test.
12973 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12976 context->Global()->Set(v8_str("ext_array"), obj2);
12977 result = CompileRun("ext_array['']");
12980 // Property "" is a constant function that shouldn't not be interfered with
12981 // when an external array is set.
12983 v8::Handle<v8::Object> obj2 = v8::Object::New();
12985 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12987 // Add a constant function to an object.
12988 context->Global()->Set(v8_str("ext_array"), obj2);
12989 result = CompileRun("ext_array[''] = function() {return 1503;};"
12990 "ext_array['']();");
12992 // Add an external array transition to the same map that
12993 // has the constant transition.
12994 v8::Handle<v8::Object> obj3 = v8::Object::New();
12995 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12996 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12999 context->Global()->Set(v8_str("ext_array"), obj3);
13002 // If a external array transition is in the map, it should get clobbered
13003 // by a constant function.
13005 // Add an external array transition.
13006 v8::Handle<v8::Object> obj3 = v8::Object::New();
13007 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13008 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13012 // Add a constant function to the same map that just got an external array
13014 v8::Handle<v8::Object> obj2 = v8::Object::New();
13015 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13016 context->Global()->Set(v8_str("ext_array"), obj2);
13017 result = CompileRun("ext_array[''] = function() {return 1503;};"
13018 "ext_array['']();");
13025 THREADED_TEST(ExternalByteArray) {
13026 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
13027 v8::kExternalByteArray,
13033 THREADED_TEST(ExternalUnsignedByteArray) {
13034 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
13035 v8::kExternalUnsignedByteArray,
13041 THREADED_TEST(ExternalPixelArray) {
13042 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13043 v8::kExternalPixelArray,
13049 THREADED_TEST(ExternalShortArray) {
13050 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
13051 v8::kExternalShortArray,
13057 THREADED_TEST(ExternalUnsignedShortArray) {
13058 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
13059 v8::kExternalUnsignedShortArray,
13065 THREADED_TEST(ExternalIntArray) {
13066 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
13067 v8::kExternalIntArray,
13068 INT_MIN, // -2147483648
13069 INT_MAX); // 2147483647
13073 THREADED_TEST(ExternalUnsignedIntArray) {
13074 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
13075 v8::kExternalUnsignedIntArray,
13077 UINT_MAX); // 4294967295
13081 THREADED_TEST(ExternalFloatArray) {
13082 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
13083 v8::kExternalFloatArray,
13089 THREADED_TEST(ExternalDoubleArray) {
13090 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13091 v8::kExternalDoubleArray,
13097 THREADED_TEST(ExternalArrays) {
13098 TestExternalByteArray();
13099 TestExternalUnsignedByteArray();
13100 TestExternalShortArray();
13101 TestExternalUnsignedShortArray();
13102 TestExternalIntArray();
13103 TestExternalUnsignedIntArray();
13104 TestExternalFloatArray();
13108 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13109 v8::HandleScope scope;
13110 LocalContext context;
13111 for (int size = 0; size < 100; size += 10) {
13112 int element_size = ExternalArrayElementSize(array_type);
13113 void* external_data = malloc(size * element_size);
13114 v8::Handle<v8::Object> obj = v8::Object::New();
13115 obj->SetIndexedPropertiesToExternalArrayData(
13116 external_data, array_type, size);
13117 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13118 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13119 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13120 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13121 free(external_data);
13126 THREADED_TEST(ExternalArrayInfo) {
13127 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13128 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13129 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13130 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13131 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13132 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13133 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
13134 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
13135 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
13139 THREADED_TEST(ScriptContextDependence) {
13140 v8::HandleScope scope;
13142 const char *source = "foo";
13143 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13144 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13145 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13146 CHECK_EQ(dep->Run()->Int32Value(), 100);
13147 CHECK_EQ(indep->Run()->Int32Value(), 100);
13149 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13150 CHECK_EQ(dep->Run()->Int32Value(), 100);
13151 CHECK_EQ(indep->Run()->Int32Value(), 101);
13155 THREADED_TEST(StackTrace) {
13156 v8::HandleScope scope;
13157 LocalContext context;
13158 v8::TryCatch try_catch;
13159 const char *source = "function foo() { FAIL.FAIL; }; foo();";
13160 v8::Handle<v8::String> src = v8::String::New(source);
13161 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13162 v8::Script::New(src, origin)->Run();
13163 CHECK(try_catch.HasCaught());
13164 v8::String::Utf8Value stack(try_catch.StackTrace());
13165 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13169 // Checks that a StackFrame has certain expected values.
13170 void checkStackFrame(const char* expected_script_name,
13171 const char* expected_func_name, int expected_line_number,
13172 int expected_column, bool is_eval, bool is_constructor,
13173 v8::Handle<v8::StackFrame> frame) {
13174 v8::HandleScope scope;
13175 v8::String::Utf8Value func_name(frame->GetFunctionName());
13176 v8::String::Utf8Value script_name(frame->GetScriptName());
13177 if (*script_name == NULL) {
13178 // The situation where there is no associated script, like for evals.
13179 CHECK(expected_script_name == NULL);
13181 CHECK(strstr(*script_name, expected_script_name) != NULL);
13183 CHECK(strstr(*func_name, expected_func_name) != NULL);
13184 CHECK_EQ(expected_line_number, frame->GetLineNumber());
13185 CHECK_EQ(expected_column, frame->GetColumn());
13186 CHECK_EQ(is_eval, frame->IsEval());
13187 CHECK_EQ(is_constructor, frame->IsConstructor());
13191 v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13192 v8::HandleScope scope;
13193 const char* origin = "capture-stack-trace-test";
13194 const int kOverviewTest = 1;
13195 const int kDetailedTest = 2;
13197 ASSERT(args.Length() == 1);
13199 int testGroup = args[0]->Int32Value();
13200 if (testGroup == kOverviewTest) {
13201 v8::Handle<v8::StackTrace> stackTrace =
13202 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13203 CHECK_EQ(4, stackTrace->GetFrameCount());
13204 checkStackFrame(origin, "bar", 2, 10, false, false,
13205 stackTrace->GetFrame(0));
13206 checkStackFrame(origin, "foo", 6, 3, false, false,
13207 stackTrace->GetFrame(1));
13208 // This is the source string inside the eval which has the call to foo.
13209 checkStackFrame(NULL, "", 1, 5, false, false,
13210 stackTrace->GetFrame(2));
13211 // The last frame is an anonymous function which has the initial eval call.
13212 checkStackFrame(origin, "", 8, 7, false, false,
13213 stackTrace->GetFrame(3));
13215 CHECK(stackTrace->AsArray()->IsArray());
13216 } else if (testGroup == kDetailedTest) {
13217 v8::Handle<v8::StackTrace> stackTrace =
13218 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13219 CHECK_EQ(4, stackTrace->GetFrameCount());
13220 checkStackFrame(origin, "bat", 4, 22, false, false,
13221 stackTrace->GetFrame(0));
13222 checkStackFrame(origin, "baz", 8, 3, false, true,
13223 stackTrace->GetFrame(1));
13224 #ifdef ENABLE_DEBUGGER_SUPPORT
13225 bool is_eval = true;
13226 #else // ENABLE_DEBUGGER_SUPPORT
13227 bool is_eval = false;
13228 #endif // ENABLE_DEBUGGER_SUPPORT
13230 // This is the source string inside the eval which has the call to baz.
13231 checkStackFrame(NULL, "", 1, 5, is_eval, false,
13232 stackTrace->GetFrame(2));
13233 // The last frame is an anonymous function which has the initial eval call.
13234 checkStackFrame(origin, "", 10, 1, false, false,
13235 stackTrace->GetFrame(3));
13237 CHECK(stackTrace->AsArray()->IsArray());
13239 return v8::Undefined();
13243 // Tests the C++ StackTrace API.
13244 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13245 // THREADED_TEST(CaptureStackTrace) {
13246 TEST(CaptureStackTrace) {
13247 v8::HandleScope scope;
13248 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13249 Local<ObjectTemplate> templ = ObjectTemplate::New();
13250 templ->Set(v8_str("AnalyzeStackInNativeCode"),
13251 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13252 LocalContext context(0, templ);
13254 // Test getting OVERVIEW information. Should ignore information that is not
13255 // script name, function name, line number, and column offset.
13256 const char *overview_source =
13257 "function bar() {\n"
13258 " var y; AnalyzeStackInNativeCode(1);\n"
13260 "function foo() {\n"
13264 "var x;eval('new foo();');";
13265 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
13266 v8::Handle<Value> overview_result(
13267 v8::Script::New(overview_src, origin)->Run());
13268 ASSERT(!overview_result.IsEmpty());
13269 ASSERT(overview_result->IsObject());
13271 // Test getting DETAILED information.
13272 const char *detailed_source =
13273 "function bat() {AnalyzeStackInNativeCode(2);\n"
13276 "function baz() {\n"
13279 "eval('new baz();');";
13280 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13281 // Make the script using a non-zero line and column offset.
13282 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13283 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13284 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13285 v8::Handle<v8::Script> detailed_script(
13286 v8::Script::New(detailed_src, &detailed_origin));
13287 v8::Handle<Value> detailed_result(detailed_script->Run());
13288 ASSERT(!detailed_result.IsEmpty());
13289 ASSERT(detailed_result->IsObject());
13293 static void StackTraceForUncaughtExceptionListener(
13294 v8::Handle<v8::Message> message,
13295 v8::Handle<Value>) {
13296 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13297 CHECK_EQ(2, stack_trace->GetFrameCount());
13298 checkStackFrame("origin", "foo", 2, 3, false, false,
13299 stack_trace->GetFrame(0));
13300 checkStackFrame("origin", "bar", 5, 3, false, false,
13301 stack_trace->GetFrame(1));
13304 TEST(CaptureStackTraceForUncaughtException) {
13306 v8::HandleScope scope;
13308 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13309 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13311 Script::Compile(v8_str("function foo() {\n"
13314 "function bar() {\n"
13317 v8_str("origin"))->Run();
13318 v8::Local<v8::Object> global = env->Global();
13319 Local<Value> trouble = global->Get(v8_str("bar"));
13320 CHECK(trouble->IsFunction());
13321 Function::Cast(*trouble)->Call(global, 0, NULL);
13322 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13323 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13327 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13328 v8::HandleScope scope;
13330 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13332 v8::StackTrace::kDetailed);
13335 "var setters = ['column', 'lineNumber', 'scriptName',\n"
13336 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13337 " 'isConstructor'];\n"
13338 "for (var i = 0; i < setters.length; i++) {\n"
13339 " var prop = setters[i];\n"
13340 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13342 CompileRun("throw 'exception';");
13343 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13347 v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13348 v8::HandleScope scope;
13349 v8::Handle<v8::StackTrace> stackTrace =
13350 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13351 CHECK_EQ(5, stackTrace->GetFrameCount());
13352 v8::Handle<v8::String> url = v8_str("eval_url");
13353 for (int i = 0; i < 3; i++) {
13354 v8::Handle<v8::String> name =
13355 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13356 CHECK(!name.IsEmpty());
13357 CHECK_EQ(url, name);
13359 return v8::Undefined();
13363 TEST(SourceURLInStackTrace) {
13364 v8::HandleScope scope;
13365 Local<ObjectTemplate> templ = ObjectTemplate::New();
13366 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13367 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13368 LocalContext context(0, templ);
13370 const char *source =
13371 "function outer() {\n"
13372 "function bar() {\n"
13373 " AnalyzeStackOfEvalWithSourceURL();\n"
13375 "function foo() {\n"
13381 "eval('(' + outer +')()//@ sourceURL=eval_url');";
13382 CHECK(CompileRun(source)->IsUndefined());
13386 // Test that idle notification can be handled and eventually returns true.
13387 THREADED_TEST(IdleNotification) {
13389 for (int i = 0; i < 100; i++) {
13390 rv = v8::V8::IdleNotification();
13398 static uint32_t* stack_limit;
13400 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
13401 stack_limit = reinterpret_cast<uint32_t*>(
13402 i::Isolate::Current()->stack_guard()->real_climit());
13403 return v8::Undefined();
13407 // Uses the address of a local variable to determine the stack top now.
13408 // Given a size, returns an address that is that far from the current
13410 static uint32_t* ComputeStackLimit(uint32_t size) {
13411 uint32_t* answer = &size - (size / sizeof(size));
13412 // If the size is very large and the stack is very near the bottom of
13413 // memory then the calculation above may wrap around and give an address
13414 // that is above the (downwards-growing) stack. In that case we return
13415 // a very low address.
13416 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13421 TEST(SetResourceConstraints) {
13422 static const int K = 1024;
13423 uint32_t* set_limit = ComputeStackLimit(128 * K);
13425 // Set stack limit.
13426 v8::ResourceConstraints constraints;
13427 constraints.set_stack_limit(set_limit);
13428 CHECK(v8::SetResourceConstraints(&constraints));
13430 // Execute a script.
13431 v8::HandleScope scope;
13433 Local<v8::FunctionTemplate> fun_templ =
13434 v8::FunctionTemplate::New(GetStackLimitCallback);
13435 Local<Function> fun = fun_templ->GetFunction();
13436 env->Global()->Set(v8_str("get_stack_limit"), fun);
13437 CompileRun("get_stack_limit();");
13439 CHECK(stack_limit == set_limit);
13443 TEST(SetResourceConstraintsInThread) {
13444 uint32_t* set_limit;
13447 static const int K = 1024;
13448 set_limit = ComputeStackLimit(128 * K);
13450 // Set stack limit.
13451 v8::ResourceConstraints constraints;
13452 constraints.set_stack_limit(set_limit);
13453 CHECK(v8::SetResourceConstraints(&constraints));
13455 // Execute a script.
13456 v8::HandleScope scope;
13458 Local<v8::FunctionTemplate> fun_templ =
13459 v8::FunctionTemplate::New(GetStackLimitCallback);
13460 Local<Function> fun = fun_templ->GetFunction();
13461 env->Global()->Set(v8_str("get_stack_limit"), fun);
13462 CompileRun("get_stack_limit();");
13464 CHECK(stack_limit == set_limit);
13468 CHECK(stack_limit == set_limit);
13473 THREADED_TEST(GetHeapStatistics) {
13474 v8::HandleScope scope;
13476 v8::HeapStatistics heap_statistics;
13477 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13478 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
13479 v8::V8::GetHeapStatistics(&heap_statistics);
13480 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13481 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13485 static double DoubleFromBits(uint64_t value) {
13487 memcpy(&target, &value, sizeof(target));
13492 static uint64_t DoubleToBits(double value) {
13494 memcpy(&target, &value, sizeof(target));
13499 static double DoubleToDateTime(double input) {
13500 double date_limit = 864e13;
13501 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13502 return i::OS::nan_value();
13504 return (input < 0) ? -(floor(-input)) : floor(input);
13507 // We don't have a consistent way to write 64-bit constants syntactically, so we
13508 // split them into two 32-bit constants and combine them programmatically.
13509 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13510 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13514 THREADED_TEST(QuietSignalingNaNs) {
13515 v8::HandleScope scope;
13516 LocalContext context;
13517 v8::TryCatch try_catch;
13519 // Special double values.
13520 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13521 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13522 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13523 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13524 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13525 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13526 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13528 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13529 // on either side of the epoch.
13530 double date_limit = 864e13;
13532 double test_values[] = {
13554 int num_test_values = 20;
13556 for (int i = 0; i < num_test_values; i++) {
13557 double test_value = test_values[i];
13559 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13560 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13561 double stored_number = number->NumberValue();
13562 if (!IsNaN(test_value)) {
13563 CHECK_EQ(test_value, stored_number);
13565 uint64_t stored_bits = DoubleToBits(stored_number);
13566 // Check if quiet nan (bits 51..62 all set).
13567 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13570 // Check that Date::New preserves non-NaNs in the date range and
13572 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13573 double expected_stored_date = DoubleToDateTime(test_value);
13574 double stored_date = date->NumberValue();
13575 if (!IsNaN(expected_stored_date)) {
13576 CHECK_EQ(expected_stored_date, stored_date);
13578 uint64_t stored_bits = DoubleToBits(stored_date);
13579 // Check if quiet nan (bits 51..62 all set).
13580 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13586 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13587 v8::HandleScope scope;
13589 v8::Handle<v8::String> str(args[0]->ToString());
13590 if (tc.HasCaught())
13591 return tc.ReThrow();
13592 return v8::Undefined();
13596 // Test that an exception can be propagated down through a spaghetti
13597 // stack using ReThrow.
13598 THREADED_TEST(SpaghettiStackReThrow) {
13599 v8::HandleScope scope;
13600 LocalContext context;
13601 context->Global()->Set(
13602 v8::String::New("s"),
13603 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13604 v8::TryCatch try_catch;
13608 " toString: function () {"
13618 CHECK(try_catch.HasCaught());
13619 v8::String::Utf8Value value(try_catch.Exception());
13620 CHECK_EQ(0, strcmp(*value, "Hey!"));
13625 v8::V8::Initialize();
13627 v8::HandleScope scope;
13628 v8::Persistent<Context> context;
13629 v8::Persistent<Context> other_context;
13632 // Create a context used to keep the code from aging in the compilation
13634 other_context = Context::New();
13636 // Context-dependent context data creates reference from the compilation
13637 // cache to the global object.
13638 const char* source_simple = "1";
13639 context = Context::New();
13641 v8::HandleScope scope;
13644 Local<v8::String> obj = v8::String::New("");
13645 context->SetData(obj);
13646 CompileRun(source_simple);
13650 for (gc_count = 1; gc_count < 10; gc_count++) {
13651 other_context->Enter();
13652 CompileRun(source_simple);
13653 other_context->Exit();
13654 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13655 if (GetGlobalObjectsCount() == 1) break;
13657 CHECK_GE(2, gc_count);
13658 CHECK_EQ(1, GetGlobalObjectsCount());
13660 // Eval in a function creates reference from the compilation cache to the
13662 const char* source_eval = "function f(){eval('1')}; f()";
13663 context = Context::New();
13665 v8::HandleScope scope;
13668 CompileRun(source_eval);
13672 for (gc_count = 1; gc_count < 10; gc_count++) {
13673 other_context->Enter();
13674 CompileRun(source_eval);
13675 other_context->Exit();
13676 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13677 if (GetGlobalObjectsCount() == 1) break;
13679 CHECK_GE(2, gc_count);
13680 CHECK_EQ(1, GetGlobalObjectsCount());
13682 // Looking up the line number for an exception creates reference from the
13683 // compilation cache to the global object.
13684 const char* source_exception = "function f(){throw 1;} f()";
13685 context = Context::New();
13687 v8::HandleScope scope;
13690 v8::TryCatch try_catch;
13691 CompileRun(source_exception);
13692 CHECK(try_catch.HasCaught());
13693 v8::Handle<v8::Message> message = try_catch.Message();
13694 CHECK(!message.IsEmpty());
13695 CHECK_EQ(1, message->GetLineNumber());
13699 for (gc_count = 1; gc_count < 10; gc_count++) {
13700 other_context->Enter();
13701 CompileRun(source_exception);
13702 other_context->Exit();
13703 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13704 if (GetGlobalObjectsCount() == 1) break;
13706 CHECK_GE(2, gc_count);
13707 CHECK_EQ(1, GetGlobalObjectsCount());
13709 other_context.Dispose();
13713 THREADED_TEST(ScriptOrigin) {
13714 v8::HandleScope scope;
13716 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13717 v8::Handle<v8::String> script = v8::String::New(
13718 "function f() {}\n\nfunction g() {}");
13719 v8::Script::Compile(script, &origin)->Run();
13720 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13721 env->Global()->Get(v8::String::New("f")));
13722 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13723 env->Global()->Get(v8::String::New("g")));
13725 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13726 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13727 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13729 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13730 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13731 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13735 THREADED_TEST(ScriptLineNumber) {
13736 v8::HandleScope scope;
13738 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13739 v8::Handle<v8::String> script = v8::String::New(
13740 "function f() {}\n\nfunction g() {}");
13741 v8::Script::Compile(script, &origin)->Run();
13742 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13743 env->Global()->Get(v8::String::New("f")));
13744 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13745 env->Global()->Get(v8::String::New("g")));
13746 CHECK_EQ(0, f->GetScriptLineNumber());
13747 CHECK_EQ(2, g->GetScriptLineNumber());
13751 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13752 const AccessorInfo& info) {
13757 static void SetterWhichSetsYOnThisTo23(Local<String> name,
13758 Local<Value> value,
13759 const AccessorInfo& info) {
13760 info.This()->Set(v8_str("y"), v8_num(23));
13764 TEST(SetterOnConstructorPrototype) {
13765 v8::HandleScope scope;
13766 Local<ObjectTemplate> templ = ObjectTemplate::New();
13767 templ->SetAccessor(v8_str("x"),
13768 GetterWhichReturns42,
13769 SetterWhichSetsYOnThisTo23);
13770 LocalContext context;
13771 context->Global()->Set(v8_str("P"), templ->NewInstance());
13772 CompileRun("function C1() {"
13775 "C1.prototype = P;"
13779 "C2.prototype = { };"
13780 "C2.prototype.__proto__ = P;");
13782 v8::Local<v8::Script> script;
13783 script = v8::Script::Compile(v8_str("new C1();"));
13784 for (int i = 0; i < 10; i++) {
13785 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13786 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13787 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13790 script = v8::Script::Compile(v8_str("new C2();"));
13791 for (int i = 0; i < 10; i++) {
13792 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13793 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13794 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13799 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13800 Local<String> name, const AccessorInfo& info) {
13805 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13806 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13807 if (name->Equals(v8_str("x"))) {
13808 info.This()->Set(v8_str("y"), v8_num(23));
13810 return v8::Handle<Value>();
13814 THREADED_TEST(InterceptorOnConstructorPrototype) {
13815 v8::HandleScope scope;
13816 Local<ObjectTemplate> templ = ObjectTemplate::New();
13817 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13818 NamedPropertySetterWhichSetsYOnThisTo23);
13819 LocalContext context;
13820 context->Global()->Set(v8_str("P"), templ->NewInstance());
13821 CompileRun("function C1() {"
13824 "C1.prototype = P;"
13828 "C2.prototype = { };"
13829 "C2.prototype.__proto__ = P;");
13831 v8::Local<v8::Script> script;
13832 script = v8::Script::Compile(v8_str("new C1();"));
13833 for (int i = 0; i < 10; i++) {
13834 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13835 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13836 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13839 script = v8::Script::Compile(v8_str("new C2();"));
13840 for (int i = 0; i < 10; i++) {
13841 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13842 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13843 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13849 const char* source = "function C1() {"
13852 "C1.prototype = P;";
13854 v8::HandleScope scope;
13855 LocalContext context;
13856 v8::Local<v8::Script> script;
13858 // Use a simple object as prototype.
13859 v8::Local<v8::Object> prototype = v8::Object::New();
13860 prototype->Set(v8_str("y"), v8_num(42));
13861 context->Global()->Set(v8_str("P"), prototype);
13863 // This compile will add the code to the compilation cache.
13864 CompileRun(source);
13866 script = v8::Script::Compile(v8_str("new C1();"));
13867 // Allow enough iterations for the inobject slack tracking logic
13868 // to finalize instance size and install the fast construct stub.
13869 for (int i = 0; i < 256; i++) {
13870 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13871 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13872 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13875 // Use an API object with accessors as prototype.
13876 Local<ObjectTemplate> templ = ObjectTemplate::New();
13877 templ->SetAccessor(v8_str("x"),
13878 GetterWhichReturns42,
13879 SetterWhichSetsYOnThisTo23);
13880 context->Global()->Set(v8_str("P"), templ->NewInstance());
13882 // This compile will get the code from the compilation cache.
13883 CompileRun(source);
13885 script = v8::Script::Compile(v8_str("new C1();"));
13886 for (int i = 0; i < 10; i++) {
13887 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13888 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13889 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13893 int prologue_call_count = 0;
13894 int epilogue_call_count = 0;
13895 int prologue_call_count_second = 0;
13896 int epilogue_call_count_second = 0;
13898 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13899 ++prologue_call_count;
13902 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13903 ++epilogue_call_count;
13906 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13907 ++prologue_call_count_second;
13910 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13911 ++epilogue_call_count_second;
13914 TEST(GCCallbacks) {
13915 LocalContext context;
13917 v8::V8::AddGCPrologueCallback(PrologueCallback);
13918 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13919 CHECK_EQ(0, prologue_call_count);
13920 CHECK_EQ(0, epilogue_call_count);
13921 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13922 CHECK_EQ(1, prologue_call_count);
13923 CHECK_EQ(1, epilogue_call_count);
13924 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13925 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
13926 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13927 CHECK_EQ(2, prologue_call_count);
13928 CHECK_EQ(2, epilogue_call_count);
13929 CHECK_EQ(1, prologue_call_count_second);
13930 CHECK_EQ(1, epilogue_call_count_second);
13931 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13932 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
13933 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13934 CHECK_EQ(2, prologue_call_count);
13935 CHECK_EQ(2, epilogue_call_count);
13936 CHECK_EQ(2, prologue_call_count_second);
13937 CHECK_EQ(2, epilogue_call_count_second);
13938 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13939 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
13940 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13941 CHECK_EQ(2, prologue_call_count);
13942 CHECK_EQ(2, epilogue_call_count);
13943 CHECK_EQ(2, prologue_call_count_second);
13944 CHECK_EQ(2, epilogue_call_count_second);
13948 THREADED_TEST(AddToJSFunctionResultCache) {
13949 i::FLAG_allow_natives_syntax = true;
13950 v8::HandleScope scope;
13952 LocalContext context;
13958 " var r0 = %_GetFromCache(0, key0);"
13959 " var r1 = %_GetFromCache(0, key1);"
13960 " var r0_ = %_GetFromCache(0, key0);"
13962 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13963 " var r1_ = %_GetFromCache(0, key1);"
13965 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13966 " return 'PASSED';"
13968 HEAP->ClearJSFunctionResultCaches();
13969 ExpectString(code, "PASSED");
13973 static const int k0CacheSize = 16;
13975 THREADED_TEST(FillJSFunctionResultCache) {
13976 i::FLAG_allow_natives_syntax = true;
13977 v8::HandleScope scope;
13979 LocalContext context;
13984 " var r = %_GetFromCache(0, k);"
13985 " for (var i = 0; i < 16; i++) {"
13986 " %_GetFromCache(0, 'a' + i);"
13988 " if (r === %_GetFromCache(0, k))"
13989 " return 'FAILED: k0CacheSize is too small';"
13990 " return 'PASSED';"
13992 HEAP->ClearJSFunctionResultCaches();
13993 ExpectString(code, "PASSED");
13997 THREADED_TEST(RoundRobinGetFromCache) {
13998 i::FLAG_allow_natives_syntax = true;
13999 v8::HandleScope scope;
14001 LocalContext context;
14006 " for (var i = 0; i < 16; i++) keys.push(i);"
14007 " var values = [];"
14008 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14009 " for (var i = 0; i < 16; i++) {"
14010 " var v = %_GetFromCache(0, keys[i]);"
14011 " if (v !== values[i])"
14012 " return 'Wrong value for ' + "
14013 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14015 " return 'PASSED';"
14017 HEAP->ClearJSFunctionResultCaches();
14018 ExpectString(code, "PASSED");
14022 THREADED_TEST(ReverseGetFromCache) {
14023 i::FLAG_allow_natives_syntax = true;
14024 v8::HandleScope scope;
14026 LocalContext context;
14031 " for (var i = 0; i < 16; i++) keys.push(i);"
14032 " var values = [];"
14033 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14034 " for (var i = 15; i >= 16; i--) {"
14035 " var v = %_GetFromCache(0, keys[i]);"
14036 " if (v !== values[i])"
14037 " return 'Wrong value for ' + "
14038 " keys[i] + ': ' + v + ' vs. ' + values[i];"
14040 " return 'PASSED';"
14042 HEAP->ClearJSFunctionResultCaches();
14043 ExpectString(code, "PASSED");
14047 THREADED_TEST(TestEviction) {
14048 i::FLAG_allow_natives_syntax = true;
14049 v8::HandleScope scope;
14051 LocalContext context;
14055 " for (var i = 0; i < 2*16; i++) {"
14056 " %_GetFromCache(0, 'a' + i);"
14058 " return 'PASSED';"
14060 HEAP->ClearJSFunctionResultCaches();
14061 ExpectString(code, "PASSED");
14065 THREADED_TEST(TwoByteStringInAsciiCons) {
14066 // See Chromium issue 47824.
14067 v8::HandleScope scope;
14069 LocalContext context;
14070 const char* init_code =
14071 "var str1 = 'abelspendabel';"
14072 "var str2 = str1 + str1 + str1;"
14074 Local<Value> result = CompileRun(init_code);
14076 Local<Value> indexof = CompileRun("str2.indexOf('els')");
14077 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14079 CHECK(result->IsString());
14080 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14081 int length = string->length();
14082 CHECK(string->IsAsciiRepresentation());
14084 FlattenString(string);
14085 i::Handle<i::String> flat_string = FlattenGetString(string);
14087 CHECK(string->IsAsciiRepresentation());
14088 CHECK(flat_string->IsAsciiRepresentation());
14090 // Create external resource.
14091 uint16_t* uc16_buffer = new uint16_t[length + 1];
14093 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14094 uc16_buffer[length] = 0;
14096 TestResource resource(uc16_buffer);
14098 flat_string->MakeExternal(&resource);
14100 CHECK(flat_string->IsTwoByteRepresentation());
14102 // At this point, we should have a Cons string which is flat and ASCII,
14103 // with a first half that is a two-byte string (although it only contains
14104 // ASCII characters). This is a valid sequence of steps, and it can happen
14107 CHECK(string->IsAsciiRepresentation());
14108 i::ConsString* cons = i::ConsString::cast(*string);
14109 CHECK_EQ(0, cons->second()->length());
14110 CHECK(cons->first()->IsTwoByteRepresentation());
14112 // Check that some string operations work.
14115 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14116 CHECK_EQ(6, reresult->Int32Value());
14119 reresult = CompileRun("str2.match(/abe./g).length;");
14120 CHECK_EQ(6, reresult->Int32Value());
14122 reresult = CompileRun("str2.search(/bel/g);");
14123 CHECK_EQ(1, reresult->Int32Value());
14125 reresult = CompileRun("str2.search(/be./g);");
14126 CHECK_EQ(1, reresult->Int32Value());
14128 ExpectTrue("/bel/g.test(str2);");
14130 ExpectTrue("/be./g.test(str2);");
14132 reresult = CompileRun("/bel/g.exec(str2);");
14133 CHECK(!reresult->IsNull());
14135 reresult = CompileRun("/be./g.exec(str2);");
14136 CHECK(!reresult->IsNull());
14138 ExpectString("str2.substring(2, 10);", "elspenda");
14140 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14142 ExpectString("str2.charAt(2);", "e");
14144 ExpectObject("str2.indexOf('els');", indexof);
14146 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14148 reresult = CompileRun("str2.charCodeAt(2);");
14149 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14153 // Failed access check callback that performs a GC on each invocation.
14154 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14155 v8::AccessType type,
14156 Local<v8::Value> data) {
14157 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14161 TEST(GCInFailedAccessCheckCallback) {
14162 // Install a failed access check callback that performs a GC on each
14163 // invocation. Then force the callback to be called from va
14165 v8::V8::Initialize();
14166 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14168 v8::HandleScope scope;
14170 // Create an ObjectTemplate for global objects and install access
14171 // check callbacks that will block access.
14172 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14173 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14174 IndexedGetAccessBlocker,
14175 v8::Handle<v8::Value>(),
14178 // Create a context and set an x property on it's global object.
14179 LocalContext context0(NULL, global_template);
14180 context0->Global()->Set(v8_str("x"), v8_num(42));
14181 v8::Handle<v8::Object> global0 = context0->Global();
14183 // Create a context with a different security token so that the
14184 // failed access check callback will be called on each access.
14185 LocalContext context1(NULL, global_template);
14186 context1->Global()->Set(v8_str("other"), global0);
14188 // Get property with failed access check.
14189 ExpectUndefined("other.x");
14191 // Get element with failed access check.
14192 ExpectUndefined("other[0]");
14194 // Set property with failed access check.
14195 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14196 CHECK(result->IsObject());
14198 // Set element with failed access check.
14199 result = CompileRun("other[0] = new Object()");
14200 CHECK(result->IsObject());
14202 // Get property attribute with failed access check.
14203 ExpectFalse("\'x\' in other");
14205 // Get property attribute for element with failed access check.
14206 ExpectFalse("0 in other");
14208 // Delete property.
14209 ExpectFalse("delete other.x");
14212 CHECK_EQ(false, global0->Delete(0));
14216 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14218 // Define JavaScript accessor.
14219 ExpectUndefined("Object.prototype.__defineGetter__.call("
14220 " other, \'x\', function() { return 42; })");
14223 ExpectUndefined("Object.prototype.__lookupGetter__.call("
14226 // HasLocalElement.
14227 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14229 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14230 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14231 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14233 // Reset the failed access check callback so it does not influence
14234 // the other tests.
14235 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14238 TEST(DefaultIsolateGetCurrent) {
14239 CHECK(v8::Isolate::GetCurrent() != NULL);
14240 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14241 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14242 printf("*** %s\n", "DefaultIsolateGetCurrent success");
14245 TEST(IsolateNewDispose) {
14246 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14247 v8::Isolate* isolate = v8::Isolate::New();
14248 CHECK(isolate != NULL);
14249 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14250 CHECK(current_isolate != isolate);
14251 CHECK(current_isolate == v8::Isolate::GetCurrent());
14253 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14254 last_location = last_message = NULL;
14255 isolate->Dispose();
14256 CHECK_EQ(last_location, NULL);
14257 CHECK_EQ(last_message, NULL);
14260 TEST(IsolateEnterExitDefault) {
14261 v8::HandleScope scope;
14262 LocalContext context;
14263 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14264 CHECK(current_isolate != NULL); // Default isolate.
14265 ExpectString("'hello'", "hello");
14266 current_isolate->Enter();
14267 ExpectString("'still working'", "still working");
14268 current_isolate->Exit();
14269 ExpectString("'still working 2'", "still working 2");
14270 current_isolate->Exit();
14271 // Default isolate is always, well, 'default current'.
14272 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14273 // Still working since default isolate is auto-entering any thread
14274 // that has no isolate and attempts to execute V8 APIs.
14275 ExpectString("'still working 3'", "still working 3");
14278 TEST(DisposeDefaultIsolate) {
14279 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14281 // Run some V8 code to trigger default isolate to become 'current'.
14282 v8::HandleScope scope;
14283 LocalContext context;
14284 ExpectString("'run some V8'", "run some V8");
14286 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14287 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14288 last_location = last_message = NULL;
14289 isolate->Dispose();
14290 // It is not possible to dispose default isolate via Isolate API.
14291 CHECK_NE(last_location, NULL);
14292 CHECK_NE(last_message, NULL);
14295 TEST(RunDefaultAndAnotherIsolate) {
14296 v8::HandleScope scope;
14297 LocalContext context;
14299 // Enter new isolate.
14300 v8::Isolate* isolate = v8::Isolate::New();
14303 { // Need this block because subsequent Exit() will deallocate Heap,
14304 // so we need all scope objects to be deconstructed when it happens.
14305 v8::HandleScope scope_new;
14306 LocalContext context_new;
14308 // Run something in new isolate.
14309 CompileRun("var foo = 153;");
14310 ExpectTrue("function f() { return foo == 153; }; f()");
14314 // This runs automatically in default isolate.
14315 // Variables in another isolate should be not available.
14316 ExpectTrue("function f() {"
14327 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14328 last_location = last_message = NULL;
14329 isolate->Dispose();
14330 CHECK_EQ(last_location, NULL);
14331 CHECK_EQ(last_message, NULL);
14333 // Check that default isolate still runs.
14334 ExpectTrue("function f() { return bar == 371; }; f()");
14337 TEST(DisposeIsolateWhenInUse) {
14338 v8::Isolate* isolate = v8::Isolate::New();
14341 v8::HandleScope scope;
14342 LocalContext context;
14343 // Run something in this isolate.
14344 ExpectTrue("true");
14345 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14346 last_location = last_message = NULL;
14347 // Still entered, should fail.
14348 isolate->Dispose();
14349 CHECK_NE(last_location, NULL);
14350 CHECK_NE(last_message, NULL);
14353 TEST(RunTwoIsolatesOnSingleThread) {
14355 v8::Isolate* isolate1 = v8::Isolate::New();
14357 v8::Persistent<v8::Context> context1 = v8::Context::New();
14360 v8::Context::Scope cscope(context1);
14361 v8::HandleScope scope;
14362 // Run something in new isolate.
14363 CompileRun("var foo = 'isolate 1';");
14364 ExpectString("function f() { return foo; }; f()", "isolate 1");
14368 v8::Isolate* isolate2 = v8::Isolate::New();
14369 v8::Persistent<v8::Context> context2;
14372 v8::Isolate::Scope iscope(isolate2);
14373 context2 = v8::Context::New();
14374 v8::Context::Scope cscope(context2);
14375 v8::HandleScope scope;
14377 // Run something in new isolate.
14378 CompileRun("var foo = 'isolate 2';");
14379 ExpectString("function f() { return foo; }; f()", "isolate 2");
14383 v8::Context::Scope cscope(context1);
14384 v8::HandleScope scope;
14385 // Now again in isolate 1
14386 ExpectString("function f() { return foo; }; f()", "isolate 1");
14391 // Run some stuff in default isolate.
14392 v8::Persistent<v8::Context> context_default = v8::Context::New();
14395 v8::Context::Scope cscope(context_default);
14396 v8::HandleScope scope;
14397 // Variables in other isolates should be not available, verify there
14398 // is an exception.
14399 ExpectTrue("function f() {"
14407 "var isDefaultIsolate = true;"
14414 v8::Isolate::Scope iscope(isolate2);
14415 v8::Context::Scope cscope(context2);
14416 v8::HandleScope scope;
14417 ExpectString("function f() { return foo; }; f()", "isolate 2");
14421 v8::Context::Scope cscope(context1);
14422 v8::HandleScope scope;
14423 ExpectString("function f() { return foo; }; f()", "isolate 1");
14427 v8::Isolate::Scope iscope(isolate2);
14428 context2.Dispose();
14431 context1.Dispose();
14434 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14435 last_location = last_message = NULL;
14437 isolate1->Dispose();
14438 CHECK_EQ(last_location, NULL);
14439 CHECK_EQ(last_message, NULL);
14441 isolate2->Dispose();
14442 CHECK_EQ(last_location, NULL);
14443 CHECK_EQ(last_message, NULL);
14445 // Check that default isolate still runs.
14447 v8::Context::Scope cscope(context_default);
14448 v8::HandleScope scope;
14449 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14453 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14454 v8::Isolate::Scope isolate_scope(isolate);
14455 v8::HandleScope scope;
14456 LocalContext context;
14457 i::ScopedVector<char> code(1024);
14458 i::OS::SNPrintF(code, "function fib(n) {"
14459 " if (n <= 2) return 1;"
14460 " return fib(n-1) + fib(n-2);"
14463 Local<Value> value = CompileRun(code.start());
14464 CHECK(value->IsNumber());
14465 return static_cast<int>(value->NumberValue());
14468 class IsolateThread : public v8::internal::Thread {
14470 IsolateThread(v8::Isolate* isolate, int fib_limit)
14471 : Thread("IsolateThread"),
14473 fib_limit_(fib_limit),
14477 result_ = CalcFibonacci(isolate_, fib_limit_);
14480 int result() { return result_; }
14483 v8::Isolate* isolate_;
14488 TEST(MultipleIsolatesOnIndividualThreads) {
14489 v8::Isolate* isolate1 = v8::Isolate::New();
14490 v8::Isolate* isolate2 = v8::Isolate::New();
14492 IsolateThread thread1(isolate1, 21);
14493 IsolateThread thread2(isolate2, 12);
14495 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14499 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14500 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14505 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14506 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14507 CHECK_EQ(result1, 10946);
14508 CHECK_EQ(result2, 144);
14509 CHECK_EQ(result1, thread1.result());
14510 CHECK_EQ(result2, thread2.result());
14512 isolate1->Dispose();
14513 isolate2->Dispose();
14516 TEST(IsolateDifferentContexts) {
14517 v8::Isolate* isolate = v8::Isolate::New();
14518 Persistent<v8::Context> context;
14520 v8::Isolate::Scope isolate_scope(isolate);
14521 v8::HandleScope handle_scope;
14522 context = v8::Context::New();
14523 v8::Context::Scope context_scope(context);
14524 Local<Value> v = CompileRun("2");
14525 CHECK(v->IsNumber());
14526 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14529 v8::Isolate::Scope isolate_scope(isolate);
14530 v8::HandleScope handle_scope;
14531 context = v8::Context::New();
14532 v8::Context::Scope context_scope(context);
14533 Local<Value> v = CompileRun("22");
14534 CHECK(v->IsNumber());
14535 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14539 class InitDefaultIsolateThread : public v8::internal::Thread {
14543 SetResourceConstraints,
14545 SetCounterFunction,
14546 SetCreateHistogramFunction,
14547 SetAddHistogramSampleFunction
14550 explicit InitDefaultIsolateThread(TestCase testCase)
14551 : Thread("InitDefaultIsolateThread"),
14552 testCase_(testCase),
14556 switch (testCase_) {
14558 v8::V8::IgnoreOutOfMemoryException();
14561 case SetResourceConstraints: {
14562 static const int K = 1024;
14563 v8::ResourceConstraints constraints;
14564 constraints.set_max_young_space_size(256 * K);
14565 constraints.set_max_old_space_size(4 * K * K);
14566 v8::SetResourceConstraints(&constraints);
14570 case SetFatalHandler:
14571 v8::V8::SetFatalErrorHandler(NULL);
14574 case SetCounterFunction:
14575 v8::V8::SetCounterFunction(NULL);
14578 case SetCreateHistogramFunction:
14579 v8::V8::SetCreateHistogramFunction(NULL);
14582 case SetAddHistogramSampleFunction:
14583 v8::V8::SetAddHistogramSampleFunction(NULL);
14589 bool result() { return result_; }
14592 TestCase testCase_;
14597 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14598 InitDefaultIsolateThread thread(testCase);
14601 CHECK_EQ(thread.result(), true);
14604 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14605 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14608 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14609 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14612 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14613 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14616 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14617 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14620 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14621 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14624 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14625 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14629 TEST(StringCheckMultipleContexts) {
14631 "(function() { return \"a\".charAt(0); })()";
14634 // Run the code twice in the first context to initialize the call IC.
14635 v8::HandleScope scope;
14636 LocalContext context1;
14637 ExpectString(code, "a");
14638 ExpectString(code, "a");
14642 // Change the String.prototype in the second context and check
14643 // that the right function gets called.
14644 v8::HandleScope scope;
14645 LocalContext context2;
14646 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14647 ExpectString(code, "not a");
14652 TEST(NumberCheckMultipleContexts) {
14654 "(function() { return (42).toString(); })()";
14657 // Run the code twice in the first context to initialize the call IC.
14658 v8::HandleScope scope;
14659 LocalContext context1;
14660 ExpectString(code, "42");
14661 ExpectString(code, "42");
14665 // Change the Number.prototype in the second context and check
14666 // that the right function gets called.
14667 v8::HandleScope scope;
14668 LocalContext context2;
14669 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14670 ExpectString(code, "not 42");
14675 TEST(BooleanCheckMultipleContexts) {
14677 "(function() { return true.toString(); })()";
14680 // Run the code twice in the first context to initialize the call IC.
14681 v8::HandleScope scope;
14682 LocalContext context1;
14683 ExpectString(code, "true");
14684 ExpectString(code, "true");
14688 // Change the Boolean.prototype in the second context and check
14689 // that the right function gets called.
14690 v8::HandleScope scope;
14691 LocalContext context2;
14692 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14693 ExpectString(code, "");
14698 TEST(DontDeleteCellLoadIC) {
14699 const char* function_code =
14700 "function readCell() { while (true) { return cell; } }";
14703 // Run the code twice in the first context to initialize the load
14704 // IC for a don't delete cell.
14705 v8::HandleScope scope;
14706 LocalContext context1;
14707 CompileRun("var cell = \"first\";");
14708 ExpectBoolean("delete cell", false);
14709 CompileRun(function_code);
14710 ExpectString("readCell()", "first");
14711 ExpectString("readCell()", "first");
14715 // Use a deletable cell in the second context.
14716 v8::HandleScope scope;
14717 LocalContext context2;
14718 CompileRun("cell = \"second\";");
14719 CompileRun(function_code);
14720 ExpectString("readCell()", "second");
14721 ExpectBoolean("delete cell", true);
14722 ExpectString("(function() {"
14724 " return readCell();"
14726 " return e.toString();"
14729 "ReferenceError: cell is not defined");
14730 CompileRun("cell = \"new_second\";");
14731 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14732 ExpectString("readCell()", "new_second");
14733 ExpectString("readCell()", "new_second");
14738 TEST(DontDeleteCellLoadICForceDelete) {
14739 const char* function_code =
14740 "function readCell() { while (true) { return cell; } }";
14742 // Run the code twice to initialize the load IC for a don't delete
14744 v8::HandleScope scope;
14745 LocalContext context;
14746 CompileRun("var cell = \"value\";");
14747 ExpectBoolean("delete cell", false);
14748 CompileRun(function_code);
14749 ExpectString("readCell()", "value");
14750 ExpectString("readCell()", "value");
14752 // Delete the cell using the API and check the inlined code works
14754 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14755 ExpectString("(function() {"
14757 " return readCell();"
14759 " return e.toString();"
14762 "ReferenceError: cell is not defined");
14766 TEST(DontDeleteCellLoadICAPI) {
14767 const char* function_code =
14768 "function readCell() { while (true) { return cell; } }";
14770 // Run the code twice to initialize the load IC for a don't delete
14771 // cell created using the API.
14772 v8::HandleScope scope;
14773 LocalContext context;
14774 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14775 ExpectBoolean("delete cell", false);
14776 CompileRun(function_code);
14777 ExpectString("readCell()", "value");
14778 ExpectString("readCell()", "value");
14780 // Delete the cell using the API and check the inlined code works
14782 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14783 ExpectString("(function() {"
14785 " return readCell();"
14787 " return e.toString();"
14790 "ReferenceError: cell is not defined");
14795 v8::HandleScope scope;
14796 LocalContext context;
14798 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14799 CHECK(re->IsRegExp());
14800 CHECK(re->GetSource()->Equals(v8_str("foo")));
14801 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14803 re = v8::RegExp::New(v8_str("bar"),
14804 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14805 v8::RegExp::kGlobal));
14806 CHECK(re->IsRegExp());
14807 CHECK(re->GetSource()->Equals(v8_str("bar")));
14808 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
14809 static_cast<int>(re->GetFlags()));
14811 re = v8::RegExp::New(v8_str("baz"),
14812 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14813 v8::RegExp::kMultiline));
14814 CHECK(re->IsRegExp());
14815 CHECK(re->GetSource()->Equals(v8_str("baz")));
14816 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14817 static_cast<int>(re->GetFlags()));
14819 re = CompileRun("/quux/").As<v8::RegExp>();
14820 CHECK(re->IsRegExp());
14821 CHECK(re->GetSource()->Equals(v8_str("quux")));
14822 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14824 re = CompileRun("/quux/gm").As<v8::RegExp>();
14825 CHECK(re->IsRegExp());
14826 CHECK(re->GetSource()->Equals(v8_str("quux")));
14827 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
14828 static_cast<int>(re->GetFlags()));
14830 // Override the RegExp constructor and check the API constructor
14832 CompileRun("RegExp = function() {}");
14834 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14835 CHECK(re->IsRegExp());
14836 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14837 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14839 re = v8::RegExp::New(v8_str("foobarbaz"),
14840 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14841 v8::RegExp::kMultiline));
14842 CHECK(re->IsRegExp());
14843 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14844 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14845 static_cast<int>(re->GetFlags()));
14847 context->Global()->Set(v8_str("re"), re);
14848 ExpectTrue("re.test('FoobarbaZ')");
14850 // RegExps are objects on which you can set properties.
14851 re->Set(v8_str("property"), v8::Integer::New(32));
14852 v8::Handle<v8::Value> value(CompileRun("re.property"));
14853 ASSERT_EQ(32, value->Int32Value());
14855 v8::TryCatch try_catch;
14856 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14857 CHECK(re.IsEmpty());
14858 CHECK(try_catch.HasCaught());
14859 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14860 ExpectTrue("ex instanceof SyntaxError");
14864 THREADED_TEST(Equals) {
14865 v8::HandleScope handleScope;
14866 LocalContext localContext;
14868 v8::Handle<v8::Object> globalProxy = localContext->Global();
14869 v8::Handle<Value> global = globalProxy->GetPrototype();
14871 CHECK(global->StrictEquals(global));
14872 CHECK(!global->StrictEquals(globalProxy));
14873 CHECK(!globalProxy->StrictEquals(global));
14874 CHECK(globalProxy->StrictEquals(globalProxy));
14876 CHECK(global->Equals(global));
14877 CHECK(!global->Equals(globalProxy));
14878 CHECK(!globalProxy->Equals(global));
14879 CHECK(globalProxy->Equals(globalProxy));
14883 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14884 const v8::AccessorInfo& info ) {
14885 return v8_str("42!");
14889 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14890 v8::Handle<v8::Array> result = v8::Array::New();
14891 result->Set(0, v8_str("universalAnswer"));
14896 TEST(NamedEnumeratorAndForIn) {
14897 v8::HandleScope handle_scope;
14898 LocalContext context;
14899 v8::Context::Scope context_scope(context.local());
14901 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14902 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14903 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14904 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14905 "var result = []; for (var k in o) result.push(k); result"));
14906 CHECK_EQ(1, result->Length());
14907 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14911 TEST(DefinePropertyPostDetach) {
14912 v8::HandleScope scope;
14913 LocalContext context;
14914 v8::Handle<v8::Object> proxy = context->Global();
14915 v8::Handle<v8::Function> define_property =
14916 CompileRun("(function() {"
14917 " Object.defineProperty("
14920 " { configurable: true, enumerable: true, value: 3 });"
14921 "})").As<Function>();
14922 context->DetachGlobal();
14923 define_property->Call(proxy, 0, NULL);
14927 static void InstallContextId(v8::Handle<Context> context, int id) {
14928 Context::Scope scope(context);
14929 CompileRun("Object.prototype").As<Object>()->
14930 Set(v8_str("context_id"), v8::Integer::New(id));
14934 static void CheckContextId(v8::Handle<Object> object, int expected) {
14935 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14939 THREADED_TEST(CreationContext) {
14940 HandleScope handle_scope;
14941 Persistent<Context> context1 = Context::New();
14942 InstallContextId(context1, 1);
14943 Persistent<Context> context2 = Context::New();
14944 InstallContextId(context2, 2);
14945 Persistent<Context> context3 = Context::New();
14946 InstallContextId(context3, 3);
14948 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14950 Local<Object> object1;
14951 Local<Function> func1;
14953 Context::Scope scope(context1);
14954 object1 = Object::New();
14955 func1 = tmpl->GetFunction();
14958 Local<Object> object2;
14959 Local<Function> func2;
14961 Context::Scope scope(context2);
14962 object2 = Object::New();
14963 func2 = tmpl->GetFunction();
14966 Local<Object> instance1;
14967 Local<Object> instance2;
14970 Context::Scope scope(context3);
14971 instance1 = func1->NewInstance();
14972 instance2 = func2->NewInstance();
14975 CHECK(object1->CreationContext() == context1);
14976 CheckContextId(object1, 1);
14977 CHECK(func1->CreationContext() == context1);
14978 CheckContextId(func1, 1);
14979 CHECK(instance1->CreationContext() == context1);
14980 CheckContextId(instance1, 1);
14981 CHECK(object2->CreationContext() == context2);
14982 CheckContextId(object2, 2);
14983 CHECK(func2->CreationContext() == context2);
14984 CheckContextId(func2, 2);
14985 CHECK(instance2->CreationContext() == context2);
14986 CheckContextId(instance2, 2);
14989 Context::Scope scope(context1);
14990 CHECK(object1->CreationContext() == context1);
14991 CheckContextId(object1, 1);
14992 CHECK(func1->CreationContext() == context1);
14993 CheckContextId(func1, 1);
14994 CHECK(instance1->CreationContext() == context1);
14995 CheckContextId(instance1, 1);
14996 CHECK(object2->CreationContext() == context2);
14997 CheckContextId(object2, 2);
14998 CHECK(func2->CreationContext() == context2);
14999 CheckContextId(func2, 2);
15000 CHECK(instance2->CreationContext() == context2);
15001 CheckContextId(instance2, 2);
15005 Context::Scope scope(context2);
15006 CHECK(object1->CreationContext() == context1);
15007 CheckContextId(object1, 1);
15008 CHECK(func1->CreationContext() == context1);
15009 CheckContextId(func1, 1);
15010 CHECK(instance1->CreationContext() == context1);
15011 CheckContextId(instance1, 1);
15012 CHECK(object2->CreationContext() == context2);
15013 CheckContextId(object2, 2);
15014 CHECK(func2->CreationContext() == context2);
15015 CheckContextId(func2, 2);
15016 CHECK(instance2->CreationContext() == context2);
15017 CheckContextId(instance2, 2);
15020 context1.Dispose();
15021 context2.Dispose();
15022 context3.Dispose();
15026 THREADED_TEST(CreationContextOfJsFunction) {
15027 HandleScope handle_scope;
15028 Persistent<Context> context = Context::New();
15029 InstallContextId(context, 1);
15031 Local<Object> function;
15033 Context::Scope scope(context);
15034 function = CompileRun("function foo() {}; foo").As<Object>();
15037 CHECK(function->CreationContext() == context);
15038 CheckContextId(function, 1);
15044 Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15045 const AccessorInfo& info) {
15046 if (index == 42) return v8_str("yes");
15047 return Handle<v8::Integer>();
15051 Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15052 const AccessorInfo& info) {
15053 if (property->Equals(v8_str("foo"))) return v8_str("yes");
15054 return Handle<Value>();
15058 Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15059 uint32_t index, const AccessorInfo& info) {
15060 if (index == 42) return v8_num(1).As<v8::Integer>();
15061 return Handle<v8::Integer>();
15065 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15066 Local<String> property, const AccessorInfo& info) {
15067 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15068 return Handle<v8::Integer>();
15072 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15073 Local<String> property, const AccessorInfo& info) {
15074 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15075 return Handle<v8::Integer>();
15079 Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15080 const AccessorInfo& info) {
15081 return v8_str("yes");
15085 TEST(HasOwnProperty) {
15086 v8::HandleScope scope;
15088 { // Check normal properties and defined getters.
15089 Handle<Value> value = CompileRun(
15092 " this.__defineGetter__('baz', function() { return 1; });"
15094 "function Bar() { "
15096 " this.__defineGetter__('bla', function() { return 2; });"
15098 "Bar.prototype = new Foo();"
15100 CHECK(value->IsObject());
15101 Handle<Object> object = value->ToObject();
15102 CHECK(object->Has(v8_str("foo")));
15103 CHECK(!object->HasOwnProperty(v8_str("foo")));
15104 CHECK(object->HasOwnProperty(v8_str("bar")));
15105 CHECK(object->Has(v8_str("baz")));
15106 CHECK(!object->HasOwnProperty(v8_str("baz")));
15107 CHECK(object->HasOwnProperty(v8_str("bla")));
15109 { // Check named getter interceptors.
15110 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15111 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15112 Handle<Object> instance = templ->NewInstance();
15113 CHECK(!instance->HasOwnProperty(v8_str("42")));
15114 CHECK(instance->HasOwnProperty(v8_str("foo")));
15115 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15117 { // Check indexed getter interceptors.
15118 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15119 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15120 Handle<Object> instance = templ->NewInstance();
15121 CHECK(instance->HasOwnProperty(v8_str("42")));
15122 CHECK(!instance->HasOwnProperty(v8_str("43")));
15123 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15125 { // Check named query interceptors.
15126 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15127 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15128 Handle<Object> instance = templ->NewInstance();
15129 CHECK(instance->HasOwnProperty(v8_str("foo")));
15130 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15132 { // Check indexed query interceptors.
15133 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15134 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15135 Handle<Object> instance = templ->NewInstance();
15136 CHECK(instance->HasOwnProperty(v8_str("42")));
15137 CHECK(!instance->HasOwnProperty(v8_str("41")));
15139 { // Check callbacks.
15140 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15141 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15142 Handle<Object> instance = templ->NewInstance();
15143 CHECK(instance->HasOwnProperty(v8_str("foo")));
15144 CHECK(!instance->HasOwnProperty(v8_str("bar")));
15146 { // Check that query wins on disagreement.
15147 Handle<ObjectTemplate> templ = ObjectTemplate::New();
15148 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15150 HasOwnPropertyNamedPropertyQuery2);
15151 Handle<Object> instance = templ->NewInstance();
15152 CHECK(!instance->HasOwnProperty(v8_str("foo")));
15153 CHECK(instance->HasOwnProperty(v8_str("bar")));
15158 void CheckCodeGenerationAllowed() {
15159 Handle<Value> result = CompileRun("eval('42')");
15160 CHECK_EQ(42, result->Int32Value());
15161 result = CompileRun("(function(e) { return e('42'); })(eval)");
15162 CHECK_EQ(42, result->Int32Value());
15163 result = CompileRun("var f = new Function('return 42'); f()");
15164 CHECK_EQ(42, result->Int32Value());
15168 void CheckCodeGenerationDisallowed() {
15169 TryCatch try_catch;
15171 Handle<Value> result = CompileRun("eval('42')");
15172 CHECK(result.IsEmpty());
15173 CHECK(try_catch.HasCaught());
15176 result = CompileRun("(function(e) { return e('42'); })(eval)");
15177 CHECK(result.IsEmpty());
15178 CHECK(try_catch.HasCaught());
15181 result = CompileRun("var f = new Function('return 42'); f()");
15182 CHECK(result.IsEmpty());
15183 CHECK(try_catch.HasCaught());
15187 bool CodeGenerationAllowed(Local<Context> context) {
15188 ApiTestFuzzer::Fuzz();
15193 bool CodeGenerationDisallowed(Local<Context> context) {
15194 ApiTestFuzzer::Fuzz();
15199 THREADED_TEST(AllowCodeGenFromStrings) {
15200 v8::HandleScope scope;
15201 LocalContext context;
15203 // eval and the Function constructor allowed by default.
15204 CheckCodeGenerationAllowed();
15206 // Disallow eval and the Function constructor.
15207 context->AllowCodeGenerationFromStrings(false);
15208 CheckCodeGenerationDisallowed();
15211 context->AllowCodeGenerationFromStrings(true);
15212 CheckCodeGenerationAllowed();
15214 // Disallow but setting a global callback that will allow the calls.
15215 context->AllowCodeGenerationFromStrings(false);
15216 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15217 CheckCodeGenerationAllowed();
15219 // Set a callback that disallows the code generation.
15220 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15221 CheckCodeGenerationDisallowed();
15225 static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15226 return v8::Undefined();
15230 THREADED_TEST(CallAPIFunctionOnNonObject) {
15231 v8::HandleScope scope;
15232 LocalContext context;
15233 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15234 Handle<Function> function = templ->GetFunction();
15235 context->Global()->Set(v8_str("f"), function);
15236 TryCatch try_catch;
15237 CompileRun("f.call(2)");
15241 // Regression test for issue 1470.
15242 THREADED_TEST(ReadOnlyIndexedProperties) {
15243 v8::HandleScope scope;
15244 Local<ObjectTemplate> templ = ObjectTemplate::New();
15246 LocalContext context;
15247 Local<v8::Object> obj = templ->NewInstance();
15248 context->Global()->Set(v8_str("obj"), obj);
15249 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15250 obj->Set(v8_str("1"), v8_str("foobar"));
15251 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15252 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15253 obj->Set(v8_num(2), v8_str("foobar"));
15254 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15256 // Test non-smi case.
15257 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15258 obj->Set(v8_str("2000000000"), v8_str("foobar"));
15259 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15263 THREADED_TEST(Regress1516) {
15264 v8::HandleScope scope;
15266 LocalContext context;
15267 { v8::HandleScope temp_scope;
15268 CompileRun("({'a': 0})");
15272 { i::MapCache* map_cache =
15273 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15274 elements = map_cache->NumberOfElements();
15275 CHECK_LE(1, elements);
15278 i::Isolate::Current()->heap()->CollectAllGarbage(true);
15279 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15280 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15281 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15282 CHECK_GT(elements, map_cache->NumberOfElements());
15288 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15290 v8::AccessType type,
15291 Local<Value> data) {
15292 // Only block read access to __proto__.
15293 if (type == v8::ACCESS_GET &&
15294 name->IsString() &&
15295 name->ToString()->Length() == 9 &&
15296 name->ToString()->Utf8Length() == 9) {
15298 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15299 return strncmp(buffer, "__proto__", 9) != 0;
15306 THREADED_TEST(Regress93759) {
15309 // Template for object with security check.
15310 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15311 // We don't do indexing, so any callback can be used for that.
15312 no_proto_template->SetAccessCheckCallbacks(
15313 BlockProtoNamedSecurityTestCallback,
15314 IndexedSecurityTestCallback);
15316 // Templates for objects with hidden prototypes and possibly security check.
15317 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15318 hidden_proto_template->SetHiddenPrototype(true);
15320 Local<FunctionTemplate> protected_hidden_proto_template =
15321 v8::FunctionTemplate::New();
15322 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15323 BlockProtoNamedSecurityTestCallback,
15324 IndexedSecurityTestCallback);
15325 protected_hidden_proto_template->SetHiddenPrototype(true);
15327 // Context for "foreign" objects used in test.
15328 Persistent<Context> context = v8::Context::New();
15331 // Plain object, no security check.
15332 Local<Object> simple_object = Object::New();
15334 // Object with explicit security check.
15335 Local<Object> protected_object =
15336 no_proto_template->NewInstance();
15338 // JSGlobalProxy object, always have security check.
15339 Local<Object> proxy_object =
15342 // Global object, the prototype of proxy_object. No security checks.
15343 Local<Object> global_object =
15344 proxy_object->GetPrototype()->ToObject();
15346 // Hidden prototype without security check.
15347 Local<Object> hidden_prototype =
15348 hidden_proto_template->GetFunction()->NewInstance();
15349 Local<Object> object_with_hidden =
15351 object_with_hidden->SetPrototype(hidden_prototype);
15353 // Hidden prototype with security check on the hidden prototype.
15354 Local<Object> protected_hidden_prototype =
15355 protected_hidden_proto_template->GetFunction()->NewInstance();
15356 Local<Object> object_with_protected_hidden =
15358 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15362 // Template for object for second context. Values to test are put on it as
15364 Local<ObjectTemplate> global_template = ObjectTemplate::New();
15365 global_template->Set(v8_str("simple"), simple_object);
15366 global_template->Set(v8_str("protected"), protected_object);
15367 global_template->Set(v8_str("global"), global_object);
15368 global_template->Set(v8_str("proxy"), proxy_object);
15369 global_template->Set(v8_str("hidden"), object_with_hidden);
15370 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15372 LocalContext context2(NULL, global_template);
15374 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15375 CHECK(result1->Equals(simple_object->GetPrototype()));
15377 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15378 CHECK(result2->Equals(Undefined()));
15380 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15381 CHECK(result3->Equals(global_object->GetPrototype()));
15383 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15384 CHECK(result4->Equals(Undefined()));
15386 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15387 CHECK(result5->Equals(
15388 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15390 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15391 CHECK(result6->Equals(Undefined()));
15397 static void TestReceiver(Local<Value> expected_result,
15398 Local<Value> expected_receiver,
15399 const char* code) {
15400 Local<Value> result = CompileRun(code);
15401 CHECK(result->IsObject());
15402 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15403 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15407 THREADED_TEST(ForeignFunctionReceiver) {
15410 // Create two contexts with different "id" properties ('i' and 'o').
15411 // Call a function both from its own context and from a the foreign
15412 // context, and see what "this" is bound to (returning both "this"
15413 // and "this.id" for comparison).
15415 Persistent<Context> foreign_context = v8::Context::New();
15416 foreign_context->Enter();
15417 Local<Value> foreign_function =
15418 CompileRun("function func() { return { 0: this.id, "
15420 " toString: function() { "
15427 CHECK(foreign_function->IsFunction());
15428 foreign_context->Exit();
15430 LocalContext context;
15432 Local<String> password = v8_str("Password");
15433 // Don't get hit by security checks when accessing foreign_context's
15434 // global receiver (aka. global proxy).
15435 context->SetSecurityToken(password);
15436 foreign_context->SetSecurityToken(password);
15438 Local<String> i = v8_str("i");
15439 Local<String> o = v8_str("o");
15440 Local<String> id = v8_str("id");
15442 CompileRun("function ownfunc() { return { 0: this.id, "
15444 " toString: function() { "
15451 context->Global()->Set(v8_str("func"), foreign_function);
15453 // Sanity check the contexts.
15454 CHECK(i->Equals(foreign_context->Global()->Get(id)));
15455 CHECK(o->Equals(context->Global()->Get(id)));
15457 // Checking local function's receiver.
15458 // Calling function using its call/apply methods.
15459 TestReceiver(o, context->Global(), "ownfunc.call()");
15460 TestReceiver(o, context->Global(), "ownfunc.apply()");
15461 // Making calls through built-in functions.
15462 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15463 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15464 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15465 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15466 // Calling with environment record as base.
15467 TestReceiver(o, context->Global(), "ownfunc()");
15468 // Calling with no base.
15469 TestReceiver(o, context->Global(), "(1,ownfunc)()");
15471 // Checking foreign function return value.
15472 // Calling function using its call/apply methods.
15473 TestReceiver(i, foreign_context->Global(), "func.call()");
15474 TestReceiver(i, foreign_context->Global(), "func.apply()");
15475 // Calling function using another context's call/apply methods.
15476 TestReceiver(i, foreign_context->Global(),
15477 "Function.prototype.call.call(func)");
15478 TestReceiver(i, foreign_context->Global(),
15479 "Function.prototype.call.apply(func)");
15480 TestReceiver(i, foreign_context->Global(),
15481 "Function.prototype.apply.call(func)");
15482 TestReceiver(i, foreign_context->Global(),
15483 "Function.prototype.apply.apply(func)");
15484 // Making calls through built-in functions.
15485 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15486 // ToString(func()) is func()[0], i.e., the returned this.id.
15487 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15488 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15489 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15491 // TODO(1547): Make the following also return "i".
15492 // Calling with environment record as base.
15493 TestReceiver(o, context->Global(), "func()");
15494 // Calling with no base.
15495 TestReceiver(o, context->Global(), "(1,func)()");
15497 foreign_context.Dispose();