1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
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.
31 #include <signal.h> // kill
32 #include <unistd.h> // getpid
39 #include "compilation-cache.h"
40 #include "execution.h"
47 #include "unicode-inl.h"
49 static const bool kLogThreading = false;
51 static bool IsNaN(double x) {
59 using ::v8::AccessorInfo;
60 using ::v8::Arguments;
62 using ::v8::Extension;
64 using ::v8::FunctionTemplate;
66 using ::v8::HandleScope;
69 using ::v8::MessageCallback;
71 using ::v8::ObjectTemplate;
72 using ::v8::Persistent;
74 using ::v8::StackTrace;
77 using ::v8::Undefined;
82 static void ExpectString(const char* code, const char* expected) {
83 Local<Value> result = CompileRun(code);
84 CHECK(result->IsString());
85 String::AsciiValue ascii(result);
86 CHECK_EQ(expected, *ascii);
89 static void ExpectInt32(const char* code, int expected) {
90 Local<Value> result = CompileRun(code);
91 CHECK(result->IsInt32());
92 CHECK_EQ(expected, result->Int32Value());
95 static void ExpectBoolean(const char* code, bool expected) {
96 Local<Value> result = CompileRun(code);
97 CHECK(result->IsBoolean());
98 CHECK_EQ(expected, result->BooleanValue());
102 static void ExpectTrue(const char* code) {
103 ExpectBoolean(code, true);
107 static void ExpectFalse(const char* code) {
108 ExpectBoolean(code, false);
112 static void ExpectObject(const char* code, Local<Value> expected) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->Equals(expected));
118 static void ExpectUndefined(const char* code) {
119 Local<Value> result = CompileRun(code);
120 CHECK(result->IsUndefined());
124 static int signature_callback_count;
125 static v8::Handle<Value> IncrementingSignatureCallback(
126 const v8::Arguments& args) {
127 ApiTestFuzzer::Fuzz();
128 signature_callback_count++;
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++)
131 result->Set(v8::Integer::New(i), args[i]);
136 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
137 ApiTestFuzzer::Fuzz();
138 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
139 for (int i = 0; i < args.Length(); i++) {
140 result->Set(v8::Integer::New(i), args[i]);
146 THREADED_TEST(Handles) {
147 v8::HandleScope scope;
148 Local<Context> local_env;
151 local_env = env.local();
154 // Local context should still be live.
155 CHECK(!local_env.IsEmpty());
158 v8::Handle<v8::Primitive> undef = v8::Undefined();
159 CHECK(!undef.IsEmpty());
160 CHECK(undef->IsUndefined());
162 const char* c_source = "1 + 2 + 3";
163 Local<String> source = String::New(c_source);
164 Local<Script> script = Script::Compile(source);
165 CHECK_EQ(6, script->Run()->Int32Value());
171 THREADED_TEST(ReceiverSignature) {
172 v8::HandleScope scope;
174 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
175 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
176 fun->PrototypeTemplate()->Set(
178 v8::FunctionTemplate::New(IncrementingSignatureCallback,
181 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
182 signature_callback_count = 0;
186 CHECK_EQ(1, signature_callback_count);
187 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
188 sub_fun->Inherit(fun);
189 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
191 "var o = new SubFun();"
193 CHECK_EQ(2, signature_callback_count);
195 v8::TryCatch try_catch;
198 "o.m = Fun.prototype.m;"
200 CHECK_EQ(2, signature_callback_count);
201 CHECK(try_catch.HasCaught());
203 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
204 sub_fun->Inherit(fun);
205 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
207 "var o = new UnrelFun();"
208 "o.m = Fun.prototype.m;"
210 CHECK_EQ(2, signature_callback_count);
211 CHECK(try_catch.HasCaught());
215 THREADED_TEST(ArgumentSignature) {
216 v8::HandleScope scope;
218 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
219 cons->SetClassName(v8_str("Cons"));
220 v8::Handle<v8::Signature> sig =
221 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
222 v8::Handle<v8::FunctionTemplate> fun =
223 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
224 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
225 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
227 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
228 CHECK(value1->IsTrue());
230 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
231 CHECK(value2->IsTrue());
233 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
234 CHECK(value3->IsTrue());
236 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
237 cons1->SetClassName(v8_str("Cons1"));
238 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
239 cons2->SetClassName(v8_str("Cons2"));
240 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
241 cons3->SetClassName(v8_str("Cons3"));
243 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
244 v8::Handle<v8::Signature> wsig =
245 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
246 v8::Handle<v8::FunctionTemplate> fun2 =
247 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
249 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
250 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
251 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
252 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
253 v8::Handle<Value> value4 = CompileRun(
254 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
255 "'[object Cons1],[object Cons2],[object Cons3]'");
256 CHECK(value4->IsTrue());
258 v8::Handle<Value> value5 = CompileRun(
259 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
260 CHECK(value5->IsTrue());
262 v8::Handle<Value> value6 = CompileRun(
263 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
264 CHECK(value6->IsTrue());
266 v8::Handle<Value> value7 = CompileRun(
267 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
268 "'[object Cons1],[object Cons2],[object Cons3],d';");
269 CHECK(value7->IsTrue());
271 v8::Handle<Value> value8 = CompileRun(
272 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
273 CHECK(value8->IsTrue());
277 THREADED_TEST(HulIgennem) {
278 v8::HandleScope scope;
280 v8::Handle<v8::Primitive> undef = v8::Undefined();
281 Local<String> undef_str = undef->ToString();
282 char* value = i::NewArray<char>(undef_str->Length() + 1);
283 undef_str->WriteAscii(value);
284 CHECK_EQ(0, strcmp(value, "undefined"));
285 i::DeleteArray(value);
289 THREADED_TEST(Access) {
290 v8::HandleScope scope;
292 Local<v8::Object> obj = v8::Object::New();
293 Local<Value> foo_before = obj->Get(v8_str("foo"));
294 CHECK(foo_before->IsUndefined());
295 Local<String> bar_str = v8_str("bar");
296 obj->Set(v8_str("foo"), bar_str);
297 Local<Value> foo_after = obj->Get(v8_str("foo"));
298 CHECK(!foo_after->IsUndefined());
299 CHECK(foo_after->IsString());
300 CHECK_EQ(bar_str, foo_after);
304 THREADED_TEST(AccessElement) {
305 v8::HandleScope scope;
307 Local<v8::Object> obj = v8::Object::New();
308 Local<Value> before = obj->Get(1);
309 CHECK(before->IsUndefined());
310 Local<String> bar_str = v8_str("bar");
311 obj->Set(1, bar_str);
312 Local<Value> after = obj->Get(1);
313 CHECK(!after->IsUndefined());
314 CHECK(after->IsString());
315 CHECK_EQ(bar_str, after);
317 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
318 CHECK_EQ(v8_str("a"), value->Get(0));
319 CHECK_EQ(v8_str("b"), value->Get(1));
323 THREADED_TEST(Script) {
324 v8::HandleScope scope;
326 const char* c_source = "1 + 2 + 3";
327 Local<String> source = String::New(c_source);
328 Local<Script> script = Script::Compile(source);
329 CHECK_EQ(6, script->Run()->Int32Value());
333 static uint16_t* AsciiToTwoByteString(const char* source) {
334 int array_length = i::StrLength(source) + 1;
335 uint16_t* converted = i::NewArray<uint16_t>(array_length);
336 for (int i = 0; i < array_length; i++) converted[i] = source[i];
341 class TestResource: public String::ExternalStringResource {
343 explicit TestResource(uint16_t* data, int* counter = NULL)
344 : data_(data), length_(0), counter_(counter) {
345 while (data[length_]) ++length_;
349 i::DeleteArray(data_);
350 if (counter_ != NULL) ++*counter_;
353 const uint16_t* data() const {
357 size_t length() const {
367 class TestAsciiResource: public String::ExternalAsciiStringResource {
369 explicit TestAsciiResource(const char* data, int* counter = NULL)
370 : data_(data), length_(strlen(data)), counter_(counter) { }
372 ~TestAsciiResource() {
373 i::DeleteArray(data_);
374 if (counter_ != NULL) ++*counter_;
377 const char* data() const {
381 size_t length() const {
391 THREADED_TEST(ScriptUsingStringResource) {
392 int dispose_count = 0;
393 const char* c_source = "1 + 2 * 3";
394 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
396 v8::HandleScope scope;
398 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
399 Local<String> source = String::NewExternal(resource);
400 Local<Script> script = Script::Compile(source);
401 Local<Value> value = script->Run();
402 CHECK(value->IsNumber());
403 CHECK_EQ(7, value->Int32Value());
404 CHECK(source->IsExternal());
406 static_cast<TestResource*>(source->GetExternalStringResource()));
407 String::Encoding encoding = String::UNKNOWN_ENCODING;
408 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
409 source->GetExternalStringResourceBase(&encoding));
410 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
411 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
412 CHECK_EQ(0, dispose_count);
414 v8::internal::Isolate::Current()->compilation_cache()->Clear();
415 HEAP->CollectAllAvailableGarbage();
416 CHECK_EQ(1, dispose_count);
420 THREADED_TEST(ScriptUsingAsciiStringResource) {
421 int dispose_count = 0;
422 const char* c_source = "1 + 2 * 3";
424 v8::HandleScope scope;
426 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
428 Local<String> source = String::NewExternal(resource);
429 CHECK(source->IsExternalAscii());
430 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
431 source->GetExternalAsciiStringResource());
432 String::Encoding encoding = String::UNKNOWN_ENCODING;
433 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
434 source->GetExternalStringResourceBase(&encoding));
435 CHECK_EQ(String::ASCII_ENCODING, encoding);
436 Local<Script> script = Script::Compile(source);
437 Local<Value> value = script->Run();
438 CHECK(value->IsNumber());
439 CHECK_EQ(7, value->Int32Value());
440 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
441 CHECK_EQ(0, dispose_count);
443 i::Isolate::Current()->compilation_cache()->Clear();
444 HEAP->CollectAllAvailableGarbage();
445 CHECK_EQ(1, dispose_count);
449 THREADED_TEST(ScriptMakingExternalString) {
450 int dispose_count = 0;
451 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
453 v8::HandleScope scope;
455 Local<String> source = String::New(two_byte_source);
456 // Trigger GCs so that the newly allocated string moves to old gen.
457 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
458 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
459 CHECK_EQ(source->IsExternal(), false);
460 CHECK_EQ(source->IsExternalAscii(), false);
461 String::Encoding encoding = String::UNKNOWN_ENCODING;
462 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
463 CHECK_EQ(String::ASCII_ENCODING, encoding);
464 bool success = source->MakeExternal(new TestResource(two_byte_source,
467 Local<Script> script = Script::Compile(source);
468 Local<Value> value = script->Run();
469 CHECK(value->IsNumber());
470 CHECK_EQ(7, value->Int32Value());
471 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
472 CHECK_EQ(0, dispose_count);
474 i::Isolate::Current()->compilation_cache()->Clear();
475 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
476 CHECK_EQ(1, dispose_count);
480 THREADED_TEST(ScriptMakingExternalAsciiString) {
481 int dispose_count = 0;
482 const char* c_source = "1 + 2 * 3";
484 v8::HandleScope scope;
486 Local<String> source = v8_str(c_source);
487 // Trigger GCs so that the newly allocated string moves to old gen.
488 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
489 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
490 bool success = source->MakeExternal(
491 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
493 Local<Script> script = Script::Compile(source);
494 Local<Value> value = script->Run();
495 CHECK(value->IsNumber());
496 CHECK_EQ(7, value->Int32Value());
497 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
498 CHECK_EQ(0, dispose_count);
500 i::Isolate::Current()->compilation_cache()->Clear();
501 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
502 CHECK_EQ(1, dispose_count);
506 TEST(MakingExternalStringConditions) {
507 v8::HandleScope scope;
510 // Free some space in the new space so that we can check freshness.
511 HEAP->CollectGarbage(i::NEW_SPACE);
512 HEAP->CollectGarbage(i::NEW_SPACE);
514 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
515 Local<String> small_string = String::New(two_byte_string);
516 i::DeleteArray(two_byte_string);
518 // We should refuse to externalize newly created small string.
519 CHECK(!small_string->CanMakeExternal());
520 // Trigger GCs so that the newly allocated string moves to old gen.
521 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
522 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
523 // Old space strings should be accepted.
524 CHECK(small_string->CanMakeExternal());
526 two_byte_string = AsciiToTwoByteString("small string 2");
527 small_string = String::New(two_byte_string);
528 i::DeleteArray(two_byte_string);
530 // We should refuse externalizing newly created small string.
531 CHECK(!small_string->CanMakeExternal());
532 for (int i = 0; i < 100; i++) {
533 String::Value value(small_string);
535 // Frequently used strings should be accepted.
536 CHECK(small_string->CanMakeExternal());
538 const int buf_size = 10 * 1024;
539 char* buf = i::NewArray<char>(buf_size);
540 memset(buf, 'a', buf_size);
541 buf[buf_size - 1] = '\0';
543 two_byte_string = AsciiToTwoByteString(buf);
544 Local<String> large_string = String::New(two_byte_string);
546 i::DeleteArray(two_byte_string);
547 // Large strings should be immediately accepted.
548 CHECK(large_string->CanMakeExternal());
552 TEST(MakingExternalAsciiStringConditions) {
553 v8::HandleScope scope;
556 // Free some space in the new space so that we can check freshness.
557 HEAP->CollectGarbage(i::NEW_SPACE);
558 HEAP->CollectGarbage(i::NEW_SPACE);
560 Local<String> small_string = String::New("s1");
561 // We should refuse to externalize newly created small string.
562 CHECK(!small_string->CanMakeExternal());
563 // Trigger GCs so that the newly allocated string moves to old gen.
564 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
565 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
566 // Old space strings should be accepted.
567 CHECK(small_string->CanMakeExternal());
569 small_string = String::New("small string 2");
570 // We should refuse externalizing newly created small string.
571 CHECK(!small_string->CanMakeExternal());
572 for (int i = 0; i < 100; i++) {
573 String::Value value(small_string);
575 // Frequently used strings should be accepted.
576 CHECK(small_string->CanMakeExternal());
578 const int buf_size = 10 * 1024;
579 char* buf = i::NewArray<char>(buf_size);
580 memset(buf, 'a', buf_size);
581 buf[buf_size - 1] = '\0';
582 Local<String> large_string = String::New(buf);
584 // Large strings should be immediately accepted.
585 CHECK(large_string->CanMakeExternal());
589 THREADED_TEST(UsingExternalString) {
591 v8::HandleScope scope;
592 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
593 Local<String> string =
594 String::NewExternal(new TestResource(two_byte_string));
595 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596 // Trigger GCs so that the newly allocated string moves to old gen.
597 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
598 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
599 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
600 CHECK(isymbol->IsSymbol());
602 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
603 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
607 THREADED_TEST(UsingExternalAsciiString) {
609 v8::HandleScope scope;
610 const char* one_byte_string = "test string";
611 Local<String> string = String::NewExternal(
612 new TestAsciiResource(i::StrDup(one_byte_string)));
613 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
614 // Trigger GCs so that the newly allocated string moves to old gen.
615 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
616 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
617 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
618 CHECK(isymbol->IsSymbol());
620 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
621 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
625 THREADED_TEST(ScavengeExternalString) {
626 int dispose_count = 0;
627 bool in_new_space = false;
629 v8::HandleScope scope;
630 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
631 Local<String> string =
632 String::NewExternal(new TestResource(two_byte_string,
634 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
635 HEAP->CollectGarbage(i::NEW_SPACE);
636 in_new_space = HEAP->InNewSpace(*istring);
637 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
638 CHECK_EQ(0, dispose_count);
640 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
641 CHECK_EQ(1, dispose_count);
645 THREADED_TEST(ScavengeExternalAsciiString) {
646 int dispose_count = 0;
647 bool in_new_space = false;
649 v8::HandleScope scope;
650 const char* one_byte_string = "test string";
651 Local<String> string = String::NewExternal(
652 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
653 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
654 HEAP->CollectGarbage(i::NEW_SPACE);
655 in_new_space = HEAP->InNewSpace(*istring);
656 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
657 CHECK_EQ(0, dispose_count);
659 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
660 CHECK_EQ(1, dispose_count);
664 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
666 // Only used by non-threaded tests, so it can use static fields.
667 static int dispose_calls;
668 static int dispose_count;
670 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
671 : TestAsciiResource(data, &dispose_count),
672 dispose_(dispose) { }
676 if (dispose_) delete this;
683 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
684 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
687 TEST(ExternalStringWithDisposeHandling) {
688 const char* c_source = "1 + 2 * 3";
690 // Use a stack allocated external string resource allocated object.
691 TestAsciiResourceWithDisposeControl::dispose_count = 0;
692 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
695 v8::HandleScope scope;
697 Local<String> source = String::NewExternal(&res_stack);
698 Local<Script> script = Script::Compile(source);
699 Local<Value> value = script->Run();
700 CHECK(value->IsNumber());
701 CHECK_EQ(7, value->Int32Value());
702 HEAP->CollectAllAvailableGarbage();
703 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
705 i::Isolate::Current()->compilation_cache()->Clear();
706 HEAP->CollectAllAvailableGarbage();
707 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
708 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
710 // Use a heap allocated external string resource allocated object.
711 TestAsciiResourceWithDisposeControl::dispose_count = 0;
712 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
713 TestAsciiResource* res_heap =
714 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
716 v8::HandleScope scope;
718 Local<String> source = String::NewExternal(res_heap);
719 Local<Script> script = Script::Compile(source);
720 Local<Value> value = script->Run();
721 CHECK(value->IsNumber());
722 CHECK_EQ(7, value->Int32Value());
723 HEAP->CollectAllAvailableGarbage();
724 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
726 i::Isolate::Current()->compilation_cache()->Clear();
727 HEAP->CollectAllAvailableGarbage();
728 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
729 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
733 THREADED_TEST(StringConcat) {
735 v8::HandleScope scope;
737 const char* one_byte_string_1 = "function a_times_t";
738 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
739 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
740 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
741 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
742 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
743 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
744 Local<String> left = v8_str(one_byte_string_1);
746 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
747 Local<String> right = String::New(two_byte_source);
748 i::DeleteArray(two_byte_source);
750 Local<String> source = String::Concat(left, right);
751 right = String::NewExternal(
752 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
753 source = String::Concat(source, right);
754 right = String::NewExternal(
755 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
756 source = String::Concat(source, right);
757 right = v8_str(one_byte_string_2);
758 source = String::Concat(source, right);
760 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
761 right = String::New(two_byte_source);
762 i::DeleteArray(two_byte_source);
764 source = String::Concat(source, right);
765 right = String::NewExternal(
766 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
767 source = String::Concat(source, right);
768 Local<Script> script = Script::Compile(source);
769 Local<Value> value = script->Run();
770 CHECK(value->IsNumber());
771 CHECK_EQ(68, value->Int32Value());
773 i::Isolate::Current()->compilation_cache()->Clear();
774 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
775 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
779 THREADED_TEST(GlobalProperties) {
780 v8::HandleScope scope;
782 v8::Handle<v8::Object> global = env->Global();
783 global->Set(v8_str("pi"), v8_num(3.1415926));
784 Local<Value> pi = global->Get(v8_str("pi"));
785 CHECK_EQ(3.1415926, pi->NumberValue());
789 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
790 ApiTestFuzzer::Fuzz();
795 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
796 ApiTestFuzzer::Fuzz();
797 args.This()->Set(v8_str("x"), v8_num(1));
798 args.This()->Set(v8_str("y"), v8_num(2));
802 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
803 ApiTestFuzzer::Fuzz();
808 THREADED_TEST(FunctionTemplate) {
809 v8::HandleScope scope;
812 Local<v8::FunctionTemplate> fun_templ =
813 v8::FunctionTemplate::New(handle_call);
814 Local<Function> fun = fun_templ->GetFunction();
815 env->Global()->Set(v8_str("obj"), fun);
816 Local<Script> script = v8_compile("obj()");
817 CHECK_EQ(102, script->Run()->Int32Value());
819 // Use SetCallHandler to initialize a function template, should work like the
822 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
823 fun_templ->SetCallHandler(handle_call);
824 Local<Function> fun = fun_templ->GetFunction();
825 env->Global()->Set(v8_str("obj"), fun);
826 Local<Script> script = v8_compile("obj()");
827 CHECK_EQ(102, script->Run()->Int32Value());
829 // Test constructor calls.
831 Local<v8::FunctionTemplate> fun_templ =
832 v8::FunctionTemplate::New(construct_call);
833 fun_templ->SetClassName(v8_str("funky"));
834 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
835 Local<Function> fun = fun_templ->GetFunction();
836 env->Global()->Set(v8_str("obj"), fun);
837 Local<Script> script = v8_compile("var s = new obj(); s.x");
838 CHECK_EQ(1, script->Run()->Int32Value());
840 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
841 CHECK_EQ(v8_str("[object funky]"), result);
843 result = v8_compile("(new obj()).m")->Run();
844 CHECK_EQ(239, result->Int32Value());
849 static void* expected_ptr;
850 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
851 void* ptr = v8::External::Unwrap(args.Data());
852 CHECK_EQ(expected_ptr, ptr);
857 static void TestExternalPointerWrapping() {
858 v8::HandleScope scope;
861 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
863 v8::Handle<v8::Object> obj = v8::Object::New();
864 obj->Set(v8_str("func"),
865 v8::FunctionTemplate::New(callback, data)->GetFunction());
866 env->Global()->Set(v8_str("obj"), obj);
870 " for (var i = 0; i < 13; i++) obj.func();\n"
872 "foo(), true")->BooleanValue());
876 THREADED_TEST(ExternalWrap) {
877 // Check heap allocated object.
880 TestExternalPointerWrapping();
883 // Check stack allocated object.
886 TestExternalPointerWrapping();
888 // Check not aligned addresses.
890 char* s = new char[n];
891 for (int i = 0; i < n; i++) {
892 expected_ptr = s + i;
893 TestExternalPointerWrapping();
898 // Check several invalid addresses.
899 expected_ptr = reinterpret_cast<void*>(1);
900 TestExternalPointerWrapping();
902 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
903 TestExternalPointerWrapping();
905 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
906 TestExternalPointerWrapping();
908 #if defined(V8_HOST_ARCH_X64)
909 // Check a value with a leading 1 bit in x64 Smi encoding.
910 expected_ptr = reinterpret_cast<void*>(0x400000000);
911 TestExternalPointerWrapping();
913 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
914 TestExternalPointerWrapping();
916 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
917 TestExternalPointerWrapping();
922 THREADED_TEST(FindInstanceInPrototypeChain) {
923 v8::HandleScope scope;
926 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
927 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
928 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
929 derived->Inherit(base);
931 Local<v8::Function> base_function = base->GetFunction();
932 Local<v8::Function> derived_function = derived->GetFunction();
933 Local<v8::Function> other_function = other->GetFunction();
935 Local<v8::Object> base_instance = base_function->NewInstance();
936 Local<v8::Object> derived_instance = derived_function->NewInstance();
937 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
938 Local<v8::Object> other_instance = other_function->NewInstance();
939 derived_instance2->Set(v8_str("__proto__"), derived_instance);
940 other_instance->Set(v8_str("__proto__"), derived_instance2);
942 // base_instance is only an instance of base.
943 CHECK_EQ(base_instance,
944 base_instance->FindInstanceInPrototypeChain(base));
945 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
946 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
948 // derived_instance is an instance of base and derived.
949 CHECK_EQ(derived_instance,
950 derived_instance->FindInstanceInPrototypeChain(base));
951 CHECK_EQ(derived_instance,
952 derived_instance->FindInstanceInPrototypeChain(derived));
953 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
955 // other_instance is an instance of other and its immediate
956 // prototype derived_instance2 is an instance of base and derived.
957 // Note, derived_instance is an instance of base and derived too,
958 // but it comes after derived_instance2 in the prototype chain of
960 CHECK_EQ(derived_instance2,
961 other_instance->FindInstanceInPrototypeChain(base));
962 CHECK_EQ(derived_instance2,
963 other_instance->FindInstanceInPrototypeChain(derived));
964 CHECK_EQ(other_instance,
965 other_instance->FindInstanceInPrototypeChain(other));
969 THREADED_TEST(TinyInteger) {
970 v8::HandleScope scope;
972 v8::Isolate* isolate = v8::Isolate::GetCurrent();
975 Local<v8::Integer> value_obj = v8::Integer::New(value);
976 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
978 value_obj = v8::Integer::New(value, isolate);
979 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983 THREADED_TEST(BigSmiInteger) {
984 v8::HandleScope scope;
986 v8::Isolate* isolate = v8::Isolate::GetCurrent();
988 int32_t value = i::Smi::kMaxValue;
989 // We cannot add one to a Smi::kMaxValue without wrapping.
990 if (i::kSmiValueSize < 32) {
991 CHECK(i::Smi::IsValid(value));
992 CHECK(!i::Smi::IsValid(value + 1));
994 Local<v8::Integer> value_obj = v8::Integer::New(value);
995 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
997 value_obj = v8::Integer::New(value, isolate);
998 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1003 THREADED_TEST(BigInteger) {
1004 v8::HandleScope scope;
1006 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1008 // We cannot add one to a Smi::kMaxValue without wrapping.
1009 if (i::kSmiValueSize < 32) {
1010 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1011 // The code will not be run in that case, due to the "if" guard.
1013 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1014 CHECK(value > i::Smi::kMaxValue);
1015 CHECK(!i::Smi::IsValid(value));
1017 Local<v8::Integer> value_obj = v8::Integer::New(value);
1018 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1020 value_obj = v8::Integer::New(value, isolate);
1021 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026 THREADED_TEST(TinyUnsignedInteger) {
1027 v8::HandleScope scope;
1029 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1031 uint32_t value = 239;
1033 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1034 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1036 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1037 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1041 THREADED_TEST(BigUnsignedSmiInteger) {
1042 v8::HandleScope scope;
1044 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1046 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1047 CHECK(i::Smi::IsValid(value));
1048 CHECK(!i::Smi::IsValid(value + 1));
1050 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1051 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1053 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1054 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1058 THREADED_TEST(BigUnsignedInteger) {
1059 v8::HandleScope scope;
1061 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1063 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1064 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1065 CHECK(!i::Smi::IsValid(value));
1067 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1068 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1070 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1071 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1075 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1076 v8::HandleScope scope;
1078 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1080 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1081 uint32_t value = INT32_MAX_AS_UINT + 1;
1082 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1084 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1085 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1087 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1088 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1092 THREADED_TEST(IsNativeError) {
1093 v8::HandleScope scope;
1095 v8::Handle<Value> syntax_error = CompileRun(
1096 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1097 CHECK(syntax_error->IsNativeError());
1098 v8::Handle<Value> not_error = CompileRun("{a:42}");
1099 CHECK(!not_error->IsNativeError());
1100 v8::Handle<Value> not_object = CompileRun("42");
1101 CHECK(!not_object->IsNativeError());
1105 THREADED_TEST(StringObject) {
1106 v8::HandleScope scope;
1108 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1109 CHECK(boxed_string->IsStringObject());
1110 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1111 CHECK(!unboxed_string->IsStringObject());
1112 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1113 CHECK(!boxed_not_string->IsStringObject());
1114 v8::Handle<Value> not_object = CompileRun("0");
1115 CHECK(!not_object->IsStringObject());
1116 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1117 CHECK(!as_boxed.IsEmpty());
1118 Local<v8::String> the_string = as_boxed->StringValue();
1119 CHECK(!the_string.IsEmpty());
1120 ExpectObject("\"test\"", the_string);
1121 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1122 CHECK(new_boxed_string->IsStringObject());
1123 as_boxed = new_boxed_string.As<v8::StringObject>();
1124 the_string = as_boxed->StringValue();
1125 CHECK(!the_string.IsEmpty());
1126 ExpectObject("\"test\"", the_string);
1130 THREADED_TEST(NumberObject) {
1131 v8::HandleScope scope;
1133 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1134 CHECK(boxed_number->IsNumberObject());
1135 v8::Handle<Value> unboxed_number = CompileRun("42");
1136 CHECK(!unboxed_number->IsNumberObject());
1137 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1138 CHECK(!boxed_not_number->IsNumberObject());
1139 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1140 CHECK(!as_boxed.IsEmpty());
1141 double the_number = as_boxed->NumberValue();
1142 CHECK_EQ(42.0, the_number);
1143 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1144 CHECK(new_boxed_number->IsNumberObject());
1145 as_boxed = new_boxed_number.As<v8::NumberObject>();
1146 the_number = as_boxed->NumberValue();
1147 CHECK_EQ(43.0, the_number);
1151 THREADED_TEST(BooleanObject) {
1152 v8::HandleScope scope;
1154 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1155 CHECK(boxed_boolean->IsBooleanObject());
1156 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1157 CHECK(!unboxed_boolean->IsBooleanObject());
1158 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1159 CHECK(!boxed_not_boolean->IsBooleanObject());
1160 v8::Handle<v8::BooleanObject> as_boxed =
1161 boxed_boolean.As<v8::BooleanObject>();
1162 CHECK(!as_boxed.IsEmpty());
1163 bool the_boolean = as_boxed->BooleanValue();
1164 CHECK_EQ(true, the_boolean);
1165 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1166 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1167 CHECK(boxed_true->IsBooleanObject());
1168 CHECK(boxed_false->IsBooleanObject());
1169 as_boxed = boxed_true.As<v8::BooleanObject>();
1170 CHECK_EQ(true, as_boxed->BooleanValue());
1171 as_boxed = boxed_false.As<v8::BooleanObject>();
1172 CHECK_EQ(false, as_boxed->BooleanValue());
1176 THREADED_TEST(Number) {
1177 v8::HandleScope scope;
1179 double PI = 3.1415926;
1180 Local<v8::Number> pi_obj = v8::Number::New(PI);
1181 CHECK_EQ(PI, pi_obj->NumberValue());
1185 THREADED_TEST(ToNumber) {
1186 v8::HandleScope scope;
1188 Local<String> str = v8_str("3.1415926");
1189 CHECK_EQ(3.1415926, str->NumberValue());
1190 v8::Handle<v8::Boolean> t = v8::True();
1191 CHECK_EQ(1.0, t->NumberValue());
1192 v8::Handle<v8::Boolean> f = v8::False();
1193 CHECK_EQ(0.0, f->NumberValue());
1197 THREADED_TEST(Date) {
1198 v8::HandleScope scope;
1200 double PI = 3.1415926;
1201 Local<Value> date = v8::Date::New(PI);
1202 CHECK_EQ(3.0, date->NumberValue());
1203 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1204 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1208 THREADED_TEST(Boolean) {
1209 v8::HandleScope scope;
1211 v8::Handle<v8::Boolean> t = v8::True();
1213 v8::Handle<v8::Boolean> f = v8::False();
1215 v8::Handle<v8::Primitive> u = v8::Undefined();
1216 CHECK(!u->BooleanValue());
1217 v8::Handle<v8::Primitive> n = v8::Null();
1218 CHECK(!n->BooleanValue());
1219 v8::Handle<String> str1 = v8_str("");
1220 CHECK(!str1->BooleanValue());
1221 v8::Handle<String> str2 = v8_str("x");
1222 CHECK(str2->BooleanValue());
1223 CHECK(!v8::Number::New(0)->BooleanValue());
1224 CHECK(v8::Number::New(-1)->BooleanValue());
1225 CHECK(v8::Number::New(1)->BooleanValue());
1226 CHECK(v8::Number::New(42)->BooleanValue());
1227 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1231 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1232 ApiTestFuzzer::Fuzz();
1233 return v8_num(13.4);
1237 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1238 ApiTestFuzzer::Fuzz();
1243 THREADED_TEST(GlobalPrototype) {
1244 v8::HandleScope scope;
1245 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1246 func_templ->PrototypeTemplate()->Set(
1248 v8::FunctionTemplate::New(DummyCallHandler));
1249 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1250 templ->Set("x", v8_num(200));
1251 templ->SetAccessor(v8_str("m"), GetM);
1252 LocalContext env(0, templ);
1253 v8::Handle<Script> script(v8_compile("dummy()"));
1254 v8::Handle<Value> result(script->Run());
1255 CHECK_EQ(13.4, result->NumberValue());
1256 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1257 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1261 THREADED_TEST(ObjectTemplate) {
1262 v8::HandleScope scope;
1263 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1264 templ1->Set("x", v8_num(10));
1265 templ1->Set("y", v8_num(13));
1267 Local<v8::Object> instance1 = templ1->NewInstance();
1268 env->Global()->Set(v8_str("p"), instance1);
1269 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1270 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1271 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1272 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1273 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1274 templ2->Set("a", v8_num(12));
1275 templ2->Set("b", templ1);
1276 Local<v8::Object> instance2 = templ2->NewInstance();
1277 env->Global()->Set(v8_str("q"), instance2);
1278 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1279 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1280 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1281 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1285 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1286 ApiTestFuzzer::Fuzz();
1287 return v8_num(17.2);
1291 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1292 ApiTestFuzzer::Fuzz();
1293 return v8_num(15.2);
1297 THREADED_TEST(DescriptorInheritance) {
1298 v8::HandleScope scope;
1299 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1300 super->PrototypeTemplate()->Set("flabby",
1301 v8::FunctionTemplate::New(GetFlabby));
1302 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1304 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1306 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1307 base1->Inherit(super);
1308 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1310 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1311 base2->Inherit(super);
1312 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1316 env->Global()->Set(v8_str("s"), super->GetFunction());
1317 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1318 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1320 // Checks right __proto__ chain.
1321 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1322 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1324 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1326 // Instance accessor should not be visible on function object or its prototype
1327 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1328 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1329 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1331 env->Global()->Set(v8_str("obj"),
1332 base1->GetFunction()->NewInstance());
1333 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1334 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1335 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1336 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1337 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1339 env->Global()->Set(v8_str("obj2"),
1340 base2->GetFunction()->NewInstance());
1341 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1342 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1343 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1344 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1345 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1347 // base1 and base2 cannot cross reference to each's prototype
1348 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1349 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1353 int echo_named_call_count;
1356 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1357 const AccessorInfo& info) {
1358 ApiTestFuzzer::Fuzz();
1359 CHECK_EQ(v8_str("data"), info.Data());
1360 echo_named_call_count++;
1364 // Helper functions for Interceptor/Accessor interaction tests
1366 Handle<Value> SimpleAccessorGetter(Local<String> name,
1367 const AccessorInfo& info) {
1368 Handle<Object> self = info.This();
1369 return self->Get(String::Concat(v8_str("accessor_"), name));
1372 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1373 const AccessorInfo& info) {
1374 Handle<Object> self = info.This();
1375 self->Set(String::Concat(v8_str("accessor_"), name), value);
1378 Handle<Value> EmptyInterceptorGetter(Local<String> name,
1379 const AccessorInfo& info) {
1380 return Handle<Value>();
1383 Handle<Value> EmptyInterceptorSetter(Local<String> name,
1385 const AccessorInfo& info) {
1386 return Handle<Value>();
1389 Handle<Value> InterceptorGetter(Local<String> name,
1390 const AccessorInfo& info) {
1391 // Intercept names that start with 'interceptor_'.
1392 String::AsciiValue ascii(name);
1393 char* name_str = *ascii;
1394 char prefix[] = "interceptor_";
1396 for (i = 0; name_str[i] && prefix[i]; ++i) {
1397 if (name_str[i] != prefix[i]) return Handle<Value>();
1399 Handle<Object> self = info.This();
1400 return self->GetHiddenValue(v8_str(name_str + i));
1403 Handle<Value> InterceptorSetter(Local<String> name,
1405 const AccessorInfo& info) {
1406 // Intercept accesses that set certain integer values.
1407 if (value->IsInt32() && value->Int32Value() < 10000) {
1408 Handle<Object> self = info.This();
1409 self->SetHiddenValue(name, value);
1412 return Handle<Value>();
1415 void AddAccessor(Handle<FunctionTemplate> templ,
1416 Handle<String> name,
1417 v8::AccessorGetter getter,
1418 v8::AccessorSetter setter) {
1419 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1422 void AddInterceptor(Handle<FunctionTemplate> templ,
1423 v8::NamedPropertyGetter getter,
1424 v8::NamedPropertySetter setter) {
1425 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1428 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1429 v8::HandleScope scope;
1430 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1431 Handle<FunctionTemplate> child = FunctionTemplate::New();
1432 child->Inherit(parent);
1433 AddAccessor(parent, v8_str("age"),
1434 SimpleAccessorGetter, SimpleAccessorSetter);
1435 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1437 env->Global()->Set(v8_str("Child"), child->GetFunction());
1438 CompileRun("var child = new Child;"
1440 ExpectBoolean("child.hasOwnProperty('age')", false);
1441 ExpectInt32("child.age", 10);
1442 ExpectInt32("child.accessor_age", 10);
1445 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1446 v8::HandleScope scope;
1447 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1448 Handle<FunctionTemplate> child = FunctionTemplate::New();
1449 child->Inherit(parent);
1450 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1452 env->Global()->Set(v8_str("Child"), child->GetFunction());
1453 CompileRun("var child = new Child;"
1454 "var parent = child.__proto__;"
1455 "Object.defineProperty(parent, 'age', "
1456 " {get: function(){ return this.accessor_age; }, "
1457 " set: function(v){ this.accessor_age = v; }, "
1458 " enumerable: true, configurable: true});"
1460 ExpectBoolean("child.hasOwnProperty('age')", false);
1461 ExpectInt32("child.age", 10);
1462 ExpectInt32("child.accessor_age", 10);
1465 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1466 v8::HandleScope scope;
1467 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1468 Handle<FunctionTemplate> child = FunctionTemplate::New();
1469 child->Inherit(parent);
1470 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1472 env->Global()->Set(v8_str("Child"), child->GetFunction());
1473 CompileRun("var child = new Child;"
1474 "var parent = child.__proto__;"
1475 "parent.name = 'Alice';");
1476 ExpectBoolean("child.hasOwnProperty('name')", false);
1477 ExpectString("child.name", "Alice");
1478 CompileRun("child.name = 'Bob';");
1479 ExpectString("child.name", "Bob");
1480 ExpectBoolean("child.hasOwnProperty('name')", true);
1481 ExpectString("parent.name", "Alice");
1484 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1485 v8::HandleScope scope;
1486 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1487 AddAccessor(templ, v8_str("age"),
1488 SimpleAccessorGetter, SimpleAccessorSetter);
1489 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1491 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1492 CompileRun("var obj = new Obj;"
1493 "function setAge(i){ obj.age = i; };"
1494 "for(var i = 0; i <= 10000; i++) setAge(i);");
1495 // All i < 10000 go to the interceptor.
1496 ExpectInt32("obj.interceptor_age", 9999);
1497 // The last i goes to the accessor.
1498 ExpectInt32("obj.accessor_age", 10000);
1501 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1502 v8::HandleScope scope;
1503 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1504 AddAccessor(templ, v8_str("age"),
1505 SimpleAccessorGetter, SimpleAccessorSetter);
1506 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1508 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1509 CompileRun("var obj = new Obj;"
1510 "function setAge(i){ obj.age = i; };"
1511 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1512 // All i >= 10000 go to the accessor.
1513 ExpectInt32("obj.accessor_age", 10000);
1514 // The last i goes to the interceptor.
1515 ExpectInt32("obj.interceptor_age", 9999);
1518 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1519 v8::HandleScope scope;
1520 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1521 Handle<FunctionTemplate> child = FunctionTemplate::New();
1522 child->Inherit(parent);
1523 AddAccessor(parent, v8_str("age"),
1524 SimpleAccessorGetter, SimpleAccessorSetter);
1525 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1527 env->Global()->Set(v8_str("Child"), child->GetFunction());
1528 CompileRun("var child = new Child;"
1529 "function setAge(i){ child.age = i; };"
1530 "for(var i = 0; i <= 10000; i++) setAge(i);");
1531 // All i < 10000 go to the interceptor.
1532 ExpectInt32("child.interceptor_age", 9999);
1533 // The last i goes to the accessor.
1534 ExpectInt32("child.accessor_age", 10000);
1537 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1538 v8::HandleScope scope;
1539 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1540 Handle<FunctionTemplate> child = FunctionTemplate::New();
1541 child->Inherit(parent);
1542 AddAccessor(parent, v8_str("age"),
1543 SimpleAccessorGetter, SimpleAccessorSetter);
1544 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1546 env->Global()->Set(v8_str("Child"), child->GetFunction());
1547 CompileRun("var child = new Child;"
1548 "function setAge(i){ child.age = i; };"
1549 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1550 // All i >= 10000 go to the accessor.
1551 ExpectInt32("child.accessor_age", 10000);
1552 // The last i goes to the interceptor.
1553 ExpectInt32("child.interceptor_age", 9999);
1556 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1557 v8::HandleScope scope;
1558 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1559 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1561 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1562 CompileRun("var obj = new Obj;"
1563 "function setter(i) { this.accessor_age = i; };"
1564 "function getter() { return this.accessor_age; };"
1565 "function setAge(i) { obj.age = i; };"
1566 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1567 "for(var i = 0; i <= 10000; i++) setAge(i);");
1568 // All i < 10000 go to the interceptor.
1569 ExpectInt32("obj.interceptor_age", 9999);
1570 // The last i goes to the JavaScript accessor.
1571 ExpectInt32("obj.accessor_age", 10000);
1572 // The installed JavaScript getter is still intact.
1573 // This last part is a regression test for issue 1651 and relies on the fact
1574 // that both interceptor and accessor are being installed on the same object.
1575 ExpectInt32("obj.age", 10000);
1576 ExpectBoolean("obj.hasOwnProperty('age')", true);
1577 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1580 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1581 v8::HandleScope scope;
1582 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1583 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1585 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1586 CompileRun("var obj = new Obj;"
1587 "function setter(i) { this.accessor_age = i; };"
1588 "function getter() { return this.accessor_age; };"
1589 "function setAge(i) { obj.age = i; };"
1590 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1591 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1592 // All i >= 10000 go to the accessor.
1593 ExpectInt32("obj.accessor_age", 10000);
1594 // The last i goes to the interceptor.
1595 ExpectInt32("obj.interceptor_age", 9999);
1596 // The installed JavaScript getter is still intact.
1597 // This last part is a regression test for issue 1651 and relies on the fact
1598 // that both interceptor and accessor are being installed on the same object.
1599 ExpectInt32("obj.age", 10000);
1600 ExpectBoolean("obj.hasOwnProperty('age')", true);
1601 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1604 THREADED_TEST(SwitchFromInterceptorToProperty) {
1605 v8::HandleScope scope;
1606 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1607 Handle<FunctionTemplate> child = FunctionTemplate::New();
1608 child->Inherit(parent);
1609 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1611 env->Global()->Set(v8_str("Child"), child->GetFunction());
1612 CompileRun("var child = new Child;"
1613 "function setAge(i){ child.age = i; };"
1614 "for(var i = 0; i <= 10000; i++) setAge(i);");
1615 // All i < 10000 go to the interceptor.
1616 ExpectInt32("child.interceptor_age", 9999);
1617 // The last i goes to child's own property.
1618 ExpectInt32("child.age", 10000);
1621 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1622 v8::HandleScope scope;
1623 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1624 Handle<FunctionTemplate> child = FunctionTemplate::New();
1625 child->Inherit(parent);
1626 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1628 env->Global()->Set(v8_str("Child"), child->GetFunction());
1629 CompileRun("var child = new Child;"
1630 "function setAge(i){ child.age = i; };"
1631 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1632 // All i >= 10000 go to child's own property.
1633 ExpectInt32("child.age", 10000);
1634 // The last i goes to the interceptor.
1635 ExpectInt32("child.interceptor_age", 9999);
1638 THREADED_TEST(NamedPropertyHandlerGetter) {
1639 echo_named_call_count = 0;
1640 v8::HandleScope scope;
1641 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1642 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1646 env->Global()->Set(v8_str("obj"),
1647 templ->GetFunction()->NewInstance());
1648 CHECK_EQ(echo_named_call_count, 0);
1649 v8_compile("obj.x")->Run();
1650 CHECK_EQ(echo_named_call_count, 1);
1651 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1652 v8::Handle<Value> str = CompileRun(code);
1653 String::AsciiValue value(str);
1654 CHECK_EQ(*value, "oddlepoddle");
1655 // Check default behavior
1656 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1657 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1658 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1662 int echo_indexed_call_count = 0;
1665 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1666 const AccessorInfo& info) {
1667 ApiTestFuzzer::Fuzz();
1668 CHECK_EQ(v8_num(637), info.Data());
1669 echo_indexed_call_count++;
1670 return v8_num(index);
1674 THREADED_TEST(IndexedPropertyHandlerGetter) {
1675 v8::HandleScope scope;
1676 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1677 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1681 env->Global()->Set(v8_str("obj"),
1682 templ->GetFunction()->NewInstance());
1683 Local<Script> script = v8_compile("obj[900]");
1684 CHECK_EQ(script->Run()->Int32Value(), 900);
1688 v8::Handle<v8::Object> bottom;
1690 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1692 const AccessorInfo& info) {
1693 ApiTestFuzzer::Fuzz();
1694 CHECK(info.This()->Equals(bottom));
1695 return v8::Handle<Value>();
1698 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1700 const AccessorInfo& info) {
1701 ApiTestFuzzer::Fuzz();
1702 CHECK(info.This()->Equals(bottom));
1703 return v8::Handle<Value>();
1707 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1709 const AccessorInfo& info) {
1710 ApiTestFuzzer::Fuzz();
1711 CHECK(info.This()->Equals(bottom));
1712 return v8::Handle<Value>();
1716 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1718 const AccessorInfo& info) {
1719 ApiTestFuzzer::Fuzz();
1720 CHECK(info.This()->Equals(bottom));
1721 return v8::Handle<Value>();
1724 v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1726 const AccessorInfo& info) {
1727 ApiTestFuzzer::Fuzz();
1728 CHECK(info.This()->Equals(bottom));
1729 return v8::Handle<v8::Integer>();
1733 v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1734 const AccessorInfo& info) {
1735 ApiTestFuzzer::Fuzz();
1736 CHECK(info.This()->Equals(bottom));
1737 return v8::Handle<v8::Integer>();
1741 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1743 const AccessorInfo& info) {
1744 ApiTestFuzzer::Fuzz();
1745 CHECK(info.This()->Equals(bottom));
1746 return v8::Handle<v8::Boolean>();
1750 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1751 Local<String> property,
1752 const AccessorInfo& info) {
1753 ApiTestFuzzer::Fuzz();
1754 CHECK(info.This()->Equals(bottom));
1755 return v8::Handle<v8::Boolean>();
1759 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1760 const AccessorInfo& info) {
1761 ApiTestFuzzer::Fuzz();
1762 CHECK(info.This()->Equals(bottom));
1763 return v8::Handle<v8::Array>();
1767 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1768 const AccessorInfo& info) {
1769 ApiTestFuzzer::Fuzz();
1770 CHECK(info.This()->Equals(bottom));
1771 return v8::Handle<v8::Array>();
1775 THREADED_TEST(PropertyHandlerInPrototype) {
1776 v8::HandleScope scope;
1779 // Set up a prototype chain with three interceptors.
1780 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1781 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1782 CheckThisIndexedPropertyHandler,
1783 CheckThisIndexedPropertySetter,
1784 CheckThisIndexedPropertyQuery,
1785 CheckThisIndexedPropertyDeleter,
1786 CheckThisIndexedPropertyEnumerator);
1788 templ->InstanceTemplate()->SetNamedPropertyHandler(
1789 CheckThisNamedPropertyHandler,
1790 CheckThisNamedPropertySetter,
1791 CheckThisNamedPropertyQuery,
1792 CheckThisNamedPropertyDeleter,
1793 CheckThisNamedPropertyEnumerator);
1795 bottom = templ->GetFunction()->NewInstance();
1796 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1797 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1799 bottom->Set(v8_str("__proto__"), middle);
1800 middle->Set(v8_str("__proto__"), top);
1801 env->Global()->Set(v8_str("obj"), bottom);
1803 // Indexed and named get.
1804 Script::Compile(v8_str("obj[0]"))->Run();
1805 Script::Compile(v8_str("obj.x"))->Run();
1807 // Indexed and named set.
1808 Script::Compile(v8_str("obj[1] = 42"))->Run();
1809 Script::Compile(v8_str("obj.y = 42"))->Run();
1811 // Indexed and named query.
1812 Script::Compile(v8_str("0 in obj"))->Run();
1813 Script::Compile(v8_str("'x' in obj"))->Run();
1815 // Indexed and named deleter.
1816 Script::Compile(v8_str("delete obj[0]"))->Run();
1817 Script::Compile(v8_str("delete obj.x"))->Run();
1820 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1824 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1825 const AccessorInfo& info) {
1826 ApiTestFuzzer::Fuzz();
1827 if (v8_str("pre")->Equals(key)) {
1828 return v8_str("PrePropertyHandler: pre");
1830 return v8::Handle<String>();
1834 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1835 const AccessorInfo&) {
1836 if (v8_str("pre")->Equals(key)) {
1837 return v8::Integer::New(v8::None);
1840 return v8::Handle<v8::Integer>(); // do not intercept the call
1844 THREADED_TEST(PrePropertyHandler) {
1845 v8::HandleScope scope;
1846 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1847 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1849 PrePropertyHandlerQuery);
1850 LocalContext env(NULL, desc->InstanceTemplate());
1851 Script::Compile(v8_str(
1852 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1853 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1854 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1855 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1856 CHECK_EQ(v8_str("Object: on"), result_on);
1857 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1858 CHECK(result_post.IsEmpty());
1862 THREADED_TEST(UndefinedIsNotEnumerable) {
1863 v8::HandleScope scope;
1865 v8::Handle<Value> result = Script::Compile(v8_str(
1866 "this.propertyIsEnumerable(undefined)"))->Run();
1867 CHECK(result->IsFalse());
1871 v8::Handle<Script> call_recursively_script;
1872 static const int kTargetRecursionDepth = 200; // near maximum
1875 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1876 ApiTestFuzzer::Fuzz();
1877 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1878 if (depth == kTargetRecursionDepth) return v8::Undefined();
1879 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1880 return call_recursively_script->Run();
1884 static v8::Handle<Value> CallFunctionRecursivelyCall(
1885 const v8::Arguments& args) {
1886 ApiTestFuzzer::Fuzz();
1887 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1888 if (depth == kTargetRecursionDepth) {
1889 printf("[depth = %d]\n", depth);
1890 return v8::Undefined();
1892 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1893 v8::Handle<Value> function =
1894 args.This()->Get(v8_str("callFunctionRecursively"));
1895 return function.As<Function>()->Call(args.This(), 0, NULL);
1899 THREADED_TEST(DeepCrossLanguageRecursion) {
1900 v8::HandleScope scope;
1901 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1902 global->Set(v8_str("callScriptRecursively"),
1903 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1904 global->Set(v8_str("callFunctionRecursively"),
1905 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1906 LocalContext env(NULL, global);
1908 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1909 call_recursively_script = v8_compile("callScriptRecursively()");
1910 call_recursively_script->Run();
1911 call_recursively_script = v8::Handle<Script>();
1913 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1914 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1918 static v8::Handle<Value>
1919 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1920 ApiTestFuzzer::Fuzz();
1921 return v8::ThrowException(key);
1925 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1927 const AccessorInfo&) {
1928 v8::ThrowException(key);
1929 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1933 THREADED_TEST(CallbackExceptionRegression) {
1934 v8::HandleScope scope;
1935 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1936 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1937 ThrowingPropertyHandlerSet);
1939 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1940 v8::Handle<Value> otto = Script::Compile(v8_str(
1941 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1942 CHECK_EQ(v8_str("otto"), otto);
1943 v8::Handle<Value> netto = Script::Compile(v8_str(
1944 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1945 CHECK_EQ(v8_str("netto"), netto);
1949 THREADED_TEST(FunctionPrototype) {
1950 v8::HandleScope scope;
1951 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1952 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1954 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1955 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1956 CHECK_EQ(script->Run()->Int32Value(), 321);
1960 THREADED_TEST(InternalFields) {
1961 v8::HandleScope scope;
1964 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1965 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1966 instance_templ->SetInternalFieldCount(1);
1967 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1968 CHECK_EQ(1, obj->InternalFieldCount());
1969 CHECK(obj->GetInternalField(0)->IsUndefined());
1970 obj->SetInternalField(0, v8_num(17));
1971 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1975 THREADED_TEST(GlobalObjectInternalFields) {
1976 v8::HandleScope scope;
1977 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1978 global_template->SetInternalFieldCount(1);
1979 LocalContext env(NULL, global_template);
1980 v8::Handle<v8::Object> global_proxy = env->Global();
1981 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1982 CHECK_EQ(1, global->InternalFieldCount());
1983 CHECK(global->GetInternalField(0)->IsUndefined());
1984 global->SetInternalField(0, v8_num(17));
1985 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1989 THREADED_TEST(InternalFieldsNativePointers) {
1990 v8::HandleScope scope;
1993 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1994 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1995 instance_templ->SetInternalFieldCount(1);
1996 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1997 CHECK_EQ(1, obj->InternalFieldCount());
1998 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2000 char* data = new char[100];
2002 void* aligned = data;
2003 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
2004 void* unaligned = data + 1;
2005 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
2007 // Check reading and writing aligned pointers.
2008 obj->SetPointerInInternalField(0, aligned);
2009 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2010 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2012 // Check reading and writing unaligned pointers.
2013 obj->SetPointerInInternalField(0, unaligned);
2014 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2015 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2021 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2022 v8::HandleScope scope;
2025 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2026 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2027 instance_templ->SetInternalFieldCount(1);
2028 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2029 CHECK_EQ(1, obj->InternalFieldCount());
2030 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2032 char* data = new char[100];
2034 void* aligned = data;
2035 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
2036 void* unaligned = data + 1;
2037 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
2039 obj->SetPointerInInternalField(0, aligned);
2040 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2041 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2043 obj->SetPointerInInternalField(0, unaligned);
2044 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2045 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2047 obj->SetInternalField(0, v8::External::Wrap(aligned));
2048 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2049 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2051 obj->SetInternalField(0, v8::External::Wrap(unaligned));
2052 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2053 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2059 THREADED_TEST(IdentityHash) {
2060 v8::HandleScope scope;
2063 // Ensure that the test starts with an fresh heap to test whether the hash
2064 // code is based on the address.
2065 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2066 Local<v8::Object> obj = v8::Object::New();
2067 int hash = obj->GetIdentityHash();
2068 int hash1 = obj->GetIdentityHash();
2069 CHECK_EQ(hash, hash1);
2070 int hash2 = v8::Object::New()->GetIdentityHash();
2071 // Since the identity hash is essentially a random number two consecutive
2072 // objects should not be assigned the same hash code. If the test below fails
2073 // the random number generator should be evaluated.
2074 CHECK_NE(hash, hash2);
2075 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2076 int hash3 = v8::Object::New()->GetIdentityHash();
2077 // Make sure that the identity hash is not based on the initial address of
2078 // the object alone. If the test below fails the random number generator
2079 // should be evaluated.
2080 CHECK_NE(hash, hash3);
2081 int hash4 = obj->GetIdentityHash();
2082 CHECK_EQ(hash, hash4);
2084 // Check identity hashes behaviour in the presence of JS accessors.
2085 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2087 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2088 Local<v8::Object> o1 = v8::Object::New();
2089 Local<v8::Object> o2 = v8::Object::New();
2090 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2094 "function cnst() { return 42; };\n"
2095 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2096 Local<v8::Object> o1 = v8::Object::New();
2097 Local<v8::Object> o2 = v8::Object::New();
2098 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2103 THREADED_TEST(HiddenProperties) {
2104 v8::HandleScope scope;
2107 v8::Local<v8::Object> obj = v8::Object::New();
2108 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2109 v8::Local<v8::String> empty = v8_str("");
2110 v8::Local<v8::String> prop_name = v8_str("prop_name");
2112 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2114 // Make sure delete of a non-existent hidden value works
2115 CHECK(obj->DeleteHiddenValue(key));
2117 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2118 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2119 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2120 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2122 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2124 // Make sure we do not find the hidden property.
2125 CHECK(!obj->Has(empty));
2126 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2127 CHECK(obj->Get(empty)->IsUndefined());
2128 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2129 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2130 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2131 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2133 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2135 // Add another property and delete it afterwards to force the object in
2137 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2138 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2139 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2140 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2141 CHECK(obj->Delete(prop_name));
2142 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2144 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2146 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2147 CHECK(obj->GetHiddenValue(key).IsEmpty());
2149 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2150 CHECK(obj->DeleteHiddenValue(key));
2151 CHECK(obj->GetHiddenValue(key).IsEmpty());
2155 THREADED_TEST(Regress97784) {
2156 // Regression test for crbug.com/97784
2157 // Messing with the Object.prototype should not have effect on
2158 // hidden properties.
2159 v8::HandleScope scope;
2162 v8::Local<v8::Object> obj = v8::Object::New();
2163 v8::Local<v8::String> key = v8_str("hidden");
2166 "set_called = false;"
2167 "Object.defineProperty("
2168 " Object.prototype,"
2170 " {get: function() { return 45; },"
2171 " set: function() { set_called = true; }})");
2173 CHECK(obj->GetHiddenValue(key).IsEmpty());
2174 // Make sure that the getter and setter from Object.prototype is not invoked.
2175 // If it did we would have full access to the hidden properties in
2177 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2178 ExpectFalse("set_called");
2179 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2183 static bool interceptor_for_hidden_properties_called;
2184 static v8::Handle<Value> InterceptorForHiddenProperties(
2185 Local<String> name, const AccessorInfo& info) {
2186 interceptor_for_hidden_properties_called = true;
2187 return v8::Handle<Value>();
2191 THREADED_TEST(HiddenPropertiesWithInterceptors) {
2192 v8::HandleScope scope;
2193 LocalContext context;
2195 interceptor_for_hidden_properties_called = false;
2197 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2199 // Associate an interceptor with an object and start setting hidden values.
2200 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2201 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2202 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2203 Local<v8::Function> function = fun_templ->GetFunction();
2204 Local<v8::Object> obj = function->NewInstance();
2205 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2206 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2207 CHECK(!interceptor_for_hidden_properties_called);
2211 THREADED_TEST(External) {
2212 v8::HandleScope scope;
2214 Local<v8::External> ext = v8::External::New(&x);
2216 env->Global()->Set(v8_str("ext"), ext);
2217 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2218 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2219 int* ptr = static_cast<int*>(reext->Value());
2224 // Make sure unaligned pointers are wrapped properly.
2225 char* data = i::StrDup("0123456789");
2226 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2227 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2228 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2229 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2231 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2232 CHECK_EQ('0', *char_ptr);
2233 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2234 CHECK_EQ('1', *char_ptr);
2235 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2236 CHECK_EQ('2', *char_ptr);
2237 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2238 CHECK_EQ('3', *char_ptr);
2239 i::DeleteArray(data);
2243 THREADED_TEST(GlobalHandle) {
2244 v8::Persistent<String> global;
2246 v8::HandleScope scope;
2247 Local<String> str = v8_str("str");
2248 global = v8::Persistent<String>::New(str);
2250 CHECK_EQ(global->Length(), 3);
2255 class WeakCallCounter {
2257 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2258 int id() { return id_; }
2259 void increment() { number_of_weak_calls_++; }
2260 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2263 int number_of_weak_calls_;
2267 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2268 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2269 CHECK_EQ(1234, counter->id());
2270 counter->increment();
2275 THREADED_TEST(ApiObjectGroups) {
2279 Persistent<Object> g1s1;
2280 Persistent<Object> g1s2;
2281 Persistent<Object> g1c1;
2282 Persistent<Object> g2s1;
2283 Persistent<Object> g2s2;
2284 Persistent<Object> g2c1;
2286 WeakCallCounter counter(1234);
2290 g1s1 = Persistent<Object>::New(Object::New());
2291 g1s2 = Persistent<Object>::New(Object::New());
2292 g1c1 = Persistent<Object>::New(Object::New());
2293 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2294 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2295 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2297 g2s1 = Persistent<Object>::New(Object::New());
2298 g2s2 = Persistent<Object>::New(Object::New());
2299 g2c1 = Persistent<Object>::New(Object::New());
2300 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2301 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2302 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2305 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2307 // Connect group 1 and 2, make a cycle.
2308 CHECK(g1s2->Set(0, g2s2));
2309 CHECK(g2s1->Set(0, g1s1));
2312 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2313 Persistent<Value> g1_children[] = { g1c1 };
2314 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2315 Persistent<Value> g2_children[] = { g2c1 };
2316 V8::AddObjectGroup(g1_objects, 2);
2317 V8::AddImplicitReferences(g1s1, g1_children, 1);
2318 V8::AddObjectGroup(g2_objects, 2);
2319 V8::AddImplicitReferences(g2s2, g2_children, 1);
2321 // Do a single full GC, ensure incremental marking is stopped.
2322 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2324 // All object should be alive.
2325 CHECK_EQ(0, counter.NumberOfWeakCalls());
2328 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2329 // But make children strong roots---all the objects (except for children)
2330 // should be collectable now.
2334 // Groups are deleted, rebuild groups.
2336 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2337 Persistent<Value> g1_children[] = { g1c1 };
2338 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2339 Persistent<Value> g2_children[] = { g2c1 };
2340 V8::AddObjectGroup(g1_objects, 2);
2341 V8::AddImplicitReferences(g1s1, g1_children, 1);
2342 V8::AddObjectGroup(g2_objects, 2);
2343 V8::AddImplicitReferences(g2s2, g2_children, 1);
2346 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2348 // All objects should be gone. 5 global handles in total.
2349 CHECK_EQ(5, counter.NumberOfWeakCalls());
2351 // And now make children weak again and collect them.
2352 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2353 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2355 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2356 CHECK_EQ(7, counter.NumberOfWeakCalls());
2360 THREADED_TEST(ApiObjectGroupsCycle) {
2364 WeakCallCounter counter(1234);
2366 Persistent<Object> g1s1;
2367 Persistent<Object> g1s2;
2368 Persistent<Object> g2s1;
2369 Persistent<Object> g2s2;
2370 Persistent<Object> g3s1;
2371 Persistent<Object> g3s2;
2375 g1s1 = Persistent<Object>::New(Object::New());
2376 g1s2 = Persistent<Object>::New(Object::New());
2377 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2378 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2380 g2s1 = Persistent<Object>::New(Object::New());
2381 g2s2 = Persistent<Object>::New(Object::New());
2382 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2383 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2385 g3s1 = Persistent<Object>::New(Object::New());
2386 g3s2 = Persistent<Object>::New(Object::New());
2387 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2388 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2391 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2393 // Connect groups. We're building the following cycle:
2394 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2397 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2398 Persistent<Value> g1_children[] = { g2s1 };
2399 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2400 Persistent<Value> g2_children[] = { g3s1 };
2401 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2402 Persistent<Value> g3_children[] = { g1s1 };
2403 V8::AddObjectGroup(g1_objects, 2);
2404 V8::AddImplicitReferences(g1s1, g1_children, 1);
2405 V8::AddObjectGroup(g2_objects, 2);
2406 V8::AddImplicitReferences(g2s1, g2_children, 1);
2407 V8::AddObjectGroup(g3_objects, 2);
2408 V8::AddImplicitReferences(g3s1, g3_children, 1);
2410 // Do a single full GC
2411 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2413 // All object should be alive.
2414 CHECK_EQ(0, counter.NumberOfWeakCalls());
2417 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2419 // Groups are deleted, rebuild groups.
2421 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2422 Persistent<Value> g1_children[] = { g2s1 };
2423 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2424 Persistent<Value> g2_children[] = { g3s1 };
2425 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2426 Persistent<Value> g3_children[] = { g1s1 };
2427 V8::AddObjectGroup(g1_objects, 2);
2428 V8::AddImplicitReferences(g1s1, g1_children, 1);
2429 V8::AddObjectGroup(g2_objects, 2);
2430 V8::AddImplicitReferences(g2s1, g2_children, 1);
2431 V8::AddObjectGroup(g3_objects, 2);
2432 V8::AddImplicitReferences(g3s1, g3_children, 1);
2435 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
2437 // All objects should be gone. 7 global handles in total.
2438 CHECK_EQ(7, counter.NumberOfWeakCalls());
2442 THREADED_TEST(ScriptException) {
2443 v8::HandleScope scope;
2445 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2446 v8::TryCatch try_catch;
2447 Local<Value> result = script->Run();
2448 CHECK(result.IsEmpty());
2449 CHECK(try_catch.HasCaught());
2450 String::AsciiValue exception_value(try_catch.Exception());
2451 CHECK_EQ(*exception_value, "panama!");
2455 bool message_received;
2458 static void check_message_0(v8::Handle<v8::Message> message,
2459 v8::Handle<Value> data) {
2460 CHECK_EQ(5.76, data->NumberValue());
2461 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2462 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2463 message_received = true;
2467 THREADED_TEST(MessageHandler0) {
2468 message_received = false;
2469 v8::HandleScope scope;
2470 CHECK(!message_received);
2471 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
2472 LocalContext context;
2473 v8::ScriptOrigin origin =
2474 v8::ScriptOrigin(v8_str("6.75"));
2475 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2477 script->SetData(v8_str("7.56"));
2479 CHECK(message_received);
2480 // clear out the message listener
2481 v8::V8::RemoveMessageListeners(check_message_0);
2485 static void check_message_1(v8::Handle<v8::Message> message,
2486 v8::Handle<Value> data) {
2487 CHECK(data->IsNumber());
2488 CHECK_EQ(1337, data->Int32Value());
2489 message_received = true;
2493 TEST(MessageHandler1) {
2494 message_received = false;
2495 v8::HandleScope scope;
2496 CHECK(!message_received);
2497 v8::V8::AddMessageListener(check_message_1);
2498 LocalContext context;
2499 CompileRun("throw 1337;");
2500 CHECK(message_received);
2501 // clear out the message listener
2502 v8::V8::RemoveMessageListeners(check_message_1);
2506 static void check_message_2(v8::Handle<v8::Message> message,
2507 v8::Handle<Value> data) {
2508 LocalContext context;
2509 CHECK(data->IsObject());
2510 v8::Local<v8::Value> hidden_property =
2511 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2512 CHECK(v8_str("hidden value")->Equals(hidden_property));
2513 message_received = true;
2517 TEST(MessageHandler2) {
2518 message_received = false;
2519 v8::HandleScope scope;
2520 CHECK(!message_received);
2521 v8::V8::AddMessageListener(check_message_2);
2522 LocalContext context;
2523 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2524 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2525 v8_str("hidden value"));
2526 context->Global()->Set(v8_str("error"), error);
2527 CompileRun("throw error;");
2528 CHECK(message_received);
2529 // clear out the message listener
2530 v8::V8::RemoveMessageListeners(check_message_2);
2534 THREADED_TEST(GetSetProperty) {
2535 v8::HandleScope scope;
2536 LocalContext context;
2537 context->Global()->Set(v8_str("foo"), v8_num(14));
2538 context->Global()->Set(v8_str("12"), v8_num(92));
2539 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2540 context->Global()->Set(v8_num(13), v8_num(56));
2541 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2542 CHECK_EQ(14, foo->Int32Value());
2543 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2544 CHECK_EQ(92, twelve->Int32Value());
2545 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2546 CHECK_EQ(32, sixteen->Int32Value());
2547 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2548 CHECK_EQ(56, thirteen->Int32Value());
2549 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2550 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2551 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2552 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2553 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2554 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2555 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2556 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2557 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2561 THREADED_TEST(PropertyAttributes) {
2562 v8::HandleScope scope;
2563 LocalContext context;
2565 Local<String> prop = v8_str("none");
2566 context->Global()->Set(prop, v8_num(7));
2567 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2569 prop = v8_str("read_only");
2570 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2571 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2572 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2573 Script::Compile(v8_str("read_only = 9"))->Run();
2574 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2575 context->Global()->Set(prop, v8_num(10));
2576 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2578 prop = v8_str("dont_delete");
2579 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2580 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2581 Script::Compile(v8_str("delete dont_delete"))->Run();
2582 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2583 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2585 prop = v8_str("dont_enum");
2586 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2587 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2589 prop = v8_str("absent");
2590 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2591 Local<Value> fake_prop = v8_num(1);
2592 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2595 Local<Value> exception =
2596 CompileRun("({ toString: function() { throw 'exception';} })");
2597 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2598 CHECK(try_catch.HasCaught());
2599 String::AsciiValue exception_value(try_catch.Exception());
2600 CHECK_EQ("exception", *exception_value);
2605 THREADED_TEST(Array) {
2606 v8::HandleScope scope;
2607 LocalContext context;
2608 Local<v8::Array> array = v8::Array::New();
2609 CHECK_EQ(0, array->Length());
2610 CHECK(array->Get(0)->IsUndefined());
2611 CHECK(!array->Has(0));
2612 CHECK(array->Get(100)->IsUndefined());
2613 CHECK(!array->Has(100));
2614 array->Set(2, v8_num(7));
2615 CHECK_EQ(3, array->Length());
2616 CHECK(!array->Has(0));
2617 CHECK(!array->Has(1));
2618 CHECK(array->Has(2));
2619 CHECK_EQ(7, array->Get(2)->Int32Value());
2620 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2621 Local<v8::Array> arr = obj.As<v8::Array>();
2622 CHECK_EQ(3, arr->Length());
2623 CHECK_EQ(1, arr->Get(0)->Int32Value());
2624 CHECK_EQ(2, arr->Get(1)->Int32Value());
2625 CHECK_EQ(3, arr->Get(2)->Int32Value());
2626 array = v8::Array::New(27);
2627 CHECK_EQ(27, array->Length());
2628 array = v8::Array::New(-27);
2629 CHECK_EQ(0, array->Length());
2633 v8::Handle<Value> HandleF(const v8::Arguments& args) {
2634 v8::HandleScope scope;
2635 ApiTestFuzzer::Fuzz();
2636 Local<v8::Array> result = v8::Array::New(args.Length());
2637 for (int i = 0; i < args.Length(); i++)
2638 result->Set(i, args[i]);
2639 return scope.Close(result);
2643 THREADED_TEST(Vector) {
2644 v8::HandleScope scope;
2645 Local<ObjectTemplate> global = ObjectTemplate::New();
2646 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2647 LocalContext context(0, global);
2649 const char* fun = "f()";
2650 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2651 CHECK_EQ(0, a0->Length());
2653 const char* fun2 = "f(11)";
2654 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2655 CHECK_EQ(1, a1->Length());
2656 CHECK_EQ(11, a1->Get(0)->Int32Value());
2658 const char* fun3 = "f(12, 13)";
2659 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2660 CHECK_EQ(2, a2->Length());
2661 CHECK_EQ(12, a2->Get(0)->Int32Value());
2662 CHECK_EQ(13, a2->Get(1)->Int32Value());
2664 const char* fun4 = "f(14, 15, 16)";
2665 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2666 CHECK_EQ(3, a3->Length());
2667 CHECK_EQ(14, a3->Get(0)->Int32Value());
2668 CHECK_EQ(15, a3->Get(1)->Int32Value());
2669 CHECK_EQ(16, a3->Get(2)->Int32Value());
2671 const char* fun5 = "f(17, 18, 19, 20)";
2672 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2673 CHECK_EQ(4, a4->Length());
2674 CHECK_EQ(17, a4->Get(0)->Int32Value());
2675 CHECK_EQ(18, a4->Get(1)->Int32Value());
2676 CHECK_EQ(19, a4->Get(2)->Int32Value());
2677 CHECK_EQ(20, a4->Get(3)->Int32Value());
2681 THREADED_TEST(FunctionCall) {
2682 v8::HandleScope scope;
2683 LocalContext context;
2687 " for (var i = 0; i < arguments.length; i++) {"
2688 " result.push(arguments[i]);"
2692 Local<Function> Foo =
2693 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2695 v8::Handle<Value>* args0 = NULL;
2696 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2697 CHECK_EQ(0, a0->Length());
2699 v8::Handle<Value> args1[] = { v8_num(1.1) };
2700 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2701 CHECK_EQ(1, a1->Length());
2702 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2704 v8::Handle<Value> args2[] = { v8_num(2.2),
2706 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2707 CHECK_EQ(2, a2->Length());
2708 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2709 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2711 v8::Handle<Value> args3[] = { v8_num(4.4),
2714 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2715 CHECK_EQ(3, a3->Length());
2716 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2717 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2718 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2720 v8::Handle<Value> args4[] = { v8_num(7.7),
2724 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2725 CHECK_EQ(4, a4->Length());
2726 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2727 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2728 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2729 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2733 static const char* js_code_causing_out_of_memory =
2734 "var a = new Array(); while(true) a.push(a);";
2737 // These tests run for a long time and prevent us from running tests
2738 // that come after them so they cannot run in parallel.
2740 // It's not possible to read a snapshot into a heap with different dimensions.
2741 if (i::Snapshot::IsEnabled()) return;
2743 static const int K = 1024;
2744 v8::ResourceConstraints constraints;
2745 constraints.set_max_young_space_size(256 * K);
2746 constraints.set_max_old_space_size(4 * K * K);
2747 v8::SetResourceConstraints(&constraints);
2749 // Execute a script that causes out of memory.
2750 v8::HandleScope scope;
2751 LocalContext context;
2752 v8::V8::IgnoreOutOfMemoryException();
2753 Local<Script> script =
2754 Script::Compile(String::New(js_code_causing_out_of_memory));
2755 Local<Value> result = script->Run();
2757 // Check for out of memory state.
2758 CHECK(result.IsEmpty());
2759 CHECK(context->HasOutOfMemoryException());
2763 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2764 ApiTestFuzzer::Fuzz();
2766 v8::HandleScope scope;
2767 LocalContext context;
2768 Local<Script> script =
2769 Script::Compile(String::New(js_code_causing_out_of_memory));
2770 Local<Value> result = script->Run();
2772 // Check for out of memory state.
2773 CHECK(result.IsEmpty());
2774 CHECK(context->HasOutOfMemoryException());
2780 TEST(OutOfMemoryNested) {
2781 // It's not possible to read a snapshot into a heap with different dimensions.
2782 if (i::Snapshot::IsEnabled()) return;
2784 static const int K = 1024;
2785 v8::ResourceConstraints constraints;
2786 constraints.set_max_young_space_size(256 * K);
2787 constraints.set_max_old_space_size(4 * K * K);
2788 v8::SetResourceConstraints(&constraints);
2790 v8::HandleScope scope;
2791 Local<ObjectTemplate> templ = ObjectTemplate::New();
2792 templ->Set(v8_str("ProvokeOutOfMemory"),
2793 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2794 LocalContext context(0, templ);
2795 v8::V8::IgnoreOutOfMemoryException();
2796 Local<Value> result = CompileRun(
2797 "var thrown = false;"
2799 " ProvokeOutOfMemory();"
2803 // Check for out of memory state.
2804 CHECK(result.IsEmpty());
2805 CHECK(context->HasOutOfMemoryException());
2809 TEST(HugeConsStringOutOfMemory) {
2810 // It's not possible to read a snapshot into a heap with different dimensions.
2811 if (i::Snapshot::IsEnabled()) return;
2813 static const int K = 1024;
2814 v8::ResourceConstraints constraints;
2815 constraints.set_max_young_space_size(256 * K);
2816 constraints.set_max_old_space_size(3 * K * K);
2817 v8::SetResourceConstraints(&constraints);
2819 // Execute a script that causes out of memory.
2820 v8::V8::IgnoreOutOfMemoryException();
2822 v8::HandleScope scope;
2823 LocalContext context;
2825 // Build huge string. This should fail with out of memory exception.
2826 Local<Value> result = CompileRun(
2827 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2828 "for (var i = 0; i < 22; i++) { str = str + str; }");
2830 // Check for out of memory state.
2831 CHECK(result.IsEmpty());
2832 CHECK(context->HasOutOfMemoryException());
2836 THREADED_TEST(ConstructCall) {
2837 v8::HandleScope scope;
2838 LocalContext context;
2842 " for (var i = 0; i < arguments.length; i++) {"
2843 " result.push(arguments[i]);"
2847 Local<Function> Foo =
2848 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2850 v8::Handle<Value>* args0 = NULL;
2851 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2852 CHECK_EQ(0, a0->Length());
2854 v8::Handle<Value> args1[] = { v8_num(1.1) };
2855 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2856 CHECK_EQ(1, a1->Length());
2857 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2859 v8::Handle<Value> args2[] = { v8_num(2.2),
2861 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2862 CHECK_EQ(2, a2->Length());
2863 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2864 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2866 v8::Handle<Value> args3[] = { v8_num(4.4),
2869 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2870 CHECK_EQ(3, a3->Length());
2871 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2872 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2873 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2875 v8::Handle<Value> args4[] = { v8_num(7.7),
2879 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2880 CHECK_EQ(4, a4->Length());
2881 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2882 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2883 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2884 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2888 static void CheckUncle(v8::TryCatch* try_catch) {
2889 CHECK(try_catch->HasCaught());
2890 String::AsciiValue str_value(try_catch->Exception());
2891 CHECK_EQ(*str_value, "uncle?");
2896 THREADED_TEST(ConversionNumber) {
2897 v8::HandleScope scope;
2899 // Very large number.
2900 CompileRun("var obj = Math.pow(2,32) * 1237;");
2901 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2902 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2903 CHECK_EQ(0, obj->ToInt32()->Value());
2904 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2906 CompileRun("var obj = -1234567890123;");
2907 obj = env->Global()->Get(v8_str("obj"));
2908 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2909 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2910 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2911 // Small positive integer.
2912 CompileRun("var obj = 42;");
2913 obj = env->Global()->Get(v8_str("obj"));
2914 CHECK_EQ(42.0, obj->ToNumber()->Value());
2915 CHECK_EQ(42, obj->ToInt32()->Value());
2916 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2917 // Negative integer.
2918 CompileRun("var obj = -37;");
2919 obj = env->Global()->Get(v8_str("obj"));
2920 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2921 CHECK_EQ(-37, obj->ToInt32()->Value());
2922 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2923 // Positive non-int32 integer.
2924 CompileRun("var obj = 0x81234567;");
2925 obj = env->Global()->Get(v8_str("obj"));
2926 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2927 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2928 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2930 CompileRun("var obj = 42.3;");
2931 obj = env->Global()->Get(v8_str("obj"));
2932 CHECK_EQ(42.3, obj->ToNumber()->Value());
2933 CHECK_EQ(42, obj->ToInt32()->Value());
2934 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2935 // Large negative fraction.
2936 CompileRun("var obj = -5726623061.75;");
2937 obj = env->Global()->Get(v8_str("obj"));
2938 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2939 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2940 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2944 THREADED_TEST(isNumberType) {
2945 v8::HandleScope scope;
2947 // Very large number.
2948 CompileRun("var obj = Math.pow(2,32) * 1237;");
2949 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2950 CHECK(!obj->IsInt32());
2951 CHECK(!obj->IsUint32());
2952 // Large negative number.
2953 CompileRun("var obj = -1234567890123;");
2954 obj = env->Global()->Get(v8_str("obj"));
2955 CHECK(!obj->IsInt32());
2956 CHECK(!obj->IsUint32());
2957 // Small positive integer.
2958 CompileRun("var obj = 42;");
2959 obj = env->Global()->Get(v8_str("obj"));
2960 CHECK(obj->IsInt32());
2961 CHECK(obj->IsUint32());
2962 // Negative integer.
2963 CompileRun("var obj = -37;");
2964 obj = env->Global()->Get(v8_str("obj"));
2965 CHECK(obj->IsInt32());
2966 CHECK(!obj->IsUint32());
2967 // Positive non-int32 integer.
2968 CompileRun("var obj = 0x81234567;");
2969 obj = env->Global()->Get(v8_str("obj"));
2970 CHECK(!obj->IsInt32());
2971 CHECK(obj->IsUint32());
2973 CompileRun("var obj = 42.3;");
2974 obj = env->Global()->Get(v8_str("obj"));
2975 CHECK(!obj->IsInt32());
2976 CHECK(!obj->IsUint32());
2977 // Large negative fraction.
2978 CompileRun("var obj = -5726623061.75;");
2979 obj = env->Global()->Get(v8_str("obj"));
2980 CHECK(!obj->IsInt32());
2981 CHECK(!obj->IsUint32());
2983 CompileRun("var obj = 0.0;");
2984 obj = env->Global()->Get(v8_str("obj"));
2985 CHECK(obj->IsInt32());
2986 CHECK(obj->IsUint32());
2988 CompileRun("var obj = -0.0;");
2989 obj = env->Global()->Get(v8_str("obj"));
2990 CHECK(!obj->IsInt32());
2991 CHECK(!obj->IsUint32());
2995 THREADED_TEST(ConversionException) {
2996 v8::HandleScope scope;
2999 "function TestClass() { };"
3000 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3001 "var obj = new TestClass();");
3002 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3004 v8::TryCatch try_catch;
3006 Local<Value> to_string_result = obj->ToString();
3007 CHECK(to_string_result.IsEmpty());
3008 CheckUncle(&try_catch);
3010 Local<Value> to_number_result = obj->ToNumber();
3011 CHECK(to_number_result.IsEmpty());
3012 CheckUncle(&try_catch);
3014 Local<Value> to_integer_result = obj->ToInteger();
3015 CHECK(to_integer_result.IsEmpty());
3016 CheckUncle(&try_catch);
3018 Local<Value> to_uint32_result = obj->ToUint32();
3019 CHECK(to_uint32_result.IsEmpty());
3020 CheckUncle(&try_catch);
3022 Local<Value> to_int32_result = obj->ToInt32();
3023 CHECK(to_int32_result.IsEmpty());
3024 CheckUncle(&try_catch);
3026 Local<Value> to_object_result = v8::Undefined()->ToObject();
3027 CHECK(to_object_result.IsEmpty());
3028 CHECK(try_catch.HasCaught());
3031 int32_t int32_value = obj->Int32Value();
3032 CHECK_EQ(0, int32_value);
3033 CheckUncle(&try_catch);
3035 uint32_t uint32_value = obj->Uint32Value();
3036 CHECK_EQ(0, uint32_value);
3037 CheckUncle(&try_catch);
3039 double number_value = obj->NumberValue();
3040 CHECK_NE(0, IsNaN(number_value));
3041 CheckUncle(&try_catch);
3043 int64_t integer_value = obj->IntegerValue();
3044 CHECK_EQ(0.0, static_cast<double>(integer_value));
3045 CheckUncle(&try_catch);
3049 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3050 ApiTestFuzzer::Fuzz();
3051 return v8::ThrowException(v8_str("konto"));
3055 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
3056 if (args.Length() < 1) return v8::False();
3057 v8::HandleScope scope;
3058 v8::TryCatch try_catch;
3059 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3060 CHECK(!try_catch.HasCaught() || result.IsEmpty());
3061 return v8::Boolean::New(try_catch.HasCaught());
3065 THREADED_TEST(APICatch) {
3066 v8::HandleScope scope;
3067 Local<ObjectTemplate> templ = ObjectTemplate::New();
3068 templ->Set(v8_str("ThrowFromC"),
3069 v8::FunctionTemplate::New(ThrowFromC));
3070 LocalContext context(0, templ);
3072 "var thrown = false;"
3078 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3079 CHECK(thrown->BooleanValue());
3083 THREADED_TEST(APIThrowTryCatch) {
3084 v8::HandleScope scope;
3085 Local<ObjectTemplate> templ = ObjectTemplate::New();
3086 templ->Set(v8_str("ThrowFromC"),
3087 v8::FunctionTemplate::New(ThrowFromC));
3088 LocalContext context(0, templ);
3089 v8::TryCatch try_catch;
3090 CompileRun("ThrowFromC();");
3091 CHECK(try_catch.HasCaught());
3095 // Test that a try-finally block doesn't shadow a try-catch block
3096 // when setting up an external handler.
3098 // BUG(271): Some of the exception propagation does not work on the
3099 // ARM simulator because the simulator separates the C++ stack and the
3100 // JS stack. This test therefore fails on the simulator. The test is
3101 // not threaded to allow the threading tests to run on the simulator.
3102 TEST(TryCatchInTryFinally) {
3103 v8::HandleScope scope;
3104 Local<ObjectTemplate> templ = ObjectTemplate::New();
3105 templ->Set(v8_str("CCatcher"),
3106 v8::FunctionTemplate::New(CCatcher));
3107 LocalContext context(0, templ);
3108 Local<Value> result = CompileRun("try {"
3110 " CCatcher('throw 7;');"
3115 CHECK(result->IsTrue());
3119 static void check_reference_error_message(
3120 v8::Handle<v8::Message> message,
3121 v8::Handle<v8::Value> data) {
3122 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3123 CHECK(message->Get()->Equals(v8_str(reference_error)));
3127 static v8::Handle<Value> Fail(const v8::Arguments& args) {
3128 ApiTestFuzzer::Fuzz();
3130 return v8::Undefined();
3134 // Test that overwritten methods are not invoked on uncaught exception
3135 // formatting. However, they are invoked when performing normal error
3136 // string conversions.
3137 TEST(APIThrowMessageOverwrittenToString) {
3138 v8::HandleScope scope;
3139 v8::V8::AddMessageListener(check_reference_error_message);
3140 Local<ObjectTemplate> templ = ObjectTemplate::New();
3141 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3142 LocalContext context(NULL, templ);
3143 CompileRun("asdf;");
3144 CompileRun("var limit = {};"
3145 "limit.valueOf = fail;"
3146 "Error.stackTraceLimit = limit;");
3148 CompileRun("Array.prototype.pop = fail;");
3149 CompileRun("Object.prototype.hasOwnProperty = fail;");
3150 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
3151 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3152 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
3153 CompileRun("ReferenceError.prototype.toString ="
3154 " function() { return 'Whoops' }");
3155 CompileRun("asdf;");
3156 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3157 CompileRun("asdf;");
3158 CompileRun("ReferenceError.prototype.constructor = void 0;");
3159 CompileRun("asdf;");
3160 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3161 CompileRun("asdf;");
3162 CompileRun("ReferenceError.prototype = new Object();");
3163 CompileRun("asdf;");
3164 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3165 CHECK(string->Equals(v8_str("Whoops")));
3166 CompileRun("ReferenceError.prototype.constructor = new Object();"
3167 "ReferenceError.prototype.constructor.name = 1;"
3168 "Number.prototype.toString = function() { return 'Whoops'; };"
3169 "ReferenceError.prototype.toString = Object.prototype.toString;");
3170 CompileRun("asdf;");
3171 v8::V8::RemoveMessageListeners(check_reference_error_message);
3175 static void check_custom_error_message(
3176 v8::Handle<v8::Message> message,
3177 v8::Handle<v8::Value> data) {
3178 const char* uncaught_error = "Uncaught MyError toString";
3179 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3183 TEST(CustomErrorToString) {
3184 v8::HandleScope scope;
3185 v8::V8::AddMessageListener(check_custom_error_message);
3186 LocalContext context;
3188 "function MyError(name, message) { "
3189 " this.name = name; "
3190 " this.message = message; "
3192 "MyError.prototype = Object.create(Error.prototype); "
3193 "MyError.prototype.toString = function() { "
3194 " return 'MyError toString'; "
3196 "throw new MyError('my name', 'my message'); ");
3197 v8::V8::RemoveMessageListeners(check_custom_error_message);
3201 static void receive_message(v8::Handle<v8::Message> message,
3202 v8::Handle<v8::Value> data) {
3204 message_received = true;
3208 TEST(APIThrowMessage) {
3209 message_received = false;
3210 v8::HandleScope scope;
3211 v8::V8::AddMessageListener(receive_message);
3212 Local<ObjectTemplate> templ = ObjectTemplate::New();
3213 templ->Set(v8_str("ThrowFromC"),
3214 v8::FunctionTemplate::New(ThrowFromC));
3215 LocalContext context(0, templ);
3216 CompileRun("ThrowFromC();");
3217 CHECK(message_received);
3218 v8::V8::RemoveMessageListeners(receive_message);
3222 TEST(APIThrowMessageAndVerboseTryCatch) {
3223 message_received = false;
3224 v8::HandleScope scope;
3225 v8::V8::AddMessageListener(receive_message);
3226 Local<ObjectTemplate> templ = ObjectTemplate::New();
3227 templ->Set(v8_str("ThrowFromC"),
3228 v8::FunctionTemplate::New(ThrowFromC));
3229 LocalContext context(0, templ);
3230 v8::TryCatch try_catch;
3231 try_catch.SetVerbose(true);
3232 Local<Value> result = CompileRun("ThrowFromC();");
3233 CHECK(try_catch.HasCaught());
3234 CHECK(result.IsEmpty());
3235 CHECK(message_received);
3236 v8::V8::RemoveMessageListeners(receive_message);
3240 TEST(APIStackOverflowAndVerboseTryCatch) {
3241 message_received = false;
3242 v8::HandleScope scope;
3243 v8::V8::AddMessageListener(receive_message);
3244 LocalContext context;
3245 v8::TryCatch try_catch;
3246 try_catch.SetVerbose(true);
3247 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3248 CHECK(try_catch.HasCaught());
3249 CHECK(result.IsEmpty());
3250 CHECK(message_received);
3251 v8::V8::RemoveMessageListeners(receive_message);
3255 THREADED_TEST(ExternalScriptException) {
3256 v8::HandleScope scope;
3257 Local<ObjectTemplate> templ = ObjectTemplate::New();
3258 templ->Set(v8_str("ThrowFromC"),
3259 v8::FunctionTemplate::New(ThrowFromC));
3260 LocalContext context(0, templ);
3262 v8::TryCatch try_catch;
3263 Local<Script> script
3264 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3265 Local<Value> result = script->Run();
3266 CHECK(result.IsEmpty());
3267 CHECK(try_catch.HasCaught());
3268 String::AsciiValue exception_value(try_catch.Exception());
3269 CHECK_EQ("konto", *exception_value);
3274 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3275 ApiTestFuzzer::Fuzz();
3276 CHECK_EQ(4, args.Length());
3277 int count = args[0]->Int32Value();
3278 int cInterval = args[2]->Int32Value();
3280 return v8::ThrowException(v8_str("FromC"));
3282 Local<v8::Object> global = Context::GetCurrent()->Global();
3283 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3284 v8::Handle<Value> argv[] = { v8_num(count - 1),
3288 if (count % cInterval == 0) {
3289 v8::TryCatch try_catch;
3290 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3291 int expected = args[3]->Int32Value();
3292 if (try_catch.HasCaught()) {
3293 CHECK_EQ(expected, count);
3294 CHECK(result.IsEmpty());
3295 CHECK(!i::Isolate::Current()->has_scheduled_exception());
3297 CHECK_NE(expected, count);
3301 return fun.As<Function>()->Call(global, 4, argv);
3307 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3308 ApiTestFuzzer::Fuzz();
3309 CHECK_EQ(3, args.Length());
3310 bool equality = args[0]->BooleanValue();
3311 int count = args[1]->Int32Value();
3312 int expected = args[2]->Int32Value();
3314 CHECK_EQ(count, expected);
3316 CHECK_NE(count, expected);
3318 return v8::Undefined();
3322 THREADED_TEST(EvalInTryFinally) {
3323 v8::HandleScope scope;
3324 LocalContext context;
3325 v8::TryCatch try_catch;
3326 CompileRun("(function() {"
3328 " eval('asldkf (*&^&*^');"
3333 CHECK(!try_catch.HasCaught());
3337 // This test works by making a stack of alternating JavaScript and C
3338 // activations. These activations set up exception handlers with regular
3339 // intervals, one interval for C activations and another for JavaScript
3340 // activations. When enough activations have been created an exception is
3341 // thrown and we check that the right activation catches the exception and that
3342 // no other activations do. The right activation is always the topmost one with
3343 // a handler, regardless of whether it is in JavaScript or C.
3345 // The notation used to describe a test case looks like this:
3347 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3349 // Each entry is an activation, either JS or C. The index is the count at that
3350 // level. Stars identify activations with exception handlers, the @ identifies
3351 // the exception handler that should catch the exception.
3353 // BUG(271): Some of the exception propagation does not work on the
3354 // ARM simulator because the simulator separates the C++ stack and the
3355 // JS stack. This test therefore fails on the simulator. The test is
3356 // not threaded to allow the threading tests to run on the simulator.
3357 TEST(ExceptionOrder) {
3358 v8::HandleScope scope;
3359 Local<ObjectTemplate> templ = ObjectTemplate::New();
3360 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3361 templ->Set(v8_str("CThrowCountDown"),
3362 v8::FunctionTemplate::New(CThrowCountDown));
3363 LocalContext context(0, templ);
3365 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3366 " if (count == 0) throw 'FromJS';"
3367 " if (count % jsInterval == 0) {"
3369 " var value = CThrowCountDown(count - 1,"
3373 " check(false, count, expected);"
3376 " check(true, count, expected);"
3379 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3382 Local<Function> fun =
3383 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3386 // count jsInterval cInterval expected
3388 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3389 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3390 fun->Call(fun, argc, a0);
3392 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3393 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3394 fun->Call(fun, argc, a1);
3396 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3397 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3398 fun->Call(fun, argc, a2);
3400 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3401 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3402 fun->Call(fun, argc, a3);
3404 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3405 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3406 fun->Call(fun, argc, a4);
3408 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3409 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3410 fun->Call(fun, argc, a5);
3414 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3415 ApiTestFuzzer::Fuzz();
3416 CHECK_EQ(1, args.Length());
3417 return v8::ThrowException(args[0]);
3421 THREADED_TEST(ThrowValues) {
3422 v8::HandleScope scope;
3423 Local<ObjectTemplate> templ = ObjectTemplate::New();
3424 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3425 LocalContext context(0, templ);
3426 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3427 "function Run(obj) {"
3433 " return 'no exception';"
3435 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3436 CHECK_EQ(5, result->Length());
3437 CHECK(result->Get(v8::Integer::New(0))->IsString());
3438 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3439 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3440 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3441 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3442 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3443 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3447 THREADED_TEST(CatchZero) {
3448 v8::HandleScope scope;
3449 LocalContext context;
3450 v8::TryCatch try_catch;
3451 CHECK(!try_catch.HasCaught());
3452 Script::Compile(v8_str("throw 10"))->Run();
3453 CHECK(try_catch.HasCaught());
3454 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3456 CHECK(!try_catch.HasCaught());
3457 Script::Compile(v8_str("throw 0"))->Run();
3458 CHECK(try_catch.HasCaught());
3459 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3463 THREADED_TEST(CatchExceptionFromWith) {
3464 v8::HandleScope scope;
3465 LocalContext context;
3466 v8::TryCatch try_catch;
3467 CHECK(!try_catch.HasCaught());
3468 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3469 CHECK(try_catch.HasCaught());
3473 THREADED_TEST(TryCatchAndFinallyHidingException) {
3474 v8::HandleScope scope;
3475 LocalContext context;
3476 v8::TryCatch try_catch;
3477 CHECK(!try_catch.HasCaught());
3478 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3479 CompileRun("f({toString: function() { throw 42; }});");
3480 CHECK(!try_catch.HasCaught());
3484 v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3485 v8::TryCatch try_catch;
3486 return v8::Undefined();
3490 THREADED_TEST(TryCatchAndFinally) {
3491 v8::HandleScope scope;
3492 LocalContext context;
3493 context->Global()->Set(
3494 v8_str("native_with_try_catch"),
3495 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3496 v8::TryCatch try_catch;
3497 CHECK(!try_catch.HasCaught());
3500 " throw new Error('a');\n"
3502 " native_with_try_catch();\n"
3504 CHECK(try_catch.HasCaught());
3508 THREADED_TEST(Equality) {
3509 v8::HandleScope scope;
3510 LocalContext context;
3511 // Check that equality works at all before relying on CHECK_EQ
3512 CHECK(v8_str("a")->Equals(v8_str("a")));
3513 CHECK(!v8_str("a")->Equals(v8_str("b")));
3515 CHECK_EQ(v8_str("a"), v8_str("a"));
3516 CHECK_NE(v8_str("a"), v8_str("b"));
3517 CHECK_EQ(v8_num(1), v8_num(1));
3518 CHECK_EQ(v8_num(1.00), v8_num(1));
3519 CHECK_NE(v8_num(1), v8_num(2));
3521 // Assume String is not symbol.
3522 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3523 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3524 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3525 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3526 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3527 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3528 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3529 CHECK(!not_a_number->StrictEquals(not_a_number));
3530 CHECK(v8::False()->StrictEquals(v8::False()));
3531 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3533 v8::Handle<v8::Object> obj = v8::Object::New();
3534 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3535 CHECK(alias->StrictEquals(obj));
3540 THREADED_TEST(MultiRun) {
3541 v8::HandleScope scope;
3542 LocalContext context;
3543 Local<Script> script = Script::Compile(v8_str("x"));
3544 for (int i = 0; i < 10; i++)
3549 static v8::Handle<Value> GetXValue(Local<String> name,
3550 const AccessorInfo& info) {
3551 ApiTestFuzzer::Fuzz();
3552 CHECK_EQ(info.Data(), v8_str("donut"));
3553 CHECK_EQ(name, v8_str("x"));
3558 THREADED_TEST(SimplePropertyRead) {
3559 v8::HandleScope scope;
3560 Local<ObjectTemplate> templ = ObjectTemplate::New();
3561 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3562 LocalContext context;
3563 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3564 Local<Script> script = Script::Compile(v8_str("obj.x"));
3565 for (int i = 0; i < 10; i++) {
3566 Local<Value> result = script->Run();
3567 CHECK_EQ(result, v8_str("x"));
3571 THREADED_TEST(DefinePropertyOnAPIAccessor) {
3572 v8::HandleScope scope;
3573 Local<ObjectTemplate> templ = ObjectTemplate::New();
3574 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3575 LocalContext context;
3576 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3578 // Uses getOwnPropertyDescriptor to check the configurable status
3579 Local<Script> script_desc
3580 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3582 "prop.configurable;"));
3583 Local<Value> result = script_desc->Run();
3584 CHECK_EQ(result->BooleanValue(), true);
3586 // Redefine get - but still configurable
3587 Local<Script> script_define
3588 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3589 " configurable: true };"
3590 "Object.defineProperty(obj, 'x', desc);"
3592 result = script_define->Run();
3593 CHECK_EQ(result, v8_num(42));
3595 // Check that the accessor is still configurable
3596 result = script_desc->Run();
3597 CHECK_EQ(result->BooleanValue(), true);
3599 // Redefine to a non-configurable
3601 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3602 " configurable: false };"
3603 "Object.defineProperty(obj, 'x', desc);"
3605 result = script_define->Run();
3606 CHECK_EQ(result, v8_num(43));
3607 result = script_desc->Run();
3608 CHECK_EQ(result->BooleanValue(), false);
3610 // Make sure that it is not possible to redefine again
3611 v8::TryCatch try_catch;
3612 result = script_define->Run();
3613 CHECK(try_catch.HasCaught());
3614 String::AsciiValue exception_value(try_catch.Exception());
3615 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3618 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3619 v8::HandleScope scope;
3620 Local<ObjectTemplate> templ = ObjectTemplate::New();
3621 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3622 LocalContext context;
3623 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3625 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3626 "Object.getOwnPropertyDescriptor( "
3628 "prop.configurable;"));
3629 Local<Value> result = script_desc->Run();
3630 CHECK_EQ(result->BooleanValue(), true);
3632 Local<Script> script_define =
3633 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3634 " configurable: true };"
3635 "Object.defineProperty(obj, 'x', desc);"
3637 result = script_define->Run();
3638 CHECK_EQ(result, v8_num(42));
3641 result = script_desc->Run();
3642 CHECK_EQ(result->BooleanValue(), true);
3646 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3647 " configurable: false };"
3648 "Object.defineProperty(obj, 'x', desc);"
3650 result = script_define->Run();
3651 CHECK_EQ(result, v8_num(43));
3652 result = script_desc->Run();
3654 CHECK_EQ(result->BooleanValue(), false);
3656 v8::TryCatch try_catch;
3657 result = script_define->Run();
3658 CHECK(try_catch.HasCaught());
3659 String::AsciiValue exception_value(try_catch.Exception());
3660 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3664 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3666 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3670 THREADED_TEST(DefineAPIAccessorOnObject) {
3671 v8::HandleScope scope;
3672 Local<ObjectTemplate> templ = ObjectTemplate::New();
3673 LocalContext context;
3675 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3676 CompileRun("var obj2 = {};");
3678 CHECK(CompileRun("obj1.x")->IsUndefined());
3679 CHECK(CompileRun("obj2.x")->IsUndefined());
3681 CHECK(GetGlobalProperty(&context, "obj1")->
3682 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3684 ExpectString("obj1.x", "x");
3685 CHECK(CompileRun("obj2.x")->IsUndefined());
3687 CHECK(GetGlobalProperty(&context, "obj2")->
3688 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3690 ExpectString("obj1.x", "x");
3691 ExpectString("obj2.x", "x");
3693 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3694 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3696 CompileRun("Object.defineProperty(obj1, 'x',"
3697 "{ get: function() { return 'y'; }, configurable: true })");
3699 ExpectString("obj1.x", "y");
3700 ExpectString("obj2.x", "x");
3702 CompileRun("Object.defineProperty(obj2, 'x',"
3703 "{ get: function() { return 'y'; }, configurable: true })");
3705 ExpectString("obj1.x", "y");
3706 ExpectString("obj2.x", "y");
3708 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3709 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3711 CHECK(GetGlobalProperty(&context, "obj1")->
3712 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3713 CHECK(GetGlobalProperty(&context, "obj2")->
3714 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3716 ExpectString("obj1.x", "x");
3717 ExpectString("obj2.x", "x");
3719 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3720 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3722 // Define getters/setters, but now make them not configurable.
3723 CompileRun("Object.defineProperty(obj1, 'x',"
3724 "{ get: function() { return 'z'; }, configurable: false })");
3725 CompileRun("Object.defineProperty(obj2, 'x',"
3726 "{ get: function() { return 'z'; }, configurable: false })");
3728 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3729 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3731 ExpectString("obj1.x", "z");
3732 ExpectString("obj2.x", "z");
3734 CHECK(!GetGlobalProperty(&context, "obj1")->
3735 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3736 CHECK(!GetGlobalProperty(&context, "obj2")->
3737 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3739 ExpectString("obj1.x", "z");
3740 ExpectString("obj2.x", "z");
3744 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3745 v8::HandleScope scope;
3746 Local<ObjectTemplate> templ = ObjectTemplate::New();
3747 LocalContext context;
3749 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3750 CompileRun("var obj2 = {};");
3752 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3755 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3756 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3759 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3761 ExpectString("obj1.x", "x");
3762 ExpectString("obj2.x", "x");
3764 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3765 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3767 CHECK(!GetGlobalProperty(&context, "obj1")->
3768 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3769 CHECK(!GetGlobalProperty(&context, "obj2")->
3770 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3773 v8::TryCatch try_catch;
3774 CompileRun("Object.defineProperty(obj1, 'x',"
3775 "{get: function() { return 'func'; }})");
3776 CHECK(try_catch.HasCaught());
3777 String::AsciiValue exception_value(try_catch.Exception());
3778 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3781 v8::TryCatch try_catch;
3782 CompileRun("Object.defineProperty(obj2, 'x',"
3783 "{get: function() { return 'func'; }})");
3784 CHECK(try_catch.HasCaught());
3785 String::AsciiValue exception_value(try_catch.Exception());
3786 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3791 static v8::Handle<Value> Get239Value(Local<String> name,
3792 const AccessorInfo& info) {
3793 ApiTestFuzzer::Fuzz();
3794 CHECK_EQ(info.Data(), v8_str("donut"));
3795 CHECK_EQ(name, v8_str("239"));
3800 THREADED_TEST(ElementAPIAccessor) {
3801 v8::HandleScope scope;
3802 Local<ObjectTemplate> templ = ObjectTemplate::New();
3803 LocalContext context;
3805 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3806 CompileRun("var obj2 = {};");
3808 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3812 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3817 ExpectString("obj1[239]", "239");
3818 ExpectString("obj2[239]", "239");
3819 ExpectString("obj1['239']", "239");
3820 ExpectString("obj2['239']", "239");
3824 v8::Persistent<Value> xValue;
3827 static void SetXValue(Local<String> name,
3829 const AccessorInfo& info) {
3830 CHECK_EQ(value, v8_num(4));
3831 CHECK_EQ(info.Data(), v8_str("donut"));
3832 CHECK_EQ(name, v8_str("x"));
3833 CHECK(xValue.IsEmpty());
3834 xValue = v8::Persistent<Value>::New(value);
3838 THREADED_TEST(SimplePropertyWrite) {
3839 v8::HandleScope scope;
3840 Local<ObjectTemplate> templ = ObjectTemplate::New();
3841 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3842 LocalContext context;
3843 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3844 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3845 for (int i = 0; i < 10; i++) {
3846 CHECK(xValue.IsEmpty());
3848 CHECK_EQ(v8_num(4), xValue);
3850 xValue = v8::Persistent<Value>();
3855 THREADED_TEST(SetterOnly) {
3856 v8::HandleScope scope;
3857 Local<ObjectTemplate> templ = ObjectTemplate::New();
3858 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
3859 LocalContext context;
3860 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3861 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3862 for (int i = 0; i < 10; i++) {
3863 CHECK(xValue.IsEmpty());
3865 CHECK_EQ(v8_num(4), xValue);
3867 xValue = v8::Persistent<Value>();
3872 THREADED_TEST(NoAccessors) {
3873 v8::HandleScope scope;
3874 Local<ObjectTemplate> templ = ObjectTemplate::New();
3875 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
3876 LocalContext context;
3877 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3878 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3879 for (int i = 0; i < 10; i++) {
3885 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3886 const AccessorInfo& info) {
3887 ApiTestFuzzer::Fuzz();
3888 CHECK(info.Data()->IsUndefined());
3893 THREADED_TEST(NamedInterceptorPropertyRead) {
3894 v8::HandleScope scope;
3895 Local<ObjectTemplate> templ = ObjectTemplate::New();
3896 templ->SetNamedPropertyHandler(XPropertyGetter);
3897 LocalContext context;
3898 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3899 Local<Script> script = Script::Compile(v8_str("obj.x"));
3900 for (int i = 0; i < 10; i++) {
3901 Local<Value> result = script->Run();
3902 CHECK_EQ(result, v8_str("x"));
3907 THREADED_TEST(NamedInterceptorDictionaryIC) {
3908 v8::HandleScope scope;
3909 Local<ObjectTemplate> templ = ObjectTemplate::New();
3910 templ->SetNamedPropertyHandler(XPropertyGetter);
3911 LocalContext context;
3912 // Create an object with a named interceptor.
3913 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3914 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3915 for (int i = 0; i < 10; i++) {
3916 Local<Value> result = script->Run();
3917 CHECK_EQ(result, v8_str("x"));
3919 // Create a slow case object and a function accessing a property in
3920 // that slow case object (with dictionary probing in generated
3921 // code). Then force object with a named interceptor into slow-case,
3922 // pass it to the function, and check that the interceptor is called
3923 // instead of accessing the local property.
3924 Local<Value> result =
3925 CompileRun("function get_x(o) { return o.x; };"
3926 "var obj = { x : 42, y : 0 };"
3928 "for (var i = 0; i < 10; i++) get_x(obj);"
3929 "interceptor_obj.x = 42;"
3930 "interceptor_obj.y = 10;"
3931 "delete interceptor_obj.y;"
3932 "get_x(interceptor_obj)");
3933 CHECK_EQ(result, v8_str("x"));
3937 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3938 v8::HandleScope scope;
3940 v8::Persistent<Context> context1 = Context::New();
3943 Local<ObjectTemplate> templ = ObjectTemplate::New();
3944 templ->SetNamedPropertyHandler(XPropertyGetter);
3945 // Create an object with a named interceptor.
3946 v8::Local<v8::Object> object = templ->NewInstance();
3947 context1->Global()->Set(v8_str("interceptor_obj"), object);
3949 // Force the object into the slow case.
3950 CompileRun("interceptor_obj.y = 0;"
3951 "delete interceptor_obj.y;");
3955 // Introduce the object into a different context.
3956 // Repeat named loads to exercise ICs.
3957 LocalContext context2;
3958 context2->Global()->Set(v8_str("interceptor_obj"), object);
3959 Local<Value> result =
3960 CompileRun("function get_x(o) { return o.x; }"
3961 "interceptor_obj.x = 42;"
3962 "for (var i=0; i != 10; i++) {"
3963 " get_x(interceptor_obj);"
3965 "get_x(interceptor_obj)");
3966 // Check that the interceptor was actually invoked.
3967 CHECK_EQ(result, v8_str("x"));
3970 // Return to the original context and force some object to the slow case
3971 // to cause the NormalizedMapCache to verify.
3973 CompileRun("var obj = { x : 0 }; delete obj.x;");
3980 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3981 const AccessorInfo& info) {
3982 // Set x on the prototype object and do not handle the get request.
3983 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3984 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3985 return v8::Handle<Value>();
3989 // This is a regression test for http://crbug.com/20104. Map
3990 // transitions should not interfere with post interceptor lookup.
3991 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3992 v8::HandleScope scope;
3993 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3994 Local<v8::ObjectTemplate> instance_template
3995 = function_template->InstanceTemplate();
3996 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3997 LocalContext context;
3998 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3999 // Create an instance of F and introduce a map transition for x.
4000 CompileRun("var o = new F(); o.x = 23;");
4001 // Create an instance of F and invoke the getter. The result should be 23.
4002 Local<Value> result = CompileRun("o = new F(); o.x");
4003 CHECK_EQ(result->Int32Value(), 23);
4007 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4008 const AccessorInfo& info) {
4009 ApiTestFuzzer::Fuzz();
4011 return v8::Handle<Value>(v8_num(625));
4013 return v8::Handle<Value>();
4017 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4019 const AccessorInfo& info) {
4020 ApiTestFuzzer::Fuzz();
4024 return v8::Handle<Value>();
4028 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4029 v8::HandleScope scope;
4030 Local<ObjectTemplate> templ = ObjectTemplate::New();
4031 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4032 IndexedPropertySetter);
4033 LocalContext context;
4034 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4035 Local<Script> getter_script = Script::Compile(v8_str(
4036 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4037 Local<Script> setter_script = Script::Compile(v8_str(
4038 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4041 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4042 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4044 "obj.foo;")); // This setter should not run, due to the interceptor.
4045 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4047 Local<Value> result = getter_script->Run();
4048 CHECK_EQ(v8_num(5), result);
4049 result = setter_script->Run();
4050 CHECK_EQ(v8_num(23), result);
4051 result = interceptor_setter_script->Run();
4052 CHECK_EQ(v8_num(23), result);
4053 result = interceptor_getter_script->Run();
4054 CHECK_EQ(v8_num(625), result);
4058 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4060 const AccessorInfo& info) {
4061 ApiTestFuzzer::Fuzz();
4063 return v8::Handle<Value>(v8_num(index));
4065 return v8::Handle<Value>();
4069 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4072 const AccessorInfo& info) {
4073 ApiTestFuzzer::Fuzz();
4075 return v8::Handle<Value>(v8_num(index));
4077 return v8::Handle<Value>();
4081 Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4082 const AccessorInfo& info) {
4083 // Force the list of returned keys to be stored in a FastDoubleArray.
4084 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4085 "keys = new Array(); keys[125000] = 1;"
4086 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4087 "keys.length = 25; keys;"));
4088 Local<Value> result = indexed_property_names_script->Run();
4089 return Local<v8::Array>(::v8::Array::Cast(*result));
4093 // Make sure that the the interceptor code in the runtime properly handles
4094 // merging property name lists for double-array-backed arrays.
4095 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4096 v8::HandleScope scope;
4097 Local<ObjectTemplate> templ = ObjectTemplate::New();
4098 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4099 UnboxedDoubleIndexedPropertySetter,
4102 UnboxedDoubleIndexedPropertyEnumerator);
4103 LocalContext context;
4104 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4105 // When obj is created, force it to be Stored in a FastDoubleArray.
4106 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4107 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4109 "for (x in obj) {key_count++;};"
4111 Local<Value> result = create_unboxed_double_script->Run();
4112 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4113 Local<Script> key_count_check = Script::Compile(v8_str(
4115 result = key_count_check->Run();
4116 CHECK_EQ(v8_num(40013), result);
4120 Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4121 const AccessorInfo& info) {
4122 // Force the list of returned keys to be stored in a Arguments object.
4123 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4125 " return arguments;"
4127 "keys = f(0, 1, 2, 3);"
4129 Local<Value> result = indexed_property_names_script->Run();
4130 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4134 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4136 const AccessorInfo& info) {
4137 ApiTestFuzzer::Fuzz();
4139 return v8::Handle<Value>(v8_num(index));
4141 return v8::Handle<Value>();
4145 // Make sure that the the interceptor code in the runtime properly handles
4146 // merging property name lists for non-string arguments arrays.
4147 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4148 v8::HandleScope scope;
4149 Local<ObjectTemplate> templ = ObjectTemplate::New();
4150 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4154 NonStrictArgsIndexedPropertyEnumerator);
4155 LocalContext context;
4156 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4157 Local<Script> create_args_script =
4158 Script::Compile(v8_str(
4159 "var key_count = 0;"
4160 "for (x in obj) {key_count++;} key_count;"));
4161 Local<Value> result = create_args_script->Run();
4162 CHECK_EQ(v8_num(4), result);
4166 static v8::Handle<Value> IdentityIndexedPropertyGetter(
4168 const AccessorInfo& info) {
4169 return v8::Integer::NewFromUnsigned(index);
4173 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4174 v8::HandleScope scope;
4175 Local<ObjectTemplate> templ = ObjectTemplate::New();
4176 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4178 LocalContext context;
4179 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4181 // Check fast object case.
4182 const char* fast_case_code =
4183 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4184 ExpectString(fast_case_code, "0");
4187 const char* slow_case_code =
4188 "obj.x = 1; delete obj.x;"
4189 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4190 ExpectString(slow_case_code, "1");
4194 THREADED_TEST(IndexedInterceptorWithNoSetter) {
4195 v8::HandleScope scope;
4196 Local<ObjectTemplate> templ = ObjectTemplate::New();
4197 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4199 LocalContext context;
4200 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4205 " for (var i = 0; i < 100; i++) {"
4207 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4213 ExpectString(code, "PASSED");
4217 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4218 v8::HandleScope scope;
4219 Local<ObjectTemplate> templ = ObjectTemplate::New();
4220 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4222 LocalContext context;
4223 Local<v8::Object> obj = templ->NewInstance();
4224 obj->TurnOnAccessCheck();
4225 context->Global()->Set(v8_str("obj"), obj);
4229 " for (var i = 0; i < 100; i++) {"
4231 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4237 ExpectString(code, "PASSED");
4241 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4242 i::FLAG_allow_natives_syntax = true;
4243 v8::HandleScope scope;
4244 Local<ObjectTemplate> templ = ObjectTemplate::New();
4245 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4247 LocalContext context;
4248 Local<v8::Object> obj = templ->NewInstance();
4249 context->Global()->Set(v8_str("obj"), obj);
4253 " for (var i = 0; i < 100; i++) {"
4254 " var expected = i;"
4256 " %EnableAccessChecks(obj);"
4257 " expected = undefined;"
4260 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4261 " if (i == 5) %DisableAccessChecks(obj);"
4267 ExpectString(code, "PASSED");
4271 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4272 v8::HandleScope scope;
4273 Local<ObjectTemplate> templ = ObjectTemplate::New();
4274 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4276 LocalContext context;
4277 Local<v8::Object> obj = templ->NewInstance();
4278 context->Global()->Set(v8_str("obj"), obj);
4282 " for (var i = 0; i < 100; i++) {"
4284 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4290 ExpectString(code, "PASSED");
4294 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4295 v8::HandleScope scope;
4296 Local<ObjectTemplate> templ = ObjectTemplate::New();
4297 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4299 LocalContext context;
4300 Local<v8::Object> obj = templ->NewInstance();
4301 context->Global()->Set(v8_str("obj"), obj);
4305 " for (var i = 0; i < 100; i++) {"
4306 " var expected = i;"
4310 " expected = undefined;"
4313 " /* probe minimal Smi number on 32-bit platforms */"
4314 " key = -(1 << 30);"
4315 " expected = undefined;"
4318 " /* probe minimal Smi number on 64-bit platforms */"
4320 " expected = undefined;"
4322 " var v = obj[key];"
4323 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4329 ExpectString(code, "PASSED");
4333 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4334 v8::HandleScope scope;
4335 Local<ObjectTemplate> templ = ObjectTemplate::New();
4336 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4338 LocalContext context;
4339 Local<v8::Object> obj = templ->NewInstance();
4340 context->Global()->Set(v8_str("obj"), obj);
4344 " for (var i = 0; i < 100; i++) {"
4345 " var expected = i;"
4349 " expected = undefined;"
4351 " var v = obj[key];"
4352 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4358 ExpectString(code, "PASSED");
4362 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4363 v8::HandleScope scope;
4364 Local<ObjectTemplate> templ = ObjectTemplate::New();
4365 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4367 LocalContext context;
4368 Local<v8::Object> obj = templ->NewInstance();
4369 context->Global()->Set(v8_str("obj"), obj);
4372 "var original = obj;"
4374 " for (var i = 0; i < 100; i++) {"
4375 " var expected = i;"
4377 " obj = {50: 'foobar'};"
4378 " expected = 'foobar';"
4381 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4382 " if (i == 50) obj = original;"
4388 ExpectString(code, "PASSED");
4392 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4393 v8::HandleScope scope;
4394 Local<ObjectTemplate> templ = ObjectTemplate::New();
4395 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4397 LocalContext context;
4398 Local<v8::Object> obj = templ->NewInstance();
4399 context->Global()->Set(v8_str("obj"), obj);
4402 "var original = obj;"
4404 " for (var i = 0; i < 100; i++) {"
4405 " var expected = i;"
4408 " expected = undefined;"
4411 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4412 " if (i == 5) obj = original;"
4418 ExpectString(code, "PASSED");
4422 THREADED_TEST(IndexedInterceptorOnProto) {
4423 v8::HandleScope scope;
4424 Local<ObjectTemplate> templ = ObjectTemplate::New();
4425 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4427 LocalContext context;
4428 Local<v8::Object> obj = templ->NewInstance();
4429 context->Global()->Set(v8_str("obj"), obj);
4432 "var o = {__proto__: obj};"
4434 " for (var i = 0; i < 100; i++) {"
4436 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4442 ExpectString(code, "PASSED");
4446 THREADED_TEST(MultiContexts) {
4447 v8::HandleScope scope;
4448 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4449 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4451 Local<String> password = v8_str("Password");
4453 // Create an environment
4454 LocalContext context0(0, templ);
4455 context0->SetSecurityToken(password);
4456 v8::Handle<v8::Object> global0 = context0->Global();
4457 global0->Set(v8_str("custom"), v8_num(1234));
4458 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4460 // Create an independent environment
4461 LocalContext context1(0, templ);
4462 context1->SetSecurityToken(password);
4463 v8::Handle<v8::Object> global1 = context1->Global();
4464 global1->Set(v8_str("custom"), v8_num(1234));
4465 CHECK_NE(global0, global1);
4466 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4467 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4469 // Now create a new context with the old global
4470 LocalContext context2(0, templ, global1);
4471 context2->SetSecurityToken(password);
4472 v8::Handle<v8::Object> global2 = context2->Global();
4473 CHECK_EQ(global1, global2);
4474 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4475 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4479 THREADED_TEST(FunctionPrototypeAcrossContexts) {
4480 // Make sure that functions created by cloning boilerplates cannot
4481 // communicate through their __proto__ field.
4483 v8::HandleScope scope;
4486 v8::Handle<v8::Object> global0 =
4488 v8::Handle<v8::Object> object0 =
4489 global0->Get(v8_str("Object")).As<v8::Object>();
4490 v8::Handle<v8::Object> tostring0 =
4491 object0->Get(v8_str("toString")).As<v8::Object>();
4492 v8::Handle<v8::Object> proto0 =
4493 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4494 proto0->Set(v8_str("custom"), v8_num(1234));
4497 v8::Handle<v8::Object> global1 =
4499 v8::Handle<v8::Object> object1 =
4500 global1->Get(v8_str("Object")).As<v8::Object>();
4501 v8::Handle<v8::Object> tostring1 =
4502 object1->Get(v8_str("toString")).As<v8::Object>();
4503 v8::Handle<v8::Object> proto1 =
4504 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4505 CHECK(!proto1->Has(v8_str("custom")));
4509 THREADED_TEST(Regress892105) {
4510 // Make sure that object and array literals created by cloning
4511 // boilerplates cannot communicate through their __proto__
4512 // field. This is rather difficult to check, but we try to add stuff
4513 // to Object.prototype and Array.prototype and create a new
4514 // environment. This should succeed.
4516 v8::HandleScope scope;
4518 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4519 "Array.prototype.arr = 4567;"
4523 Local<Script> script0 = Script::Compile(source);
4524 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4527 Local<Script> script1 = Script::Compile(source);
4528 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4532 THREADED_TEST(UndetectableObject) {
4533 v8::HandleScope scope;
4536 Local<v8::FunctionTemplate> desc =
4537 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4538 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4540 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4541 env->Global()->Set(v8_str("undetectable"), obj);
4543 ExpectString("undetectable.toString()", "[object Object]");
4544 ExpectString("typeof undetectable", "undefined");
4545 ExpectString("typeof(undetectable)", "undefined");
4546 ExpectBoolean("typeof undetectable == 'undefined'", true);
4547 ExpectBoolean("typeof undetectable == 'object'", false);
4548 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4549 ExpectBoolean("!undetectable", true);
4551 ExpectObject("true&&undetectable", obj);
4552 ExpectBoolean("false&&undetectable", false);
4553 ExpectBoolean("true||undetectable", true);
4554 ExpectObject("false||undetectable", obj);
4556 ExpectObject("undetectable&&true", obj);
4557 ExpectObject("undetectable&&false", obj);
4558 ExpectBoolean("undetectable||true", true);
4559 ExpectBoolean("undetectable||false", false);
4561 ExpectBoolean("undetectable==null", true);
4562 ExpectBoolean("null==undetectable", true);
4563 ExpectBoolean("undetectable==undefined", true);
4564 ExpectBoolean("undefined==undetectable", true);
4565 ExpectBoolean("undetectable==undetectable", true);
4568 ExpectBoolean("undetectable===null", false);
4569 ExpectBoolean("null===undetectable", false);
4570 ExpectBoolean("undetectable===undefined", false);
4571 ExpectBoolean("undefined===undetectable", false);
4572 ExpectBoolean("undetectable===undetectable", true);
4576 THREADED_TEST(VoidLiteral) {
4577 v8::HandleScope scope;
4580 Local<v8::FunctionTemplate> desc =
4581 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4582 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4584 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4585 env->Global()->Set(v8_str("undetectable"), obj);
4587 ExpectBoolean("undefined == void 0", true);
4588 ExpectBoolean("undetectable == void 0", true);
4589 ExpectBoolean("null == void 0", true);
4590 ExpectBoolean("undefined === void 0", true);
4591 ExpectBoolean("undetectable === void 0", false);
4592 ExpectBoolean("null === void 0", false);
4594 ExpectBoolean("void 0 == undefined", true);
4595 ExpectBoolean("void 0 == undetectable", true);
4596 ExpectBoolean("void 0 == null", true);
4597 ExpectBoolean("void 0 === undefined", true);
4598 ExpectBoolean("void 0 === undetectable", false);
4599 ExpectBoolean("void 0 === null", false);
4601 ExpectString("(function() {"
4603 " return x === void 0;"
4605 " return e.toString();"
4608 "ReferenceError: x is not defined");
4609 ExpectString("(function() {"
4611 " return void 0 === x;"
4613 " return e.toString();"
4616 "ReferenceError: x is not defined");
4620 THREADED_TEST(ExtensibleOnUndetectable) {
4621 v8::HandleScope scope;
4624 Local<v8::FunctionTemplate> desc =
4625 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4626 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4628 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4629 env->Global()->Set(v8_str("undetectable"), obj);
4631 Local<String> source = v8_str("undetectable.x = 42;"
4634 Local<Script> script = Script::Compile(source);
4636 CHECK_EQ(v8::Integer::New(42), script->Run());
4638 ExpectBoolean("Object.isExtensible(undetectable)", true);
4640 source = v8_str("Object.preventExtensions(undetectable);");
4641 script = Script::Compile(source);
4643 ExpectBoolean("Object.isExtensible(undetectable)", false);
4645 source = v8_str("undetectable.y = 2000;");
4646 script = Script::Compile(source);
4648 ExpectBoolean("undetectable.y == undefined", true);
4653 THREADED_TEST(UndetectableString) {
4654 v8::HandleScope scope;
4657 Local<String> obj = String::NewUndetectable("foo");
4658 env->Global()->Set(v8_str("undetectable"), obj);
4660 ExpectString("undetectable", "foo");
4661 ExpectString("typeof undetectable", "undefined");
4662 ExpectString("typeof(undetectable)", "undefined");
4663 ExpectBoolean("typeof undetectable == 'undefined'", true);
4664 ExpectBoolean("typeof undetectable == 'string'", false);
4665 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4666 ExpectBoolean("!undetectable", true);
4668 ExpectObject("true&&undetectable", obj);
4669 ExpectBoolean("false&&undetectable", false);
4670 ExpectBoolean("true||undetectable", true);
4671 ExpectObject("false||undetectable", obj);
4673 ExpectObject("undetectable&&true", obj);
4674 ExpectObject("undetectable&&false", obj);
4675 ExpectBoolean("undetectable||true", true);
4676 ExpectBoolean("undetectable||false", false);
4678 ExpectBoolean("undetectable==null", true);
4679 ExpectBoolean("null==undetectable", true);
4680 ExpectBoolean("undetectable==undefined", true);
4681 ExpectBoolean("undefined==undetectable", true);
4682 ExpectBoolean("undetectable==undetectable", true);
4685 ExpectBoolean("undetectable===null", false);
4686 ExpectBoolean("null===undetectable", false);
4687 ExpectBoolean("undetectable===undefined", false);
4688 ExpectBoolean("undefined===undetectable", false);
4689 ExpectBoolean("undetectable===undetectable", true);
4693 TEST(UndetectableOptimized) {
4694 i::FLAG_allow_natives_syntax = true;
4695 v8::HandleScope scope;
4698 Local<String> obj = String::NewUndetectable("foo");
4699 env->Global()->Set(v8_str("undetectable"), obj);
4700 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4703 "function testBranch() {"
4704 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4705 " if (%_IsUndetectableObject(detectable)) throw 2;"
4707 "function testBool() {"
4708 " var b1 = !%_IsUndetectableObject(undetectable);"
4709 " var b2 = %_IsUndetectableObject(detectable);"
4714 "%OptimizeFunctionOnNextCall(testBranch);"
4715 "%OptimizeFunctionOnNextCall(testBool);"
4716 "for (var i = 0; i < 10; i++) {"
4725 template <typename T> static void USE(T) { }
4728 // This test is not intended to be run, just type checked.
4729 static inline void PersistentHandles() {
4730 USE(PersistentHandles);
4731 Local<String> str = v8_str("foo");
4732 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4734 Local<Script> scr = Script::Compile(v8_str(""));
4735 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4737 Local<ObjectTemplate> templ = ObjectTemplate::New();
4738 v8::Persistent<ObjectTemplate> p_templ =
4739 v8::Persistent<ObjectTemplate>::New(templ);
4744 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4745 ApiTestFuzzer::Fuzz();
4746 return v8::Undefined();
4750 THREADED_TEST(GlobalObjectTemplate) {
4751 v8::HandleScope handle_scope;
4752 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4753 global_template->Set(v8_str("JSNI_Log"),
4754 v8::FunctionTemplate::New(HandleLogDelegator));
4755 v8::Persistent<Context> context = Context::New(0, global_template);
4756 Context::Scope context_scope(context);
4757 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4762 static const char* kSimpleExtensionSource =
4768 THREADED_TEST(SimpleExtensions) {
4769 v8::HandleScope handle_scope;
4770 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4771 const char* extension_names[] = { "simpletest" };
4772 v8::ExtensionConfiguration extensions(1, extension_names);
4773 v8::Handle<Context> context = Context::New(&extensions);
4774 Context::Scope lock(context);
4775 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4776 CHECK_EQ(result, v8::Integer::New(4));
4780 THREADED_TEST(NullExtensions) {
4781 v8::HandleScope handle_scope;
4782 v8::RegisterExtension(new Extension("nulltest", NULL));
4783 const char* extension_names[] = { "nulltest" };
4784 v8::ExtensionConfiguration extensions(1, extension_names);
4785 v8::Handle<Context> context = Context::New(&extensions);
4786 Context::Scope lock(context);
4787 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
4788 CHECK_EQ(result, v8::Integer::New(4));
4792 static const char* kEmbeddedExtensionSource =
4793 "function Ret54321(){return 54321;}~~@@$"
4794 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4795 static const int kEmbeddedExtensionSourceValidLen = 34;
4798 THREADED_TEST(ExtensionMissingSourceLength) {
4799 v8::HandleScope handle_scope;
4800 v8::RegisterExtension(new Extension("srclentest_fail",
4801 kEmbeddedExtensionSource));
4802 const char* extension_names[] = { "srclentest_fail" };
4803 v8::ExtensionConfiguration extensions(1, extension_names);
4804 v8::Handle<Context> context = Context::New(&extensions);
4805 CHECK_EQ(0, *context);
4809 THREADED_TEST(ExtensionWithSourceLength) {
4810 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4811 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4812 v8::HandleScope handle_scope;
4813 i::ScopedVector<char> extension_name(32);
4814 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4815 v8::RegisterExtension(new Extension(extension_name.start(),
4816 kEmbeddedExtensionSource, 0, 0,
4818 const char* extension_names[1] = { extension_name.start() };
4819 v8::ExtensionConfiguration extensions(1, extension_names);
4820 v8::Handle<Context> context = Context::New(&extensions);
4821 if (source_len == kEmbeddedExtensionSourceValidLen) {
4822 Context::Scope lock(context);
4823 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4824 CHECK_EQ(v8::Integer::New(54321), result);
4826 // Anything but exactly the right length should fail to compile.
4827 CHECK_EQ(0, *context);
4833 static const char* kEvalExtensionSource1 =
4834 "function UseEval1() {"
4836 " return eval('x');"
4840 static const char* kEvalExtensionSource2 =
4844 " return eval('x');"
4846 " this.UseEval2 = e;"
4850 THREADED_TEST(UseEvalFromExtension) {
4851 v8::HandleScope handle_scope;
4852 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4853 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4854 const char* extension_names[] = { "evaltest1", "evaltest2" };
4855 v8::ExtensionConfiguration extensions(2, extension_names);
4856 v8::Handle<Context> context = Context::New(&extensions);
4857 Context::Scope lock(context);
4858 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4859 CHECK_EQ(result, v8::Integer::New(42));
4860 result = Script::Compile(v8_str("UseEval2()"))->Run();
4861 CHECK_EQ(result, v8::Integer::New(42));
4865 static const char* kWithExtensionSource1 =
4866 "function UseWith1() {"
4868 " with({x:87}) { return x; }"
4873 static const char* kWithExtensionSource2 =
4877 " with ({x:87}) { return x; }"
4879 " this.UseWith2 = e;"
4883 THREADED_TEST(UseWithFromExtension) {
4884 v8::HandleScope handle_scope;
4885 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4886 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4887 const char* extension_names[] = { "withtest1", "withtest2" };
4888 v8::ExtensionConfiguration extensions(2, extension_names);
4889 v8::Handle<Context> context = Context::New(&extensions);
4890 Context::Scope lock(context);
4891 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4892 CHECK_EQ(result, v8::Integer::New(87));
4893 result = Script::Compile(v8_str("UseWith2()"))->Run();
4894 CHECK_EQ(result, v8::Integer::New(87));
4898 THREADED_TEST(AutoExtensions) {
4899 v8::HandleScope handle_scope;
4900 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4901 extension->set_auto_enable(true);
4902 v8::RegisterExtension(extension);
4903 v8::Handle<Context> context = Context::New();
4904 Context::Scope lock(context);
4905 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4906 CHECK_EQ(result, v8::Integer::New(4));
4910 static const char* kSyntaxErrorInExtensionSource =
4914 // Test that a syntax error in an extension does not cause a fatal
4915 // error but results in an empty context.
4916 THREADED_TEST(SyntaxErrorExtensions) {
4917 v8::HandleScope handle_scope;
4918 v8::RegisterExtension(new Extension("syntaxerror",
4919 kSyntaxErrorInExtensionSource));
4920 const char* extension_names[] = { "syntaxerror" };
4921 v8::ExtensionConfiguration extensions(1, extension_names);
4922 v8::Handle<Context> context = Context::New(&extensions);
4923 CHECK(context.IsEmpty());
4927 static const char* kExceptionInExtensionSource =
4931 // Test that an exception when installing an extension does not cause
4932 // a fatal error but results in an empty context.
4933 THREADED_TEST(ExceptionExtensions) {
4934 v8::HandleScope handle_scope;
4935 v8::RegisterExtension(new Extension("exception",
4936 kExceptionInExtensionSource));
4937 const char* extension_names[] = { "exception" };
4938 v8::ExtensionConfiguration extensions(1, extension_names);
4939 v8::Handle<Context> context = Context::New(&extensions);
4940 CHECK(context.IsEmpty());
4944 static const char* kNativeCallInExtensionSource =
4945 "function call_runtime_last_index_of(x) {"
4946 " return %StringLastIndexOf(x, 'bob', 10);"
4950 static const char* kNativeCallTest =
4951 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4953 // Test that a native runtime calls are supported in extensions.
4954 THREADED_TEST(NativeCallInExtensions) {
4955 v8::HandleScope handle_scope;
4956 v8::RegisterExtension(new Extension("nativecall",
4957 kNativeCallInExtensionSource));
4958 const char* extension_names[] = { "nativecall" };
4959 v8::ExtensionConfiguration extensions(1, extension_names);
4960 v8::Handle<Context> context = Context::New(&extensions);
4961 Context::Scope lock(context);
4962 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4963 CHECK_EQ(result, v8::Integer::New(3));
4967 class NativeFunctionExtension : public Extension {
4969 NativeFunctionExtension(const char* name,
4971 v8::InvocationCallback fun = &Echo)
4972 : Extension(name, source),
4975 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4976 v8::Handle<v8::String> name) {
4977 return v8::FunctionTemplate::New(function_);
4980 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4981 if (args.Length() >= 1) return (args[0]);
4982 return v8::Undefined();
4985 v8::InvocationCallback function_;
4989 THREADED_TEST(NativeFunctionDeclaration) {
4990 v8::HandleScope handle_scope;
4991 const char* name = "nativedecl";
4992 v8::RegisterExtension(new NativeFunctionExtension(name,
4993 "native function foo();"));
4994 const char* extension_names[] = { name };
4995 v8::ExtensionConfiguration extensions(1, extension_names);
4996 v8::Handle<Context> context = Context::New(&extensions);
4997 Context::Scope lock(context);
4998 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4999 CHECK_EQ(result, v8::Integer::New(42));
5003 THREADED_TEST(NativeFunctionDeclarationError) {
5004 v8::HandleScope handle_scope;
5005 const char* name = "nativedeclerr";
5006 // Syntax error in extension code.
5007 v8::RegisterExtension(new NativeFunctionExtension(name,
5008 "native\nfunction foo();"));
5009 const char* extension_names[] = { name };
5010 v8::ExtensionConfiguration extensions(1, extension_names);
5011 v8::Handle<Context> context(Context::New(&extensions));
5012 CHECK(context.IsEmpty());
5016 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5017 v8::HandleScope handle_scope;
5018 const char* name = "nativedeclerresc";
5019 // Syntax error in extension code - escape code in "native" means that
5020 // it's not treated as a keyword.
5021 v8::RegisterExtension(new NativeFunctionExtension(
5023 "nativ\\u0065 function foo();"));
5024 const char* extension_names[] = { name };
5025 v8::ExtensionConfiguration extensions(1, extension_names);
5026 v8::Handle<Context> context(Context::New(&extensions));
5027 CHECK(context.IsEmpty());
5031 static void CheckDependencies(const char* name, const char* expected) {
5032 v8::HandleScope handle_scope;
5033 v8::ExtensionConfiguration config(1, &name);
5034 LocalContext context(&config);
5035 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5046 THREADED_TEST(ExtensionDependency) {
5047 static const char* kEDeps[] = { "D" };
5048 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5049 static const char* kDDeps[] = { "B", "C" };
5050 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5051 static const char* kBCDeps[] = { "A" };
5052 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5053 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5054 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5055 CheckDependencies("A", "undefinedA");
5056 CheckDependencies("B", "undefinedAB");
5057 CheckDependencies("C", "undefinedAC");
5058 CheckDependencies("D", "undefinedABCD");
5059 CheckDependencies("E", "undefinedABCDE");
5060 v8::HandleScope handle_scope;
5061 static const char* exts[2] = { "C", "E" };
5062 v8::ExtensionConfiguration config(2, exts);
5063 LocalContext context(&config);
5064 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5068 static const char* kExtensionTestScript =
5069 "native function A();"
5070 "native function B();"
5071 "native function C();"
5073 " if (i == 0) return A();"
5074 " if (i == 1) return B();"
5075 " if (i == 2) return C();"
5079 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5080 ApiTestFuzzer::Fuzz();
5081 if (args.IsConstructCall()) {
5082 args.This()->Set(v8_str("data"), args.Data());
5089 class FunctionExtension : public Extension {
5091 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5092 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5093 v8::Handle<String> name);
5097 static int lookup_count = 0;
5098 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5099 v8::Handle<String> name) {
5101 if (name->Equals(v8_str("A"))) {
5102 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5103 } else if (name->Equals(v8_str("B"))) {
5104 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5105 } else if (name->Equals(v8_str("C"))) {
5106 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5108 return v8::Handle<v8::FunctionTemplate>();
5113 THREADED_TEST(FunctionLookup) {
5114 v8::RegisterExtension(new FunctionExtension());
5115 v8::HandleScope handle_scope;
5116 static const char* exts[1] = { "functiontest" };
5117 v8::ExtensionConfiguration config(1, exts);
5118 LocalContext context(&config);
5119 CHECK_EQ(3, lookup_count);
5120 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5121 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5122 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5126 THREADED_TEST(NativeFunctionConstructCall) {
5127 v8::RegisterExtension(new FunctionExtension());
5128 v8::HandleScope handle_scope;
5129 static const char* exts[1] = { "functiontest" };
5130 v8::ExtensionConfiguration config(1, exts);
5131 LocalContext context(&config);
5132 for (int i = 0; i < 10; i++) {
5133 // Run a few times to ensure that allocation of objects doesn't
5134 // change behavior of a constructor function.
5135 CHECK_EQ(v8::Integer::New(8),
5136 Script::Compile(v8_str("(new A()).data"))->Run());
5137 CHECK_EQ(v8::Integer::New(7),
5138 Script::Compile(v8_str("(new B()).data"))->Run());
5139 CHECK_EQ(v8::Integer::New(6),
5140 Script::Compile(v8_str("(new C()).data"))->Run());
5145 static const char* last_location;
5146 static const char* last_message;
5147 void StoringErrorCallback(const char* location, const char* message) {
5148 if (last_location == NULL) {
5149 last_location = location;
5150 last_message = message;
5155 // ErrorReporting creates a circular extensions configuration and
5156 // tests that the fatal error handler gets called. This renders V8
5157 // unusable and therefore this test cannot be run in parallel.
5158 TEST(ErrorReporting) {
5159 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5160 static const char* aDeps[] = { "B" };
5161 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5162 static const char* bDeps[] = { "A" };
5163 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5164 last_location = NULL;
5165 v8::ExtensionConfiguration config(1, bDeps);
5166 v8::Handle<Context> context = Context::New(&config);
5167 CHECK(context.IsEmpty());
5168 CHECK_NE(last_location, NULL);
5172 static const char* js_code_causing_huge_string_flattening =
5174 "for (var i = 0; i < 30; i++) {"
5180 void OOMCallback(const char* location, const char* message) {
5185 TEST(RegexpOutOfMemory) {
5186 // Execute a script that causes out of memory when flattening a string.
5187 v8::HandleScope scope;
5188 v8::V8::SetFatalErrorHandler(OOMCallback);
5189 LocalContext context;
5190 Local<Script> script =
5191 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5192 last_location = NULL;
5195 CHECK(false); // Should not return.
5199 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5200 v8::Handle<Value> data) {
5201 CHECK(message->GetScriptResourceName()->IsUndefined());
5202 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
5203 message->GetLineNumber();
5204 message->GetSourceLine();
5208 THREADED_TEST(ErrorWithMissingScriptInfo) {
5209 v8::HandleScope scope;
5210 LocalContext context;
5211 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5212 Script::Compile(v8_str("throw Error()"))->Run();
5213 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5217 int global_index = 0;
5221 Snorkel() { index_ = global_index++; }
5233 v8::Handle<Script> getScript() {
5234 if (script_.IsEmpty())
5235 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5236 return Local<Script>(*script_);
5240 static const int kObjectCount = 256;
5242 v8::Persistent<v8::Object> objects_[kObjectCount];
5243 v8::Persistent<Script> script_;
5246 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
5247 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5252 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5253 const AccessorInfo& info) {
5255 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5257 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5259 v8::Handle<v8::Object> obj = v8::Object::New();
5260 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5261 if (!prev.IsEmpty()) {
5262 prev->Set(v8_str("next"), obj);
5263 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5264 whammy->objects_[whammy->cursor_].Clear();
5266 whammy->objects_[whammy->cursor_] = global;
5267 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5268 return whammy->getScript()->Run();
5271 THREADED_TEST(WeakReference) {
5272 v8::HandleScope handle_scope;
5273 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
5274 Whammy* whammy = new Whammy();
5275 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5277 v8::External::New(whammy));
5278 const char* extension_list[] = { "v8/gc" };
5279 v8::ExtensionConfiguration extensions(1, extension_list);
5280 v8::Persistent<Context> context = Context::New(&extensions);
5281 Context::Scope context_scope(context);
5283 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5284 context->Global()->Set(v8_str("whammy"), interceptor);
5287 "for (var i = 0; i < 10000; i++) {"
5288 " var obj = whammy.length;"
5289 " if (last) last.next = obj;"
5294 v8::Handle<Value> result = CompileRun(code);
5295 CHECK_EQ(4.0, result->NumberValue());
5301 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5304 *(reinterpret_cast<bool*>(data)) = true;
5308 THREADED_TEST(IndependentWeakHandle) {
5309 v8::Persistent<Context> context = Context::New();
5310 Context::Scope context_scope(context);
5312 v8::Persistent<v8::Object> object_a;
5315 v8::HandleScope handle_scope;
5316 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5319 bool object_a_disposed = false;
5320 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5321 CHECK(!object_a.IsIndependent());
5322 object_a.MarkIndependent();
5323 CHECK(object_a.IsIndependent());
5324 HEAP->PerformScavenge();
5325 CHECK(object_a_disposed);
5329 static void InvokeScavenge() {
5330 HEAP->PerformScavenge();
5334 static void InvokeMarkSweep() {
5335 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5339 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5342 *(reinterpret_cast<bool*>(data)) = true;
5347 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5350 *(reinterpret_cast<bool*>(data)) = true;
5355 THREADED_TEST(GCFromWeakCallbacks) {
5356 v8::Persistent<Context> context = Context::New();
5357 Context::Scope context_scope(context);
5359 static const int kNumberOfGCTypes = 2;
5360 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5361 {&ForceScavenge, &ForceMarkSweep};
5363 typedef void (*GCInvoker)();
5364 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5366 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5367 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5368 v8::Persistent<v8::Object> object;
5370 v8::HandleScope handle_scope;
5371 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5373 bool disposed = false;
5374 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5375 object.MarkIndependent();
5376 invoke_gc[outer_gc]();
5383 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5385 *(reinterpret_cast<bool*>(data)) = true;
5389 THREADED_TEST(IndependentHandleRevival) {
5390 v8::Persistent<Context> context = Context::New();
5391 Context::Scope context_scope(context);
5393 v8::Persistent<v8::Object> object;
5395 v8::HandleScope handle_scope;
5396 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5397 object->Set(v8_str("x"), v8::Integer::New(1));
5398 v8::Local<String> y_str = v8_str("y");
5399 object->Set(y_str, y_str);
5401 bool revived = false;
5402 object.MakeWeak(&revived, &RevivingCallback);
5403 object.MarkIndependent();
5404 HEAP->PerformScavenge();
5406 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
5408 v8::HandleScope handle_scope;
5409 v8::Local<String> y_str = v8_str("y");
5410 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5411 CHECK(object->Get(y_str)->Equals(y_str));
5416 v8::Handle<Function> args_fun;
5419 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5420 ApiTestFuzzer::Fuzz();
5421 CHECK_EQ(args_fun, args.Callee());
5422 CHECK_EQ(3, args.Length());
5423 CHECK_EQ(v8::Integer::New(1), args[0]);
5424 CHECK_EQ(v8::Integer::New(2), args[1]);
5425 CHECK_EQ(v8::Integer::New(3), args[2]);
5426 CHECK_EQ(v8::Undefined(), args[3]);
5427 v8::HandleScope scope;
5428 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5429 return v8::Undefined();
5433 THREADED_TEST(Arguments) {
5434 v8::HandleScope scope;
5435 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5436 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5437 LocalContext context(NULL, global);
5438 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5439 v8_compile("f(1, 2, 3)")->Run();
5443 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5444 const AccessorInfo&) {
5445 return v8::Handle<Value>();
5449 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5450 const AccessorInfo&) {
5451 return v8::Handle<Value>();
5455 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5456 const AccessorInfo&) {
5457 if (!name->Equals(v8_str("foo"))) {
5458 return v8::Handle<v8::Boolean>(); // not intercepted
5461 return v8::False(); // intercepted, and don't delete the property
5465 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5467 return v8::Handle<v8::Boolean>(); // not intercepted
5470 return v8::False(); // intercepted, and don't delete the property
5474 THREADED_TEST(Deleter) {
5475 v8::HandleScope scope;
5476 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5477 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5478 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5479 LocalContext context;
5480 context->Global()->Set(v8_str("k"), obj->NewInstance());
5486 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5487 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5489 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5490 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5492 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5493 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5495 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5496 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5500 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5501 ApiTestFuzzer::Fuzz();
5502 if (name->Equals(v8_str("foo")) ||
5503 name->Equals(v8_str("bar")) ||
5504 name->Equals(v8_str("baz"))) {
5505 return v8::Undefined();
5507 return v8::Handle<Value>();
5511 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5512 ApiTestFuzzer::Fuzz();
5513 if (index == 0 || index == 1) return v8::Undefined();
5514 return v8::Handle<Value>();
5518 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5519 ApiTestFuzzer::Fuzz();
5520 v8::Handle<v8::Array> result = v8::Array::New(3);
5521 result->Set(v8::Integer::New(0), v8_str("foo"));
5522 result->Set(v8::Integer::New(1), v8_str("bar"));
5523 result->Set(v8::Integer::New(2), v8_str("baz"));
5528 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5529 ApiTestFuzzer::Fuzz();
5530 v8::Handle<v8::Array> result = v8::Array::New(2);
5531 result->Set(v8::Integer::New(0), v8_str("0"));
5532 result->Set(v8::Integer::New(1), v8_str("1"));
5537 THREADED_TEST(Enumerators) {
5538 v8::HandleScope scope;
5539 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5540 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5541 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5542 LocalContext context;
5543 context->Global()->Set(v8_str("k"), obj->NewInstance());
5544 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5549 "k[4294967295] = 0;"
5551 "k[4294967296] = 0;"
5555 "k[30000000000] = 0;"
5558 "for (var prop in k) {"
5559 " result.push(prop);"
5562 // Check that we get all the property names returned including the
5563 // ones from the enumerators in the right order: indexed properties
5564 // in numerical order, indexed interceptor properties, named
5565 // properties in insertion order, named interceptor properties.
5566 // This order is not mandated by the spec, so this test is just
5567 // documenting our behavior.
5568 CHECK_EQ(17, result->Length());
5569 // Indexed properties in numerical order.
5570 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5571 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5572 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5573 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5574 // Indexed interceptor properties in the order they are returned
5575 // from the enumerator interceptor.
5576 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5577 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5578 // Named properties in insertion order.
5579 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5580 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5581 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5582 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5583 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5584 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5585 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5586 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5587 // Named interceptor properties.
5588 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5589 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5590 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5595 int p_getter_count2;
5598 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5599 ApiTestFuzzer::Fuzz();
5601 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5602 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5603 if (name->Equals(v8_str("p1"))) {
5604 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5605 } else if (name->Equals(v8_str("p2"))) {
5606 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5607 } else if (name->Equals(v8_str("p3"))) {
5608 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5609 } else if (name->Equals(v8_str("p4"))) {
5610 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5612 return v8::Undefined();
5616 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5617 ApiTestFuzzer::Fuzz();
5618 LocalContext context;
5619 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5621 "o1.__proto__ = { };"
5622 "var o2 = { __proto__: o1 };"
5623 "var o3 = { __proto__: o2 };"
5624 "var o4 = { __proto__: o3 };"
5625 "for (var i = 0; i < 10; i++) o4.p4;"
5626 "for (var i = 0; i < 10; i++) o3.p3;"
5627 "for (var i = 0; i < 10; i++) o2.p2;"
5628 "for (var i = 0; i < 10; i++) o1.p1;");
5632 static v8::Handle<Value> PGetter2(Local<String> name,
5633 const AccessorInfo& info) {
5634 ApiTestFuzzer::Fuzz();
5636 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5637 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5638 if (name->Equals(v8_str("p1"))) {
5639 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5640 } else if (name->Equals(v8_str("p2"))) {
5641 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5642 } else if (name->Equals(v8_str("p3"))) {
5643 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5644 } else if (name->Equals(v8_str("p4"))) {
5645 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5647 return v8::Undefined();
5651 THREADED_TEST(GetterHolders) {
5652 v8::HandleScope scope;
5653 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5654 obj->SetAccessor(v8_str("p1"), PGetter);
5655 obj->SetAccessor(v8_str("p2"), PGetter);
5656 obj->SetAccessor(v8_str("p3"), PGetter);
5657 obj->SetAccessor(v8_str("p4"), PGetter);
5660 CHECK_EQ(40, p_getter_count);
5664 THREADED_TEST(PreInterceptorHolders) {
5665 v8::HandleScope scope;
5666 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5667 obj->SetNamedPropertyHandler(PGetter2);
5668 p_getter_count2 = 0;
5670 CHECK_EQ(40, p_getter_count2);
5674 THREADED_TEST(ObjectInstantiation) {
5675 v8::HandleScope scope;
5676 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5677 templ->SetAccessor(v8_str("t"), PGetter2);
5678 LocalContext context;
5679 context->Global()->Set(v8_str("o"), templ->NewInstance());
5680 for (int i = 0; i < 100; i++) {
5681 v8::HandleScope inner_scope;
5682 v8::Handle<v8::Object> obj = templ->NewInstance();
5683 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5684 context->Global()->Set(v8_str("o2"), obj);
5685 v8::Handle<Value> value =
5686 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5687 CHECK_EQ(v8::True(), value);
5688 context->Global()->Set(v8_str("o"), obj);
5693 static int StrCmp16(uint16_t* a, uint16_t* b) {
5695 if (*a == 0 && *b == 0) return 0;
5696 if (*a != *b) return 0 + *a - *b;
5703 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5705 if (n-- == 0) return 0;
5706 if (*a == 0 && *b == 0) return 0;
5707 if (*a != *b) return 0 + *a - *b;
5714 int GetUtf8Length(Handle<String> str) {
5715 int len = str->Utf8Length();
5717 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5718 i::FlattenString(istr);
5719 len = str->Utf8Length();
5725 THREADED_TEST(StringWrite) {
5726 LocalContext context;
5727 v8::HandleScope scope;
5728 v8::Handle<String> str = v8_str("abcde");
5729 // abc<Icelandic eth><Unicode snowman>.
5730 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5731 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
5732 const int kStride = 4; // Must match stride in for loops in JS below.
5735 "for (var i = 0; i < 0xd800; i += 4) {"
5736 " left = left + String.fromCharCode(i);"
5740 "for (var i = 0; i < 0xd800; i += 4) {"
5741 " right = String.fromCharCode(i) + right;"
5743 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5744 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5745 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5747 CHECK_EQ(5, str2->Length());
5748 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5749 CHECK_EQ(0xd800 / kStride, right_tree->Length());
5752 char utf8buf[0xd800 * 3];
5757 memset(utf8buf, 0x1, 1000);
5758 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5760 CHECK_EQ(5, charlen);
5761 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5763 memset(utf8buf, 0x1, 1000);
5764 len = str2->WriteUtf8(utf8buf, 8, &charlen);
5766 CHECK_EQ(5, charlen);
5767 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5769 memset(utf8buf, 0x1, 1000);
5770 len = str2->WriteUtf8(utf8buf, 7, &charlen);
5772 CHECK_EQ(4, charlen);
5773 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5775 memset(utf8buf, 0x1, 1000);
5776 len = str2->WriteUtf8(utf8buf, 6, &charlen);
5778 CHECK_EQ(4, charlen);
5779 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5781 memset(utf8buf, 0x1, 1000);
5782 len = str2->WriteUtf8(utf8buf, 5, &charlen);
5784 CHECK_EQ(4, charlen);
5785 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5787 memset(utf8buf, 0x1, 1000);
5788 len = str2->WriteUtf8(utf8buf, 4, &charlen);
5790 CHECK_EQ(3, charlen);
5791 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5793 memset(utf8buf, 0x1, 1000);
5794 len = str2->WriteUtf8(utf8buf, 3, &charlen);
5796 CHECK_EQ(3, charlen);
5797 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5799 memset(utf8buf, 0x1, 1000);
5800 len = str2->WriteUtf8(utf8buf, 2, &charlen);
5802 CHECK_EQ(2, charlen);
5803 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5805 memset(utf8buf, 0x1, sizeof(utf8buf));
5806 len = GetUtf8Length(left_tree);
5808 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5809 CHECK_EQ(utf8_expected, len);
5810 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5811 CHECK_EQ(utf8_expected, len);
5812 CHECK_EQ(0xd800 / kStride, charlen);
5813 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5814 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5815 CHECK_EQ(0xc0 - kStride,
5816 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5817 CHECK_EQ(1, utf8buf[utf8_expected]);
5819 memset(utf8buf, 0x1, sizeof(utf8buf));
5820 len = GetUtf8Length(right_tree);
5821 CHECK_EQ(utf8_expected, len);
5822 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5823 CHECK_EQ(utf8_expected, len);
5824 CHECK_EQ(0xd800 / kStride, charlen);
5825 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5826 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5827 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5828 CHECK_EQ(1, utf8buf[utf8_expected]);
5830 memset(buf, 0x1, sizeof(buf));
5831 memset(wbuf, 0x1, sizeof(wbuf));
5832 len = str->WriteAscii(buf);
5834 len = str->Write(wbuf);
5836 CHECK_EQ(0, strcmp("abcde", buf));
5837 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5838 CHECK_EQ(0, StrCmp16(answer1, wbuf));
5840 memset(buf, 0x1, sizeof(buf));
5841 memset(wbuf, 0x1, sizeof(wbuf));
5842 len = str->WriteAscii(buf, 0, 4);
5844 len = str->Write(wbuf, 0, 4);
5846 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5847 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5848 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5850 memset(buf, 0x1, sizeof(buf));
5851 memset(wbuf, 0x1, sizeof(wbuf));
5852 len = str->WriteAscii(buf, 0, 5);
5854 len = str->Write(wbuf, 0, 5);
5856 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5857 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5858 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5860 memset(buf, 0x1, sizeof(buf));
5861 memset(wbuf, 0x1, sizeof(wbuf));
5862 len = str->WriteAscii(buf, 0, 6);
5864 len = str->Write(wbuf, 0, 6);
5866 CHECK_EQ(0, strcmp("abcde", buf));
5867 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5868 CHECK_EQ(0, StrCmp16(answer4, wbuf));
5870 memset(buf, 0x1, sizeof(buf));
5871 memset(wbuf, 0x1, sizeof(wbuf));
5872 len = str->WriteAscii(buf, 4, -1);
5874 len = str->Write(wbuf, 4, -1);
5876 CHECK_EQ(0, strcmp("e", buf));
5877 uint16_t answer5[] = {'e', '\0'};
5878 CHECK_EQ(0, StrCmp16(answer5, wbuf));
5880 memset(buf, 0x1, sizeof(buf));
5881 memset(wbuf, 0x1, sizeof(wbuf));
5882 len = str->WriteAscii(buf, 4, 6);
5884 len = str->Write(wbuf, 4, 6);
5886 CHECK_EQ(0, strcmp("e", buf));
5887 CHECK_EQ(0, StrCmp16(answer5, wbuf));
5889 memset(buf, 0x1, sizeof(buf));
5890 memset(wbuf, 0x1, sizeof(wbuf));
5891 len = str->WriteAscii(buf, 4, 1);
5893 len = str->Write(wbuf, 4, 1);
5895 CHECK_EQ(0, strncmp("e\1", buf, 2));
5896 uint16_t answer6[] = {'e', 0x101};
5897 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5899 memset(buf, 0x1, sizeof(buf));
5900 memset(wbuf, 0x1, sizeof(wbuf));
5901 len = str->WriteAscii(buf, 3, 1);
5903 len = str->Write(wbuf, 3, 1);
5905 CHECK_EQ(0, strncmp("d\1", buf, 2));
5906 uint16_t answer7[] = {'d', 0x101};
5907 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5909 memset(wbuf, 0x1, sizeof(wbuf));
5911 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5913 CHECK_EQ('X', wbuf[5]);
5914 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5915 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5916 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5917 CHECK_NE(0, StrCmp16(answer8b, wbuf));
5919 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5921 memset(buf, 0x1, sizeof(buf));
5923 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5925 CHECK_EQ('X', buf[5]);
5926 CHECK_EQ(0, strncmp("abcde", buf, 5));
5927 CHECK_NE(0, strcmp("abcde", buf));
5929 CHECK_EQ(0, strcmp("abcde", buf));
5931 memset(utf8buf, 0x1, sizeof(utf8buf));
5933 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5934 String::NO_NULL_TERMINATION);
5936 CHECK_EQ('X', utf8buf[8]);
5937 CHECK_EQ(5, charlen);
5938 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5939 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5941 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5943 memset(utf8buf, 0x1, sizeof(utf8buf));
5945 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5946 String::NO_NULL_TERMINATION);
5948 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
5949 CHECK_EQ(5, charlen);
5951 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
5953 memset(buf, 0x1, sizeof(buf));
5954 len = str3->WriteAscii(buf);
5956 CHECK_EQ(0, strcmp("abc def", buf));
5958 memset(buf, 0x1, sizeof(buf));
5959 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
5961 CHECK_EQ(0, strcmp("abc", buf));
5962 CHECK_EQ(0, buf[3]);
5963 CHECK_EQ(0, strcmp("def", buf + 4));
5967 static void Utf16Helper(
5968 LocalContext& context,
5970 const char* lengths_name,
5972 Local<v8::Array> a =
5973 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
5974 Local<v8::Array> alens =
5975 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
5976 for (int i = 0; i < len; i++) {
5977 Local<v8::String> string =
5978 Local<v8::String>::Cast(a->Get(i));
5979 Local<v8::Number> expected_len =
5980 Local<v8::Number>::Cast(alens->Get(i));
5981 CHECK_EQ(expected_len->Value() != string->Length(),
5982 string->MayContainNonAscii());
5983 int length = GetUtf8Length(string);
5984 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
5989 static uint16_t StringGet(Handle<String> str, int index) {
5990 i::Handle<i::String> istring =
5991 v8::Utils::OpenHandle(String::Cast(*str));
5992 return istring->Get(index);
5996 static void WriteUtf8Helper(
5997 LocalContext& context,
5999 const char* lengths_name,
6001 Local<v8::Array> b =
6002 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6003 Local<v8::Array> alens =
6004 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6007 for (int i = 0; i < len; i++) {
6008 Local<v8::String> string =
6009 Local<v8::String>::Cast(b->Get(i));
6010 Local<v8::Number> expected_len =
6011 Local<v8::Number>::Cast(alens->Get(i));
6012 int utf8_length = static_cast<int>(expected_len->Value());
6013 for (int j = utf8_length + 1; j >= 0; j--) {
6014 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6015 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6018 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6020 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6021 CHECK_GE(utf8_length + 1, utf8_written);
6022 CHECK_GE(utf8_length, utf8_written2);
6023 for (int k = 0; k < utf8_written2; k++) {
6024 CHECK_EQ(buffer[k], buffer2[k]);
6026 CHECK(nchars * 3 >= utf8_written - 1);
6027 CHECK(nchars <= utf8_written);
6028 if (j == utf8_length + 1) {
6029 CHECK_EQ(utf8_written2, utf8_length);
6030 CHECK_EQ(utf8_written2 + 1, utf8_written);
6032 CHECK_EQ(buffer[utf8_written], 42);
6033 if (j > utf8_length) {
6034 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6035 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6036 Handle<String> roundtrip = v8_str(buffer);
6037 CHECK(roundtrip->Equals(string));
6039 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6041 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6043 uint16_t trail = StringGet(string, nchars - 1);
6044 uint16_t lead = StringGet(string, nchars - 2);
6045 if (((lead & 0xfc00) == 0xd800) &&
6046 ((trail & 0xfc00) == 0xdc00)) {
6047 unsigned char u1 = buffer2[utf8_written2 - 4];
6048 unsigned char u2 = buffer2[utf8_written2 - 3];
6049 unsigned char u3 = buffer2[utf8_written2 - 2];
6050 unsigned char u4 = buffer2[utf8_written2 - 1];
6051 CHECK_EQ((u1 & 0xf8), 0xf0);
6052 CHECK_EQ((u2 & 0xc0), 0x80);
6053 CHECK_EQ((u3 & 0xc0), 0x80);
6054 CHECK_EQ((u4 & 0xc0), 0x80);
6055 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6056 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6057 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6058 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6059 CHECK_EQ((u1 & 0x3), c >> 18);
6067 THREADED_TEST(Utf16) {
6068 LocalContext context;
6069 v8::HandleScope scope;
6071 "var pad = '01234567890123456789';"
6073 "var plens = [20, 3, 3];"
6074 "p.push('01234567890123456789');"
6075 "var lead = 0xd800;"
6076 "var trail = 0xdc00;"
6077 "p.push(String.fromCharCode(0xd800));"
6078 "p.push(String.fromCharCode(0xdc00));"
6083 "for (var i = 0; i < 3; i++) {"
6084 " p[1] = String.fromCharCode(lead++);"
6085 " for (var j = 0; j < 3; j++) {"
6086 " p[2] = String.fromCharCode(trail++);"
6087 " a.push(p[i] + p[j]);"
6088 " b.push(p[i] + p[j]);"
6089 " c.push(p[i] + p[j]);"
6090 " alens.push(plens[i] + plens[j]);"
6093 "alens[5] -= 2;" // Here the surrogate pairs match up.
6098 "for (var m = 0; m < 9; m++) {"
6099 " for (var n = 0; n < 9; n++) {"
6100 " a2.push(a[m] + a[n]);"
6101 " b2.push(b[m] + b[n]);"
6102 " var newc = 'x' + c[m] + c[n] + 'y';"
6103 " c2.push(newc.substring(1, newc.length - 1));"
6104 " var utf = alens[m] + alens[n];" // And here.
6105 // The 'n's that start with 0xdc.. are 6-8
6106 // The 'm's that end with 0xd8.. are 1, 4 and 7
6107 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6108 " a2lens.push(utf);"
6111 Utf16Helper(context, "a", "alens", 9);
6112 Utf16Helper(context, "a2", "a2lens", 81);
6113 WriteUtf8Helper(context, "b", "alens", 9);
6114 WriteUtf8Helper(context, "b2", "a2lens", 81);
6115 WriteUtf8Helper(context, "c2", "a2lens", 81);
6119 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6120 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6121 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6122 return *is1 == *is2;
6126 static void SameSymbolHelper(const char* a, const char* b) {
6127 Handle<String> symbol1 = v8::String::NewSymbol(a);
6128 Handle<String> symbol2 = v8::String::NewSymbol(b);
6129 CHECK(SameSymbol(symbol1, symbol2));
6133 THREADED_TEST(Utf16Symbol) {
6134 LocalContext context;
6135 v8::HandleScope scope;
6137 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6138 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6139 CHECK(SameSymbol(symbol1, symbol2));
6141 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6142 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6143 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6144 "\360\220\220\206"); // 4 byte encoding.
6145 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6146 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6147 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6148 "x\360\220\220\206"); // 4 byte encoding.
6150 "var sym0 = 'benedictus';"
6151 "var sym0b = 'S\303\270ren';"
6152 "var sym1 = '\355\240\201\355\260\207';"
6153 "var sym2 = '\360\220\220\210';"
6154 "var sym3 = 'x\355\240\201\355\260\207';"
6155 "var sym4 = 'x\360\220\220\210';"
6156 "if (sym1.length != 2) throw sym1;"
6157 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6158 "if (sym2.length != 2) throw sym2;"
6159 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6160 "if (sym3.length != 3) throw sym3;"
6161 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6162 "if (sym4.length != 3) throw sym4;"
6163 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6164 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6165 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6166 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6167 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6168 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6169 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6170 v8::Local<v8::Object> global = context->Global();
6171 Local<Value> s0 = global->Get(v8_str("sym0"));
6172 Local<Value> s0b = global->Get(v8_str("sym0b"));
6173 Local<Value> s1 = global->Get(v8_str("sym1"));
6174 Local<Value> s2 = global->Get(v8_str("sym2"));
6175 Local<Value> s3 = global->Get(v8_str("sym3"));
6176 Local<Value> s4 = global->Get(v8_str("sym4"));
6177 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6178 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6179 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6180 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6181 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6182 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6186 THREADED_TEST(ToArrayIndex) {
6187 v8::HandleScope scope;
6188 LocalContext context;
6190 v8::Handle<String> str = v8_str("42");
6191 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6192 CHECK(!index.IsEmpty());
6193 CHECK_EQ(42.0, index->Uint32Value());
6194 str = v8_str("42asdf");
6195 index = str->ToArrayIndex();
6196 CHECK(index.IsEmpty());
6197 str = v8_str("-42");
6198 index = str->ToArrayIndex();
6199 CHECK(index.IsEmpty());
6200 str = v8_str("4294967295");
6201 index = str->ToArrayIndex();
6202 CHECK(!index.IsEmpty());
6203 CHECK_EQ(4294967295.0, index->Uint32Value());
6204 v8::Handle<v8::Number> num = v8::Number::New(1);
6205 index = num->ToArrayIndex();
6206 CHECK(!index.IsEmpty());
6207 CHECK_EQ(1.0, index->Uint32Value());
6208 num = v8::Number::New(-1);
6209 index = num->ToArrayIndex();
6210 CHECK(index.IsEmpty());
6211 v8::Handle<v8::Object> obj = v8::Object::New();
6212 index = obj->ToArrayIndex();
6213 CHECK(index.IsEmpty());
6217 THREADED_TEST(ErrorConstruction) {
6218 v8::HandleScope scope;
6219 LocalContext context;
6221 v8::Handle<String> foo = v8_str("foo");
6222 v8::Handle<String> message = v8_str("message");
6223 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6224 CHECK(range_error->IsObject());
6225 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
6226 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6227 CHECK(reference_error->IsObject());
6228 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
6229 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6230 CHECK(syntax_error->IsObject());
6231 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
6232 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6233 CHECK(type_error->IsObject());
6234 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
6235 v8::Handle<Value> error = v8::Exception::Error(foo);
6236 CHECK(error->IsObject());
6237 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
6241 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6242 ApiTestFuzzer::Fuzz();
6247 static void YSetter(Local<String> name,
6249 const AccessorInfo& info) {
6250 if (info.This()->Has(name)) {
6251 info.This()->Delete(name);
6253 info.This()->Set(name, value);
6257 THREADED_TEST(DeleteAccessor) {
6258 v8::HandleScope scope;
6259 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6260 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6261 LocalContext context;
6262 v8::Handle<v8::Object> holder = obj->NewInstance();
6263 context->Global()->Set(v8_str("holder"), holder);
6264 v8::Handle<Value> result = CompileRun(
6265 "holder.y = 11; holder.y = 12; holder.y");
6266 CHECK_EQ(12, result->Uint32Value());
6270 THREADED_TEST(TypeSwitch) {
6271 v8::HandleScope scope;
6272 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6273 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6274 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6275 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6276 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6277 LocalContext context;
6278 v8::Handle<v8::Object> obj0 = v8::Object::New();
6279 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6280 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6281 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6282 for (int i = 0; i < 10; i++) {
6283 CHECK_EQ(0, type_switch->match(obj0));
6284 CHECK_EQ(1, type_switch->match(obj1));
6285 CHECK_EQ(2, type_switch->match(obj2));
6286 CHECK_EQ(3, type_switch->match(obj3));
6287 CHECK_EQ(3, type_switch->match(obj3));
6288 CHECK_EQ(2, type_switch->match(obj2));
6289 CHECK_EQ(1, type_switch->match(obj1));
6290 CHECK_EQ(0, type_switch->match(obj0));
6295 // For use within the TestSecurityHandler() test.
6296 static bool g_security_callback_result = false;
6297 static bool NamedSecurityTestCallback(Local<v8::Object> global,
6299 v8::AccessType type,
6300 Local<Value> data) {
6301 // Always allow read access.
6302 if (type == v8::ACCESS_GET)
6305 // Sometimes allow other access.
6306 return g_security_callback_result;
6310 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6312 v8::AccessType type,
6313 Local<Value> data) {
6314 // Always allow read access.
6315 if (type == v8::ACCESS_GET)
6318 // Sometimes allow other access.
6319 return g_security_callback_result;
6323 static int trouble_nesting = 0;
6324 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6325 ApiTestFuzzer::Fuzz();
6328 // Call a JS function that throws an uncaught exception.
6329 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6330 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6331 arg_this->Get(v8_str("trouble_callee")) :
6332 arg_this->Get(v8_str("trouble_caller"));
6333 CHECK(trouble_callee->IsFunction());
6334 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6338 static int report_count = 0;
6339 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6340 v8::Handle<Value>) {
6345 // Counts uncaught exceptions, but other tests running in parallel
6346 // also have uncaught exceptions.
6347 TEST(ApiUncaughtException) {
6349 v8::HandleScope scope;
6351 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6353 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6354 v8::Local<v8::Object> global = env->Global();
6355 global->Set(v8_str("trouble"), fun->GetFunction());
6357 Script::Compile(v8_str("function trouble_callee() {"
6361 "function trouble_caller() {"
6364 Local<Value> trouble = global->Get(v8_str("trouble"));
6365 CHECK(trouble->IsFunction());
6366 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6367 CHECK(trouble_callee->IsFunction());
6368 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6369 CHECK(trouble_caller->IsFunction());
6370 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6371 CHECK_EQ(1, report_count);
6372 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6375 static const char* script_resource_name = "ExceptionInNativeScript.js";
6376 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6377 v8::Handle<Value>) {
6378 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6379 CHECK(!name_val.IsEmpty() && name_val->IsString());
6380 v8::String::AsciiValue name(message->GetScriptResourceName());
6381 CHECK_EQ(script_resource_name, *name);
6382 CHECK_EQ(3, message->GetLineNumber());
6383 v8::String::AsciiValue source_line(message->GetSourceLine());
6384 CHECK_EQ(" new o.foo();", *source_line);
6387 TEST(ExceptionInNativeScript) {
6388 v8::HandleScope scope;
6390 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6392 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6393 v8::Local<v8::Object> global = env->Global();
6394 global->Set(v8_str("trouble"), fun->GetFunction());
6396 Script::Compile(v8_str("function trouble() {\n"
6399 "};"), v8::String::New(script_resource_name))->Run();
6400 Local<Value> trouble = global->Get(v8_str("trouble"));
6401 CHECK(trouble->IsFunction());
6402 Function::Cast(*trouble)->Call(global, 0, NULL);
6403 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6407 TEST(CompilationErrorUsingTryCatchHandler) {
6408 v8::HandleScope scope;
6410 v8::TryCatch try_catch;
6411 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6412 CHECK_NE(NULL, *try_catch.Exception());
6413 CHECK(try_catch.HasCaught());
6417 TEST(TryCatchFinallyUsingTryCatchHandler) {
6418 v8::HandleScope scope;
6420 v8::TryCatch try_catch;
6421 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6422 CHECK(!try_catch.HasCaught());
6423 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6424 CHECK(try_catch.HasCaught());
6426 Script::Compile(v8_str("(function() {"
6427 "try { throw ''; } finally { return; }"
6429 CHECK(!try_catch.HasCaught());
6430 Script::Compile(v8_str("(function()"
6431 " { try { throw ''; } finally { throw 0; }"
6433 CHECK(try_catch.HasCaught());
6437 // SecurityHandler can't be run twice
6438 TEST(SecurityHandler) {
6439 v8::HandleScope scope0;
6440 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6441 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6442 IndexedSecurityTestCallback);
6443 // Create an environment
6444 v8::Persistent<Context> context0 =
6445 Context::New(NULL, global_template);
6448 v8::Handle<v8::Object> global0 = context0->Global();
6449 v8::Handle<Script> script0 = v8_compile("foo = 111");
6451 global0->Set(v8_str("0"), v8_num(999));
6452 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6453 CHECK_EQ(111, foo0->Int32Value());
6454 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6455 CHECK_EQ(999, z0->Int32Value());
6457 // Create another environment, should fail security checks.
6458 v8::HandleScope scope1;
6460 v8::Persistent<Context> context1 =
6461 Context::New(NULL, global_template);
6464 v8::Handle<v8::Object> global1 = context1->Global();
6465 global1->Set(v8_str("othercontext"), global0);
6466 // This set will fail the security check.
6467 v8::Handle<Script> script1 =
6468 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6470 // This read will pass the security check.
6471 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6472 CHECK_EQ(111, foo1->Int32Value());
6473 // This read will pass the security check.
6474 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6475 CHECK_EQ(999, z1->Int32Value());
6477 // Create another environment, should pass security checks.
6478 { g_security_callback_result = true; // allow security handler to pass.
6479 v8::HandleScope scope2;
6480 LocalContext context2;
6481 v8::Handle<v8::Object> global2 = context2->Global();
6482 global2->Set(v8_str("othercontext"), global0);
6483 v8::Handle<Script> script2 =
6484 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6486 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6487 CHECK_EQ(333, foo2->Int32Value());
6488 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6489 CHECK_EQ(888, z2->Int32Value());
6500 THREADED_TEST(SecurityChecks) {
6501 v8::HandleScope handle_scope;
6503 v8::Persistent<Context> env2 = Context::New();
6505 Local<Value> foo = v8_str("foo");
6506 Local<Value> bar = v8_str("bar");
6508 // Set to the same domain.
6509 env1->SetSecurityToken(foo);
6511 // Create a function in env1.
6512 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6513 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6514 CHECK(spy->IsFunction());
6516 // Create another function accessing global objects.
6517 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
6518 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6519 CHECK(spy2->IsFunction());
6521 // Switch to env2 in the same domain and invoke spy on env2.
6523 env2->SetSecurityToken(foo);
6525 Context::Scope scope_env2(env2);
6526 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6527 CHECK(result->IsFunction());
6531 env2->SetSecurityToken(bar);
6532 Context::Scope scope_env2(env2);
6534 // Call cross_domain_call, it should throw an exception
6535 v8::TryCatch try_catch;
6536 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6537 CHECK(try_catch.HasCaught());
6544 // Regression test case for issue 1183439.
6545 THREADED_TEST(SecurityChecksForPrototypeChain) {
6546 v8::HandleScope scope;
6547 LocalContext current;
6548 v8::Persistent<Context> other = Context::New();
6550 // Change context to be able to get to the Object function in the
6551 // other context without hitting the security checks.
6552 v8::Local<Value> other_object;
6553 { Context::Scope scope(other);
6554 other_object = other->Global()->Get(v8_str("Object"));
6555 other->Global()->Set(v8_num(42), v8_num(87));
6558 current->Global()->Set(v8_str("other"), other->Global());
6559 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6561 // Make sure the security check fails here and we get an undefined
6562 // result instead of getting the Object function. Repeat in a loop
6563 // to make sure to exercise the IC code.
6564 v8::Local<Script> access_other0 = v8_compile("other.Object");
6565 v8::Local<Script> access_other1 = v8_compile("other[42]");
6566 for (int i = 0; i < 5; i++) {
6567 CHECK(!access_other0->Run()->Equals(other_object));
6568 CHECK(access_other0->Run()->IsUndefined());
6569 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6570 CHECK(access_other1->Run()->IsUndefined());
6573 // Create an object that has 'other' in its prototype chain and make
6574 // sure we cannot access the Object function indirectly through
6575 // that. Repeat in a loop to make sure to exercise the IC code.
6576 v8_compile("function F() { };"
6577 "F.prototype = other;"
6578 "var f = new F();")->Run();
6579 v8::Local<Script> access_f0 = v8_compile("f.Object");
6580 v8::Local<Script> access_f1 = v8_compile("f[42]");
6581 for (int j = 0; j < 5; j++) {
6582 CHECK(!access_f0->Run()->Equals(other_object));
6583 CHECK(access_f0->Run()->IsUndefined());
6584 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6585 CHECK(access_f1->Run()->IsUndefined());
6588 // Now it gets hairy: Set the prototype for the other global object
6589 // to be the current global object. The prototype chain for 'f' now
6590 // goes through 'other' but ends up in the current global object.
6591 { Context::Scope scope(other);
6592 other->Global()->Set(v8_str("__proto__"), current->Global());
6594 // Set a named and an index property on the current global
6595 // object. To force the lookup to go through the other global object,
6596 // the properties must not exist in the other global object.
6597 current->Global()->Set(v8_str("foo"), v8_num(100));
6598 current->Global()->Set(v8_num(99), v8_num(101));
6599 // Try to read the properties from f and make sure that the access
6600 // gets stopped by the security checks on the other global object.
6601 Local<Script> access_f2 = v8_compile("f.foo");
6602 Local<Script> access_f3 = v8_compile("f[99]");
6603 for (int k = 0; k < 5; k++) {
6604 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6605 CHECK(access_f2->Run()->IsUndefined());
6606 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6607 CHECK(access_f3->Run()->IsUndefined());
6613 THREADED_TEST(CrossDomainDelete) {
6614 v8::HandleScope handle_scope;
6616 v8::Persistent<Context> env2 = Context::New();
6618 Local<Value> foo = v8_str("foo");
6619 Local<Value> bar = v8_str("bar");
6621 // Set to the same domain.
6622 env1->SetSecurityToken(foo);
6623 env2->SetSecurityToken(foo);
6625 env1->Global()->Set(v8_str("prop"), v8_num(3));
6626 env2->Global()->Set(v8_str("env1"), env1->Global());
6628 // Change env2 to a different domain and delete env1.prop.
6629 env2->SetSecurityToken(bar);
6631 Context::Scope scope_env2(env2);
6632 Local<Value> result =
6633 Script::Compile(v8_str("delete env1.prop"))->Run();
6634 CHECK(result->IsFalse());
6637 // Check that env1.prop still exists.
6638 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6639 CHECK(v->IsNumber());
6640 CHECK_EQ(3, v->Int32Value());
6646 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6647 v8::HandleScope handle_scope;
6649 v8::Persistent<Context> env2 = Context::New();
6651 Local<Value> foo = v8_str("foo");
6652 Local<Value> bar = v8_str("bar");
6654 // Set to the same domain.
6655 env1->SetSecurityToken(foo);
6656 env2->SetSecurityToken(foo);
6658 env1->Global()->Set(v8_str("prop"), v8_num(3));
6659 env2->Global()->Set(v8_str("env1"), env1->Global());
6661 // env1.prop is enumerable in env2.
6662 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6664 Context::Scope scope_env2(env2);
6665 Local<Value> result = Script::Compile(test)->Run();
6666 CHECK(result->IsTrue());
6669 // Change env2 to a different domain and test again.
6670 env2->SetSecurityToken(bar);
6672 Context::Scope scope_env2(env2);
6673 Local<Value> result = Script::Compile(test)->Run();
6674 CHECK(result->IsFalse());
6681 THREADED_TEST(CrossDomainForIn) {
6682 v8::HandleScope handle_scope;
6684 v8::Persistent<Context> env2 = Context::New();
6686 Local<Value> foo = v8_str("foo");
6687 Local<Value> bar = v8_str("bar");
6689 // Set to the same domain.
6690 env1->SetSecurityToken(foo);
6691 env2->SetSecurityToken(foo);
6693 env1->Global()->Set(v8_str("prop"), v8_num(3));
6694 env2->Global()->Set(v8_str("env1"), env1->Global());
6696 // Change env2 to a different domain and set env1's global object
6697 // as the __proto__ of an object in env2 and enumerate properties
6698 // in for-in. It shouldn't enumerate properties on env1's global
6700 env2->SetSecurityToken(bar);
6702 Context::Scope scope_env2(env2);
6703 Local<Value> result =
6704 CompileRun("(function(){var obj = {'__proto__':env1};"
6705 "for (var p in obj)"
6706 " if (p == 'prop') return false;"
6707 "return true;})()");
6708 CHECK(result->IsTrue());
6714 TEST(ContextDetachGlobal) {
6715 v8::HandleScope handle_scope;
6717 v8::Persistent<Context> env2 = Context::New();
6719 Local<v8::Object> global1 = env1->Global();
6721 Local<Value> foo = v8_str("foo");
6723 // Set to the same domain.
6724 env1->SetSecurityToken(foo);
6725 env2->SetSecurityToken(foo);
6730 // Create a function in env2 and add a reference to it in env1.
6731 Local<v8::Object> global2 = env2->Global();
6732 global2->Set(v8_str("prop"), v8::Integer::New(1));
6733 CompileRun("function getProp() {return prop;}");
6735 env1->Global()->Set(v8_str("getProp"),
6736 global2->Get(v8_str("getProp")));
6738 // Detach env2's global, and reuse the global object of env2
6740 env2->DetachGlobal();
6741 // env2 has a new global object.
6742 CHECK(!env2->Global()->Equals(global2));
6744 v8::Persistent<Context> env3 =
6745 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6746 env3->SetSecurityToken(v8_str("bar"));
6749 Local<v8::Object> global3 = env3->Global();
6750 CHECK_EQ(global2, global3);
6751 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6752 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6753 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6754 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6757 // Call getProp in env1, and it should return the value 1
6759 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6760 CHECK(get_prop->IsFunction());
6761 v8::TryCatch try_catch;
6762 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6763 CHECK(!try_catch.HasCaught());
6764 CHECK_EQ(1, r->Int32Value());
6767 // Check that env3 is not accessible from env1
6769 Local<Value> r = global3->Get(v8_str("prop2"));
6770 CHECK(r->IsUndefined());
6778 TEST(DetachAndReattachGlobal) {
6779 v8::HandleScope scope;
6782 // Create second environment.
6783 v8::Persistent<Context> env2 = Context::New();
6785 Local<Value> foo = v8_str("foo");
6787 // Set same security token for env1 and env2.
6788 env1->SetSecurityToken(foo);
6789 env2->SetSecurityToken(foo);
6791 // Create a property on the global object in env2.
6793 v8::Context::Scope scope(env2);
6794 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6797 // Create a reference to env2 global from env1 global.
6798 env1->Global()->Set(v8_str("other"), env2->Global());
6800 // Check that we have access to other.p in env2 from env1.
6801 Local<Value> result = CompileRun("other.p");
6802 CHECK(result->IsInt32());
6803 CHECK_EQ(42, result->Int32Value());
6805 // Hold on to global from env2 and detach global from env2.
6806 Local<v8::Object> global2 = env2->Global();
6807 env2->DetachGlobal();
6809 // Check that the global has been detached. No other.p property can
6811 result = CompileRun("other.p");
6812 CHECK(result->IsUndefined());
6814 // Reuse global2 for env3.
6815 v8::Persistent<Context> env3 =
6816 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6817 CHECK_EQ(global2, env3->Global());
6819 // Start by using the same security token for env3 as for env1 and env2.
6820 env3->SetSecurityToken(foo);
6822 // Create a property on the global object in env3.
6824 v8::Context::Scope scope(env3);
6825 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6828 // Check that other.p is now the property in env3 and that we have access.
6829 result = CompileRun("other.p");
6830 CHECK(result->IsInt32());
6831 CHECK_EQ(24, result->Int32Value());
6833 // Change security token for env3 to something different from env1 and env2.
6834 env3->SetSecurityToken(v8_str("bar"));
6836 // Check that we do not have access to other.p in env1. |other| is now
6837 // the global object for env3 which has a different security token,
6838 // so access should be blocked.
6839 result = CompileRun("other.p");
6840 CHECK(result->IsUndefined());
6842 // Detach the global for env3 and reattach it to env2.
6843 env3->DetachGlobal();
6844 env2->ReattachGlobal(global2);
6846 // Check that we have access to other.p again in env1. |other| is now
6847 // the global object for env2 which has the same security token as env1.
6848 result = CompileRun("other.p");
6849 CHECK(result->IsInt32());
6850 CHECK_EQ(42, result->Int32Value());
6857 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6858 static bool NamedAccessBlocker(Local<v8::Object> global,
6860 v8::AccessType type,
6861 Local<Value> data) {
6862 return Context::GetCurrent()->Global()->Equals(global) ||
6863 allowed_access_type[type];
6867 static bool IndexedAccessBlocker(Local<v8::Object> global,
6869 v8::AccessType type,
6870 Local<Value> data) {
6871 return Context::GetCurrent()->Global()->Equals(global) ||
6872 allowed_access_type[type];
6876 static int g_echo_value = -1;
6877 static v8::Handle<Value> EchoGetter(Local<String> name,
6878 const AccessorInfo& info) {
6879 return v8_num(g_echo_value);
6883 static void EchoSetter(Local<String> name,
6885 const AccessorInfo&) {
6886 if (value->IsNumber())
6887 g_echo_value = value->Int32Value();
6891 static v8::Handle<Value> UnreachableGetter(Local<String> name,
6892 const AccessorInfo& info) {
6893 CHECK(false); // This function should not be called..
6894 return v8::Undefined();
6898 static void UnreachableSetter(Local<String>, Local<Value>,
6899 const AccessorInfo&) {
6900 CHECK(false); // This function should nto be called.
6904 TEST(AccessControl) {
6905 v8::HandleScope handle_scope;
6906 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6908 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6909 IndexedAccessBlocker);
6911 // Add an accessor accessible by cross-domain JS code.
6912 global_template->SetAccessor(
6913 v8_str("accessible_prop"),
6914 EchoGetter, EchoSetter,
6915 v8::Handle<Value>(),
6916 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6918 // Add an accessor that is not accessible by cross-domain JS code.
6919 global_template->SetAccessor(v8_str("blocked_prop"),
6920 UnreachableGetter, UnreachableSetter,
6921 v8::Handle<Value>(),
6924 // Create an environment
6925 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6928 v8::Handle<v8::Object> global0 = context0->Global();
6930 // Define a property with JS getter and setter.
6932 "function getter() { return 'getter'; };\n"
6933 "function setter() { return 'setter'; }\n"
6934 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6936 Local<Value> getter = global0->Get(v8_str("getter"));
6937 Local<Value> setter = global0->Get(v8_str("setter"));
6939 // And define normal element.
6940 global0->Set(239, v8_str("239"));
6942 // Define an element with JS getter and setter.
6944 "function el_getter() { return 'el_getter'; };\n"
6945 "function el_setter() { return 'el_setter'; };\n"
6946 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6948 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6949 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6951 v8::HandleScope scope1;
6953 v8::Persistent<Context> context1 = Context::New();
6956 v8::Handle<v8::Object> global1 = context1->Global();
6957 global1->Set(v8_str("other"), global0);
6959 // Access blocked property.
6960 CompileRun("other.blocked_prop = 1");
6962 ExpectUndefined("other.blocked_prop");
6964 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6965 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6967 // Enable ACCESS_HAS
6968 allowed_access_type[v8::ACCESS_HAS] = true;
6969 ExpectUndefined("other.blocked_prop");
6970 // ... and now we can get the descriptor...
6972 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6973 // ... and enumerate the property.
6974 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6975 allowed_access_type[v8::ACCESS_HAS] = false;
6977 // Access blocked element.
6978 CompileRun("other[239] = 1");
6980 ExpectUndefined("other[239]");
6981 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6982 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6984 // Enable ACCESS_HAS
6985 allowed_access_type[v8::ACCESS_HAS] = true;
6986 ExpectUndefined("other[239]");
6987 // ... and now we can get the descriptor...
6988 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6989 // ... and enumerate the property.
6990 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6991 allowed_access_type[v8::ACCESS_HAS] = false;
6993 // Access a property with JS accessor.
6994 CompileRun("other.js_accessor_p = 2");
6996 ExpectUndefined("other.js_accessor_p");
6998 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7000 // Enable ACCESS_HAS.
7001 allowed_access_type[v8::ACCESS_HAS] = true;
7002 ExpectUndefined("other.js_accessor_p");
7004 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7006 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7008 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7009 allowed_access_type[v8::ACCESS_HAS] = false;
7011 // Enable both ACCESS_HAS and ACCESS_GET.
7012 allowed_access_type[v8::ACCESS_HAS] = true;
7013 allowed_access_type[v8::ACCESS_GET] = true;
7015 ExpectString("other.js_accessor_p", "getter");
7017 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7019 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7021 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7023 allowed_access_type[v8::ACCESS_GET] = false;
7024 allowed_access_type[v8::ACCESS_HAS] = false;
7026 // Enable both ACCESS_HAS and ACCESS_SET.
7027 allowed_access_type[v8::ACCESS_HAS] = true;
7028 allowed_access_type[v8::ACCESS_SET] = true;
7030 ExpectUndefined("other.js_accessor_p");
7032 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7034 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7036 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7038 allowed_access_type[v8::ACCESS_SET] = false;
7039 allowed_access_type[v8::ACCESS_HAS] = false;
7041 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7042 allowed_access_type[v8::ACCESS_HAS] = true;
7043 allowed_access_type[v8::ACCESS_GET] = true;
7044 allowed_access_type[v8::ACCESS_SET] = true;
7046 ExpectString("other.js_accessor_p", "getter");
7048 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7050 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7052 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7054 allowed_access_type[v8::ACCESS_SET] = false;
7055 allowed_access_type[v8::ACCESS_GET] = false;
7056 allowed_access_type[v8::ACCESS_HAS] = false;
7058 // Access an element with JS accessor.
7059 CompileRun("other[42] = 2");
7061 ExpectUndefined("other[42]");
7062 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7064 // Enable ACCESS_HAS.
7065 allowed_access_type[v8::ACCESS_HAS] = true;
7066 ExpectUndefined("other[42]");
7067 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7068 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7069 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7070 allowed_access_type[v8::ACCESS_HAS] = false;
7072 // Enable both ACCESS_HAS and ACCESS_GET.
7073 allowed_access_type[v8::ACCESS_HAS] = true;
7074 allowed_access_type[v8::ACCESS_GET] = true;
7076 ExpectString("other[42]", "el_getter");
7077 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7078 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7079 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7081 allowed_access_type[v8::ACCESS_GET] = false;
7082 allowed_access_type[v8::ACCESS_HAS] = false;
7084 // Enable both ACCESS_HAS and ACCESS_SET.
7085 allowed_access_type[v8::ACCESS_HAS] = true;
7086 allowed_access_type[v8::ACCESS_SET] = true;
7088 ExpectUndefined("other[42]");
7089 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7090 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7091 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7093 allowed_access_type[v8::ACCESS_SET] = false;
7094 allowed_access_type[v8::ACCESS_HAS] = false;
7096 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7097 allowed_access_type[v8::ACCESS_HAS] = true;
7098 allowed_access_type[v8::ACCESS_GET] = true;
7099 allowed_access_type[v8::ACCESS_SET] = true;
7101 ExpectString("other[42]", "el_getter");
7102 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7103 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7104 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7106 allowed_access_type[v8::ACCESS_SET] = false;
7107 allowed_access_type[v8::ACCESS_GET] = false;
7108 allowed_access_type[v8::ACCESS_HAS] = false;
7110 v8::Handle<Value> value;
7112 // Access accessible property
7113 value = CompileRun("other.accessible_prop = 3");
7114 CHECK(value->IsNumber());
7115 CHECK_EQ(3, value->Int32Value());
7116 CHECK_EQ(3, g_echo_value);
7118 value = CompileRun("other.accessible_prop");
7119 CHECK(value->IsNumber());
7120 CHECK_EQ(3, value->Int32Value());
7123 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7124 CHECK(value->IsNumber());
7125 CHECK_EQ(3, value->Int32Value());
7127 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
7128 CHECK(value->IsTrue());
7130 // Enumeration doesn't enumerate accessors from inaccessible objects in
7131 // the prototype chain even if the accessors are in themselves accessible.
7133 CompileRun("(function(){var obj = {'__proto__':other};"
7134 "for (var p in obj)"
7135 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7138 "return true;})()");
7139 CHECK(value->IsTrue());
7148 TEST(AccessControlES5) {
7149 v8::HandleScope handle_scope;
7150 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7152 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7153 IndexedAccessBlocker);
7155 // Add accessible accessor.
7156 global_template->SetAccessor(
7157 v8_str("accessible_prop"),
7158 EchoGetter, EchoSetter,
7159 v8::Handle<Value>(),
7160 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7163 // Add an accessor that is not accessible by cross-domain JS code.
7164 global_template->SetAccessor(v8_str("blocked_prop"),
7165 UnreachableGetter, UnreachableSetter,
7166 v8::Handle<Value>(),
7169 // Create an environment
7170 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7173 v8::Handle<v8::Object> global0 = context0->Global();
7175 v8::Persistent<Context> context1 = Context::New();
7177 v8::Handle<v8::Object> global1 = context1->Global();
7178 global1->Set(v8_str("other"), global0);
7180 // Regression test for issue 1154.
7181 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
7183 ExpectUndefined("other.blocked_prop");
7185 // Regression test for issue 1027.
7186 CompileRun("Object.defineProperty(\n"
7187 " other, 'blocked_prop', {configurable: false})");
7188 ExpectUndefined("other.blocked_prop");
7190 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7192 // Regression test for issue 1171.
7193 ExpectTrue("Object.isExtensible(other)");
7194 CompileRun("Object.preventExtensions(other)");
7195 ExpectTrue("Object.isExtensible(other)");
7197 // Object.seal and Object.freeze.
7198 CompileRun("Object.freeze(other)");
7199 ExpectTrue("Object.isExtensible(other)");
7201 CompileRun("Object.seal(other)");
7202 ExpectTrue("Object.isExtensible(other)");
7204 // Regression test for issue 1250.
7205 // Make sure that we can set the accessible accessors value using normal
7207 CompileRun("other.accessible_prop = 42");
7208 CHECK_EQ(42, g_echo_value);
7210 v8::Handle<Value> value;
7211 // We follow Safari in ignoring assignments to host object accessors.
7212 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7213 value = CompileRun("other.accessible_prop == 42");
7214 CHECK(value->IsTrue());
7218 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7220 v8::AccessType type,
7221 Local<Value> data) {
7226 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7228 v8::AccessType type,
7229 Local<Value> data) {
7234 THREADED_TEST(AccessControlGetOwnPropertyNames) {
7235 v8::HandleScope handle_scope;
7236 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7238 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7239 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7240 GetOwnPropertyNamesIndexedBlocker);
7242 // Create an environment
7243 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7246 v8::Handle<v8::Object> global0 = context0->Global();
7248 v8::HandleScope scope1;
7250 v8::Persistent<Context> context1 = Context::New();
7253 v8::Handle<v8::Object> global1 = context1->Global();
7254 global1->Set(v8_str("other"), global0);
7255 global1->Set(v8_str("object"), obj_template->NewInstance());
7257 v8::Handle<Value> value;
7259 // Attempt to get the property names of the other global object and
7260 // of an object that requires access checks. Accessing the other
7261 // global object should be blocked by access checks on the global
7262 // proxy object. Accessing the object that requires access checks
7263 // is blocked by the access checks on the object itself.
7264 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7265 CHECK(value->IsTrue());
7267 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7268 CHECK(value->IsTrue());
7277 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7278 v8::Handle<v8::Array> result = v8::Array::New(1);
7279 result->Set(0, v8_str("x"));
7284 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7285 v8::HandleScope handle_scope;
7286 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7288 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7289 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7290 NamedPropertyEnumerator);
7292 LocalContext context;
7293 v8::Handle<v8::Object> global = context->Global();
7294 global->Set(v8_str("object"), obj_template->NewInstance());
7296 v8::Handle<Value> value =
7297 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7298 CHECK_EQ(v8_str("x"), value);
7302 static v8::Handle<Value> ConstTenGetter(Local<String> name,
7303 const AccessorInfo& info) {
7308 THREADED_TEST(CrossDomainAccessors) {
7309 v8::HandleScope handle_scope;
7311 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7313 v8::Handle<v8::ObjectTemplate> global_template =
7314 func_template->InstanceTemplate();
7316 v8::Handle<v8::ObjectTemplate> proto_template =
7317 func_template->PrototypeTemplate();
7319 // Add an accessor to proto that's accessible by cross-domain JS code.
7320 proto_template->SetAccessor(v8_str("accessible"),
7322 v8::Handle<Value>(),
7325 // Add an accessor that is not accessible by cross-domain JS code.
7326 global_template->SetAccessor(v8_str("unreachable"),
7327 UnreachableGetter, 0,
7328 v8::Handle<Value>(),
7331 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7334 Local<v8::Object> global = context0->Global();
7335 // Add a normal property that shadows 'accessible'
7336 global->Set(v8_str("accessible"), v8_num(11));
7338 // Enter a new context.
7339 v8::HandleScope scope1;
7340 v8::Persistent<Context> context1 = Context::New();
7343 v8::Handle<v8::Object> global1 = context1->Global();
7344 global1->Set(v8_str("other"), global);
7346 // Should return 10, instead of 11
7347 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7348 CHECK(value->IsNumber());
7349 CHECK_EQ(10, value->Int32Value());
7351 value = v8_compile("other.unreachable")->Run();
7352 CHECK(value->IsUndefined());
7361 static int named_access_count = 0;
7362 static int indexed_access_count = 0;
7364 static bool NamedAccessCounter(Local<v8::Object> global,
7366 v8::AccessType type,
7367 Local<Value> data) {
7368 named_access_count++;
7373 static bool IndexedAccessCounter(Local<v8::Object> global,
7375 v8::AccessType type,
7376 Local<Value> data) {
7377 indexed_access_count++;
7382 // This one is too easily disturbed by other tests.
7383 TEST(AccessControlIC) {
7384 named_access_count = 0;
7385 indexed_access_count = 0;
7387 v8::HandleScope handle_scope;
7389 // Create an environment.
7390 v8::Persistent<Context> context0 = Context::New();
7393 // Create an object that requires access-check functions to be
7394 // called for cross-domain access.
7395 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7396 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7397 IndexedAccessCounter);
7398 Local<v8::Object> object = object_template->NewInstance();
7400 v8::HandleScope scope1;
7402 // Create another environment.
7403 v8::Persistent<Context> context1 = Context::New();
7406 // Make easy access to the object from the other environment.
7407 v8::Handle<v8::Object> global1 = context1->Global();
7408 global1->Set(v8_str("obj"), object);
7410 v8::Handle<Value> value;
7412 // Check that the named access-control function is called every time.
7413 CompileRun("function testProp(obj) {"
7414 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7415 " for (var j = 0; j < 10; j++) obj.prop;"
7418 value = CompileRun("testProp(obj)");
7419 CHECK(value->IsNumber());
7420 CHECK_EQ(1, value->Int32Value());
7421 CHECK_EQ(21, named_access_count);
7423 // Check that the named access-control function is called every time.
7424 CompileRun("var p = 'prop';"
7425 "function testKeyed(obj) {"
7426 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7427 " for (var j = 0; j < 10; j++) obj[p];"
7430 // Use obj which requires access checks. No inline caching is used
7432 value = CompileRun("testKeyed(obj)");
7433 CHECK(value->IsNumber());
7434 CHECK_EQ(1, value->Int32Value());
7435 CHECK_EQ(42, named_access_count);
7436 // Force the inline caches into generic state and try again.
7437 CompileRun("testKeyed({ a: 0 })");
7438 CompileRun("testKeyed({ b: 0 })");
7439 value = CompileRun("testKeyed(obj)");
7440 CHECK(value->IsNumber());
7441 CHECK_EQ(1, value->Int32Value());
7442 CHECK_EQ(63, named_access_count);
7444 // Check that the indexed access-control function is called every time.
7445 CompileRun("function testIndexed(obj) {"
7446 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7447 " for (var j = 0; j < 10; j++) obj[0];"
7450 value = CompileRun("testIndexed(obj)");
7451 CHECK(value->IsNumber());
7452 CHECK_EQ(1, value->Int32Value());
7453 CHECK_EQ(21, indexed_access_count);
7454 // Force the inline caches into generic state.
7455 CompileRun("testIndexed(new Array(1))");
7456 // Test that the indexed access check is called.
7457 value = CompileRun("testIndexed(obj)");
7458 CHECK(value->IsNumber());
7459 CHECK_EQ(1, value->Int32Value());
7460 CHECK_EQ(42, indexed_access_count);
7462 // Check that the named access check is called when invoking
7463 // functions on an object that requires access checks.
7464 CompileRun("obj.f = function() {}");
7465 CompileRun("function testCallNormal(obj) {"
7466 " for (var i = 0; i < 10; i++) obj.f();"
7468 CompileRun("testCallNormal(obj)");
7469 CHECK_EQ(74, named_access_count);
7471 // Force obj into slow case.
7472 value = CompileRun("delete obj.prop");
7473 CHECK(value->BooleanValue());
7474 // Force inline caches into dictionary probing mode.
7475 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7476 // Test that the named access check is called.
7477 value = CompileRun("testProp(obj);");
7478 CHECK(value->IsNumber());
7479 CHECK_EQ(1, value->Int32Value());
7480 CHECK_EQ(96, named_access_count);
7482 // Force the call inline cache into dictionary probing mode.
7483 CompileRun("o.f = function() {}; testCallNormal(o)");
7484 // Test that the named access check is still called for each
7485 // invocation of the function.
7486 value = CompileRun("testCallNormal(obj)");
7487 CHECK_EQ(106, named_access_count);
7496 static bool NamedAccessFlatten(Local<v8::Object> global,
7498 v8::AccessType type,
7499 Local<Value> data) {
7503 CHECK(name->IsString());
7505 memset(buf, 0x1, sizeof(buf));
7506 len = name.As<String>()->WriteAscii(buf);
7511 memset(buf, 0x1, sizeof(buf));
7512 len = name.As<String>()->Write(buf2);
7519 static bool IndexedAccessFlatten(Local<v8::Object> global,
7521 v8::AccessType type,
7522 Local<Value> data) {
7527 // Regression test. In access checks, operations that may cause
7528 // garbage collection are not allowed. It used to be the case that
7529 // using the Write operation on a string could cause a garbage
7530 // collection due to flattening of the string. This is no longer the
7532 THREADED_TEST(AccessControlFlatten) {
7533 named_access_count = 0;
7534 indexed_access_count = 0;
7536 v8::HandleScope handle_scope;
7538 // Create an environment.
7539 v8::Persistent<Context> context0 = Context::New();
7542 // Create an object that requires access-check functions to be
7543 // called for cross-domain access.
7544 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7545 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7546 IndexedAccessFlatten);
7547 Local<v8::Object> object = object_template->NewInstance();
7549 v8::HandleScope scope1;
7551 // Create another environment.
7552 v8::Persistent<Context> context1 = Context::New();
7555 // Make easy access to the object from the other environment.
7556 v8::Handle<v8::Object> global1 = context1->Global();
7557 global1->Set(v8_str("obj"), object);
7559 v8::Handle<Value> value;
7561 value = v8_compile("var p = 'as' + 'df';")->Run();
7562 value = v8_compile("obj[p];")->Run();
7571 static v8::Handle<Value> AccessControlNamedGetter(
7572 Local<String>, const AccessorInfo&) {
7573 return v8::Integer::New(42);
7577 static v8::Handle<Value> AccessControlNamedSetter(
7578 Local<String>, Local<Value> value, const AccessorInfo&) {
7583 static v8::Handle<Value> AccessControlIndexedGetter(
7585 const AccessorInfo& info) {
7590 static v8::Handle<Value> AccessControlIndexedSetter(
7591 uint32_t, Local<Value> value, const AccessorInfo&) {
7596 THREADED_TEST(AccessControlInterceptorIC) {
7597 named_access_count = 0;
7598 indexed_access_count = 0;
7600 v8::HandleScope handle_scope;
7602 // Create an environment.
7603 v8::Persistent<Context> context0 = Context::New();
7606 // Create an object that requires access-check functions to be
7607 // called for cross-domain access. The object also has interceptors
7609 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7610 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7611 IndexedAccessCounter);
7612 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7613 AccessControlNamedSetter);
7614 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7615 AccessControlIndexedSetter);
7616 Local<v8::Object> object = object_template->NewInstance();
7618 v8::HandleScope scope1;
7620 // Create another environment.
7621 v8::Persistent<Context> context1 = Context::New();
7624 // Make easy access to the object from the other environment.
7625 v8::Handle<v8::Object> global1 = context1->Global();
7626 global1->Set(v8_str("obj"), object);
7628 v8::Handle<Value> value;
7630 // Check that the named access-control function is called every time
7631 // eventhough there is an interceptor on the object.
7632 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7633 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7635 CHECK(value->IsNumber());
7636 CHECK_EQ(42, value->Int32Value());
7637 CHECK_EQ(21, named_access_count);
7639 value = v8_compile("var p = 'x';")->Run();
7640 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7641 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7643 CHECK(value->IsNumber());
7644 CHECK_EQ(42, value->Int32Value());
7645 CHECK_EQ(42, named_access_count);
7647 // Check that the indexed access-control function is called every
7648 // time eventhough there is an interceptor on the object.
7649 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7650 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7652 CHECK(value->IsNumber());
7653 CHECK_EQ(42, value->Int32Value());
7654 CHECK_EQ(21, indexed_access_count);
7663 THREADED_TEST(Version) {
7664 v8::V8::GetVersion();
7668 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7669 ApiTestFuzzer::Fuzz();
7674 THREADED_TEST(InstanceProperties) {
7675 v8::HandleScope handle_scope;
7676 LocalContext context;
7678 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7679 Local<ObjectTemplate> instance = t->InstanceTemplate();
7681 instance->Set(v8_str("x"), v8_num(42));
7682 instance->Set(v8_str("f"),
7683 v8::FunctionTemplate::New(InstanceFunctionCallback));
7685 Local<Value> o = t->GetFunction()->NewInstance();
7687 context->Global()->Set(v8_str("i"), o);
7688 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7689 CHECK_EQ(42, value->Int32Value());
7691 value = Script::Compile(v8_str("i.f()"))->Run();
7692 CHECK_EQ(12, value->Int32Value());
7696 static v8::Handle<Value>
7697 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7698 ApiTestFuzzer::Fuzz();
7699 return v8::Handle<Value>();
7703 THREADED_TEST(GlobalObjectInstanceProperties) {
7704 v8::HandleScope handle_scope;
7706 Local<Value> global_object;
7708 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7709 t->InstanceTemplate()->SetNamedPropertyHandler(
7710 GlobalObjectInstancePropertiesGet);
7711 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7712 instance_template->Set(v8_str("x"), v8_num(42));
7713 instance_template->Set(v8_str("f"),
7714 v8::FunctionTemplate::New(InstanceFunctionCallback));
7716 // The script to check how Crankshaft compiles missing global function
7717 // invocations. function g is not defined and should throw on call.
7718 const char* script =
7719 "function wrapper(call) {"
7720 " var x = 0, y = 1;"
7721 " for (var i = 0; i < 1000; i++) {"
7727 "for (var i = 0; i < 17; i++) wrapper(false);"
7729 "try { wrapper(true); } catch (e) { thrown = 1; };"
7733 LocalContext env(NULL, instance_template);
7734 // Hold on to the global object so it can be used again in another
7735 // environment initialization.
7736 global_object = env->Global();
7738 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7739 CHECK_EQ(42, value->Int32Value());
7740 value = Script::Compile(v8_str("f()"))->Run();
7741 CHECK_EQ(12, value->Int32Value());
7742 value = Script::Compile(v8_str(script))->Run();
7743 CHECK_EQ(1, value->Int32Value());
7747 // Create new environment reusing the global object.
7748 LocalContext env(NULL, instance_template, global_object);
7749 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7750 CHECK_EQ(42, value->Int32Value());
7751 value = Script::Compile(v8_str("f()"))->Run();
7752 CHECK_EQ(12, value->Int32Value());
7753 value = Script::Compile(v8_str(script))->Run();
7754 CHECK_EQ(1, value->Int32Value());
7759 THREADED_TEST(CallKnownGlobalReceiver) {
7760 v8::HandleScope handle_scope;
7762 Local<Value> global_object;
7764 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7765 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7767 // The script to check that we leave global object not
7768 // global object proxy on stack when we deoptimize from inside
7769 // arguments evaluation.
7770 // To provoke error we need to both force deoptimization
7771 // from arguments evaluation and to force CallIC to take
7772 // CallIC_Miss code path that can't cope with global proxy.
7773 const char* script =
7774 "function bar(x, y) { try { } finally { } }"
7775 "function baz(x) { try { } finally { } }"
7776 "function bom(x) { try { } finally { } }"
7777 "function foo(x) { bar([x], bom(2)); }"
7778 "for (var i = 0; i < 10000; i++) foo(1);"
7783 LocalContext env(NULL, instance_template);
7784 // Hold on to the global object so it can be used again in another
7785 // environment initialization.
7786 global_object = env->Global();
7787 foo = Script::Compile(v8_str(script))->Run();
7791 // Create new environment reusing the global object.
7792 LocalContext env(NULL, instance_template, global_object);
7793 env->Global()->Set(v8_str("foo"), foo);
7794 Script::Compile(v8_str("foo()"))->Run();
7799 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7800 ApiTestFuzzer::Fuzz();
7805 static int shadow_y;
7806 static int shadow_y_setter_call_count;
7807 static int shadow_y_getter_call_count;
7810 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7811 shadow_y_setter_call_count++;
7816 static v8::Handle<Value> ShadowYGetter(Local<String> name,
7817 const AccessorInfo& info) {
7818 ApiTestFuzzer::Fuzz();
7819 shadow_y_getter_call_count++;
7820 return v8_num(shadow_y);
7824 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7825 const AccessorInfo& info) {
7826 return v8::Handle<Value>();
7830 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7831 const AccessorInfo&) {
7832 return v8::Handle<Value>();
7836 THREADED_TEST(ShadowObject) {
7837 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7838 v8::HandleScope handle_scope;
7840 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7841 LocalContext context(NULL, global_template);
7843 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7844 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7845 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7846 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7847 Local<ObjectTemplate> instance = t->InstanceTemplate();
7849 // Only allow calls of f on instances of t.
7850 Local<v8::Signature> signature = v8::Signature::New(t);
7851 proto->Set(v8_str("f"),
7852 v8::FunctionTemplate::New(ShadowFunctionCallback,
7855 proto->Set(v8_str("x"), v8_num(12));
7857 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7859 Local<Value> o = t->GetFunction()->NewInstance();
7860 context->Global()->Set(v8_str("__proto__"), o);
7862 Local<Value> value =
7863 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7864 CHECK(value->IsBoolean());
7865 CHECK(!value->BooleanValue());
7867 value = Script::Compile(v8_str("x"))->Run();
7868 CHECK_EQ(12, value->Int32Value());
7870 value = Script::Compile(v8_str("f()"))->Run();
7871 CHECK_EQ(42, value->Int32Value());
7873 Script::Compile(v8_str("y = 43"))->Run();
7874 CHECK_EQ(1, shadow_y_setter_call_count);
7875 value = Script::Compile(v8_str("y"))->Run();
7876 CHECK_EQ(1, shadow_y_getter_call_count);
7877 CHECK_EQ(42, value->Int32Value());
7881 THREADED_TEST(HiddenPrototype) {
7882 v8::HandleScope handle_scope;
7883 LocalContext context;
7885 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7886 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7887 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7888 t1->SetHiddenPrototype(true);
7889 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7890 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7891 t2->SetHiddenPrototype(true);
7892 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7893 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7894 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7896 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7897 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7898 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7899 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7901 // Setting the prototype on an object skips hidden prototypes.
7902 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7903 o0->Set(v8_str("__proto__"), o1);
7904 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7905 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7906 o0->Set(v8_str("__proto__"), o2);
7907 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7908 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7909 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7910 o0->Set(v8_str("__proto__"), o3);
7911 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7912 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7913 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7914 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7916 // Getting the prototype of o0 should get the first visible one
7917 // which is o3. Therefore, z should not be defined on the prototype
7919 Local<Value> proto = o0->Get(v8_str("__proto__"));
7920 CHECK(proto->IsObject());
7921 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7925 THREADED_TEST(SetPrototype) {
7926 v8::HandleScope handle_scope;
7927 LocalContext context;
7929 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7930 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7931 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7932 t1->SetHiddenPrototype(true);
7933 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7934 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7935 t2->SetHiddenPrototype(true);
7936 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7937 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7938 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7940 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7941 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7942 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7943 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7945 // Setting the prototype on an object does not skip hidden prototypes.
7946 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7947 CHECK(o0->SetPrototype(o1));
7948 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7949 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7950 CHECK(o1->SetPrototype(o2));
7951 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7952 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7953 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7954 CHECK(o2->SetPrototype(o3));
7955 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7956 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7957 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7958 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7960 // Getting the prototype of o0 should get the first visible one
7961 // which is o3. Therefore, z should not be defined on the prototype
7963 Local<Value> proto = o0->Get(v8_str("__proto__"));
7964 CHECK(proto->IsObject());
7965 CHECK_EQ(proto.As<v8::Object>(), o3);
7967 // However, Object::GetPrototype ignores hidden prototype.
7968 Local<Value> proto0 = o0->GetPrototype();
7969 CHECK(proto0->IsObject());
7970 CHECK_EQ(proto0.As<v8::Object>(), o1);
7972 Local<Value> proto1 = o1->GetPrototype();
7973 CHECK(proto1->IsObject());
7974 CHECK_EQ(proto1.As<v8::Object>(), o2);
7976 Local<Value> proto2 = o2->GetPrototype();
7977 CHECK(proto2->IsObject());
7978 CHECK_EQ(proto2.As<v8::Object>(), o3);
7982 // Getting property names of an object with a prototype chain that
7983 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
7984 // crash the runtime.
7985 THREADED_TEST(Regress91517) {
7986 i::FLAG_allow_natives_syntax = true;
7987 v8::HandleScope handle_scope;
7988 LocalContext context;
7990 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7991 t1->SetHiddenPrototype(true);
7992 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
7993 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7994 t2->SetHiddenPrototype(true);
7995 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
7996 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
7997 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
7998 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7999 t3->SetHiddenPrototype(true);
8000 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8001 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8002 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8004 // Force dictionary-based properties.
8005 i::ScopedVector<char> name_buf(1024);
8006 for (int i = 1; i <= 1000; i++) {
8007 i::OS::SNPrintF(name_buf, "sdf%d", i);
8008 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8011 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8012 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8013 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8014 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8016 // Create prototype chain of hidden prototypes.
8017 CHECK(o4->SetPrototype(o3));
8018 CHECK(o3->SetPrototype(o2));
8019 CHECK(o2->SetPrototype(o1));
8021 // Call the runtime version of GetLocalPropertyNames() on the natively
8022 // created object through JavaScript.
8023 context->Global()->Set(v8_str("obj"), o4);
8024 CompileRun("var names = %GetLocalPropertyNames(obj);");
8026 ExpectInt32("names.length", 1006);
8027 ExpectTrue("names.indexOf(\"baz\") >= 0");
8028 ExpectTrue("names.indexOf(\"boo\") >= 0");
8029 ExpectTrue("names.indexOf(\"foo\") >= 0");
8030 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8031 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8032 ExpectFalse("names[1005] == undefined");
8036 THREADED_TEST(FunctionReadOnlyPrototype) {
8037 v8::HandleScope handle_scope;
8038 LocalContext context;
8040 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8041 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8042 t1->ReadOnlyPrototype();
8043 context->Global()->Set(v8_str("func1"), t1->GetFunction());
8044 // Configured value of ReadOnly flag.
8047 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
8048 " return (descriptor['writable'] == false);"
8049 "})()")->BooleanValue());
8050 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8052 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
8054 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8055 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8056 context->Global()->Set(v8_str("func2"), t2->GetFunction());
8057 // Default value of ReadOnly flag.
8060 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
8061 " return (descriptor['writable'] == true);"
8062 "})()")->BooleanValue());
8063 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
8067 THREADED_TEST(SetPrototypeThrows) {
8068 v8::HandleScope handle_scope;
8069 LocalContext context;
8071 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8073 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8074 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8076 CHECK(o0->SetPrototype(o1));
8077 // If setting the prototype leads to the cycle, SetPrototype should
8078 // return false and keep VM in sane state.
8079 v8::TryCatch try_catch;
8080 CHECK(!o1->SetPrototype(o0));
8081 CHECK(!try_catch.HasCaught());
8082 ASSERT(!i::Isolate::Current()->has_pending_exception());
8084 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8088 THREADED_TEST(GetterSetterExceptions) {
8089 v8::HandleScope handle_scope;
8090 LocalContext context;
8092 "function Foo() { };"
8093 "function Throw() { throw 5; };"
8095 "x.__defineSetter__('set', Throw);"
8096 "x.__defineGetter__('get', Throw);");
8097 Local<v8::Object> x =
8098 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8099 v8::TryCatch try_catch;
8100 x->Set(v8_str("set"), v8::Integer::New(8));
8101 x->Get(v8_str("get"));
8102 x->Set(v8_str("set"), v8::Integer::New(8));
8103 x->Get(v8_str("get"));
8104 x->Set(v8_str("set"), v8::Integer::New(8));
8105 x->Get(v8_str("get"));
8106 x->Set(v8_str("set"), v8::Integer::New(8));
8107 x->Get(v8_str("get"));
8111 THREADED_TEST(Constructor) {
8112 v8::HandleScope handle_scope;
8113 LocalContext context;
8114 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8115 templ->SetClassName(v8_str("Fun"));
8116 Local<Function> cons = templ->GetFunction();
8117 context->Global()->Set(v8_str("Fun"), cons);
8118 Local<v8::Object> inst = cons->NewInstance();
8119 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
8120 CHECK(obj->IsJSObject());
8121 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8122 CHECK(value->BooleanValue());
8126 static Handle<Value> ConstructorCallback(const Arguments& args) {
8127 ApiTestFuzzer::Fuzz();
8130 if (args.IsConstructCall()) {
8131 Local<Object> Holder = args.Holder();
8132 This = Object::New();
8133 Local<Value> proto = Holder->GetPrototype();
8134 if (proto->IsObject()) {
8135 This->SetPrototype(proto);
8141 This->Set(v8_str("a"), args[0]);
8146 static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8147 ApiTestFuzzer::Fuzz();
8152 THREADED_TEST(ConstructorForObject) {
8153 v8::HandleScope handle_scope;
8154 LocalContext context;
8156 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8157 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8158 Local<Object> instance = instance_template->NewInstance();
8159 context->Global()->Set(v8_str("obj"), instance);
8160 v8::TryCatch try_catch;
8162 CHECK(!try_catch.HasCaught());
8164 // Call the Object's constructor with a 32-bit signed integer.
8165 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8166 CHECK(!try_catch.HasCaught());
8167 CHECK(value->IsInt32());
8168 CHECK_EQ(28, value->Int32Value());
8170 Local<Value> args1[] = { v8_num(28) };
8171 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8172 CHECK(value_obj1->IsObject());
8173 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8174 value = object1->Get(v8_str("a"));
8175 CHECK(value->IsInt32());
8176 CHECK(!try_catch.HasCaught());
8177 CHECK_EQ(28, value->Int32Value());
8179 // Call the Object's constructor with a String.
8181 "(function() { var o = new obj('tipli'); return o.a; })()");
8182 CHECK(!try_catch.HasCaught());
8183 CHECK(value->IsString());
8184 String::AsciiValue string_value1(value->ToString());
8185 CHECK_EQ("tipli", *string_value1);
8187 Local<Value> args2[] = { v8_str("tipli") };
8188 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8189 CHECK(value_obj2->IsObject());
8190 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8191 value = object2->Get(v8_str("a"));
8192 CHECK(!try_catch.HasCaught());
8193 CHECK(value->IsString());
8194 String::AsciiValue string_value2(value->ToString());
8195 CHECK_EQ("tipli", *string_value2);
8197 // Call the Object's constructor with a Boolean.
8198 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8199 CHECK(!try_catch.HasCaught());
8200 CHECK(value->IsBoolean());
8201 CHECK_EQ(true, value->BooleanValue());
8203 Handle<Value> args3[] = { v8::True() };
8204 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8205 CHECK(value_obj3->IsObject());
8206 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8207 value = object3->Get(v8_str("a"));
8208 CHECK(!try_catch.HasCaught());
8209 CHECK(value->IsBoolean());
8210 CHECK_EQ(true, value->BooleanValue());
8212 // Call the Object's constructor with undefined.
8213 Handle<Value> args4[] = { v8::Undefined() };
8214 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8215 CHECK(value_obj4->IsObject());
8216 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8217 value = object4->Get(v8_str("a"));
8218 CHECK(!try_catch.HasCaught());
8219 CHECK(value->IsUndefined());
8221 // Call the Object's constructor with null.
8222 Handle<Value> args5[] = { v8::Null() };
8223 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8224 CHECK(value_obj5->IsObject());
8225 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8226 value = object5->Get(v8_str("a"));
8227 CHECK(!try_catch.HasCaught());
8228 CHECK(value->IsNull());
8231 // Check exception handling when there is no constructor set for the Object.
8232 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8233 Local<Object> instance = instance_template->NewInstance();
8234 context->Global()->Set(v8_str("obj2"), instance);
8235 v8::TryCatch try_catch;
8237 CHECK(!try_catch.HasCaught());
8239 value = CompileRun("new obj2(28)");
8240 CHECK(try_catch.HasCaught());
8241 String::AsciiValue exception_value1(try_catch.Exception());
8242 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8245 Local<Value> args[] = { v8_num(29) };
8246 value = instance->CallAsConstructor(1, args);
8247 CHECK(try_catch.HasCaught());
8248 String::AsciiValue exception_value2(try_catch.Exception());
8249 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8253 // Check the case when constructor throws exception.
8254 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8255 instance_template->SetCallAsFunctionHandler(ThrowValue);
8256 Local<Object> instance = instance_template->NewInstance();
8257 context->Global()->Set(v8_str("obj3"), instance);
8258 v8::TryCatch try_catch;
8260 CHECK(!try_catch.HasCaught());
8262 value = CompileRun("new obj3(22)");
8263 CHECK(try_catch.HasCaught());
8264 String::AsciiValue exception_value1(try_catch.Exception());
8265 CHECK_EQ("22", *exception_value1);
8268 Local<Value> args[] = { v8_num(23) };
8269 value = instance->CallAsConstructor(1, args);
8270 CHECK(try_catch.HasCaught());
8271 String::AsciiValue exception_value2(try_catch.Exception());
8272 CHECK_EQ("23", *exception_value2);
8276 // Check whether constructor returns with an object or non-object.
8277 { Local<FunctionTemplate> function_template =
8278 FunctionTemplate::New(FakeConstructorCallback);
8279 Local<Function> function = function_template->GetFunction();
8280 Local<Object> instance1 = function;
8281 context->Global()->Set(v8_str("obj4"), instance1);
8282 v8::TryCatch try_catch;
8284 CHECK(!try_catch.HasCaught());
8286 CHECK(instance1->IsObject());
8287 CHECK(instance1->IsFunction());
8289 value = CompileRun("new obj4(28)");
8290 CHECK(!try_catch.HasCaught());
8291 CHECK(value->IsObject());
8293 Local<Value> args1[] = { v8_num(28) };
8294 value = instance1->CallAsConstructor(1, args1);
8295 CHECK(!try_catch.HasCaught());
8296 CHECK(value->IsObject());
8298 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8299 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8300 Local<Object> instance2 = instance_template->NewInstance();
8301 context->Global()->Set(v8_str("obj5"), instance2);
8302 CHECK(!try_catch.HasCaught());
8304 CHECK(instance2->IsObject());
8305 CHECK(!instance2->IsFunction());
8307 value = CompileRun("new obj5(28)");
8308 CHECK(!try_catch.HasCaught());
8309 CHECK(!value->IsObject());
8311 Local<Value> args2[] = { v8_num(28) };
8312 value = instance2->CallAsConstructor(1, args2);
8313 CHECK(!try_catch.HasCaught());
8314 CHECK(!value->IsObject());
8319 THREADED_TEST(FunctionDescriptorException) {
8320 v8::HandleScope handle_scope;
8321 LocalContext context;
8322 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8323 templ->SetClassName(v8_str("Fun"));
8324 Local<Function> cons = templ->GetFunction();
8325 context->Global()->Set(v8_str("Fun"), cons);
8326 Local<Value> value = CompileRun(
8329 " (new Fun()).blah()"
8331 " var str = String(e);"
8332 " if (str.indexOf('TypeError') == -1) return 1;"
8333 " if (str.indexOf('[object Fun]') != -1) return 2;"
8334 " if (str.indexOf('#<Fun>') == -1) return 3;"
8340 CHECK_EQ(0, value->Int32Value());
8344 THREADED_TEST(EvalAliasedDynamic) {
8345 v8::HandleScope scope;
8346 LocalContext current;
8348 // Tests where aliased eval can only be resolved dynamically.
8349 Local<Script> script =
8350 Script::Compile(v8_str("function f(x) { "
8352 " with (x) { return eval('foo'); }"
8355 "result1 = f(new Object());"
8356 "result2 = f(this);"
8357 "var x = new Object();"
8358 "x.eval = function(x) { return 1; };"
8359 "result3 = f(x);"));
8361 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8362 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8363 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8365 v8::TryCatch try_catch;
8367 Script::Compile(v8_str("function f(x) { "
8369 " with (x) { return eval('bar'); }"
8371 "result4 = f(this)"));
8373 CHECK(!try_catch.HasCaught());
8374 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8380 THREADED_TEST(CrossEval) {
8381 v8::HandleScope scope;
8383 LocalContext current;
8385 Local<String> token = v8_str("<security token>");
8386 other->SetSecurityToken(token);
8387 current->SetSecurityToken(token);
8389 // Set up reference from current to other.
8390 current->Global()->Set(v8_str("other"), other->Global());
8392 // Check that new variables are introduced in other context.
8393 Local<Script> script =
8394 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8396 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8397 CHECK_EQ(1234, foo->Int32Value());
8398 CHECK(!current->Global()->Has(v8_str("foo")));
8400 // Check that writing to non-existing properties introduces them in
8401 // the other context.
8403 Script::Compile(v8_str("other.eval('na = 1234')"));
8405 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8406 CHECK(!current->Global()->Has(v8_str("na")));
8408 // Check that global variables in current context are not visible in other
8410 v8::TryCatch try_catch;
8412 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
8413 Local<Value> result = script->Run();
8414 CHECK(try_catch.HasCaught());
8417 // Check that local variables in current context are not visible in other
8420 Script::Compile(v8_str("(function() { "
8422 " return other.eval('baz');"
8424 result = script->Run();
8425 CHECK(try_catch.HasCaught());
8428 // Check that global variables in the other environment are visible
8429 // when evaluting code.
8430 other->Global()->Set(v8_str("bis"), v8_num(1234));
8431 script = Script::Compile(v8_str("other.eval('bis')"));
8432 CHECK_EQ(1234, script->Run()->Int32Value());
8433 CHECK(!try_catch.HasCaught());
8435 // Check that the 'this' pointer points to the global object evaluating
8437 other->Global()->Set(v8_str("t"), other->Global());
8438 script = Script::Compile(v8_str("other.eval('this == t')"));
8439 result = script->Run();
8440 CHECK(result->IsTrue());
8441 CHECK(!try_catch.HasCaught());
8443 // Check that variables introduced in with-statement are not visible in
8446 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
8447 result = script->Run();
8448 CHECK(try_catch.HasCaught());
8451 // Check that you cannot use 'eval.call' with another object than the
8452 // current global object.
8454 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8455 result = script->Run();
8456 CHECK(try_catch.HasCaught());
8460 // Test that calling eval in a context which has been detached from
8461 // its global throws an exception. This behavior is consistent with
8462 // other JavaScript implementations.
8463 THREADED_TEST(EvalInDetachedGlobal) {
8464 v8::HandleScope scope;
8466 v8::Persistent<Context> context0 = Context::New();
8467 v8::Persistent<Context> context1 = Context::New();
8469 // Set up function in context0 that uses eval from context0.
8471 v8::Handle<v8::Value> fun =
8472 CompileRun("var x = 42;"
8475 " return function(s) { return e(s); }"
8479 // Put the function into context1 and call it before and after
8480 // detaching the global. Before detaching, the call succeeds and
8481 // after detaching and exception is thrown.
8483 context1->Global()->Set(v8_str("fun"), fun);
8484 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8485 CHECK_EQ(42, x_value->Int32Value());
8486 context0->DetachGlobal();
8487 v8::TryCatch catcher;
8488 x_value = CompileRun("fun('x')");
8489 CHECK(x_value.IsEmpty());
8490 CHECK(catcher.HasCaught());
8498 THREADED_TEST(CrossLazyLoad) {
8499 v8::HandleScope scope;
8501 LocalContext current;
8503 Local<String> token = v8_str("<security token>");
8504 other->SetSecurityToken(token);
8505 current->SetSecurityToken(token);
8507 // Set up reference from current to other.
8508 current->Global()->Set(v8_str("other"), other->Global());
8510 // Trigger lazy loading in other context.
8511 Local<Script> script =
8512 Script::Compile(v8_str("other.eval('new Date(42)')"));
8513 Local<Value> value = script->Run();
8514 CHECK_EQ(42.0, value->NumberValue());
8518 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8519 ApiTestFuzzer::Fuzz();
8520 if (args.IsConstructCall()) {
8521 if (args[0]->IsInt32()) {
8522 return v8_num(-args[0]->Int32Value());
8530 // Test that a call handler can be set for objects which will allow
8531 // non-function objects created through the API to be called as
8533 THREADED_TEST(CallAsFunction) {
8534 v8::HandleScope scope;
8535 LocalContext context;
8537 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8538 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8539 instance_template->SetCallAsFunctionHandler(call_as_function);
8540 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8541 context->Global()->Set(v8_str("obj"), instance);
8542 v8::TryCatch try_catch;
8544 CHECK(!try_catch.HasCaught());
8546 value = CompileRun("obj(42)");
8547 CHECK(!try_catch.HasCaught());
8548 CHECK_EQ(42, value->Int32Value());
8550 value = CompileRun("(function(o){return o(49)})(obj)");
8551 CHECK(!try_catch.HasCaught());
8552 CHECK_EQ(49, value->Int32Value());
8554 // test special case of call as function
8555 value = CompileRun("[obj]['0'](45)");
8556 CHECK(!try_catch.HasCaught());
8557 CHECK_EQ(45, value->Int32Value());
8559 value = CompileRun("obj.call = Function.prototype.call;"
8560 "obj.call(null, 87)");
8561 CHECK(!try_catch.HasCaught());
8562 CHECK_EQ(87, value->Int32Value());
8564 // Regression tests for bug #1116356: Calling call through call/apply
8565 // must work for non-function receivers.
8566 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8567 value = CompileRun(apply_99);
8568 CHECK(!try_catch.HasCaught());
8569 CHECK_EQ(99, value->Int32Value());
8571 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8572 value = CompileRun(call_17);
8573 CHECK(!try_catch.HasCaught());
8574 CHECK_EQ(17, value->Int32Value());
8576 // Check that the call-as-function handler can be called through
8578 value = CompileRun("new obj(43)");
8579 CHECK(!try_catch.HasCaught());
8580 CHECK_EQ(-43, value->Int32Value());
8582 // Check that the call-as-function handler can be called through
8584 v8::Handle<Value> args[] = { v8_num(28) };
8585 value = instance->CallAsFunction(instance, 1, args);
8586 CHECK(!try_catch.HasCaught());
8587 CHECK_EQ(28, value->Int32Value());
8590 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8591 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8592 USE(instance_template);
8593 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8594 context->Global()->Set(v8_str("obj2"), instance);
8595 v8::TryCatch try_catch;
8597 CHECK(!try_catch.HasCaught());
8599 // Call an object without call-as-function handler through the JS
8600 value = CompileRun("obj2(28)");
8601 CHECK(value.IsEmpty());
8602 CHECK(try_catch.HasCaught());
8603 String::AsciiValue exception_value1(try_catch.Exception());
8604 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8608 // Call an object without call-as-function handler through the API
8609 value = CompileRun("obj2(28)");
8610 v8::Handle<Value> args[] = { v8_num(28) };
8611 value = instance->CallAsFunction(instance, 1, args);
8612 CHECK(value.IsEmpty());
8613 CHECK(try_catch.HasCaught());
8614 String::AsciiValue exception_value2(try_catch.Exception());
8615 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8619 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8620 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8621 instance_template->SetCallAsFunctionHandler(ThrowValue);
8622 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8623 context->Global()->Set(v8_str("obj3"), instance);
8624 v8::TryCatch try_catch;
8626 CHECK(!try_catch.HasCaught());
8628 // Catch the exception which is thrown by call-as-function handler
8629 value = CompileRun("obj3(22)");
8630 CHECK(try_catch.HasCaught());
8631 String::AsciiValue exception_value1(try_catch.Exception());
8632 CHECK_EQ("22", *exception_value1);
8635 v8::Handle<Value> args[] = { v8_num(23) };
8636 value = instance->CallAsFunction(instance, 1, args);
8637 CHECK(try_catch.HasCaught());
8638 String::AsciiValue exception_value2(try_catch.Exception());
8639 CHECK_EQ("23", *exception_value2);
8645 // Check whether a non-function object is callable.
8646 THREADED_TEST(CallableObject) {
8647 v8::HandleScope scope;
8648 LocalContext context;
8650 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8651 instance_template->SetCallAsFunctionHandler(call_as_function);
8652 Local<Object> instance = instance_template->NewInstance();
8653 v8::TryCatch try_catch;
8655 CHECK(instance->IsCallable());
8656 CHECK(!try_catch.HasCaught());
8659 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8660 Local<Object> instance = instance_template->NewInstance();
8661 v8::TryCatch try_catch;
8663 CHECK(!instance->IsCallable());
8664 CHECK(!try_catch.HasCaught());
8667 { Local<FunctionTemplate> function_template =
8668 FunctionTemplate::New(call_as_function);
8669 Local<Function> function = function_template->GetFunction();
8670 Local<Object> instance = function;
8671 v8::TryCatch try_catch;
8673 CHECK(instance->IsCallable());
8674 CHECK(!try_catch.HasCaught());
8677 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8678 Local<Function> function = function_template->GetFunction();
8679 Local<Object> instance = function;
8680 v8::TryCatch try_catch;
8682 CHECK(instance->IsCallable());
8683 CHECK(!try_catch.HasCaught());
8688 static int CountHandles() {
8689 return v8::HandleScope::NumberOfHandles();
8693 static int Recurse(int depth, int iterations) {
8694 v8::HandleScope scope;
8695 if (depth == 0) return CountHandles();
8696 for (int i = 0; i < iterations; i++) {
8697 Local<v8::Number> n(v8::Integer::New(42));
8699 return Recurse(depth - 1, iterations);
8703 THREADED_TEST(HandleIteration) {
8704 static const int kIterations = 500;
8705 static const int kNesting = 200;
8706 CHECK_EQ(0, CountHandles());
8708 v8::HandleScope scope1;
8709 CHECK_EQ(0, CountHandles());
8710 for (int i = 0; i < kIterations; i++) {
8711 Local<v8::Number> n(v8::Integer::New(42));
8712 CHECK_EQ(i + 1, CountHandles());
8715 CHECK_EQ(kIterations, CountHandles());
8717 v8::HandleScope scope2;
8718 for (int j = 0; j < kIterations; j++) {
8719 Local<v8::Number> n(v8::Integer::New(42));
8720 CHECK_EQ(j + 1 + kIterations, CountHandles());
8723 CHECK_EQ(kIterations, CountHandles());
8725 CHECK_EQ(0, CountHandles());
8726 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8730 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8732 const AccessorInfo& info) {
8733 ApiTestFuzzer::Fuzz();
8734 return v8::Handle<Value>();
8738 THREADED_TEST(InterceptorHasOwnProperty) {
8739 v8::HandleScope scope;
8740 LocalContext context;
8741 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8742 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8743 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8744 Local<Function> function = fun_templ->GetFunction();
8745 context->Global()->Set(v8_str("constructor"), function);
8746 v8::Handle<Value> value = CompileRun(
8747 "var o = new constructor();"
8748 "o.hasOwnProperty('ostehaps');");
8749 CHECK_EQ(false, value->BooleanValue());
8752 "o.hasOwnProperty('ostehaps');");
8753 CHECK_EQ(true, value->BooleanValue());
8755 "var p = new constructor();"
8756 "p.hasOwnProperty('ostehaps');");
8757 CHECK_EQ(false, value->BooleanValue());
8761 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8763 const AccessorInfo& info) {
8764 ApiTestFuzzer::Fuzz();
8765 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8766 return v8::Handle<Value>();
8770 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8771 v8::HandleScope scope;
8772 LocalContext context;
8773 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8774 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8775 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8776 Local<Function> function = fun_templ->GetFunction();
8777 context->Global()->Set(v8_str("constructor"), function);
8778 // Let's first make some stuff so we can be sure to get a good GC.
8780 "function makestr(size) {"
8782 " case 1: return 'f';"
8783 " case 2: return 'fo';"
8784 " case 3: return 'foo';"
8786 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8788 "var x = makestr(12345);"
8789 "x = makestr(31415);"
8790 "x = makestr(23456);");
8791 v8::Handle<Value> value = CompileRun(
8792 "var o = new constructor();"
8793 "o.__proto__ = new String(x);"
8794 "o.hasOwnProperty('ostehaps');");
8795 CHECK_EQ(false, value->BooleanValue());
8799 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8800 const AccessorInfo& info);
8803 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8806 v8::HandleScope scope;
8807 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8808 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8809 LocalContext context;
8810 context->Global()->Set(v8_str("o"), templ->NewInstance());
8811 v8::Handle<Value> value = CompileRun(source);
8812 CHECK_EQ(expected, value->Int32Value());
8816 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8817 const AccessorInfo& info) {
8818 ApiTestFuzzer::Fuzz();
8819 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8820 CHECK_EQ(isolate, info.GetIsolate());
8821 CHECK_EQ(v8_str("data"), info.Data());
8822 CHECK_EQ(v8_str("x"), name);
8823 return v8::Integer::New(42);
8827 // This test should hit the load IC for the interceptor case.
8828 THREADED_TEST(InterceptorLoadIC) {
8829 CheckInterceptorLoadIC(InterceptorLoadICGetter,
8831 "for (var i = 0; i < 1000; i++) {"
8838 // Below go several tests which verify that JITing for various
8839 // configurations of interceptor and explicit fields works fine
8840 // (those cases are special cased to get better performance).
8842 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8843 const AccessorInfo& info) {
8844 ApiTestFuzzer::Fuzz();
8845 return v8_str("x")->Equals(name)
8846 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8850 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8851 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8854 "for (var i = 0; i < 1000; i++) {"
8861 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8862 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8864 "o.__proto__ = { 'y': 239 };"
8865 "for (var i = 0; i < 1000; i++) {"
8866 " result = o.y + o.x;"
8872 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8873 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8875 "o.__proto__.y = 239;"
8876 "for (var i = 0; i < 1000; i++) {"
8877 " result = o.y + o.x;"
8883 THREADED_TEST(InterceptorLoadICUndefined) {
8884 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8886 "for (var i = 0; i < 1000; i++) {"
8887 " result = (o.y == undefined) ? 239 : 42;"
8893 THREADED_TEST(InterceptorLoadICWithOverride) {
8894 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8895 "fst = new Object(); fst.__proto__ = o;"
8896 "snd = new Object(); snd.__proto__ = fst;"
8898 "for (var i = 0; i < 1000; i++) {"
8903 "for (var i = 0; i < 1000; i++) {"
8911 // Test the case when we stored field into
8912 // a stub, but interceptor produced value on its own.
8913 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8914 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8915 "proto = new Object();"
8916 "o.__proto__ = proto;"
8918 "for (var i = 0; i < 1000; i++) {"
8920 // Now it should be ICed and keep a reference to x defined on proto
8923 "for (var i = 0; i < 1000; i++) {"
8931 // Test the case when we stored field into
8932 // a stub, but it got invalidated later on.
8933 THREADED_TEST(InterceptorLoadICInvalidatedField) {
8934 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8935 "proto1 = new Object();"
8936 "proto2 = new Object();"
8937 "o.__proto__ = proto1;"
8938 "proto1.__proto__ = proto2;"
8940 "for (var i = 0; i < 1000; i++) {"
8942 // Now it should be ICed and keep a reference to y defined on proto2
8946 "for (var i = 0; i < 1000; i++) {"
8954 static int interceptor_load_not_handled_calls = 0;
8955 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8956 const AccessorInfo& info) {
8957 ++interceptor_load_not_handled_calls;
8958 return v8::Handle<v8::Value>();
8962 // Test how post-interceptor lookups are done in the non-cacheable
8963 // case: the interceptor should not be invoked during this lookup.
8964 THREADED_TEST(InterceptorLoadICPostInterceptor) {
8965 interceptor_load_not_handled_calls = 0;
8966 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8967 "receiver = new Object();"
8968 "receiver.__proto__ = o;"
8969 "proto = new Object();"
8970 "/* Make proto a slow-case object. */"
8971 "for (var i = 0; i < 1000; i++) {"
8972 " proto[\"xxxxxxxx\" + i] = [];"
8975 "o.__proto__ = proto;"
8977 "for (var i = 0; i < 1000; i++) {"
8978 " result += receiver.x;"
8982 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8986 // Test the case when we stored field into
8987 // a stub, but it got invalidated later on due to override on
8988 // global object which is between interceptor and fields' holders.
8989 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8990 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8991 "o.__proto__ = this;" // set a global to be a proto of o.
8992 "this.__proto__.y = 239;"
8993 "for (var i = 0; i < 10; i++) {"
8994 " if (o.y != 239) throw 'oops: ' + o.y;"
8995 // Now it should be ICed and keep a reference to y defined on field_holder.
8997 "this.y = 42;" // Assign on a global.
8999 "for (var i = 0; i < 10; i++) {"
9007 static void SetOnThis(Local<String> name,
9009 const AccessorInfo& info) {
9010 info.This()->ForceSet(name, value);
9014 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9015 v8::HandleScope scope;
9016 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9017 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9018 templ->SetAccessor(v8_str("y"), Return239);
9019 LocalContext context;
9020 context->Global()->Set(v8_str("o"), templ->NewInstance());
9022 // Check the case when receiver and interceptor's holder
9023 // are the same objects.
9024 v8::Handle<Value> value = CompileRun(
9026 "for (var i = 0; i < 7; i++) {"
9029 CHECK_EQ(239, value->Int32Value());
9031 // Check the case when interceptor's holder is in proto chain
9034 "r = { __proto__: o };"
9036 "for (var i = 0; i < 7; i++) {"
9039 CHECK_EQ(239, value->Int32Value());
9043 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9044 v8::HandleScope scope;
9045 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9046 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9047 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9048 templ_p->SetAccessor(v8_str("y"), Return239);
9050 LocalContext context;
9051 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9052 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9054 // Check the case when receiver and interceptor's holder
9055 // are the same objects.
9056 v8::Handle<Value> value = CompileRun(
9059 "for (var i = 0; i < 7; i++) {"
9060 " result = o.x + o.y;"
9062 CHECK_EQ(239 + 42, value->Int32Value());
9064 // Check the case when interceptor's holder is in proto chain
9067 "r = { __proto__: o };"
9069 "for (var i = 0; i < 7; i++) {"
9070 " result = r.x + r.y;"
9072 CHECK_EQ(239 + 42, value->Int32Value());
9076 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9077 v8::HandleScope scope;
9078 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9079 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9080 templ->SetAccessor(v8_str("y"), Return239);
9082 LocalContext context;
9083 context->Global()->Set(v8_str("o"), templ->NewInstance());
9085 v8::Handle<Value> value = CompileRun(
9086 "fst = new Object(); fst.__proto__ = o;"
9087 "snd = new Object(); snd.__proto__ = fst;"
9089 "for (var i = 0; i < 7; i++) {"
9094 "for (var i = 0; i < 7; i++) {"
9097 "result + result1");
9098 CHECK_EQ(239 + 42, value->Int32Value());
9102 // Test the case when we stored callback into
9103 // a stub, but interceptor produced value on its own.
9104 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9105 v8::HandleScope scope;
9106 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9107 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9108 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9109 templ_p->SetAccessor(v8_str("y"), Return239);
9111 LocalContext context;
9112 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9113 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9115 v8::Handle<Value> value = CompileRun(
9117 "for (var i = 0; i < 7; i++) {"
9119 // Now it should be ICed and keep a reference to x defined on p
9122 "for (var i = 0; i < 7; i++) {"
9126 CHECK_EQ(42 * 7, value->Int32Value());
9130 // Test the case when we stored callback into
9131 // a stub, but it got invalidated later on.
9132 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9133 v8::HandleScope scope;
9134 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9135 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9136 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9137 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9139 LocalContext context;
9140 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9141 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9143 v8::Handle<Value> value = CompileRun(
9144 "inbetween = new Object();"
9145 "o.__proto__ = inbetween;"
9146 "inbetween.__proto__ = p;"
9147 "for (var i = 0; i < 10; i++) {"
9149 // Now it should be ICed and keep a reference to y defined on p
9153 "for (var i = 0; i < 10; i++) {"
9157 CHECK_EQ(42 * 10, value->Int32Value());
9161 // Test the case when we stored callback into
9162 // a stub, but it got invalidated later on due to override on
9163 // global object which is between interceptor and callbacks' holders.
9164 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9165 v8::HandleScope scope;
9166 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9167 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9168 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9169 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9171 LocalContext context;
9172 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9173 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9175 v8::Handle<Value> value = CompileRun(
9176 "o.__proto__ = this;"
9177 "this.__proto__ = p;"
9178 "for (var i = 0; i < 10; i++) {"
9179 " if (o.y != 239) throw 'oops: ' + o.y;"
9180 // Now it should be ICed and keep a reference to y defined on p
9184 "for (var i = 0; i < 10; i++) {"
9188 CHECK_EQ(42 * 10, value->Int32Value());
9192 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9193 const AccessorInfo& info) {
9194 ApiTestFuzzer::Fuzz();
9195 CHECK(v8_str("x")->Equals(name));
9196 return v8::Integer::New(0);
9200 THREADED_TEST(InterceptorReturningZero) {
9201 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9202 "o.x == undefined ? 1 : 0",
9207 static v8::Handle<Value> InterceptorStoreICSetter(
9208 Local<String> key, Local<Value> value, const AccessorInfo&) {
9209 CHECK(v8_str("x")->Equals(key));
9210 CHECK_EQ(42, value->Int32Value());
9215 // This test should hit the store IC for the interceptor case.
9216 THREADED_TEST(InterceptorStoreIC) {
9217 v8::HandleScope scope;
9218 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9219 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
9220 InterceptorStoreICSetter,
9221 0, 0, 0, v8_str("data"));
9222 LocalContext context;
9223 context->Global()->Set(v8_str("o"), templ->NewInstance());
9225 "for (var i = 0; i < 1000; i++) {"
9231 THREADED_TEST(InterceptorStoreICWithNoSetter) {
9232 v8::HandleScope scope;
9233 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9234 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9235 LocalContext context;
9236 context->Global()->Set(v8_str("o"), templ->NewInstance());
9237 v8::Handle<Value> value = CompileRun(
9238 "for (var i = 0; i < 1000; i++) {"
9242 CHECK_EQ(239 + 42, value->Int32Value());
9248 v8::Handle<Value> call_ic_function;
9249 v8::Handle<Value> call_ic_function2;
9250 v8::Handle<Value> call_ic_function3;
9252 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9253 const AccessorInfo& info) {
9254 ApiTestFuzzer::Fuzz();
9255 CHECK(v8_str("x")->Equals(name));
9256 return call_ic_function;
9260 // This test should hit the call IC for the interceptor case.
9261 THREADED_TEST(InterceptorCallIC) {
9262 v8::HandleScope scope;
9263 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9264 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9265 LocalContext context;
9266 context->Global()->Set(v8_str("o"), templ->NewInstance());
9268 v8_compile("function f(x) { return x + 1; }; f")->Run();
9269 v8::Handle<Value> value = CompileRun(
9271 "for (var i = 0; i < 1000; i++) {"
9272 " result = o.x(41);"
9274 CHECK_EQ(42, value->Int32Value());
9278 // This test checks that if interceptor doesn't provide
9279 // a value, we can fetch regular value.
9280 THREADED_TEST(InterceptorCallICSeesOthers) {
9281 v8::HandleScope scope;
9282 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9283 templ->SetNamedPropertyHandler(NoBlockGetterX);
9284 LocalContext context;
9285 context->Global()->Set(v8_str("o"), templ->NewInstance());
9286 v8::Handle<Value> value = CompileRun(
9287 "o.x = function f(x) { return x + 1; };"
9289 "for (var i = 0; i < 7; i++) {"
9290 " result = o.x(41);"
9292 CHECK_EQ(42, value->Int32Value());
9296 static v8::Handle<Value> call_ic_function4;
9297 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9298 const AccessorInfo& info) {
9299 ApiTestFuzzer::Fuzz();
9300 CHECK(v8_str("x")->Equals(name));
9301 return call_ic_function4;
9305 // This test checks that if interceptor provides a function,
9306 // even if we cached shadowed variant, interceptor's function
9308 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9309 v8::HandleScope scope;
9310 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9311 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9312 LocalContext context;
9313 context->Global()->Set(v8_str("o"), templ->NewInstance());
9315 v8_compile("function f(x) { return x - 1; }; f")->Run();
9316 v8::Handle<Value> value = CompileRun(
9317 "o.__proto__.x = function(x) { return x + 1; };"
9319 "for (var i = 0; i < 1000; i++) {"
9320 " result = o.x(42);"
9322 CHECK_EQ(41, value->Int32Value());
9326 // Test the case when we stored cacheable lookup into
9327 // a stub, but it got invalidated later on
9328 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9329 v8::HandleScope scope;
9330 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9331 templ->SetNamedPropertyHandler(NoBlockGetterX);
9332 LocalContext context;
9333 context->Global()->Set(v8_str("o"), templ->NewInstance());
9334 v8::Handle<Value> value = CompileRun(
9335 "proto1 = new Object();"
9336 "proto2 = new Object();"
9337 "o.__proto__ = proto1;"
9338 "proto1.__proto__ = proto2;"
9339 "proto2.y = function(x) { return x + 1; };"
9340 // Invoke it many times to compile a stub
9341 "for (var i = 0; i < 7; i++) {"
9344 "proto1.y = function(x) { return x - 1; };"
9346 "for (var i = 0; i < 7; i++) {"
9347 " result += o.y(42);"
9349 CHECK_EQ(41 * 7, value->Int32Value());
9353 // This test checks that if interceptor doesn't provide a function,
9354 // cached constant function is used
9355 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9356 v8::HandleScope scope;
9357 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9358 templ->SetNamedPropertyHandler(NoBlockGetterX);
9359 LocalContext context;
9360 context->Global()->Set(v8_str("o"), templ->NewInstance());
9361 v8::Handle<Value> value = CompileRun(
9362 "function inc(x) { return x + 1; };"
9366 "for (var i = 0; i < 1000; i++) {"
9367 " result = o.x(42);"
9369 CHECK_EQ(43, value->Int32Value());
9373 static v8::Handle<Value> call_ic_function5;
9374 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9375 const AccessorInfo& info) {
9376 ApiTestFuzzer::Fuzz();
9377 if (v8_str("x")->Equals(name))
9378 return call_ic_function5;
9380 return Local<Value>();
9384 // This test checks that if interceptor provides a function,
9385 // even if we cached constant function, interceptor's function
9387 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9388 v8::HandleScope scope;
9389 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9390 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9391 LocalContext context;
9392 context->Global()->Set(v8_str("o"), templ->NewInstance());
9394 v8_compile("function f(x) { return x - 1; }; f")->Run();
9395 v8::Handle<Value> value = CompileRun(
9396 "function inc(x) { return x + 1; };"
9400 "for (var i = 0; i < 1000; i++) {"
9401 " result = o.x(42);"
9403 CHECK_EQ(41, value->Int32Value());
9407 static v8::Handle<Value> call_ic_function6;
9408 static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9409 const AccessorInfo& info) {
9410 ApiTestFuzzer::Fuzz();
9411 if (v8_str("x")->Equals(name))
9412 return call_ic_function6;
9414 return Local<Value>();
9418 // Same test as above, except the code is wrapped in a function
9419 // to test the optimized compiler.
9420 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9421 i::FLAG_allow_natives_syntax = true;
9422 v8::HandleScope scope;
9423 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9424 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9425 LocalContext context;
9426 context->Global()->Set(v8_str("o"), templ->NewInstance());
9428 v8_compile("function f(x) { return x - 1; }; f")->Run();
9429 v8::Handle<Value> value = CompileRun(
9430 "function inc(x) { return x + 1; };"
9435 " for (var i = 0; i < 1000; i++) {"
9436 " result = o.x(42);"
9443 "%OptimizeFunctionOnNextCall(test);"
9445 CHECK_EQ(41, value->Int32Value());
9449 // Test the case when we stored constant function into
9450 // a stub, but it got invalidated later on
9451 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9452 v8::HandleScope scope;
9453 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9454 templ->SetNamedPropertyHandler(NoBlockGetterX);
9455 LocalContext context;
9456 context->Global()->Set(v8_str("o"), templ->NewInstance());
9457 v8::Handle<Value> value = CompileRun(
9458 "function inc(x) { return x + 1; };"
9460 "proto1 = new Object();"
9461 "proto2 = new Object();"
9462 "o.__proto__ = proto1;"
9463 "proto1.__proto__ = proto2;"
9465 // Invoke it many times to compile a stub
9466 "for (var i = 0; i < 7; i++) {"
9469 "proto1.y = function(x) { return x - 1; };"
9471 "for (var i = 0; i < 7; i++) {"
9472 " result += o.y(42);"
9474 CHECK_EQ(41 * 7, value->Int32Value());
9478 // Test the case when we stored constant function into
9479 // a stub, but it got invalidated later on due to override on
9480 // global object which is between interceptor and constant function' holders.
9481 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9482 v8::HandleScope scope;
9483 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9484 templ->SetNamedPropertyHandler(NoBlockGetterX);
9485 LocalContext context;
9486 context->Global()->Set(v8_str("o"), templ->NewInstance());
9487 v8::Handle<Value> value = CompileRun(
9488 "function inc(x) { return x + 1; };"
9490 "o.__proto__ = this;"
9491 "this.__proto__.y = inc;"
9492 // Invoke it many times to compile a stub
9493 "for (var i = 0; i < 7; i++) {"
9494 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9496 "this.y = function(x) { return x - 1; };"
9498 "for (var i = 0; i < 7; i++) {"
9499 " result += o.y(42);"
9501 CHECK_EQ(41 * 7, value->Int32Value());
9505 // Test the case when actual function to call sits on global object.
9506 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9507 v8::HandleScope scope;
9508 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9509 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9511 LocalContext context;
9512 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9514 v8::Handle<Value> value = CompileRun(
9516 " o.__proto__ = this;"
9517 " for (var i = 0; i < 10; i++) {"
9518 " var v = o.parseFloat('239');"
9519 " if (v != 239) throw v;"
9520 // Now it should be ICed and keep a reference to parseFloat.
9523 " for (var i = 0; i < 10; i++) {"
9524 " result += o.parseFloat('239');"
9530 CHECK_EQ(239 * 10, value->Int32Value());
9533 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9534 const AccessorInfo& info) {
9535 ApiTestFuzzer::Fuzz();
9536 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9538 if ((*call_count) % 20 == 0) {
9539 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
9541 return v8::Handle<Value>();
9544 static v8::Handle<Value> FastApiCallback_TrivialSignature(
9545 const v8::Arguments& args) {
9546 ApiTestFuzzer::Fuzz();
9547 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9548 CHECK_EQ(isolate, args.GetIsolate());
9549 CHECK_EQ(args.This(), args.Holder());
9550 CHECK(args.Data()->Equals(v8_str("method_data")));
9551 return v8::Integer::New(args[0]->Int32Value() + 1);
9554 static v8::Handle<Value> FastApiCallback_SimpleSignature(
9555 const v8::Arguments& args) {
9556 ApiTestFuzzer::Fuzz();
9557 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9558 CHECK_EQ(isolate, args.GetIsolate());
9559 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9560 CHECK(args.Data()->Equals(v8_str("method_data")));
9561 // Note, we're using HasRealNamedProperty instead of Has to avoid
9562 // invoking the interceptor again.
9563 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9564 return v8::Integer::New(args[0]->Int32Value() + 1);
9567 // Helper to maximize the odds of object moving.
9568 static void GenerateSomeGarbage() {
9571 "for (var i = 0; i < 1000; i++) {"
9572 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9574 "garbage = undefined;");
9578 v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9579 static int count = 0;
9580 if (count++ % 3 == 0) {
9581 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9582 // This should move the stub
9583 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9585 return v8::Handle<v8::Value>();
9589 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9590 v8::HandleScope scope;
9591 LocalContext context;
9592 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9593 nativeobject_templ->Set("callback",
9594 v8::FunctionTemplate::New(DirectApiCallback));
9595 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9596 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9597 // call the api function multiple times to ensure direct call stub creation.
9600 " for (var i = 1; i <= 30; i++) {"
9601 " nativeobject.callback();"
9608 v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9609 return v8::ThrowException(v8_str("g"));
9613 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9614 v8::HandleScope scope;
9615 LocalContext context;
9616 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9617 nativeobject_templ->Set("callback",
9618 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9619 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9620 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9621 // call the api function multiple times to ensure direct call stub creation.
9622 v8::Handle<Value> result = CompileRun(
9625 " for (var i = 1; i <= 5; i++) {"
9626 " try { nativeobject.callback(); } catch (e) { result += e; }"
9630 CHECK_EQ(v8_str("ggggg"), result);
9634 v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9635 const v8::AccessorInfo& info) {
9636 if (++p_getter_count % 3 == 0) {
9637 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9638 GenerateSomeGarbage();
9640 return v8::Handle<v8::Value>();
9644 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9645 v8::HandleScope scope;
9646 LocalContext context;
9647 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9648 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9649 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9653 " for (var i = 0; i < 30; i++) o1.p1;"
9656 CHECK_EQ(30, p_getter_count);
9660 v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9661 Local<String> name, const v8::AccessorInfo& info) {
9662 return v8::ThrowException(v8_str("g"));
9666 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9667 v8::HandleScope scope;
9668 LocalContext context;
9669 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9670 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9671 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9672 v8::Handle<Value> result = CompileRun(
9674 "for (var i = 0; i < 5; i++) {"
9675 " try { o1.p1; } catch (e) { result += e; }"
9678 CHECK_EQ(v8_str("ggggg"), result);
9682 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9683 int interceptor_call_count = 0;
9684 v8::HandleScope scope;
9685 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9686 v8::Handle<v8::FunctionTemplate> method_templ =
9687 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9688 v8_str("method_data"),
9689 v8::Handle<v8::Signature>());
9690 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9691 proto_templ->Set(v8_str("method"), method_templ);
9692 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9693 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9694 NULL, NULL, NULL, NULL,
9695 v8::External::Wrap(&interceptor_call_count));
9696 LocalContext context;
9697 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9698 GenerateSomeGarbage();
9699 context->Global()->Set(v8_str("o"), fun->NewInstance());
9702 "for (var i = 0; i < 100; i++) {"
9703 " result = o.method(41);"
9705 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9706 CHECK_EQ(100, interceptor_call_count);
9709 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9710 int interceptor_call_count = 0;
9711 v8::HandleScope scope;
9712 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9713 v8::Handle<v8::FunctionTemplate> method_templ =
9714 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9715 v8_str("method_data"),
9716 v8::Signature::New(fun_templ));
9717 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9718 proto_templ->Set(v8_str("method"), method_templ);
9719 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9720 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9721 NULL, NULL, NULL, NULL,
9722 v8::External::Wrap(&interceptor_call_count));
9723 LocalContext context;
9724 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9725 GenerateSomeGarbage();
9726 context->Global()->Set(v8_str("o"), fun->NewInstance());
9729 "var receiver = {};"
9730 "receiver.__proto__ = o;"
9732 "for (var i = 0; i < 100; i++) {"
9733 " result = receiver.method(41);"
9735 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9736 CHECK_EQ(100, interceptor_call_count);
9739 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9740 int interceptor_call_count = 0;
9741 v8::HandleScope scope;
9742 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9743 v8::Handle<v8::FunctionTemplate> method_templ =
9744 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9745 v8_str("method_data"),
9746 v8::Signature::New(fun_templ));
9747 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9748 proto_templ->Set(v8_str("method"), method_templ);
9749 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9750 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9751 NULL, NULL, NULL, NULL,
9752 v8::External::Wrap(&interceptor_call_count));
9753 LocalContext context;
9754 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9755 GenerateSomeGarbage();
9756 context->Global()->Set(v8_str("o"), fun->NewInstance());
9759 "var receiver = {};"
9760 "receiver.__proto__ = o;"
9762 "var saved_result = 0;"
9763 "for (var i = 0; i < 100; i++) {"
9764 " result = receiver.method(41);"
9766 " saved_result = result;"
9767 " receiver = {method: function(x) { return x - 1 }};"
9770 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9771 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9772 CHECK_GE(interceptor_call_count, 50);
9775 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9776 int interceptor_call_count = 0;
9777 v8::HandleScope scope;
9778 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9779 v8::Handle<v8::FunctionTemplate> method_templ =
9780 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9781 v8_str("method_data"),
9782 v8::Signature::New(fun_templ));
9783 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9784 proto_templ->Set(v8_str("method"), method_templ);
9785 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9786 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9787 NULL, NULL, NULL, NULL,
9788 v8::External::Wrap(&interceptor_call_count));
9789 LocalContext context;
9790 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9791 GenerateSomeGarbage();
9792 context->Global()->Set(v8_str("o"), fun->NewInstance());
9795 "var receiver = {};"
9796 "receiver.__proto__ = o;"
9798 "var saved_result = 0;"
9799 "for (var i = 0; i < 100; i++) {"
9800 " result = receiver.method(41);"
9802 " saved_result = result;"
9803 " o.method = function(x) { return x - 1 };"
9806 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9807 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9808 CHECK_GE(interceptor_call_count, 50);
9811 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9812 int interceptor_call_count = 0;
9813 v8::HandleScope scope;
9814 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9815 v8::Handle<v8::FunctionTemplate> method_templ =
9816 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9817 v8_str("method_data"),
9818 v8::Signature::New(fun_templ));
9819 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9820 proto_templ->Set(v8_str("method"), method_templ);
9821 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9822 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9823 NULL, NULL, NULL, NULL,
9824 v8::External::Wrap(&interceptor_call_count));
9825 LocalContext context;
9826 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9827 GenerateSomeGarbage();
9828 context->Global()->Set(v8_str("o"), fun->NewInstance());
9829 v8::TryCatch try_catch;
9832 "var receiver = {};"
9833 "receiver.__proto__ = o;"
9835 "var saved_result = 0;"
9836 "for (var i = 0; i < 100; i++) {"
9837 " result = receiver.method(41);"
9839 " saved_result = result;"
9843 CHECK(try_catch.HasCaught());
9844 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9845 try_catch.Exception()->ToString());
9846 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9847 CHECK_GE(interceptor_call_count, 50);
9850 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9851 int interceptor_call_count = 0;
9852 v8::HandleScope scope;
9853 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9854 v8::Handle<v8::FunctionTemplate> method_templ =
9855 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9856 v8_str("method_data"),
9857 v8::Signature::New(fun_templ));
9858 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9859 proto_templ->Set(v8_str("method"), method_templ);
9860 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9861 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9862 NULL, NULL, NULL, NULL,
9863 v8::External::Wrap(&interceptor_call_count));
9864 LocalContext context;
9865 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9866 GenerateSomeGarbage();
9867 context->Global()->Set(v8_str("o"), fun->NewInstance());
9868 v8::TryCatch try_catch;
9871 "var receiver = {};"
9872 "receiver.__proto__ = o;"
9874 "var saved_result = 0;"
9875 "for (var i = 0; i < 100; i++) {"
9876 " result = receiver.method(41);"
9878 " saved_result = result;"
9879 " receiver = {method: receiver.method};"
9882 CHECK(try_catch.HasCaught());
9883 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9884 try_catch.Exception()->ToString());
9885 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9886 CHECK_GE(interceptor_call_count, 50);
9889 THREADED_TEST(CallICFastApi_TrivialSignature) {
9890 v8::HandleScope scope;
9891 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9892 v8::Handle<v8::FunctionTemplate> method_templ =
9893 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9894 v8_str("method_data"),
9895 v8::Handle<v8::Signature>());
9896 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9897 proto_templ->Set(v8_str("method"), method_templ);
9898 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9900 LocalContext context;
9901 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9902 GenerateSomeGarbage();
9903 context->Global()->Set(v8_str("o"), fun->NewInstance());
9906 "for (var i = 0; i < 100; i++) {"
9907 " result = o.method(41);"
9910 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9913 THREADED_TEST(CallICFastApi_SimpleSignature) {
9914 v8::HandleScope scope;
9915 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9916 v8::Handle<v8::FunctionTemplate> method_templ =
9917 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9918 v8_str("method_data"),
9919 v8::Signature::New(fun_templ));
9920 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9921 proto_templ->Set(v8_str("method"), method_templ);
9922 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9923 CHECK(!templ.IsEmpty());
9924 LocalContext context;
9925 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9926 GenerateSomeGarbage();
9927 context->Global()->Set(v8_str("o"), fun->NewInstance());
9930 "var receiver = {};"
9931 "receiver.__proto__ = o;"
9933 "for (var i = 0; i < 100; i++) {"
9934 " result = receiver.method(41);"
9937 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9940 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9941 v8::HandleScope scope;
9942 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9943 v8::Handle<v8::FunctionTemplate> method_templ =
9944 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9945 v8_str("method_data"),
9946 v8::Signature::New(fun_templ));
9947 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9948 proto_templ->Set(v8_str("method"), method_templ);
9949 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9950 CHECK(!templ.IsEmpty());
9951 LocalContext context;
9952 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9953 GenerateSomeGarbage();
9954 context->Global()->Set(v8_str("o"), fun->NewInstance());
9957 "var receiver = {};"
9958 "receiver.__proto__ = o;"
9960 "var saved_result = 0;"
9961 "for (var i = 0; i < 100; i++) {"
9962 " result = receiver.method(41);"
9964 " saved_result = result;"
9965 " receiver = {method: function(x) { return x - 1 }};"
9968 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9969 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9972 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9973 v8::HandleScope scope;
9974 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9975 v8::Handle<v8::FunctionTemplate> method_templ =
9976 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9977 v8_str("method_data"),
9978 v8::Signature::New(fun_templ));
9979 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9980 proto_templ->Set(v8_str("method"), method_templ);
9981 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9982 CHECK(!templ.IsEmpty());
9983 LocalContext context;
9984 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9985 GenerateSomeGarbage();
9986 context->Global()->Set(v8_str("o"), fun->NewInstance());
9987 v8::TryCatch try_catch;
9990 "var receiver = {};"
9991 "receiver.__proto__ = o;"
9993 "var saved_result = 0;"
9994 "for (var i = 0; i < 100; i++) {"
9995 " result = receiver.method(41);"
9997 " saved_result = result;"
10001 CHECK(try_catch.HasCaught());
10002 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10003 try_catch.Exception()->ToString());
10004 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10008 v8::Handle<Value> keyed_call_ic_function;
10010 static v8::Handle<Value> InterceptorKeyedCallICGetter(
10011 Local<String> name, const AccessorInfo& info) {
10012 ApiTestFuzzer::Fuzz();
10013 if (v8_str("x")->Equals(name)) {
10014 return keyed_call_ic_function;
10016 return v8::Handle<Value>();
10020 // Test the case when we stored cacheable lookup into
10021 // a stub, but the function name changed (to another cacheable function).
10022 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10023 v8::HandleScope scope;
10024 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10025 templ->SetNamedPropertyHandler(NoBlockGetterX);
10026 LocalContext context;
10027 context->Global()->Set(v8_str("o"), templ->NewInstance());
10029 "proto = new Object();"
10030 "proto.y = function(x) { return x + 1; };"
10031 "proto.z = function(x) { return x - 1; };"
10032 "o.__proto__ = proto;"
10034 "var method = 'y';"
10035 "for (var i = 0; i < 10; i++) {"
10036 " if (i == 5) { method = 'z'; };"
10037 " result += o[method](41);"
10039 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10043 // Test the case when we stored cacheable lookup into
10044 // a stub, but the function name changed (and the new function is present
10045 // both before and after the interceptor in the prototype chain).
10046 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10047 v8::HandleScope scope;
10048 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10049 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10050 LocalContext context;
10051 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10052 keyed_call_ic_function =
10053 v8_compile("function f(x) { return x - 1; }; f")->Run();
10055 "o = new Object();"
10056 "proto2 = new Object();"
10057 "o.y = function(x) { return x + 1; };"
10058 "proto2.y = function(x) { return x + 2; };"
10059 "o.__proto__ = proto1;"
10060 "proto1.__proto__ = proto2;"
10062 "var method = 'x';"
10063 "for (var i = 0; i < 10; i++) {"
10064 " if (i == 5) { method = 'y'; };"
10065 " result += o[method](41);"
10067 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10071 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10072 // on the global object.
10073 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10074 v8::HandleScope scope;
10075 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10076 templ->SetNamedPropertyHandler(NoBlockGetterX);
10077 LocalContext context;
10078 context->Global()->Set(v8_str("o"), templ->NewInstance());
10080 "function inc(x) { return x + 1; };"
10082 "function dec(x) { return x - 1; };"
10084 "o.__proto__ = this;"
10085 "this.__proto__.x = inc;"
10086 "this.__proto__.y = dec;"
10088 "var method = 'x';"
10089 "for (var i = 0; i < 10; i++) {"
10090 " if (i == 5) { method = 'y'; };"
10091 " result += o[method](41);"
10093 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10097 // Test the case when actual function to call sits on global object.
10098 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10099 v8::HandleScope scope;
10100 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10101 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10102 LocalContext context;
10103 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10106 "function len(x) { return x.length; };"
10107 "o.__proto__ = this;"
10108 "var m = 'parseFloat';"
10110 "for (var i = 0; i < 10; i++) {"
10113 " saved_result = result;"
10115 " result = o[m]('239');"
10117 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10118 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10121 // Test the map transition before the interceptor.
10122 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10123 v8::HandleScope scope;
10124 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10125 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10126 LocalContext context;
10127 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10130 "var o = new Object();"
10131 "o.__proto__ = proto;"
10132 "o.method = function(x) { return x + 1; };"
10133 "var m = 'method';"
10135 "for (var i = 0; i < 10; i++) {"
10136 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10137 " result += o[m](41);"
10139 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10143 // Test the map transition after the interceptor.
10144 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10145 v8::HandleScope scope;
10146 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10147 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10148 LocalContext context;
10149 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10152 "var proto = new Object();"
10153 "o.__proto__ = proto;"
10154 "proto.method = function(x) { return x + 1; };"
10155 "var m = 'method';"
10157 "for (var i = 0; i < 10; i++) {"
10158 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10159 " result += o[m](41);"
10161 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10165 static int interceptor_call_count = 0;
10167 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10168 const AccessorInfo& info) {
10169 ApiTestFuzzer::Fuzz();
10170 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10171 return call_ic_function2;
10173 return v8::Handle<Value>();
10177 // This test should hit load and call ICs for the interceptor case.
10178 // Once in a while, the interceptor will reply that a property was not
10179 // found in which case we should get a reference error.
10180 THREADED_TEST(InterceptorICReferenceErrors) {
10181 v8::HandleScope scope;
10182 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10183 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10184 LocalContext context(0, templ, v8::Handle<Value>());
10185 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10186 v8::Handle<Value> value = CompileRun(
10188 " for (var i = 0; i < 1000; i++) {"
10189 " try { x; } catch(e) { return true; }"
10194 CHECK_EQ(true, value->BooleanValue());
10195 interceptor_call_count = 0;
10196 value = CompileRun(
10198 " for (var i = 0; i < 1000; i++) {"
10199 " try { x(42); } catch(e) { return true; }"
10204 CHECK_EQ(true, value->BooleanValue());
10208 static int interceptor_ic_exception_get_count = 0;
10210 static v8::Handle<Value> InterceptorICExceptionGetter(
10211 Local<String> name,
10212 const AccessorInfo& info) {
10213 ApiTestFuzzer::Fuzz();
10214 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10215 return call_ic_function3;
10217 if (interceptor_ic_exception_get_count == 20) {
10218 return v8::ThrowException(v8_num(42));
10220 // Do not handle get for properties other than x.
10221 return v8::Handle<Value>();
10224 // Test interceptor load/call IC where the interceptor throws an
10225 // exception once in a while.
10226 THREADED_TEST(InterceptorICGetterExceptions) {
10227 interceptor_ic_exception_get_count = 0;
10228 v8::HandleScope scope;
10229 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10230 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10231 LocalContext context(0, templ, v8::Handle<Value>());
10232 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10233 v8::Handle<Value> value = CompileRun(
10235 " for (var i = 0; i < 100; i++) {"
10236 " try { x; } catch(e) { return true; }"
10241 CHECK_EQ(true, value->BooleanValue());
10242 interceptor_ic_exception_get_count = 0;
10243 value = CompileRun(
10245 " for (var i = 0; i < 100; i++) {"
10246 " try { x(42); } catch(e) { return true; }"
10251 CHECK_EQ(true, value->BooleanValue());
10255 static int interceptor_ic_exception_set_count = 0;
10257 static v8::Handle<Value> InterceptorICExceptionSetter(
10258 Local<String> key, Local<Value> value, const AccessorInfo&) {
10259 ApiTestFuzzer::Fuzz();
10260 if (++interceptor_ic_exception_set_count > 20) {
10261 return v8::ThrowException(v8_num(42));
10263 // Do not actually handle setting.
10264 return v8::Handle<Value>();
10267 // Test interceptor store IC where the interceptor throws an exception
10268 // once in a while.
10269 THREADED_TEST(InterceptorICSetterExceptions) {
10270 interceptor_ic_exception_set_count = 0;
10271 v8::HandleScope scope;
10272 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10273 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10274 LocalContext context(0, templ, v8::Handle<Value>());
10275 v8::Handle<Value> value = CompileRun(
10277 " for (var i = 0; i < 100; i++) {"
10278 " try { x = 42; } catch(e) { return true; }"
10283 CHECK_EQ(true, value->BooleanValue());
10287 // Test that we ignore null interceptors.
10288 THREADED_TEST(NullNamedInterceptor) {
10289 v8::HandleScope scope;
10290 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10291 templ->SetNamedPropertyHandler(0);
10292 LocalContext context;
10293 templ->Set("x", v8_num(42));
10294 v8::Handle<v8::Object> obj = templ->NewInstance();
10295 context->Global()->Set(v8_str("obj"), obj);
10296 v8::Handle<Value> value = CompileRun("obj.x");
10297 CHECK(value->IsInt32());
10298 CHECK_EQ(42, value->Int32Value());
10302 // Test that we ignore null interceptors.
10303 THREADED_TEST(NullIndexedInterceptor) {
10304 v8::HandleScope scope;
10305 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10306 templ->SetIndexedPropertyHandler(0);
10307 LocalContext context;
10308 templ->Set("42", v8_num(42));
10309 v8::Handle<v8::Object> obj = templ->NewInstance();
10310 context->Global()->Set(v8_str("obj"), obj);
10311 v8::Handle<Value> value = CompileRun("obj[42]");
10312 CHECK(value->IsInt32());
10313 CHECK_EQ(42, value->Int32Value());
10317 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10318 v8::HandleScope scope;
10319 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10320 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10322 env->Global()->Set(v8_str("obj"),
10323 templ->GetFunction()->NewInstance());
10324 ExpectTrue("obj.x === 42");
10325 ExpectTrue("!obj.propertyIsEnumerable('x')");
10329 static Handle<Value> ThrowingGetter(Local<String> name,
10330 const AccessorInfo& info) {
10331 ApiTestFuzzer::Fuzz();
10332 ThrowException(Handle<Value>());
10333 return Undefined();
10337 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10339 LocalContext context;
10341 Local<FunctionTemplate> templ = FunctionTemplate::New();
10342 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10343 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10345 Local<Object> instance = templ->GetFunction()->NewInstance();
10347 Local<Object> another = Object::New();
10348 another->SetPrototype(instance);
10350 Local<Object> with_js_getter = CompileRun(
10352 "o.__defineGetter__('f', function() { throw undefined; });\n"
10353 "o\n").As<Object>();
10354 CHECK(!with_js_getter.IsEmpty());
10356 TryCatch try_catch;
10358 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10359 CHECK(try_catch.HasCaught());
10361 CHECK(result.IsEmpty());
10363 result = another->GetRealNamedProperty(v8_str("f"));
10364 CHECK(try_catch.HasCaught());
10366 CHECK(result.IsEmpty());
10368 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10369 CHECK(try_catch.HasCaught());
10371 CHECK(result.IsEmpty());
10373 result = another->Get(v8_str("f"));
10374 CHECK(try_catch.HasCaught());
10376 CHECK(result.IsEmpty());
10378 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10379 CHECK(try_catch.HasCaught());
10381 CHECK(result.IsEmpty());
10383 result = with_js_getter->Get(v8_str("f"));
10384 CHECK(try_catch.HasCaught());
10386 CHECK(result.IsEmpty());
10390 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10391 TryCatch try_catch;
10392 // Verboseness is important: it triggers message delivery which can call into
10394 try_catch.SetVerbose(true);
10395 CompileRun("throw 'from JS';");
10396 CHECK(try_catch.HasCaught());
10397 CHECK(!i::Isolate::Current()->has_pending_exception());
10398 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10399 return Undefined();
10403 static int call_depth;
10406 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10407 TryCatch try_catch;
10411 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10412 if (--call_depth) CompileRun("throw 'ThrowInJS';");
10416 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10417 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
10421 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10422 Handle<String> errorMessageString = message->Get();
10423 CHECK(!errorMessageString.IsEmpty());
10424 message->GetStackTrace();
10425 message->GetScriptResourceName();
10428 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10430 LocalContext context;
10432 Local<Function> func =
10433 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10434 context->Global()->Set(v8_str("func"), func);
10436 MessageCallback callbacks[] =
10437 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10438 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10439 MessageCallback callback = callbacks[i];
10440 if (callback != NULL) {
10441 V8::AddMessageListener(callback);
10443 // Some small number to control number of times message handler should
10444 // throw an exception.
10447 "var thrown = false;\n"
10448 "try { func(); } catch(e) { thrown = true; }\n"
10450 if (callback != NULL) {
10451 V8::RemoveMessageListeners(callback);
10457 static v8::Handle<Value> ParentGetter(Local<String> name,
10458 const AccessorInfo& info) {
10459 ApiTestFuzzer::Fuzz();
10464 static v8::Handle<Value> ChildGetter(Local<String> name,
10465 const AccessorInfo& info) {
10466 ApiTestFuzzer::Fuzz();
10471 THREADED_TEST(Overriding) {
10472 i::FLAG_es5_readonly = true;
10473 v8::HandleScope scope;
10474 LocalContext context;
10476 // Parent template.
10477 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10478 Local<ObjectTemplate> parent_instance_templ =
10479 parent_templ->InstanceTemplate();
10480 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10482 // Template that inherits from the parent template.
10483 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10484 Local<ObjectTemplate> child_instance_templ =
10485 child_templ->InstanceTemplate();
10486 child_templ->Inherit(parent_templ);
10487 // Override 'f'. The child version of 'f' should get called for child
10489 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10490 // Add 'g' twice. The 'g' added last should get called for instances.
10491 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10492 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10494 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10495 // so 'h' can be shadowed on the instance object.
10496 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10497 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10498 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10500 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10501 // but the attribute does not have effect because it is duplicated with
10503 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10504 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10508 // Instantiate the child template.
10509 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10511 // Check that the child function overrides the parent one.
10512 context->Global()->Set(v8_str("o"), instance);
10513 Local<Value> value = v8_compile("o.f")->Run();
10514 // Check that the 'g' that was added last is hit.
10515 CHECK_EQ(42, value->Int32Value());
10516 value = v8_compile("o.g")->Run();
10517 CHECK_EQ(42, value->Int32Value());
10519 // Check that 'h' cannot be shadowed.
10520 value = v8_compile("o.h = 3; o.h")->Run();
10521 CHECK_EQ(1, value->Int32Value());
10523 // Check that 'i' cannot be shadowed or changed.
10524 value = v8_compile("o.i = 3; o.i")->Run();
10525 CHECK_EQ(42, value->Int32Value());
10529 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10530 ApiTestFuzzer::Fuzz();
10531 return v8::Boolean::New(args.IsConstructCall());
10535 THREADED_TEST(IsConstructCall) {
10536 v8::HandleScope scope;
10538 // Function template with call handler.
10539 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10540 templ->SetCallHandler(IsConstructHandler);
10542 LocalContext context;
10544 context->Global()->Set(v8_str("f"), templ->GetFunction());
10545 Local<Value> value = v8_compile("f()")->Run();
10546 CHECK(!value->BooleanValue());
10547 value = v8_compile("new f()")->Run();
10548 CHECK(value->BooleanValue());
10552 THREADED_TEST(ObjectProtoToString) {
10553 v8::HandleScope scope;
10554 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10555 templ->SetClassName(v8_str("MyClass"));
10557 LocalContext context;
10559 Local<String> customized_tostring = v8_str("customized toString");
10561 // Replace Object.prototype.toString
10562 v8_compile("Object.prototype.toString = function() {"
10563 " return 'customized toString';"
10566 // Normal ToString call should call replaced Object.prototype.toString
10567 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10568 Local<String> value = instance->ToString();
10569 CHECK(value->IsString() && value->Equals(customized_tostring));
10571 // ObjectProtoToString should not call replace toString function.
10572 value = instance->ObjectProtoToString();
10573 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10576 value = context->Global()->ObjectProtoToString();
10577 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10579 // Check ordinary object
10580 Local<Value> object = v8_compile("new Object()")->Run();
10581 value = object.As<v8::Object>()->ObjectProtoToString();
10582 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10586 THREADED_TEST(ObjectGetConstructorName) {
10587 v8::HandleScope scope;
10588 LocalContext context;
10589 v8_compile("function Parent() {};"
10590 "function Child() {};"
10591 "Child.prototype = new Parent();"
10592 "var outer = { inner: function() { } };"
10593 "var p = new Parent();"
10594 "var c = new Child();"
10595 "var x = new outer.inner();")->Run();
10597 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10598 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10599 v8_str("Parent")));
10601 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10602 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10605 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10606 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10607 v8_str("outer.inner")));
10611 bool ApiTestFuzzer::fuzzing_ = false;
10612 i::Semaphore* ApiTestFuzzer::all_tests_done_=
10613 i::OS::CreateSemaphore(0);
10614 int ApiTestFuzzer::active_tests_;
10615 int ApiTestFuzzer::tests_being_run_;
10616 int ApiTestFuzzer::current_;
10619 // We are in a callback and want to switch to another thread (if we
10620 // are currently running the thread fuzzing test).
10621 void ApiTestFuzzer::Fuzz() {
10622 if (!fuzzing_) return;
10623 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10624 test->ContextSwitch();
10628 // Let the next thread go. Since it is also waiting on the V8 lock it may
10629 // not start immediately.
10630 bool ApiTestFuzzer::NextThread() {
10631 int test_position = GetNextTestNumber();
10632 const char* test_name = RegisterThreadedTest::nth(current_)->name();
10633 if (test_position == current_) {
10635 printf("Stay with %s\n", test_name);
10638 if (kLogThreading) {
10639 printf("Switch from %s to %s\n",
10641 RegisterThreadedTest::nth(test_position)->name());
10643 current_ = test_position;
10644 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10649 void ApiTestFuzzer::Run() {
10650 // When it is our turn...
10653 // ... get the V8 lock and start running the test.
10657 // This test finished.
10660 // If it was the last then signal that fact.
10661 if (active_tests_ == 0) {
10662 all_tests_done_->Signal();
10664 // Otherwise select a new test and start that.
10670 static unsigned linear_congruential_generator;
10673 void ApiTestFuzzer::SetUp(PartOfTest part) {
10674 linear_congruential_generator = i::FLAG_testing_prng_seed;
10676 int count = RegisterThreadedTest::count();
10677 int start = count * part / (LAST_PART + 1);
10678 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10679 active_tests_ = tests_being_run_ = end - start + 1;
10680 for (int i = 0; i < tests_being_run_; i++) {
10681 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10683 for (int i = 0; i < active_tests_; i++) {
10684 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10689 static void CallTestNumber(int test_number) {
10690 (RegisterThreadedTest::nth(test_number)->callback())();
10694 void ApiTestFuzzer::RunAllTests() {
10695 // Set off the first test.
10698 // Wait till they are all done.
10699 all_tests_done_->Wait();
10703 int ApiTestFuzzer::GetNextTestNumber() {
10706 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10707 linear_congruential_generator *= 1664525u;
10708 linear_congruential_generator += 1013904223u;
10709 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10714 void ApiTestFuzzer::ContextSwitch() {
10715 // If the new thread is the same as the current thread there is nothing to do.
10716 if (NextThread()) {
10717 // Now it can start.
10718 v8::Unlocker unlocker;
10719 // Wait till someone starts us again.
10726 void ApiTestFuzzer::TearDown() {
10728 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10729 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10730 if (fuzzer != NULL) fuzzer->Join();
10735 // Lets not be needlessly self-referential.
10737 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
10738 ApiTestFuzzer::RunAllTests();
10739 ApiTestFuzzer::TearDown();
10743 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
10744 ApiTestFuzzer::RunAllTests();
10745 ApiTestFuzzer::TearDown();
10749 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
10750 ApiTestFuzzer::RunAllTests();
10751 ApiTestFuzzer::TearDown();
10755 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
10756 ApiTestFuzzer::RunAllTests();
10757 ApiTestFuzzer::TearDown();
10760 void ApiTestFuzzer::CallTest() {
10762 printf("Start test %d\n", test_number_);
10763 CallTestNumber(test_number_);
10765 printf("End test %d\n", test_number_);
10769 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10770 CHECK(v8::Locker::IsLocked());
10771 ApiTestFuzzer::Fuzz();
10772 v8::Unlocker unlocker;
10773 const char* code = "throw 7;";
10775 v8::Locker nested_locker;
10776 v8::HandleScope scope;
10777 v8::Handle<Value> exception;
10778 { v8::TryCatch try_catch;
10779 v8::Handle<Value> value = CompileRun(code);
10780 CHECK(value.IsEmpty());
10781 CHECK(try_catch.HasCaught());
10782 // Make sure to wrap the exception in a new handle because
10783 // the handle returned from the TryCatch is destroyed
10784 // when the TryCatch is destroyed.
10785 exception = Local<Value>::New(try_catch.Exception());
10787 return v8::ThrowException(exception);
10792 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10793 CHECK(v8::Locker::IsLocked());
10794 ApiTestFuzzer::Fuzz();
10795 v8::Unlocker unlocker;
10796 const char* code = "throw 7;";
10798 v8::Locker nested_locker;
10799 v8::HandleScope scope;
10800 v8::Handle<Value> value = CompileRun(code);
10801 CHECK(value.IsEmpty());
10802 return v8_str("foo");
10807 // These are locking tests that don't need to be run again
10808 // as part of the locking aggregation tests.
10809 TEST(NestedLockers) {
10811 CHECK(v8::Locker::IsLocked());
10812 v8::HandleScope scope;
10814 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10815 Local<Function> fun = fun_templ->GetFunction();
10816 env->Global()->Set(v8_str("throw_in_js"), fun);
10817 Local<Script> script = v8_compile("(function () {"
10825 CHECK_EQ(91, script->Run()->Int32Value());
10829 // These are locking tests that don't need to be run again
10830 // as part of the locking aggregation tests.
10831 TEST(NestedLockersNoTryCatch) {
10833 v8::HandleScope scope;
10835 Local<v8::FunctionTemplate> fun_templ =
10836 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10837 Local<Function> fun = fun_templ->GetFunction();
10838 env->Global()->Set(v8_str("throw_in_js"), fun);
10839 Local<Script> script = v8_compile("(function () {"
10847 CHECK_EQ(91, script->Run()->Int32Value());
10851 THREADED_TEST(RecursiveLocking) {
10854 v8::Locker locker2;
10855 CHECK(v8::Locker::IsLocked());
10860 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10861 ApiTestFuzzer::Fuzz();
10862 v8::Unlocker unlocker;
10863 return v8::Undefined();
10867 THREADED_TEST(LockUnlockLock) {
10870 v8::HandleScope scope;
10872 Local<v8::FunctionTemplate> fun_templ =
10873 v8::FunctionTemplate::New(UnlockForAMoment);
10874 Local<Function> fun = fun_templ->GetFunction();
10875 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10876 Local<Script> script = v8_compile("(function () {"
10877 " unlock_for_a_moment();"
10880 CHECK_EQ(42, script->Run()->Int32Value());
10884 v8::HandleScope scope;
10886 Local<v8::FunctionTemplate> fun_templ =
10887 v8::FunctionTemplate::New(UnlockForAMoment);
10888 Local<Function> fun = fun_templ->GetFunction();
10889 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10890 Local<Script> script = v8_compile("(function () {"
10891 " unlock_for_a_moment();"
10894 CHECK_EQ(42, script->Run()->Int32Value());
10899 static int GetGlobalObjectsCount() {
10900 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10902 i::HeapIterator it;
10903 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10904 if (object->IsJSGlobalObject()) count++;
10909 static void CheckSurvivingGlobalObjectsCount(int expected) {
10910 // We need to collect all garbage twice to be sure that everything
10911 // has been collected. This is because inline caches are cleared in
10912 // the first garbage collection but some of the maps have already
10913 // been marked at that point. Therefore some of the maps are not
10914 // collected until the second garbage collection.
10915 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10916 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10917 int count = GetGlobalObjectsCount();
10919 if (count != expected) HEAP->TracePathToGlobal();
10921 CHECK_EQ(expected, count);
10925 TEST(DontLeakGlobalObjects) {
10926 // Regression test for issues 1139850 and 1174891.
10928 v8::V8::Initialize();
10930 for (int i = 0; i < 5; i++) {
10931 { v8::HandleScope scope;
10932 LocalContext context;
10934 v8::V8::ContextDisposedNotification();
10935 CheckSurvivingGlobalObjectsCount(0);
10937 { v8::HandleScope scope;
10938 LocalContext context;
10939 v8_compile("Date")->Run();
10941 v8::V8::ContextDisposedNotification();
10942 CheckSurvivingGlobalObjectsCount(0);
10944 { v8::HandleScope scope;
10945 LocalContext context;
10946 v8_compile("/aaa/")->Run();
10948 v8::V8::ContextDisposedNotification();
10949 CheckSurvivingGlobalObjectsCount(0);
10951 { v8::HandleScope scope;
10952 const char* extension_list[] = { "v8/gc" };
10953 v8::ExtensionConfiguration extensions(1, extension_list);
10954 LocalContext context(&extensions);
10955 v8_compile("gc();")->Run();
10957 v8::V8::ContextDisposedNotification();
10958 CheckSurvivingGlobalObjectsCount(0);
10963 v8::Persistent<v8::Object> some_object;
10964 v8::Persistent<v8::Object> bad_handle;
10966 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10967 v8::HandleScope scope;
10968 bad_handle = v8::Persistent<v8::Object>::New(some_object);
10973 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10974 LocalContext context;
10976 v8::Persistent<v8::Object> handle1, handle2;
10978 v8::HandleScope scope;
10979 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10980 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10981 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10983 // Note: order is implementation dependent alas: currently
10984 // global handle nodes are processed by PostGarbageCollectionProcessing
10985 // in reverse allocation order, so if second allocated handle is deleted,
10986 // weak callback of the first handle would be able to 'reallocate' it.
10987 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10989 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10993 v8::Persistent<v8::Object> to_be_disposed;
10995 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10996 to_be_disposed.Dispose();
10997 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11002 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11003 LocalContext context;
11005 v8::Persistent<v8::Object> handle1, handle2;
11007 v8::HandleScope scope;
11008 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11009 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11011 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11012 to_be_disposed = handle2;
11013 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11016 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11020 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11021 v8::HandleScope scope;
11022 v8::Persistent<v8::Object>::New(v8::Object::New());
11027 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11028 LocalContext context;
11030 v8::Persistent<v8::Object> handle1, handle2, handle3;
11032 v8::HandleScope scope;
11033 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
11034 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11035 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11037 handle2.MakeWeak(NULL, DisposingCallback);
11038 handle3.MakeWeak(NULL, HandleCreatingCallback);
11039 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11043 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11044 v8::V8::Initialize();
11047 const char* sources[nof] = {
11048 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11052 for (int i = 0; i < nof; i++) {
11053 const char* source = sources[i];
11054 { v8::HandleScope scope;
11055 LocalContext context;
11056 CompileRun(source);
11058 { v8::HandleScope scope;
11059 LocalContext context;
11060 CompileRun(source);
11066 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11067 v8::HandleScope inner;
11069 v8::Handle<Value> three = v8_num(3);
11070 v8::Handle<Value> value = inner.Close(three);
11076 THREADED_TEST(NestedHandleScopeAndContexts) {
11077 v8::HandleScope outer;
11078 v8::Persistent<Context> env = Context::New();
11080 v8::Handle<Value> value = NestedScope(env);
11081 v8::Handle<String> str(value->ToString());
11082 CHECK(!str.IsEmpty());
11088 static i::Handle<i::JSFunction>* foo_ptr = NULL;
11089 static int foo_count = 0;
11090 static i::Handle<i::JSFunction>* bar_ptr = NULL;
11091 static int bar_count = 0;
11094 static void entry_hook(uintptr_t function,
11095 uintptr_t return_addr_location) {
11096 i::Code* code = i::Code::GetCodeFromTargetAddress(
11097 reinterpret_cast<i::Address>(function));
11098 CHECK(code != NULL);
11100 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11103 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11106 // TODO(siggi): Verify return_addr_location.
11107 // This can be done by capturing JitCodeEvents, but requires an ordered
11112 static void RunLoopInNewEnv() {
11116 v8::HandleScope outer;
11117 v8::Persistent<Context> env = Context::New();
11120 const char* script =
11123 " for (i = 0; i < 100; ++i)"
11127 "function foo(i) { return i * i; }";
11128 CompileRun(script);
11129 i::Handle<i::JSFunction> bar =
11130 i::Handle<i::JSFunction>::cast(
11131 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11134 i::Handle<i::JSFunction> foo =
11135 i::Handle<i::JSFunction>::cast(
11136 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11142 v8::Handle<v8::Value> value = CompileRun("bar();");
11143 CHECK(value->IsNumber());
11144 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11146 // Test the optimized codegen path.
11147 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11149 CHECK(value->IsNumber());
11150 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11156 TEST(SetFunctionEntryHook) {
11157 i::FLAG_allow_natives_syntax = true;
11159 // Test setting and resetting the entry hook.
11160 // Nulling it should always succeed.
11161 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11163 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11164 // Setting a hook while one's active should fail.
11165 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11167 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11169 // Reset the entry count to zero and set the entry hook.
11172 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11175 CHECK_EQ(2, bar_count);
11176 CHECK_EQ(200, foo_count);
11178 // Clear the entry hook and count.
11181 v8::V8::SetFunctionEntryHook(NULL);
11183 // Clear the compilation cache to make sure we don't reuse the
11184 // functions from the previous invocation.
11185 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11187 // Verify that entry hooking is now disabled.
11189 CHECK_EQ(0u, bar_count);
11190 CHECK_EQ(0u, foo_count);
11194 static i::HashMap* code_map = NULL;
11195 static int saw_bar = 0;
11196 static int move_events = 0;
11199 static bool FunctionNameIs(const char* expected,
11200 const v8::JitCodeEvent* event) {
11201 // Log lines for functions are of the general form:
11202 // "LazyCompile:<type><function_name>", where the type is one of
11204 static const char kPreamble[] = "LazyCompile:";
11205 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11207 if (event->name.len < sizeof(kPreamble) - 1 ||
11208 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11212 const char* tail = event->name.str + kPreambleLen;
11213 size_t tail_len = event->name.len - kPreambleLen;
11214 size_t expected_len = strlen(expected);
11215 if (tail_len == expected_len + 1) {
11216 if (*tail == '*' || *tail == '~') {
11224 if (tail_len != expected_len)
11227 return strncmp(tail, expected, expected_len) == 0;
11231 static void event_handler(const v8::JitCodeEvent* event) {
11232 CHECK(event != NULL);
11233 CHECK(code_map != NULL);
11235 switch (event->type) {
11236 case v8::JitCodeEvent::CODE_ADDED: {
11237 CHECK(event->code_start != NULL);
11238 CHECK_NE(0, static_cast<int>(event->code_len));
11239 CHECK(event->name.str != NULL);
11240 i::HashMap::Entry* entry =
11241 code_map->Lookup(event->code_start,
11242 i::ComputePointerHash(event->code_start),
11244 entry->value = reinterpret_cast<void*>(event->code_len);
11246 if (FunctionNameIs("bar", event)) {
11252 case v8::JitCodeEvent::CODE_MOVED: {
11253 uint32_t hash = i::ComputePointerHash(event->code_start);
11254 // We would like to never see code move that we haven't seen before,
11255 // but the code creation event does not happen until the line endings
11256 // have been calculated (this is so that we can report the line in the
11257 // script at which the function source is found, see
11258 // Compiler::RecordFunctionCompilation) and the line endings
11259 // calculations can cause a GC, which can move the newly created code
11260 // before its existence can be logged.
11261 i::HashMap::Entry* entry =
11262 code_map->Lookup(event->code_start, hash, false);
11263 if (entry != NULL) {
11266 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11267 code_map->Remove(event->code_start, hash);
11269 entry = code_map->Lookup(event->new_code_start,
11270 i::ComputePointerHash(event->new_code_start),
11272 CHECK(entry != NULL);
11273 entry->value = reinterpret_cast<void*>(event->code_len);
11278 case v8::JitCodeEvent::CODE_REMOVED:
11279 // Object/code removal events are currently not dispatched from the GC.
11283 // Impossible event.
11290 // Implemented in the test-alloc.cc test suite.
11291 void SimulateFullSpace(i::PagedSpace* space);
11294 static bool MatchPointers(void* key1, void* key2) {
11295 return key1 == key2;
11299 TEST(SetJitCodeEventHandler) {
11300 const char* script =
11303 " for (i = 0; i < 100; ++i)"
11307 "function foo(i) { return i * i; };"
11310 // Run this test in a new isolate to make sure we don't
11311 // have remnants of state from other code.
11312 v8::Isolate* isolate = v8::Isolate::New();
11316 i::HashMap code(MatchPointers);
11322 i::FLAG_stress_compaction = true;
11323 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11325 v8::HandleScope scope;
11326 // Generate new code objects sparsely distributed across several
11327 // different fragmented code-space pages.
11328 const int kIterations = 10;
11329 for (int i = 0; i < kIterations; ++i) {
11332 v8::Handle<v8::Script> compiled_script;
11334 i::AlwaysAllocateScope always_allocate;
11335 SimulateFullSpace(HEAP->code_space());
11336 compiled_script = v8_compile(script);
11338 compiled_script->Run();
11340 // Clear the compilation cache to get more wastage.
11341 ISOLATE->compilation_cache()->Clear();
11344 // Force code movement.
11345 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11347 CHECK_LE(kIterations, saw_bar);
11348 CHECK_NE(0, move_events);
11351 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11355 isolate->Dispose();
11357 // Do this in a new isolate.
11358 isolate = v8::Isolate::New();
11361 // Verify that we get callbacks for existing code objects when we
11362 // request enumeration of existing code.
11364 v8::HandleScope scope;
11366 CompileRun(script);
11368 // Now get code through initial iteration.
11369 i::HashMap code(MatchPointers);
11372 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11373 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11377 // We expect that we got some events. Note that if we could get code removal
11378 // notifications, we could compare two collections, one created by listening
11379 // from the time of creation of an isolate, and the other by subscribing
11380 // with EnumExisting.
11381 CHECK_NE(0, code.occupancy());
11385 isolate->Dispose();
11389 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11392 THREADED_TEST(ExternalAllocatedMemory) {
11393 v8::HandleScope outer;
11394 v8::Persistent<Context> env(Context::New());
11395 CHECK(!env.IsEmpty());
11396 const intptr_t kSize = 1024*1024;
11397 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
11399 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11404 THREADED_TEST(DisposeEnteredContext) {
11405 v8::HandleScope scope;
11406 LocalContext outer;
11407 { v8::Persistent<v8::Context> inner = v8::Context::New();
11416 // Regression test for issue 54, object templates with internal fields
11417 // but no accessors or interceptors did not get their internal field
11418 // count set on instances.
11419 THREADED_TEST(Regress54) {
11420 v8::HandleScope outer;
11421 LocalContext context;
11422 static v8::Persistent<v8::ObjectTemplate> templ;
11423 if (templ.IsEmpty()) {
11424 v8::HandleScope inner;
11425 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11426 local->SetInternalFieldCount(1);
11427 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11429 v8::Handle<v8::Object> result = templ->NewInstance();
11430 CHECK_EQ(1, result->InternalFieldCount());
11434 // If part of the threaded tests, this test makes ThreadingTest fail
11436 TEST(CatchStackOverflow) {
11437 v8::HandleScope scope;
11438 LocalContext context;
11439 v8::TryCatch try_catch;
11440 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11446 v8::Handle<v8::Value> result = script->Run();
11447 CHECK(result.IsEmpty());
11451 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11452 const char* resource_name,
11454 v8::HandleScope scope;
11455 v8::TryCatch try_catch;
11456 v8::Handle<v8::Value> result = script->Run();
11457 CHECK(result.IsEmpty());
11458 CHECK(try_catch.HasCaught());
11459 v8::Handle<v8::Message> message = try_catch.Message();
11460 CHECK(!message.IsEmpty());
11461 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11462 CHECK_EQ(91, message->GetStartPosition());
11463 CHECK_EQ(92, message->GetEndPosition());
11464 CHECK_EQ(2, message->GetStartColumn());
11465 CHECK_EQ(3, message->GetEndColumn());
11466 v8::String::AsciiValue line(message->GetSourceLine());
11467 CHECK_EQ(" throw 'nirk';", *line);
11468 v8::String::AsciiValue name(message->GetScriptResourceName());
11469 CHECK_EQ(resource_name, *name);
11473 THREADED_TEST(TryCatchSourceInfo) {
11474 v8::HandleScope scope;
11475 LocalContext context;
11476 v8::Handle<v8::String> source = v8::String::New(
11477 "function Foo() {\n"
11481 "function Bar() {\n"
11485 "function Baz() {\n"
11491 const char* resource_name;
11492 v8::Handle<v8::Script> script;
11493 resource_name = "test.js";
11494 script = v8::Script::Compile(source, v8::String::New(resource_name));
11495 CheckTryCatchSourceInfo(script, resource_name, 0);
11497 resource_name = "test1.js";
11498 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11499 script = v8::Script::Compile(source, &origin1);
11500 CheckTryCatchSourceInfo(script, resource_name, 0);
11502 resource_name = "test2.js";
11503 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11504 script = v8::Script::Compile(source, &origin2);
11505 CheckTryCatchSourceInfo(script, resource_name, 7);
11509 THREADED_TEST(CompilationCache) {
11510 v8::HandleScope scope;
11511 LocalContext context;
11512 v8::Handle<v8::String> source0 = v8::String::New("1234");
11513 v8::Handle<v8::String> source1 = v8::String::New("1234");
11514 v8::Handle<v8::Script> script0 =
11515 v8::Script::Compile(source0, v8::String::New("test.js"));
11516 v8::Handle<v8::Script> script1 =
11517 v8::Script::Compile(source1, v8::String::New("test.js"));
11518 v8::Handle<v8::Script> script2 =
11519 v8::Script::Compile(source0); // different origin
11520 CHECK_EQ(1234, script0->Run()->Int32Value());
11521 CHECK_EQ(1234, script1->Run()->Int32Value());
11522 CHECK_EQ(1234, script2->Run()->Int32Value());
11526 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11527 ApiTestFuzzer::Fuzz();
11532 THREADED_TEST(CallbackFunctionName) {
11533 v8::HandleScope scope;
11534 LocalContext context;
11535 Local<ObjectTemplate> t = ObjectTemplate::New();
11536 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11537 context->Global()->Set(v8_str("obj"), t->NewInstance());
11538 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11539 CHECK(value->IsString());
11540 v8::String::AsciiValue name(value);
11541 CHECK_EQ("asdf", *name);
11545 THREADED_TEST(DateAccess) {
11546 v8::HandleScope scope;
11547 LocalContext context;
11548 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11549 CHECK(date->IsDate());
11550 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
11554 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
11555 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11556 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11557 CHECK_EQ(elmc, props->Length());
11558 for (int i = 0; i < elmc; i++) {
11559 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11560 CHECK_EQ(elmv[i], *elm);
11565 void CheckOwnProperties(v8::Handle<v8::Value> val,
11567 const char* elmv[]) {
11568 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11569 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11570 CHECK_EQ(elmc, props->Length());
11571 for (int i = 0; i < elmc; i++) {
11572 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11573 CHECK_EQ(elmv[i], *elm);
11578 THREADED_TEST(PropertyEnumeration) {
11579 v8::HandleScope scope;
11580 LocalContext context;
11581 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11584 "result[1] = {a: 1, b: 2};"
11585 "result[2] = [1, 2, 3];"
11586 "var proto = {x: 1, y: 2, z: 3};"
11587 "var x = { __proto__: proto, w: 0, z: 1 };"
11589 "result;"))->Run();
11590 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11591 CHECK_EQ(4, elms->Length());
11593 const char** elmv0 = NULL;
11594 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11595 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11597 const char* elmv1[] = {"a", "b"};
11598 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11599 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
11601 const char* elmv2[] = {"0", "1", "2"};
11602 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11603 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
11605 const char* elmv3[] = {"w", "z", "x", "y"};
11606 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
11608 const char* elmv4[] = {"w", "z"};
11609 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
11612 THREADED_TEST(PropertyEnumeration2) {
11613 v8::HandleScope scope;
11614 LocalContext context;
11615 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11618 "result[1] = {a: 1, b: 2};"
11619 "result[2] = [1, 2, 3];"
11620 "var proto = {x: 1, y: 2, z: 3};"
11621 "var x = { __proto__: proto, w: 0, z: 1 };"
11623 "result;"))->Run();
11624 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11625 CHECK_EQ(4, elms->Length());
11627 const char** elmv0 = NULL;
11628 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11630 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11631 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11632 CHECK_EQ(0, props->Length());
11633 for (uint32_t i = 0; i < props->Length(); i++) {
11634 printf("p[%d]\n", i);
11638 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11640 v8::AccessType type,
11641 Local<Value> data) {
11642 return type != v8::ACCESS_SET;
11646 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11648 v8::AccessType type,
11649 Local<Value> data) {
11650 return type != v8::ACCESS_SET;
11654 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11655 v8::HandleScope scope;
11656 LocalContext context;
11657 Local<ObjectTemplate> templ = ObjectTemplate::New();
11658 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11659 IndexedSetAccessBlocker);
11660 templ->Set(v8_str("x"), v8::True());
11661 Local<v8::Object> instance = templ->NewInstance();
11662 context->Global()->Set(v8_str("obj"), instance);
11663 Local<Value> value = CompileRun("obj.x");
11664 CHECK(value->BooleanValue());
11668 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11670 v8::AccessType type,
11671 Local<Value> data) {
11676 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11678 v8::AccessType type,
11679 Local<Value> data) {
11685 THREADED_TEST(AccessChecksReenabledCorrectly) {
11686 v8::HandleScope scope;
11687 LocalContext context;
11688 Local<ObjectTemplate> templ = ObjectTemplate::New();
11689 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11690 IndexedGetAccessBlocker);
11691 templ->Set(v8_str("a"), v8_str("a"));
11692 // Add more than 8 (see kMaxFastProperties) properties
11693 // so that the constructor will force copying map.
11694 // Cannot sprintf, gcc complains unsafety.
11696 for (char i = '0'; i <= '9' ; i++) {
11698 for (char j = '0'; j <= '9'; j++) {
11700 for (char k = '0'; k <= '9'; k++) {
11703 templ->Set(v8_str(buf), v8::Number::New(k));
11708 Local<v8::Object> instance_1 = templ->NewInstance();
11709 context->Global()->Set(v8_str("obj_1"), instance_1);
11711 Local<Value> value_1 = CompileRun("obj_1.a");
11712 CHECK(value_1->IsUndefined());
11714 Local<v8::Object> instance_2 = templ->NewInstance();
11715 context->Global()->Set(v8_str("obj_2"), instance_2);
11717 Local<Value> value_2 = CompileRun("obj_2.a");
11718 CHECK(value_2->IsUndefined());
11722 // This tests that access check information remains on the global
11723 // object template when creating contexts.
11724 THREADED_TEST(AccessControlRepeatedContextCreation) {
11725 v8::HandleScope handle_scope;
11726 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11727 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11728 IndexedSetAccessBlocker);
11729 i::Handle<i::ObjectTemplateInfo> internal_template =
11730 v8::Utils::OpenHandle(*global_template);
11731 CHECK(!internal_template->constructor()->IsUndefined());
11732 i::Handle<i::FunctionTemplateInfo> constructor(
11733 i::FunctionTemplateInfo::cast(internal_template->constructor()));
11734 CHECK(!constructor->access_check_info()->IsUndefined());
11735 v8::Persistent<Context> context0(Context::New(NULL, global_template));
11736 CHECK(!context0.IsEmpty());
11737 CHECK(!constructor->access_check_info()->IsUndefined());
11741 THREADED_TEST(TurnOnAccessCheck) {
11742 v8::HandleScope handle_scope;
11744 // Create an environment with access check to the global object disabled by
11746 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11747 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11748 IndexedGetAccessBlocker,
11749 v8::Handle<v8::Value>(),
11751 v8::Persistent<Context> context = Context::New(NULL, global_template);
11752 Context::Scope context_scope(context);
11754 // Set up a property and a number of functions.
11755 context->Global()->Set(v8_str("a"), v8_num(1));
11756 CompileRun("function f1() {return a;}"
11757 "function f2() {return a;}"
11758 "function g1() {return h();}"
11759 "function g2() {return h();}"
11760 "function h() {return 1;}");
11761 Local<Function> f1 =
11762 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11763 Local<Function> f2 =
11764 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11765 Local<Function> g1 =
11766 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11767 Local<Function> g2 =
11768 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11769 Local<Function> h =
11770 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11772 // Get the global object.
11773 v8::Handle<v8::Object> global = context->Global();
11775 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11776 // uses the runtime system to retreive property a whereas f2 uses global load
11778 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11779 for (int i = 0; i < 4; i++) {
11780 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11783 // Same for g1 and g2.
11784 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11785 for (int i = 0; i < 4; i++) {
11786 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11789 // Detach the global and turn on access check.
11790 context->DetachGlobal();
11791 context->Global()->TurnOnAccessCheck();
11793 // Failing access check to property get results in undefined.
11794 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11795 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11797 // Failing access check to function call results in exception.
11798 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11799 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11801 // No failing access check when just returning a constant.
11802 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11806 static const char* kPropertyA = "a";
11807 static const char* kPropertyH = "h";
11809 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11811 v8::AccessType type,
11812 Local<Value> data) {
11813 if (!name->IsString()) return false;
11814 i::Handle<i::String> name_handle =
11815 v8::Utils::OpenHandle(String::Cast(*name));
11816 return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11817 && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
11821 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
11822 v8::HandleScope handle_scope;
11824 // Create an environment with access check to the global object disabled by
11825 // default. When the registered access checker will block access to properties
11827 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11828 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11829 IndexedGetAccessBlocker,
11830 v8::Handle<v8::Value>(),
11832 v8::Persistent<Context> context = Context::New(NULL, global_template);
11833 Context::Scope context_scope(context);
11835 // Set up a property and a number of functions.
11836 context->Global()->Set(v8_str("a"), v8_num(1));
11837 static const char* source = "function f1() {return a;}"
11838 "function f2() {return a;}"
11839 "function g1() {return h();}"
11840 "function g2() {return h();}"
11841 "function h() {return 1;}";
11843 CompileRun(source);
11844 Local<Function> f1;
11845 Local<Function> f2;
11846 Local<Function> g1;
11847 Local<Function> g2;
11849 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11850 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11851 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11852 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11853 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11855 // Get the global object.
11856 v8::Handle<v8::Object> global = context->Global();
11858 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11859 // uses the runtime system to retreive property a whereas f2 uses global load
11861 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11862 for (int i = 0; i < 4; i++) {
11863 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11866 // Same for g1 and g2.
11867 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11868 for (int i = 0; i < 4; i++) {
11869 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11872 // Detach the global and turn on access check now blocking access to property
11873 // a and function h.
11874 context->DetachGlobal();
11875 context->Global()->TurnOnAccessCheck();
11877 // Failing access check to property get results in undefined.
11878 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11879 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11881 // Failing access check to function call results in exception.
11882 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11883 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11885 // No failing access check when just returning a constant.
11886 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11888 // Now compile the source again. And get the newly compiled functions, except
11889 // for h for which access is blocked.
11890 CompileRun(source);
11891 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11892 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11893 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11894 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11895 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
11897 // Failing access check to property get results in undefined.
11898 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11899 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11901 // Failing access check to function call results in exception.
11902 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11903 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11907 // This test verifies that pre-compilation (aka preparsing) can be called
11908 // without initializing the whole VM. Thus we cannot run this test in a
11909 // multi-threaded setup.
11911 // TODO(155): This test would break without the initialization of V8. This is
11912 // a workaround for now to make this test not fail.
11913 v8::V8::Initialize();
11914 const char* script = "function foo(a) { return a+1; }";
11915 v8::ScriptData* sd =
11916 v8::ScriptData::PreCompile(script, i::StrLength(script));
11917 CHECK_NE(sd->Length(), 0);
11918 CHECK_NE(sd->Data(), NULL);
11919 CHECK(!sd->HasError());
11924 TEST(PreCompileWithError) {
11925 v8::V8::Initialize();
11926 const char* script = "function foo(a) { return 1 * * 2; }";
11927 v8::ScriptData* sd =
11928 v8::ScriptData::PreCompile(script, i::StrLength(script));
11929 CHECK(sd->HasError());
11934 TEST(Regress31661) {
11935 v8::V8::Initialize();
11936 const char* script = " The Definintive Guide";
11937 v8::ScriptData* sd =
11938 v8::ScriptData::PreCompile(script, i::StrLength(script));
11939 CHECK(sd->HasError());
11944 // Tests that ScriptData can be serialized and deserialized.
11945 TEST(PreCompileSerialization) {
11946 v8::V8::Initialize();
11947 const char* script = "function foo(a) { return a+1; }";
11948 v8::ScriptData* sd =
11949 v8::ScriptData::PreCompile(script, i::StrLength(script));
11952 int serialized_data_length = sd->Length();
11953 char* serialized_data = i::NewArray<char>(serialized_data_length);
11954 memcpy(serialized_data, sd->Data(), serialized_data_length);
11957 v8::ScriptData* deserialized_sd =
11958 v8::ScriptData::New(serialized_data, serialized_data_length);
11960 // Verify that the original is the same as the deserialized.
11961 CHECK_EQ(sd->Length(), deserialized_sd->Length());
11962 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11963 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11966 delete deserialized_sd;
11970 // Attempts to deserialize bad data.
11971 TEST(PreCompileDeserializationError) {
11972 v8::V8::Initialize();
11973 const char* data = "DONT CARE";
11974 int invalid_size = 3;
11975 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11977 CHECK_EQ(0, sd->Length());
11983 // Attempts to deserialize bad data.
11984 TEST(PreCompileInvalidPreparseDataError) {
11985 v8::V8::Initialize();
11986 v8::HandleScope scope;
11987 LocalContext context;
11989 const char* script = "function foo(){ return 5;}\n"
11990 "function bar(){ return 6 + 7;} foo();";
11991 v8::ScriptData* sd =
11992 v8::ScriptData::PreCompile(script, i::StrLength(script));
11993 CHECK(!sd->HasError());
11994 // ScriptDataImpl private implementation details
11995 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11996 const int kFunctionEntrySize = i::FunctionEntry::kSize;
11997 const int kFunctionEntryStartOffset = 0;
11998 const int kFunctionEntryEndOffset = 1;
11999 unsigned* sd_data =
12000 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
12002 // Overwrite function bar's end position with 0.
12003 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12004 v8::TryCatch try_catch;
12006 Local<String> source = String::New(script);
12007 Local<Script> compiled_script = Script::New(source, NULL, sd);
12008 CHECK(try_catch.HasCaught());
12009 String::AsciiValue exception_value(try_catch.Message()->Get());
12010 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12015 // Overwrite function bar's start position with 200. The function entry
12016 // will not be found when searching for it by position and we should fall
12017 // back on eager compilation.
12018 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12019 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
12020 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12022 compiled_script = Script::New(source, NULL, sd);
12023 CHECK(!try_catch.HasCaught());
12029 // Verifies that the Handle<String> and const char* versions of the API produce
12030 // the same results (at least for one trivial case).
12031 TEST(PreCompileAPIVariationsAreSame) {
12032 v8::V8::Initialize();
12033 v8::HandleScope scope;
12035 const char* cstring = "function foo(a) { return a+1; }";
12037 v8::ScriptData* sd_from_cstring =
12038 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12040 TestAsciiResource* resource = new TestAsciiResource(cstring);
12041 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
12042 v8::String::NewExternal(resource));
12044 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12045 v8::String::New(cstring));
12047 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
12048 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12049 sd_from_external_string->Data(),
12050 sd_from_cstring->Length()));
12052 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12053 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12054 sd_from_string->Data(),
12055 sd_from_cstring->Length()));
12058 delete sd_from_cstring;
12059 delete sd_from_external_string;
12060 delete sd_from_string;
12064 // This tests that we do not allow dictionary load/call inline caches
12065 // to use functions that have not yet been compiled. The potential
12066 // problem of loading a function that has not yet been compiled can
12067 // arise because we share code between contexts via the compilation
12069 THREADED_TEST(DictionaryICLoadedFunction) {
12070 v8::HandleScope scope;
12072 for (int i = 0; i < 2; i++) {
12073 LocalContext context;
12074 context->Global()->Set(v8_str("tmp"), v8::True());
12075 context->Global()->Delete(v8_str("tmp"));
12076 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12079 for (int i = 0; i < 2; i++) {
12080 LocalContext context;
12081 context->Global()->Set(v8_str("tmp"), v8::True());
12082 context->Global()->Delete(v8_str("tmp"));
12083 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12088 // Test that cross-context new calls use the context of the callee to
12089 // create the new JavaScript object.
12090 THREADED_TEST(CrossContextNew) {
12091 v8::HandleScope scope;
12092 v8::Persistent<Context> context0 = Context::New();
12093 v8::Persistent<Context> context1 = Context::New();
12095 // Allow cross-domain access.
12096 Local<String> token = v8_str("<security token>");
12097 context0->SetSecurityToken(token);
12098 context1->SetSecurityToken(token);
12100 // Set an 'x' property on the Object prototype and define a
12101 // constructor function in context0.
12103 CompileRun("Object.prototype.x = 42; function C() {};");
12106 // Call the constructor function from context0 and check that the
12107 // result has the 'x' property.
12109 context1->Global()->Set(v8_str("other"), context0->Global());
12110 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12111 CHECK(value->IsInt32());
12112 CHECK_EQ(42, value->Int32Value());
12115 // Dispose the contexts to allow them to be garbage collected.
12116 context0.Dispose();
12117 context1.Dispose();
12121 class RegExpInterruptTest {
12123 RegExpInterruptTest() : block_(NULL) {}
12124 ~RegExpInterruptTest() { delete block_; }
12126 block_ = i::OS::CreateSemaphore(0);
12128 gc_during_regexp_ = 0;
12129 regexp_success_ = false;
12130 gc_success_ = false;
12131 GCThread gc_thread(this);
12133 v8::Locker::StartPreemption(1);
12135 LongRunningRegExp();
12137 v8::Unlocker unlock;
12140 v8::Locker::StopPreemption();
12141 CHECK(regexp_success_);
12142 CHECK(gc_success_);
12146 // Number of garbage collections required.
12147 static const int kRequiredGCs = 5;
12149 class GCThread : public i::Thread {
12151 explicit GCThread(RegExpInterruptTest* test)
12152 : Thread("GCThread"), test_(test) {}
12153 virtual void Run() {
12154 test_->CollectGarbage();
12157 RegExpInterruptTest* test_;
12160 void CollectGarbage() {
12162 while (gc_during_regexp_ < kRequiredGCs) {
12165 // TODO(lrn): Perhaps create some garbage before collecting.
12166 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12171 gc_success_ = true;
12174 void LongRunningRegExp() {
12175 block_->Signal(); // Enable garbage collection thread on next preemption.
12177 while (gc_during_regexp_ < kRequiredGCs) {
12178 int gc_before = gc_count_;
12180 // Match 15-30 "a"'s against 14 and a "b".
12181 const char* c_source =
12182 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12183 ".exec('aaaaaaaaaaaaaaab') === null";
12184 Local<String> source = String::New(c_source);
12185 Local<Script> script = Script::Compile(source);
12186 Local<Value> result = script->Run();
12187 if (!result->BooleanValue()) {
12188 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12193 // Match 15-30 "a"'s against 15 and a "b".
12194 const char* c_source =
12195 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12196 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12197 Local<String> source = String::New(c_source);
12198 Local<Script> script = Script::Compile(source);
12199 Local<Value> result = script->Run();
12200 if (!result->BooleanValue()) {
12201 gc_during_regexp_ = kRequiredGCs;
12205 int gc_after = gc_count_;
12206 gc_during_regexp_ += gc_after - gc_before;
12210 regexp_success_ = true;
12213 i::Semaphore* block_;
12215 int gc_during_regexp_;
12216 bool regexp_success_;
12221 // Test that a regular expression execution can be interrupted and
12222 // survive a garbage collection.
12223 TEST(RegExpInterruption) {
12225 v8::V8::Initialize();
12226 v8::HandleScope scope;
12227 Local<Context> local_env;
12230 local_env = env.local();
12233 // Local context should still be live.
12234 CHECK(!local_env.IsEmpty());
12235 local_env->Enter();
12237 // Should complete without problems.
12238 RegExpInterruptTest().RunTest();
12244 class ApplyInterruptTest {
12246 ApplyInterruptTest() : block_(NULL) {}
12247 ~ApplyInterruptTest() { delete block_; }
12249 block_ = i::OS::CreateSemaphore(0);
12251 gc_during_apply_ = 0;
12252 apply_success_ = false;
12253 gc_success_ = false;
12254 GCThread gc_thread(this);
12256 v8::Locker::StartPreemption(1);
12258 LongRunningApply();
12260 v8::Unlocker unlock;
12263 v8::Locker::StopPreemption();
12264 CHECK(apply_success_);
12265 CHECK(gc_success_);
12269 // Number of garbage collections required.
12270 static const int kRequiredGCs = 2;
12272 class GCThread : public i::Thread {
12274 explicit GCThread(ApplyInterruptTest* test)
12275 : Thread("GCThread"), test_(test) {}
12276 virtual void Run() {
12277 test_->CollectGarbage();
12280 ApplyInterruptTest* test_;
12283 void CollectGarbage() {
12285 while (gc_during_apply_ < kRequiredGCs) {
12288 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12293 gc_success_ = true;
12296 void LongRunningApply() {
12299 while (gc_during_apply_ < kRequiredGCs) {
12300 int gc_before = gc_count_;
12302 const char* c_source =
12303 "function do_very_little(bar) {"
12306 "for (var i = 0; i < 100000; i++) {"
12307 " do_very_little.apply(this, ['bar']);"
12309 Local<String> source = String::New(c_source);
12310 Local<Script> script = Script::Compile(source);
12311 Local<Value> result = script->Run();
12312 // Check that no exception was thrown.
12313 CHECK(!result.IsEmpty());
12315 int gc_after = gc_count_;
12316 gc_during_apply_ += gc_after - gc_before;
12319 apply_success_ = true;
12322 i::Semaphore* block_;
12324 int gc_during_apply_;
12325 bool apply_success_;
12330 // Test that nothing bad happens if we get a preemption just when we were
12331 // about to do an apply().
12332 TEST(ApplyInterruption) {
12334 v8::V8::Initialize();
12335 v8::HandleScope scope;
12336 Local<Context> local_env;
12339 local_env = env.local();
12342 // Local context should still be live.
12343 CHECK(!local_env.IsEmpty());
12344 local_env->Enter();
12346 // Should complete without problems.
12347 ApplyInterruptTest().RunTest();
12353 // Verify that we can clone an object
12354 TEST(ObjectClone) {
12355 v8::HandleScope scope;
12358 const char* sample =
12360 "rv.alpha = 'hello';" \
12364 // Create an object, verify basics.
12365 Local<Value> val = CompileRun(sample);
12366 CHECK(val->IsObject());
12367 Local<v8::Object> obj = val.As<v8::Object>();
12368 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12370 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12371 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12372 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12375 Local<v8::Object> clone = obj->Clone();
12376 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12377 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12378 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12380 // Set a property on the clone, verify each object.
12381 clone->Set(v8_str("beta"), v8::Integer::New(456));
12382 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12383 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12387 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12389 explicit AsciiVectorResource(i::Vector<const char> vector)
12391 virtual ~AsciiVectorResource() {}
12392 virtual size_t length() const { return data_.length(); }
12393 virtual const char* data() const { return data_.start(); }
12395 i::Vector<const char> data_;
12399 class UC16VectorResource : public v8::String::ExternalStringResource {
12401 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12403 virtual ~UC16VectorResource() {}
12404 virtual size_t length() const { return data_.length(); }
12405 virtual const i::uc16* data() const { return data_.start(); }
12407 i::Vector<const i::uc16> data_;
12411 static void MorphAString(i::String* string,
12412 AsciiVectorResource* ascii_resource,
12413 UC16VectorResource* uc16_resource) {
12414 CHECK(i::StringShape(string).IsExternal());
12415 if (string->IsAsciiRepresentation()) {
12416 // Check old map is not symbol or long.
12417 CHECK(string->map() == HEAP->external_ascii_string_map());
12418 // Morph external string to be TwoByte string.
12419 string->set_map(HEAP->external_string_map());
12420 i::ExternalTwoByteString* morphed =
12421 i::ExternalTwoByteString::cast(string);
12422 morphed->set_resource(uc16_resource);
12424 // Check old map is not symbol or long.
12425 CHECK(string->map() == HEAP->external_string_map());
12426 // Morph external string to be ASCII string.
12427 string->set_map(HEAP->external_ascii_string_map());
12428 i::ExternalAsciiString* morphed =
12429 i::ExternalAsciiString::cast(string);
12430 morphed->set_resource(ascii_resource);
12435 // Test that we can still flatten a string if the components it is built up
12436 // from have been turned into 16 bit strings in the mean time.
12437 THREADED_TEST(MorphCompositeStringTest) {
12438 char utf_buffer[129];
12439 const char* c_string = "Now is the time for all good men"
12440 " to come to the aid of the party";
12441 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12443 v8::HandleScope scope;
12445 AsciiVectorResource ascii_resource(
12446 i::Vector<const char>(c_string, i::StrLength(c_string)));
12447 UC16VectorResource uc16_resource(
12448 i::Vector<const uint16_t>(two_byte_string,
12449 i::StrLength(c_string)));
12451 Local<String> lhs(v8::Utils::ToLocal(
12452 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12453 Local<String> rhs(v8::Utils::ToLocal(
12454 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
12456 env->Global()->Set(v8_str("lhs"), lhs);
12457 env->Global()->Set(v8_str("rhs"), rhs);
12460 "var cons = lhs + rhs;"
12461 "var slice = lhs.substring(1, lhs.length - 1);"
12462 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12464 CHECK(!lhs->MayContainNonAscii());
12465 CHECK(!rhs->MayContainNonAscii());
12467 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12468 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12470 // This should UTF-8 without flattening, since everything is ASCII.
12471 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12472 CHECK_EQ(128, cons->Utf8Length());
12474 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12475 CHECK_EQ(128, nchars);
12476 CHECK_EQ(0, strcmp(
12478 "Now is the time for all good men to come to the aid of the party"
12479 "Now is the time for all good men to come to the aid of the party"));
12481 // Now do some stuff to make sure the strings are flattened, etc.
12483 "/[^a-z]/.test(cons);"
12484 "/[^a-z]/.test(slice);"
12485 "/[^a-z]/.test(slice_on_cons);");
12486 const char* expected_cons =
12487 "Now is the time for all good men to come to the aid of the party"
12488 "Now is the time for all good men to come to the aid of the party";
12489 const char* expected_slice =
12490 "ow is the time for all good men to come to the aid of the part";
12491 const char* expected_slice_on_cons =
12492 "ow is the time for all good men to come to the aid of the party"
12493 "Now is the time for all good men to come to the aid of the part";
12494 CHECK_EQ(String::New(expected_cons),
12495 env->Global()->Get(v8_str("cons")));
12496 CHECK_EQ(String::New(expected_slice),
12497 env->Global()->Get(v8_str("slice")));
12498 CHECK_EQ(String::New(expected_slice_on_cons),
12499 env->Global()->Get(v8_str("slice_on_cons")));
12501 i::DeleteArray(two_byte_string);
12505 TEST(CompileExternalTwoByteSource) {
12506 v8::HandleScope scope;
12507 LocalContext context;
12509 // This is a very short list of sources, which currently is to check for a
12510 // regression caused by r2703.
12511 const char* ascii_sources[] = {
12513 "-0.5", // This mainly testes PushBack in the Scanner.
12514 "--0.5", // This mainly testes PushBack in the Scanner.
12518 // Compile the sources as external two byte strings.
12519 for (int i = 0; ascii_sources[i] != NULL; i++) {
12520 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12521 UC16VectorResource uc16_resource(
12522 i::Vector<const uint16_t>(two_byte_string,
12523 i::StrLength(ascii_sources[i])));
12524 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12525 v8::Script::Compile(source);
12526 i::DeleteArray(two_byte_string);
12531 class RegExpStringModificationTest {
12533 RegExpStringModificationTest()
12534 : block_(i::OS::CreateSemaphore(0)),
12536 morphs_during_regexp_(0),
12537 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12538 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12539 ~RegExpStringModificationTest() { delete block_; }
12541 regexp_success_ = false;
12542 morph_success_ = false;
12544 // Initialize the contents of two_byte_content_ to be a uc16 representation
12545 // of "aaaaaaaaaaaaaab".
12546 for (int i = 0; i < 14; i++) {
12547 two_byte_content_[i] = 'a';
12549 two_byte_content_[14] = 'b';
12551 // Create the input string for the regexp - the one we are going to change
12553 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
12555 // Inject the input as a global variable.
12556 i::Handle<i::String> input_name =
12557 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
12558 i::Isolate::Current()->native_context()->global_object()->SetProperty(
12562 i::kNonStrictMode)->ToObjectChecked();
12564 MorphThread morph_thread(this);
12565 morph_thread.Start();
12566 v8::Locker::StartPreemption(1);
12567 LongRunningRegExp();
12569 v8::Unlocker unlock;
12570 morph_thread.Join();
12572 v8::Locker::StopPreemption();
12573 CHECK(regexp_success_);
12574 CHECK(morph_success_);
12578 // Number of string modifications required.
12579 static const int kRequiredModifications = 5;
12580 static const int kMaxModifications = 100;
12582 class MorphThread : public i::Thread {
12584 explicit MorphThread(RegExpStringModificationTest* test)
12585 : Thread("MorphThread"), test_(test) {}
12586 virtual void Run() {
12587 test_->MorphString();
12590 RegExpStringModificationTest* test_;
12593 void MorphString() {
12595 while (morphs_during_regexp_ < kRequiredModifications &&
12596 morphs_ < kMaxModifications) {
12599 // Swap string between ascii and two-byte representation.
12600 i::String* string = *input_;
12601 MorphAString(string, &ascii_resource_, &uc16_resource_);
12606 morph_success_ = true;
12609 void LongRunningRegExp() {
12610 block_->Signal(); // Enable morphing thread on next preemption.
12611 while (morphs_during_regexp_ < kRequiredModifications &&
12612 morphs_ < kMaxModifications) {
12613 int morphs_before = morphs_;
12615 v8::HandleScope scope;
12616 // Match 15-30 "a"'s against 14 and a "b".
12617 const char* c_source =
12618 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12619 ".exec(input) === null";
12620 Local<String> source = String::New(c_source);
12621 Local<Script> script = Script::Compile(source);
12622 Local<Value> result = script->Run();
12623 CHECK(result->IsTrue());
12625 int morphs_after = morphs_;
12626 morphs_during_regexp_ += morphs_after - morphs_before;
12628 regexp_success_ = true;
12631 i::uc16 two_byte_content_[15];
12632 i::Semaphore* block_;
12634 int morphs_during_regexp_;
12635 bool regexp_success_;
12636 bool morph_success_;
12637 i::Handle<i::String> input_;
12638 AsciiVectorResource ascii_resource_;
12639 UC16VectorResource uc16_resource_;
12643 // Test that a regular expression execution can be interrupted and
12644 // the string changed without failing.
12645 TEST(RegExpStringModification) {
12647 v8::V8::Initialize();
12648 v8::HandleScope scope;
12649 Local<Context> local_env;
12652 local_env = env.local();
12655 // Local context should still be live.
12656 CHECK(!local_env.IsEmpty());
12657 local_env->Enter();
12659 // Should complete without problems.
12660 RegExpStringModificationTest().RunTest();
12666 // Test that we cannot set a property on the global object if there
12667 // is a read-only property in the prototype chain.
12668 TEST(ReadOnlyPropertyInGlobalProto) {
12669 i::FLAG_es5_readonly = true;
12670 v8::HandleScope scope;
12671 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12672 LocalContext context(0, templ);
12673 v8::Handle<v8::Object> global = context->Global();
12674 v8::Handle<v8::Object> global_proto =
12675 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12676 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12677 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12678 // Check without 'eval' or 'with'.
12679 v8::Handle<v8::Value> res =
12680 CompileRun("function f() { x = 42; return x; }; f()");
12681 CHECK_EQ(v8::Integer::New(0), res);
12682 // Check with 'eval'.
12683 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12684 CHECK_EQ(v8::Integer::New(0), res);
12685 // Check with 'with'.
12686 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12687 CHECK_EQ(v8::Integer::New(0), res);
12690 static int force_set_set_count = 0;
12691 static int force_set_get_count = 0;
12692 bool pass_on_get = false;
12694 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12695 const v8::AccessorInfo& info) {
12696 force_set_get_count++;
12698 return v8::Handle<v8::Value>();
12700 return v8::Int32::New(3);
12704 static void ForceSetSetter(v8::Local<v8::String> name,
12705 v8::Local<v8::Value> value,
12706 const v8::AccessorInfo& info) {
12707 force_set_set_count++;
12710 static v8::Handle<v8::Value> ForceSetInterceptSetter(
12711 v8::Local<v8::String> name,
12712 v8::Local<v8::Value> value,
12713 const v8::AccessorInfo& info) {
12714 force_set_set_count++;
12715 return v8::Undefined();
12719 force_set_get_count = 0;
12720 force_set_set_count = 0;
12721 pass_on_get = false;
12723 v8::HandleScope scope;
12724 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12725 v8::Handle<v8::String> access_property = v8::String::New("a");
12726 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12727 LocalContext context(NULL, templ);
12728 v8::Handle<v8::Object> global = context->Global();
12730 // Ordinary properties
12731 v8::Handle<v8::String> simple_property = v8::String::New("p");
12732 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12733 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12734 // This should fail because the property is read-only
12735 global->Set(simple_property, v8::Int32::New(5));
12736 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12737 // This should succeed even though the property is read-only
12738 global->ForceSet(simple_property, v8::Int32::New(6));
12739 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12742 CHECK_EQ(0, force_set_set_count);
12743 CHECK_EQ(0, force_set_get_count);
12744 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12745 // CHECK_EQ the property shouldn't override it, just call the setter
12746 // which in this case does nothing.
12747 global->Set(access_property, v8::Int32::New(7));
12748 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12749 CHECK_EQ(1, force_set_set_count);
12750 CHECK_EQ(2, force_set_get_count);
12751 // Forcing the property to be set should override the accessor without
12753 global->ForceSet(access_property, v8::Int32::New(8));
12754 CHECK_EQ(8, global->Get(access_property)->Int32Value());
12755 CHECK_EQ(1, force_set_set_count);
12756 CHECK_EQ(2, force_set_get_count);
12759 TEST(ForceSetWithInterceptor) {
12760 force_set_get_count = 0;
12761 force_set_set_count = 0;
12762 pass_on_get = false;
12764 v8::HandleScope scope;
12765 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12766 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12767 LocalContext context(NULL, templ);
12768 v8::Handle<v8::Object> global = context->Global();
12770 v8::Handle<v8::String> some_property = v8::String::New("a");
12771 CHECK_EQ(0, force_set_set_count);
12772 CHECK_EQ(0, force_set_get_count);
12773 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12774 // Setting the property shouldn't override it, just call the setter
12775 // which in this case does nothing.
12776 global->Set(some_property, v8::Int32::New(7));
12777 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12778 CHECK_EQ(1, force_set_set_count);
12779 CHECK_EQ(2, force_set_get_count);
12780 // Getting the property when the interceptor returns an empty handle
12781 // should yield undefined, since the property isn't present on the
12782 // object itself yet.
12783 pass_on_get = true;
12784 CHECK(global->Get(some_property)->IsUndefined());
12785 CHECK_EQ(1, force_set_set_count);
12786 CHECK_EQ(3, force_set_get_count);
12787 // Forcing the property to be set should cause the value to be
12788 // set locally without calling the interceptor.
12789 global->ForceSet(some_property, v8::Int32::New(8));
12790 CHECK_EQ(8, global->Get(some_property)->Int32Value());
12791 CHECK_EQ(1, force_set_set_count);
12792 CHECK_EQ(4, force_set_get_count);
12793 // Reenabling the interceptor should cause it to take precedence over
12795 pass_on_get = false;
12796 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12797 CHECK_EQ(1, force_set_set_count);
12798 CHECK_EQ(5, force_set_get_count);
12799 // The interceptor should also work for other properties
12800 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12801 CHECK_EQ(1, force_set_set_count);
12802 CHECK_EQ(6, force_set_get_count);
12806 THREADED_TEST(ForceDelete) {
12807 v8::HandleScope scope;
12808 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12809 LocalContext context(NULL, templ);
12810 v8::Handle<v8::Object> global = context->Global();
12812 // Ordinary properties
12813 v8::Handle<v8::String> simple_property = v8::String::New("p");
12814 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12815 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12816 // This should fail because the property is dont-delete.
12817 CHECK(!global->Delete(simple_property));
12818 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12819 // This should succeed even though the property is dont-delete.
12820 CHECK(global->ForceDelete(simple_property));
12821 CHECK(global->Get(simple_property)->IsUndefined());
12825 static int force_delete_interceptor_count = 0;
12826 static bool pass_on_delete = false;
12829 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12830 v8::Local<v8::String> name,
12831 const v8::AccessorInfo& info) {
12832 force_delete_interceptor_count++;
12833 if (pass_on_delete) {
12834 return v8::Handle<v8::Boolean>();
12841 THREADED_TEST(ForceDeleteWithInterceptor) {
12842 force_delete_interceptor_count = 0;
12843 pass_on_delete = false;
12845 v8::HandleScope scope;
12846 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12847 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12848 LocalContext context(NULL, templ);
12849 v8::Handle<v8::Object> global = context->Global();
12851 v8::Handle<v8::String> some_property = v8::String::New("a");
12852 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12854 // Deleting a property should get intercepted and nothing should
12856 CHECK_EQ(0, force_delete_interceptor_count);
12857 CHECK(global->Delete(some_property));
12858 CHECK_EQ(1, force_delete_interceptor_count);
12859 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12860 // Deleting the property when the interceptor returns an empty
12861 // handle should not delete the property since it is DontDelete.
12862 pass_on_delete = true;
12863 CHECK(!global->Delete(some_property));
12864 CHECK_EQ(2, force_delete_interceptor_count);
12865 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12866 // Forcing the property to be deleted should delete the value
12867 // without calling the interceptor.
12868 CHECK(global->ForceDelete(some_property));
12869 CHECK(global->Get(some_property)->IsUndefined());
12870 CHECK_EQ(2, force_delete_interceptor_count);
12874 // Make sure that forcing a delete invalidates any IC stubs, so we
12875 // don't read the hole value.
12876 THREADED_TEST(ForceDeleteIC) {
12877 v8::HandleScope scope;
12878 LocalContext context;
12879 // Create a DontDelete variable on the global object.
12880 CompileRun("this.__proto__ = { foo: 'horse' };"
12881 "var foo = 'fish';"
12882 "function f() { return foo.length; }");
12883 // Initialize the IC for foo in f.
12884 CompileRun("for (var i = 0; i < 4; i++) f();");
12885 // Make sure the value of foo is correct before the deletion.
12886 CHECK_EQ(4, CompileRun("f()")->Int32Value());
12887 // Force the deletion of foo.
12888 CHECK(context->Global()->ForceDelete(v8_str("foo")));
12889 // Make sure the value for foo is read from the prototype, and that
12890 // we don't get in trouble with reading the deleted cell value
12892 CHECK_EQ(5, CompileRun("f()")->Int32Value());
12896 TEST(InlinedFunctionAcrossContexts) {
12897 i::FLAG_allow_natives_syntax = true;
12898 v8::HandleScope outer_scope;
12899 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
12900 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
12904 v8::HandleScope inner_scope;
12905 CompileRun("var G = 42; function foo() { return G; }");
12906 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
12908 ctx2->Global()->Set(v8_str("o"), foo);
12909 v8::Local<v8::Value> res = CompileRun(
12910 "function f() { return o(); }"
12911 "for (var i = 0; i < 10; ++i) f();"
12912 "%OptimizeFunctionOnNextCall(f);"
12914 CHECK_EQ(42, res->Int32Value());
12916 v8::Handle<v8::String> G_property = v8::String::New("G");
12917 CHECK(ctx1->Global()->ForceDelete(G_property));
12924 " return e.toString();"
12927 "ReferenceError: G is not defined");
12936 v8::Persistent<Context> calling_context0;
12937 v8::Persistent<Context> calling_context1;
12938 v8::Persistent<Context> calling_context2;
12941 // Check that the call to the callback is initiated in
12942 // calling_context2, the directly calling context is calling_context1
12943 // and the callback itself is in calling_context0.
12944 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
12945 ApiTestFuzzer::Fuzz();
12946 CHECK(Context::GetCurrent() == calling_context0);
12947 CHECK(Context::GetCalling() == calling_context1);
12948 CHECK(Context::GetEntered() == calling_context2);
12949 return v8::Integer::New(42);
12953 THREADED_TEST(GetCallingContext) {
12954 v8::HandleScope scope;
12956 calling_context0 = Context::New();
12957 calling_context1 = Context::New();
12958 calling_context2 = Context::New();
12960 // Allow cross-domain access.
12961 Local<String> token = v8_str("<security token>");
12962 calling_context0->SetSecurityToken(token);
12963 calling_context1->SetSecurityToken(token);
12964 calling_context2->SetSecurityToken(token);
12966 // Create an object with a C++ callback in context0.
12967 calling_context0->Enter();
12968 Local<v8::FunctionTemplate> callback_templ =
12969 v8::FunctionTemplate::New(GetCallingContextCallback);
12970 calling_context0->Global()->Set(v8_str("callback"),
12971 callback_templ->GetFunction());
12972 calling_context0->Exit();
12974 // Expose context0 in context1 and set up a function that calls the
12975 // callback function.
12976 calling_context1->Enter();
12977 calling_context1->Global()->Set(v8_str("context0"),
12978 calling_context0->Global());
12979 CompileRun("function f() { context0.callback() }");
12980 calling_context1->Exit();
12982 // Expose context1 in context2 and call the callback function in
12983 // context0 indirectly through f in context1.
12984 calling_context2->Enter();
12985 calling_context2->Global()->Set(v8_str("context1"),
12986 calling_context1->Global());
12987 CompileRun("context1.f()");
12988 calling_context2->Exit();
12990 // Dispose the contexts to allow them to be garbage collected.
12991 calling_context0.Dispose();
12992 calling_context1.Dispose();
12993 calling_context2.Dispose();
12994 calling_context0.Clear();
12995 calling_context1.Clear();
12996 calling_context2.Clear();
13000 // Check that a variable declaration with no explicit initialization
13001 // value does shadow an existing property in the prototype chain.
13002 THREADED_TEST(InitGlobalVarInProtoChain) {
13003 i::FLAG_es52_globals = true;
13004 v8::HandleScope scope;
13005 LocalContext context;
13006 // Introduce a variable in the prototype chain.
13007 CompileRun("__proto__.x = 42");
13008 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13009 CHECK(!result->IsUndefined());
13010 CHECK_EQ(43, result->Int32Value());
13014 // Regression test for issue 398.
13015 // If a function is added to an object, creating a constant function
13016 // field, and the result is cloned, replacing the constant function on the
13017 // original should not affect the clone.
13018 // See http://code.google.com/p/v8/issues/detail?id=398
13019 THREADED_TEST(ReplaceConstantFunction) {
13020 v8::HandleScope scope;
13021 LocalContext context;
13022 v8::Handle<v8::Object> obj = v8::Object::New();
13023 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13024 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13025 obj->Set(foo_string, func_templ->GetFunction());
13026 v8::Handle<v8::Object> obj_clone = obj->Clone();
13027 obj_clone->Set(foo_string, v8::String::New("Hello"));
13028 CHECK(!obj->Get(foo_string)->IsUndefined());
13032 // Regression test for http://crbug.com/16276.
13033 THREADED_TEST(Regress16276) {
13034 v8::HandleScope scope;
13035 LocalContext context;
13036 // Force the IC in f to be a dictionary load IC.
13037 CompileRun("function f(obj) { return obj.x; }\n"
13038 "var obj = { x: { foo: 42 }, y: 87 };\n"
13041 "for (var i = 0; i < 5; i++) f(obj);");
13042 // Detach the global object to make 'this' refer directly to the
13043 // global object (not the proxy), and make sure that the dictionary
13044 // load IC doesn't mess up loading directly from the global object.
13045 context->DetachGlobal();
13046 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13050 THREADED_TEST(PixelArray) {
13051 v8::HandleScope scope;
13052 LocalContext context;
13053 const int kElementCount = 260;
13054 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13055 i::Handle<i::ExternalPixelArray> pixels =
13056 i::Handle<i::ExternalPixelArray>::cast(
13057 FACTORY->NewExternalArray(kElementCount,
13058 v8::kExternalPixelArray,
13060 // Force GC to trigger verification.
13061 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13062 for (int i = 0; i < kElementCount; i++) {
13063 pixels->set(i, i % 256);
13065 // Force GC to trigger verification.
13066 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13067 for (int i = 0; i < kElementCount; i++) {
13068 CHECK_EQ(i % 256, pixels->get_scalar(i));
13069 CHECK_EQ(i % 256, pixel_data[i]);
13072 v8::Handle<v8::Object> obj = v8::Object::New();
13073 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13074 // Set the elements to be the pixels.
13075 // jsobj->set_elements(*pixels);
13076 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13077 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13078 obj->Set(v8_str("field"), v8::Int32::New(1503));
13079 context->Global()->Set(v8_str("pixels"), obj);
13080 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13081 CHECK_EQ(1503, result->Int32Value());
13082 result = CompileRun("pixels[1]");
13083 CHECK_EQ(1, result->Int32Value());
13085 result = CompileRun("var sum = 0;"
13086 "for (var i = 0; i < 8; i++) {"
13087 " sum += pixels[i] = pixels[i] = -i;"
13090 CHECK_EQ(-28, result->Int32Value());
13092 result = CompileRun("var sum = 0;"
13093 "for (var i = 0; i < 8; i++) {"
13094 " sum += pixels[i] = pixels[i] = 0;"
13097 CHECK_EQ(0, result->Int32Value());
13099 result = CompileRun("var sum = 0;"
13100 "for (var i = 0; i < 8; i++) {"
13101 " sum += pixels[i] = pixels[i] = 255;"
13104 CHECK_EQ(8 * 255, result->Int32Value());
13106 result = CompileRun("var sum = 0;"
13107 "for (var i = 0; i < 8; i++) {"
13108 " sum += pixels[i] = pixels[i] = 256 + i;"
13111 CHECK_EQ(2076, result->Int32Value());
13113 result = CompileRun("var sum = 0;"
13114 "for (var i = 0; i < 8; i++) {"
13115 " sum += pixels[i] = pixels[i] = i;"
13118 CHECK_EQ(28, result->Int32Value());
13120 result = CompileRun("var sum = 0;"
13121 "for (var i = 0; i < 8; i++) {"
13122 " sum += pixels[i];"
13125 CHECK_EQ(28, result->Int32Value());
13127 i::Handle<i::Smi> value(i::Smi::FromInt(2));
13128 i::Handle<i::Object> no_failure;
13130 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13131 ASSERT(!no_failure.is_null());
13132 i::USE(no_failure);
13133 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13134 *value.location() = i::Smi::FromInt(256);
13136 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13137 ASSERT(!no_failure.is_null());
13138 i::USE(no_failure);
13140 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13141 *value.location() = i::Smi::FromInt(-1);
13143 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
13144 ASSERT(!no_failure.is_null());
13145 i::USE(no_failure);
13146 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13148 result = CompileRun("for (var i = 0; i < 8; i++) {"
13149 " pixels[i] = (i * 65) - 109;"
13151 "pixels[1] + pixels[6];");
13152 CHECK_EQ(255, result->Int32Value());
13153 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13154 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13156 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13158 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13160 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13162 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13164 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13166 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13167 result = CompileRun("var sum = 0;"
13168 "for (var i = 0; i < 8; i++) {"
13169 " sum += pixels[i];"
13172 CHECK_EQ(984, result->Int32Value());
13174 result = CompileRun("for (var i = 0; i < 8; i++) {"
13175 " pixels[i] = (i * 1.1);"
13177 "pixels[1] + pixels[6];");
13178 CHECK_EQ(8, result->Int32Value());
13179 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13180 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13181 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13182 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13183 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13184 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13185 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13186 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13188 result = CompileRun("for (var i = 0; i < 8; i++) {"
13189 " pixels[7] = undefined;"
13192 CHECK_EQ(0, result->Int32Value());
13193 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
13195 result = CompileRun("for (var i = 0; i < 8; i++) {"
13196 " pixels[6] = '2.3';"
13199 CHECK_EQ(2, result->Int32Value());
13200 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13202 result = CompileRun("for (var i = 0; i < 8; i++) {"
13203 " pixels[5] = NaN;"
13206 CHECK_EQ(0, result->Int32Value());
13207 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13209 result = CompileRun("for (var i = 0; i < 8; i++) {"
13210 " pixels[8] = Infinity;"
13213 CHECK_EQ(255, result->Int32Value());
13215 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
13217 result = CompileRun("for (var i = 0; i < 8; i++) {"
13218 " pixels[9] = -Infinity;"
13221 CHECK_EQ(0, result->Int32Value());
13222 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
13224 result = CompileRun("pixels[3] = 33;"
13225 "delete pixels[3];"
13227 CHECK_EQ(33, result->Int32Value());
13229 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13230 "pixels[2] = 12; pixels[3] = 13;"
13231 "pixels.__defineGetter__('2',"
13232 "function() { return 120; });"
13234 CHECK_EQ(12, result->Int32Value());
13236 result = CompileRun("var js_array = new Array(40);"
13237 "js_array[0] = 77;"
13239 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13241 result = CompileRun("pixels[1] = 23;"
13242 "pixels.__proto__ = [];"
13243 "js_array.__proto__ = pixels;"
13244 "js_array.concat(pixels);");
13245 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13246 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13248 result = CompileRun("pixels[1] = 23;");
13249 CHECK_EQ(23, result->Int32Value());
13251 // Test for index greater than 255. Regression test for:
13252 // http://code.google.com/p/chromium/issues/detail?id=26337.
13253 result = CompileRun("pixels[256] = 255;");
13254 CHECK_EQ(255, result->Int32Value());
13255 result = CompileRun("var i = 0;"
13256 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13258 CHECK_EQ(255, result->Int32Value());
13260 // Make sure that pixel array ICs recognize when a non-pixel array
13261 // is passed to it.
13262 result = CompileRun("function pa_load(p) {"
13264 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13267 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13268 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13269 "just_ints = new Object();"
13270 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13271 "for (var i = 0; i < 10; ++i) {"
13272 " result = pa_load(just_ints);"
13275 CHECK_EQ(32640, result->Int32Value());
13277 // Make sure that pixel array ICs recognize out-of-bound accesses.
13278 result = CompileRun("function pa_load(p, start) {"
13280 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13283 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13284 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13285 "for (var i = 0; i < 10; ++i) {"
13286 " result = pa_load(pixels,-10);"
13289 CHECK_EQ(0, result->Int32Value());
13291 // Make sure that generic ICs properly handles a pixel array.
13292 result = CompileRun("function pa_load(p) {"
13294 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13297 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13298 "just_ints = new Object();"
13299 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13300 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13301 "for (var i = 0; i < 10; ++i) {"
13302 " result = pa_load(pixels);"
13305 CHECK_EQ(32640, result->Int32Value());
13307 // Make sure that generic load ICs recognize out-of-bound accesses in
13309 result = CompileRun("function pa_load(p, start) {"
13311 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13314 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13315 "just_ints = new Object();"
13316 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13317 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13318 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13319 "for (var i = 0; i < 10; ++i) {"
13320 " result = pa_load(pixels,-10);"
13323 CHECK_EQ(0, result->Int32Value());
13325 // Make sure that generic ICs properly handles other types than pixel
13326 // arrays (that the inlined fast pixel array test leaves the right information
13327 // in the right registers).
13328 result = CompileRun("function pa_load(p) {"
13330 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13333 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13334 "just_ints = new Object();"
13335 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13336 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13337 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13338 "sparse_array = new Object();"
13339 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13340 "sparse_array[1000000] = 3;"
13341 "for (var i = 0; i < 10; ++i) {"
13342 " result = pa_load(sparse_array);"
13345 CHECK_EQ(32640, result->Int32Value());
13347 // Make sure that pixel array store ICs clamp values correctly.
13348 result = CompileRun("function pa_store(p) {"
13349 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13351 "pa_store(pixels);"
13353 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13355 CHECK_EQ(48896, result->Int32Value());
13357 // Make sure that pixel array stores correctly handle accesses outside
13358 // of the pixel array..
13359 result = CompileRun("function pa_store(p,start) {"
13360 " for (var j = 0; j < 256; j++) {"
13361 " p[j+start] = j * 2;"
13364 "pa_store(pixels,0);"
13365 "pa_store(pixels,-128);"
13367 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13369 CHECK_EQ(65280, result->Int32Value());
13371 // Make sure that the generic store stub correctly handle accesses outside
13372 // of the pixel array..
13373 result = CompileRun("function pa_store(p,start) {"
13374 " for (var j = 0; j < 256; j++) {"
13375 " p[j+start] = j * 2;"
13378 "pa_store(pixels,0);"
13379 "just_ints = new Object();"
13380 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13381 "pa_store(just_ints, 0);"
13382 "pa_store(pixels,-128);"
13384 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13386 CHECK_EQ(65280, result->Int32Value());
13388 // Make sure that the generic keyed store stub clamps pixel array values
13390 result = CompileRun("function pa_store(p) {"
13391 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13393 "pa_store(pixels);"
13394 "just_ints = new Object();"
13395 "pa_store(just_ints);"
13396 "pa_store(pixels);"
13398 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13400 CHECK_EQ(48896, result->Int32Value());
13402 // Make sure that pixel array loads are optimized by crankshaft.
13403 result = CompileRun("function pa_load(p) {"
13405 " for (var i=0; i<256; ++i) {"
13410 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13411 "for (var i = 0; i < 5000; ++i) {"
13412 " result = pa_load(pixels);"
13415 CHECK_EQ(32640, result->Int32Value());
13417 // Make sure that pixel array stores are optimized by crankshaft.
13418 result = CompileRun("function pa_init(p) {"
13419 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13421 "function pa_load(p) {"
13423 " for (var i=0; i<256; ++i) {"
13428 "for (var i = 0; i < 5000; ++i) {"
13429 " pa_init(pixels);"
13431 "result = pa_load(pixels);"
13433 CHECK_EQ(32640, result->Int32Value());
13439 THREADED_TEST(PixelArrayInfo) {
13440 v8::HandleScope scope;
13441 LocalContext context;
13442 for (int size = 0; size < 100; size += 10) {
13443 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13444 v8::Handle<v8::Object> obj = v8::Object::New();
13445 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13446 CHECK(obj->HasIndexedPropertiesInPixelData());
13447 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13448 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13454 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13456 const AccessorInfo& info) {
13457 ApiTestFuzzer::Fuzz();
13458 return v8::Handle<Value>();
13462 static v8::Handle<Value> NotHandledIndexedPropertySetter(
13464 Local<Value> value,
13465 const AccessorInfo& info) {
13466 ApiTestFuzzer::Fuzz();
13467 return v8::Handle<Value>();
13471 THREADED_TEST(PixelArrayWithInterceptor) {
13472 v8::HandleScope scope;
13473 LocalContext context;
13474 const int kElementCount = 260;
13475 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13476 i::Handle<i::ExternalPixelArray> pixels =
13477 i::Handle<i::ExternalPixelArray>::cast(
13478 FACTORY->NewExternalArray(kElementCount,
13479 v8::kExternalPixelArray,
13481 for (int i = 0; i < kElementCount; i++) {
13482 pixels->set(i, i % 256);
13484 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13485 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13486 NotHandledIndexedPropertySetter);
13487 v8::Handle<v8::Object> obj = templ->NewInstance();
13488 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13489 context->Global()->Set(v8_str("pixels"), obj);
13490 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13491 CHECK_EQ(1, result->Int32Value());
13492 result = CompileRun("var sum = 0;"
13493 "for (var i = 0; i < 8; i++) {"
13494 " sum += pixels[i] = pixels[i] = -i;"
13497 CHECK_EQ(-28, result->Int32Value());
13498 result = CompileRun("pixels.hasOwnProperty('1')");
13499 CHECK(result->BooleanValue());
13504 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13505 switch (array_type) {
13506 case v8::kExternalByteArray:
13507 case v8::kExternalUnsignedByteArray:
13508 case v8::kExternalPixelArray:
13511 case v8::kExternalShortArray:
13512 case v8::kExternalUnsignedShortArray:
13515 case v8::kExternalIntArray:
13516 case v8::kExternalUnsignedIntArray:
13517 case v8::kExternalFloatArray:
13520 case v8::kExternalDoubleArray:
13532 template <class ExternalArrayClass, class ElementType>
13533 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13536 v8::HandleScope scope;
13537 LocalContext context;
13538 const int kElementCount = 40;
13539 int element_size = ExternalArrayElementSize(array_type);
13540 ElementType* array_data =
13541 static_cast<ElementType*>(malloc(kElementCount * element_size));
13542 i::Handle<ExternalArrayClass> array =
13543 i::Handle<ExternalArrayClass>::cast(
13544 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
13545 // Force GC to trigger verification.
13546 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13547 for (int i = 0; i < kElementCount; i++) {
13548 array->set(i, static_cast<ElementType>(i));
13550 // Force GC to trigger verification.
13551 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13552 for (int i = 0; i < kElementCount; i++) {
13553 CHECK_EQ(static_cast<int64_t>(i),
13554 static_cast<int64_t>(array->get_scalar(i)));
13555 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13558 v8::Handle<v8::Object> obj = v8::Object::New();
13559 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13560 // Set the elements to be the external array.
13561 obj->SetIndexedPropertiesToExternalArrayData(array_data,
13565 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
13566 obj->Set(v8_str("field"), v8::Int32::New(1503));
13567 context->Global()->Set(v8_str("ext_array"), obj);
13568 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13569 CHECK_EQ(1503, result->Int32Value());
13570 result = CompileRun("ext_array[1]");
13571 CHECK_EQ(1, result->Int32Value());
13573 // Check pass through of assigned smis
13574 result = CompileRun("var sum = 0;"
13575 "for (var i = 0; i < 8; i++) {"
13576 " sum += ext_array[i] = ext_array[i] = -i;"
13579 CHECK_EQ(-28, result->Int32Value());
13581 // Check assigned smis
13582 result = CompileRun("for (var i = 0; i < 8; i++) {"
13583 " ext_array[i] = i;"
13586 "for (var i = 0; i < 8; i++) {"
13587 " sum += ext_array[i];"
13590 CHECK_EQ(28, result->Int32Value());
13592 // Check assigned smis in reverse order
13593 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13594 " ext_array[i] = i;"
13597 "for (var i = 0; i < 8; i++) {"
13598 " sum += ext_array[i];"
13601 CHECK_EQ(28, result->Int32Value());
13603 // Check pass through of assigned HeapNumbers
13604 result = CompileRun("var sum = 0;"
13605 "for (var i = 0; i < 16; i+=2) {"
13606 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13609 CHECK_EQ(-28, result->Int32Value());
13611 // Check assigned HeapNumbers
13612 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13613 " ext_array[i] = (i * 0.5);"
13616 "for (var i = 0; i < 16; i+=2) {"
13617 " sum += ext_array[i];"
13620 CHECK_EQ(28, result->Int32Value());
13622 // Check assigned HeapNumbers in reverse order
13623 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13624 " ext_array[i] = (i * 0.5);"
13627 "for (var i = 0; i < 16; i+=2) {"
13628 " sum += ext_array[i];"
13631 CHECK_EQ(28, result->Int32Value());
13633 i::ScopedVector<char> test_buf(1024);
13635 // Check legal boundary conditions.
13636 // The repeated loads and stores ensure the ICs are exercised.
13637 const char* boundary_program =
13639 "for (var i = 0; i < 16; i++) {"
13640 " ext_array[i] = %lld;"
13642 " res = ext_array[i];"
13646 i::OS::SNPrintF(test_buf,
13649 result = CompileRun(test_buf.start());
13650 CHECK_EQ(low, result->IntegerValue());
13652 i::OS::SNPrintF(test_buf,
13655 result = CompileRun(test_buf.start());
13656 CHECK_EQ(high, result->IntegerValue());
13658 // Check misprediction of type in IC.
13659 result = CompileRun("var tmp_array = ext_array;"
13661 "for (var i = 0; i < 8; i++) {"
13662 " tmp_array[i] = i;"
13663 " sum += tmp_array[i];"
13669 // Force GC to trigger verification.
13670 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13671 CHECK_EQ(28, result->Int32Value());
13673 // Make sure out-of-range loads do not throw.
13674 i::OS::SNPrintF(test_buf,
13675 "var caught_exception = false;"
13679 " caught_exception = true;"
13681 "caught_exception;",
13683 result = CompileRun(test_buf.start());
13684 CHECK_EQ(false, result->BooleanValue());
13686 // Make sure out-of-range stores do not throw.
13687 i::OS::SNPrintF(test_buf,
13688 "var caught_exception = false;"
13690 " ext_array[%d] = 1;"
13692 " caught_exception = true;"
13694 "caught_exception;",
13696 result = CompileRun(test_buf.start());
13697 CHECK_EQ(false, result->BooleanValue());
13699 // Check other boundary conditions, values and operations.
13700 result = CompileRun("for (var i = 0; i < 8; i++) {"
13701 " ext_array[7] = undefined;"
13704 CHECK_EQ(0, result->Int32Value());
13705 if (array_type == v8::kExternalDoubleArray ||
13706 array_type == v8::kExternalFloatArray) {
13708 static_cast<int>(i::OS::nan_value()),
13709 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13711 CHECK_EQ(0, static_cast<int>(
13712 jsobj->GetElement(7)->ToObjectChecked()->Number()));
13715 result = CompileRun("for (var i = 0; i < 8; i++) {"
13716 " ext_array[6] = '2.3';"
13719 CHECK_EQ(2, result->Int32Value());
13721 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
13723 if (array_type != v8::kExternalFloatArray &&
13724 array_type != v8::kExternalDoubleArray) {
13725 // Though the specification doesn't state it, be explicit about
13726 // converting NaNs and +/-Infinity to zero.
13727 result = CompileRun("for (var i = 0; i < 8; i++) {"
13728 " ext_array[i] = 5;"
13730 "for (var i = 0; i < 8; i++) {"
13731 " ext_array[i] = NaN;"
13734 CHECK_EQ(0, result->Int32Value());
13736 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13738 result = CompileRun("for (var i = 0; i < 8; i++) {"
13739 " ext_array[i] = 5;"
13741 "for (var i = 0; i < 8; i++) {"
13742 " ext_array[i] = Infinity;"
13745 int expected_value =
13746 (array_type == v8::kExternalPixelArray) ? 255 : 0;
13747 CHECK_EQ(expected_value, result->Int32Value());
13748 CHECK_EQ(expected_value,
13749 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13751 result = CompileRun("for (var i = 0; i < 8; i++) {"
13752 " ext_array[i] = 5;"
13754 "for (var i = 0; i < 8; i++) {"
13755 " ext_array[i] = -Infinity;"
13758 CHECK_EQ(0, result->Int32Value());
13760 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13762 // Check truncation behavior of integral arrays.
13763 const char* unsigned_data =
13764 "var source_data = [0.6, 10.6];"
13765 "var expected_results = [0, 10];";
13766 const char* signed_data =
13767 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13768 "var expected_results = [0, 10, 0, -10];";
13769 const char* pixel_data =
13770 "var source_data = [0.6, 10.6];"
13771 "var expected_results = [1, 11];";
13773 (array_type == v8::kExternalUnsignedByteArray ||
13774 array_type == v8::kExternalUnsignedShortArray ||
13775 array_type == v8::kExternalUnsignedIntArray);
13776 bool is_pixel_data = array_type == v8::kExternalPixelArray;
13778 i::OS::SNPrintF(test_buf,
13780 "var all_passed = true;"
13781 "for (var i = 0; i < source_data.length; i++) {"
13782 " for (var j = 0; j < 8; j++) {"
13783 " ext_array[j] = source_data[i];"
13785 " all_passed = all_passed &&"
13786 " (ext_array[5] == expected_results[i]);"
13791 (is_pixel_data ? pixel_data : signed_data)));
13792 result = CompileRun(test_buf.start());
13793 CHECK_EQ(true, result->BooleanValue());
13796 for (int i = 0; i < kElementCount; i++) {
13797 array->set(i, static_cast<ElementType>(i));
13799 // Test complex assignments
13800 result = CompileRun("function ee_op_test_complex_func(sum) {"
13801 " for (var i = 0; i < 40; ++i) {"
13802 " sum += (ext_array[i] += 1);"
13803 " sum += (ext_array[i] -= 1);"
13808 "for (var i=0;i<10000;++i) {"
13809 " sum=ee_op_test_complex_func(sum);"
13812 CHECK_EQ(16000000, result->Int32Value());
13814 // Test count operations
13815 result = CompileRun("function ee_op_test_count_func(sum) {"
13816 " for (var i = 0; i < 40; ++i) {"
13817 " sum += (++ext_array[i]);"
13818 " sum += (--ext_array[i]);"
13823 "for (var i=0;i<10000;++i) {"
13824 " sum=ee_op_test_count_func(sum);"
13827 CHECK_EQ(16000000, result->Int32Value());
13829 result = CompileRun("ext_array[3] = 33;"
13830 "delete ext_array[3];"
13832 CHECK_EQ(33, result->Int32Value());
13834 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13835 "ext_array[2] = 12; ext_array[3] = 13;"
13836 "ext_array.__defineGetter__('2',"
13837 "function() { return 120; });"
13839 CHECK_EQ(12, result->Int32Value());
13841 result = CompileRun("var js_array = new Array(40);"
13842 "js_array[0] = 77;"
13844 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13846 result = CompileRun("ext_array[1] = 23;"
13847 "ext_array.__proto__ = [];"
13848 "js_array.__proto__ = ext_array;"
13849 "js_array.concat(ext_array);");
13850 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13851 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13853 result = CompileRun("ext_array[1] = 23;");
13854 CHECK_EQ(23, result->Int32Value());
13856 // Test more complex manipulations which cause eax to contain values
13857 // that won't be completely overwritten by loads from the arrays.
13858 // This catches bugs in the instructions used for the KeyedLoadIC
13859 // for byte and word types.
13861 const int kXSize = 300;
13862 const int kYSize = 300;
13863 const int kLargeElementCount = kXSize * kYSize * 4;
13864 ElementType* large_array_data =
13865 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
13866 v8::Handle<v8::Object> large_obj = v8::Object::New();
13867 // Set the elements to be the external array.
13868 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13870 kLargeElementCount);
13871 context->Global()->Set(v8_str("large_array"), large_obj);
13872 // Initialize contents of a few rows.
13873 for (int x = 0; x < 300; x++) {
13875 int offset = row * 300 * 4;
13876 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13877 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13878 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13879 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13881 offset = row * 300 * 4;
13882 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13883 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13884 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13885 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13887 offset = row * 300 * 4;
13888 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13889 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13890 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13891 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13893 // The goal of the code below is to make "offset" large enough
13894 // that the computation of the index (which goes into eax) has
13895 // high bits set which will not be overwritten by a byte or short
13897 result = CompileRun("var failed = false;"
13899 "for (var i = 0; i < 300; i++) {"
13900 " if (large_array[4 * i] != 127 ||"
13901 " large_array[4 * i + 1] != 0 ||"
13902 " large_array[4 * i + 2] != 0 ||"
13903 " large_array[4 * i + 3] != 127) {"
13907 "offset = 150 * 300 * 4;"
13908 "for (var i = 0; i < 300; i++) {"
13909 " if (large_array[offset + 4 * i] != 127 ||"
13910 " large_array[offset + 4 * i + 1] != 0 ||"
13911 " large_array[offset + 4 * i + 2] != 0 ||"
13912 " large_array[offset + 4 * i + 3] != 127) {"
13916 "offset = 298 * 300 * 4;"
13917 "for (var i = 0; i < 300; i++) {"
13918 " if (large_array[offset + 4 * i] != 127 ||"
13919 " large_array[offset + 4 * i + 1] != 0 ||"
13920 " large_array[offset + 4 * i + 2] != 0 ||"
13921 " large_array[offset + 4 * i + 3] != 127) {"
13926 CHECK_EQ(true, result->BooleanValue());
13927 free(large_array_data);
13930 // The "" property descriptor is overloaded to store information about
13931 // the external array. Ensure that setting and accessing the "" property
13932 // works (it should overwrite the information cached about the external
13933 // array in the DescriptorArray) in various situations.
13934 result = CompileRun("ext_array[''] = 23; ext_array['']");
13935 CHECK_EQ(23, result->Int32Value());
13937 // Property "" set after the external array is associated with the object.
13939 v8::Handle<v8::Object> obj2 = v8::Object::New();
13940 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
13941 obj2->Set(v8_str(""), v8::Int32::New(1503));
13942 // Set the elements to be the external array.
13943 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13946 context->Global()->Set(v8_str("ext_array"), obj2);
13947 result = CompileRun("ext_array['']");
13948 CHECK_EQ(1503, result->Int32Value());
13951 // Property "" set after the external array is associated with the object.
13953 v8::Handle<v8::Object> obj2 = v8::Object::New();
13954 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13955 // Set the elements to be the external array.
13956 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13959 obj2->Set(v8_str(""), v8::Int32::New(1503));
13960 context->Global()->Set(v8_str("ext_array"), obj2);
13961 result = CompileRun("ext_array['']");
13962 CHECK_EQ(1503, result->Int32Value());
13965 // Should reuse the map from previous test.
13967 v8::Handle<v8::Object> obj2 = v8::Object::New();
13968 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
13969 // Set the elements to be the external array. Should re-use the map
13970 // from previous test.
13971 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
13974 context->Global()->Set(v8_str("ext_array"), obj2);
13975 result = CompileRun("ext_array['']");
13978 // Property "" is a constant function that shouldn't not be interfered with
13979 // when an external array is set.
13981 v8::Handle<v8::Object> obj2 = v8::Object::New();
13983 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13985 // Add a constant function to an object.
13986 context->Global()->Set(v8_str("ext_array"), obj2);
13987 result = CompileRun("ext_array[''] = function() {return 1503;};"
13988 "ext_array['']();");
13990 // Add an external array transition to the same map that
13991 // has the constant transition.
13992 v8::Handle<v8::Object> obj3 = v8::Object::New();
13993 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
13994 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13997 context->Global()->Set(v8_str("ext_array"), obj3);
14000 // If a external array transition is in the map, it should get clobbered
14001 // by a constant function.
14003 // Add an external array transition.
14004 v8::Handle<v8::Object> obj3 = v8::Object::New();
14005 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14006 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14010 // Add a constant function to the same map that just got an external array
14012 v8::Handle<v8::Object> obj2 = v8::Object::New();
14013 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14014 context->Global()->Set(v8_str("ext_array"), obj2);
14015 result = CompileRun("ext_array[''] = function() {return 1503;};"
14016 "ext_array['']();");
14023 THREADED_TEST(ExternalByteArray) {
14024 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
14025 v8::kExternalByteArray,
14031 THREADED_TEST(ExternalUnsignedByteArray) {
14032 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
14033 v8::kExternalUnsignedByteArray,
14039 THREADED_TEST(ExternalPixelArray) {
14040 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14041 v8::kExternalPixelArray,
14047 THREADED_TEST(ExternalShortArray) {
14048 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
14049 v8::kExternalShortArray,
14055 THREADED_TEST(ExternalUnsignedShortArray) {
14056 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
14057 v8::kExternalUnsignedShortArray,
14063 THREADED_TEST(ExternalIntArray) {
14064 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
14065 v8::kExternalIntArray,
14066 INT_MIN, // -2147483648
14067 INT_MAX); // 2147483647
14071 THREADED_TEST(ExternalUnsignedIntArray) {
14072 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
14073 v8::kExternalUnsignedIntArray,
14075 UINT_MAX); // 4294967295
14079 THREADED_TEST(ExternalFloatArray) {
14080 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
14081 v8::kExternalFloatArray,
14087 THREADED_TEST(ExternalDoubleArray) {
14088 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14089 v8::kExternalDoubleArray,
14095 THREADED_TEST(ExternalArrays) {
14096 TestExternalByteArray();
14097 TestExternalUnsignedByteArray();
14098 TestExternalShortArray();
14099 TestExternalUnsignedShortArray();
14100 TestExternalIntArray();
14101 TestExternalUnsignedIntArray();
14102 TestExternalFloatArray();
14106 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14107 v8::HandleScope scope;
14108 LocalContext context;
14109 for (int size = 0; size < 100; size += 10) {
14110 int element_size = ExternalArrayElementSize(array_type);
14111 void* external_data = malloc(size * element_size);
14112 v8::Handle<v8::Object> obj = v8::Object::New();
14113 obj->SetIndexedPropertiesToExternalArrayData(
14114 external_data, array_type, size);
14115 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14116 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14117 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14118 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14119 free(external_data);
14124 THREADED_TEST(ExternalArrayInfo) {
14125 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14126 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14127 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14128 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14129 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14130 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14131 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
14132 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
14133 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
14137 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14138 v8::Handle<v8::Object> obj = v8::Object::New();
14139 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14140 last_location = last_message = NULL;
14141 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14142 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14143 CHECK_NE(NULL, last_location);
14144 CHECK_NE(NULL, last_message);
14148 TEST(ExternalArrayLimits) {
14149 v8::HandleScope scope;
14150 LocalContext context;
14151 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14152 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14153 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14154 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14155 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14156 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14157 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14158 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14159 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14160 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14161 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14162 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14163 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14164 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14165 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14166 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14167 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14168 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14172 THREADED_TEST(ScriptContextDependence) {
14173 v8::HandleScope scope;
14175 const char *source = "foo";
14176 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14177 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14178 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14179 CHECK_EQ(dep->Run()->Int32Value(), 100);
14180 CHECK_EQ(indep->Run()->Int32Value(), 100);
14182 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14183 CHECK_EQ(dep->Run()->Int32Value(), 100);
14184 CHECK_EQ(indep->Run()->Int32Value(), 101);
14188 THREADED_TEST(StackTrace) {
14189 v8::HandleScope scope;
14190 LocalContext context;
14191 v8::TryCatch try_catch;
14192 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14193 v8::Handle<v8::String> src = v8::String::New(source);
14194 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14195 v8::Script::New(src, origin)->Run();
14196 CHECK(try_catch.HasCaught());
14197 v8::String::Utf8Value stack(try_catch.StackTrace());
14198 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14202 // Checks that a StackFrame has certain expected values.
14203 void checkStackFrame(const char* expected_script_name,
14204 const char* expected_func_name, int expected_line_number,
14205 int expected_column, bool is_eval, bool is_constructor,
14206 v8::Handle<v8::StackFrame> frame) {
14207 v8::HandleScope scope;
14208 v8::String::Utf8Value func_name(frame->GetFunctionName());
14209 v8::String::Utf8Value script_name(frame->GetScriptName());
14210 if (*script_name == NULL) {
14211 // The situation where there is no associated script, like for evals.
14212 CHECK(expected_script_name == NULL);
14214 CHECK(strstr(*script_name, expected_script_name) != NULL);
14216 CHECK(strstr(*func_name, expected_func_name) != NULL);
14217 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14218 CHECK_EQ(expected_column, frame->GetColumn());
14219 CHECK_EQ(is_eval, frame->IsEval());
14220 CHECK_EQ(is_constructor, frame->IsConstructor());
14224 v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
14225 v8::HandleScope scope;
14226 const char* origin = "capture-stack-trace-test";
14227 const int kOverviewTest = 1;
14228 const int kDetailedTest = 2;
14230 ASSERT(args.Length() == 1);
14232 int testGroup = args[0]->Int32Value();
14233 if (testGroup == kOverviewTest) {
14234 v8::Handle<v8::StackTrace> stackTrace =
14235 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14236 CHECK_EQ(4, stackTrace->GetFrameCount());
14237 checkStackFrame(origin, "bar", 2, 10, false, false,
14238 stackTrace->GetFrame(0));
14239 checkStackFrame(origin, "foo", 6, 3, false, false,
14240 stackTrace->GetFrame(1));
14241 // This is the source string inside the eval which has the call to foo.
14242 checkStackFrame(NULL, "", 1, 5, false, false,
14243 stackTrace->GetFrame(2));
14244 // The last frame is an anonymous function which has the initial eval call.
14245 checkStackFrame(origin, "", 8, 7, false, false,
14246 stackTrace->GetFrame(3));
14248 CHECK(stackTrace->AsArray()->IsArray());
14249 } else if (testGroup == kDetailedTest) {
14250 v8::Handle<v8::StackTrace> stackTrace =
14251 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14252 CHECK_EQ(4, stackTrace->GetFrameCount());
14253 checkStackFrame(origin, "bat", 4, 22, false, false,
14254 stackTrace->GetFrame(0));
14255 checkStackFrame(origin, "baz", 8, 3, false, true,
14256 stackTrace->GetFrame(1));
14257 #ifdef ENABLE_DEBUGGER_SUPPORT
14258 bool is_eval = true;
14259 #else // ENABLE_DEBUGGER_SUPPORT
14260 bool is_eval = false;
14261 #endif // ENABLE_DEBUGGER_SUPPORT
14263 // This is the source string inside the eval which has the call to baz.
14264 checkStackFrame(NULL, "", 1, 5, is_eval, false,
14265 stackTrace->GetFrame(2));
14266 // The last frame is an anonymous function which has the initial eval call.
14267 checkStackFrame(origin, "", 10, 1, false, false,
14268 stackTrace->GetFrame(3));
14270 CHECK(stackTrace->AsArray()->IsArray());
14272 return v8::Undefined();
14276 // Tests the C++ StackTrace API.
14277 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14278 // THREADED_TEST(CaptureStackTrace) {
14279 TEST(CaptureStackTrace) {
14280 v8::HandleScope scope;
14281 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14282 Local<ObjectTemplate> templ = ObjectTemplate::New();
14283 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14284 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14285 LocalContext context(0, templ);
14287 // Test getting OVERVIEW information. Should ignore information that is not
14288 // script name, function name, line number, and column offset.
14289 const char *overview_source =
14290 "function bar() {\n"
14291 " var y; AnalyzeStackInNativeCode(1);\n"
14293 "function foo() {\n"
14297 "var x;eval('new foo();');";
14298 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
14299 v8::Handle<Value> overview_result(
14300 v8::Script::New(overview_src, origin)->Run());
14301 CHECK(!overview_result.IsEmpty());
14302 CHECK(overview_result->IsObject());
14304 // Test getting DETAILED information.
14305 const char *detailed_source =
14306 "function bat() {AnalyzeStackInNativeCode(2);\n"
14309 "function baz() {\n"
14312 "eval('new baz();');";
14313 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14314 // Make the script using a non-zero line and column offset.
14315 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14316 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14317 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14318 v8::Handle<v8::Script> detailed_script(
14319 v8::Script::New(detailed_src, &detailed_origin));
14320 v8::Handle<Value> detailed_result(detailed_script->Run());
14321 CHECK(!detailed_result.IsEmpty());
14322 CHECK(detailed_result->IsObject());
14326 static void StackTraceForUncaughtExceptionListener(
14327 v8::Handle<v8::Message> message,
14328 v8::Handle<Value>) {
14329 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14330 CHECK_EQ(2, stack_trace->GetFrameCount());
14331 checkStackFrame("origin", "foo", 2, 3, false, false,
14332 stack_trace->GetFrame(0));
14333 checkStackFrame("origin", "bar", 5, 3, false, false,
14334 stack_trace->GetFrame(1));
14337 TEST(CaptureStackTraceForUncaughtException) {
14339 v8::HandleScope scope;
14341 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14342 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14344 Script::Compile(v8_str("function foo() {\n"
14347 "function bar() {\n"
14350 v8_str("origin"))->Run();
14351 v8::Local<v8::Object> global = env->Global();
14352 Local<Value> trouble = global->Get(v8_str("bar"));
14353 CHECK(trouble->IsFunction());
14354 Function::Cast(*trouble)->Call(global, 0, NULL);
14355 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14356 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14360 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14361 v8::HandleScope scope;
14363 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14365 v8::StackTrace::kDetailed);
14368 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14369 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14370 " 'isConstructor'];\n"
14371 "for (var i = 0; i < setters.length; i++) {\n"
14372 " var prop = setters[i];\n"
14373 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14375 CompileRun("throw 'exception';");
14376 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14380 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14381 v8::Handle<v8::Value> data) {
14382 // Use the frame where JavaScript is called from.
14383 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14384 CHECK(!stack_trace.IsEmpty());
14385 int frame_count = stack_trace->GetFrameCount();
14386 CHECK_EQ(3, frame_count);
14387 int line_number[] = {1, 2, 5};
14388 for (int i = 0; i < frame_count; i++) {
14389 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14394 // Test that we only return the stack trace at the site where the exception
14395 // is first thrown (not where it is rethrown).
14396 TEST(RethrowStackTrace) {
14397 v8::HandleScope scope;
14399 // We make sure that
14400 // - the stack trace of the ReferenceError in g() is reported.
14401 // - the stack trace is not overwritten when e1 is rethrown by t().
14402 // - the stack trace of e2 does not overwrite that of e1.
14403 const char* source =
14404 "function g() { error; } \n"
14405 "function f() { g(); } \n"
14406 "function t(e) { throw e; } \n"
14409 "} catch (e1) { \n"
14412 " } catch (e2) { \n"
14416 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14417 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14418 CompileRun(source);
14419 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14420 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14424 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14425 v8::Handle<v8::Value> data) {
14426 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14427 CHECK(!stack_trace.IsEmpty());
14428 int frame_count = stack_trace->GetFrameCount();
14429 CHECK_EQ(2, frame_count);
14430 int line_number[] = {3, 7};
14431 for (int i = 0; i < frame_count; i++) {
14432 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14437 // Test that we do not recognize identity for primitive exceptions.
14438 TEST(RethrowPrimitiveStackTrace) {
14439 v8::HandleScope scope;
14441 // We do not capture stack trace for non Error objects on creation time.
14442 // Instead, we capture the stack trace on last throw.
14443 const char* source =
14444 "function g() { throw 404; } \n"
14445 "function f() { g(); } \n"
14446 "function t(e) { throw e; } \n"
14449 "} catch (e1) { \n"
14452 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14453 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14454 CompileRun(source);
14455 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14456 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14460 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14461 v8::Handle<v8::Value> data) {
14462 // Use the frame where JavaScript is called from.
14463 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14464 CHECK(!stack_trace.IsEmpty());
14465 CHECK_EQ(1, stack_trace->GetFrameCount());
14466 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14470 // Test that the stack trace is captured when the error object is created and
14471 // not where it is thrown.
14472 TEST(RethrowExistingStackTrace) {
14473 v8::HandleScope scope;
14475 const char* source =
14476 "var e = new Error(); \n"
14478 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14479 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14480 CompileRun(source);
14481 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14482 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14486 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14487 v8::Handle<v8::Value> data) {
14488 // Use the frame where JavaScript is called from.
14489 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14490 CHECK(!stack_trace.IsEmpty());
14491 CHECK_EQ(1, stack_trace->GetFrameCount());
14492 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14496 // Test that the stack trace is captured where the bogus Error object is thrown.
14497 TEST(RethrowBogusErrorStackTrace) {
14498 v8::HandleScope scope;
14500 const char* source =
14501 "var e = {__proto__: new Error()} \n"
14503 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14504 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14505 CompileRun(source);
14506 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14507 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14511 v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
14512 v8::HandleScope scope;
14513 v8::Handle<v8::StackTrace> stackTrace =
14514 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14515 CHECK_EQ(5, stackTrace->GetFrameCount());
14516 v8::Handle<v8::String> url = v8_str("eval_url");
14517 for (int i = 0; i < 3; i++) {
14518 v8::Handle<v8::String> name =
14519 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14520 CHECK(!name.IsEmpty());
14521 CHECK_EQ(url, name);
14523 return v8::Undefined();
14527 TEST(SourceURLInStackTrace) {
14528 v8::HandleScope scope;
14529 Local<ObjectTemplate> templ = ObjectTemplate::New();
14530 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14531 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14532 LocalContext context(0, templ);
14534 const char *source =
14535 "function outer() {\n"
14536 "function bar() {\n"
14537 " AnalyzeStackOfEvalWithSourceURL();\n"
14539 "function foo() {\n"
14545 "eval('(' + outer +')()//@ sourceURL=eval_url');";
14546 CHECK(CompileRun(source)->IsUndefined());
14550 v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
14551 const v8::Arguments& args) {
14552 v8::HandleScope scope;
14553 v8::Handle<v8::StackTrace> stackTrace =
14554 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14555 CHECK_EQ(4, stackTrace->GetFrameCount());
14556 v8::Handle<v8::String> url = v8_str("url");
14557 for (int i = 0; i < 3; i++) {
14558 v8::Handle<v8::String> name =
14559 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14560 CHECK(!name.IsEmpty());
14561 CHECK_EQ(url, name);
14563 return v8::Undefined();
14567 TEST(InlineScriptWithSourceURLInStackTrace) {
14568 v8::HandleScope scope;
14569 Local<ObjectTemplate> templ = ObjectTemplate::New();
14570 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14571 v8::FunctionTemplate::New(
14572 AnalyzeStackOfInlineScriptWithSourceURL));
14573 LocalContext context(0, templ);
14575 const char *source =
14576 "function outer() {\n"
14577 "function bar() {\n"
14578 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14580 "function foo() {\n"
14587 "//@ sourceURL=source_url";
14588 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14592 v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
14593 const v8::Arguments& args) {
14594 v8::HandleScope scope;
14595 v8::Handle<v8::StackTrace> stackTrace =
14596 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14597 CHECK_EQ(4, stackTrace->GetFrameCount());
14598 v8::Handle<v8::String> url = v8_str("source_url");
14599 for (int i = 0; i < 3; i++) {
14600 v8::Handle<v8::String> name =
14601 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14602 CHECK(!name.IsEmpty());
14603 CHECK_EQ(url, name);
14605 return v8::Undefined();
14609 TEST(DynamicWithSourceURLInStackTrace) {
14610 v8::HandleScope scope;
14611 Local<ObjectTemplate> templ = ObjectTemplate::New();
14612 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14613 v8::FunctionTemplate::New(
14614 AnalyzeStackOfDynamicScriptWithSourceURL));
14615 LocalContext context(0, templ);
14617 const char *source =
14618 "function outer() {\n"
14619 "function bar() {\n"
14620 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14622 "function foo() {\n"
14629 "//@ sourceURL=source_url";
14630 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14633 static void CreateGarbageInOldSpace() {
14634 v8::HandleScope scope;
14635 i::AlwaysAllocateScope always_allocate;
14636 for (int i = 0; i < 1000; i++) {
14637 FACTORY->NewFixedArray(1000, i::TENURED);
14641 // Test that idle notification can be handled and eventually returns true.
14642 TEST(IdleNotification) {
14643 const intptr_t MB = 1024 * 1024;
14644 v8::HandleScope scope;
14646 intptr_t initial_size = HEAP->SizeOfObjects();
14647 CreateGarbageInOldSpace();
14648 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14649 CHECK_GT(size_with_garbage, initial_size + MB);
14650 bool finished = false;
14651 for (int i = 0; i < 200 && !finished; i++) {
14652 finished = v8::V8::IdleNotification();
14654 intptr_t final_size = HEAP->SizeOfObjects();
14656 CHECK_LT(final_size, initial_size + 1);
14660 // Test that idle notification can be handled and eventually collects garbage.
14661 TEST(IdleNotificationWithSmallHint) {
14662 const intptr_t MB = 1024 * 1024;
14663 const int IdlePauseInMs = 900;
14664 v8::HandleScope scope;
14666 intptr_t initial_size = HEAP->SizeOfObjects();
14667 CreateGarbageInOldSpace();
14668 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14669 CHECK_GT(size_with_garbage, initial_size + MB);
14670 bool finished = false;
14671 for (int i = 0; i < 200 && !finished; i++) {
14672 finished = v8::V8::IdleNotification(IdlePauseInMs);
14674 intptr_t final_size = HEAP->SizeOfObjects();
14676 CHECK_LT(final_size, initial_size + 1);
14680 // Test that idle notification can be handled and eventually collects garbage.
14681 TEST(IdleNotificationWithLargeHint) {
14682 const intptr_t MB = 1024 * 1024;
14683 const int IdlePauseInMs = 900;
14684 v8::HandleScope scope;
14686 intptr_t initial_size = HEAP->SizeOfObjects();
14687 CreateGarbageInOldSpace();
14688 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14689 CHECK_GT(size_with_garbage, initial_size + MB);
14690 bool finished = false;
14691 for (int i = 0; i < 200 && !finished; i++) {
14692 finished = v8::V8::IdleNotification(IdlePauseInMs);
14694 intptr_t final_size = HEAP->SizeOfObjects();
14696 CHECK_LT(final_size, initial_size + 1);
14700 TEST(Regress2107) {
14701 const intptr_t MB = 1024 * 1024;
14702 const int kShortIdlePauseInMs = 100;
14703 const int kLongIdlePauseInMs = 1000;
14704 v8::HandleScope scope;
14706 intptr_t initial_size = HEAP->SizeOfObjects();
14707 // Send idle notification to start a round of incremental GCs.
14708 v8::V8::IdleNotification(kShortIdlePauseInMs);
14709 // Emulate 7 page reloads.
14710 for (int i = 0; i < 7; i++) {
14711 v8::Persistent<v8::Context> ctx = v8::Context::New();
14713 CreateGarbageInOldSpace();
14716 v8::V8::ContextDisposedNotification();
14717 v8::V8::IdleNotification(kLongIdlePauseInMs);
14719 // Create garbage and check that idle notification still collects it.
14720 CreateGarbageInOldSpace();
14721 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14722 CHECK_GT(size_with_garbage, initial_size + MB);
14723 bool finished = false;
14724 for (int i = 0; i < 200 && !finished; i++) {
14725 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14727 intptr_t final_size = HEAP->SizeOfObjects();
14728 CHECK_LT(final_size, initial_size + 1);
14731 static uint32_t* stack_limit;
14733 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
14734 stack_limit = reinterpret_cast<uint32_t*>(
14735 i::Isolate::Current()->stack_guard()->real_climit());
14736 return v8::Undefined();
14740 // Uses the address of a local variable to determine the stack top now.
14741 // Given a size, returns an address that is that far from the current
14743 static uint32_t* ComputeStackLimit(uint32_t size) {
14744 uint32_t* answer = &size - (size / sizeof(size));
14745 // If the size is very large and the stack is very near the bottom of
14746 // memory then the calculation above may wrap around and give an address
14747 // that is above the (downwards-growing) stack. In that case we return
14748 // a very low address.
14749 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14754 TEST(SetResourceConstraints) {
14755 static const int K = 1024;
14756 uint32_t* set_limit = ComputeStackLimit(128 * K);
14758 // Set stack limit.
14759 v8::ResourceConstraints constraints;
14760 constraints.set_stack_limit(set_limit);
14761 CHECK(v8::SetResourceConstraints(&constraints));
14763 // Execute a script.
14764 v8::HandleScope scope;
14766 Local<v8::FunctionTemplate> fun_templ =
14767 v8::FunctionTemplate::New(GetStackLimitCallback);
14768 Local<Function> fun = fun_templ->GetFunction();
14769 env->Global()->Set(v8_str("get_stack_limit"), fun);
14770 CompileRun("get_stack_limit();");
14772 CHECK(stack_limit == set_limit);
14776 TEST(SetResourceConstraintsInThread) {
14777 uint32_t* set_limit;
14780 static const int K = 1024;
14781 set_limit = ComputeStackLimit(128 * K);
14783 // Set stack limit.
14784 v8::ResourceConstraints constraints;
14785 constraints.set_stack_limit(set_limit);
14786 CHECK(v8::SetResourceConstraints(&constraints));
14788 // Execute a script.
14789 v8::HandleScope scope;
14791 Local<v8::FunctionTemplate> fun_templ =
14792 v8::FunctionTemplate::New(GetStackLimitCallback);
14793 Local<Function> fun = fun_templ->GetFunction();
14794 env->Global()->Set(v8_str("get_stack_limit"), fun);
14795 CompileRun("get_stack_limit();");
14797 CHECK(stack_limit == set_limit);
14801 CHECK(stack_limit == set_limit);
14806 THREADED_TEST(GetHeapStatistics) {
14807 v8::HandleScope scope;
14809 v8::HeapStatistics heap_statistics;
14810 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14811 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
14812 v8::V8::GetHeapStatistics(&heap_statistics);
14813 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14814 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
14818 class VisitorImpl : public v8::ExternalResourceVisitor {
14820 VisitorImpl(TestResource* r1, TestResource* r2)
14823 found_resource1_(false),
14824 found_resource2_(false) {}
14825 virtual ~VisitorImpl() {}
14826 virtual void VisitExternalString(v8::Handle<v8::String> string) {
14827 if (!string->IsExternal()) {
14828 CHECK(string->IsExternalAscii());
14831 v8::String::ExternalStringResource* resource =
14832 string->GetExternalStringResource();
14834 if (resource1_ == resource) {
14835 CHECK(!found_resource1_);
14836 found_resource1_ = true;
14838 if (resource2_ == resource) {
14839 CHECK(!found_resource2_);
14840 found_resource2_ = true;
14843 void CheckVisitedResources() {
14844 CHECK(found_resource1_);
14845 CHECK(found_resource2_);
14849 v8::String::ExternalStringResource* resource1_;
14850 v8::String::ExternalStringResource* resource2_;
14851 bool found_resource1_;
14852 bool found_resource2_;
14855 TEST(VisitExternalStrings) {
14856 v8::HandleScope scope;
14858 const char* string = "Some string";
14859 uint16_t* two_byte_string = AsciiToTwoByteString(string);
14860 TestResource* resource1 = new TestResource(two_byte_string);
14861 v8::Local<v8::String> string1 = v8::String::NewExternal(resource1);
14862 TestResource* resource2 = new TestResource(two_byte_string);
14863 v8::Local<v8::String> string2 = v8::String::NewExternal(resource2);
14865 // We need to add usages for string1 and string2 to avoid warnings in GCC 4.7
14866 CHECK(string1->IsExternal());
14867 CHECK(string2->IsExternal());
14869 VisitorImpl visitor(resource1, resource2);
14870 v8::V8::VisitExternalResources(&visitor);
14871 visitor.CheckVisitedResources();
14875 static double DoubleFromBits(uint64_t value) {
14877 memcpy(&target, &value, sizeof(target));
14882 static uint64_t DoubleToBits(double value) {
14884 memcpy(&target, &value, sizeof(target));
14889 static double DoubleToDateTime(double input) {
14890 double date_limit = 864e13;
14891 if (IsNaN(input) || input < -date_limit || input > date_limit) {
14892 return i::OS::nan_value();
14894 return (input < 0) ? -(floor(-input)) : floor(input);
14897 // We don't have a consistent way to write 64-bit constants syntactically, so we
14898 // split them into two 32-bit constants and combine them programmatically.
14899 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
14900 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
14904 THREADED_TEST(QuietSignalingNaNs) {
14905 v8::HandleScope scope;
14906 LocalContext context;
14907 v8::TryCatch try_catch;
14909 // Special double values.
14910 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
14911 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
14912 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
14913 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
14914 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
14915 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
14916 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
14918 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
14919 // on either side of the epoch.
14920 double date_limit = 864e13;
14922 double test_values[] = {
14944 int num_test_values = 20;
14946 for (int i = 0; i < num_test_values; i++) {
14947 double test_value = test_values[i];
14949 // Check that Number::New preserves non-NaNs and quiets SNaNs.
14950 v8::Handle<v8::Value> number = v8::Number::New(test_value);
14951 double stored_number = number->NumberValue();
14952 if (!IsNaN(test_value)) {
14953 CHECK_EQ(test_value, stored_number);
14955 uint64_t stored_bits = DoubleToBits(stored_number);
14956 // Check if quiet nan (bits 51..62 all set).
14957 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14958 // Most significant fraction bit for quiet nan is set to 0
14959 // on MIPS architecture. Allowed by IEEE-754.
14960 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14962 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14966 // Check that Date::New preserves non-NaNs in the date range and
14968 v8::Handle<v8::Value> date = v8::Date::New(test_value);
14969 double expected_stored_date = DoubleToDateTime(test_value);
14970 double stored_date = date->NumberValue();
14971 if (!IsNaN(expected_stored_date)) {
14972 CHECK_EQ(expected_stored_date, stored_date);
14974 uint64_t stored_bits = DoubleToBits(stored_date);
14975 // Check if quiet nan (bits 51..62 all set).
14976 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
14977 // Most significant fraction bit for quiet nan is set to 0
14978 // on MIPS architecture. Allowed by IEEE-754.
14979 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
14981 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
14988 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
14989 v8::HandleScope scope;
14991 v8::Handle<v8::String> str(args[0]->ToString());
14993 if (tc.HasCaught())
14994 return tc.ReThrow();
14995 return v8::Undefined();
14999 // Test that an exception can be propagated down through a spaghetti
15000 // stack using ReThrow.
15001 THREADED_TEST(SpaghettiStackReThrow) {
15002 v8::HandleScope scope;
15003 LocalContext context;
15004 context->Global()->Set(
15005 v8::String::New("s"),
15006 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15007 v8::TryCatch try_catch;
15011 " toString: function () {"
15021 CHECK(try_catch.HasCaught());
15022 v8::String::Utf8Value value(try_catch.Exception());
15023 CHECK_EQ(0, strcmp(*value, "Hey!"));
15028 v8::V8::Initialize();
15030 v8::HandleScope scope;
15031 v8::Persistent<Context> context;
15032 v8::Persistent<Context> other_context;
15035 // Create a context used to keep the code from aging in the compilation
15037 other_context = Context::New();
15039 // Context-dependent context data creates reference from the compilation
15040 // cache to the global object.
15041 const char* source_simple = "1";
15042 context = Context::New();
15044 v8::HandleScope scope;
15047 Local<v8::String> obj = v8::String::New("");
15048 context->SetData(obj);
15049 CompileRun(source_simple);
15053 v8::V8::ContextDisposedNotification();
15054 for (gc_count = 1; gc_count < 10; gc_count++) {
15055 other_context->Enter();
15056 CompileRun(source_simple);
15057 other_context->Exit();
15058 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15059 if (GetGlobalObjectsCount() == 1) break;
15061 CHECK_GE(2, gc_count);
15062 CHECK_EQ(1, GetGlobalObjectsCount());
15064 // Eval in a function creates reference from the compilation cache to the
15066 const char* source_eval = "function f(){eval('1')}; f()";
15067 context = Context::New();
15069 v8::HandleScope scope;
15072 CompileRun(source_eval);
15076 v8::V8::ContextDisposedNotification();
15077 for (gc_count = 1; gc_count < 10; gc_count++) {
15078 other_context->Enter();
15079 CompileRun(source_eval);
15080 other_context->Exit();
15081 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15082 if (GetGlobalObjectsCount() == 1) break;
15084 CHECK_GE(2, gc_count);
15085 CHECK_EQ(1, GetGlobalObjectsCount());
15087 // Looking up the line number for an exception creates reference from the
15088 // compilation cache to the global object.
15089 const char* source_exception = "function f(){throw 1;} f()";
15090 context = Context::New();
15092 v8::HandleScope scope;
15095 v8::TryCatch try_catch;
15096 CompileRun(source_exception);
15097 CHECK(try_catch.HasCaught());
15098 v8::Handle<v8::Message> message = try_catch.Message();
15099 CHECK(!message.IsEmpty());
15100 CHECK_EQ(1, message->GetLineNumber());
15104 v8::V8::ContextDisposedNotification();
15105 for (gc_count = 1; gc_count < 10; gc_count++) {
15106 other_context->Enter();
15107 CompileRun(source_exception);
15108 other_context->Exit();
15109 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15110 if (GetGlobalObjectsCount() == 1) break;
15112 CHECK_GE(2, gc_count);
15113 CHECK_EQ(1, GetGlobalObjectsCount());
15115 other_context.Dispose();
15116 v8::V8::ContextDisposedNotification();
15120 THREADED_TEST(ScriptOrigin) {
15121 v8::HandleScope scope;
15123 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15124 v8::Handle<v8::String> script = v8::String::New(
15125 "function f() {}\n\nfunction g() {}");
15126 v8::Script::Compile(script, &origin)->Run();
15127 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15128 env->Global()->Get(v8::String::New("f")));
15129 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15130 env->Global()->Get(v8::String::New("g")));
15132 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15133 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15134 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15136 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15137 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15138 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15141 THREADED_TEST(FunctionGetInferredName) {
15142 v8::HandleScope scope;
15144 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15145 v8::Handle<v8::String> script = v8::String::New(
15146 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15147 v8::Script::Compile(script, &origin)->Run();
15148 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15149 env->Global()->Get(v8::String::New("f")));
15150 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15153 THREADED_TEST(ScriptLineNumber) {
15154 v8::HandleScope scope;
15156 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15157 v8::Handle<v8::String> script = v8::String::New(
15158 "function f() {}\n\nfunction g() {}");
15159 v8::Script::Compile(script, &origin)->Run();
15160 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15161 env->Global()->Get(v8::String::New("f")));
15162 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15163 env->Global()->Get(v8::String::New("g")));
15164 CHECK_EQ(0, f->GetScriptLineNumber());
15165 CHECK_EQ(2, g->GetScriptLineNumber());
15169 THREADED_TEST(ScriptColumnNumber) {
15170 v8::HandleScope scope;
15172 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15173 v8::Integer::New(3), v8::Integer::New(2));
15174 v8::Handle<v8::String> script = v8::String::New(
15175 "function foo() {}\n\n function bar() {}");
15176 v8::Script::Compile(script, &origin)->Run();
15177 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15178 env->Global()->Get(v8::String::New("foo")));
15179 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15180 env->Global()->Get(v8::String::New("bar")));
15181 CHECK_EQ(14, foo->GetScriptColumnNumber());
15182 CHECK_EQ(17, bar->GetScriptColumnNumber());
15186 THREADED_TEST(FunctionGetScriptId) {
15187 v8::HandleScope scope;
15189 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15190 v8::Integer::New(3), v8::Integer::New(2));
15191 v8::Handle<v8::String> scriptSource = v8::String::New(
15192 "function foo() {}\n\n function bar() {}");
15193 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15195 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15196 env->Global()->Get(v8::String::New("foo")));
15197 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15198 env->Global()->Get(v8::String::New("bar")));
15199 CHECK_EQ(script->Id(), foo->GetScriptId());
15200 CHECK_EQ(script->Id(), bar->GetScriptId());
15204 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15205 const AccessorInfo& info) {
15206 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15207 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15212 static void SetterWhichSetsYOnThisTo23(Local<String> name,
15213 Local<Value> value,
15214 const AccessorInfo& info) {
15215 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15216 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15217 info.This()->Set(v8_str("y"), v8_num(23));
15221 Handle<Value> FooGetInterceptor(Local<String> name,
15222 const AccessorInfo& info) {
15223 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15224 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15225 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15230 Handle<Value> FooSetInterceptor(Local<String> name,
15231 Local<Value> value,
15232 const AccessorInfo& info) {
15233 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15234 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
15235 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15236 info.This()->Set(v8_str("y"), v8_num(23));
15241 TEST(SetterOnConstructorPrototype) {
15242 v8::HandleScope scope;
15243 Local<ObjectTemplate> templ = ObjectTemplate::New();
15244 templ->SetAccessor(v8_str("x"),
15245 GetterWhichReturns42,
15246 SetterWhichSetsYOnThisTo23);
15247 LocalContext context;
15248 context->Global()->Set(v8_str("P"), templ->NewInstance());
15249 CompileRun("function C1() {"
15252 "C1.prototype = P;"
15256 "C2.prototype = { };"
15257 "C2.prototype.__proto__ = P;");
15259 v8::Local<v8::Script> script;
15260 script = v8::Script::Compile(v8_str("new C1();"));
15261 for (int i = 0; i < 10; i++) {
15262 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15263 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15264 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15267 script = v8::Script::Compile(v8_str("new C2();"));
15268 for (int i = 0; i < 10; i++) {
15269 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15270 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15271 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15276 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15277 Local<String> name, const AccessorInfo& info) {
15282 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15283 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15284 if (name->Equals(v8_str("x"))) {
15285 info.This()->Set(v8_str("y"), v8_num(23));
15287 return v8::Handle<Value>();
15291 THREADED_TEST(InterceptorOnConstructorPrototype) {
15292 v8::HandleScope scope;
15293 Local<ObjectTemplate> templ = ObjectTemplate::New();
15294 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15295 NamedPropertySetterWhichSetsYOnThisTo23);
15296 LocalContext context;
15297 context->Global()->Set(v8_str("P"), templ->NewInstance());
15298 CompileRun("function C1() {"
15301 "C1.prototype = P;"
15305 "C2.prototype = { };"
15306 "C2.prototype.__proto__ = P;");
15308 v8::Local<v8::Script> script;
15309 script = v8::Script::Compile(v8_str("new C1();"));
15310 for (int i = 0; i < 10; i++) {
15311 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15312 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15313 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15316 script = v8::Script::Compile(v8_str("new C2();"));
15317 for (int i = 0; i < 10; i++) {
15318 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15319 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15320 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15326 const char* source = "function C1() {"
15329 "C1.prototype = P;";
15331 v8::HandleScope scope;
15332 LocalContext context;
15333 v8::Local<v8::Script> script;
15335 // Use a simple object as prototype.
15336 v8::Local<v8::Object> prototype = v8::Object::New();
15337 prototype->Set(v8_str("y"), v8_num(42));
15338 context->Global()->Set(v8_str("P"), prototype);
15340 // This compile will add the code to the compilation cache.
15341 CompileRun(source);
15343 script = v8::Script::Compile(v8_str("new C1();"));
15344 // Allow enough iterations for the inobject slack tracking logic
15345 // to finalize instance size and install the fast construct stub.
15346 for (int i = 0; i < 256; i++) {
15347 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15348 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15349 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15352 // Use an API object with accessors as prototype.
15353 Local<ObjectTemplate> templ = ObjectTemplate::New();
15354 templ->SetAccessor(v8_str("x"),
15355 GetterWhichReturns42,
15356 SetterWhichSetsYOnThisTo23);
15357 context->Global()->Set(v8_str("P"), templ->NewInstance());
15359 // This compile will get the code from the compilation cache.
15360 CompileRun(source);
15362 script = v8::Script::Compile(v8_str("new C1();"));
15363 for (int i = 0; i < 10; i++) {
15364 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15365 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15366 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15370 int prologue_call_count = 0;
15371 int epilogue_call_count = 0;
15372 int prologue_call_count_second = 0;
15373 int epilogue_call_count_second = 0;
15375 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15376 ++prologue_call_count;
15379 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15380 ++epilogue_call_count;
15383 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15384 ++prologue_call_count_second;
15387 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15388 ++epilogue_call_count_second;
15391 TEST(GCCallbacks) {
15392 LocalContext context;
15394 v8::V8::AddGCPrologueCallback(PrologueCallback);
15395 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15396 CHECK_EQ(0, prologue_call_count);
15397 CHECK_EQ(0, epilogue_call_count);
15398 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15399 CHECK_EQ(1, prologue_call_count);
15400 CHECK_EQ(1, epilogue_call_count);
15401 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15402 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
15403 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15404 CHECK_EQ(2, prologue_call_count);
15405 CHECK_EQ(2, epilogue_call_count);
15406 CHECK_EQ(1, prologue_call_count_second);
15407 CHECK_EQ(1, epilogue_call_count_second);
15408 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15409 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
15410 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15411 CHECK_EQ(2, prologue_call_count);
15412 CHECK_EQ(2, epilogue_call_count);
15413 CHECK_EQ(2, prologue_call_count_second);
15414 CHECK_EQ(2, epilogue_call_count_second);
15415 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15416 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
15417 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15418 CHECK_EQ(2, prologue_call_count);
15419 CHECK_EQ(2, epilogue_call_count);
15420 CHECK_EQ(2, prologue_call_count_second);
15421 CHECK_EQ(2, epilogue_call_count_second);
15425 THREADED_TEST(AddToJSFunctionResultCache) {
15426 i::FLAG_allow_natives_syntax = true;
15427 v8::HandleScope scope;
15429 LocalContext context;
15435 " var r0 = %_GetFromCache(0, key0);"
15436 " var r1 = %_GetFromCache(0, key1);"
15437 " var r0_ = %_GetFromCache(0, key0);"
15439 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15440 " var r1_ = %_GetFromCache(0, key1);"
15442 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15443 " return 'PASSED';"
15445 HEAP->ClearJSFunctionResultCaches();
15446 ExpectString(code, "PASSED");
15450 static const int k0CacheSize = 16;
15452 THREADED_TEST(FillJSFunctionResultCache) {
15453 i::FLAG_allow_natives_syntax = true;
15454 v8::HandleScope scope;
15456 LocalContext context;
15461 " var r = %_GetFromCache(0, k);"
15462 " for (var i = 0; i < 16; i++) {"
15463 " %_GetFromCache(0, 'a' + i);"
15465 " if (r === %_GetFromCache(0, k))"
15466 " return 'FAILED: k0CacheSize is too small';"
15467 " return 'PASSED';"
15469 HEAP->ClearJSFunctionResultCaches();
15470 ExpectString(code, "PASSED");
15474 THREADED_TEST(RoundRobinGetFromCache) {
15475 i::FLAG_allow_natives_syntax = true;
15476 v8::HandleScope scope;
15478 LocalContext context;
15483 " for (var i = 0; i < 16; i++) keys.push(i);"
15484 " var values = [];"
15485 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15486 " for (var i = 0; i < 16; i++) {"
15487 " var v = %_GetFromCache(0, keys[i]);"
15488 " if (v.toString() !== values[i].toString())"
15489 " return 'Wrong value for ' + "
15490 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15492 " return 'PASSED';"
15494 HEAP->ClearJSFunctionResultCaches();
15495 ExpectString(code, "PASSED");
15499 THREADED_TEST(ReverseGetFromCache) {
15500 i::FLAG_allow_natives_syntax = true;
15501 v8::HandleScope scope;
15503 LocalContext context;
15508 " for (var i = 0; i < 16; i++) keys.push(i);"
15509 " var values = [];"
15510 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15511 " for (var i = 15; i >= 16; i--) {"
15512 " var v = %_GetFromCache(0, keys[i]);"
15513 " if (v !== values[i])"
15514 " return 'Wrong value for ' + "
15515 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15517 " return 'PASSED';"
15519 HEAP->ClearJSFunctionResultCaches();
15520 ExpectString(code, "PASSED");
15524 THREADED_TEST(TestEviction) {
15525 i::FLAG_allow_natives_syntax = true;
15526 v8::HandleScope scope;
15528 LocalContext context;
15532 " for (var i = 0; i < 2*16; i++) {"
15533 " %_GetFromCache(0, 'a' + i);"
15535 " return 'PASSED';"
15537 HEAP->ClearJSFunctionResultCaches();
15538 ExpectString(code, "PASSED");
15542 THREADED_TEST(TwoByteStringInAsciiCons) {
15543 // See Chromium issue 47824.
15544 v8::HandleScope scope;
15546 LocalContext context;
15547 const char* init_code =
15548 "var str1 = 'abelspendabel';"
15549 "var str2 = str1 + str1 + str1;"
15551 Local<Value> result = CompileRun(init_code);
15553 Local<Value> indexof = CompileRun("str2.indexOf('els')");
15554 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15556 CHECK(result->IsString());
15557 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15558 int length = string->length();
15559 CHECK(string->IsAsciiRepresentation());
15561 FlattenString(string);
15562 i::Handle<i::String> flat_string = FlattenGetString(string);
15564 CHECK(string->IsAsciiRepresentation());
15565 CHECK(flat_string->IsAsciiRepresentation());
15567 // Create external resource.
15568 uint16_t* uc16_buffer = new uint16_t[length + 1];
15570 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15571 uc16_buffer[length] = 0;
15573 TestResource resource(uc16_buffer);
15575 flat_string->MakeExternal(&resource);
15577 CHECK(flat_string->IsTwoByteRepresentation());
15579 // At this point, we should have a Cons string which is flat and ASCII,
15580 // with a first half that is a two-byte string (although it only contains
15581 // ASCII characters). This is a valid sequence of steps, and it can happen
15584 CHECK(string->IsAsciiRepresentation());
15585 i::ConsString* cons = i::ConsString::cast(*string);
15586 CHECK_EQ(0, cons->second()->length());
15587 CHECK(cons->first()->IsTwoByteRepresentation());
15589 // Check that some string operations work.
15592 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15593 CHECK_EQ(6, reresult->Int32Value());
15596 reresult = CompileRun("str2.match(/abe./g).length;");
15597 CHECK_EQ(6, reresult->Int32Value());
15599 reresult = CompileRun("str2.search(/bel/g);");
15600 CHECK_EQ(1, reresult->Int32Value());
15602 reresult = CompileRun("str2.search(/be./g);");
15603 CHECK_EQ(1, reresult->Int32Value());
15605 ExpectTrue("/bel/g.test(str2);");
15607 ExpectTrue("/be./g.test(str2);");
15609 reresult = CompileRun("/bel/g.exec(str2);");
15610 CHECK(!reresult->IsNull());
15612 reresult = CompileRun("/be./g.exec(str2);");
15613 CHECK(!reresult->IsNull());
15615 ExpectString("str2.substring(2, 10);", "elspenda");
15617 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15619 ExpectString("str2.charAt(2);", "e");
15621 ExpectObject("str2.indexOf('els');", indexof);
15623 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15625 reresult = CompileRun("str2.charCodeAt(2);");
15626 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
15630 // Failed access check callback that performs a GC on each invocation.
15631 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
15632 v8::AccessType type,
15633 Local<v8::Value> data) {
15634 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15638 TEST(GCInFailedAccessCheckCallback) {
15639 // Install a failed access check callback that performs a GC on each
15640 // invocation. Then force the callback to be called from va
15642 v8::V8::Initialize();
15643 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
15645 v8::HandleScope scope;
15647 // Create an ObjectTemplate for global objects and install access
15648 // check callbacks that will block access.
15649 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
15650 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15651 IndexedGetAccessBlocker,
15652 v8::Handle<v8::Value>(),
15655 // Create a context and set an x property on it's global object.
15656 LocalContext context0(NULL, global_template);
15657 context0->Global()->Set(v8_str("x"), v8_num(42));
15658 v8::Handle<v8::Object> global0 = context0->Global();
15660 // Create a context with a different security token so that the
15661 // failed access check callback will be called on each access.
15662 LocalContext context1(NULL, global_template);
15663 context1->Global()->Set(v8_str("other"), global0);
15665 // Get property with failed access check.
15666 ExpectUndefined("other.x");
15668 // Get element with failed access check.
15669 ExpectUndefined("other[0]");
15671 // Set property with failed access check.
15672 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15673 CHECK(result->IsObject());
15675 // Set element with failed access check.
15676 result = CompileRun("other[0] = new Object()");
15677 CHECK(result->IsObject());
15679 // Get property attribute with failed access check.
15680 ExpectFalse("\'x\' in other");
15682 // Get property attribute for element with failed access check.
15683 ExpectFalse("0 in other");
15685 // Delete property.
15686 ExpectFalse("delete other.x");
15689 CHECK_EQ(false, global0->Delete(0));
15693 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15695 // Define JavaScript accessor.
15696 ExpectUndefined("Object.prototype.__defineGetter__.call("
15697 " other, \'x\', function() { return 42; })");
15700 ExpectUndefined("Object.prototype.__lookupGetter__.call("
15703 // HasLocalElement.
15704 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15706 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15707 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15708 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15710 // Reset the failed access check callback so it does not influence
15711 // the other tests.
15712 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
15715 TEST(DefaultIsolateGetCurrent) {
15716 CHECK(v8::Isolate::GetCurrent() != NULL);
15717 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15718 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15719 printf("*** %s\n", "DefaultIsolateGetCurrent success");
15722 TEST(IsolateNewDispose) {
15723 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15724 v8::Isolate* isolate = v8::Isolate::New();
15725 CHECK(isolate != NULL);
15726 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15727 CHECK(current_isolate != isolate);
15728 CHECK(current_isolate == v8::Isolate::GetCurrent());
15730 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15731 last_location = last_message = NULL;
15732 isolate->Dispose();
15733 CHECK_EQ(last_location, NULL);
15734 CHECK_EQ(last_message, NULL);
15737 TEST(IsolateEnterExitDefault) {
15738 v8::HandleScope scope;
15739 LocalContext context;
15740 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15741 CHECK(current_isolate != NULL); // Default isolate.
15742 ExpectString("'hello'", "hello");
15743 current_isolate->Enter();
15744 ExpectString("'still working'", "still working");
15745 current_isolate->Exit();
15746 ExpectString("'still working 2'", "still working 2");
15747 current_isolate->Exit();
15748 // Default isolate is always, well, 'default current'.
15749 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15750 // Still working since default isolate is auto-entering any thread
15751 // that has no isolate and attempts to execute V8 APIs.
15752 ExpectString("'still working 3'", "still working 3");
15755 TEST(DisposeDefaultIsolate) {
15756 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15758 // Run some V8 code to trigger default isolate to become 'current'.
15759 v8::HandleScope scope;
15760 LocalContext context;
15761 ExpectString("'run some V8'", "run some V8");
15763 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15764 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15765 last_location = last_message = NULL;
15766 isolate->Dispose();
15767 // It is not possible to dispose default isolate via Isolate API.
15768 CHECK_NE(last_location, NULL);
15769 CHECK_NE(last_message, NULL);
15772 TEST(RunDefaultAndAnotherIsolate) {
15773 v8::HandleScope scope;
15774 LocalContext context;
15776 // Enter new isolate.
15777 v8::Isolate* isolate = v8::Isolate::New();
15780 { // Need this block because subsequent Exit() will deallocate Heap,
15781 // so we need all scope objects to be deconstructed when it happens.
15782 v8::HandleScope scope_new;
15783 LocalContext context_new;
15785 // Run something in new isolate.
15786 CompileRun("var foo = 153;");
15787 ExpectTrue("function f() { return foo == 153; }; f()");
15791 // This runs automatically in default isolate.
15792 // Variables in another isolate should be not available.
15793 ExpectTrue("function f() {"
15804 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15805 last_location = last_message = NULL;
15806 isolate->Dispose();
15807 CHECK_EQ(last_location, NULL);
15808 CHECK_EQ(last_message, NULL);
15810 // Check that default isolate still runs.
15811 ExpectTrue("function f() { return bar == 371; }; f()");
15814 TEST(DisposeIsolateWhenInUse) {
15815 v8::Isolate* isolate = v8::Isolate::New();
15818 v8::HandleScope scope;
15819 LocalContext context;
15820 // Run something in this isolate.
15821 ExpectTrue("true");
15822 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15823 last_location = last_message = NULL;
15824 // Still entered, should fail.
15825 isolate->Dispose();
15826 CHECK_NE(last_location, NULL);
15827 CHECK_NE(last_message, NULL);
15830 TEST(RunTwoIsolatesOnSingleThread) {
15832 v8::Isolate* isolate1 = v8::Isolate::New();
15834 v8::Persistent<v8::Context> context1 = v8::Context::New();
15837 v8::Context::Scope cscope(context1);
15838 v8::HandleScope scope;
15839 // Run something in new isolate.
15840 CompileRun("var foo = 'isolate 1';");
15841 ExpectString("function f() { return foo; }; f()", "isolate 1");
15845 v8::Isolate* isolate2 = v8::Isolate::New();
15846 v8::Persistent<v8::Context> context2;
15849 v8::Isolate::Scope iscope(isolate2);
15850 context2 = v8::Context::New();
15851 v8::Context::Scope cscope(context2);
15852 v8::HandleScope scope;
15854 // Run something in new isolate.
15855 CompileRun("var foo = 'isolate 2';");
15856 ExpectString("function f() { return foo; }; f()", "isolate 2");
15860 v8::Context::Scope cscope(context1);
15861 v8::HandleScope scope;
15862 // Now again in isolate 1
15863 ExpectString("function f() { return foo; }; f()", "isolate 1");
15868 // Run some stuff in default isolate.
15869 v8::Persistent<v8::Context> context_default = v8::Context::New();
15872 v8::Context::Scope cscope(context_default);
15873 v8::HandleScope scope;
15874 // Variables in other isolates should be not available, verify there
15875 // is an exception.
15876 ExpectTrue("function f() {"
15884 "var isDefaultIsolate = true;"
15891 v8::Isolate::Scope iscope(isolate2);
15892 v8::Context::Scope cscope(context2);
15893 v8::HandleScope scope;
15894 ExpectString("function f() { return foo; }; f()", "isolate 2");
15898 v8::Context::Scope cscope(context1);
15899 v8::HandleScope scope;
15900 ExpectString("function f() { return foo; }; f()", "isolate 1");
15904 v8::Isolate::Scope iscope(isolate2);
15905 context2.Dispose();
15908 context1.Dispose();
15911 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15912 last_location = last_message = NULL;
15914 isolate1->Dispose();
15915 CHECK_EQ(last_location, NULL);
15916 CHECK_EQ(last_message, NULL);
15918 isolate2->Dispose();
15919 CHECK_EQ(last_location, NULL);
15920 CHECK_EQ(last_message, NULL);
15922 // Check that default isolate still runs.
15924 v8::Context::Scope cscope(context_default);
15925 v8::HandleScope scope;
15926 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
15930 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
15931 v8::Isolate::Scope isolate_scope(isolate);
15932 v8::HandleScope scope;
15933 LocalContext context;
15934 i::ScopedVector<char> code(1024);
15935 i::OS::SNPrintF(code, "function fib(n) {"
15936 " if (n <= 2) return 1;"
15937 " return fib(n-1) + fib(n-2);"
15940 Local<Value> value = CompileRun(code.start());
15941 CHECK(value->IsNumber());
15942 return static_cast<int>(value->NumberValue());
15945 class IsolateThread : public v8::internal::Thread {
15947 IsolateThread(v8::Isolate* isolate, int fib_limit)
15948 : Thread("IsolateThread"),
15950 fib_limit_(fib_limit),
15954 result_ = CalcFibonacci(isolate_, fib_limit_);
15957 int result() { return result_; }
15960 v8::Isolate* isolate_;
15965 TEST(MultipleIsolatesOnIndividualThreads) {
15966 v8::Isolate* isolate1 = v8::Isolate::New();
15967 v8::Isolate* isolate2 = v8::Isolate::New();
15969 IsolateThread thread1(isolate1, 21);
15970 IsolateThread thread2(isolate2, 12);
15972 // Compute some fibonacci numbers on 3 threads in 3 isolates.
15976 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
15977 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
15982 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
15983 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
15984 CHECK_EQ(result1, 10946);
15985 CHECK_EQ(result2, 144);
15986 CHECK_EQ(result1, thread1.result());
15987 CHECK_EQ(result2, thread2.result());
15989 isolate1->Dispose();
15990 isolate2->Dispose();
15993 TEST(IsolateDifferentContexts) {
15994 v8::Isolate* isolate = v8::Isolate::New();
15995 Persistent<v8::Context> context;
15997 v8::Isolate::Scope isolate_scope(isolate);
15998 v8::HandleScope handle_scope;
15999 context = v8::Context::New();
16000 v8::Context::Scope context_scope(context);
16001 Local<Value> v = CompileRun("2");
16002 CHECK(v->IsNumber());
16003 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16006 v8::Isolate::Scope isolate_scope(isolate);
16007 v8::HandleScope handle_scope;
16008 context = v8::Context::New();
16009 v8::Context::Scope context_scope(context);
16010 Local<Value> v = CompileRun("22");
16011 CHECK(v->IsNumber());
16012 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16016 class InitDefaultIsolateThread : public v8::internal::Thread {
16020 SetResourceConstraints,
16022 SetCounterFunction,
16023 SetCreateHistogramFunction,
16024 SetAddHistogramSampleFunction
16027 explicit InitDefaultIsolateThread(TestCase testCase)
16028 : Thread("InitDefaultIsolateThread"),
16029 testCase_(testCase),
16033 switch (testCase_) {
16035 v8::V8::IgnoreOutOfMemoryException();
16038 case SetResourceConstraints: {
16039 static const int K = 1024;
16040 v8::ResourceConstraints constraints;
16041 constraints.set_max_young_space_size(256 * K);
16042 constraints.set_max_old_space_size(4 * K * K);
16043 v8::SetResourceConstraints(&constraints);
16047 case SetFatalHandler:
16048 v8::V8::SetFatalErrorHandler(NULL);
16051 case SetCounterFunction:
16052 v8::V8::SetCounterFunction(NULL);
16055 case SetCreateHistogramFunction:
16056 v8::V8::SetCreateHistogramFunction(NULL);
16059 case SetAddHistogramSampleFunction:
16060 v8::V8::SetAddHistogramSampleFunction(NULL);
16066 bool result() { return result_; }
16069 TestCase testCase_;
16074 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16075 InitDefaultIsolateThread thread(testCase);
16078 CHECK_EQ(thread.result(), true);
16081 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16082 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16085 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16086 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16089 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16090 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16093 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16094 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16097 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16098 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16101 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16102 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16106 TEST(StringCheckMultipleContexts) {
16108 "(function() { return \"a\".charAt(0); })()";
16111 // Run the code twice in the first context to initialize the call IC.
16112 v8::HandleScope scope;
16113 LocalContext context1;
16114 ExpectString(code, "a");
16115 ExpectString(code, "a");
16119 // Change the String.prototype in the second context and check
16120 // that the right function gets called.
16121 v8::HandleScope scope;
16122 LocalContext context2;
16123 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16124 ExpectString(code, "not a");
16129 TEST(NumberCheckMultipleContexts) {
16131 "(function() { return (42).toString(); })()";
16134 // Run the code twice in the first context to initialize the call IC.
16135 v8::HandleScope scope;
16136 LocalContext context1;
16137 ExpectString(code, "42");
16138 ExpectString(code, "42");
16142 // Change the Number.prototype in the second context and check
16143 // that the right function gets called.
16144 v8::HandleScope scope;
16145 LocalContext context2;
16146 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16147 ExpectString(code, "not 42");
16152 TEST(BooleanCheckMultipleContexts) {
16154 "(function() { return true.toString(); })()";
16157 // Run the code twice in the first context to initialize the call IC.
16158 v8::HandleScope scope;
16159 LocalContext context1;
16160 ExpectString(code, "true");
16161 ExpectString(code, "true");
16165 // Change the Boolean.prototype in the second context and check
16166 // that the right function gets called.
16167 v8::HandleScope scope;
16168 LocalContext context2;
16169 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16170 ExpectString(code, "");
16175 TEST(DontDeleteCellLoadIC) {
16176 const char* function_code =
16177 "function readCell() { while (true) { return cell; } }";
16180 // Run the code twice in the first context to initialize the load
16181 // IC for a don't delete cell.
16182 v8::HandleScope scope;
16183 LocalContext context1;
16184 CompileRun("var cell = \"first\";");
16185 ExpectBoolean("delete cell", false);
16186 CompileRun(function_code);
16187 ExpectString("readCell()", "first");
16188 ExpectString("readCell()", "first");
16192 // Use a deletable cell in the second context.
16193 v8::HandleScope scope;
16194 LocalContext context2;
16195 CompileRun("cell = \"second\";");
16196 CompileRun(function_code);
16197 ExpectString("readCell()", "second");
16198 ExpectBoolean("delete cell", true);
16199 ExpectString("(function() {"
16201 " return readCell();"
16203 " return e.toString();"
16206 "ReferenceError: cell is not defined");
16207 CompileRun("cell = \"new_second\";");
16208 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16209 ExpectString("readCell()", "new_second");
16210 ExpectString("readCell()", "new_second");
16215 TEST(DontDeleteCellLoadICForceDelete) {
16216 const char* function_code =
16217 "function readCell() { while (true) { return cell; } }";
16219 // Run the code twice to initialize the load IC for a don't delete
16221 v8::HandleScope scope;
16222 LocalContext context;
16223 CompileRun("var cell = \"value\";");
16224 ExpectBoolean("delete cell", false);
16225 CompileRun(function_code);
16226 ExpectString("readCell()", "value");
16227 ExpectString("readCell()", "value");
16229 // Delete the cell using the API and check the inlined code works
16231 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16232 ExpectString("(function() {"
16234 " return readCell();"
16236 " return e.toString();"
16239 "ReferenceError: cell is not defined");
16243 TEST(DontDeleteCellLoadICAPI) {
16244 const char* function_code =
16245 "function readCell() { while (true) { return cell; } }";
16247 // Run the code twice to initialize the load IC for a don't delete
16248 // cell created using the API.
16249 v8::HandleScope scope;
16250 LocalContext context;
16251 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16252 ExpectBoolean("delete cell", false);
16253 CompileRun(function_code);
16254 ExpectString("readCell()", "value");
16255 ExpectString("readCell()", "value");
16257 // Delete the cell using the API and check the inlined code works
16259 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16260 ExpectString("(function() {"
16262 " return readCell();"
16264 " return e.toString();"
16267 "ReferenceError: cell is not defined");
16271 class Visitor42 : public v8::PersistentHandleVisitor {
16273 explicit Visitor42(v8::Persistent<v8::Object> object)
16274 : counter_(0), object_(object) { }
16276 virtual void VisitPersistentHandle(Persistent<Value> value,
16277 uint16_t class_id) {
16278 if (class_id == 42) {
16279 CHECK(value->IsObject());
16280 v8::Persistent<v8::Object> visited =
16281 v8::Persistent<v8::Object>::Cast(value);
16282 CHECK_EQ(42, visited.WrapperClassId());
16283 CHECK_EQ(object_, visited);
16289 v8::Persistent<v8::Object> object_;
16293 TEST(PersistentHandleVisitor) {
16294 v8::HandleScope scope;
16295 LocalContext context;
16296 v8::Persistent<v8::Object> object =
16297 v8::Persistent<v8::Object>::New(v8::Object::New());
16298 CHECK_EQ(0, object.WrapperClassId());
16299 object.SetWrapperClassId(42);
16300 CHECK_EQ(42, object.WrapperClassId());
16302 Visitor42 visitor(object);
16303 v8::V8::VisitHandlesWithClassIds(&visitor);
16304 CHECK_EQ(1, visitor.counter_);
16311 v8::HandleScope scope;
16312 LocalContext context;
16314 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16315 CHECK(re->IsRegExp());
16316 CHECK(re->GetSource()->Equals(v8_str("foo")));
16317 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
16319 re = v8::RegExp::New(v8_str("bar"),
16320 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16321 v8::RegExp::kGlobal));
16322 CHECK(re->IsRegExp());
16323 CHECK(re->GetSource()->Equals(v8_str("bar")));
16324 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16325 static_cast<int>(re->GetFlags()));
16327 re = v8::RegExp::New(v8_str("baz"),
16328 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16329 v8::RegExp::kMultiline));
16330 CHECK(re->IsRegExp());
16331 CHECK(re->GetSource()->Equals(v8_str("baz")));
16332 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16333 static_cast<int>(re->GetFlags()));
16335 re = CompileRun("/quux/").As<v8::RegExp>();
16336 CHECK(re->IsRegExp());
16337 CHECK(re->GetSource()->Equals(v8_str("quux")));
16338 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
16340 re = CompileRun("/quux/gm").As<v8::RegExp>();
16341 CHECK(re->IsRegExp());
16342 CHECK(re->GetSource()->Equals(v8_str("quux")));
16343 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16344 static_cast<int>(re->GetFlags()));
16346 // Override the RegExp constructor and check the API constructor
16348 CompileRun("RegExp = function() {}");
16350 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16351 CHECK(re->IsRegExp());
16352 CHECK(re->GetSource()->Equals(v8_str("foobar")));
16353 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
16355 re = v8::RegExp::New(v8_str("foobarbaz"),
16356 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16357 v8::RegExp::kMultiline));
16358 CHECK(re->IsRegExp());
16359 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
16360 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16361 static_cast<int>(re->GetFlags()));
16363 context->Global()->Set(v8_str("re"), re);
16364 ExpectTrue("re.test('FoobarbaZ')");
16366 // RegExps are objects on which you can set properties.
16367 re->Set(v8_str("property"), v8::Integer::New(32));
16368 v8::Handle<v8::Value> value(CompileRun("re.property"));
16369 CHECK_EQ(32, value->Int32Value());
16371 v8::TryCatch try_catch;
16372 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16373 CHECK(re.IsEmpty());
16374 CHECK(try_catch.HasCaught());
16375 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16376 ExpectTrue("ex instanceof SyntaxError");
16380 THREADED_TEST(Equals) {
16381 v8::HandleScope handleScope;
16382 LocalContext localContext;
16384 v8::Handle<v8::Object> globalProxy = localContext->Global();
16385 v8::Handle<Value> global = globalProxy->GetPrototype();
16387 CHECK(global->StrictEquals(global));
16388 CHECK(!global->StrictEquals(globalProxy));
16389 CHECK(!globalProxy->StrictEquals(global));
16390 CHECK(globalProxy->StrictEquals(globalProxy));
16392 CHECK(global->Equals(global));
16393 CHECK(!global->Equals(globalProxy));
16394 CHECK(!globalProxy->Equals(global));
16395 CHECK(globalProxy->Equals(globalProxy));
16399 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16400 const v8::AccessorInfo& info ) {
16401 return v8_str("42!");
16405 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16406 v8::Handle<v8::Array> result = v8::Array::New();
16407 result->Set(0, v8_str("universalAnswer"));
16412 TEST(NamedEnumeratorAndForIn) {
16413 v8::HandleScope handle_scope;
16414 LocalContext context;
16415 v8::Context::Scope context_scope(context.local());
16417 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16418 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16419 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16420 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16421 "var result = []; for (var k in o) result.push(k); result"));
16422 CHECK_EQ(1, result->Length());
16423 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16427 TEST(DefinePropertyPostDetach) {
16428 v8::HandleScope scope;
16429 LocalContext context;
16430 v8::Handle<v8::Object> proxy = context->Global();
16431 v8::Handle<v8::Function> define_property =
16432 CompileRun("(function() {"
16433 " Object.defineProperty("
16436 " { configurable: true, enumerable: true, value: 3 });"
16437 "})").As<Function>();
16438 context->DetachGlobal();
16439 define_property->Call(proxy, 0, NULL);
16443 static void InstallContextId(v8::Handle<Context> context, int id) {
16444 Context::Scope scope(context);
16445 CompileRun("Object.prototype").As<Object>()->
16446 Set(v8_str("context_id"), v8::Integer::New(id));
16450 static void CheckContextId(v8::Handle<Object> object, int expected) {
16451 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16455 THREADED_TEST(CreationContext) {
16456 HandleScope handle_scope;
16457 Persistent<Context> context1 = Context::New();
16458 InstallContextId(context1, 1);
16459 Persistent<Context> context2 = Context::New();
16460 InstallContextId(context2, 2);
16461 Persistent<Context> context3 = Context::New();
16462 InstallContextId(context3, 3);
16464 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16466 Local<Object> object1;
16467 Local<Function> func1;
16469 Context::Scope scope(context1);
16470 object1 = Object::New();
16471 func1 = tmpl->GetFunction();
16474 Local<Object> object2;
16475 Local<Function> func2;
16477 Context::Scope scope(context2);
16478 object2 = Object::New();
16479 func2 = tmpl->GetFunction();
16482 Local<Object> instance1;
16483 Local<Object> instance2;
16486 Context::Scope scope(context3);
16487 instance1 = func1->NewInstance();
16488 instance2 = func2->NewInstance();
16491 CHECK(object1->CreationContext() == context1);
16492 CheckContextId(object1, 1);
16493 CHECK(func1->CreationContext() == context1);
16494 CheckContextId(func1, 1);
16495 CHECK(instance1->CreationContext() == context1);
16496 CheckContextId(instance1, 1);
16497 CHECK(object2->CreationContext() == context2);
16498 CheckContextId(object2, 2);
16499 CHECK(func2->CreationContext() == context2);
16500 CheckContextId(func2, 2);
16501 CHECK(instance2->CreationContext() == context2);
16502 CheckContextId(instance2, 2);
16505 Context::Scope scope(context1);
16506 CHECK(object1->CreationContext() == context1);
16507 CheckContextId(object1, 1);
16508 CHECK(func1->CreationContext() == context1);
16509 CheckContextId(func1, 1);
16510 CHECK(instance1->CreationContext() == context1);
16511 CheckContextId(instance1, 1);
16512 CHECK(object2->CreationContext() == context2);
16513 CheckContextId(object2, 2);
16514 CHECK(func2->CreationContext() == context2);
16515 CheckContextId(func2, 2);
16516 CHECK(instance2->CreationContext() == context2);
16517 CheckContextId(instance2, 2);
16521 Context::Scope scope(context2);
16522 CHECK(object1->CreationContext() == context1);
16523 CheckContextId(object1, 1);
16524 CHECK(func1->CreationContext() == context1);
16525 CheckContextId(func1, 1);
16526 CHECK(instance1->CreationContext() == context1);
16527 CheckContextId(instance1, 1);
16528 CHECK(object2->CreationContext() == context2);
16529 CheckContextId(object2, 2);
16530 CHECK(func2->CreationContext() == context2);
16531 CheckContextId(func2, 2);
16532 CHECK(instance2->CreationContext() == context2);
16533 CheckContextId(instance2, 2);
16536 context1.Dispose();
16537 context2.Dispose();
16538 context3.Dispose();
16542 THREADED_TEST(CreationContextOfJsFunction) {
16543 HandleScope handle_scope;
16544 Persistent<Context> context = Context::New();
16545 InstallContextId(context, 1);
16547 Local<Object> function;
16549 Context::Scope scope(context);
16550 function = CompileRun("function foo() {}; foo").As<Object>();
16553 CHECK(function->CreationContext() == context);
16554 CheckContextId(function, 1);
16560 Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16561 const AccessorInfo& info) {
16562 if (index == 42) return v8_str("yes");
16563 return Handle<v8::Integer>();
16567 Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16568 const AccessorInfo& info) {
16569 if (property->Equals(v8_str("foo"))) return v8_str("yes");
16570 return Handle<Value>();
16574 Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
16575 uint32_t index, const AccessorInfo& info) {
16576 if (index == 42) return v8_num(1).As<v8::Integer>();
16577 return Handle<v8::Integer>();
16581 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
16582 Local<String> property, const AccessorInfo& info) {
16583 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
16584 return Handle<v8::Integer>();
16588 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
16589 Local<String> property, const AccessorInfo& info) {
16590 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
16591 return Handle<v8::Integer>();
16595 Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16596 const AccessorInfo& info) {
16597 return v8_str("yes");
16601 TEST(HasOwnProperty) {
16602 v8::HandleScope scope;
16604 { // Check normal properties and defined getters.
16605 Handle<Value> value = CompileRun(
16608 " this.__defineGetter__('baz', function() { return 1; });"
16610 "function Bar() { "
16612 " this.__defineGetter__('bla', function() { return 2; });"
16614 "Bar.prototype = new Foo();"
16616 CHECK(value->IsObject());
16617 Handle<Object> object = value->ToObject();
16618 CHECK(object->Has(v8_str("foo")));
16619 CHECK(!object->HasOwnProperty(v8_str("foo")));
16620 CHECK(object->HasOwnProperty(v8_str("bar")));
16621 CHECK(object->Has(v8_str("baz")));
16622 CHECK(!object->HasOwnProperty(v8_str("baz")));
16623 CHECK(object->HasOwnProperty(v8_str("bla")));
16625 { // Check named getter interceptors.
16626 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16627 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
16628 Handle<Object> instance = templ->NewInstance();
16629 CHECK(!instance->HasOwnProperty(v8_str("42")));
16630 CHECK(instance->HasOwnProperty(v8_str("foo")));
16631 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16633 { // Check indexed getter interceptors.
16634 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16635 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
16636 Handle<Object> instance = templ->NewInstance();
16637 CHECK(instance->HasOwnProperty(v8_str("42")));
16638 CHECK(!instance->HasOwnProperty(v8_str("43")));
16639 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16641 { // Check named query interceptors.
16642 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16643 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
16644 Handle<Object> instance = templ->NewInstance();
16645 CHECK(instance->HasOwnProperty(v8_str("foo")));
16646 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16648 { // Check indexed query interceptors.
16649 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16650 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
16651 Handle<Object> instance = templ->NewInstance();
16652 CHECK(instance->HasOwnProperty(v8_str("42")));
16653 CHECK(!instance->HasOwnProperty(v8_str("41")));
16655 { // Check callbacks.
16656 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16657 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
16658 Handle<Object> instance = templ->NewInstance();
16659 CHECK(instance->HasOwnProperty(v8_str("foo")));
16660 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16662 { // Check that query wins on disagreement.
16663 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16664 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16666 HasOwnPropertyNamedPropertyQuery2);
16667 Handle<Object> instance = templ->NewInstance();
16668 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16669 CHECK(instance->HasOwnProperty(v8_str("bar")));
16674 void CheckCodeGenerationAllowed() {
16675 Handle<Value> result = CompileRun("eval('42')");
16676 CHECK_EQ(42, result->Int32Value());
16677 result = CompileRun("(function(e) { return e('42'); })(eval)");
16678 CHECK_EQ(42, result->Int32Value());
16679 result = CompileRun("var f = new Function('return 42'); f()");
16680 CHECK_EQ(42, result->Int32Value());
16684 void CheckCodeGenerationDisallowed() {
16685 TryCatch try_catch;
16687 Handle<Value> result = CompileRun("eval('42')");
16688 CHECK(result.IsEmpty());
16689 CHECK(try_catch.HasCaught());
16692 result = CompileRun("(function(e) { return e('42'); })(eval)");
16693 CHECK(result.IsEmpty());
16694 CHECK(try_catch.HasCaught());
16697 result = CompileRun("var f = new Function('return 42'); f()");
16698 CHECK(result.IsEmpty());
16699 CHECK(try_catch.HasCaught());
16703 bool CodeGenerationAllowed(Local<Context> context) {
16704 ApiTestFuzzer::Fuzz();
16709 bool CodeGenerationDisallowed(Local<Context> context) {
16710 ApiTestFuzzer::Fuzz();
16715 THREADED_TEST(AllowCodeGenFromStrings) {
16716 v8::HandleScope scope;
16717 LocalContext context;
16719 // eval and the Function constructor allowed by default.
16720 CHECK(context->IsCodeGenerationFromStringsAllowed());
16721 CheckCodeGenerationAllowed();
16723 // Disallow eval and the Function constructor.
16724 context->AllowCodeGenerationFromStrings(false);
16725 CHECK(!context->IsCodeGenerationFromStringsAllowed());
16726 CheckCodeGenerationDisallowed();
16729 context->AllowCodeGenerationFromStrings(true);
16730 CheckCodeGenerationAllowed();
16732 // Disallow but setting a global callback that will allow the calls.
16733 context->AllowCodeGenerationFromStrings(false);
16734 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
16735 CHECK(!context->IsCodeGenerationFromStringsAllowed());
16736 CheckCodeGenerationAllowed();
16738 // Set a callback that disallows the code generation.
16739 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16740 CHECK(!context->IsCodeGenerationFromStringsAllowed());
16741 CheckCodeGenerationDisallowed();
16745 TEST(SetErrorMessageForCodeGenFromStrings) {
16746 v8::HandleScope scope;
16747 LocalContext context;
16748 TryCatch try_catch;
16750 Handle<String> message = v8_str("Message") ;
16751 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
16752 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16753 context->AllowCodeGenerationFromStrings(false);
16754 context->SetErrorMessageForCodeGenerationFromStrings(message);
16755 Handle<Value> result = CompileRun("eval('42')");
16756 CHECK(result.IsEmpty());
16757 CHECK(try_catch.HasCaught());
16758 Handle<String> actual_message = try_catch.Message()->Get();
16759 CHECK(expected_message->Equals(actual_message));
16763 static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16764 return v8::Undefined();
16768 THREADED_TEST(CallAPIFunctionOnNonObject) {
16769 v8::HandleScope scope;
16770 LocalContext context;
16771 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
16772 Handle<Function> function = templ->GetFunction();
16773 context->Global()->Set(v8_str("f"), function);
16774 TryCatch try_catch;
16775 CompileRun("f.call(2)");
16779 // Regression test for issue 1470.
16780 THREADED_TEST(ReadOnlyIndexedProperties) {
16781 v8::HandleScope scope;
16782 Local<ObjectTemplate> templ = ObjectTemplate::New();
16784 LocalContext context;
16785 Local<v8::Object> obj = templ->NewInstance();
16786 context->Global()->Set(v8_str("obj"), obj);
16787 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16788 obj->Set(v8_str("1"), v8_str("foobar"));
16789 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
16790 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
16791 obj->Set(v8_num(2), v8_str("foobar"));
16792 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
16794 // Test non-smi case.
16795 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16796 obj->Set(v8_str("2000000000"), v8_str("foobar"));
16797 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16801 THREADED_TEST(Regress1516) {
16802 v8::HandleScope scope;
16804 LocalContext context;
16805 { v8::HandleScope temp_scope;
16806 CompileRun("({'a': 0})");
16810 { i::MapCache* map_cache =
16811 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16812 elements = map_cache->NumberOfElements();
16813 CHECK_LE(1, elements);
16816 i::Isolate::Current()->heap()->CollectAllGarbage(
16817 i::Heap::kAbortIncrementalMarkingMask);
16818 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16819 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16820 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16821 CHECK_GT(elements, map_cache->NumberOfElements());
16827 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16829 v8::AccessType type,
16830 Local<Value> data) {
16831 // Only block read access to __proto__.
16832 if (type == v8::ACCESS_GET &&
16833 name->IsString() &&
16834 name->ToString()->Length() == 9 &&
16835 name->ToString()->Utf8Length() == 9) {
16837 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16838 return strncmp(buffer, "__proto__", 9) != 0;
16845 THREADED_TEST(Regress93759) {
16848 // Template for object with security check.
16849 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16850 // We don't do indexing, so any callback can be used for that.
16851 no_proto_template->SetAccessCheckCallbacks(
16852 BlockProtoNamedSecurityTestCallback,
16853 IndexedSecurityTestCallback);
16855 // Templates for objects with hidden prototypes and possibly security check.
16856 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16857 hidden_proto_template->SetHiddenPrototype(true);
16859 Local<FunctionTemplate> protected_hidden_proto_template =
16860 v8::FunctionTemplate::New();
16861 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16862 BlockProtoNamedSecurityTestCallback,
16863 IndexedSecurityTestCallback);
16864 protected_hidden_proto_template->SetHiddenPrototype(true);
16866 // Context for "foreign" objects used in test.
16867 Persistent<Context> context = v8::Context::New();
16870 // Plain object, no security check.
16871 Local<Object> simple_object = Object::New();
16873 // Object with explicit security check.
16874 Local<Object> protected_object =
16875 no_proto_template->NewInstance();
16877 // JSGlobalProxy object, always have security check.
16878 Local<Object> proxy_object =
16881 // Global object, the prototype of proxy_object. No security checks.
16882 Local<Object> global_object =
16883 proxy_object->GetPrototype()->ToObject();
16885 // Hidden prototype without security check.
16886 Local<Object> hidden_prototype =
16887 hidden_proto_template->GetFunction()->NewInstance();
16888 Local<Object> object_with_hidden =
16890 object_with_hidden->SetPrototype(hidden_prototype);
16892 // Hidden prototype with security check on the hidden prototype.
16893 Local<Object> protected_hidden_prototype =
16894 protected_hidden_proto_template->GetFunction()->NewInstance();
16895 Local<Object> object_with_protected_hidden =
16897 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
16901 // Template for object for second context. Values to test are put on it as
16903 Local<ObjectTemplate> global_template = ObjectTemplate::New();
16904 global_template->Set(v8_str("simple"), simple_object);
16905 global_template->Set(v8_str("protected"), protected_object);
16906 global_template->Set(v8_str("global"), global_object);
16907 global_template->Set(v8_str("proxy"), proxy_object);
16908 global_template->Set(v8_str("hidden"), object_with_hidden);
16909 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
16911 LocalContext context2(NULL, global_template);
16913 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
16914 CHECK(result1->Equals(simple_object->GetPrototype()));
16916 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
16917 CHECK(result2->Equals(Undefined()));
16919 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
16920 CHECK(result3->Equals(global_object->GetPrototype()));
16922 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
16923 CHECK(result4->Equals(Undefined()));
16925 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
16926 CHECK(result5->Equals(
16927 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
16929 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
16930 CHECK(result6->Equals(Undefined()));
16936 THREADED_TEST(Regress125988) {
16937 v8::HandleScope scope;
16938 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
16939 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
16941 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
16942 CompileRun("var a = new Object();"
16943 "var b = new Intercept();"
16944 "var c = new Object();"
16948 "for (var i = 0; i < 3; i++) c.x;");
16949 ExpectBoolean("c.hasOwnProperty('x')", false);
16950 ExpectInt32("c.x", 23);
16951 CompileRun("a.y = 42;"
16952 "for (var i = 0; i < 3; i++) c.x;");
16953 ExpectBoolean("c.hasOwnProperty('x')", false);
16954 ExpectInt32("c.x", 23);
16955 ExpectBoolean("c.hasOwnProperty('y')", false);
16956 ExpectInt32("c.y", 42);
16960 static void TestReceiver(Local<Value> expected_result,
16961 Local<Value> expected_receiver,
16962 const char* code) {
16963 Local<Value> result = CompileRun(code);
16964 CHECK(result->IsObject());
16965 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
16966 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
16970 THREADED_TEST(ForeignFunctionReceiver) {
16973 // Create two contexts with different "id" properties ('i' and 'o').
16974 // Call a function both from its own context and from a the foreign
16975 // context, and see what "this" is bound to (returning both "this"
16976 // and "this.id" for comparison).
16978 Persistent<Context> foreign_context = v8::Context::New();
16979 foreign_context->Enter();
16980 Local<Value> foreign_function =
16981 CompileRun("function func() { return { 0: this.id, "
16983 " toString: function() { "
16990 CHECK(foreign_function->IsFunction());
16991 foreign_context->Exit();
16993 LocalContext context;
16995 Local<String> password = v8_str("Password");
16996 // Don't get hit by security checks when accessing foreign_context's
16997 // global receiver (aka. global proxy).
16998 context->SetSecurityToken(password);
16999 foreign_context->SetSecurityToken(password);
17001 Local<String> i = v8_str("i");
17002 Local<String> o = v8_str("o");
17003 Local<String> id = v8_str("id");
17005 CompileRun("function ownfunc() { return { 0: this.id, "
17007 " toString: function() { "
17014 context->Global()->Set(v8_str("func"), foreign_function);
17016 // Sanity check the contexts.
17017 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17018 CHECK(o->Equals(context->Global()->Get(id)));
17020 // Checking local function's receiver.
17021 // Calling function using its call/apply methods.
17022 TestReceiver(o, context->Global(), "ownfunc.call()");
17023 TestReceiver(o, context->Global(), "ownfunc.apply()");
17024 // Making calls through built-in functions.
17025 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17026 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17027 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17028 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17029 // Calling with environment record as base.
17030 TestReceiver(o, context->Global(), "ownfunc()");
17031 // Calling with no base.
17032 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17034 // Checking foreign function return value.
17035 // Calling function using its call/apply methods.
17036 TestReceiver(i, foreign_context->Global(), "func.call()");
17037 TestReceiver(i, foreign_context->Global(), "func.apply()");
17038 // Calling function using another context's call/apply methods.
17039 TestReceiver(i, foreign_context->Global(),
17040 "Function.prototype.call.call(func)");
17041 TestReceiver(i, foreign_context->Global(),
17042 "Function.prototype.call.apply(func)");
17043 TestReceiver(i, foreign_context->Global(),
17044 "Function.prototype.apply.call(func)");
17045 TestReceiver(i, foreign_context->Global(),
17046 "Function.prototype.apply.apply(func)");
17047 // Making calls through built-in functions.
17048 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17049 // ToString(func()) is func()[0], i.e., the returned this.id.
17050 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17051 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17052 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17054 // TODO(1547): Make the following also return "i".
17055 // Calling with environment record as base.
17056 TestReceiver(o, context->Global(), "func()");
17057 // Calling with no base.
17058 TestReceiver(o, context->Global(), "(1,func)()");
17060 foreign_context.Dispose();
17064 uint8_t callback_fired = 0;
17067 void CallCompletedCallback1() {
17068 i::OS::Print("Firing callback 1.\n");
17069 callback_fired ^= 1; // Toggle first bit.
17073 void CallCompletedCallback2() {
17074 i::OS::Print("Firing callback 2.\n");
17075 callback_fired ^= 2; // Toggle second bit.
17079 Handle<Value> RecursiveCall(const Arguments& args) {
17080 int32_t level = args[0]->Int32Value();
17083 i::OS::Print("Entering recursion level %d.\n", level);
17085 i::Vector<char> script_vector(script, sizeof(script));
17086 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17087 CompileRun(script_vector.start());
17088 i::OS::Print("Leaving recursion level %d.\n", level);
17089 CHECK_EQ(0, callback_fired);
17091 i::OS::Print("Recursion ends.\n");
17092 CHECK_EQ(0, callback_fired);
17094 return Undefined();
17098 TEST(CallCompletedCallback) {
17099 v8::HandleScope scope;
17101 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17102 v8::FunctionTemplate::New(RecursiveCall);
17103 env->Global()->Set(v8_str("recursion"),
17104 recursive_runtime->GetFunction());
17105 // Adding the same callback a second time has no effect.
17106 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17107 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17108 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17109 i::OS::Print("--- Script (1) ---\n");
17110 Local<Script> script =
17111 v8::Script::Compile(v8::String::New("recursion(0)"));
17113 CHECK_EQ(3, callback_fired);
17115 i::OS::Print("\n--- Script (2) ---\n");
17116 callback_fired = 0;
17117 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17119 CHECK_EQ(2, callback_fired);
17121 i::OS::Print("\n--- Function ---\n");
17122 callback_fired = 0;
17123 Local<Function> recursive_function =
17124 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17125 v8::Handle<Value> args[] = { v8_num(0) };
17126 recursive_function->Call(env->Global(), 1, args);
17127 CHECK_EQ(2, callback_fired);
17131 void CallCompletedCallbackNoException() {
17132 v8::HandleScope scope;
17133 CompileRun("1+1;");
17137 void CallCompletedCallbackException() {
17138 v8::HandleScope scope;
17139 CompileRun("throw 'second exception';");
17143 TEST(CallCompletedCallbackOneException) {
17144 v8::HandleScope scope;
17146 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17147 CompileRun("throw 'exception';");
17151 TEST(CallCompletedCallbackTwoExceptions) {
17152 v8::HandleScope scope;
17154 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17155 CompileRun("throw 'first exception';");
17159 static int probes_counter = 0;
17160 static int misses_counter = 0;
17161 static int updates_counter = 0;
17164 static int* LookupCounter(const char* name) {
17165 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17166 return &probes_counter;
17167 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17168 return &misses_counter;
17169 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17170 return &updates_counter;
17176 static const char* kMegamorphicTestProgram =
17177 "function ClassA() { };"
17178 "function ClassB() { };"
17179 "ClassA.prototype.foo = function() { };"
17180 "ClassB.prototype.foo = function() { };"
17181 "function fooify(obj) { obj.foo(); };"
17182 "var a = new ClassA();"
17183 "var b = new ClassB();"
17184 "for (var i = 0; i < 10000; i++) {"
17190 static void StubCacheHelper(bool primary) {
17191 V8::SetCounterFunction(LookupCounter);
17192 USE(kMegamorphicTestProgram);
17194 i::FLAG_native_code_counters = true;
17196 i::FLAG_test_primary_stub_cache = true;
17198 i::FLAG_test_secondary_stub_cache = true;
17200 i::FLAG_crankshaft = false;
17201 v8::HandleScope scope;
17203 int initial_probes = probes_counter;
17204 int initial_misses = misses_counter;
17205 int initial_updates = updates_counter;
17206 CompileRun(kMegamorphicTestProgram);
17207 int probes = probes_counter - initial_probes;
17208 int misses = misses_counter - initial_misses;
17209 int updates = updates_counter - initial_updates;
17210 CHECK_LT(updates, 10);
17211 CHECK_LT(misses, 10);
17212 CHECK_GE(probes, 10000);
17217 TEST(SecondaryStubCache) {
17218 StubCacheHelper(true);
17222 TEST(PrimaryStubCache) {
17223 StubCacheHelper(false);
17227 static int fatal_error_callback_counter = 0;
17228 static void CountingErrorCallback(const char* location, const char* message) {
17229 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17230 fatal_error_callback_counter++;
17234 TEST(StaticGetters) {
17235 v8::HandleScope scope;
17236 LocalContext context;
17237 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17238 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17239 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17240 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17241 i::Handle<i::Object> null_value = FACTORY->null_value();
17242 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17243 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17244 i::Handle<i::Object> true_value = FACTORY->true_value();
17245 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17246 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17247 i::Handle<i::Object> false_value = FACTORY->false_value();
17248 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17249 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17251 // Test after-death behavior.
17252 CHECK(i::Internals::IsInitialized(isolate));
17253 CHECK_EQ(0, fatal_error_callback_counter);
17254 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17255 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17256 i::Isolate::Current()->TearDown();
17257 CHECK(!i::Internals::IsInitialized(isolate));
17258 CHECK_EQ(1, fatal_error_callback_counter);
17259 CHECK(v8::Undefined().IsEmpty());
17260 CHECK_EQ(2, fatal_error_callback_counter);
17261 CHECK(v8::Undefined(isolate).IsEmpty());
17262 CHECK_EQ(3, fatal_error_callback_counter);
17263 CHECK(v8::Null().IsEmpty());
17264 CHECK_EQ(4, fatal_error_callback_counter);
17265 CHECK(v8::Null(isolate).IsEmpty());
17266 CHECK_EQ(5, fatal_error_callback_counter);
17267 CHECK(v8::True().IsEmpty());
17268 CHECK_EQ(6, fatal_error_callback_counter);
17269 CHECK(v8::True(isolate).IsEmpty());
17270 CHECK_EQ(7, fatal_error_callback_counter);
17271 CHECK(v8::False().IsEmpty());
17272 CHECK_EQ(8, fatal_error_callback_counter);
17273 CHECK(v8::False(isolate).IsEmpty());
17274 CHECK_EQ(9, fatal_error_callback_counter);
17278 TEST(IsolateEmbedderData) {
17279 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17280 CHECK_EQ(NULL, isolate->GetData());
17281 CHECK_EQ(NULL, ISOLATE->GetData());
17282 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17283 isolate->SetData(data1);
17284 CHECK_EQ(data1, isolate->GetData());
17285 CHECK_EQ(data1, ISOLATE->GetData());
17286 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17287 ISOLATE->SetData(data2);
17288 CHECK_EQ(data2, isolate->GetData());
17289 CHECK_EQ(data2, ISOLATE->GetData());
17290 ISOLATE->TearDown();
17291 CHECK_EQ(data2, isolate->GetData());
17292 CHECK_EQ(data2, ISOLATE->GetData());
17296 TEST(StringEmpty) {
17297 v8::HandleScope scope;
17298 LocalContext context;
17299 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17300 i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17301 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17302 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17304 // Test after-death behavior.
17305 CHECK(i::Internals::IsInitialized(isolate));
17306 CHECK_EQ(0, fatal_error_callback_counter);
17307 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17308 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17309 i::Isolate::Current()->TearDown();
17310 CHECK(!i::Internals::IsInitialized(isolate));
17311 CHECK_EQ(1, fatal_error_callback_counter);
17312 CHECK(v8::String::Empty().IsEmpty());
17313 CHECK_EQ(2, fatal_error_callback_counter);
17314 CHECK(v8::String::Empty(isolate).IsEmpty());
17315 CHECK_EQ(3, fatal_error_callback_counter);
17319 static int instance_checked_getter_count = 0;
17320 static Handle<Value> InstanceCheckedGetter(Local<String> name,
17321 const AccessorInfo& info) {
17322 CHECK_EQ(name, v8_str("foo"));
17323 instance_checked_getter_count++;
17328 static int instance_checked_setter_count = 0;
17329 static void InstanceCheckedSetter(Local<String> name,
17330 Local<Value> value,
17331 const AccessorInfo& info) {
17332 CHECK_EQ(name, v8_str("foo"));
17333 CHECK_EQ(value, v8_num(23));
17334 instance_checked_setter_count++;
17338 static void CheckInstanceCheckedResult(int getters,
17340 bool expects_callbacks,
17341 TryCatch* try_catch) {
17342 if (expects_callbacks) {
17343 CHECK(!try_catch->HasCaught());
17344 CHECK_EQ(getters, instance_checked_getter_count);
17345 CHECK_EQ(setters, instance_checked_setter_count);
17347 CHECK(try_catch->HasCaught());
17348 CHECK_EQ(0, instance_checked_getter_count);
17349 CHECK_EQ(0, instance_checked_setter_count);
17351 try_catch->Reset();
17355 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17356 instance_checked_getter_count = 0;
17357 instance_checked_setter_count = 0;
17358 TryCatch try_catch;
17360 // Test path through generic runtime code.
17361 CompileRun("obj.foo");
17362 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17363 CompileRun("obj.foo = 23");
17364 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17366 // Test path through generated LoadIC and StoredIC.
17367 CompileRun("function test_get(o) { o.foo; }"
17369 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17370 CompileRun("test_get(obj);");
17371 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17372 CompileRun("test_get(obj);");
17373 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17374 CompileRun("function test_set(o) { o.foo = 23; }"
17376 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17377 CompileRun("test_set(obj);");
17378 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17379 CompileRun("test_set(obj);");
17380 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17382 // Test path through optimized code.
17383 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17385 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17386 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17388 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17390 // Cleanup so that closures start out fresh in next check.
17391 CompileRun("%DeoptimizeFunction(test_get);"
17392 "%ClearFunctionTypeFeedback(test_get);"
17393 "%DeoptimizeFunction(test_set);"
17394 "%ClearFunctionTypeFeedback(test_set);");
17398 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17399 v8::internal::FLAG_allow_natives_syntax = true;
17400 v8::HandleScope scope;
17401 LocalContext context;
17403 Local<FunctionTemplate> templ = FunctionTemplate::New();
17404 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17405 inst->SetAccessor(v8_str("foo"),
17406 InstanceCheckedGetter, InstanceCheckedSetter,
17410 v8::AccessorSignature::New(templ));
17411 context->Global()->Set(v8_str("f"), templ->GetFunction());
17413 printf("Testing positive ...\n");
17414 CompileRun("var obj = new f();");
17415 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17416 CheckInstanceCheckedAccessors(true);
17418 printf("Testing negative ...\n");
17419 CompileRun("var obj = {};"
17420 "obj.__proto__ = new f();");
17421 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17422 CheckInstanceCheckedAccessors(false);
17426 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17427 v8::internal::FLAG_allow_natives_syntax = true;
17428 v8::HandleScope scope;
17429 LocalContext context;
17431 Local<FunctionTemplate> templ = FunctionTemplate::New();
17432 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17433 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17434 inst->SetAccessor(v8_str("foo"),
17435 InstanceCheckedGetter, InstanceCheckedSetter,
17439 v8::AccessorSignature::New(templ));
17440 context->Global()->Set(v8_str("f"), templ->GetFunction());
17442 printf("Testing positive ...\n");
17443 CompileRun("var obj = new f();");
17444 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17445 CheckInstanceCheckedAccessors(true);
17447 printf("Testing negative ...\n");
17448 CompileRun("var obj = {};"
17449 "obj.__proto__ = new f();");
17450 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17451 CheckInstanceCheckedAccessors(false);
17455 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17456 v8::internal::FLAG_allow_natives_syntax = true;
17457 v8::HandleScope scope;
17458 LocalContext context;
17460 Local<FunctionTemplate> templ = FunctionTemplate::New();
17461 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17462 proto->SetAccessor(v8_str("foo"),
17463 InstanceCheckedGetter, InstanceCheckedSetter,
17467 v8::AccessorSignature::New(templ));
17468 context->Global()->Set(v8_str("f"), templ->GetFunction());
17470 printf("Testing positive ...\n");
17471 CompileRun("var obj = new f();");
17472 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17473 CheckInstanceCheckedAccessors(true);
17475 printf("Testing negative ...\n");
17476 CompileRun("var obj = {};"
17477 "obj.__proto__ = new f();");
17478 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17479 CheckInstanceCheckedAccessors(false);
17481 printf("Testing positive with modified prototype chain ...\n");
17482 CompileRun("var obj = new f();"
17484 "pro.__proto__ = obj.__proto__;"
17485 "obj.__proto__ = pro;");
17486 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17487 CheckInstanceCheckedAccessors(true);
17491 TEST(TryFinallyMessage) {
17492 v8::HandleScope scope;
17493 LocalContext context;
17495 // Test that the original error message is not lost if there is a
17496 // recursive call into Javascript is done in the finally block, e.g. to
17497 // initialize an IC. (crbug.com/129171)
17498 TryCatch try_catch;
17499 const char* trigger_ic =
17501 " throw new Error('test'); \n"
17504 " x++; \n" // Trigger an IC initialization here.
17506 CompileRun(trigger_ic);
17507 CHECK(try_catch.HasCaught());
17508 Local<Message> message = try_catch.Message();
17509 CHECK(!message.IsEmpty());
17510 CHECK_EQ(2, message->GetLineNumber());
17514 // Test that the original exception message is indeed overwritten if
17515 // a new error is thrown in the finally block.
17516 TryCatch try_catch;
17517 const char* throw_again =
17519 " throw new Error('test'); \n"
17523 " throw new Error('again'); \n" // This is the new uncaught error.
17525 CompileRun(throw_again);
17526 CHECK(try_catch.HasCaught());
17527 Local<Message> message = try_catch.Message();
17528 CHECK(!message.IsEmpty());
17529 CHECK_EQ(6, message->GetLineNumber());
17534 static void Helper137002(bool do_store,
17536 bool remove_accessor,
17537 bool interceptor) {
17538 LocalContext context;
17539 Local<ObjectTemplate> templ = ObjectTemplate::New();
17541 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17543 templ->SetAccessor(v8_str("foo"),
17544 GetterWhichReturns42,
17545 SetterWhichSetsYOnThisTo23);
17547 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17549 // Turn monomorphic on slow object with native accessor, then turn
17550 // polymorphic, finally optimize to create negative lookup and fail.
17551 CompileRun(do_store ?
17552 "function f(x) { x.foo = void 0; }" :
17553 "function f(x) { return x.foo; }");
17554 CompileRun("obj.y = void 0;");
17555 if (!interceptor) {
17556 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17558 CompileRun("obj.__proto__ = null;"
17559 "f(obj); f(obj); f(obj);");
17561 CompileRun("f({});");
17563 CompileRun("obj.y = void 0;"
17564 "%OptimizeFunctionOnNextCall(f);");
17565 if (remove_accessor) {
17566 CompileRun("delete obj.foo;");
17568 CompileRun("var result = f(obj);");
17570 CompileRun("result = obj.y;");
17572 if (remove_accessor && !interceptor) {
17573 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17575 CHECK_EQ(do_store ? 23 : 42,
17576 context->Global()->Get(v8_str("result"))->Int32Value());
17581 THREADED_TEST(Regress137002a) {
17582 i::FLAG_allow_natives_syntax = true;
17583 i::FLAG_compilation_cache = false;
17584 v8::HandleScope scope;
17585 for (int i = 0; i < 16; i++) {
17586 Helper137002(i & 8, i & 4, i & 2, i & 1);
17591 THREADED_TEST(Regress137002b) {
17592 i::FLAG_allow_natives_syntax = true;
17593 v8::HandleScope scope;
17594 LocalContext context;
17595 Local<ObjectTemplate> templ = ObjectTemplate::New();
17596 templ->SetAccessor(v8_str("foo"),
17597 GetterWhichReturns42,
17598 SetterWhichSetsYOnThisTo23);
17599 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17601 // Turn monomorphic on slow object with native accessor, then just
17602 // delete the property and fail.
17603 CompileRun("function load(x) { return x.foo; }"
17604 "function store(x) { x.foo = void 0; }"
17605 "function keyed_load(x, key) { return x[key]; }"
17606 // Second version of function has a different source (add void 0)
17607 // so that it does not share code with the first version. This
17608 // ensures that the ICs are monomorphic.
17609 "function load2(x) { void 0; return x.foo; }"
17610 "function store2(x) { void 0; x.foo = void 0; }"
17611 "function keyed_load2(x, key) { void 0; return x[key]; }"
17614 "obj.__proto__ = null;"
17616 "subobj.y = void 0;"
17617 "subobj.__proto__ = obj;"
17618 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17620 // Make the ICs monomorphic.
17621 "load(obj); load(obj);"
17622 "load2(subobj); load2(subobj);"
17623 "store(obj); store(obj);"
17624 "store2(subobj); store2(subobj);"
17625 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
17626 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
17628 // Actually test the shiny new ICs and better not crash. This
17629 // serves as a regression test for issue 142088 as well.
17634 "keyed_load(obj, 'foo');"
17635 "keyed_load2(subobj, 'foo');"
17637 // Delete the accessor. It better not be called any more now.
17640 "subobj.y = void 0;"
17642 "var load_result = load(obj);"
17643 "var load_result2 = load2(subobj);"
17644 "var keyed_load_result = keyed_load(obj, 'foo');"
17645 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
17648 "var y_from_obj = obj.y;"
17649 "var y_from_subobj = subobj.y;");
17650 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
17651 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
17652 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
17653 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
17654 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
17655 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
17659 THREADED_TEST(Regress142088) {
17660 i::FLAG_allow_natives_syntax = true;
17661 v8::HandleScope scope;
17662 LocalContext context;
17663 Local<ObjectTemplate> templ = ObjectTemplate::New();
17664 templ->SetAccessor(v8_str("foo"),
17665 GetterWhichReturns42,
17666 SetterWhichSetsYOnThisTo23);
17667 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17669 CompileRun("function load(x) { return x.foo; }"
17670 "var o = Object.create(obj);"
17671 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17672 "load(o); load(o); load(o); load(o);");
17676 THREADED_TEST(Regress137496) {
17677 i::FLAG_expose_gc = true;
17678 v8::HandleScope scope;
17679 LocalContext context;
17681 // Compile a try-finally clause where the finally block causes a GC
17682 // while there still is a message pending for external reporting.
17683 TryCatch try_catch;
17684 try_catch.SetVerbose(true);
17685 CompileRun("try { throw new Error(); } finally { gc(); }");
17686 CHECK(try_catch.HasCaught());
17690 THREADED_TEST(Regress149912) {
17691 v8::HandleScope scope;
17692 LocalContext context;
17693 Handle<FunctionTemplate> templ = FunctionTemplate::New();
17694 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17695 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
17696 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
17700 THREADED_TEST(Regress157124) {
17701 v8::HandleScope scope;
17702 LocalContext context;
17703 Local<ObjectTemplate> templ = ObjectTemplate::New();
17704 Local<Object> obj = templ->NewInstance();
17705 obj->GetIdentityHash();
17706 obj->DeleteHiddenValue(v8_str("Bug"));
17711 class ThreadInterruptTest {
17713 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17714 ~ThreadInterruptTest() { delete sem_; }
17717 sem_ = i::OS::CreateSemaphore(0);
17719 InterruptThread i_thread(this);
17723 CHECK_EQ(kExpectedValue, sem_value_);
17727 static const int kExpectedValue = 1;
17729 class InterruptThread : public i::Thread {
17731 explicit InterruptThread(ThreadInterruptTest* test)
17732 : Thread("InterruptThread"), test_(test) {}
17734 virtual void Run() {
17735 struct sigaction action;
17737 // Ensure that we'll enter waiting condition
17740 // Setup signal handler
17741 memset(&action, 0, sizeof(action));
17742 action.sa_handler = SignalHandler;
17743 sigaction(SIGCHLD, &action, NULL);
17746 kill(getpid(), SIGCHLD);
17748 // Ensure that if wait has returned because of error
17751 // Set value and signal semaphore
17752 test_->sem_value_ = 1;
17753 test_->sem_->Signal();
17756 static void SignalHandler(int signal) {
17760 ThreadInterruptTest* test_;
17761 struct sigaction sa_;
17764 i::Semaphore* sem_;
17765 volatile int sem_value_;
17769 THREADED_TEST(SemaphoreInterruption) {
17770 ThreadInterruptTest().RunTest();